diff --git a/TMessagesProj/build.gradle b/TMessagesProj/build.gradle index 29b6baa91..b700ac90a 100644 --- a/TMessagesProj/build.gradle +++ b/TMessagesProj/build.gradle @@ -300,7 +300,7 @@ android { } } - defaultConfig.versionCode = 2600 + defaultConfig.versionCode = 2622 applicationVariants.all { variant -> variant.outputs.all { output -> @@ -319,7 +319,7 @@ android { defaultConfig { minSdkVersion 16 targetSdkVersion 30 - versionName "8.6.2" + versionName "8.7.0" vectorDrawables.generatedDensities = ['mdpi', 'hdpi', 'xhdpi', 'xxhdpi'] diff --git a/TMessagesProj/jni/voip/CMakeLists.txt b/TMessagesProj/jni/voip/CMakeLists.txt index da5a84b6a..74acffcf3 100644 --- a/TMessagesProj/jni/voip/CMakeLists.txt +++ b/TMessagesProj/jni/voip/CMakeLists.txt @@ -457,6 +457,10 @@ add_library(tgcalls STATIC voip/tgcalls/v2/NativeNetworkingImpl.cpp voip/tgcalls/v2/Signaling.cpp voip/tgcalls/v2/SignalingEncryption.cpp + voip/tgcalls/v2/ContentNegotiation.cpp + voip/tgcalls/v2/InstanceV2ReferenceImpl.cpp + voip/tgcalls/v2_4_0_0/InstanceV2_4_0_0Impl.cpp + voip/tgcalls/v2_4_0_0/Signaling_4_0_0.cpp voip/webrtc/rtc_base/bitstream_reader.cc voip/webrtc/rtc_base/async_invoker.cc voip/webrtc/rtc_base/system_time.cc diff --git a/TMessagesProj/jni/voip/org_telegram_messenger_voip_Instance.cpp b/TMessagesProj/jni/voip/org_telegram_messenger_voip_Instance.cpp index 96a05d237..7f4e9e35d 100644 --- a/TMessagesProj/jni/voip/org_telegram_messenger_voip_Instance.cpp +++ b/TMessagesProj/jni/voip/org_telegram_messenger_voip_Instance.cpp @@ -24,12 +24,14 @@ #include "libtgvoip/os/android/JNIUtilities.h" #include "tgcalls/VideoCaptureInterface.h" #include "tgcalls/v2/InstanceV2Impl.h" +#include "tgcalls/v2_4_0_0/InstanceV2_4_0_0Impl.h" using namespace tgcalls; const auto RegisterTag = Register(); const auto RegisterTagLegacy = Register(); -const auto RegisterTagV2 = Register(); +const auto RegisterTagV2_4_0_0 = Register(); +const auto RegisterTagV2_4_0_1 = Register(); jclass TrafficStatsClass; jclass FingerprintClass; diff --git a/TMessagesProj/jni/voip/tgcalls/MediaManager.cpp b/TMessagesProj/jni/voip/tgcalls/MediaManager.cpp index 2db2b783f..0f5d5558f 100644 --- a/TMessagesProj/jni/voip/tgcalls/MediaManager.cpp +++ b/TMessagesProj/jni/voip/tgcalls/MediaManager.cpp @@ -408,7 +408,7 @@ _platformContext(platformContext) { rtc::scoped_refptr MediaManager::createAudioDeviceModule() { const auto create = [&](webrtc::AudioDeviceModule::AudioLayer layer) { #ifdef WEBRTC_IOS - return rtc::make_ref_counted(false, false); + return rtc::make_ref_counted(false, false, 1); #else return webrtc::AudioDeviceModule::Create( layer, diff --git a/TMessagesProj/jni/voip/tgcalls/NetworkManager.cpp b/TMessagesProj/jni/voip/tgcalls/NetworkManager.cpp index faa7f50e7..fd87da112 100644 --- a/TMessagesProj/jni/voip/tgcalls/NetworkManager.cpp +++ b/TMessagesProj/jni/voip/tgcalls/NetworkManager.cpp @@ -104,6 +104,7 @@ NetworkManager::~NetworkManager() { _portAllocator.reset(); _networkManager.reset(); _socketFactory.reset(); + _networkMonitorFactory.reset(); } void NetworkManager::start() { diff --git a/TMessagesProj/jni/voip/tgcalls/group/AudioStreamingPartInternal.cpp b/TMessagesProj/jni/voip/tgcalls/group/AudioStreamingPartInternal.cpp index 27a71cbad..56390368a 100644 --- a/TMessagesProj/jni/voip/tgcalls/group/AudioStreamingPartInternal.cpp +++ b/TMessagesProj/jni/voip/tgcalls/group/AudioStreamingPartInternal.cpp @@ -104,6 +104,9 @@ _avIoContext(std::move(fileData)) { _frame = av_frame_alloc(); +#if LIBAVFORMAT_VERSION_MAJOR >= 59 + const +#endif AVInputFormat *inputFormat = av_find_input_format(container.c_str()); if (!inputFormat) { _didReadToEnd = true; @@ -144,7 +147,7 @@ _avIoContext(std::move(fileData)) { _streamId = i; - _durationInMilliseconds = (int)((inStream->duration + inStream->first_dts) * 1000 / 48000); + _durationInMilliseconds = (int)(inStream->duration * av_q2d(inStream->time_base) * 1000); if (inStream->metadata) { AVDictionaryEntry *entry = av_dict_get(inStream->metadata, "TG_META", nullptr, 0); diff --git a/TMessagesProj/jni/voip/tgcalls/group/AudioStreamingPartPersistentDecoder.cpp b/TMessagesProj/jni/voip/tgcalls/group/AudioStreamingPartPersistentDecoder.cpp index e79d4304d..63ef4755f 100644 --- a/TMessagesProj/jni/voip/tgcalls/group/AudioStreamingPartPersistentDecoder.cpp +++ b/TMessagesProj/jni/voip/tgcalls/group/AudioStreamingPartPersistentDecoder.cpp @@ -32,7 +32,7 @@ public: AudioStreamingPartPersistentDecoderState(AVCodecParameters const *codecParameters, AVRational timeBase) : _codecParameters(codecParameters), _timeBase(timeBase) { - AVCodec *codec = avcodec_find_decoder(codecParameters->codec_id); + const AVCodec *codec = avcodec_find_decoder(codecParameters->codec_id); if (codec) { _codecContext = avcodec_alloc_context3(codec); int ret = avcodec_parameters_to_context(_codecContext, codecParameters); diff --git a/TMessagesProj/jni/voip/tgcalls/group/GroupInstanceCustomImpl.cpp b/TMessagesProj/jni/voip/tgcalls/group/GroupInstanceCustomImpl.cpp index f124ded4c..eaf6c941a 100644 --- a/TMessagesProj/jni/voip/tgcalls/group/GroupInstanceCustomImpl.cpp +++ b/TMessagesProj/jni/voip/tgcalls/group/GroupInstanceCustomImpl.cpp @@ -1514,7 +1514,13 @@ public: std::unique_ptr audioProcessor = nullptr; #endif if (_videoContentType != VideoContentType::Screencast) { - PlatformInterface::SharedInstance()->configurePlatformAudio(); + int numChannels = 1; +#ifdef WEBRTC_IOS + if (_disableAudioInput) { + numChannels = 2; + } +#endif + PlatformInterface::SharedInstance()->configurePlatformAudio(numChannels); #if USE_RNNOISE audioProcessor = std::make_unique([weak, threads = _threads](GroupLevelValue const &level) { @@ -3297,7 +3303,7 @@ private: #endif const auto create = [&](webrtc::AudioDeviceModule::AudioLayer layer) { #ifdef WEBRTC_IOS - return rtc::make_ref_counted(false, disableRecording); + return rtc::make_ref_counted(false, disableRecording, disableRecording ? 2 : 1); #else return webrtc::AudioDeviceModule::Create( layer, diff --git a/TMessagesProj/jni/voip/tgcalls/group/StreamingMediaContext.cpp b/TMessagesProj/jni/voip/tgcalls/group/StreamingMediaContext.cpp index 905532f9a..9b566735c 100644 --- a/TMessagesProj/jni/voip/tgcalls/group/StreamingMediaContext.cpp +++ b/TMessagesProj/jni/voip/tgcalls/group/StreamingMediaContext.cpp @@ -423,6 +423,27 @@ public: if (numChannels == 1) { frameOut.UpdateFrame(0, audioChannels[0].pcmData.data(), audioChannels[0].pcmData.size(), 48000, webrtc::AudioFrame::SpeechType::kNormalSpeech, webrtc::AudioFrame::VADActivity::kVadActive, numChannels); + } else if (numChannels == _audioRingBufferNumChannels) { + bool skipFrame = false; + int numSamples = (int)audioChannels[0].pcmData.size(); + for (int i = 1; i < numChannels; i++) { + if (audioChannels[i].pcmData.size() != numSamples) { + skipFrame = true; + break; + } + } + if (skipFrame) { + break; + } + if (_stereoShuffleBuffer.size() < numChannels * numSamples) { + _stereoShuffleBuffer.resize(numChannels * numSamples); + } + for (int i = 0; i < numSamples; i++) { + for (int j = 0; j < numChannels; j++) { + _stereoShuffleBuffer[i * numChannels + j] = audioChannels[j].pcmData[i]; + } + } + frameOut.UpdateFrame(0, _stereoShuffleBuffer.data(), numSamples, 48000, webrtc::AudioFrame::SpeechType::kNormalSpeech, webrtc::AudioFrame::VADActivity::kVadActive, numChannels); } else { bool skipFrame = false; int numSamples = (int)audioChannels[0].pcmData.size(); @@ -483,6 +504,9 @@ public: RTC_LOG(LS_INFO) << "render: discarding video frames at the end of a segment (displayed " << segment->video[0]->_displayedFrames << " frames)"; } } + if (!segment->unified.empty() && segment->unified[0]->videoPart->hasRemainingFrames()) { + RTC_LOG(LS_INFO) << "render: discarding video frames at the end of a segment (displayed " << segment->unified[0]->_displayedFrames << " frames)"; + } _availableSegments.erase(_availableSegments.begin()); } diff --git a/TMessagesProj/jni/voip/tgcalls/group/VideoStreamingPart.cpp b/TMessagesProj/jni/voip/tgcalls/group/VideoStreamingPart.cpp index 84ecad22a..4a3441d5c 100644 --- a/TMessagesProj/jni/voip/tgcalls/group/VideoStreamingPart.cpp +++ b/TMessagesProj/jni/voip/tgcalls/group/VideoStreamingPart.cpp @@ -87,20 +87,16 @@ public: return _frame; } - double pts(AVStream *stream) { + double pts(AVStream *stream, double &firstFramePts) { int64_t framePts = _frame->pts; double spf = av_q2d(stream->time_base); - return ((double)framePts) * spf; - } - - double duration(AVStream *stream) { - int64_t frameDuration = _frame->pkt_duration; - double spf = av_q2d(stream->time_base); - if (frameDuration != 0) { - return ((double)frameDuration) * spf; - } else { - return spf; + double value = ((double)framePts) * spf; + + if (firstFramePts < 0.0) { + firstFramePts = value; } + + return value - firstFramePts; } private: @@ -280,6 +276,9 @@ public: int ret = 0; +#if LIBAVFORMAT_VERSION_MAJOR >= 59 + const +#endif AVInputFormat *inputFormat = av_find_input_format(container.c_str()); if (!inputFormat) { _didReadToEnd = true; @@ -323,7 +322,7 @@ public: } if (videoCodecParameters && videoStream) { - AVCodec *codec = avcodec_find_decoder(videoCodecParameters->codec_id); + const AVCodec *codec = avcodec_find_decoder(videoCodecParameters->codec_id); if (codec) { _codecContext = avcodec_alloc_context3(codec); ret = avcodec_parameters_to_context(_codecContext, videoCodecParameters); @@ -410,7 +409,7 @@ public: .set_rotation(_rotation) .build(); - return VideoStreamingPartFrame(_endpointId, videoFrame, _frame.pts(_videoStream), _frame.duration(_videoStream), _frameIndex); + return VideoStreamingPartFrame(_endpointId, videoFrame, _frame.pts(_videoStream, _firstFramePts), _frameIndex); } else { return absl::nullopt; } @@ -490,6 +489,7 @@ private: std::vector _finalFrames; int _frameIndex = 0; + double _firstFramePts = -1.0; bool _didReadToEnd = false; }; @@ -566,25 +566,33 @@ public: absl::optional getFrameAtRelativeTimestamp(double timestamp) { while (true) { - if (!_currentFrame) { + while (_availableFrames.size() >= 2) { + if (timestamp >= _availableFrames[1].pts) { + _availableFrames.erase(_availableFrames.begin()); + } else { + break; + } + } + + if (_availableFrames.size() < 2) { if (!_parsedVideoParts.empty()) { auto result = _parsedVideoParts[0]->getNextFrame(); if (result) { - _currentFrame = result; - _relativeTimestamp += result->duration; + _availableFrames.push_back(result.value()); } else { _parsedVideoParts.erase(_parsedVideoParts.begin()); - continue; } + continue; } } - if (_currentFrame) { - if (timestamp <= _relativeTimestamp) { - return _currentFrame; - } else { - _currentFrame = absl::nullopt; + if (!_availableFrames.empty()) { + for (size_t i = 1; i < _availableFrames.size(); i++) { + if (timestamp < _availableFrames[i].pts) { + return _availableFrames[i - 1]; + } } + return _availableFrames[_availableFrames.size() - 1]; } else { return absl::nullopt; } @@ -598,6 +606,10 @@ public: return absl::nullopt; } } + + bool hasRemainingFrames() const { + return !_parsedVideoParts.empty(); + } int getAudioRemainingMilliseconds() { while (!_parsedAudioParts.empty()) { @@ -626,8 +638,7 @@ public: private: absl::optional _videoStreamInfo; std::vector> _parsedVideoParts; - absl::optional _currentFrame; - double _relativeTimestamp = 0.0; + std::vector _availableFrames; std::vector> _parsedAudioParts; }; @@ -656,6 +667,12 @@ absl::optional VideoStreamingPart::getActiveEndpointId() const { : absl::nullopt; } +bool VideoStreamingPart::hasRemainingFrames() const { + return _state + ? _state->hasRemainingFrames() + : false; +} + int VideoStreamingPart::getAudioRemainingMilliseconds() { return _state ? _state->getAudioRemainingMilliseconds() diff --git a/TMessagesProj/jni/voip/tgcalls/group/VideoStreamingPart.h b/TMessagesProj/jni/voip/tgcalls/group/VideoStreamingPart.h index 87f7f15d1..16bc0ab4b 100644 --- a/TMessagesProj/jni/voip/tgcalls/group/VideoStreamingPart.h +++ b/TMessagesProj/jni/voip/tgcalls/group/VideoStreamingPart.h @@ -19,14 +19,12 @@ struct VideoStreamingPartFrame { std::string endpointId; webrtc::VideoFrame frame; double pts = 0; - double duration = 0.0; int index = 0; - VideoStreamingPartFrame(std::string endpointId_, webrtc::VideoFrame const &frame_, double pts_, double duration_, int index_) : + VideoStreamingPartFrame(std::string endpointId_, webrtc::VideoFrame const &frame_, double pts_, int index_) : endpointId(endpointId_), frame(frame_), pts(pts_), - duration(duration_), index(index_) { } }; @@ -52,6 +50,7 @@ public: absl::optional getFrameAtRelativeTimestamp(double timestamp); absl::optional getActiveEndpointId() const; + bool hasRemainingFrames() const; int getAudioRemainingMilliseconds(); std::vector getAudio10msPerChannel(AudioStreamingPartPersistentDecoder &persistentDecoder); diff --git a/TMessagesProj/jni/voip/tgcalls/platform/PlatformInterface.h b/TMessagesProj/jni/voip/tgcalls/platform/PlatformInterface.h index b1a588413..234a91a4b 100644 --- a/TMessagesProj/jni/voip/tgcalls/platform/PlatformInterface.h +++ b/TMessagesProj/jni/voip/tgcalls/platform/PlatformInterface.h @@ -297,7 +297,7 @@ public: static PlatformInterface *SharedInstance(); virtual ~PlatformInterface() = default; - virtual void configurePlatformAudio() { + virtual void configurePlatformAudio(int numChannels = 1) { } virtual std::unique_ptr createNetworkMonitorFactory() { diff --git a/TMessagesProj/jni/voip/tgcalls/platform/android/AndroidInterface.cpp b/TMessagesProj/jni/voip/tgcalls/platform/android/AndroidInterface.cpp index 7a968bd90..85067628e 100644 --- a/TMessagesProj/jni/voip/tgcalls/platform/android/AndroidInterface.cpp +++ b/TMessagesProj/jni/voip/tgcalls/platform/android/AndroidInterface.cpp @@ -23,7 +23,7 @@ namespace tgcalls { -void AndroidInterface::configurePlatformAudio() { +void AndroidInterface::configurePlatformAudio(int numChannels) { } diff --git a/TMessagesProj/jni/voip/tgcalls/platform/android/AndroidInterface.h b/TMessagesProj/jni/voip/tgcalls/platform/android/AndroidInterface.h index d2b1820e1..f19374c01 100644 --- a/TMessagesProj/jni/voip/tgcalls/platform/android/AndroidInterface.h +++ b/TMessagesProj/jni/voip/tgcalls/platform/android/AndroidInterface.h @@ -9,7 +9,7 @@ namespace tgcalls { class AndroidInterface : public PlatformInterface { public: - void configurePlatformAudio() override; + void configurePlatformAudio(int numChannels = 1) override; std::unique_ptr makeVideoEncoderFactory(std::shared_ptr platformContext, bool preferHardwareEncoding = false, bool isScreencast = false) override; std::unique_ptr makeVideoDecoderFactory(std::shared_ptr platformContext) override; bool supportsEncoding(const std::string &codecName, std::shared_ptr platformContext) override; diff --git a/TMessagesProj/jni/voip/tgcalls/v2/ContentNegotiation.cpp b/TMessagesProj/jni/voip/tgcalls/v2/ContentNegotiation.cpp new file mode 100644 index 000000000..4ee37c249 --- /dev/null +++ b/TMessagesProj/jni/voip/tgcalls/v2/ContentNegotiation.cpp @@ -0,0 +1,696 @@ +#include "v2/ContentNegotiation.h" + +#include "rtc_base/rtc_certificate_generator.h" + +#include + +namespace tgcalls { + +namespace { + +signaling::MediaContent convertContentInfoToSingalingContent(cricket::ContentInfo const &content) { + signaling::MediaContent mappedContent; + + switch (content.media_description()->type()) { + case cricket::MediaType::MEDIA_TYPE_AUDIO: { + mappedContent.type = signaling::MediaContent::Type::Audio; + + for (const auto &codec : content.media_description()->as_audio()->codecs()) { + signaling::PayloadType mappedPayloadType; + mappedPayloadType.id = codec.id; + mappedPayloadType.name = codec.name; + mappedPayloadType.clockrate = codec.clockrate; + mappedPayloadType.channels = (uint32_t)codec.channels; + + for (const auto &feedbackType : codec.feedback_params.params()) { + signaling::FeedbackType mappedFeedbackType; + mappedFeedbackType.type = feedbackType.id(); + mappedFeedbackType.subtype = feedbackType.param(); + mappedPayloadType.feedbackTypes.push_back(std::move(mappedFeedbackType)); + } + + for (const auto ¶meter : codec.params) { + mappedPayloadType.parameters.push_back(std::make_pair(parameter.first, parameter.second)); + } + std::sort(mappedPayloadType.parameters.begin(), mappedPayloadType.parameters.end(), [](std::pair const &lhs, std::pair const &rhs) -> bool { + return lhs.first < rhs.first; + }); + + mappedContent.payloadTypes.push_back(std::move(mappedPayloadType)); + } + break; + } + case cricket::MediaType::MEDIA_TYPE_VIDEO: { + mappedContent.type = signaling::MediaContent::Type::Video; + + for (const auto &codec : content.media_description()->as_video()->codecs()) { + signaling::PayloadType mappedPayloadType; + mappedPayloadType.id = codec.id; + mappedPayloadType.name = codec.name; + mappedPayloadType.clockrate = codec.clockrate; + mappedPayloadType.channels = 0; + + for (const auto &feedbackType : codec.feedback_params.params()) { + signaling::FeedbackType mappedFeedbackType; + mappedFeedbackType.type = feedbackType.id(); + mappedFeedbackType.subtype = feedbackType.param(); + mappedPayloadType.feedbackTypes.push_back(std::move(mappedFeedbackType)); + } + + for (const auto ¶meter : codec.params) { + mappedPayloadType.parameters.push_back(std::make_pair(parameter.first, parameter.second)); + } + std::sort(mappedPayloadType.parameters.begin(), mappedPayloadType.parameters.end(), [](std::pair const &lhs, std::pair const &rhs) -> bool { + return lhs.first < rhs.first; + }); + + mappedContent.payloadTypes.push_back(std::move(mappedPayloadType)); + } + break; + } + default: { + RTC_FATAL() << "Unknown media type"; + break; + } + } + + if (!content.media_description()->streams().empty()) { + mappedContent.ssrc = content.media_description()->streams()[0].first_ssrc(); + for (const auto &ssrcGroup : content.media_description()->streams()[0].ssrc_groups) { + signaling::SsrcGroup mappedSsrcGroup; + mappedSsrcGroup.semantics = ssrcGroup.semantics; + mappedSsrcGroup.ssrcs = ssrcGroup.ssrcs; + mappedContent.ssrcGroups.push_back(std::move(mappedSsrcGroup)); + } + } + + for (const auto &extension : content.media_description()->rtp_header_extensions()) { + mappedContent.rtpExtensions.push_back(extension); + } + + return mappedContent; +} + +cricket::ContentInfo convertSingalingContentToContentInfo(std::string const &contentId, signaling::MediaContent const &content, webrtc::RtpTransceiverDirection direction) { + std::unique_ptr contentDescription; + + switch (content.type) { + case signaling::MediaContent::Type::Audio: { + auto audioDescription = std::make_unique(); + + for (const auto &payloadType : content.payloadTypes) { + cricket::AudioCodec mappedCodec((int)payloadType.id, payloadType.name, (int)payloadType.clockrate, 0, payloadType.channels); + for (const auto ¶meter : payloadType.parameters) { + mappedCodec.params.insert(parameter); + } + for (const auto &feedbackParam : payloadType.feedbackTypes) { + mappedCodec.AddFeedbackParam(cricket::FeedbackParam(feedbackParam.type, feedbackParam.subtype)); + } + audioDescription->AddCodec(mappedCodec); + } + + contentDescription = std::move(audioDescription); + + break; + } + case signaling::MediaContent::Type::Video: { + auto videoDescription = std::make_unique(); + + for (const auto &payloadType : content.payloadTypes) { + cricket::VideoCodec mappedCodec((int)payloadType.id, payloadType.name); + for (const auto ¶meter : payloadType.parameters) { + mappedCodec.params.insert(parameter); + } + for (const auto &feedbackParam : payloadType.feedbackTypes) { + mappedCodec.AddFeedbackParam(cricket::FeedbackParam(feedbackParam.type, feedbackParam.subtype)); + } + videoDescription->AddCodec(mappedCodec); + } + + contentDescription = std::move(videoDescription); + + break; + } + default: { + RTC_FATAL() << "Unknown media type"; + break; + } + } + + cricket::StreamParams streamParams; + streamParams.id = contentId; + streamParams.set_stream_ids({ contentId }); + streamParams.add_ssrc(content.ssrc); + for (const auto &ssrcGroup : content.ssrcGroups) { + streamParams.ssrc_groups.push_back(cricket::SsrcGroup(ssrcGroup.semantics, ssrcGroup.ssrcs)); + for (const auto &ssrc : ssrcGroup.ssrcs) { + if (!streamParams.has_ssrc(ssrc)) { + streamParams.add_ssrc(ssrc); + } + } + } + contentDescription->AddStream(streamParams); + + for (const auto &extension : content.rtpExtensions) { + contentDescription->AddRtpHeaderExtension(extension); + } + + contentDescription->set_direction(direction); + contentDescription->set_rtcp_mux(true); + + cricket::ContentInfo mappedContentInfo(cricket::MediaProtocolType::kRtp); + mappedContentInfo.name = contentId; + mappedContentInfo.rejected = false; + mappedContentInfo.bundle_only = false; + mappedContentInfo.set_media_description(std::move(contentDescription)); + + return mappedContentInfo; +} + +cricket::ContentInfo createInactiveContentInfo(std::string const &contentId) { + std::unique_ptr contentDescription; + + auto audioDescription = std::make_unique(); + contentDescription = std::move(audioDescription); + + contentDescription->set_direction(webrtc::RtpTransceiverDirection::kInactive); + contentDescription->set_rtcp_mux(true); + + cricket::ContentInfo mappedContentInfo(cricket::MediaProtocolType::kRtp); + mappedContentInfo.name = contentId; + mappedContentInfo.rejected = false; + mappedContentInfo.bundle_only = false; + mappedContentInfo.set_media_description(std::move(contentDescription)); + + return mappedContentInfo; +} + +std::string contentIdBySsrc(uint32_t ssrc) { + std::ostringstream contentIdString; + + contentIdString << ssrc; + + return contentIdString.str(); +} + +} + +ContentNegotiationContext::ContentNegotiationContext(bool isOutgoing, rtc::UniqueRandomIdGenerator *uniqueRandomIdGenerator) : +_isOutgoing(isOutgoing), +_uniqueRandomIdGenerator(uniqueRandomIdGenerator) { + _transportDescriptionFactory = std::make_unique(); + + // tempCertificate is only used to fill in the local SDP + auto tempCertificate = rtc::RTCCertificateGenerator::GenerateCertificate(rtc::KeyParams(rtc::KT_ECDSA), absl::nullopt); + _transportDescriptionFactory->set_secure(cricket::SecurePolicy::SEC_REQUIRED); + _transportDescriptionFactory->set_certificate(tempCertificate); + + _sessionDescriptionFactory = std::make_unique(_transportDescriptionFactory.get(), uniqueRandomIdGenerator); + + _needNegotiation = true; +} + +ContentNegotiationContext::~ContentNegotiationContext() { + +} + +void ContentNegotiationContext::copyCodecsFromChannelManager(cricket::ChannelManager *channelManager, bool randomize) { + cricket::AudioCodecs audioSendCodecs; + cricket::AudioCodecs audioRecvCodecs; + cricket::VideoCodecs videoSendCodecs; + cricket::VideoCodecs videoRecvCodecs; + + channelManager->GetSupportedAudioSendCodecs(&audioSendCodecs); + channelManager->GetSupportedAudioReceiveCodecs(&audioRecvCodecs); + channelManager->GetSupportedVideoSendCodecs(&videoSendCodecs); + channelManager->GetSupportedVideoReceiveCodecs(&videoRecvCodecs); + + for (const auto &codec : audioSendCodecs) { + if (codec.name == "opus") { + audioSendCodecs = { codec }; + audioRecvCodecs = { codec }; + break; + } + } + + if (randomize) { + for (auto &codec : audioSendCodecs) { + codec.id += 3; + } + for (auto &codec : videoSendCodecs) { + codec.id += 3; + } + for (auto &codec : audioRecvCodecs) { + codec.id += 3; + } + for (auto &codec : videoRecvCodecs) { + codec.id += 3; + } + } + + _sessionDescriptionFactory->set_audio_codecs(audioSendCodecs, audioRecvCodecs); + _sessionDescriptionFactory->set_video_codecs(videoSendCodecs, videoRecvCodecs); + + int absSendTimeUriId = 2; + int transportSequenceNumberUriId = 3; + int videoRotationUri = 13; + + if (randomize) { + absSendTimeUriId = 3; + transportSequenceNumberUriId = 2; + videoRotationUri = 4; + } + + _rtpAudioExtensions.emplace_back(webrtc::RtpExtension::kAbsSendTimeUri, absSendTimeUriId); + _rtpAudioExtensions.emplace_back(webrtc::RtpExtension::kTransportSequenceNumberUri, transportSequenceNumberUriId); + + _rtpVideoExtensions.emplace_back(webrtc::RtpExtension::kAbsSendTimeUri, absSendTimeUriId); + _rtpVideoExtensions.emplace_back(webrtc::RtpExtension::kTransportSequenceNumberUri, transportSequenceNumberUriId); + _rtpVideoExtensions.emplace_back(webrtc::RtpExtension::kVideoRotationUri, videoRotationUri); +} + +std::string ContentNegotiationContext::addOutgoingChannel(signaling::MediaContent::Type mediaType) { + std::string channelId = takeNextOutgoingChannelId(); + + cricket::MediaType mappedMediaType; + std::vector rtpExtensions; + switch (mediaType) { + case signaling::MediaContent::Type::Audio: { + mappedMediaType = cricket::MediaType::MEDIA_TYPE_AUDIO; + rtpExtensions = _rtpAudioExtensions; + break; + } + case signaling::MediaContent::Type::Video: { + mappedMediaType = cricket::MediaType::MEDIA_TYPE_VIDEO; + rtpExtensions = _rtpVideoExtensions; + break; + } + default: { + RTC_FATAL() << "Unknown media type"; + break; + } + } + cricket::MediaDescriptionOptions offerDescription(mappedMediaType, channelId, webrtc::RtpTransceiverDirection::kSendOnly, false); + offerDescription.header_extensions = rtpExtensions; + + switch (mediaType) { + case signaling::MediaContent::Type::Audio: { + offerDescription.AddAudioSender(channelId, { channelId }); + break; + } + case signaling::MediaContent::Type::Video: { + cricket::SimulcastLayerList simulcastLayers; + offerDescription.AddVideoSender(channelId, { channelId }, {}, simulcastLayers, 1); + break; + } + default: { + RTC_FATAL() << "Unknown media type"; + break; + } + } + + _outgoingChannelDescriptions.emplace_back(std::move(offerDescription)); + _needNegotiation = true; + + return channelId; +} + +void ContentNegotiationContext::removeOutgoingChannel(std::string const &id) { + for (size_t i = 0; i < _outgoingChannels.size(); i++) { + if (_outgoingChannelDescriptions[i].description.mid == id) { + _outgoingChannelDescriptions.erase(_outgoingChannelDescriptions.begin() + i); + + _needNegotiation = true; + + break; + } + } +} + +std::unique_ptr ContentNegotiationContext::currentSessionDescriptionFromCoordinatedState() { + if (_channelIdOrder.empty()) { + return nullptr; + } + + auto sessionDescription = std::make_unique(); + + for (const auto &id : _channelIdOrder) { + bool found = false; + + for (const auto &channel : _incomingChannels) { + if (contentIdBySsrc(channel.ssrc) == id) { + found = true; + + auto mappedContent = convertSingalingContentToContentInfo(contentIdBySsrc(channel.ssrc), channel, webrtc::RtpTransceiverDirection::kRecvOnly); + + cricket::TransportDescription transportDescription; + cricket::TransportInfo transportInfo(contentIdBySsrc(channel.ssrc), transportDescription); + sessionDescription->AddTransportInfo(transportInfo); + + sessionDescription->AddContent(std::move(mappedContent)); + + break; + } + } + + for (const auto &channel : _outgoingChannels) { + if (channel.id == id) { + found = true; + + auto mappedContent = convertSingalingContentToContentInfo(channel.id, channel.content, webrtc::RtpTransceiverDirection::kSendOnly); + + cricket::TransportDescription transportDescription; + cricket::TransportInfo transportInfo(mappedContent.name, transportDescription); + sessionDescription->AddTransportInfo(transportInfo); + + sessionDescription->AddContent(std::move(mappedContent)); + + break; + } + } + + if (!found) { + auto mappedContent = createInactiveContentInfo("_" + id); + + cricket::TransportDescription transportDescription; + cricket::TransportInfo transportInfo(mappedContent.name, transportDescription); + sessionDescription->AddTransportInfo(transportInfo); + + sessionDescription->AddContent(std::move(mappedContent)); + } + } + + return sessionDescription; +} + +static cricket::MediaDescriptionOptions getIncomingContentDescription(signaling::MediaContent const &content) { + auto mappedContent = convertSingalingContentToContentInfo(contentIdBySsrc(content.ssrc), content, webrtc::RtpTransceiverDirection::kSendOnly); + + cricket::MediaDescriptionOptions contentDescription(mappedContent.media_description()->type(), mappedContent.name, webrtc::RtpTransceiverDirection::kRecvOnly, false); + for (const auto &extension : mappedContent.media_description()->rtp_header_extensions()) { + contentDescription.header_extensions.emplace_back(extension.uri, extension.id); + } + + return contentDescription; +} + +std::unique_ptr ContentNegotiationContext::getPendingOffer() { + if (!_needNegotiation) { + return nullptr; + } + if (_pendingOutgoingOffer) { + return nullptr; + } + + _pendingOutgoingOffer = std::make_unique(); + _pendingOutgoingOffer->exchangeId = _uniqueRandomIdGenerator->GenerateId(); + + auto currentSessionDescription = currentSessionDescriptionFromCoordinatedState(); + + cricket::MediaSessionOptions offerOptions; + offerOptions.offer_extmap_allow_mixed = true; + offerOptions.bundle_enabled = true; + + for (const auto &id : _channelIdOrder) { + bool found = false; + + for (const auto &channel : _outgoingChannelDescriptions) { + if (channel.description.mid == id) { + found = true; + offerOptions.media_description_options.push_back(channel.description); + + break; + } + } + + for (const auto &content : _incomingChannels) { + if (contentIdBySsrc(content.ssrc) == id) { + found = true; + offerOptions.media_description_options.push_back(getIncomingContentDescription(content)); + + break; + } + } + + if (!found) { + cricket::MediaDescriptionOptions contentDescription(cricket::MediaType::MEDIA_TYPE_AUDIO, "_" + id, webrtc::RtpTransceiverDirection::kInactive, false); + offerOptions.media_description_options.push_back(contentDescription); + } + } + + for (const auto &channel : _outgoingChannelDescriptions) { + if (std::find(_channelIdOrder.begin(), _channelIdOrder.end(), channel.description.mid) == _channelIdOrder.end()) { + _channelIdOrder.push_back(channel.description.mid); + + offerOptions.media_description_options.push_back(channel.description); + } + + for (const auto &content : _incomingChannels) { + if (std::find(_channelIdOrder.begin(), _channelIdOrder.end(), contentIdBySsrc(content.ssrc)) == _channelIdOrder.end()) { + _channelIdOrder.push_back(contentIdBySsrc(content.ssrc)); + + offerOptions.media_description_options.push_back(getIncomingContentDescription(content)); + } + } + } + + std::unique_ptr offer = _sessionDescriptionFactory->CreateOffer(offerOptions, currentSessionDescription.get()); + + auto mappedOffer = std::make_unique(); + + mappedOffer->exchangeId = _pendingOutgoingOffer->exchangeId; + + for (const auto &content : offer->contents()) { + auto mappedContent = convertContentInfoToSingalingContent(content); + + if (content.media_description()->direction() == webrtc::RtpTransceiverDirection::kSendOnly) { + mappedOffer->contents.push_back(std::move(mappedContent)); + + for (auto &channel : _outgoingChannelDescriptions) { + if (channel.description.mid == content.mid()) { + channel.ssrc = mappedContent.ssrc; + channel.ssrcGroups = mappedContent.ssrcGroups; + } + } + } + } + + return mappedOffer; +} + +std::unique_ptr ContentNegotiationContext::setRemoteNegotiationContent(std::unique_ptr &&remoteNegotiationContent) { + if (!remoteNegotiationContent) { + return nullptr; + } + + if (_pendingOutgoingOffer) { + if (remoteNegotiationContent->exchangeId == _pendingOutgoingOffer->exchangeId) { + setAnswer(std::move(remoteNegotiationContent)); + return nullptr; + } else { + // race condition detected — call initiator wins + if (!_isOutgoing) { + _pendingOutgoingOffer.reset(); + return getAnswer(std::move(remoteNegotiationContent)); + } else { + return nullptr; + } + } + } else { + return getAnswer(std::move(remoteNegotiationContent)); + } +} + +std::unique_ptr ContentNegotiationContext::getAnswer(std::unique_ptr &&offer) { + auto currentSessionDescription = currentSessionDescriptionFromCoordinatedState(); + + auto mappedOffer = std::make_unique(); + + cricket::MediaSessionOptions answerOptions; + answerOptions.offer_extmap_allow_mixed = true; + answerOptions.bundle_enabled = true; + + for (const auto &id : _channelIdOrder) { + bool found = false; + + for (const auto &channel : _outgoingChannels) { + if (channel.id == id) { + found = true; + + auto mappedContent = convertSingalingContentToContentInfo(channel.id, channel.content, webrtc::RtpTransceiverDirection::kRecvOnly); + + cricket::MediaDescriptionOptions contentDescription(mappedContent.media_description()->type(), mappedContent.name, webrtc::RtpTransceiverDirection::kSendOnly, false); + for (const auto &extension : mappedContent.media_description()->rtp_header_extensions()) { + contentDescription.header_extensions.emplace_back(extension.uri, extension.id); + } + answerOptions.media_description_options.push_back(contentDescription); + + cricket::TransportDescription transportDescription; + cricket::TransportInfo transportInfo(channel.id, transportDescription); + mappedOffer->AddTransportInfo(transportInfo); + + mappedOffer->AddContent(std::move(mappedContent)); + + break; + } + } + + for (const auto &content : offer->contents) { + if (contentIdBySsrc(content.ssrc) == id) { + found = true; + + auto mappedContent = convertSingalingContentToContentInfo(contentIdBySsrc(content.ssrc), content, webrtc::RtpTransceiverDirection::kSendOnly); + + cricket::MediaDescriptionOptions contentDescription(mappedContent.media_description()->type(), mappedContent.name, webrtc::RtpTransceiverDirection::kRecvOnly, false); + for (const auto &extension : mappedContent.media_description()->rtp_header_extensions()) { + contentDescription.header_extensions.emplace_back(extension.uri, extension.id); + } + answerOptions.media_description_options.push_back(contentDescription); + + cricket::TransportDescription transportDescription; + cricket::TransportInfo transportInfo(mappedContent.mid(), transportDescription); + mappedOffer->AddTransportInfo(transportInfo); + + mappedOffer->AddContent(std::move(mappedContent)); + + break; + } + } + + if (!found) { + auto mappedContent = createInactiveContentInfo("_" + id); + + cricket::MediaDescriptionOptions contentDescription(cricket::MediaType::MEDIA_TYPE_AUDIO, "_" + id, webrtc::RtpTransceiverDirection::kInactive, false); + answerOptions.media_description_options.push_back(contentDescription); + + cricket::TransportDescription transportDescription; + cricket::TransportInfo transportInfo(mappedContent.mid(), transportDescription); + mappedOffer->AddTransportInfo(transportInfo); + + mappedOffer->AddContent(std::move(mappedContent)); + } + } + + for (const auto &content : offer->contents) { + if (std::find(_channelIdOrder.begin(), _channelIdOrder.end(), contentIdBySsrc(content.ssrc)) == _channelIdOrder.end()) { + _channelIdOrder.push_back(contentIdBySsrc(content.ssrc)); + + answerOptions.media_description_options.push_back(getIncomingContentDescription(content)); + + auto mappedContent = convertSingalingContentToContentInfo(contentIdBySsrc(content.ssrc), content, webrtc::RtpTransceiverDirection::kSendOnly); + + cricket::TransportDescription transportDescription; + cricket::TransportInfo transportInfo(mappedContent.mid(), transportDescription); + mappedOffer->AddTransportInfo(transportInfo); + + mappedOffer->AddContent(std::move(mappedContent)); + } + } + + std::unique_ptr answer = _sessionDescriptionFactory->CreateAnswer(mappedOffer.get(), answerOptions, currentSessionDescription.get()); + + auto mappedAnswer = std::make_unique(); + + mappedAnswer->exchangeId = offer->exchangeId; + + std::vector incomingChannels; + + for (const auto &content : answer->contents()) { + auto mappedContent = convertContentInfoToSingalingContent(content); + + if (content.media_description()->direction() == webrtc::RtpTransceiverDirection::kRecvOnly) { + for (const auto &offerContent : offer->contents) { + if (contentIdBySsrc(offerContent.ssrc) == content.mid()) { + mappedContent.ssrc = offerContent.ssrc; + mappedContent.ssrcGroups = offerContent.ssrcGroups; + + break; + } + } + + incomingChannels.push_back(mappedContent); + mappedAnswer->contents.push_back(std::move(mappedContent)); + } + } + + _incomingChannels = incomingChannels; + + return mappedAnswer; +} + +void ContentNegotiationContext::setAnswer(std::unique_ptr &&answer) { + if (!_pendingOutgoingOffer) { + return; + } + if (_pendingOutgoingOffer->exchangeId != answer->exchangeId) { + return; + } + + _pendingOutgoingOffer.reset(); + _needNegotiation = false; + + _outgoingChannels.clear(); + + for (const auto &content : answer->contents) { + for (const auto &pendingChannel : _outgoingChannelDescriptions) { + if (pendingChannel.ssrc != 0 && content.ssrc == pendingChannel.ssrc) { + _outgoingChannels.emplace_back(pendingChannel.description.mid, content); + + break; + } + } + } +} + +std::string ContentNegotiationContext::takeNextOutgoingChannelId() { + std::ostringstream result; + result << "m" << _nextOutgoingChannelId; + _nextOutgoingChannelId++; + + return result.str(); +} + +std::unique_ptr ContentNegotiationContext::coordinatedState() const { + auto result = std::make_unique(); + + result->incomingContents = _incomingChannels; + for (const auto &channel : _outgoingChannels) { + bool found = false; + + for (const auto &channelDescription : _outgoingChannelDescriptions) { + if (channelDescription.description.mid == channel.id) { + found = true; + break; + } + } + + if (found) { + result->outgoingContents.push_back(channel.content); + } + } + + return result; +} + +absl::optional ContentNegotiationContext::outgoingChannelSsrc(std::string const &id) const { + for (const auto &channel : _outgoingChannels) { + bool found = false; + + for (const auto &channelDescription : _outgoingChannelDescriptions) { + if (channelDescription.description.mid == channel.id) { + found = true; + break; + } + } + + if (found && channel.id == id) { + if (channel.content.ssrc != 0) { + return channel.content.ssrc; + } + } + } + + return absl::nullopt; +} + +} // namespace tgcalls diff --git a/TMessagesProj/jni/voip/tgcalls/v2/ContentNegotiation.h b/TMessagesProj/jni/voip/tgcalls/v2/ContentNegotiation.h new file mode 100644 index 000000000..53e16d73e --- /dev/null +++ b/TMessagesProj/jni/voip/tgcalls/v2/ContentNegotiation.h @@ -0,0 +1,99 @@ +#ifndef TGCALLS_CONTENT_NEGOTIATION_H +#define TGCALLS_CONTENT_NEGOTIATION_H + +#include + +#include "pc/channel_manager.h" +#include "pc/media_session.h" +#include "pc/session_description.h" +#include "p2p/base/transport_description_factory.h" + +#include "v2/Signaling.h" + +namespace tgcalls { + +class ContentNegotiationContext { +public: + struct NegotiationContents { + uint32_t exchangeId = 0; + std::vector contents; + }; + + struct PendingOutgoingOffer { + uint32_t exchangeId = 0; + }; + + struct PendingOutgoingChannel { + cricket::MediaDescriptionOptions description; + + uint32_t ssrc = 0; + std::vector ssrcGroups; + + PendingOutgoingChannel(cricket::MediaDescriptionOptions &&description_) : + description(std::move(description_)) { + } + }; + + struct OutgoingChannel { + std::string id; + signaling::MediaContent content; + + OutgoingChannel(std::string id_, signaling::MediaContent content_) : + id(id_), content(content_) { + } + }; + + struct CoordinatedState { + std::vector outgoingContents; + std::vector incomingContents; + }; + +public: + ContentNegotiationContext(bool isOutgoing, rtc::UniqueRandomIdGenerator *uniqueRandomIdGenerator); + ~ContentNegotiationContext(); + + void copyCodecsFromChannelManager(cricket::ChannelManager *channelManager, bool randomize); + + std::string addOutgoingChannel(signaling::MediaContent::Type mediaType); + void removeOutgoingChannel(std::string const &id); + + std::unique_ptr getPendingOffer(); + std::unique_ptr setRemoteNegotiationContent(std::unique_ptr &&remoteNegotiationContent); + + std::unique_ptr coordinatedState() const; + absl::optional outgoingChannelSsrc(std::string const &id) const; + +private: + std::string takeNextOutgoingChannelId(); + std::unique_ptr currentSessionDescriptionFromCoordinatedState(); + + std::unique_ptr getAnswer(std::unique_ptr &&offer); + void setAnswer(std::unique_ptr &&answer); + +private: + bool _isOutgoing = false; + rtc::UniqueRandomIdGenerator *_uniqueRandomIdGenerator = nullptr; + + std::unique_ptr _transportDescriptionFactory; + std::unique_ptr _sessionDescriptionFactory; + + std::vector _channelIdOrder; + + std::vector _rtpAudioExtensions; + std::vector _rtpVideoExtensions; + + std::vector _outgoingChannelDescriptions; + bool _needNegotiation = false; + + std::vector _outgoingChannels; + std::vector _incomingChannels; + + std::unique_ptr _pendingOutgoingOffer; + + int _nextOutgoingChannelId = 0; + +}; + +} // namespace tgcalls + +#endif diff --git a/TMessagesProj/jni/voip/tgcalls/v2/InstanceV2Impl.cpp b/TMessagesProj/jni/voip/tgcalls/v2/InstanceV2Impl.cpp index c2962ec65..a8c920815 100644 --- a/TMessagesProj/jni/voip/tgcalls/v2/InstanceV2Impl.cpp +++ b/TMessagesProj/jni/voip/tgcalls/v2/InstanceV2Impl.cpp @@ -5,6 +5,7 @@ #include "VideoCapturerInterface.h" #include "v2/NativeNetworkingImpl.h" #include "v2/Signaling.h" +#include "v2/ContentNegotiation.h" #include "CodecSelectHelper.h" #include "platform/PlatformInterface.h" @@ -32,6 +33,8 @@ #include "api/jsep_ice_candidate.h" #include "pc/used_ids.h" #include "media/base/sdp_video_format_utils.h" +#include "pc/media_session.h" +#include "rtc_base/rtc_certificate_generator.h" #include "AudioFrame.h" #include "ThreadLocalObject.h" @@ -49,479 +52,18 @@ #include #include +#include "third-party/json11.hpp" + namespace tgcalls { namespace { -static std::string intToString(int value) { - std::ostringstream stringStream; - stringStream << value; - return stringStream.str(); -} - static VideoCaptureInterfaceObject *GetVideoCaptureAssumingSameThread(VideoCaptureInterface *videoCapture) { return videoCapture ? static_cast(videoCapture)->object()->getSyncAssumingSameThread() : nullptr; } -struct OutgoingVideoFormat { - cricket::VideoCodec videoCodec; - absl::optional rtxCodec; -}; - -static void addDefaultFeedbackParams(cricket::VideoCodec *codec) { - // Don't add any feedback params for RED and ULPFEC. - if (codec->name == cricket::kRedCodecName || codec->name == cricket::kUlpfecCodecName) { - return; - } - codec->AddFeedbackParam(cricket::FeedbackParam(cricket::kRtcpFbParamRemb, cricket::kParamValueEmpty)); - codec->AddFeedbackParam(cricket::FeedbackParam(cricket::kRtcpFbParamTransportCc, cricket::kParamValueEmpty)); - // Don't add any more feedback params for FLEXFEC. - if (codec->name == cricket::kFlexfecCodecName) { - return; - } - codec->AddFeedbackParam(cricket::FeedbackParam(cricket::kRtcpFbParamCcm, cricket::kRtcpFbCcmParamFir)); - codec->AddFeedbackParam(cricket::FeedbackParam(cricket::kRtcpFbParamNack, cricket::kParamValueEmpty)); - codec->AddFeedbackParam(cricket::FeedbackParam(cricket::kRtcpFbParamNack, cricket::kRtcpFbNackParamPli)); -} - -template -static bool IsRtxCodec(const C& codec) { - return absl::EqualsIgnoreCase(codec.name, cricket::kRtxCodecName); -} - -template -static bool ReferencedCodecsMatch(const std::vector& codecs1, - const int codec1_id, - const std::vector& codecs2, - const int codec2_id) { - const C* codec1 = FindCodecById(codecs1, codec1_id); - const C* codec2 = FindCodecById(codecs2, codec2_id); - return codec1 != nullptr && codec2 != nullptr && codec1->Matches(*codec2); -} - -// Finds a codec in |codecs2| that matches |codec_to_match|, which is -// a member of |codecs1|. If |codec_to_match| is an RTX codec, both -// the codecs themselves and their associated codecs must match. -template -static bool FindMatchingCodec(const std::vector& codecs1, - const std::vector& codecs2, - const C& codec_to_match, - C* found_codec) { - // |codec_to_match| should be a member of |codecs1|, in order to look up RTX - // codecs' associated codecs correctly. If not, that's a programming error. - RTC_DCHECK(absl::c_any_of(codecs1, [&codec_to_match](const C& codec) { - return &codec == &codec_to_match; - })); - for (const C& potential_match : codecs2) { - if (potential_match.Matches(codec_to_match)) { - if (IsRtxCodec(codec_to_match)) { - int apt_value_1 = 0; - int apt_value_2 = 0; - if (!codec_to_match.GetParam(cricket::kCodecParamAssociatedPayloadType, - &apt_value_1) || - !potential_match.GetParam(cricket::kCodecParamAssociatedPayloadType, - &apt_value_2)) { - RTC_LOG(LS_WARNING) << "RTX missing associated payload type."; - continue; - } - if (!ReferencedCodecsMatch(codecs1, apt_value_1, codecs2, - apt_value_2)) { - continue; - } - } - if (found_codec) { - *found_codec = potential_match; - } - return true; - } - } - return false; -} - -template -static void NegotiatePacketization(const C& local_codec, - const C& remote_codec, - C* negotiated_codec) {} - -template <> -void NegotiatePacketization(const cricket::VideoCodec& local_codec, - const cricket::VideoCodec& remote_codec, - cricket::VideoCodec* negotiated_codec) { - negotiated_codec->packetization = - cricket::VideoCodec::IntersectPacketization(local_codec, remote_codec); -} - -template -static void NegotiateCodecs(const std::vector& local_codecs, - const std::vector& offered_codecs, - std::vector* negotiated_codecs, - bool keep_offer_order) { - for (const C& ours : local_codecs) { - C theirs; - // Note that we intentionally only find one matching codec for each of our - // local codecs, in case the remote offer contains duplicate codecs. - if (FindMatchingCodec(local_codecs, offered_codecs, ours, &theirs)) { - C negotiated = ours; - NegotiatePacketization(ours, theirs, &negotiated); - negotiated.IntersectFeedbackParams(theirs); - if (IsRtxCodec(negotiated)) { - const auto apt_it = - theirs.params.find(cricket::kCodecParamAssociatedPayloadType); - // FindMatchingCodec shouldn't return something with no apt value. - RTC_DCHECK(apt_it != theirs.params.end()); - negotiated.SetParam(cricket::kCodecParamAssociatedPayloadType, apt_it->second); - } - if (absl::EqualsIgnoreCase(ours.name, cricket::kH264CodecName)) { - webrtc::H264GenerateProfileLevelIdForAnswer( - ours.params, theirs.params, &negotiated.params); - } - negotiated.id = theirs.id; - negotiated.name = theirs.name; - negotiated_codecs->push_back(std::move(negotiated)); - } - } - if (keep_offer_order) { - // RFC3264: Although the answerer MAY list the formats in their desired - // order of preference, it is RECOMMENDED that unless there is a - // specific reason, the answerer list formats in the same relative order - // they were present in the offer. - // This can be skipped when the transceiver has any codec preferences. - std::unordered_map payload_type_preferences; - int preference = static_cast(offered_codecs.size() + 1); - for (const C& codec : offered_codecs) { - payload_type_preferences[codec.id] = preference--; - } - absl::c_sort(*negotiated_codecs, [&payload_type_preferences](const C& a, - const C& b) { - return payload_type_preferences[a.id] > payload_type_preferences[b.id]; - }); - } -} - -// Find the codec in |codec_list| that |rtx_codec| is associated with. -template -static const C* GetAssociatedCodec(const std::vector& codec_list, - const C& rtx_codec) { - std::string associated_pt_str; - if (!rtx_codec.GetParam(cricket::kCodecParamAssociatedPayloadType, - &associated_pt_str)) { - RTC_LOG(LS_WARNING) << "RTX codec " << rtx_codec.name - << " is missing an associated payload type."; - return nullptr; - } - - int associated_pt; - if (!rtc::FromString(associated_pt_str, &associated_pt)) { - RTC_LOG(LS_WARNING) << "Couldn't convert payload type " << associated_pt_str - << " of RTX codec " << rtx_codec.name - << " to an integer."; - return nullptr; - } - - // Find the associated reference codec for the reference RTX codec. - const C* associated_codec = FindCodecById(codec_list, associated_pt); - if (!associated_codec) { - RTC_LOG(LS_WARNING) << "Couldn't find associated codec with payload type " - << associated_pt << " for RTX codec " << rtx_codec.name - << "."; - } - return associated_codec; -} - -// Adds all codecs from |reference_codecs| to |offered_codecs| that don't -// already exist in |offered_codecs| and ensure the payload types don't -// collide. -template -static void MergeCodecs(const std::vector& reference_codecs, - std::vector* offered_codecs, - cricket::UsedPayloadTypes* used_pltypes) { - // Add all new codecs that are not RTX codecs. - for (const C& reference_codec : reference_codecs) { - if (!IsRtxCodec(reference_codec) && - !FindMatchingCodec(reference_codecs, *offered_codecs, - reference_codec, nullptr)) { - C codec = reference_codec; - used_pltypes->FindAndSetIdUsed(&codec); - offered_codecs->push_back(codec); - } - } - - // Add all new RTX codecs. - for (const C& reference_codec : reference_codecs) { - if (IsRtxCodec(reference_codec) && - !FindMatchingCodec(reference_codecs, *offered_codecs, - reference_codec, nullptr)) { - C rtx_codec = reference_codec; - const C* associated_codec = - GetAssociatedCodec(reference_codecs, rtx_codec); - if (!associated_codec) { - continue; - } - // Find a codec in the offered list that matches the reference codec. - // Its payload type may be different than the reference codec. - C matching_codec; - if (!FindMatchingCodec(reference_codecs, *offered_codecs, - *associated_codec, &matching_codec)) { - RTC_LOG(LS_WARNING) - << "Couldn't find matching " << associated_codec->name << " codec."; - continue; - } - - rtx_codec.params[cricket::kCodecParamAssociatedPayloadType] = - rtc::ToString(matching_codec.id); - used_pltypes->FindAndSetIdUsed(&rtx_codec); - offered_codecs->push_back(rtx_codec); - } - } -} - -static std::vector generateAvailableVideoFormats(std::vector const &formats) { - if (formats.empty()) { - return {}; - } - - constexpr int kFirstDynamicPayloadType = 100; - constexpr int kLastDynamicPayloadType = 127; - - int payload_type = kFirstDynamicPayloadType; - - std::vector result; - - //bool codecSelected = false; - - for (const auto &format : formats) { - /*if (codecSelected) { - break; - }*/ - - bool alreadyAdded = false; - for (const auto &it : result) { - if (it.videoCodec.name == format.name) { - alreadyAdded = true; - break; - } - } - if (alreadyAdded) { - continue; - } - - OutgoingVideoFormat resultFormat; - - cricket::VideoCodec codec(format); - codec.id = payload_type; - addDefaultFeedbackParams(&codec); - - resultFormat.videoCodec = codec; - //codecSelected = true; - - // Increment payload type. - ++payload_type; - if (payload_type > kLastDynamicPayloadType) { - RTC_LOG(LS_ERROR) << "Out of dynamic payload types, skipping the rest."; - break; - } - - // Add associated RTX codec for non-FEC codecs. - if (!absl::EqualsIgnoreCase(codec.name, cricket::kUlpfecCodecName) && - !absl::EqualsIgnoreCase(codec.name, cricket::kFlexfecCodecName)) { - resultFormat.rtxCodec = cricket::VideoCodec::CreateRtxCodec(payload_type, codec.id); - - // Increment payload type. - ++payload_type; - if (payload_type > kLastDynamicPayloadType) { - RTC_LOG(LS_ERROR) << "Out of dynamic payload types, skipping the rest."; - break; - } - } - - result.push_back(std::move(resultFormat)); - } - return result; -} - -static void getCodecsFromMediaContent(signaling::MediaContent const &content, std::vector &codecs) { - for (const auto &payloadType : content.payloadTypes) { - cricket::VideoCodec codec(payloadType.id, payloadType.name); - for (const auto &feedbackType : payloadType.feedbackTypes) { - codec.AddFeedbackParam(cricket::FeedbackParam(feedbackType.type, feedbackType.subtype)); - } - for (const auto ¶meter : payloadType.parameters) { - codec.SetParam(parameter.first, parameter.second); - } - codecs.push_back(std::move(codec)); - } -} - -static std::vector getPayloadTypesFromVideoCodecs(std::vector const &codecs) { - std::vector payloadTypes; - - for (const auto &codec : codecs) { - signaling::PayloadType payloadType; - - payloadType.id = codec.id; - payloadType.name = codec.name; - payloadType.clockrate = 90000; - payloadType.channels = 0; - - for (const auto &feedbackParam : codec.feedback_params.params()) { - signaling::FeedbackType feedbackType; - feedbackType.type = feedbackParam.id(); - feedbackType.subtype = feedbackParam.param(); - payloadType.feedbackTypes.push_back(std::move(feedbackType)); - } - - for (const auto ¶m : codec.params) { - payloadType.parameters.push_back(std::make_pair(param.first, param.second)); - } - - payloadTypes.push_back(std::move(payloadType)); - } - - return payloadTypes; -} - -static void getCodecsFromMediaContent(signaling::MediaContent const &content, std::vector &codecs) { - for (const auto &payloadType : content.payloadTypes) { - cricket::AudioCodec codec(payloadType.id, payloadType.name, payloadType.clockrate, 0, payloadType.channels); - for (const auto &feedbackType : payloadType.feedbackTypes) { - codec.AddFeedbackParam(cricket::FeedbackParam(feedbackType.type, feedbackType.subtype)); - } - for (const auto ¶meter : payloadType.parameters) { - codec.SetParam(parameter.first, parameter.second); - } - codecs.push_back(std::move(codec)); - } -} - -static std::vector getPayloadTypesFromAudioCodecs(std::vector const &codecs) { - std::vector payloadTypes; - - for (const auto &codec : codecs) { - signaling::PayloadType payloadType; - - payloadType.id = codec.id; - payloadType.name = codec.name; - payloadType.clockrate = codec.clockrate; - payloadType.channels = (uint32_t)codec.channels; - - for (const auto &feedbackParam : codec.feedback_params.params()) { - signaling::FeedbackType feedbackType; - feedbackType.type = feedbackParam.id(); - feedbackType.subtype = feedbackParam.param(); - payloadType.feedbackTypes.push_back(std::move(feedbackType)); - } - - for (const auto ¶m : codec.params) { - payloadType.parameters.push_back(std::make_pair(param.first, param.second)); - } - - payloadTypes.push_back(std::move(payloadType)); - } - - return payloadTypes; -} - -template -struct NegotiatedMediaContent { - uint32_t ssrc = 0; - std::vector ssrcGroups; - std::vector rtpExtensions; - std::vector codecs; -}; - -static bool FindByUri(const cricket::RtpHeaderExtensions& extensions, - const webrtc::RtpExtension& ext_to_match, - webrtc::RtpExtension* found_extension) { - // We assume that all URIs are given in a canonical format. - const webrtc::RtpExtension* found = - webrtc::RtpExtension::FindHeaderExtensionByUri( - extensions, - ext_to_match.uri, - webrtc::RtpExtension::Filter::kPreferEncryptedExtension - ); - if (!found) { - return false; - } - if (found_extension) { - *found_extension = *found; - } - return true; -} - -template -static NegotiatedMediaContent negotiateMediaContent(signaling::MediaContent const &baseMediaContent, signaling::MediaContent const &localContent, signaling::MediaContent const &remoteContent, bool isAnswer) { - std::vector localCodecs; - getCodecsFromMediaContent(localContent, localCodecs); - - std::vector remoteCodecs; - getCodecsFromMediaContent(remoteContent, remoteCodecs); - - std::vector negotiatedCodecs; - - cricket::UsedPayloadTypes usedPayloadTypes; - NegotiateCodecs(localCodecs, remoteCodecs, &negotiatedCodecs, true); - - NegotiatedMediaContent result; - - result.ssrc = baseMediaContent.ssrc; - result.ssrcGroups = baseMediaContent.ssrcGroups; - result.codecs = std::move(negotiatedCodecs); - - cricket::UsedRtpHeaderExtensionIds extensionIds(cricket::UsedRtpHeaderExtensionIds::IdDomain::kOneByteOnly); - - for (const auto &extension : remoteContent.rtpExtensions) { - if (isAnswer) { - webrtc::RtpExtension found; - if (!FindByUri(localContent.rtpExtensions, extension, &found)) { - continue; - } - } - - webrtc::RtpExtension mutableExtension = extension; - extensionIds.FindAndSetIdUsed(&mutableExtension); - result.rtpExtensions.push_back(std::move(mutableExtension)); - } - - if (!isAnswer) { - for (const auto &extension : localContent.rtpExtensions) { - webrtc::RtpExtension found; - if (!FindByUri(result.rtpExtensions, extension, &found)) { - webrtc::RtpExtension mutableExtension = extension; - extensionIds.FindAndSetIdUsed(&mutableExtension); - result.rtpExtensions.push_back(std::move(mutableExtension)); - } - } - } - - return result; -} - class OutgoingAudioChannel : public sigslot::has_slots<> { -public: - static absl::optional createOutgoingContentDescription() { - signaling::MediaContent mediaContent; - - auto generator = std::mt19937(std::random_device()()); - auto distribution = std::uniform_int_distribution(); - do { - mediaContent.ssrc = distribution(generator) & 0x7fffffffU; - } while (!mediaContent.ssrc); - - mediaContent.rtpExtensions.emplace_back(webrtc::RtpExtension::kAudioLevelUri, 1); - mediaContent.rtpExtensions.emplace_back(webrtc::RtpExtension::kAbsSendTimeUri, 2); - mediaContent.rtpExtensions.emplace_back(webrtc::RtpExtension::kTransportSequenceNumberUri, 3); - - cricket::AudioCodec opusCodec(109, "opus", 48000, 0, 2); - opusCodec.AddFeedbackParam(cricket::FeedbackParam(cricket::kRtcpFbParamTransportCc)); - opusCodec.SetParam(cricket::kCodecParamUseInbandFec, 1); - opusCodec.SetParam(cricket::kCodecParamMinPTime, 60); - - mediaContent.payloadTypes = getPayloadTypesFromAudioCodecs({ opusCodec }); - - return mediaContent; - } - public: OutgoingAudioChannel( webrtc::Call *call, @@ -529,7 +71,7 @@ public: rtc::UniqueRandomIdGenerator *uniqueRandomIdGenerator, webrtc::LocalAudioSinkAdapter *audioSource, webrtc::RtpTransport *rtpTransport, - NegotiatedMediaContent const &mediaContent, + signaling::MediaContent const &mediaContent, std::shared_ptr threads ) : _threads(threads), @@ -553,29 +95,30 @@ public: audioOptions.echo_cancellation = true; audioOptions.noise_suppression = true; } + + std::ostringstream contentId; + contentId << _ssrc; std::vector streamIds; - streamIds.push_back("1"); + streamIds.push_back(contentId.str()); - _outgoingAudioChannel = _channelManager->CreateVoiceChannel(call, cricket::MediaConfig(), rtpTransport, threads->getMediaThread(), "audio0", false, NativeNetworkingImpl::getDefaulCryptoOptions(), uniqueRandomIdGenerator, audioOptions); + _outgoingAudioChannel = _channelManager->CreateVoiceChannel(call, cricket::MediaConfig(), rtpTransport, threads->getMediaThread(), contentId.str(), false, NativeNetworkingImpl::getDefaulCryptoOptions(), uniqueRandomIdGenerator, audioOptions); std::vector codecs; - for (const auto &codec : mediaContent.codecs) { - if (codec.name == "opus") { - auto mutableCodec = codec; + for (const auto &payloadType : mediaContent.payloadTypes) { + if (payloadType.name == "opus") { + cricket::AudioCodec codec(payloadType.id, payloadType.name, payloadType.clockrate, 0, payloadType.channels); - const uint8_t opusMinBitrateKbps = 16; - const uint8_t opusMaxBitrateKbps = 32; - const uint8_t opusStartBitrateKbps = 32; - const uint8_t opusPTimeMs = 60; + codec.SetParam(cricket::kCodecParamUseInbandFec, 1); + codec.SetParam(cricket::kCodecParamPTime, 60); + + for (const auto &feedbackType : payloadType.feedbackTypes) { + codec.AddFeedbackParam(cricket::FeedbackParam(feedbackType.type, feedbackType.subtype)); + } - mutableCodec.SetParam(cricket::kCodecParamMinBitrate, opusMinBitrateKbps); - mutableCodec.SetParam(cricket::kCodecParamStartBitrate, opusStartBitrateKbps); - mutableCodec.SetParam(cricket::kCodecParamMaxBitrate, opusMaxBitrateKbps); - mutableCodec.SetParam(cricket::kCodecParamUseInbandFec, 1); - mutableCodec.SetParam(cricket::kCodecParamPTime, opusPTimeMs); - - codecs.push_back(std::move(mutableCodec)); + codecs.push_back(std::move(codec)); + + break; } } @@ -606,14 +149,10 @@ public: _outgoingAudioChannel->SetRemoteContent(incomingAudioDescription.get(), webrtc::SdpType::kAnswer, nullptr); }); - //_outgoingAudioChannel->SignalSentPacket().connect(this, &OutgoingAudioChannel::OnSentPacket_w); - //_outgoingAudioChannel->UpdateRtpTransport(nullptr); - setIsMuted(false); } ~OutgoingAudioChannel() { - //_outgoingAudioChannel->SignalSentPacket().disconnect(this); _outgoingAudioChannel->Enable(false); _channelManager->DestroyVoiceChannel(_outgoingAudioChannel); _outgoingAudioChannel = nullptr; @@ -629,6 +168,27 @@ public: }); } } + + uint32_t ssrc() const { + return _ssrc; + } + + void setMaxBitrate(int bitrate) { + _threads->getWorkerThread()->Invoke(RTC_FROM_HERE, [&]() { + webrtc::RtpParameters initialParameters = _outgoingAudioChannel->media_channel()->GetRtpSendParameters(_ssrc); + webrtc::RtpParameters updatedParameters = initialParameters; + + if (updatedParameters.encodings.empty()) { + updatedParameters.encodings.push_back(webrtc::RtpEncodingParameters()); + } + + updatedParameters.encodings[0].max_bitrate_bps = bitrate; + + if (initialParameters != updatedParameters) { + _outgoingAudioChannel->media_channel()->SetRtpSendParameters(_ssrc, updatedParameters); + } + }); + } private: void OnSentPacket_w(const rtc::SentPacket& sent_packet) { @@ -653,7 +213,7 @@ public: webrtc::Call *call, webrtc::RtpTransport *rtpTransport, rtc::UniqueRandomIdGenerator *randomIdGenerator, - NegotiatedMediaContent const &mediaContent, + signaling::MediaContent const &mediaContent, std::shared_ptr threads) : _ssrc(mediaContent.ssrc), _channelManager(channelManager), @@ -663,12 +223,25 @@ public: cricket::AudioOptions audioOptions; audioOptions.audio_jitter_buffer_fast_accelerate = true; audioOptions.audio_jitter_buffer_min_delay_ms = 50; + + std::ostringstream contentId; + contentId << _ssrc; - std::string streamId = std::string("stream1"); + std::string streamId = contentId.str(); - _audioChannel = _channelManager->CreateVoiceChannel(call, cricket::MediaConfig(), rtpTransport, threads->getMediaThread(), "0", false, NativeNetworkingImpl::getDefaulCryptoOptions(), randomIdGenerator, audioOptions); + _audioChannel = _channelManager->CreateVoiceChannel(call, cricket::MediaConfig(), rtpTransport, threads->getMediaThread(), contentId.str(), false, NativeNetworkingImpl::getDefaulCryptoOptions(), randomIdGenerator, audioOptions); - auto audioCodecs = mediaContent.codecs; + std::vector codecs; + for (const auto &payloadType : mediaContent.payloadTypes) { + cricket::AudioCodec codec(payloadType.id, payloadType.name, payloadType.clockrate, 0, payloadType.channels); + for (const auto ¶meter : payloadType.parameters) { + codec.SetParam(parameter.first, parameter.second); + } + for (const auto &feedbackType : payloadType.feedbackTypes) { + codec.AddFeedbackParam(cricket::FeedbackParam(feedbackType.type, feedbackType.subtype)); + } + codecs.push_back(std::move(codec)); + } auto outgoingAudioDescription = std::make_unique(); for (const auto &rtpExtension : mediaContent.rtpExtensions) { @@ -677,7 +250,7 @@ public: outgoingAudioDescription->set_rtcp_mux(true); outgoingAudioDescription->set_rtcp_reduced_size(true); outgoingAudioDescription->set_direction(webrtc::RtpTransceiverDirection::kRecvOnly); - outgoingAudioDescription->set_codecs(audioCodecs); + outgoingAudioDescription->set_codecs(codecs); outgoingAudioDescription->set_bandwidth(-1); auto incomingAudioDescription = std::make_unique(); @@ -687,7 +260,7 @@ public: incomingAudioDescription->set_rtcp_mux(true); incomingAudioDescription->set_rtcp_reduced_size(true); incomingAudioDescription->set_direction(webrtc::RtpTransceiverDirection::kSendOnly); - incomingAudioDescription->set_codecs(audioCodecs); + incomingAudioDescription->set_codecs(codecs); incomingAudioDescription->set_bandwidth(-1); cricket::StreamParams streamParams = cricket::StreamParams::CreateLegacy(mediaContent.ssrc); streamParams.set_stream_ids({ streamId }); @@ -725,6 +298,10 @@ public: int64_t getActivity() { return _activityTimestamp; } + + uint32_t ssrc() const { + return _ssrc; + } private: void OnSentPacket_w(const rtc::SentPacket& sent_packet) { @@ -743,101 +320,6 @@ private: }; class OutgoingVideoChannel : public sigslot::has_slots<>, public std::enable_shared_from_this { -public: - static absl::optional createOutgoingContentDescription(std::vector const &availableVideoFormats, bool isScreencast) { - signaling::MediaContent mediaContent; - - auto generator = std::mt19937(std::random_device()()); - auto distribution = std::uniform_int_distribution(); - do { - mediaContent.ssrc = distribution(generator) & 0x7fffffffU; - } while (!mediaContent.ssrc); - - mediaContent.rtpExtensions.emplace_back(webrtc::RtpExtension::kAbsSendTimeUri, 2); - mediaContent.rtpExtensions.emplace_back(webrtc::RtpExtension::kTransportSequenceNumberUri, 3); - mediaContent.rtpExtensions.emplace_back(webrtc::RtpExtension::kVideoRotationUri, 13); - - signaling::SsrcGroup fidGroup; - fidGroup.semantics = "FID"; - fidGroup.ssrcs.push_back(mediaContent.ssrc); - fidGroup.ssrcs.push_back(mediaContent.ssrc + 1); - mediaContent.ssrcGroups.push_back(std::move(fidGroup)); - - auto unsortedVideoFormats = generateAvailableVideoFormats(availableVideoFormats); - - std::vector formatPreferences; - if (isScreencast) { - formatPreferences.push_back(cricket::kVp8CodecName); - } else { -#ifndef WEBRTC_DISABLE_H265 - formatPreferences.push_back(cricket::kH265CodecName); -#endif - formatPreferences.push_back(cricket::kH264CodecName); - } - - std::vector videoFormats; - for (const auto &name : formatPreferences) { - for (size_t i = 0; i < unsortedVideoFormats.size(); i++) { - if (absl::EqualsIgnoreCase(name, unsortedVideoFormats[i].videoCodec.name)) { - videoFormats.push_back(unsortedVideoFormats[i]); - unsortedVideoFormats.erase(unsortedVideoFormats.begin() + i); - break; - } - } - } - for (const auto &format : unsortedVideoFormats) { - videoFormats.push_back(format); - } - - for (const auto &format : videoFormats) { - signaling::PayloadType videoPayload; - videoPayload.id = format.videoCodec.id; - videoPayload.name = format.videoCodec.name; - videoPayload.clockrate = format.videoCodec.clockrate; - videoPayload.channels = 0; - - std::vector videoFeedbackTypes; - - signaling::FeedbackType fbGoogRemb; - fbGoogRemb.type = "goog-remb"; - videoFeedbackTypes.push_back(fbGoogRemb); - - signaling::FeedbackType fbTransportCc; - fbTransportCc.type = "transport-cc"; - videoFeedbackTypes.push_back(fbTransportCc); - - signaling::FeedbackType fbCcmFir; - fbCcmFir.type = "ccm"; - fbCcmFir.subtype = "fir"; - videoFeedbackTypes.push_back(fbCcmFir); - - signaling::FeedbackType fbNack; - fbNack.type = "nack"; - videoFeedbackTypes.push_back(fbNack); - - signaling::FeedbackType fbNackPli; - fbNackPli.type = "nack"; - fbNackPli.subtype = "pli"; - videoFeedbackTypes.push_back(fbNackPli); - - videoPayload.feedbackTypes = videoFeedbackTypes; - videoPayload.parameters = {}; - - mediaContent.payloadTypes.push_back(std::move(videoPayload)); - - if (format.rtxCodec) { - signaling::PayloadType rtxPayload; - rtxPayload.id = format.rtxCodec->id; - rtxPayload.name = format.rtxCodec->name; - rtxPayload.clockrate = format.rtxCodec->clockrate; - rtxPayload.parameters.push_back(std::make_pair("apt", intToString(videoPayload.id))); - mediaContent.payloadTypes.push_back(std::move(rtxPayload)); - } - } - - return mediaContent; - } - public: OutgoingVideoChannel( std::shared_ptr threads, @@ -847,7 +329,7 @@ public: rtc::UniqueRandomIdGenerator *randomIdGenerator, webrtc::VideoBitrateAllocatorFactory *videoBitrateAllocatorFactory, std::function rotationUpdated, - NegotiatedMediaContent const &mediaContent, + signaling::MediaContent const &mediaContent, bool isScreencast ) : _threads(threads), @@ -857,9 +339,44 @@ public: _rotationUpdated(rotationUpdated) { cricket::VideoOptions videoOptions; videoOptions.is_screencast = isScreencast; - _outgoingVideoChannel = _channelManager->CreateVideoChannel(call, cricket::MediaConfig(), rtpTransport, threads->getMediaThread(), "out" + intToString(mediaContent.ssrc), false, NativeNetworkingImpl::getDefaulCryptoOptions(), randomIdGenerator, videoOptions, videoBitrateAllocatorFactory); + + std::ostringstream contentId; + contentId << mediaContent.ssrc; + + _outgoingVideoChannel = _channelManager->CreateVideoChannel(call, cricket::MediaConfig(), rtpTransport, threads->getMediaThread(), contentId.str(), false, NativeNetworkingImpl::getDefaulCryptoOptions(), randomIdGenerator, videoOptions, videoBitrateAllocatorFactory); - auto videoCodecs = mediaContent.codecs; + std::vector unsortedCodecs; + for (const auto &payloadType : mediaContent.payloadTypes) { + cricket::VideoCodec codec(payloadType.id, payloadType.name); + for (const auto ¶meter : payloadType.parameters) { + codec.SetParam(parameter.first, parameter.second); + } + for (const auto &feedbackType : payloadType.feedbackTypes) { + codec.AddFeedbackParam(cricket::FeedbackParam(feedbackType.type, feedbackType.subtype)); + } + unsortedCodecs.push_back(std::move(codec)); + } + + std::vector codecPreferences = { +#ifndef WEBRTC_DISABLE_H265 + cricket::kH265CodecName, +#endif + cricket::kH264CodecName + }; + + std::vector codecs; + for (const auto &name : codecPreferences) { + for (const auto &codec : unsortedCodecs) { + if (codec.name == name) { + codecs.push_back(codec); + } + } + } + for (const auto &codec : unsortedCodecs) { + if (std::find(codecs.begin(), codecs.end(), codec) == codecs.end()) { + codecs.push_back(codec); + } + } auto outgoingVideoDescription = std::make_unique(); for (const auto &rtpExtension : mediaContent.rtpExtensions) { @@ -869,14 +386,16 @@ public: outgoingVideoDescription->set_rtcp_mux(true); outgoingVideoDescription->set_rtcp_reduced_size(true); outgoingVideoDescription->set_direction(webrtc::RtpTransceiverDirection::kSendOnly); - outgoingVideoDescription->set_codecs(videoCodecs); + outgoingVideoDescription->set_codecs(codecs); outgoingVideoDescription->set_bandwidth(-1); cricket::StreamParams videoSendStreamParams; for (const auto &ssrcGroup : mediaContent.ssrcGroups) { for (auto ssrc : ssrcGroup.ssrcs) { - videoSendStreamParams.ssrcs.push_back(ssrc); + if (!videoSendStreamParams.has_ssrc(ssrc)) { + videoSendStreamParams.ssrcs.push_back(ssrc); + } } cricket::SsrcGroup mappedGroup(ssrcGroup.semantics, ssrcGroup.ssrcs); @@ -894,7 +413,7 @@ public: incomingVideoDescription->set_rtcp_mux(true); incomingVideoDescription->set_rtcp_reduced_size(true); incomingVideoDescription->set_direction(webrtc::RtpTransceiverDirection::kRecvOnly); - incomingVideoDescription->set_codecs(videoCodecs); + incomingVideoDescription->set_codecs(codecs); incomingVideoDescription->set_bandwidth(-1); threads->getWorkerThread()->Invoke(RTC_FROM_HERE, [&]() { @@ -903,6 +422,10 @@ public: _outgoingVideoChannel->SetRemoteContent(incomingVideoDescription.get(), webrtc::SdpType::kAnswer, nullptr); webrtc::RtpParameters rtpParameters = _outgoingVideoChannel->media_channel()->GetRtpSendParameters(mediaContent.ssrc); + + if (isScreencast) { + rtpParameters.degradation_preference = webrtc::DegradationPreference::MAINTAIN_RESOLUTION; + } _outgoingVideoChannel->media_channel()->SetRtpSendParameters(mediaContent.ssrc, rtpParameters); }); @@ -999,6 +522,27 @@ public: }); } } + + uint32_t ssrc() const { + return _mainSsrc; + } + + void setMaxBitrate(int bitrate) { + _threads->getWorkerThread()->Invoke(RTC_FROM_HERE, [&]() { + webrtc::RtpParameters initialParameters = _outgoingVideoChannel->media_channel()->GetRtpSendParameters(_mainSsrc); + webrtc::RtpParameters updatedParameters = initialParameters; + + if (updatedParameters.encodings.empty()) { + updatedParameters.encodings.push_back(webrtc::RtpEncodingParameters()); + } + + updatedParameters.encodings[0].max_bitrate_bps = bitrate; + + if (initialParameters != updatedParameters) { + _outgoingVideoChannel->media_channel()->SetRtpSendParameters(_mainSsrc, updatedParameters); + } + }); + } public: std::shared_ptr videoCapture() { @@ -1081,18 +625,30 @@ public: webrtc::Call *call, webrtc::RtpTransport *rtpTransport, rtc::UniqueRandomIdGenerator *randomIdGenerator, - NegotiatedMediaContent const &mediaContent, - std::string const &streamId, + signaling::MediaContent const &mediaContent, std::shared_ptr threads) : _channelManager(channelManager), _call(call) { _videoSink.reset(new VideoSinkImpl()); _videoBitrateAllocatorFactory = webrtc::CreateBuiltinVideoBitrateAllocatorFactory(); + + std::ostringstream contentId; + contentId << mediaContent.ssrc; - _videoChannel = _channelManager->CreateVideoChannel(call, cricket::MediaConfig(), rtpTransport, threads->getMediaThread(), streamId, false, NativeNetworkingImpl::getDefaulCryptoOptions(), randomIdGenerator, cricket::VideoOptions(), _videoBitrateAllocatorFactory.get()); + _videoChannel = _channelManager->CreateVideoChannel(call, cricket::MediaConfig(), rtpTransport, threads->getMediaThread(), contentId.str(), false, NativeNetworkingImpl::getDefaulCryptoOptions(), randomIdGenerator, cricket::VideoOptions(), _videoBitrateAllocatorFactory.get()); - std::vector videoCodecs = mediaContent.codecs; + std::vector codecs; + for (const auto &payloadType : mediaContent.payloadTypes) { + cricket::VideoCodec codec(payloadType.id, payloadType.name); + for (const auto ¶meter : payloadType.parameters) { + codec.SetParam(parameter.first, parameter.second); + } + for (const auto &feedbackType : payloadType.feedbackTypes) { + codec.AddFeedbackParam(cricket::FeedbackParam(feedbackType.type, feedbackType.subtype)); + } + codecs.push_back(std::move(codec)); + } auto outgoingVideoDescription = std::make_unique(); for (const auto &rtpExtension : mediaContent.rtpExtensions) { @@ -1101,7 +657,7 @@ public: outgoingVideoDescription->set_rtcp_mux(true); outgoingVideoDescription->set_rtcp_reduced_size(true); outgoingVideoDescription->set_direction(webrtc::RtpTransceiverDirection::kRecvOnly); - outgoingVideoDescription->set_codecs(videoCodecs); + outgoingVideoDescription->set_codecs(codecs); outgoingVideoDescription->set_bandwidth(-1); cricket::StreamParams videoRecvStreamParams; @@ -1122,7 +678,7 @@ public: videoRecvStreamParams.ssrcs = allSsrcs; videoRecvStreamParams.cname = "cname"; - videoRecvStreamParams.set_stream_ids({ streamId }); + videoRecvStreamParams.set_stream_ids({ contentId.str() }); auto incomingVideoDescription = std::make_unique(); for (const auto &rtpExtension : mediaContent.rtpExtensions) { @@ -1131,7 +687,7 @@ public: incomingVideoDescription->set_rtcp_mux(true); incomingVideoDescription->set_rtcp_reduced_size(true); incomingVideoDescription->set_direction(webrtc::RtpTransceiverDirection::kSendOnly); - incomingVideoDescription->set_codecs(videoCodecs); + incomingVideoDescription->set_codecs(codecs); incomingVideoDescription->set_bandwidth(-1); incomingVideoDescription->AddStream(videoRecvStreamParams); @@ -1156,6 +712,10 @@ public: void addSink(std::weak_ptr> impl) { _videoSink->addSink(impl); } + + uint32_t ssrc() const { + return _mainVideoSsrc; + } private: void OnSentPacket_w(const rtc::SentPacket& sent_packet) { @@ -1173,6 +733,45 @@ private: webrtc::Call *_call = nullptr; }; +template +struct StateLogRecord { + int64_t timestamp = 0; + T record; + + explicit StateLogRecord(int32_t timestamp_, T &&record_) : + timestamp(timestamp_), + record(std::move(record_)) { + } +}; + +struct NetworkStateLogRecord { + bool isConnected = false; + bool isFailed = false; + absl::optional route; + absl::optional connection; + + bool operator==(NetworkStateLogRecord const &rhs) const { + if (isConnected != rhs.isConnected) { + return false; + } + if (isFailed != rhs.isFailed) { + return false; + } + if (route != rhs.route) { + return false; + } + if (connection != rhs.connection) { + return false; + } + + return true; + } +}; + +struct NetworkBitrateLogRecord { + int32_t bitrate = 0; +}; + } // namespace class InstanceV2ImplInternal : public std::enable_shared_from_this { @@ -1180,6 +779,8 @@ public: InstanceV2ImplInternal(Descriptor &&descriptor, std::shared_ptr threads) : _threads(threads), _rtcServers(descriptor.rtcServers), + _proxy(std::move(descriptor.proxy)), + _enableP2P(descriptor.config.enableP2P), _encryptionKey(std::move(descriptor.encryptionKey)), _stateUpdated(descriptor.stateUpdated), _signalBarsUpdated(descriptor.signalBarsUpdated), @@ -1189,6 +790,7 @@ public: _remotePrefferedAspectRatioUpdated(descriptor.remotePrefferedAspectRatioUpdated), _signalingDataEmitted(descriptor.signalingDataEmitted), _createAudioDeviceModule(descriptor.createAudioDeviceModule), + _statsLogPath(descriptor.config.statsLogPath), _eventLog(std::make_unique()), _taskQueueFactory(webrtc::CreateDefaultTaskQueueFactory()), _videoCapture(descriptor.videoCapture), @@ -1213,20 +815,31 @@ public: _call.reset(); _audioDeviceModule = nullptr; }); + + _contentNegotiationContext.reset(); + _threads->getNetworkThread()->Invoke(RTC_FROM_HERE, []() { }); } void start() { + _startTimestamp = rtc::TimeMillis(); + const auto weak = std::weak_ptr(shared_from_this()); + + absl::optional proxy; + if (_proxy) { + proxy = *(_proxy.get()); + } - _networking.reset(new ThreadLocalObject(_threads->getNetworkThread(), [weak, threads = _threads, isOutgoing = _encryptionKey.isOutgoing, rtcServers = _rtcServers]() { + _networking.reset(new ThreadLocalObject(_threads->getNetworkThread(), [weak, threads = _threads, isOutgoing = _encryptionKey.isOutgoing, rtcServers = _rtcServers, proxy, enableP2P = _enableP2P]() { return new NativeNetworkingImpl(NativeNetworkingImpl::Configuration{ .isOutgoing = isOutgoing, .enableStunMarking = false, .enableTCP = false, - .enableP2P = true, + .enableP2P = enableP2P, .rtcServers = rtcServers, + .proxy = proxy, .stateUpdated = [threads, weak](const NativeNetworkingImpl::State &state) { threads->getMediaThread()->PostTask(RTC_FROM_HERE, [=] { const auto strong = weak.lock(); @@ -1323,6 +936,12 @@ public: }); _uniqueRandomIdGenerator.reset(new rtc::UniqueRandomIdGenerator()); + + _contentNegotiationContext = std::make_unique(_encryptionKey.isOutgoing, _uniqueRandomIdGenerator.get()); + _contentNegotiationContext->copyCodecsFromChannelManager(_channelManager.get(), false); + + _outgoingAudioChannelId = _contentNegotiationContext->addOutgoingChannel(signaling::MediaContent::Type::Audio); + //_contentNegotiationContext->addOutgoingChannel(signaling::MediaContent::Type::Video); _threads->getNetworkThread()->Invoke(RTC_FROM_HERE, [this]() { _rtpTransport = _networking->getSyncAssumingSameThread()->getRtpTransport(); @@ -1341,6 +960,75 @@ public: beginSignaling(); adjustBitratePreferences(true); + + beginQualityTimer(0); + beginLogTimer(0); + } + + void beginQualityTimer(int delayMs) { + const auto weak = std::weak_ptr(shared_from_this()); + _threads->getMediaThread()->PostDelayedTask(RTC_FROM_HERE, [weak]() { + auto strong = weak.lock(); + if (!strong) { + return; + } + + + + strong->beginQualityTimer(500); + }, delayMs); + } + + void beginLogTimer(int delayMs) { + const auto weak = std::weak_ptr(shared_from_this()); + _threads->getMediaThread()->PostDelayedTask(RTC_FROM_HERE, [weak]() { + auto strong = weak.lock(); + if (!strong) { + return; + } + + strong->writeStateLogRecords(); + + strong->beginLogTimer(1000); + }, delayMs); + } + + void writeStateLogRecords() { + const auto weak = std::weak_ptr(shared_from_this()); + _threads->getWorkerThread()->PostTask(RTC_FROM_HERE, [weak]() { + auto strong = weak.lock(); + if (!strong) { + return; + } + + auto stats = strong->_call->GetStats(); + float sendBitrateKbps = ((float)stats.send_bandwidth_bps / 1000.0f); + + strong->_threads->getMediaThread()->PostTask(RTC_FROM_HERE, [weak, sendBitrateKbps]() { + auto strong = weak.lock(); + if (!strong) { + return; + } + + float bitrateNorm = 16.0f; + if (strong->_outgoingVideoChannel) { + bitrateNorm = 600.0f; + } + + float signalBarsNorm = 4.0f; + float adjustedQuality = sendBitrateKbps / bitrateNorm; + adjustedQuality = fmaxf(0.0f, adjustedQuality); + adjustedQuality = fminf(1.0f, adjustedQuality); + if (strong->_signalBarsUpdated) { + strong->_signalBarsUpdated((int)(adjustedQuality * signalBarsNorm)); + } + + NetworkBitrateLogRecord networkBitrateLogRecord; + networkBitrateLogRecord.bitrate = (int32_t)sendBitrateKbps; + + strong->_networkBitrateLogRecords.emplace_back(rtc::TimeMillis(), std::move(networkBitrateLogRecord)); + }); + }); } void sendSignalingMessage(signaling::Message const &message) { @@ -1363,42 +1051,188 @@ public: _signalingEncryption.reset(new SignalingEncryption(_encryptionKey)); if (_encryptionKey.isOutgoing) { - _outgoingAudioContent = OutgoingAudioChannel::createOutgoingContentDescription(); - _outgoingVideoContent = OutgoingVideoChannel::createOutgoingContentDescription(_availableVideoFormats, false); - _outgoingScreencastContent = OutgoingVideoChannel::createOutgoingContentDescription(_availableVideoFormats, true); - sendInitialSetup(); } } void createNegotiatedChannels() { - if (_negotiatedOutgoingVideoContent) { - const auto weak = std::weak_ptr(shared_from_this()); - - _outgoingVideoChannel.reset(new OutgoingVideoChannel( - _threads, - _channelManager.get(), - _call.get(), - _rtpTransport, - _uniqueRandomIdGenerator.get(), - _videoBitrateAllocatorFactory.get(), - [threads = _threads, weak]() { - threads->getMediaThread()->PostTask(RTC_FROM_HERE, [=] { - const auto strong = weak.lock(); - if (!strong) { - return; - } - strong->sendMediaState(); - }); - }, - _negotiatedOutgoingVideoContent.value(), - false - )); - - if (_videoCapture) { - _outgoingVideoChannel->setVideoCapture(_videoCapture); + const auto coordinatedState = _contentNegotiationContext->coordinatedState(); + if (!coordinatedState) { + return; + } + + if (_outgoingAudioChannelId) { + const auto audioSsrc = _contentNegotiationContext->outgoingChannelSsrc(_outgoingAudioChannelId.value()); + if (audioSsrc) { + if (_outgoingAudioChannel && _outgoingAudioChannel->ssrc() != audioSsrc.value()) { + _outgoingAudioChannel.reset(); + } + + absl::optional outgoingAudioContent; + for (const auto &content : coordinatedState->outgoingContents) { + if (content.type == signaling::MediaContent::Type::Audio && content.ssrc == audioSsrc.value()) { + outgoingAudioContent = content; + break; + } + } + + if (outgoingAudioContent) { + if (!_outgoingAudioChannel) { + _outgoingAudioChannel.reset(new OutgoingAudioChannel( + _call.get(), + _channelManager.get(), + _uniqueRandomIdGenerator.get(), + &_audioSource, + _rtpTransport, + outgoingAudioContent.value(), + _threads + )); + } + } } } + + if (_outgoingVideoChannelId) { + const auto videoSsrc = _contentNegotiationContext->outgoingChannelSsrc(_outgoingVideoChannelId.value()); + if (videoSsrc) { + if (_outgoingVideoChannel && _outgoingVideoChannel->ssrc() != videoSsrc.value()) { + _outgoingVideoChannel.reset(); + } + + absl::optional outgoingVideoContent; + for (const auto &content : coordinatedState->outgoingContents) { + if (content.type == signaling::MediaContent::Type::Video && content.ssrc == videoSsrc.value()) { + outgoingVideoContent = content; + break; + } + } + + if (outgoingVideoContent) { + if (!_outgoingVideoChannel) { + const auto weak = std::weak_ptr(shared_from_this()); + + _outgoingVideoChannel.reset(new OutgoingVideoChannel( + _threads, + _channelManager.get(), + _call.get(), + _rtpTransport, + _uniqueRandomIdGenerator.get(), + _videoBitrateAllocatorFactory.get(), + [threads = _threads, weak]() { + threads->getMediaThread()->PostTask(RTC_FROM_HERE, [=] { + const auto strong = weak.lock(); + if (!strong) { + return; + } + strong->sendMediaState(); + }); + }, + outgoingVideoContent.value(), + false + )); + + if (_videoCapture) { + _outgoingVideoChannel->setVideoCapture(_videoCapture); + } + } + } + } + } + + if (_outgoingScreencastChannelId) { + const auto screencastSsrc = _contentNegotiationContext->outgoingChannelSsrc(_outgoingScreencastChannelId.value()); + if (screencastSsrc) { + if (_outgoingScreencastChannel && _outgoingScreencastChannel->ssrc() != screencastSsrc.value()) { + _outgoingScreencastChannel.reset(); + } + + absl::optional outgoingScreencastContent; + for (const auto &content : coordinatedState->outgoingContents) { + if (content.type == signaling::MediaContent::Type::Video && content.ssrc == screencastSsrc.value()) { + outgoingScreencastContent = content; + break; + } + } + + if (outgoingScreencastContent) { + if (!_outgoingScreencastChannel) { + const auto weak = std::weak_ptr(shared_from_this()); + + _outgoingScreencastChannel.reset(new OutgoingVideoChannel( + _threads, + _channelManager.get(), + _call.get(), + _rtpTransport, + _uniqueRandomIdGenerator.get(), + _videoBitrateAllocatorFactory.get(), + [threads = _threads, weak]() { + threads->getMediaThread()->PostTask(RTC_FROM_HERE, [=] { + const auto strong = weak.lock(); + if (!strong) { + return; + } + strong->sendMediaState(); + }); + }, + outgoingScreencastContent.value(), + true + )); + + if (_screencastCapture) { + _outgoingScreencastChannel->setVideoCapture(_screencastCapture); + } + } + } + } + } + + for (const auto &content : coordinatedState->incomingContents) { + switch (content.type) { + case signaling::MediaContent::Type::Audio: { + if (_incomingAudioChannel && _incomingAudioChannel->ssrc() != content.ssrc) { + _incomingAudioChannel.reset(); + } + + if (!_incomingAudioChannel) { + _incomingAudioChannel.reset(new IncomingV2AudioChannel( + _channelManager.get(), + _call.get(), + _rtpTransport, + _uniqueRandomIdGenerator.get(), + content, + _threads + )); + } + + break; + } + case signaling::MediaContent::Type::Video: { + if (_incomingVideoChannel && _incomingVideoChannel->ssrc() != content.ssrc) { + _incomingVideoChannel.reset(); + } + + if (!_incomingVideoChannel) { + _incomingVideoChannel.reset(new IncomingV2VideoChannel( + _channelManager.get(), + _call.get(), + _rtpTransport, + _uniqueRandomIdGenerator.get(), + content, + _threads + )); + _incomingVideoChannel->addSink(_currentSink); + } + + break; + } + default: { + RTC_FATAL() << "Unknown media type"; + break; + } + } + } + + /* if (_negotiatedOutgoingScreencastContent) { const auto weak = std::weak_ptr(shared_from_this()); @@ -1438,9 +1272,10 @@ public: _negotiatedOutgoingAudioContent.value(), _threads )); - } + }*/ adjustBitratePreferences(true); + sendMediaState(); } void sendInitialSetup() { @@ -1469,16 +1304,6 @@ public: signaling::InitialSetupMessage data; - if (strong->_outgoingAudioContent) { - data.audio = strong->_outgoingAudioContent.value(); - } - if (strong->_outgoingVideoContent) { - data.video = strong->_outgoingVideoContent.value(); - } - if (strong->_outgoingScreencastContent) { - data.screencast = strong->_outgoingScreencastContent.value(); - } - data.ufrag = ufrag; data.pwd = pwd; @@ -1494,6 +1319,20 @@ public: }); }); } + + void sendOfferIfNeeded() { + if (const auto offer = _contentNegotiationContext->getPendingOffer()) { + signaling::NegotiateChannelsMessage data; + + data.exchangeId = offer->exchangeId; + + data.contents = offer->contents; + + signaling::Message message; + message.data = std::move(data); + sendSignalingMessage(message); + } + } void receiveSignalingData(const std::vector &data) { std::vector decryptedData; @@ -1537,185 +1376,35 @@ public: _networking->perform(RTC_FROM_HERE, [threads = _threads, remoteIceParameters = std::move(remoteIceParameters), fingerprint = std::move(fingerprint), sslSetup = std::move(sslSetup)](NativeNetworkingImpl *networking) { networking->setRemoteParams(remoteIceParameters, fingerprint.get(), sslSetup); }); + + _handshakeCompleted = true; - if (const auto audio = initialSetup->audio) { - if (_encryptionKey.isOutgoing) { - if (_outgoingAudioContent) { - _negotiatedOutgoingAudioContent = negotiateMediaContent(_outgoingAudioContent.value(), _outgoingAudioContent.value(), audio.value(), false); - const auto incomingAudioContent = negotiateMediaContent(audio.value(), _outgoingAudioContent.value(), audio.value(), false); - - signaling::MediaContent outgoingAudioContent; - - outgoingAudioContent.ssrc = _outgoingAudioContent->ssrc; - outgoingAudioContent.ssrcGroups = _outgoingAudioContent->ssrcGroups; - outgoingAudioContent.rtpExtensions = _negotiatedOutgoingAudioContent->rtpExtensions; - outgoingAudioContent.payloadTypes = getPayloadTypesFromAudioCodecs(_negotiatedOutgoingAudioContent->codecs); - - _outgoingAudioContent = std::move(outgoingAudioContent); - - _incomingAudioChannel.reset(new IncomingV2AudioChannel( - _channelManager.get(), - _call.get(), - _rtpTransport, - _uniqueRandomIdGenerator.get(), - incomingAudioContent, - _threads - )); - } - } else { - const auto generatedOutgoingContent = OutgoingAudioChannel::createOutgoingContentDescription(); - - if (generatedOutgoingContent) { - _negotiatedOutgoingAudioContent = negotiateMediaContent(generatedOutgoingContent.value(), generatedOutgoingContent.value(), audio.value(), true); - const auto incomingAudioContent = negotiateMediaContent(audio.value(), generatedOutgoingContent.value(), audio.value(), true); - - if (_negotiatedOutgoingAudioContent) { - signaling::MediaContent outgoingAudioContent; - - outgoingAudioContent.ssrc = generatedOutgoingContent->ssrc; - outgoingAudioContent.ssrcGroups = generatedOutgoingContent->ssrcGroups; - outgoingAudioContent.rtpExtensions = _negotiatedOutgoingAudioContent->rtpExtensions; - outgoingAudioContent.payloadTypes = getPayloadTypesFromAudioCodecs(_negotiatedOutgoingAudioContent->codecs); - - _outgoingAudioContent = std::move(outgoingAudioContent); - - _incomingAudioChannel.reset(new IncomingV2AudioChannel( - _channelManager.get(), - _call.get(), - _rtpTransport, - _uniqueRandomIdGenerator.get(), - incomingAudioContent, - _threads - )); - } - } - } - } - - if (const auto video = initialSetup->video) { - if (_encryptionKey.isOutgoing) { - if (_outgoingVideoContent) { - _negotiatedOutgoingVideoContent = negotiateMediaContent(_outgoingVideoContent.value(), _outgoingVideoContent.value(), video.value(), false); - const auto incomingVideoContent = negotiateMediaContent(video.value(), _outgoingVideoContent.value(), video.value(), false); - - signaling::MediaContent outgoingVideoContent; - - outgoingVideoContent.ssrc = _outgoingVideoContent->ssrc; - outgoingVideoContent.ssrcGroups = _outgoingVideoContent->ssrcGroups; - outgoingVideoContent.rtpExtensions = _negotiatedOutgoingVideoContent->rtpExtensions; - outgoingVideoContent.payloadTypes = getPayloadTypesFromVideoCodecs(_negotiatedOutgoingVideoContent->codecs); - - _outgoingVideoContent = std::move(outgoingVideoContent); - - _incomingVideoChannel.reset(new IncomingV2VideoChannel( - _channelManager.get(), - _call.get(), - _rtpTransport, - _uniqueRandomIdGenerator.get(), - incomingVideoContent, - "1", - _threads - )); - _incomingVideoChannel->addSink(_currentSink); - } - } else { - const auto generatedOutgoingContent = OutgoingVideoChannel::createOutgoingContentDescription(_availableVideoFormats, false); - - if (generatedOutgoingContent) { - _negotiatedOutgoingVideoContent = negotiateMediaContent(generatedOutgoingContent.value(), generatedOutgoingContent.value(), video.value(), true); - const auto incomingVideoContent = negotiateMediaContent(video.value(), generatedOutgoingContent.value(), video.value(), true); - - if (_negotiatedOutgoingVideoContent) { - signaling::MediaContent outgoingVideoContent; - - outgoingVideoContent.ssrc = generatedOutgoingContent->ssrc; - outgoingVideoContent.ssrcGroups = generatedOutgoingContent->ssrcGroups; - outgoingVideoContent.rtpExtensions = _negotiatedOutgoingVideoContent->rtpExtensions; - outgoingVideoContent.payloadTypes = getPayloadTypesFromVideoCodecs(_negotiatedOutgoingVideoContent->codecs); - - _outgoingVideoContent = std::move(outgoingVideoContent); - - _incomingVideoChannel.reset(new IncomingV2VideoChannel( - _channelManager.get(), - _call.get(), - _rtpTransport, - _uniqueRandomIdGenerator.get(), - incomingVideoContent, - "1", - _threads - )); - _incomingVideoChannel->addSink(_currentSink); - } - } - } - } - - if (const auto screencast = initialSetup->screencast) { - if (_encryptionKey.isOutgoing) { - if (_outgoingScreencastContent) { - _negotiatedOutgoingScreencastContent = negotiateMediaContent(_outgoingScreencastContent.value(), _outgoingScreencastContent.value(), screencast.value(), false); - const auto incomingScreencastContent = negotiateMediaContent(screencast.value(), _outgoingScreencastContent.value(), screencast.value(), false); - - signaling::MediaContent outgoingScreencastContent; - - outgoingScreencastContent.ssrc = _outgoingScreencastContent->ssrc; - outgoingScreencastContent.ssrcGroups = _outgoingScreencastContent->ssrcGroups; - outgoingScreencastContent.rtpExtensions = _negotiatedOutgoingScreencastContent->rtpExtensions; - outgoingScreencastContent.payloadTypes = getPayloadTypesFromVideoCodecs(_negotiatedOutgoingScreencastContent->codecs); - - _outgoingScreencastContent = std::move(outgoingScreencastContent); - - _incomingScreencastChannel.reset(new IncomingV2VideoChannel( - _channelManager.get(), - _call.get(), - _rtpTransport, - _uniqueRandomIdGenerator.get(), - incomingScreencastContent, - "2", - _threads - )); - _incomingScreencastChannel->addSink(_currentSink); - } - } else { - const auto generatedOutgoingContent = OutgoingVideoChannel::createOutgoingContentDescription(_availableVideoFormats, true); - - if (generatedOutgoingContent) { - _negotiatedOutgoingScreencastContent = negotiateMediaContent(generatedOutgoingContent.value(), generatedOutgoingContent.value(), screencast.value(), true); - const auto incomingScreencastContent = negotiateMediaContent(screencast.value(), generatedOutgoingContent.value(), screencast.value(), true); - - if (_negotiatedOutgoingScreencastContent) { - signaling::MediaContent outgoingScreencastContent; - - outgoingScreencastContent.ssrc = generatedOutgoingContent->ssrc; - outgoingScreencastContent.ssrcGroups = generatedOutgoingContent->ssrcGroups; - outgoingScreencastContent.rtpExtensions = _negotiatedOutgoingScreencastContent->rtpExtensions; - outgoingScreencastContent.payloadTypes = getPayloadTypesFromVideoCodecs(_negotiatedOutgoingScreencastContent->codecs); - - _outgoingScreencastContent = std::move(outgoingScreencastContent); - - _incomingScreencastChannel.reset(new IncomingV2VideoChannel( - _channelManager.get(), - _call.get(), - _rtpTransport, - _uniqueRandomIdGenerator.get(), - incomingScreencastContent, - "2", - _threads - )); - _incomingScreencastChannel->addSink(_currentSink); - } - } - } - } - - createNegotiatedChannels(); - - if (!_encryptionKey.isOutgoing) { + if (_encryptionKey.isOutgoing) { + sendOfferIfNeeded(); + } else { sendInitialSetup(); } - _handshakeCompleted = true; commitPendingIceCandidates(); + } else if (const auto offerAnwer = absl::get_if(messageData)) { + auto negotiationContents = std::make_unique(); + negotiationContents->exchangeId = offerAnwer->exchangeId; + negotiationContents->contents = offerAnwer->contents; + + if (const auto response = _contentNegotiationContext->setRemoteNegotiationContent(std::move(negotiationContents))) { + signaling::NegotiateChannelsMessage data; + + data.exchangeId = response->exchangeId; + data.contents = response->contents; + + signaling::Message message; + message.data = std::move(data); + sendSignalingMessage(message); + } + + sendOfferIfNeeded(); + + createNegotiatedChannels(); } else if (const auto candidatesList = absl::get_if(messageData)) { for (const auto &candidate : candidatesList->iceCandidates) { webrtc::JsepIceCandidate parseCandidate{ std::string(), 0 }; @@ -1804,11 +1493,26 @@ public: void onNetworkStateUpdated(NativeNetworkingImpl::State const &state) { State mappedState; - if (state.isReadyToSendData) { + if (state.isFailed) { + mappedState = State::Failed; + } else if (state.isReadyToSendData) { mappedState = State::Established; } else { mappedState = State::Reconnecting; } + + NetworkStateLogRecord record; + record.isConnected = state.isReadyToSendData; + record.route = state.route; + record.connection = state.connection; + record.isFailed = state.isFailed; + + if (!_currentNetworkStateLogRecord || !(_currentNetworkStateLogRecord.value() == record)) { + _currentNetworkStateLogRecord = record; + _networkStateLogRecords.emplace_back(rtc::TimeMillis(), std::move(record)); + } + + _networkState = state; _stateUpdated(mappedState); } @@ -1907,13 +1611,17 @@ public: if (_outgoingVideoChannel) { _outgoingVideoChannel->setVideoCapture(nullptr); } + if (_outgoingVideoChannelId) { + _contentNegotiationContext->removeOutgoingChannel(_outgoingVideoChannelId.value()); + _outgoingVideoChannelId.reset(); + } if (_outgoingScreencastChannel) { _outgoingScreencastChannel->setVideoCapture(videoCapture); } - - sendMediaState(); - adjustBitratePreferences(true); + if (!_outgoingScreencastChannelId) { + _outgoingScreencastChannelId = _contentNegotiationContext->addOutgoingChannel(signaling::MediaContent::Type::Video); + } } else { _videoCapture = videoCapture; _screencastCapture = nullptr; @@ -1921,13 +1629,17 @@ public: if (_outgoingVideoChannel) { _outgoingVideoChannel->setVideoCapture(videoCapture); } + if (!_outgoingVideoChannelId) { + _outgoingVideoChannelId = _contentNegotiationContext->addOutgoingChannel(signaling::MediaContent::Type::Video); + } if (_outgoingScreencastChannel) { _outgoingScreencastChannel->setVideoCapture(nullptr); } - - sendMediaState(); - adjustBitratePreferences(true); + if (_outgoingScreencastChannelId) { + _contentNegotiationContext->removeOutgoingChannel(_outgoingScreencastChannelId.value()); + _outgoingScreencastChannelId.reset(); + } } } else { _videoCapture = nullptr; @@ -1940,9 +1652,23 @@ public: if (_outgoingScreencastChannel) { _outgoingScreencastChannel->setVideoCapture(nullptr); } + + if (_outgoingVideoChannelId) { + _contentNegotiationContext->removeOutgoingChannel(_outgoingVideoChannelId.value()); + _outgoingVideoChannelId.reset(); + } + + if (_outgoingScreencastChannelId) { + _contentNegotiationContext->removeOutgoingChannel(_outgoingScreencastChannelId.value()); + _outgoingScreencastChannelId.reset(); + } + } + if (_handshakeCompleted) { + sendOfferIfNeeded(); sendMediaState(); adjustBitratePreferences(true); + createNegotiatedChannels(); } } @@ -1991,33 +1717,99 @@ public: } void stop(std::function completion) { - completion({}); + FinalState finalState; + + json11::Json::object statsLog; + + for (int i = (int)_networkStateLogRecords.size() - 1; i >= 1; i--) { + // coalesce events within 5ms + if (_networkStateLogRecords[i].timestamp - _networkStateLogRecords[i - 1].timestamp < 5) { + _networkStateLogRecords.erase(_networkStateLogRecords.begin() + i - 1); + } + } + + json11::Json::array jsonNetworkStateLogRecords; + int64_t baseTimestamp = 0; + for (const auto &record : _networkStateLogRecords) { + json11::Json::object jsonRecord; + + std::ostringstream timestampString; + + if (baseTimestamp == 0) { + baseTimestamp = record.timestamp; + } + timestampString << (record.timestamp - baseTimestamp); + + jsonRecord.insert(std::make_pair("t", json11::Json(timestampString.str()))); + jsonRecord.insert(std::make_pair("c", json11::Json(record.record.isConnected ? 1 : 0))); + if (record.record.route) { + jsonRecord.insert(std::make_pair("local", json11::Json(record.record.route->localDescription))); + jsonRecord.insert(std::make_pair("remote", json11::Json(record.record.route->remoteDescription))); + } + if (record.record.connection) { + json11::Json::object jsonConnection; + + auto serializeCandidate = [](NativeNetworkingImpl::ConnectionDescription::CandidateDescription const &candidate) -> json11::Json::object { + json11::Json::object jsonCandidate; + + jsonCandidate.insert(std::make_pair("type", json11::Json(candidate.type))); + jsonCandidate.insert(std::make_pair("protocol", json11::Json(candidate.protocol))); + jsonCandidate.insert(std::make_pair("address", json11::Json(candidate.address))); + + return jsonCandidate; + }; + + jsonConnection.insert(std::make_pair("local", serializeCandidate(record.record.connection->local))); + jsonConnection.insert(std::make_pair("remote", serializeCandidate(record.record.connection->remote))); + + jsonRecord.insert(std::make_pair("network", std::move(jsonConnection))); + } + if (record.record.isFailed) { + jsonRecord.insert(std::make_pair("failed", json11::Json(1))); + } + + jsonNetworkStateLogRecords.push_back(std::move(jsonRecord)); + } + statsLog.insert(std::make_pair("network", std::move(jsonNetworkStateLogRecords))); + + json11::Json::array jsonNetworkBitrateLogRecords; + for (const auto &record : _networkBitrateLogRecords) { + json11::Json::object jsonRecord; + + jsonRecord.insert(std::make_pair("b", json11::Json(record.record.bitrate))); + + jsonNetworkBitrateLogRecords.push_back(std::move(jsonRecord)); + } + statsLog.insert(std::make_pair("bitrate", std::move(jsonNetworkBitrateLogRecords))); + + auto jsonStatsLog = json11::Json(std::move(statsLog)); + + if (!_statsLogPath.data.empty()) { + std::ofstream file; + file.open(_statsLogPath.data); + + file << jsonStatsLog.dump(); + + file.close(); + } + + completion(finalState); } void adjustBitratePreferences(bool resetStartBitrate) { - webrtc::BitrateConstraints preferences; - if (_videoCapture || _screencastCapture) { - preferences.min_bitrate_bps = 64000; - if (resetStartBitrate) { - preferences.start_bitrate_bps = (100 + 800 + 32 + 100) * 1000; - } - preferences.max_bitrate_bps = (100 + 200 + 800 + 32 + 100) * 1000; - } else { - preferences.min_bitrate_bps = 32000; - if (resetStartBitrate) { - preferences.start_bitrate_bps = 32000; - } - preferences.max_bitrate_bps = 32000; + if (_outgoingAudioChannel) { + _outgoingAudioChannel->setMaxBitrate(32 * 1024); + } + if (_outgoingVideoChannel) { + _outgoingVideoChannel->setMaxBitrate(1000 * 1024); } - - _call->GetTransportControllerSend()->SetSdpBitrateParameters(preferences); } private: rtc::scoped_refptr createAudioDeviceModule() { const auto create = [&](webrtc::AudioDeviceModule::AudioLayer layer) { #ifdef WEBRTC_IOS - return rtc::make_ref_counted(false, false); + return rtc::make_ref_counted(false, false, 1); #else return webrtc::AudioDeviceModule::Create( layer, @@ -2038,6 +1830,8 @@ private: private: std::shared_ptr _threads; std::vector _rtcServers; + std::unique_ptr _proxy; + bool _enableP2P = false; EncryptionKey _encryptionKey; std::function _stateUpdated; std::function _signalBarsUpdated; @@ -2047,8 +1841,17 @@ private: std::function _remotePrefferedAspectRatioUpdated; std::function &)> _signalingDataEmitted; std::function(webrtc::TaskQueueFactory*)> _createAudioDeviceModule; + FilePath _statsLogPath; std::unique_ptr _signalingEncryption; + + int64_t _startTimestamp = 0; + + absl::optional _currentNetworkStateLogRecord; + std::vector> _networkStateLogRecords; + std::vector> _networkBitrateLogRecords; + + absl::optional _networkState; bool _handshakeCompleted = false; std::vector _pendingIceCandidates; @@ -2066,24 +1869,20 @@ private: webrtc::RtpTransport *_rtpTransport = nullptr; std::unique_ptr _channelManager; std::unique_ptr _videoBitrateAllocatorFactory; + + std::unique_ptr _contentNegotiationContext; std::shared_ptr> _networking; - absl::optional _outgoingAudioContent; - absl::optional> _negotiatedOutgoingAudioContent; - + absl::optional _outgoingAudioChannelId; std::unique_ptr _outgoingAudioChannel; bool _isMicrophoneMuted = false; std::vector _availableVideoFormats; - absl::optional _outgoingVideoContent; - absl::optional> _negotiatedOutgoingVideoContent; - - absl::optional _outgoingScreencastContent; - absl::optional> _negotiatedOutgoingScreencastContent; - + absl::optional _outgoingVideoChannelId; std::shared_ptr _outgoingVideoChannel; + absl::optional _outgoingScreencastChannelId; std::shared_ptr _outgoingScreencastChannel; bool _isBatteryLow = false; @@ -2193,7 +1992,7 @@ void InstanceV2Impl::setEchoCancellationStrength(int strength) { std::vector InstanceV2Impl::GetVersions() { std::vector result; - result.push_back("4.0.0"); + result.push_back("4.0.1"); return result; } diff --git a/TMessagesProj/jni/voip/tgcalls/v2/InstanceV2ReferenceImpl.cpp b/TMessagesProj/jni/voip/tgcalls/v2/InstanceV2ReferenceImpl.cpp new file mode 100644 index 000000000..6cc896d05 --- /dev/null +++ b/TMessagesProj/jni/voip/tgcalls/v2/InstanceV2ReferenceImpl.cpp @@ -0,0 +1,1023 @@ +#include "v2/InstanceV2ReferenceImpl.h" + +#include "LogSinkImpl.h" +#include "VideoCaptureInterfaceImpl.h" +#include "VideoCapturerInterface.h" +#include "v2/NativeNetworkingImpl.h" +#include "v2/Signaling.h" +#include "v2/ContentNegotiation.h" + +#include "CodecSelectHelper.h" +#include "platform/PlatformInterface.h" + +#include "api/audio_codecs/audio_decoder_factory_template.h" +#include "api/audio_codecs/audio_encoder_factory_template.h" +#include "api/audio_codecs/opus/audio_decoder_opus.h" +#include "api/audio_codecs/opus/audio_decoder_multi_channel_opus.h" +#include "api/audio_codecs/opus/audio_encoder_opus.h" +#include "api/audio_codecs/L16/audio_decoder_L16.h" +#include "api/audio_codecs/L16/audio_encoder_L16.h" +#include "api/task_queue/default_task_queue_factory.h" +#include "media/engine/webrtc_media_engine.h" +#include "system_wrappers/include/field_trial.h" +#include "api/video/builtin_video_bitrate_allocator_factory.h" +#include "call/call.h" +#include "api/call/audio_sink.h" +#include "modules/audio_processing/audio_buffer.h" +#include "absl/strings/match.h" +#include "pc/channel_manager.h" +#include "audio/audio_state.h" +#include "modules/audio_coding/neteq/default_neteq_factory.h" +#include "modules/audio_coding/include/audio_coding_module.h" +#include "api/candidate.h" +#include "api/jsep_ice_candidate.h" +#include "pc/used_ids.h" +#include "media/base/sdp_video_format_utils.h" +#include "pc/media_session.h" +#include "rtc_base/rtc_certificate_generator.h" +#include "pc/peer_connection.h" + +#include "AudioFrame.h" +#include "ThreadLocalObject.h" +#include "Manager.h" +#include "NetworkManager.h" +#include "VideoCaptureInterfaceImpl.h" +#include "platform/PlatformInterface.h" +#include "LogSinkImpl.h" +#include "CodecSelectHelper.h" +#include "AudioDeviceHelper.h" +#include "SignalingEncryption.h" +#ifdef WEBRTC_IOS +#include "platform/darwin/iOS/tgcalls_audio_device_module_ios.h" +#endif +#include +#include + +namespace tgcalls { +namespace { + +static VideoCaptureInterfaceObject *GetVideoCaptureAssumingSameThread(VideoCaptureInterface *videoCapture) { + return videoCapture + ? static_cast(videoCapture)->object()->getSyncAssumingSameThread() + : nullptr; +} + +class VideoSinkImpl : public rtc::VideoSinkInterface { +public: + VideoSinkImpl() { + } + + virtual ~VideoSinkImpl() { + } + + virtual void OnFrame(const webrtc::VideoFrame& frame) override { + //_lastFrame = frame; + for (int i = (int)(_sinks.size()) - 1; i >= 0; i--) { + auto strong = _sinks[i].lock(); + if (!strong) { + _sinks.erase(_sinks.begin() + i); + } else { + strong->OnFrame(frame); + } + } + } + + virtual void OnDiscardedFrame() override { + for (int i = (int)(_sinks.size()) - 1; i >= 0; i--) { + auto strong = _sinks[i].lock(); + if (!strong) { + _sinks.erase(_sinks.begin() + i); + } else { + strong->OnDiscardedFrame(); + } + } + } + + void addSink(std::weak_ptr> impl) { + _sinks.push_back(impl); + if (_lastFrame) { + auto strong = impl.lock(); + if (strong) { + strong->OnFrame(_lastFrame.value()); + } + } + } + +private: + std::vector>> _sinks; + absl::optional _lastFrame; +}; + +} // namespace + +class InstanceV2ReferenceImplInternal : public std::enable_shared_from_this { +public: + InstanceV2ReferenceImplInternal(Descriptor &&descriptor, std::shared_ptr threads) : + _threads(threads), + _rtcServers(descriptor.rtcServers), + _proxy(std::move(descriptor.proxy)), + _enableP2P(descriptor.config.enableP2P), + _encryptionKey(std::move(descriptor.encryptionKey)), + _stateUpdated(descriptor.stateUpdated), + _signalBarsUpdated(descriptor.signalBarsUpdated), + _audioLevelUpdated(descriptor.audioLevelUpdated), + _remoteBatteryLevelIsLowUpdated(descriptor.remoteBatteryLevelIsLowUpdated), + _remoteMediaStateUpdated(descriptor.remoteMediaStateUpdated), + _remotePrefferedAspectRatioUpdated(descriptor.remotePrefferedAspectRatioUpdated), + _signalingDataEmitted(descriptor.signalingDataEmitted), + _createAudioDeviceModule(descriptor.createAudioDeviceModule), + _eventLog(std::make_unique()), + _taskQueueFactory(webrtc::CreateDefaultTaskQueueFactory()), + _videoCapture(descriptor.videoCapture), + _platformContext(descriptor.platformContext) { + } + + ~InstanceV2ReferenceImplInternal() { + + _currentSink.reset(); + } + + void start() { + const auto weak = std::weak_ptr(shared_from_this()); + + PlatformInterface::SharedInstance()->configurePlatformAudio(); + + RTC_DCHECK(_threads->getMediaThread()->IsCurrent()); + + //_threads->getWorkerThread()->Invoke(RTC_FROM_HERE, [&]() { + cricket::MediaEngineDependencies mediaDeps; + mediaDeps.task_queue_factory = _taskQueueFactory.get(); + mediaDeps.audio_encoder_factory = webrtc::CreateAudioEncoderFactory(); + mediaDeps.audio_decoder_factory = webrtc::CreateAudioDecoderFactory(); + + mediaDeps.video_encoder_factory = PlatformInterface::SharedInstance()->makeVideoEncoderFactory(_platformContext, true); + mediaDeps.video_decoder_factory = PlatformInterface::SharedInstance()->makeVideoDecoderFactory(_platformContext); + + _audioDeviceModule = createAudioDeviceModule(); + + mediaDeps.adm = _audioDeviceModule; + + std::unique_ptr mediaEngine = cricket::CreateMediaEngine(std::move(mediaDeps)); + //}); + + webrtc::PeerConnectionFactoryDependencies peerConnectionFactoryDependencies; + peerConnectionFactoryDependencies.signaling_thread = _threads->getMediaThread(); + peerConnectionFactoryDependencies.worker_thread = _threads->getWorkerThread(); + peerConnectionFactoryDependencies.task_queue_factory = std::move(_taskQueueFactory); + peerConnectionFactoryDependencies.media_engine = std::move(mediaEngine); + + auto peerConnectionFactory = webrtc::PeerConnectionFactory::Create(std::move(peerConnectionFactoryDependencies)); + + webrtc::PeerConnectionDependencies peerConnectionDependencies(nullptr); + + webrtc::PeerConnectionInterface::RTCConfiguration peerConnectionConfiguration; + + auto peerConnectionOrError = peerConnectionFactory->CreatePeerConnectionOrError(peerConnectionConfiguration, std::move(peerConnectionDependencies)); + if (peerConnectionOrError.ok()) { + _peerConnection = peerConnectionOrError.value(); + } + + if (_videoCapture) { + setVideoCapture(_videoCapture); + } + + beginSignaling(); + } + + void sendSignalingMessage(signaling::Message const &message) { + auto data = message.serialize(); + + RTC_LOG(LS_INFO) << "sendSignalingMessage: " << std::string(data.begin(), data.end()); + + if (_signalingEncryption) { + if (const auto encryptedData = _signalingEncryption->encryptOutgoing(data)) { + _signalingDataEmitted(std::vector(encryptedData->data(), encryptedData->data() + encryptedData->size())); + } else { + RTC_LOG(LS_ERROR) << "sendSignalingMessage: failed to encrypt payload"; + } + } else { + _signalingDataEmitted(data); + } + } + + void beginSignaling() { + _signalingEncryption.reset(new SignalingEncryption(_encryptionKey)); + + if (_encryptionKey.isOutgoing) { + sendInitialSetup(); + } + } + + void createNegotiatedChannels() { + /*const auto coordinatedState = _contentNegotiationContext->coordinatedState(); + if (!coordinatedState) { + return; + } + + if (_outgoingAudioChannelId) { + const auto audioSsrc = _contentNegotiationContext->outgoingChannelSsrc(_outgoingAudioChannelId.value()); + if (audioSsrc) { + if (_outgoingAudioChannel && _outgoingAudioChannel->ssrc() != audioSsrc.value()) { + _outgoingAudioChannel.reset(); + } + + absl::optional outgoingAudioContent; + for (const auto &content : coordinatedState->outgoingContents) { + if (content.type == signaling::MediaContent::Type::Audio && content.ssrc == audioSsrc.value()) { + outgoingAudioContent = content; + break; + } + } + + if (outgoingAudioContent) { + if (!_outgoingAudioChannel) { + _outgoingAudioChannel.reset(new OutgoingAudioChannel( + _call.get(), + _channelManager.get(), + _uniqueRandomIdGenerator.get(), + &_audioSource, + _rtpTransport, + outgoingAudioContent.value(), + _threads + )); + } + } + } + } + + if (_outgoingVideoChannelId) { + const auto videoSsrc = _contentNegotiationContext->outgoingChannelSsrc(_outgoingVideoChannelId.value()); + if (videoSsrc) { + if (_outgoingVideoChannel && _outgoingVideoChannel->ssrc() != videoSsrc.value()) { + _outgoingVideoChannel.reset(); + } + + absl::optional outgoingVideoContent; + for (const auto &content : coordinatedState->outgoingContents) { + if (content.type == signaling::MediaContent::Type::Video && content.ssrc == videoSsrc.value()) { + outgoingVideoContent = content; + break; + } + } + + if (outgoingVideoContent) { + if (!_outgoingVideoChannel) { + const auto weak = std::weak_ptr(shared_from_this()); + + _outgoingVideoChannel.reset(new OutgoingVideoChannel( + _threads, + _channelManager.get(), + _call.get(), + _rtpTransport, + _uniqueRandomIdGenerator.get(), + _videoBitrateAllocatorFactory.get(), + [threads = _threads, weak]() { + threads->getMediaThread()->PostTask(RTC_FROM_HERE, [=] { + const auto strong = weak.lock(); + if (!strong) { + return; + } + strong->sendMediaState(); + }); + }, + outgoingVideoContent.value(), + false + )); + + if (_videoCapture) { + _outgoingVideoChannel->setVideoCapture(_videoCapture); + } + } + } + } + } + + if (_outgoingScreencastChannelId) { + const auto screencastSsrc = _contentNegotiationContext->outgoingChannelSsrc(_outgoingScreencastChannelId.value()); + if (screencastSsrc) { + if (_outgoingScreencastChannel && _outgoingScreencastChannel->ssrc() != screencastSsrc.value()) { + _outgoingScreencastChannel.reset(); + } + + absl::optional outgoingScreencastContent; + for (const auto &content : coordinatedState->outgoingContents) { + if (content.type == signaling::MediaContent::Type::Video && content.ssrc == screencastSsrc.value()) { + outgoingScreencastContent = content; + break; + } + } + + if (outgoingScreencastContent) { + if (!_outgoingScreencastChannel) { + const auto weak = std::weak_ptr(shared_from_this()); + + _outgoingScreencastChannel.reset(new OutgoingVideoChannel( + _threads, + _channelManager.get(), + _call.get(), + _rtpTransport, + _uniqueRandomIdGenerator.get(), + _videoBitrateAllocatorFactory.get(), + [threads = _threads, weak]() { + threads->getMediaThread()->PostTask(RTC_FROM_HERE, [=] { + const auto strong = weak.lock(); + if (!strong) { + return; + } + strong->sendMediaState(); + }); + }, + outgoingScreencastContent.value(), + true + )); + + if (_screencastCapture) { + _outgoingScreencastChannel->setVideoCapture(_screencastCapture); + } + } + } + } + } + + for (const auto &content : coordinatedState->incomingContents) { + switch (content.type) { + case signaling::MediaContent::Type::Audio: { + if (_incomingAudioChannel && _incomingAudioChannel->ssrc() != content.ssrc) { + _incomingAudioChannel.reset(); + } + + if (!_incomingAudioChannel) { + _incomingAudioChannel.reset(new IncomingV2AudioChannel( + _channelManager.get(), + _call.get(), + _rtpTransport, + _uniqueRandomIdGenerator.get(), + content, + _threads + )); + } + + break; + } + case signaling::MediaContent::Type::Video: { + if (_incomingVideoChannel && _incomingVideoChannel->ssrc() != content.ssrc) { + _incomingVideoChannel.reset(); + } + + if (!_incomingVideoChannel) { + _incomingVideoChannel.reset(new IncomingV2VideoChannel( + _channelManager.get(), + _call.get(), + _rtpTransport, + _uniqueRandomIdGenerator.get(), + content, + _threads + )); + _incomingVideoChannel->addSink(_currentSink); + } + + break; + } + default: { + RTC_FATAL() << "Unknown media type"; + break; + } + } + } + + adjustBitratePreferences(true); + sendMediaState();*/ + } + + void sendInitialSetup() { + const auto weak = std::weak_ptr(shared_from_this()); + + /*_networking->perform(RTC_FROM_HERE, [weak, threads = _threads, isOutgoing = _encryptionKey.isOutgoing](NativeNetworkingImpl *networking) { + auto localFingerprint = networking->getLocalFingerprint(); + std::string hash = localFingerprint->algorithm; + std::string fingerprint = localFingerprint->GetRfc4572Fingerprint(); + std::string setup; + if (isOutgoing) { + setup = "actpass"; + } else { + setup = "passive"; + } + + auto localIceParams = networking->getLocalIceParameters(); + std::string ufrag = localIceParams.ufrag; + std::string pwd = localIceParams.pwd; + + threads->getMediaThread()->PostTask(RTC_FROM_HERE, [weak, ufrag, pwd, hash, fingerprint, setup, localIceParams]() { + const auto strong = weak.lock(); + if (!strong) { + return; + } + + signaling::InitialSetupMessage data; + + data.ufrag = ufrag; + data.pwd = pwd; + + signaling::DtlsFingerprint dtlsFingerprint; + dtlsFingerprint.hash = hash; + dtlsFingerprint.fingerprint = fingerprint; + dtlsFingerprint.setup = setup; + data.fingerprints.push_back(std::move(dtlsFingerprint)); + + signaling::Message message; + message.data = std::move(data); + strong->sendSignalingMessage(message); + }); + });*/ + } + + void sendOfferIfNeeded() { + /*if (const auto offer = _contentNegotiationContext->getPendingOffer()) { + signaling::NegotiateChannelsMessage data; + + data.exchangeId = offer->exchangeId; + + data.contents = offer->contents; + + signaling::Message message; + message.data = std::move(data); + sendSignalingMessage(message); + }*/ + } + + void receiveSignalingData(const std::vector &data) { + std::vector decryptedData; + + if (_signalingEncryption) { + const auto rawDecryptedData = _signalingEncryption->decryptIncoming(data); + if (!rawDecryptedData) { + RTC_LOG(LS_ERROR) << "receiveSignalingData: could not decrypt payload"; + + return; + } + + decryptedData = std::vector(rawDecryptedData->data(), rawDecryptedData->data() + rawDecryptedData->size()); + } else { + decryptedData = data; + } + + processSignalingData(decryptedData); + } + + void processSignalingData(const std::vector &data) { + RTC_LOG(LS_INFO) << "processSignalingData: " << std::string(data.begin(), data.end()); + + /*const auto message = signaling::Message::parse(data); + if (!message) { + return; + } + const auto messageData = &message->data; + if (const auto initialSetup = absl::get_if(messageData)) { + PeerIceParameters remoteIceParameters; + remoteIceParameters.ufrag = initialSetup->ufrag; + remoteIceParameters.pwd = initialSetup->pwd; + + std::unique_ptr fingerprint; + std::string sslSetup; + if (initialSetup->fingerprints.size() != 0) { + fingerprint = rtc::SSLFingerprint::CreateUniqueFromRfc4572(initialSetup->fingerprints[0].hash, initialSetup->fingerprints[0].fingerprint); + sslSetup = initialSetup->fingerprints[0].setup; + } + + _networking->perform(RTC_FROM_HERE, [threads = _threads, remoteIceParameters = std::move(remoteIceParameters), fingerprint = std::move(fingerprint), sslSetup = std::move(sslSetup)](NativeNetworkingImpl *networking) { + networking->setRemoteParams(remoteIceParameters, fingerprint.get(), sslSetup); + }); + + if (_encryptionKey.isOutgoing) { + sendOfferIfNeeded(); + } else { + sendInitialSetup(); + } + + _handshakeCompleted = true; + commitPendingIceCandidates(); + } else if (const auto offerAnwer = absl::get_if(messageData)) { + auto negotiationContents = std::make_unique(); + negotiationContents->exchangeId = offerAnwer->exchangeId; + negotiationContents->contents = offerAnwer->contents; + + if (const auto response = _contentNegotiationContext->setRemoteNegotiationContent(std::move(negotiationContents))) { + signaling::NegotiateChannelsMessage data; + + data.exchangeId = response->exchangeId; + data.contents = response->contents; + + signaling::Message message; + message.data = std::move(data); + sendSignalingMessage(message); + } + + sendOfferIfNeeded(); + + createNegotiatedChannels(); + } else if (const auto candidatesList = absl::get_if(messageData)) { + for (const auto &candidate : candidatesList->iceCandidates) { + webrtc::JsepIceCandidate parseCandidate{ std::string(), 0 }; + if (!parseCandidate.Initialize(candidate.sdpString, nullptr)) { + RTC_LOG(LS_ERROR) << "Could not parse candidate: " << candidate.sdpString; + continue; + } + _pendingIceCandidates.push_back(parseCandidate.candidate()); + } + + if (_handshakeCompleted) { + commitPendingIceCandidates(); + } + } else if (const auto mediaState = absl::get_if(messageData)) { + AudioState mappedAudioState; + if (mediaState->isMuted) { + mappedAudioState = AudioState::Muted; + } else { + mappedAudioState = AudioState::Active; + } + + VideoState mappedVideoState; + switch (mediaState->videoState) { + case signaling::MediaStateMessage::VideoState::Inactive: { + mappedVideoState = VideoState::Inactive; + break; + } + case signaling::MediaStateMessage::VideoState::Suspended: { + mappedVideoState = VideoState::Paused; + break; + } + case signaling::MediaStateMessage::VideoState::Active: { + mappedVideoState = VideoState::Active; + break; + } + default: { + RTC_FATAL() << "Unknown videoState"; + break; + } + } + + VideoState mappedScreencastState; + switch (mediaState->screencastState) { + case signaling::MediaStateMessage::VideoState::Inactive: { + mappedScreencastState = VideoState::Inactive; + break; + } + case signaling::MediaStateMessage::VideoState::Suspended: { + mappedScreencastState = VideoState::Paused; + break; + } + case signaling::MediaStateMessage::VideoState::Active: { + mappedScreencastState = VideoState::Active; + break; + } + default: { + RTC_FATAL() << "Unknown videoState"; + break; + } + } + + VideoState effectiveVideoState = mappedVideoState; + if (mappedScreencastState == VideoState::Active || mappedScreencastState == VideoState::Paused) { + effectiveVideoState = mappedScreencastState; + } + + if (_remoteMediaStateUpdated) { + _remoteMediaStateUpdated(mappedAudioState, effectiveVideoState); + } + + if (_remoteBatteryLevelIsLowUpdated) { + _remoteBatteryLevelIsLowUpdated(mediaState->isBatteryLow); + } + }*/ + } + + void commitPendingIceCandidates() { + if (_pendingIceCandidates.size() == 0) { + return; + } + /*_networking->perform(RTC_FROM_HERE, [threads = _threads, parsedCandidates = _pendingIceCandidates](NativeNetworkingImpl *networking) { + networking->addCandidates(parsedCandidates); + }); + _pendingIceCandidates.clear();*/ + } + + /*void onNetworkStateUpdated(NativeNetworkingImpl::State const &state) { + State mappedState; + if (state.isReadyToSendData) { + mappedState = State::Established; + } else { + mappedState = State::Reconnecting; + } + _stateUpdated(mappedState); + }*/ + + /*void onDataChannelStateUpdated(bool isDataChannelOpen) { + if (_isDataChannelOpen != isDataChannelOpen) { + _isDataChannelOpen = isDataChannelOpen; + + if (_isDataChannelOpen) { + sendMediaState(); + } + } + } + + void sendDataChannelMessage(signaling::Message const &message) { + if (!_isDataChannelOpen) { + RTC_LOG(LS_ERROR) << "sendDataChannelMessage called, but data channel is not open"; + return; + } + auto data = message.serialize(); + std::string stringData(data.begin(), data.end()); + RTC_LOG(LS_INFO) << "sendDataChannelMessage: " << stringData; + _networking->perform(RTC_FROM_HERE, [stringData = std::move(stringData)](NativeNetworkingImpl *networking) { + networking->sendDataChannelMessage(stringData); + }); + } + + void onDataChannelMessage(std::string const &message) { + RTC_LOG(LS_INFO) << "dataChannelMessage received: " << message; + std::vector data(message.begin(), message.end()); + processSignalingData(data); + }*/ + + void sendMediaState() { + /*if (!_isDataChannelOpen) { + return; + } + signaling::Message message; + signaling::MediaStateMessage data; + data.isMuted = _isMicrophoneMuted; + data.isBatteryLow = _isBatteryLow; + if (_outgoingVideoChannel) { + if (_outgoingVideoChannel->videoCapture()) { + data.videoState = signaling::MediaStateMessage::VideoState::Active; + } else{ + data.videoState = signaling::MediaStateMessage::VideoState::Inactive; + } + data.videoRotation = _outgoingVideoChannel->getRotation(); + } else { + data.videoState = signaling::MediaStateMessage::VideoState::Inactive; + data.videoRotation = signaling::MediaStateMessage::VideoRotation::Rotation0; + } + if (_outgoingScreencastChannel) { + if (_outgoingScreencastChannel->videoCapture()) { + data.screencastState = signaling::MediaStateMessage::VideoState::Active; + } else{ + data.screencastState = signaling::MediaStateMessage::VideoState::Inactive; + } + } else { + data.screencastState = signaling::MediaStateMessage::VideoState::Inactive; + } + message.data = std::move(data); + sendDataChannelMessage(message);*/ + } + + void sendCandidate(const cricket::Candidate &candidate) { + cricket::Candidate patchedCandidate = candidate; + patchedCandidate.set_component(1); + + signaling::CandidatesMessage data; + + signaling::IceCandidate serializedCandidate; + + webrtc::JsepIceCandidate iceCandidate{ std::string(), 0 }; + iceCandidate.SetCandidate(patchedCandidate); + std::string serialized; + const auto success = iceCandidate.ToString(&serialized); + assert(success); + (void)success; + + serializedCandidate.sdpString = serialized; + + data.iceCandidates.push_back(std::move(serializedCandidate)); + + signaling::Message message; + message.data = std::move(data); + sendSignalingMessage(message); + } + + void setVideoCapture(std::shared_ptr videoCapture) { + /*auto videoCaptureImpl = GetVideoCaptureAssumingSameThread(videoCapture.get()); + if (videoCaptureImpl) { + if (videoCaptureImpl->isScreenCapture()) { + _videoCapture = nullptr; + _screencastCapture = videoCapture; + + if (_outgoingVideoChannel) { + _outgoingVideoChannel->setVideoCapture(nullptr); + } + if (_outgoingVideoChannelId) { + _contentNegotiationContext->removeOutgoingChannel(_outgoingVideoChannelId.value()); + _outgoingVideoChannelId.reset(); + } + + if (_outgoingScreencastChannel) { + _outgoingScreencastChannel->setVideoCapture(videoCapture); + } + if (!_outgoingScreencastChannelId) { + _outgoingScreencastChannelId = _contentNegotiationContext->addOutgoingChannel(signaling::MediaContent::Type::Video); + } + } else { + _videoCapture = videoCapture; + _screencastCapture = nullptr; + + if (_outgoingVideoChannel) { + _outgoingVideoChannel->setVideoCapture(videoCapture); + } + if (!_outgoingVideoChannelId) { + _outgoingVideoChannelId = _contentNegotiationContext->addOutgoingChannel(signaling::MediaContent::Type::Video); + } + + if (_outgoingScreencastChannel) { + _outgoingScreencastChannel->setVideoCapture(nullptr); + } + if (_outgoingScreencastChannelId) { + _contentNegotiationContext->removeOutgoingChannel(_outgoingScreencastChannelId.value()); + _outgoingScreencastChannelId.reset(); + } + } + } else { + _videoCapture = nullptr; + _screencastCapture = nullptr; + + if (_outgoingVideoChannel) { + _outgoingVideoChannel->setVideoCapture(nullptr); + } + + if (_outgoingScreencastChannel) { + _outgoingScreencastChannel->setVideoCapture(nullptr); + } + + if (_outgoingVideoChannelId) { + _contentNegotiationContext->removeOutgoingChannel(_outgoingVideoChannelId.value()); + _outgoingVideoChannelId.reset(); + } + + if (_outgoingScreencastChannelId) { + _contentNegotiationContext->removeOutgoingChannel(_outgoingScreencastChannelId.value()); + _outgoingScreencastChannelId.reset(); + } + } + + sendOfferIfNeeded(); + sendMediaState(); + adjustBitratePreferences(true); + createNegotiatedChannels();*/ + } + + void setRequestedVideoAspect(float aspect) { + } + + void setNetworkType(NetworkType networkType) { + } + + void setMuteMicrophone(bool muteMicrophone) { + /*if (_isMicrophoneMuted != muteMicrophone) { + _isMicrophoneMuted = muteMicrophone; + + if (_outgoingAudioChannel) { + _outgoingAudioChannel->setIsMuted(muteMicrophone); + } + + sendMediaState(); + }*/ + } + + void setIncomingVideoOutput(std::weak_ptr> sink) { + /*_currentSink = sink; + if (_incomingVideoChannel) { + _incomingVideoChannel->addSink(sink); + } + if (_incomingScreencastChannel) { + _incomingScreencastChannel->addSink(sink); + }*/ + } + + void setAudioInputDevice(std::string id) { + } + + void setAudioOutputDevice(std::string id) { + } + + void setIsLowBatteryLevel(bool isLowBatteryLevel) { + if (_isBatteryLow != isLowBatteryLevel) { + _isBatteryLow = isLowBatteryLevel; + sendMediaState(); + } + } + + void stop(std::function completion) { + completion({}); + } + + /*void adjustBitratePreferences(bool resetStartBitrate) { + if (_outgoingAudioChannel) { + _outgoingAudioChannel->setMaxBitrate(32 * 1024); + } + if (_outgoingVideoChannel) { + _outgoingVideoChannel->setMaxBitrate(1000 * 1024); + } + }*/ + +private: + rtc::scoped_refptr createAudioDeviceModule() { + const auto create = [&](webrtc::AudioDeviceModule::AudioLayer layer) { +#ifdef WEBRTC_IOS + return rtc::make_ref_counted(false, false, 1); +#else + return webrtc::AudioDeviceModule::Create( + layer, + _taskQueueFactory.get()); +#endif + }; + const auto check = [&](const rtc::scoped_refptr &result) { + return (result && result->Init() == 0) ? result : nullptr; + }; + if (_createAudioDeviceModule) { + if (const auto result = check(_createAudioDeviceModule(_taskQueueFactory.get()))) { + return result; + } + } + return check(create(webrtc::AudioDeviceModule::kPlatformDefaultAudio)); + } + +private: + std::shared_ptr _threads; + std::vector _rtcServers; + std::unique_ptr _proxy; + bool _enableP2P = false; + EncryptionKey _encryptionKey; + std::function _stateUpdated; + std::function _signalBarsUpdated; + std::function _audioLevelUpdated; + std::function _remoteBatteryLevelIsLowUpdated; + std::function _remoteMediaStateUpdated; + std::function _remotePrefferedAspectRatioUpdated; + std::function &)> _signalingDataEmitted; + std::function(webrtc::TaskQueueFactory*)> _createAudioDeviceModule; + + std::unique_ptr _signalingEncryption; + + bool _handshakeCompleted = false; + std::vector _pendingIceCandidates; + bool _isDataChannelOpen = false; + + std::unique_ptr _eventLog; + std::unique_ptr _taskQueueFactory; + rtc::scoped_refptr _peerConnection; + webrtc::FieldTrialBasedConfig _fieldTrials; + + webrtc::LocalAudioSinkAdapter _audioSource; + + rtc::scoped_refptr _audioDeviceModule; + + bool _isBatteryLow = false; + + std::weak_ptr> _currentSink; + + std::shared_ptr _videoCapture; + std::shared_ptr _screencastCapture; + std::shared_ptr _platformContext; +}; + +InstanceV2ReferenceImpl::InstanceV2ReferenceImpl(Descriptor &&descriptor) { + if (descriptor.config.logPath.data.size() != 0) { + _logSink = std::make_unique(descriptor.config.logPath); + } + rtc::LogMessage::LogToDebug(rtc::LS_INFO); + rtc::LogMessage::SetLogToStderr(false); + if (_logSink) { + rtc::LogMessage::AddLogToStream(_logSink.get(), rtc::LS_INFO); + } + + _threads = StaticThreads::getThreads(); + _internal.reset(new ThreadLocalObject(_threads->getMediaThread(), [descriptor = std::move(descriptor), threads = _threads]() mutable { + return new InstanceV2ReferenceImplInternal(std::move(descriptor), threads); + })); + _internal->perform(RTC_FROM_HERE, [](InstanceV2ReferenceImplInternal *internal) { + internal->start(); + }); +} + +InstanceV2ReferenceImpl::~InstanceV2ReferenceImpl() { + rtc::LogMessage::RemoveLogToStream(_logSink.get()); +} + +void InstanceV2ReferenceImpl::receiveSignalingData(const std::vector &data) { + _internal->perform(RTC_FROM_HERE, [data](InstanceV2ReferenceImplInternal *internal) { + internal->receiveSignalingData(data); + }); +} + +void InstanceV2ReferenceImpl::setVideoCapture(std::shared_ptr videoCapture) { + _internal->perform(RTC_FROM_HERE, [videoCapture](InstanceV2ReferenceImplInternal *internal) { + internal->setVideoCapture(videoCapture); + }); +} + +void InstanceV2ReferenceImpl::setRequestedVideoAspect(float aspect) { + _internal->perform(RTC_FROM_HERE, [aspect](InstanceV2ReferenceImplInternal *internal) { + internal->setRequestedVideoAspect(aspect); + }); +} + +void InstanceV2ReferenceImpl::setNetworkType(NetworkType networkType) { + _internal->perform(RTC_FROM_HERE, [networkType](InstanceV2ReferenceImplInternal *internal) { + internal->setNetworkType(networkType); + }); +} + +void InstanceV2ReferenceImpl::setMuteMicrophone(bool muteMicrophone) { + _internal->perform(RTC_FROM_HERE, [muteMicrophone](InstanceV2ReferenceImplInternal *internal) { + internal->setMuteMicrophone(muteMicrophone); + }); +} + +void InstanceV2ReferenceImpl::setIncomingVideoOutput(std::shared_ptr> sink) { + _internal->perform(RTC_FROM_HERE, [sink](InstanceV2ReferenceImplInternal *internal) { + internal->setIncomingVideoOutput(sink); + }); +} + +void InstanceV2ReferenceImpl::setAudioInputDevice(std::string id) { + _internal->perform(RTC_FROM_HERE, [id](InstanceV2ReferenceImplInternal *internal) { + internal->setAudioInputDevice(id); + }); +} + +void InstanceV2ReferenceImpl::setAudioOutputDevice(std::string id) { + _internal->perform(RTC_FROM_HERE, [id](InstanceV2ReferenceImplInternal *internal) { + internal->setAudioOutputDevice(id); + }); +} + +void InstanceV2ReferenceImpl::setIsLowBatteryLevel(bool isLowBatteryLevel) { + _internal->perform(RTC_FROM_HERE, [isLowBatteryLevel](InstanceV2ReferenceImplInternal *internal) { + internal->setIsLowBatteryLevel(isLowBatteryLevel); + }); +} + +void InstanceV2ReferenceImpl::setInputVolume(float level) { +} + +void InstanceV2ReferenceImpl::setOutputVolume(float level) { +} + +void InstanceV2ReferenceImpl::setAudioOutputDuckingEnabled(bool enabled) { +} + +void InstanceV2ReferenceImpl::setAudioOutputGainControlEnabled(bool enabled) { +} + +void InstanceV2ReferenceImpl::setEchoCancellationStrength(int strength) { +} + +std::vector InstanceV2ReferenceImpl::GetVersions() { + std::vector result; + result.push_back("4.0.2"); + return result; +} + +int InstanceV2ReferenceImpl::GetConnectionMaxLayer() { + return 92; +} + +std::string InstanceV2ReferenceImpl::getLastError() { + return ""; +} + +std::string InstanceV2ReferenceImpl::getDebugInfo() { + return ""; +} + +int64_t InstanceV2ReferenceImpl::getPreferredRelayId() { + return 0; +} + +TrafficStats InstanceV2ReferenceImpl::getTrafficStats() { + return {}; +} + +PersistentState InstanceV2ReferenceImpl::getPersistentState() { + return {}; +} + +void InstanceV2ReferenceImpl::stop(std::function completion) { + std::string debugLog; + if (_logSink) { + debugLog = _logSink->result(); + } + _internal->perform(RTC_FROM_HERE, [completion, debugLog = std::move(debugLog)](InstanceV2ReferenceImplInternal *internal) mutable { + internal->stop([completion, debugLog = std::move(debugLog)](FinalState finalState) mutable { + finalState.debugLog = debugLog; + completion(finalState); + }); + }); +} + +template <> +bool Register() { + return Meta::RegisterOne(); +} + +} // namespace tgcalls diff --git a/TMessagesProj/jni/voip/tgcalls/v2/InstanceV2ReferenceImpl.h b/TMessagesProj/jni/voip/tgcalls/v2/InstanceV2ReferenceImpl.h new file mode 100644 index 000000000..44b0a9587 --- /dev/null +++ b/TMessagesProj/jni/voip/tgcalls/v2/InstanceV2ReferenceImpl.h @@ -0,0 +1,59 @@ +#ifndef TGCALLS_INSTANCEV2_REFERENCE_IMPL_H +#define TGCALLS_INSTANCEV2_REFERENCE_IMPL_H + +#include "Instance.h" +#include "StaticThreads.h" + +namespace tgcalls { + +class LogSinkImpl; + +class Manager; +template +class ThreadLocalObject; + +class InstanceV2ReferenceImplInternal; + +class InstanceV2ReferenceImpl final : public Instance { +public: + explicit InstanceV2ReferenceImpl(Descriptor &&descriptor); + ~InstanceV2ReferenceImpl() override; + + void receiveSignalingData(const std::vector &data) override; + void setVideoCapture(std::shared_ptr videoCapture) override; + void setRequestedVideoAspect(float aspect) override; + void setNetworkType(NetworkType networkType) override; + void setMuteMicrophone(bool muteMicrophone) override; + bool supportsVideo() override { + return true; + } + void setIncomingVideoOutput(std::shared_ptr> sink) override; + void setAudioOutputGainControlEnabled(bool enabled) override; + void setEchoCancellationStrength(int strength) override; + void setAudioInputDevice(std::string id) override; + void setAudioOutputDevice(std::string id) override; + void setInputVolume(float level) override; + void setOutputVolume(float level) override; + void setAudioOutputDuckingEnabled(bool enabled) override; + void setIsLowBatteryLevel(bool isLowBatteryLevel) override; + static std::vector GetVersions(); + static int GetConnectionMaxLayer(); + std::string getLastError() override; + std::string getDebugInfo() override; + int64_t getPreferredRelayId() override; + TrafficStats getTrafficStats() override; + PersistentState getPersistentState() override; + void stop(std::function completion) override; + void sendVideoDeviceUpdated() override { + } + +private: + std::shared_ptr _threads; + std::unique_ptr> _internal; + std::unique_ptr _logSink; + +}; + +} // namespace tgcalls + +#endif diff --git a/TMessagesProj/jni/voip/tgcalls/v2/NativeNetworkingImpl.cpp b/TMessagesProj/jni/voip/tgcalls/v2/NativeNetworkingImpl.cpp index f234ae73a..3bf0a3c82 100644 --- a/TMessagesProj/jni/voip/tgcalls/v2/NativeNetworkingImpl.cpp +++ b/TMessagesProj/jni/voip/tgcalls/v2/NativeNetworkingImpl.cpp @@ -13,12 +13,185 @@ #include "p2p/base/dtls_transport_factory.h" #include "pc/dtls_srtp_transport.h" #include "pc/dtls_transport.h" +#include "pc/jsep_transport_controller.h" +#include "api/async_dns_resolver.h" + #include "TurnCustomizerImpl.h" #include "SctpDataChannelProviderInterfaceImpl.h" #include "StaticThreads.h" +#include "platform/PlatformInterface.h" namespace tgcalls { +namespace { + +NativeNetworkingImpl::ConnectionDescription::CandidateDescription connectionDescriptionFromCandidate(cricket::Candidate const &candidate) { + NativeNetworkingImpl::ConnectionDescription::CandidateDescription result; + + result.type = candidate.type(); + result.protocol = candidate.protocol(); + result.address = candidate.address().ToString(); + + return result; +} + +class CryptStringImpl : public rtc::CryptStringImpl { +public: + CryptStringImpl(std::string const &value) : + _value(value) { + } + + virtual ~CryptStringImpl() override { + } + + virtual size_t GetLength() const override { + return _value.size(); + } + + virtual void CopyTo(char* dest, bool nullterminate) const override { + memcpy(dest, _value.data(), _value.size()); + if (nullterminate) { + dest[_value.size()] = 0; + } + } + virtual std::string UrlEncode() const override { + return _value; + } + virtual CryptStringImpl* Copy() const override { + return new CryptStringImpl(_value); + } + + virtual void CopyRawTo(std::vector* dest) const override { + dest->resize(_value.size()); + memcpy(dest->data(), _value.data(), _value.size()); + } + +private: + std::string _value; +}; + +class WrappedAsyncPacketSocket : public rtc::AsyncPacketSocket { +public: + WrappedAsyncPacketSocket(std::unique_ptr &&wrappedSocket) : + _wrappedSocket(std::move(wrappedSocket)) { + _wrappedSocket->SignalReadPacket.connect(this, &WrappedAsyncPacketSocket::onReadPacket); + _wrappedSocket->SignalSentPacket.connect(this, &WrappedAsyncPacketSocket::onSentPacket); + _wrappedSocket->SignalReadyToSend.connect(this, &WrappedAsyncPacketSocket::onReadyToSend); + _wrappedSocket->SignalAddressReady.connect(this, &WrappedAsyncPacketSocket::onAddressReady); + _wrappedSocket->SignalConnect.connect(this, &WrappedAsyncPacketSocket::onConnect); + _wrappedSocket->SignalClose.connect(this, &WrappedAsyncPacketSocket::onClose); + } + + virtual ~WrappedAsyncPacketSocket() override { + _wrappedSocket->SignalReadPacket.disconnect(this); + _wrappedSocket->SignalSentPacket.disconnect(this); + _wrappedSocket->SignalReadyToSend.disconnect(this); + _wrappedSocket->SignalAddressReady.disconnect(this); + _wrappedSocket->SignalConnect.disconnect(this); + _wrappedSocket->SignalClose.disconnect(this); + + _wrappedSocket.reset(); + } + + virtual rtc::SocketAddress GetLocalAddress() const override { + return _wrappedSocket->GetLocalAddress(); + } + + virtual rtc::SocketAddress GetRemoteAddress() const override { + return _wrappedSocket->GetRemoteAddress(); + } + + virtual int Send(const void* pv, size_t cb, const rtc::PacketOptions& options) override { + return _wrappedSocket->Send(pv, cb, options); + } + + virtual int SendTo(const void* pv, + size_t cb, + const rtc::SocketAddress& addr, + const rtc::PacketOptions& options) override { + return _wrappedSocket->SendTo(pv, cb, addr, options); + } + + virtual int Close() override { + return _wrappedSocket->Close(); + } + + virtual State GetState() const override { + return _wrappedSocket->GetState(); + } + + virtual int GetOption(rtc::Socket::Option opt, int* value) override { + return _wrappedSocket->GetOption(opt, value); + } + + virtual int SetOption(rtc::Socket::Option opt, int value) override { + return _wrappedSocket->SetOption(opt, value); + } + + virtual int GetError() const override { + return _wrappedSocket->GetError(); + } + + virtual void SetError(int error) override { + _wrappedSocket->SetError(error); + } + +private: + void onReadPacket(AsyncPacketSocket *socket, const char *data, size_t size, const rtc::SocketAddress &address, const int64_t ×tamp) { + SignalReadPacket.emit(this, data, size, address, timestamp); + } + + void onSentPacket(AsyncPacketSocket *socket, const rtc::SentPacket &packet) { + SignalSentPacket.emit(this, packet); + } + + void onReadyToSend(AsyncPacketSocket *socket) { + SignalReadyToSend.emit(this); + } + + void onAddressReady(AsyncPacketSocket *socket, const rtc::SocketAddress &address) { + SignalAddressReady.emit(this, address); + } + + void onConnect(AsyncPacketSocket *socket) { + SignalConnect.emit(this); + } + + void onClose(AsyncPacketSocket *socket, int value) { + SignalClose(this, value); + } + +private: + std::unique_ptr _wrappedSocket; +}; + +class WrappedBasicPacketSocketFactory : public rtc::BasicPacketSocketFactory { +public: + explicit WrappedBasicPacketSocketFactory(rtc::SocketFactory* socket_factory) : + rtc::BasicPacketSocketFactory(socket_factory) { + } + + virtual ~WrappedBasicPacketSocketFactory() override { + } + + rtc::AsyncPacketSocket* CreateUdpSocket(const rtc::SocketAddress& local_address, uint16_t min_port, uint16_t max_port) override { + rtc::AsyncPacketSocket *socket = rtc::BasicPacketSocketFactory::CreateUdpSocket(local_address, min_port, max_port); + if (socket) { + std::unique_ptr socketPtr; + socketPtr.reset(socket); + + return new WrappedAsyncPacketSocket(std::move(socketPtr)); + } else { + return nullptr; + } + } + +private: + +}; + +} + webrtc::CryptoOptions NativeNetworkingImpl::getDefaulCryptoOptions() { auto options = webrtc::CryptoOptions(); options.srtp.enable_aes128_sha1_80_crypto_cipher = true; @@ -33,6 +206,7 @@ _enableStunMarking(configuration.enableStunMarking), _enableTCP(configuration.enableTCP), _enableP2P(configuration.enableP2P), _rtcServers(configuration.rtcServers), +_proxy(configuration.proxy), _stateUpdated(std::move(configuration.stateUpdated)), _candidateGathered(std::move(configuration.candidateGathered)), _transportMessageReceived(std::move(configuration.transportMessageReceived)), @@ -45,9 +219,11 @@ _dataChannelMessageReceived(configuration.dataChannelMessageReceived) { _localCertificate = rtc::RTCCertificateGenerator::GenerateCertificate(rtc::KeyParams(rtc::KT_ECDSA), absl::nullopt); + _networkMonitorFactory = PlatformInterface::SharedInstance()->createNetworkMonitorFactory(); _socketFactory.reset(new rtc::BasicPacketSocketFactory(_threads->getNetworkThread()->socketserver())); - _networkManager = std::make_unique(); - _asyncResolverFactory = std::make_unique(); + _networkManager = std::make_unique(_networkMonitorFactory.get(), nullptr); + + _asyncResolverFactory = std::make_unique(std::make_unique()); _dtlsSrtpTransport = std::make_unique(true); _dtlsSrtpTransport->SetDtlsTransports(nullptr, nullptr); @@ -72,6 +248,7 @@ NativeNetworkingImpl::~NativeNetworkingImpl() { _portAllocator.reset(); _networkManager.reset(); _socketFactory.reset(); + _networkMonitorFactory.reset(); } void NativeNetworkingImpl::resetDtlsSrtpTransport() { @@ -88,29 +265,31 @@ void NativeNetworkingImpl::resetDtlsSrtpTransport() { cricket::PORTALLOCATOR_ENABLE_IPV6 | cricket::PORTALLOCATOR_ENABLE_IPV6_ON_WIFI; - if (!_enableTCP) { - flags |= cricket::PORTALLOCATOR_DISABLE_TCP; + /*if (_proxy) { + rtc::ProxyInfo proxyInfo; + proxyInfo.type = rtc::ProxyType::PROXY_SOCKS5; + proxyInfo.address = rtc::SocketAddress(_proxy->host, _proxy->port); + proxyInfo.username = _proxy->login; + proxyInfo.password = rtc::CryptString(CryptStringImpl(_proxy->password)); + _portAllocator->set_proxy("t/1.0", proxyInfo); + + flags &= ~cricket::PORTALLOCATOR_DISABLE_TCP; + } else */{ + if (!_enableTCP) { + flags |= cricket::PORTALLOCATOR_DISABLE_TCP; + } } - if (!_enableP2P) { + + if (_proxy || !_enableP2P) { flags |= cricket::PORTALLOCATOR_DISABLE_UDP; flags |= cricket::PORTALLOCATOR_DISABLE_STUN; uint32_t candidateFilter = _portAllocator->candidate_filter(); candidateFilter &= ~(cricket::CF_REFLEXIVE); _portAllocator->SetCandidateFilter(candidateFilter); } - + _portAllocator->set_step_delay(cricket::kMinimumStepDelay); - //TODO: figure out the proxy setup - /*if (_proxy) { - rtc::ProxyInfo proxyInfo; - proxyInfo.type = rtc::ProxyType::PROXY_SOCKS5; - proxyInfo.address = rtc::SocketAddress(_proxy->host, _proxy->port); - proxyInfo.username = _proxy->login; - proxyInfo.password = rtc::CryptString(TgCallsCryptStringImpl(_proxy->password)); - _portAllocator->set_proxy("t/1.0", proxyInfo); - }*/ - _portAllocator->set_flags(flags); _portAllocator->Initialize(); @@ -133,7 +312,8 @@ void NativeNetworkingImpl::resetDtlsSrtpTransport() { _portAllocator->SetConfiguration(stunServers, turnServers, 2, webrtc::NO_PRUNE, _turnCustomizer.get()); - _transportChannel.reset(new cricket::P2PTransportChannel("transport", 0, _portAllocator.get(), _asyncResolverFactory.get(), nullptr)); + + _transportChannel = cricket::P2PTransportChannel::Create("transport", 0, _portAllocator.get(), _asyncResolverFactory.get()); cricket::IceConfig iceConfig; iceConfig.continual_gathering_policy = cricket::GATHER_CONTINUALLY; @@ -153,7 +333,9 @@ void NativeNetworkingImpl::resetDtlsSrtpTransport() { _transportChannel->SignalCandidateGathered.connect(this, &NativeNetworkingImpl::candidateGathered); _transportChannel->SignalIceTransportStateChanged.connect(this, &NativeNetworkingImpl::transportStateChanged); + _transportChannel->SignalCandidatePairChanged.connect(this, &NativeNetworkingImpl::candidatePairChanged); _transportChannel->SignalReadPacket.connect(this, &NativeNetworkingImpl::transportPacketReceived); + _transportChannel->SignalNetworkRouteChanged.connect(this, &NativeNetworkingImpl::transportRouteChanged); webrtc::CryptoOptions cryptoOptions = NativeNetworkingImpl::getDefaulCryptoOptions(); _dtlsTransport.reset(new cricket::DtlsTransport(_transportChannel.get(), cryptoOptions, nullptr)); @@ -201,12 +383,16 @@ void NativeNetworkingImpl::start() { }, _threads )); + + _lastNetworkActivityMs = rtc::TimeMillis(); + checkConnectionTimeout(); } void NativeNetworkingImpl::stop() { _transportChannel->SignalCandidateGathered.disconnect(this); _transportChannel->SignalIceTransportStateChanged.disconnect(this); _transportChannel->SignalReadPacket.disconnect(this); + _transportChannel->SignalNetworkRouteChanged.disconnect(this); _dtlsTransport->SignalWritableState.disconnect(this); _dtlsTransport->SignalReceivingState.disconnect(this); @@ -289,10 +475,8 @@ void NativeNetworkingImpl::checkConnectionTimeout() { const int64_t maxTimeout = 20000; if (strong->_lastNetworkActivityMs + maxTimeout < currentTimestamp) { - NativeNetworkingImpl::State emitState; - emitState.isReadyToSendData = false; - emitState.isFailed = true; - strong->_stateUpdated(emitState); + strong->_isFailed = true; + strong->notifyStateUpdated(); } strong->checkConnectionTimeout(); @@ -347,6 +531,46 @@ void NativeNetworkingImpl::transportPacketReceived(rtc::PacketTransportInternal assert(_threads->getNetworkThread()->IsCurrent()); _lastNetworkActivityMs = rtc::TimeMillis(); + _isFailed = false; +} + +void NativeNetworkingImpl::transportRouteChanged(absl::optional route) { + assert(_threads->getNetworkThread()->IsCurrent()); + + if (route.has_value()) { + /*cricket::IceTransportStats iceTransportStats; + if (_transportChannel->GetStats(&iceTransportStats)) { + }*/ + + RTC_LOG(LS_INFO) << "NativeNetworkingImpl route changed: " << route->DebugString(); + + bool localIsWifi = route->local.adapter_type() == rtc::AdapterType::ADAPTER_TYPE_WIFI; + bool remoteIsWifi = route->remote.adapter_type() == rtc::AdapterType::ADAPTER_TYPE_WIFI; + + RTC_LOG(LS_INFO) << "NativeNetworkingImpl is wifi: local=" << localIsWifi << ", remote=" << remoteIsWifi; + + std::string localDescription = route->local.uses_turn() ? "turn" : "p2p"; + std::string remoteDescription = route->remote.uses_turn() ? "turn" : "p2p"; + + RouteDescription routeDescription(localDescription, remoteDescription); + + if (!_currentRouteDescription || routeDescription != _currentRouteDescription.value()) { + _currentRouteDescription = std::move(routeDescription); + notifyStateUpdated(); + } + } +} + +void NativeNetworkingImpl::candidatePairChanged(cricket::CandidatePairChangeEvent const &event) { + ConnectionDescription connectionDescription; + + connectionDescription.local = connectionDescriptionFromCandidate(event.selected_candidate_pair.local); + connectionDescription.remote = connectionDescriptionFromCandidate(event.selected_candidate_pair.remote); + + if (!_currentConnectionDescription || _currentConnectionDescription.value() != connectionDescription) { + _currentConnectionDescription = std::move(connectionDescription); + notifyStateUpdated(); + } } void NativeNetworkingImpl::RtpPacketReceived_n(rtc::CopyOnWriteBuffer *packet, int64_t packet_time_us, bool isUnresolved) { @@ -382,9 +606,7 @@ void NativeNetworkingImpl::UpdateAggregateStates_n() { if (_isConnected != isConnected) { _isConnected = isConnected; - NativeNetworkingImpl::State emitState; - emitState.isReadyToSendData = isConnected; - _stateUpdated(emitState); + notifyStateUpdated(); if (_dataChannelInterface) { _dataChannelInterface->updateIsConnected(isConnected); @@ -392,6 +614,15 @@ void NativeNetworkingImpl::UpdateAggregateStates_n() { } } +void NativeNetworkingImpl::notifyStateUpdated() { + NativeNetworkingImpl::State emitState; + emitState.isReadyToSendData = _isConnected; + emitState.route = _currentRouteDescription; + emitState.connection = _currentConnectionDescription; + emitState.isFailed = _isFailed; + _stateUpdated(emitState); +} + void NativeNetworkingImpl::sctpReadyToSendData() { } diff --git a/TMessagesProj/jni/voip/tgcalls/v2/NativeNetworkingImpl.h b/TMessagesProj/jni/voip/tgcalls/v2/NativeNetworkingImpl.h index 9383c6beb..45af35e18 100644 --- a/TMessagesProj/jni/voip/tgcalls/v2/NativeNetworkingImpl.h +++ b/TMessagesProj/jni/voip/tgcalls/v2/NativeNetworkingImpl.h @@ -10,9 +10,9 @@ #include "rtc_base/third_party/sigslot/sigslot.h" #include "api/candidate.h" #include "media/base/media_channel.h" -//#include "media/sctp/sctp_transport.h" #include "rtc_base/ssl_fingerprint.h" #include "pc/sctp_data_channel.h" +#include "p2p/base/port.h" #include #include @@ -36,10 +36,10 @@ class DtlsTransport; } // namespace cricket namespace webrtc { -class BasicAsyncResolverFactory; class TurnCustomizer; class DtlsSrtpTransport; class RtpTransport; +class AsyncDnsResolverFactoryInterface; } // namespace webrtc namespace tgcalls { @@ -50,9 +50,80 @@ class Threads; class NativeNetworkingImpl : public sigslot::has_slots<>, public std::enable_shared_from_this { public: + struct RouteDescription { + explicit RouteDescription(std::string const &localDescription_, std::string const &remoteDescription_) : + localDescription(localDescription_), + remoteDescription(remoteDescription_) { + } + + std::string localDescription; + std::string remoteDescription; + + bool operator==(RouteDescription const &rhs) const { + if (localDescription != rhs.localDescription) { + return false; + } + if (remoteDescription != rhs.remoteDescription) { + return false; + } + + return true; + } + + bool operator!=(const RouteDescription& rhs) const { + return !(*this == rhs); + } + }; + + struct ConnectionDescription { + struct CandidateDescription { + std::string protocol; + std::string type; + std::string address; + + bool operator==(CandidateDescription const &rhs) const { + if (protocol != rhs.protocol) { + return false; + } + if (type != rhs.type) { + return false; + } + if (address != rhs.address) { + return false; + } + + return true; + } + + bool operator!=(const CandidateDescription& rhs) const { + return !(*this == rhs); + } + }; + + CandidateDescription local; + CandidateDescription remote; + + bool operator==(ConnectionDescription const &rhs) const { + if (local != rhs.local) { + return false; + } + if (remote != rhs.remote) { + return false; + } + + return true; + } + + bool operator!=(const ConnectionDescription& rhs) const { + return !(*this == rhs); + } + }; + struct State { bool isReadyToSendData = false; bool isFailed = false; + absl::optional route; + absl::optional connection; }; struct Configuration { @@ -61,6 +132,7 @@ public: bool enableTCP = false; bool enableP2P = false; std::vector rtcServers; + absl::optional proxy; std::function stateUpdated; std::function candidateGathered; std::function transportMessageReceived; @@ -97,6 +169,8 @@ private: void transportStateChanged(cricket::IceTransportInternal *transport); void transportReadyToSend(cricket::IceTransportInternal *transport); void transportPacketReceived(rtc::PacketTransportInternal *transport, const char *bytes, size_t size, const int64_t ×tamp, int unused); + void transportRouteChanged(absl::optional route); + void candidatePairChanged(cricket::CandidatePairChangeEvent const &event); void DtlsReadyToSend(bool DtlsReadyToSend); void UpdateAggregateStates_n(); void RtpPacketReceived_n(rtc::CopyOnWriteBuffer *packet, int64_t packet_time_us, bool isUnresolved); @@ -104,6 +178,8 @@ private: void sctpReadyToSendData(); void sctpDataReceived(const cricket::ReceiveDataParams& params, const rtc::CopyOnWriteBuffer& buffer); + + void notifyStateUpdated(); std::shared_ptr _threads; bool _isOutgoing = false; @@ -111,6 +187,7 @@ private: bool _enableTCP = false; bool _enableP2P = false; std::vector _rtcServers; + absl::optional _proxy; std::function _stateUpdated; std::function _candidateGathered; @@ -119,11 +196,12 @@ private: std::function _dataChannelStateUpdated; std::function _dataChannelMessageReceived; + std::unique_ptr _networkMonitorFactory; std::unique_ptr _socketFactory; std::unique_ptr _networkManager; std::unique_ptr _turnCustomizer; std::unique_ptr _portAllocator; - std::unique_ptr _asyncResolverFactory; + std::unique_ptr _asyncResolverFactory; std::unique_ptr _transportChannel; std::unique_ptr _dtlsTransport; std::unique_ptr _dtlsSrtpTransport; @@ -135,7 +213,10 @@ private: absl::optional _remoteIceParameters; bool _isConnected = false; + bool _isFailed = false; int64_t _lastNetworkActivityMs = 0; + absl::optional _currentRouteDescription; + absl::optional _currentConnectionDescription; }; } // namespace tgcalls diff --git a/TMessagesProj/jni/voip/tgcalls/v2/Signaling.cpp b/TMessagesProj/jni/voip/tgcalls/v2/Signaling.cpp index a98c3f8be..1a981dbca 100644 --- a/TMessagesProj/jni/voip/tgcalls/v2/Signaling.cpp +++ b/TMessagesProj/jni/voip/tgcalls/v2/Signaling.cpp @@ -3,6 +3,7 @@ #include "third-party/json11.hpp" #include "rtc_base/checks.h" +#include "rtc_base/logging.h" #include @@ -40,18 +41,21 @@ absl::optional SsrcGroup_parse(json11::Json::object const &object) { const auto semantics = object.find("semantics"); if (semantics == object.end() || !semantics->second.is_string()) { + RTC_LOG(LS_ERROR) << "Signaling: semantics must be a string"; return absl::nullopt; } result.semantics = semantics->second.string_value(); const auto ssrcs = object.find("ssrcs"); if (ssrcs == object.end() || !ssrcs->second.is_array()) { + RTC_LOG(LS_ERROR) << "Signaling: ssrcs must be an array"; return absl::nullopt; } for (const auto &ssrc : ssrcs->second.array_items()) { if (ssrc.is_string()) { uint32_t parsedSsrc = stringToUInt32(ssrc.string_value()); if (parsedSsrc == 0) { + RTC_LOG(LS_ERROR) << "Signaling: parsedSsrc must not be 0"; return absl::nullopt; } result.ssrcs.push_back(parsedSsrc); @@ -59,6 +63,7 @@ absl::optional SsrcGroup_parse(json11::Json::object const &object) { uint32_t parsedSsrc = (uint32_t)ssrc.number_value(); result.ssrcs.push_back(parsedSsrc); } else { + RTC_LOG(LS_ERROR) << "Signaling: ssrcs item must be a string or a number"; return absl::nullopt; } } @@ -80,12 +85,14 @@ absl::optional FeedbackType_parse(json11::Json::object const &obje const auto type = object.find("type"); if (type == object.end() || !type->second.is_string()) { + RTC_LOG(LS_ERROR) << "Signaling: type must be a string"; return absl::nullopt; } result.type = type->second.string_value(); const auto subtype = object.find("subtype"); if (subtype == object.end() || !subtype->second.is_string()) { + RTC_LOG(LS_ERROR) << "Signaling: subtype must be a string"; return absl::nullopt; } result.subtype = subtype->second.string_value(); @@ -105,11 +112,13 @@ json11::Json::object RtpExtension_serialize(webrtc::RtpExtension const &rtpExten absl::optional RtpExtension_parse(json11::Json::object const &object) { const auto id = object.find("id"); if (id == object.end() || !id->second.is_number()) { + RTC_LOG(LS_ERROR) << "Signaling: id must be a number"; return absl::nullopt; } const auto uri = object.find("uri"); if (uri == object.end() || !uri->second.is_string()) { + RTC_LOG(LS_ERROR) << "Signaling: uri must be a string"; return absl::nullopt; } @@ -144,18 +153,21 @@ absl::optional PayloadType_parse(json11::Json::object const &object const auto id = object.find("id"); if (id == object.end() || !id->second.is_number()) { + RTC_LOG(LS_ERROR) << "Signaling: id must be a number"; return absl::nullopt; } result.id = id->second.int_value(); const auto name = object.find("name"); if (name == object.end() || !name->second.is_string()) { + RTC_LOG(LS_ERROR) << "Signaling: name must be a string"; return absl::nullopt; } result.name = name->second.string_value(); const auto clockrate = object.find("clockrate"); if (clockrate == object.end() || !clockrate->second.is_number()) { + RTC_LOG(LS_ERROR) << "Signaling: clockrate must be a number"; return absl::nullopt; } result.clockrate = clockrate->second.int_value(); @@ -163,6 +175,7 @@ absl::optional PayloadType_parse(json11::Json::object const &object const auto channels = object.find("channels"); if (channels != object.end()) { if (!channels->second.is_number()) { + RTC_LOG(LS_ERROR) << "Signaling: channels must be a number"; return absl::nullopt; } result.channels = channels->second.int_value(); @@ -171,15 +184,18 @@ absl::optional PayloadType_parse(json11::Json::object const &object const auto feedbackTypes = object.find("feedbackTypes"); if (feedbackTypes != object.end()) { if (!feedbackTypes->second.is_array()) { + RTC_LOG(LS_ERROR) << "Signaling: feedbackTypes must be an array"; return absl::nullopt; } for (const auto &feedbackType : feedbackTypes->second.array_items()) { if (!feedbackType.is_object()) { + RTC_LOG(LS_ERROR) << "Signaling: feedbackTypes items must be objects"; return absl::nullopt; } if (const auto parsedFeedbackType = FeedbackType_parse(feedbackType.object_items())) { result.feedbackTypes.push_back(parsedFeedbackType.value()); } else { + RTC_LOG(LS_ERROR) << "Signaling: could not parse FeedbackType"; return absl::nullopt; } } @@ -188,10 +204,12 @@ absl::optional PayloadType_parse(json11::Json::object const &object const auto parameters = object.find("parameters"); if (parameters != object.end()) { if (!parameters->second.is_object()) { + RTC_LOG(LS_ERROR) << "Signaling: parameters must be an object"; return absl::nullopt; } for (const auto &item : parameters->second.object_items()) { if (!item.second.is_string()) { + RTC_LOG(LS_ERROR) << "Signaling: parameters items must be strings"; return absl::nullopt; } result.parameters.push_back(std::make_pair(item.first, item.second.string_value())); @@ -203,6 +221,23 @@ absl::optional PayloadType_parse(json11::Json::object const &object json11::Json::object MediaContent_serialize(MediaContent const &mediaContent) { json11::Json::object object; + + std::string mappedType; + switch (mediaContent.type) { + case MediaContent::Type::Audio: { + mappedType = "audio"; + break; + } + case MediaContent::Type::Video: { + mappedType = "video"; + break; + } + default: { + RTC_FATAL() << "Unknown media type"; + break; + } + } + object.insert(std::make_pair("type", mappedType)); object.insert(std::make_pair("ssrc", json11::Json(uint32ToString(mediaContent.ssrc)))); @@ -233,9 +268,24 @@ json11::Json::object MediaContent_serialize(MediaContent const &mediaContent) { absl::optional MediaContent_parse(json11::Json::object const &object) { MediaContent result; + + const auto type = object.find("type"); + if (type == object.end() || !type->second.is_string()) { + RTC_LOG(LS_ERROR) << "Signaling: type must be a string"; + return absl::nullopt; + } + if (type->second.string_value() == "audio") { + result.type = MediaContent::Type::Audio; + } else if (type->second.string_value() == "video") { + result.type = MediaContent::Type::Video; + } else { + RTC_LOG(LS_ERROR) << "Signaling: type must be one of [\"audio\", \"video\"]"; + return absl::nullopt; + } const auto ssrc = object.find("ssrc"); if (ssrc == object.end()) { + RTC_LOG(LS_ERROR) << "Signaling: ssrc must be present"; return absl::nullopt; } if (ssrc->second.is_string()) { @@ -243,21 +293,25 @@ absl::optional MediaContent_parse(json11::Json::object const &obje } else if (ssrc->second.is_number()) { result.ssrc = (uint32_t)ssrc->second.number_value(); } else { + RTC_LOG(LS_ERROR) << "Signaling: ssrc must be a string or a number"; return absl::nullopt; } const auto ssrcGroups = object.find("ssrcGroups"); if (ssrcGroups != object.end()) { if (!ssrcGroups->second.is_array()) { + RTC_LOG(LS_ERROR) << "Signaling: ssrcGroups must be an array"; return absl::nullopt; } for (const auto &ssrcGroup : ssrcGroups->second.array_items()) { if (!ssrcGroup.is_object()) { + RTC_LOG(LS_ERROR) << "Signaling: ssrcsGroups items must be objects"; return absl::nullopt; } if (const auto parsedSsrcGroup = SsrcGroup_parse(ssrcGroup.object_items())) { result.ssrcGroups.push_back(parsedSsrcGroup.value()); } else { + RTC_LOG(LS_ERROR) << "Signaling: could not parse SsrcGroup"; return absl::nullopt; } } @@ -266,15 +320,18 @@ absl::optional MediaContent_parse(json11::Json::object const &obje const auto payloadTypes = object.find("payloadTypes"); if (payloadTypes != object.end()) { if (!payloadTypes->second.is_array()) { + RTC_LOG(LS_ERROR) << "Signaling: payloadTypes must be an array"; return absl::nullopt; } for (const auto &payloadType : payloadTypes->second.array_items()) { if (!payloadType.is_object()) { + RTC_LOG(LS_ERROR) << "Signaling: payloadTypes items must be objects"; return absl::nullopt; } if (const auto parsedPayloadType = PayloadType_parse(payloadType.object_items())) { result.payloadTypes.push_back(parsedPayloadType.value()); } else { + RTC_LOG(LS_ERROR) << "Signaling: could not parse PayloadType"; return absl::nullopt; } } @@ -283,15 +340,18 @@ absl::optional MediaContent_parse(json11::Json::object const &obje const auto rtpExtensions = object.find("rtpExtensions"); if (rtpExtensions != object.end()) { if (!rtpExtensions->second.is_array()) { + RTC_LOG(LS_ERROR) << "Signaling: rtpExtensions must be an array"; return absl::nullopt; } for (const auto &rtpExtension : rtpExtensions->second.array_items()) { if (!rtpExtension.is_object()) { + RTC_LOG(LS_ERROR) << "Signaling: rtpExtensions items must be objects"; return absl::nullopt; } if (const auto parsedRtpExtension = RtpExtension_parse(rtpExtension.object_items())) { result.rtpExtensions.push_back(parsedRtpExtension.value()); } else { + RTC_LOG(LS_ERROR) << "Signaling: could not parse RtpExtension"; return absl::nullopt; } } @@ -317,18 +377,6 @@ std::vector InitialSetupMessage_serialize(const InitialSetupMessage * c } object.insert(std::make_pair("fingerprints", json11::Json(std::move(jsonFingerprints)))); - if (const auto audio = message->audio) { - object.insert(std::make_pair("audio", json11::Json(MediaContent_serialize(audio.value())))); - } - - if (const auto video = message->video) { - object.insert(std::make_pair("video", json11::Json(MediaContent_serialize(video.value())))); - } - - if (const auto screencast = message->screencast) { - object.insert(std::make_pair("screencast", json11::Json(MediaContent_serialize(screencast.value())))); - } - auto json = json11::Json(std::move(object)); std::string result = json.dump(); return std::vector(result.begin(), result.end()); @@ -337,31 +385,38 @@ std::vector InitialSetupMessage_serialize(const InitialSetupMessage * c absl::optional InitialSetupMessage_parse(json11::Json::object const &object) { const auto ufrag = object.find("ufrag"); if (ufrag == object.end() || !ufrag->second.is_string()) { + RTC_LOG(LS_ERROR) << "Signaling: ufrag must be a string"; return absl::nullopt; } const auto pwd = object.find("pwd"); if (pwd == object.end() || !pwd->second.is_string()) { + RTC_LOG(LS_ERROR) << "Signaling: pwd must be a string"; return absl::nullopt; } const auto fingerprints = object.find("fingerprints"); if (fingerprints == object.end() || !fingerprints->second.is_array()) { + RTC_LOG(LS_ERROR) << "Signaling: fingerprints must be an array"; return absl::nullopt; } std::vector parsedFingerprints; for (const auto &fingerprintObject : fingerprints->second.array_items()) { if (!fingerprintObject.is_object()) { + RTC_LOG(LS_ERROR) << "Signaling: fingerprints items must be objects"; return absl::nullopt; } const auto hash = fingerprintObject.object_items().find("hash"); if (hash == fingerprintObject.object_items().end() || !hash->second.is_string()) { + RTC_LOG(LS_ERROR) << "Signaling: hash must be a string"; return absl::nullopt; } const auto setup = fingerprintObject.object_items().find("setup"); if (setup == fingerprintObject.object_items().end() || !setup->second.is_string()) { + RTC_LOG(LS_ERROR) << "Signaling: setup must be a string"; return absl::nullopt; } const auto fingerprint = fingerprintObject.object_items().find("fingerprint"); if (fingerprint == fingerprintObject.object_items().end() || !fingerprint->second.is_string()) { + RTC_LOG(LS_ERROR) << "Signaling: fingerprint must be a string"; return absl::nullopt; } @@ -378,39 +433,61 @@ absl::optional InitialSetupMessage_parse(json11::Json::obje message.pwd = pwd->second.string_value(); message.fingerprints = std::move(parsedFingerprints); - const auto audio = object.find("audio"); - if (audio != object.end()) { - if (!audio->second.is_object()) { - return absl::nullopt; - } - if (const auto parsedAudio = MediaContent_parse(audio->second.object_items())) { - message.audio = parsedAudio.value(); - } else { - return absl::nullopt; - } + return message; +} + +std::vector NegotiateChannelsMessage_serialize(const NegotiateChannelsMessage * const message) { + json11::Json::object object; + + object.insert(std::make_pair("@type", json11::Json("NegotiateChannels"))); + + object.insert(std::make_pair("exchangeId", json11::Json(uint32ToString(message->exchangeId)))); + + json11::Json::array contents; + for (const auto &content : message->contents) { + contents.push_back(json11::Json(MediaContent_serialize(content))); + } + object.insert(std::make_pair("contents", std::move(contents))); + + auto json = json11::Json(std::move(object)); + std::string result = json.dump(); + return std::vector(result.begin(), result.end()); +} + +absl::optional NegotiateChannelsMessage_parse(json11::Json::object const &object) { + NegotiateChannelsMessage message; + + const auto exchangeId = object.find("exchangeId"); + + if (exchangeId == object.end()) { + RTC_LOG(LS_ERROR) << "Signaling: exchangeId must be present"; + return absl::nullopt; + } else if (exchangeId->second.is_string()) { + message.exchangeId = stringToUInt32(exchangeId->second.string_value()); + } else if (exchangeId->second.is_number()) { + message.exchangeId = (uint32_t)exchangeId->second.number_value(); + } else { + RTC_LOG(LS_ERROR) << "Signaling: exchangeId must be a string or a number"; + return absl::nullopt; } - const auto video = object.find("video"); - if (video != object.end()) { - if (!video->second.is_object()) { + const auto contents = object.find("contents"); + if (contents != object.end()) { + if (!contents->second.is_array()) { + RTC_LOG(LS_ERROR) << "Signaling: contents must be an array"; return absl::nullopt; } - if (const auto parsedVideo = MediaContent_parse(video->second.object_items())) { - message.video = parsedVideo.value(); - } else { - return absl::nullopt; - } - } - - const auto screencast = object.find("screencast"); - if (screencast != object.end()) { - if (!screencast->second.is_object()) { - return absl::nullopt; - } - if (const auto parsedScreencast = MediaContent_parse(screencast->second.object_items())) { - message.screencast = parsedScreencast.value(); - } else { - return absl::nullopt; + for (const auto &content : contents->second.array_items()) { + if (!content.is_object()) { + RTC_LOG(LS_ERROR) << "Signaling: contents items must be objects"; + return absl::nullopt; + } + if (auto parsedContent = MediaContent_parse(content.object_items())) { + message.contents.push_back(std::move(parsedContent.value())); + } else { + RTC_LOG(LS_ERROR) << "Signaling: could not parse MediaContent"; + return absl::nullopt; + } } } @@ -429,11 +506,13 @@ json11::Json::object ConnectionAddress_serialize(ConnectionAddress const &connec absl::optional ConnectionAddress_parse(json11::Json::object const &object) { const auto ip = object.find("ip"); if (ip == object.end() || !ip->second.is_string()) { + RTC_LOG(LS_ERROR) << "Signaling: ip must be a string"; return absl::nullopt; } const auto port = object.find("port"); if (port == object.end() || !port->second.is_number()) { + RTC_LOG(LS_ERROR) << "Signaling: port must be a number"; return absl::nullopt; } @@ -466,12 +545,14 @@ std::vector CandidatesMessage_serialize(const CandidatesMessage * const absl::optional CandidatesMessage_parse(json11::Json::object const &object) { const auto candidates = object.find("candidates"); if (candidates == object.end() || !candidates->second.is_array()) { + RTC_LOG(LS_ERROR) << "Signaling: candidates must be an array"; return absl::nullopt; } std::vector parsedCandidates; for (const auto &candidateObject : candidates->second.array_items()) { if (!candidateObject.is_object()) { + RTC_LOG(LS_ERROR) << "Signaling: candidates items must be objects"; return absl::nullopt; } @@ -479,6 +560,7 @@ absl::optional CandidatesMessage_parse(json11::Json::object c const auto sdpString = candidateObject.object_items().find("sdpString"); if (sdpString == candidateObject.object_items().end() || !sdpString->second.is_string()) { + RTC_LOG(LS_ERROR) << "Signaling: sdpString must be a string"; return absl::nullopt; } candidate.sdpString = sdpString->second.string_value(); @@ -577,6 +659,7 @@ absl::optional MediaStateMessage_parse(json11::Json::object c const auto muted = object.find("muted"); if (muted != object.end()) { if (!muted->second.is_bool()) { + RTC_LOG(LS_ERROR) << "Signaling: muted must be a bool"; return absl::nullopt; } message.isMuted = muted->second.bool_value(); @@ -585,6 +668,7 @@ absl::optional MediaStateMessage_parse(json11::Json::object c const auto lowBattery = object.find("lowBattery"); if (lowBattery != object.end()) { if (!lowBattery->second.is_bool()) { + RTC_LOG(LS_ERROR) << "Signaling: lowBattery must be a bool"; return absl::nullopt; } message.isBatteryLow = lowBattery->second.bool_value(); @@ -593,6 +677,7 @@ absl::optional MediaStateMessage_parse(json11::Json::object c const auto videoState = object.find("videoState"); if (videoState != object.end()) { if (!videoState->second.is_string()) { + RTC_LOG(LS_ERROR) << "Signaling: videoState must be a string"; return absl::nullopt; } if (videoState->second.string_value() == "inactive") { @@ -601,6 +686,8 @@ absl::optional MediaStateMessage_parse(json11::Json::object c message.videoState = MediaStateMessage::VideoState::Suspended; } else if (videoState->second.string_value() == "active") { message.videoState = MediaStateMessage::VideoState::Active; + } else { + RTC_LOG(LS_ERROR) << "videoState must be one of [\"inactive\", \"suspended\", \"active\"]"; } } else { message.videoState = MediaStateMessage::VideoState::Inactive; @@ -609,6 +696,7 @@ absl::optional MediaStateMessage_parse(json11::Json::object c const auto screencastState = object.find("screencastState"); if (screencastState != object.end()) { if (!screencastState->second.is_string()) { + RTC_LOG(LS_ERROR) << "Signaling: screencastState must be a string"; return absl::nullopt; } if (screencastState->second.string_value() == "inactive") { @@ -617,6 +705,8 @@ absl::optional MediaStateMessage_parse(json11::Json::object c message.screencastState = MediaStateMessage::VideoState::Suspended; } else if (screencastState->second.string_value() == "active") { message.screencastState = MediaStateMessage::VideoState::Active; + } else { + RTC_LOG(LS_ERROR) << "Signaling: screencastState must be one of [\"inactive\", \"suspended\", \"active\"]"; } } else { message.screencastState = MediaStateMessage::VideoState::Inactive; @@ -625,6 +715,7 @@ absl::optional MediaStateMessage_parse(json11::Json::object c const auto videoRotation = object.find("videoRotation"); if (videoRotation != object.end()) { if (!videoRotation->second.is_number()) { + RTC_LOG(LS_ERROR) << "Signaling: videoRotation must be a number"; return absl::nullopt; } if (videoState->second.int_value() == 0) { @@ -636,6 +727,7 @@ absl::optional MediaStateMessage_parse(json11::Json::object c } else if (videoState->second.int_value() == 270) { message.videoRotation = MediaStateMessage::VideoRotation::Rotation270; } else { + RTC_LOG(LS_ERROR) << "Signaling: videoRotation must be one of [0, 90, 180, 270]"; message.videoRotation = MediaStateMessage::VideoRotation::Rotation0; } } else { @@ -652,6 +744,8 @@ std::vector Message::serialize() const { return CandidatesMessage_serialize(candidates); } else if (const auto mediaState = absl::get_if(&data)) { return MediaStateMessage_serialize(mediaState); + } else if (const auto negotiateChannels = absl::get_if(&data)) { + return NegotiateChannelsMessage_serialize(negotiateChannels); } else { return {}; } @@ -661,19 +755,32 @@ absl::optional Message::parse(const std::vector &data) { std::string parsingError; auto json = json11::Json::parse(std::string(data.begin(), data.end()), parsingError); if (json.type() != json11::Json::OBJECT) { + RTC_LOG(LS_ERROR) << "Signaling: message must be an object"; return absl::nullopt; } auto type = json.object_items().find("@type"); if (type == json.object_items().end()) { + RTC_LOG(LS_ERROR) << "Signaling: message does not contain @type attribute"; return absl::nullopt; } if (!type->second.is_string()) { + RTC_LOG(LS_ERROR) << "Signaling: @type attribute must be a string"; return absl::nullopt; } if (type->second.string_value() == "InitialSetup") { auto parsed = InitialSetupMessage_parse(json.object_items()); if (!parsed) { + RTC_LOG(LS_ERROR) << "Signaling: could not parse " << type->second.string_value() << " message"; + return absl::nullopt; + } + Message message; + message.data = std::move(parsed.value()); + return message; + } else if (type->second.string_value() == "NegotiateChannels") { + auto parsed = NegotiateChannelsMessage_parse(json.object_items()); + if (!parsed) { + RTC_LOG(LS_ERROR) << "Signaling: could not parse " << type->second.string_value() << " message"; return absl::nullopt; } Message message; @@ -682,6 +789,7 @@ absl::optional Message::parse(const std::vector &data) { } else if (type->second.string_value() == "Candidates") { auto parsed = CandidatesMessage_parse(json.object_items()); if (!parsed) { + RTC_LOG(LS_ERROR) << "Signaling: could not parse " << type->second.string_value() << " message"; return absl::nullopt; } Message message; @@ -690,12 +798,14 @@ absl::optional Message::parse(const std::vector &data) { } else if (type->second.string_value() == "MediaState") { auto parsed = MediaStateMessage_parse(json.object_items()); if (!parsed) { + RTC_LOG(LS_ERROR) << "Signaling: could not parse " << type->second.string_value() << " message"; return absl::nullopt; } Message message; message.data = std::move(parsed.value()); return message; } else { + RTC_LOG(LS_ERROR) << "Signaling: unknown message type " << type->second.string_value(); return absl::nullopt; } } diff --git a/TMessagesProj/jni/voip/tgcalls/v2/Signaling.h b/TMessagesProj/jni/voip/tgcalls/v2/Signaling.h index af957318f..686c25972 100644 --- a/TMessagesProj/jni/voip/tgcalls/v2/Signaling.h +++ b/TMessagesProj/jni/voip/tgcalls/v2/Signaling.h @@ -30,11 +30,34 @@ struct IceCandidate { struct SsrcGroup { std::vector ssrcs; std::string semantics; + + bool operator==(SsrcGroup const &rhs) const { + if (ssrcs != rhs.ssrcs) { + return false; + } + + if (semantics != rhs.semantics) { + return false; + } + + return true; + } }; struct FeedbackType { std::string type; std::string subtype; + + bool operator==(FeedbackType const &rhs) const { + if (type != rhs.type) { + return false; + } + if (subtype != rhs.subtype) { + return false; + } + + return true; + } }; struct PayloadType { @@ -44,22 +67,83 @@ struct PayloadType { uint32_t channels = 0; std::vector feedbackTypes; std::vector> parameters; + + bool operator==(PayloadType const &rhs) const { + if (id != rhs.id) { + return false; + } + if (name != rhs.name) { + return false; + } + if (clockrate != rhs.clockrate) { + return false; + } + if (channels != rhs.channels) { + return false; + } + if (feedbackTypes != rhs.feedbackTypes) { + return false; + } + if (parameters != rhs.parameters) { + return false; + } + + return true; + } }; struct MediaContent { + enum class Type { + Audio, + Video + }; + + Type type = Type::Audio; uint32_t ssrc = 0; std::vector ssrcGroups; std::vector payloadTypes; std::vector rtpExtensions; + + bool operator==(const MediaContent& rhs) const { + if (type != rhs.type) { + return false; + } + if (ssrc != rhs.ssrc) { + return false; + } + if (ssrcGroups != rhs.ssrcGroups) { + return false; + } + + std::vector sortedPayloadTypes = payloadTypes; + std::sort(sortedPayloadTypes.begin(), sortedPayloadTypes.end(), [](PayloadType const &lhs, PayloadType const &rhs) { + return lhs.id < rhs.id; + }); + std::vector sortedRhsPayloadTypes = rhs.payloadTypes; + std::sort(sortedRhsPayloadTypes.begin(), sortedRhsPayloadTypes.end(), [](PayloadType const &lhs, PayloadType const &rhs) { + return lhs.id < rhs.id; + }); + if (sortedPayloadTypes != sortedRhsPayloadTypes) { + return false; + } + + if (rtpExtensions != rhs.rtpExtensions) { + return false; + } + + return true; + } }; struct InitialSetupMessage { std::string ufrag; std::string pwd; std::vector fingerprints; - absl::optional audio; - absl::optional video; - absl::optional screencast; +}; + +struct NegotiateChannelsMessage { + uint32_t exchangeId = 0; + std::vector contents; }; struct CandidatesMessage { @@ -91,6 +175,7 @@ struct MediaStateMessage { struct Message { absl::variant< InitialSetupMessage, + NegotiateChannelsMessage, CandidatesMessage, MediaStateMessage> data; diff --git a/TMessagesProj/jni/voip/tgcalls/v2_4_0_0/InstanceV2_4_0_0Impl.cpp b/TMessagesProj/jni/voip/tgcalls/v2_4_0_0/InstanceV2_4_0_0Impl.cpp new file mode 100644 index 000000000..8a822c723 --- /dev/null +++ b/TMessagesProj/jni/voip/tgcalls/v2_4_0_0/InstanceV2_4_0_0Impl.cpp @@ -0,0 +1,2242 @@ +#include "v2_4_0_0/InstanceV2_4_0_0Impl.h" + +#include "LogSinkImpl.h" +#include "VideoCaptureInterfaceImpl.h" +#include "VideoCapturerInterface.h" +#include "v2/NativeNetworkingImpl.h" +#include "v2_4_0_0/Signaling_4_0_0.h" + +#include "CodecSelectHelper.h" +#include "platform/PlatformInterface.h" + +#include "api/audio_codecs/audio_decoder_factory_template.h" +#include "api/audio_codecs/audio_encoder_factory_template.h" +#include "api/audio_codecs/opus/audio_decoder_opus.h" +#include "api/audio_codecs/opus/audio_decoder_multi_channel_opus.h" +#include "api/audio_codecs/opus/audio_encoder_opus.h" +#include "api/audio_codecs/L16/audio_decoder_L16.h" +#include "api/audio_codecs/L16/audio_encoder_L16.h" +#include "api/task_queue/default_task_queue_factory.h" +#include "media/engine/webrtc_media_engine.h" +#include "system_wrappers/include/field_trial.h" +#include "api/video/builtin_video_bitrate_allocator_factory.h" +#include "call/call.h" +#include "api/call/audio_sink.h" +#include "modules/audio_processing/audio_buffer.h" +#include "absl/strings/match.h" +#include "pc/channel_manager.h" +#include "audio/audio_state.h" +#include "modules/audio_coding/neteq/default_neteq_factory.h" +#include "modules/audio_coding/include/audio_coding_module.h" +#include "api/candidate.h" +#include "api/jsep_ice_candidate.h" +#include "pc/used_ids.h" +#include "media/base/sdp_video_format_utils.h" + +#include "AudioFrame.h" +#include "ThreadLocalObject.h" +#include "Manager.h" +#include "NetworkManager.h" +#include "VideoCaptureInterfaceImpl.h" +#include "platform/PlatformInterface.h" +#include "LogSinkImpl.h" +#include "CodecSelectHelper.h" +#include "AudioDeviceHelper.h" +#include "v2/SignalingEncryption.h" +#ifdef WEBRTC_IOS +#include "platform/darwin/iOS/tgcalls_audio_device_module_ios.h" +#endif +#include +#include + +namespace tgcalls { +namespace { + +static std::string intToString(int value) { + std::ostringstream stringStream; + stringStream << value; + return stringStream.str(); +} + +static VideoCaptureInterfaceObject *GetVideoCaptureAssumingSameThread(VideoCaptureInterface *videoCapture) { + return videoCapture + ? static_cast(videoCapture)->object()->getSyncAssumingSameThread() + : nullptr; +} + +struct OutgoingVideoFormat { + cricket::VideoCodec videoCodec; + absl::optional rtxCodec; +}; + +static void addDefaultFeedbackParams(cricket::VideoCodec *codec) { + // Don't add any feedback params for RED and ULPFEC. + if (codec->name == cricket::kRedCodecName || codec->name == cricket::kUlpfecCodecName) { + return; + } + codec->AddFeedbackParam(cricket::FeedbackParam(cricket::kRtcpFbParamRemb, cricket::kParamValueEmpty)); + codec->AddFeedbackParam(cricket::FeedbackParam(cricket::kRtcpFbParamTransportCc, cricket::kParamValueEmpty)); + // Don't add any more feedback params for FLEXFEC. + if (codec->name == cricket::kFlexfecCodecName) { + return; + } + codec->AddFeedbackParam(cricket::FeedbackParam(cricket::kRtcpFbParamCcm, cricket::kRtcpFbCcmParamFir)); + codec->AddFeedbackParam(cricket::FeedbackParam(cricket::kRtcpFbParamNack, cricket::kParamValueEmpty)); + codec->AddFeedbackParam(cricket::FeedbackParam(cricket::kRtcpFbParamNack, cricket::kRtcpFbNackParamPli)); +} + +template +static bool IsRtxCodec(const C& codec) { + return absl::EqualsIgnoreCase(codec.name, cricket::kRtxCodecName); +} + +template +static bool ReferencedCodecsMatch(const std::vector& codecs1, + const int codec1_id, + const std::vector& codecs2, + const int codec2_id) { + const C* codec1 = FindCodecById(codecs1, codec1_id); + const C* codec2 = FindCodecById(codecs2, codec2_id); + return codec1 != nullptr && codec2 != nullptr && codec1->Matches(*codec2); +} + +// Finds a codec in |codecs2| that matches |codec_to_match|, which is +// a member of |codecs1|. If |codec_to_match| is an RTX codec, both +// the codecs themselves and their associated codecs must match. +template +static bool FindMatchingCodec(const std::vector& codecs1, + const std::vector& codecs2, + const C& codec_to_match, + C* found_codec) { + // |codec_to_match| should be a member of |codecs1|, in order to look up RTX + // codecs' associated codecs correctly. If not, that's a programming error. + RTC_DCHECK(absl::c_any_of(codecs1, [&codec_to_match](const C& codec) { + return &codec == &codec_to_match; + })); + for (const C& potential_match : codecs2) { + if (potential_match.Matches(codec_to_match)) { + if (IsRtxCodec(codec_to_match)) { + int apt_value_1 = 0; + int apt_value_2 = 0; + if (!codec_to_match.GetParam(cricket::kCodecParamAssociatedPayloadType, + &apt_value_1) || + !potential_match.GetParam(cricket::kCodecParamAssociatedPayloadType, + &apt_value_2)) { + RTC_LOG(LS_WARNING) << "RTX missing associated payload type."; + continue; + } + if (!ReferencedCodecsMatch(codecs1, apt_value_1, codecs2, + apt_value_2)) { + continue; + } + } + if (found_codec) { + *found_codec = potential_match; + } + return true; + } + } + return false; +} + +template +static void NegotiatePacketization(const C& local_codec, + const C& remote_codec, + C* negotiated_codec) {} + +template <> +void NegotiatePacketization(const cricket::VideoCodec& local_codec, + const cricket::VideoCodec& remote_codec, + cricket::VideoCodec* negotiated_codec) { + negotiated_codec->packetization = + cricket::VideoCodec::IntersectPacketization(local_codec, remote_codec); +} + +template +static void NegotiateCodecs(const std::vector& local_codecs, + const std::vector& offered_codecs, + std::vector* negotiated_codecs, + bool keep_offer_order) { + for (const C& ours : local_codecs) { + C theirs; + // Note that we intentionally only find one matching codec for each of our + // local codecs, in case the remote offer contains duplicate codecs. + if (FindMatchingCodec(local_codecs, offered_codecs, ours, &theirs)) { + C negotiated = ours; + NegotiatePacketization(ours, theirs, &negotiated); + negotiated.IntersectFeedbackParams(theirs); + if (IsRtxCodec(negotiated)) { + const auto apt_it = + theirs.params.find(cricket::kCodecParamAssociatedPayloadType); + // FindMatchingCodec shouldn't return something with no apt value. + RTC_DCHECK(apt_it != theirs.params.end()); + negotiated.SetParam(cricket::kCodecParamAssociatedPayloadType, apt_it->second); + } + if (absl::EqualsIgnoreCase(ours.name, cricket::kH264CodecName)) { + webrtc::H264GenerateProfileLevelIdForAnswer( + ours.params, theirs.params, &negotiated.params); + } + negotiated.id = theirs.id; + negotiated.name = theirs.name; + negotiated_codecs->push_back(std::move(negotiated)); + } + } + if (keep_offer_order) { + // RFC3264: Although the answerer MAY list the formats in their desired + // order of preference, it is RECOMMENDED that unless there is a + // specific reason, the answerer list formats in the same relative order + // they were present in the offer. + // This can be skipped when the transceiver has any codec preferences. + std::unordered_map payload_type_preferences; + int preference = static_cast(offered_codecs.size() + 1); + for (const C& codec : offered_codecs) { + payload_type_preferences[codec.id] = preference--; + } + absl::c_sort(*negotiated_codecs, [&payload_type_preferences](const C& a, + const C& b) { + return payload_type_preferences[a.id] > payload_type_preferences[b.id]; + }); + } +} + +// Find the codec in |codec_list| that |rtx_codec| is associated with. +template +static const C* GetAssociatedCodec(const std::vector& codec_list, + const C& rtx_codec) { + std::string associated_pt_str; + if (!rtx_codec.GetParam(cricket::kCodecParamAssociatedPayloadType, + &associated_pt_str)) { + RTC_LOG(LS_WARNING) << "RTX codec " << rtx_codec.name + << " is missing an associated payload type."; + return nullptr; + } + + int associated_pt; + if (!rtc::FromString(associated_pt_str, &associated_pt)) { + RTC_LOG(LS_WARNING) << "Couldn't convert payload type " << associated_pt_str + << " of RTX codec " << rtx_codec.name + << " to an integer."; + return nullptr; + } + + // Find the associated reference codec for the reference RTX codec. + const C* associated_codec = FindCodecById(codec_list, associated_pt); + if (!associated_codec) { + RTC_LOG(LS_WARNING) << "Couldn't find associated codec with payload type " + << associated_pt << " for RTX codec " << rtx_codec.name + << "."; + } + return associated_codec; +} + +// Adds all codecs from |reference_codecs| to |offered_codecs| that don't +// already exist in |offered_codecs| and ensure the payload types don't +// collide. +template +static void MergeCodecs(const std::vector& reference_codecs, + std::vector* offered_codecs, + cricket::UsedPayloadTypes* used_pltypes) { + // Add all new codecs that are not RTX codecs. + for (const C& reference_codec : reference_codecs) { + if (!IsRtxCodec(reference_codec) && + !FindMatchingCodec(reference_codecs, *offered_codecs, + reference_codec, nullptr)) { + C codec = reference_codec; + used_pltypes->FindAndSetIdUsed(&codec); + offered_codecs->push_back(codec); + } + } + + // Add all new RTX codecs. + for (const C& reference_codec : reference_codecs) { + if (IsRtxCodec(reference_codec) && + !FindMatchingCodec(reference_codecs, *offered_codecs, + reference_codec, nullptr)) { + C rtx_codec = reference_codec; + const C* associated_codec = + GetAssociatedCodec(reference_codecs, rtx_codec); + if (!associated_codec) { + continue; + } + // Find a codec in the offered list that matches the reference codec. + // Its payload type may be different than the reference codec. + C matching_codec; + if (!FindMatchingCodec(reference_codecs, *offered_codecs, + *associated_codec, &matching_codec)) { + RTC_LOG(LS_WARNING) + << "Couldn't find matching " << associated_codec->name << " codec."; + continue; + } + + rtx_codec.params[cricket::kCodecParamAssociatedPayloadType] = + rtc::ToString(matching_codec.id); + used_pltypes->FindAndSetIdUsed(&rtx_codec); + offered_codecs->push_back(rtx_codec); + } + } +} + +static std::vector generateAvailableVideoFormats(std::vector const &formats) { + if (formats.empty()) { + return {}; + } + + constexpr int kFirstDynamicPayloadType = 100; + constexpr int kLastDynamicPayloadType = 127; + + int payload_type = kFirstDynamicPayloadType; + + std::vector result; + + //bool codecSelected = false; + + for (const auto &format : formats) { + /*if (codecSelected) { + break; + }*/ + + bool alreadyAdded = false; + for (const auto &it : result) { + if (it.videoCodec.name == format.name) { + alreadyAdded = true; + break; + } + } + if (alreadyAdded) { + continue; + } + + OutgoingVideoFormat resultFormat; + + cricket::VideoCodec codec(format); + codec.id = payload_type; + addDefaultFeedbackParams(&codec); + + resultFormat.videoCodec = codec; + //codecSelected = true; + + // Increment payload type. + ++payload_type; + if (payload_type > kLastDynamicPayloadType) { + RTC_LOG(LS_ERROR) << "Out of dynamic payload types, skipping the rest."; + break; + } + + // Add associated RTX codec for non-FEC codecs. + if (!absl::EqualsIgnoreCase(codec.name, cricket::kUlpfecCodecName) && + !absl::EqualsIgnoreCase(codec.name, cricket::kFlexfecCodecName)) { + resultFormat.rtxCodec = cricket::VideoCodec::CreateRtxCodec(payload_type, codec.id); + + // Increment payload type. + ++payload_type; + if (payload_type > kLastDynamicPayloadType) { + RTC_LOG(LS_ERROR) << "Out of dynamic payload types, skipping the rest."; + break; + } + } + + result.push_back(std::move(resultFormat)); + } + return result; +} + +static void getCodecsFromMediaContent(signaling_4_0_0::MediaContent const &content, std::vector &codecs) { + for (const auto &payloadType : content.payloadTypes) { + cricket::VideoCodec codec(payloadType.id, payloadType.name); + for (const auto &feedbackType : payloadType.feedbackTypes) { + codec.AddFeedbackParam(cricket::FeedbackParam(feedbackType.type, feedbackType.subtype)); + } + for (const auto ¶meter : payloadType.parameters) { + codec.SetParam(parameter.first, parameter.second); + } + codecs.push_back(std::move(codec)); + } +} + +static std::vector getPayloadTypesFromVideoCodecs(std::vector const &codecs) { + std::vector payloadTypes; + + for (const auto &codec : codecs) { + signaling_4_0_0::PayloadType payloadType; + + payloadType.id = codec.id; + payloadType.name = codec.name; + payloadType.clockrate = 90000; + payloadType.channels = 0; + + for (const auto &feedbackParam : codec.feedback_params.params()) { + signaling_4_0_0::FeedbackType feedbackType; + feedbackType.type = feedbackParam.id(); + feedbackType.subtype = feedbackParam.param(); + payloadType.feedbackTypes.push_back(std::move(feedbackType)); + } + + for (const auto ¶m : codec.params) { + payloadType.parameters.push_back(std::make_pair(param.first, param.second)); + } + + payloadTypes.push_back(std::move(payloadType)); + } + + return payloadTypes; +} + +static void getCodecsFromMediaContent(signaling_4_0_0::MediaContent const &content, std::vector &codecs) { + for (const auto &payloadType : content.payloadTypes) { + cricket::AudioCodec codec(payloadType.id, payloadType.name, payloadType.clockrate, 0, payloadType.channels); + for (const auto &feedbackType : payloadType.feedbackTypes) { + codec.AddFeedbackParam(cricket::FeedbackParam(feedbackType.type, feedbackType.subtype)); + } + for (const auto ¶meter : payloadType.parameters) { + codec.SetParam(parameter.first, parameter.second); + } + codecs.push_back(std::move(codec)); + } +} + +static std::vector getPayloadTypesFromAudioCodecs(std::vector const &codecs) { + std::vector payloadTypes; + + for (const auto &codec : codecs) { + signaling_4_0_0::PayloadType payloadType; + + payloadType.id = codec.id; + payloadType.name = codec.name; + payloadType.clockrate = codec.clockrate; + payloadType.channels = (uint32_t)codec.channels; + + for (const auto &feedbackParam : codec.feedback_params.params()) { + signaling_4_0_0::FeedbackType feedbackType; + feedbackType.type = feedbackParam.id(); + feedbackType.subtype = feedbackParam.param(); + payloadType.feedbackTypes.push_back(std::move(feedbackType)); + } + + for (const auto ¶m : codec.params) { + payloadType.parameters.push_back(std::make_pair(param.first, param.second)); + } + + payloadTypes.push_back(std::move(payloadType)); + } + + return payloadTypes; +} + +template +struct NegotiatedMediaContent { + uint32_t ssrc = 0; + std::vector ssrcGroups; + std::vector rtpExtensions; + std::vector codecs; +}; + +static bool FindByUri(const cricket::RtpHeaderExtensions& extensions, + const webrtc::RtpExtension& ext_to_match, + webrtc::RtpExtension* found_extension) { + // We assume that all URIs are given in a canonical format. + const webrtc::RtpExtension* found = + webrtc::RtpExtension::FindHeaderExtensionByUri( + extensions, + ext_to_match.uri, + webrtc::RtpExtension::Filter::kPreferEncryptedExtension + ); + if (!found) { + return false; + } + if (found_extension) { + *found_extension = *found; + } + return true; +} + +template +static NegotiatedMediaContent negotiateMediaContent(signaling_4_0_0::MediaContent const &baseMediaContent, signaling_4_0_0::MediaContent const &localContent, signaling_4_0_0::MediaContent const &remoteContent, bool isAnswer) { + std::vector localCodecs; + getCodecsFromMediaContent(localContent, localCodecs); + + std::vector remoteCodecs; + getCodecsFromMediaContent(remoteContent, remoteCodecs); + + std::vector negotiatedCodecs; + + cricket::UsedPayloadTypes usedPayloadTypes; + NegotiateCodecs(localCodecs, remoteCodecs, &negotiatedCodecs, true); + + NegotiatedMediaContent result; + + result.ssrc = baseMediaContent.ssrc; + result.ssrcGroups = baseMediaContent.ssrcGroups; + result.codecs = std::move(negotiatedCodecs); + + cricket::UsedRtpHeaderExtensionIds extensionIds(cricket::UsedRtpHeaderExtensionIds::IdDomain::kOneByteOnly); + + for (const auto &extension : remoteContent.rtpExtensions) { + if (isAnswer) { + webrtc::RtpExtension found; + if (!FindByUri(localContent.rtpExtensions, extension, &found)) { + continue; + } + } + + webrtc::RtpExtension mutableExtension = extension; + extensionIds.FindAndSetIdUsed(&mutableExtension); + result.rtpExtensions.push_back(std::move(mutableExtension)); + } + + if (!isAnswer) { + for (const auto &extension : localContent.rtpExtensions) { + webrtc::RtpExtension found; + if (!FindByUri(result.rtpExtensions, extension, &found)) { + webrtc::RtpExtension mutableExtension = extension; + extensionIds.FindAndSetIdUsed(&mutableExtension); + result.rtpExtensions.push_back(std::move(mutableExtension)); + } + } + } + + return result; +} + +class OutgoingAudioChannel : public sigslot::has_slots<> { +public: + static absl::optional createOutgoingContentDescription() { + signaling_4_0_0::MediaContent mediaContent; + + auto generator = std::mt19937(std::random_device()()); + auto distribution = std::uniform_int_distribution(); + do { + mediaContent.ssrc = distribution(generator) & 0x7fffffffU; + } while (!mediaContent.ssrc); + + mediaContent.rtpExtensions.emplace_back(webrtc::RtpExtension::kAudioLevelUri, 1); + mediaContent.rtpExtensions.emplace_back(webrtc::RtpExtension::kAbsSendTimeUri, 2); + mediaContent.rtpExtensions.emplace_back(webrtc::RtpExtension::kTransportSequenceNumberUri, 3); + + cricket::AudioCodec opusCodec(109, "opus", 48000, 0, 2); + opusCodec.AddFeedbackParam(cricket::FeedbackParam(cricket::kRtcpFbParamTransportCc)); + opusCodec.SetParam(cricket::kCodecParamUseInbandFec, 1); + opusCodec.SetParam(cricket::kCodecParamMinPTime, 60); + + mediaContent.payloadTypes = getPayloadTypesFromAudioCodecs({ opusCodec }); + + return mediaContent; + } + +public: + OutgoingAudioChannel( + webrtc::Call *call, + cricket::ChannelManager *channelManager, + rtc::UniqueRandomIdGenerator *uniqueRandomIdGenerator, + webrtc::LocalAudioSinkAdapter *audioSource, + webrtc::RtpTransport *rtpTransport, + NegotiatedMediaContent const &mediaContent, + std::shared_ptr threads + ) : + _threads(threads), + _ssrc(mediaContent.ssrc), + _call(call), + _channelManager(channelManager), + _audioSource(audioSource) { + cricket::AudioOptions audioOptions; + bool _disableOutgoingAudioProcessing = false; + + if (_disableOutgoingAudioProcessing) { + audioOptions.echo_cancellation = false; + audioOptions.noise_suppression = false; + audioOptions.auto_gain_control = false; + audioOptions.highpass_filter = false; + audioOptions.typing_detection = false; + audioOptions.experimental_agc = false; + audioOptions.experimental_ns = false; + audioOptions.residual_echo_detector = false; + } else { + audioOptions.echo_cancellation = true; + audioOptions.noise_suppression = true; + } + + std::vector streamIds; + streamIds.push_back("1"); + + _outgoingAudioChannel = _channelManager->CreateVoiceChannel(call, cricket::MediaConfig(), rtpTransport, threads->getMediaThread(), "audio0", false, NativeNetworkingImpl::getDefaulCryptoOptions(), uniqueRandomIdGenerator, audioOptions); + + std::vector codecs; + for (const auto &codec : mediaContent.codecs) { + if (codec.name == "opus") { + auto mutableCodec = codec; + + const uint8_t opusMinBitrateKbps = 16; + const uint8_t opusMaxBitrateKbps = 32; + const uint8_t opusStartBitrateKbps = 32; + const uint8_t opusPTimeMs = 60; + + mutableCodec.SetParam(cricket::kCodecParamMinBitrate, opusMinBitrateKbps); + mutableCodec.SetParam(cricket::kCodecParamStartBitrate, opusStartBitrateKbps); + mutableCodec.SetParam(cricket::kCodecParamMaxBitrate, opusMaxBitrateKbps); + mutableCodec.SetParam(cricket::kCodecParamUseInbandFec, 1); + mutableCodec.SetParam(cricket::kCodecParamPTime, opusPTimeMs); + + codecs.push_back(std::move(mutableCodec)); + } + } + + auto outgoingAudioDescription = std::make_unique(); + for (const auto &rtpExtension : mediaContent.rtpExtensions) { + outgoingAudioDescription->AddRtpHeaderExtension(webrtc::RtpExtension(rtpExtension.uri, rtpExtension.id)); + } + outgoingAudioDescription->set_rtcp_mux(true); + outgoingAudioDescription->set_rtcp_reduced_size(true); + outgoingAudioDescription->set_direction(webrtc::RtpTransceiverDirection::kSendOnly); + outgoingAudioDescription->set_codecs(codecs); + outgoingAudioDescription->set_bandwidth(-1); + outgoingAudioDescription->AddStream(cricket::StreamParams::CreateLegacy(_ssrc)); + + auto incomingAudioDescription = std::make_unique(); + for (const auto &rtpExtension : mediaContent.rtpExtensions) { + incomingAudioDescription->AddRtpHeaderExtension(webrtc::RtpExtension(rtpExtension.uri, rtpExtension.id)); + } + incomingAudioDescription->set_rtcp_mux(true); + incomingAudioDescription->set_rtcp_reduced_size(true); + incomingAudioDescription->set_direction(webrtc::RtpTransceiverDirection::kRecvOnly); + incomingAudioDescription->set_codecs(codecs); + incomingAudioDescription->set_bandwidth(-1); + + _threads->getWorkerThread()->Invoke(RTC_FROM_HERE, [&]() { + _outgoingAudioChannel->SetPayloadTypeDemuxingEnabled(false); + _outgoingAudioChannel->SetLocalContent(outgoingAudioDescription.get(), webrtc::SdpType::kOffer, nullptr); + _outgoingAudioChannel->SetRemoteContent(incomingAudioDescription.get(), webrtc::SdpType::kAnswer, nullptr); + }); + + //_outgoingAudioChannel->SignalSentPacket().connect(this, &OutgoingAudioChannel::OnSentPacket_w); + //_outgoingAudioChannel->UpdateRtpTransport(nullptr); + + setIsMuted(false); + } + + ~OutgoingAudioChannel() { + //_outgoingAudioChannel->SignalSentPacket().disconnect(this); + _outgoingAudioChannel->Enable(false); + _channelManager->DestroyVoiceChannel(_outgoingAudioChannel); + _outgoingAudioChannel = nullptr; + } + + void setIsMuted(bool isMuted) { + if (_isMuted != isMuted) { + _isMuted = isMuted; + + _outgoingAudioChannel->Enable(!_isMuted); + _threads->getWorkerThread()->Invoke(RTC_FROM_HERE, [&]() { + _outgoingAudioChannel->media_channel()->SetAudioSend(_ssrc, !_isMuted, nullptr, _audioSource); + }); + } + } + +private: + void OnSentPacket_w(const rtc::SentPacket& sent_packet) { + _call->OnSentPacket(sent_packet); + } + +private: + std::shared_ptr _threads; + uint32_t _ssrc = 0; + webrtc::Call *_call = nullptr; + cricket::ChannelManager *_channelManager = nullptr; + webrtc::LocalAudioSinkAdapter *_audioSource = nullptr; + cricket::VoiceChannel *_outgoingAudioChannel = nullptr; + + bool _isMuted = true; +}; + +class IncomingV2AudioChannel : public sigslot::has_slots<> { +public: + IncomingV2AudioChannel( + cricket::ChannelManager *channelManager, + webrtc::Call *call, + webrtc::RtpTransport *rtpTransport, + rtc::UniqueRandomIdGenerator *randomIdGenerator, + NegotiatedMediaContent const &mediaContent, + std::shared_ptr threads) : + _ssrc(mediaContent.ssrc), + _channelManager(channelManager), + _call(call) { + _creationTimestamp = rtc::TimeMillis(); + + cricket::AudioOptions audioOptions; + audioOptions.audio_jitter_buffer_fast_accelerate = true; + audioOptions.audio_jitter_buffer_min_delay_ms = 50; + + std::string streamId = std::string("stream1"); + + _audioChannel = _channelManager->CreateVoiceChannel(call, cricket::MediaConfig(), rtpTransport, threads->getMediaThread(), "0", false, NativeNetworkingImpl::getDefaulCryptoOptions(), randomIdGenerator, audioOptions); + + auto audioCodecs = mediaContent.codecs; + + auto outgoingAudioDescription = std::make_unique(); + for (const auto &rtpExtension : mediaContent.rtpExtensions) { + outgoingAudioDescription->AddRtpHeaderExtension(webrtc::RtpExtension(rtpExtension.uri, rtpExtension.id)); + } + outgoingAudioDescription->set_rtcp_mux(true); + outgoingAudioDescription->set_rtcp_reduced_size(true); + outgoingAudioDescription->set_direction(webrtc::RtpTransceiverDirection::kRecvOnly); + outgoingAudioDescription->set_codecs(audioCodecs); + outgoingAudioDescription->set_bandwidth(-1); + + auto incomingAudioDescription = std::make_unique(); + for (const auto &rtpExtension : mediaContent.rtpExtensions) { + incomingAudioDescription->AddRtpHeaderExtension(webrtc::RtpExtension(rtpExtension.uri, rtpExtension.id)); + } + incomingAudioDescription->set_rtcp_mux(true); + incomingAudioDescription->set_rtcp_reduced_size(true); + incomingAudioDescription->set_direction(webrtc::RtpTransceiverDirection::kSendOnly); + incomingAudioDescription->set_codecs(audioCodecs); + incomingAudioDescription->set_bandwidth(-1); + cricket::StreamParams streamParams = cricket::StreamParams::CreateLegacy(mediaContent.ssrc); + streamParams.set_stream_ids({ streamId }); + incomingAudioDescription->AddStream(streamParams); + + threads->getWorkerThread()->Invoke(RTC_FROM_HERE, [&]() { + _audioChannel->SetPayloadTypeDemuxingEnabled(false); + _audioChannel->SetLocalContent(outgoingAudioDescription.get(), webrtc::SdpType::kOffer, nullptr); + _audioChannel->SetRemoteContent(incomingAudioDescription.get(), webrtc::SdpType::kAnswer, nullptr); + }); + + outgoingAudioDescription.reset(); + incomingAudioDescription.reset(); + + //std::unique_ptr audioLevelSink(new AudioSinkImpl(onAudioLevelUpdated, _ssrc, std::move(onAudioFrame))); + //_audioChannel->media_channel()->SetRawAudioSink(ssrc.networkSsrc, std::move(audioLevelSink)); + + _audioChannel->Enable(true); + } + + ~IncomingV2AudioChannel() { + _audioChannel->Enable(false); + _channelManager->DestroyVoiceChannel(_audioChannel); + _audioChannel = nullptr; + } + + void setVolume(double value) { + _audioChannel->media_channel()->SetOutputVolume(_ssrc, value); + } + + void updateActivity() { + _activityTimestamp = rtc::TimeMillis(); + } + + int64_t getActivity() { + return _activityTimestamp; + } + +private: + void OnSentPacket_w(const rtc::SentPacket& sent_packet) { + _call->OnSentPacket(sent_packet); + } + +private: + uint32_t _ssrc = 0; + // Memory is managed by _channelManager + cricket::VoiceChannel *_audioChannel = nullptr; + // Memory is managed externally + cricket::ChannelManager *_channelManager = nullptr; + webrtc::Call *_call = nullptr; + int64_t _creationTimestamp = 0; + int64_t _activityTimestamp = 0; +}; + +class OutgoingVideoChannel : public sigslot::has_slots<>, public std::enable_shared_from_this { +public: + static absl::optional createOutgoingContentDescription(std::vector const &availableVideoFormats, bool isScreencast) { + signaling_4_0_0::MediaContent mediaContent; + + auto generator = std::mt19937(std::random_device()()); + auto distribution = std::uniform_int_distribution(); + do { + mediaContent.ssrc = distribution(generator) & 0x7fffffffU; + } while (!mediaContent.ssrc); + + mediaContent.rtpExtensions.emplace_back(webrtc::RtpExtension::kAbsSendTimeUri, 2); + mediaContent.rtpExtensions.emplace_back(webrtc::RtpExtension::kTransportSequenceNumberUri, 3); + mediaContent.rtpExtensions.emplace_back(webrtc::RtpExtension::kVideoRotationUri, 13); + + signaling_4_0_0::SsrcGroup fidGroup; + fidGroup.semantics = "FID"; + fidGroup.ssrcs.push_back(mediaContent.ssrc); + fidGroup.ssrcs.push_back(mediaContent.ssrc + 1); + mediaContent.ssrcGroups.push_back(std::move(fidGroup)); + + auto unsortedVideoFormats = generateAvailableVideoFormats(availableVideoFormats); + + std::vector formatPreferences; + if (isScreencast) { + formatPreferences.push_back(cricket::kVp8CodecName); + } else { +#ifndef WEBRTC_DISABLE_H265 + formatPreferences.push_back(cricket::kH265CodecName); +#endif + formatPreferences.push_back(cricket::kH264CodecName); + } + + std::vector videoFormats; + for (const auto &name : formatPreferences) { + for (size_t i = 0; i < unsortedVideoFormats.size(); i++) { + if (absl::EqualsIgnoreCase(name, unsortedVideoFormats[i].videoCodec.name)) { + videoFormats.push_back(unsortedVideoFormats[i]); + unsortedVideoFormats.erase(unsortedVideoFormats.begin() + i); + break; + } + } + } + for (const auto &format : unsortedVideoFormats) { + videoFormats.push_back(format); + } + + for (const auto &format : videoFormats) { + signaling_4_0_0::PayloadType videoPayload; + videoPayload.id = format.videoCodec.id; + videoPayload.name = format.videoCodec.name; + videoPayload.clockrate = format.videoCodec.clockrate; + videoPayload.channels = 0; + + std::vector videoFeedbackTypes; + + signaling_4_0_0::FeedbackType fbGoogRemb; + fbGoogRemb.type = "goog-remb"; + videoFeedbackTypes.push_back(fbGoogRemb); + + signaling_4_0_0::FeedbackType fbTransportCc; + fbTransportCc.type = "transport-cc"; + videoFeedbackTypes.push_back(fbTransportCc); + + signaling_4_0_0::FeedbackType fbCcmFir; + fbCcmFir.type = "ccm"; + fbCcmFir.subtype = "fir"; + videoFeedbackTypes.push_back(fbCcmFir); + + signaling_4_0_0::FeedbackType fbNack; + fbNack.type = "nack"; + videoFeedbackTypes.push_back(fbNack); + + signaling_4_0_0::FeedbackType fbNackPli; + fbNackPli.type = "nack"; + fbNackPli.subtype = "pli"; + videoFeedbackTypes.push_back(fbNackPli); + + videoPayload.feedbackTypes = videoFeedbackTypes; + videoPayload.parameters = {}; + + mediaContent.payloadTypes.push_back(std::move(videoPayload)); + + if (format.rtxCodec) { + signaling_4_0_0::PayloadType rtxPayload; + rtxPayload.id = format.rtxCodec->id; + rtxPayload.name = format.rtxCodec->name; + rtxPayload.clockrate = format.rtxCodec->clockrate; + rtxPayload.parameters.push_back(std::make_pair("apt", intToString(videoPayload.id))); + mediaContent.payloadTypes.push_back(std::move(rtxPayload)); + } + } + + return mediaContent; + } + +public: + OutgoingVideoChannel( + std::shared_ptr threads, + cricket::ChannelManager *channelManager, + webrtc::Call *call, + webrtc::RtpTransport *rtpTransport, + rtc::UniqueRandomIdGenerator *randomIdGenerator, + webrtc::VideoBitrateAllocatorFactory *videoBitrateAllocatorFactory, + std::function rotationUpdated, + NegotiatedMediaContent const &mediaContent, + bool isScreencast + ) : + _threads(threads), + _mainSsrc(mediaContent.ssrc), + _call(call), + _channelManager(channelManager), + _rotationUpdated(rotationUpdated) { + cricket::VideoOptions videoOptions; + videoOptions.is_screencast = isScreencast; + _outgoingVideoChannel = _channelManager->CreateVideoChannel(call, cricket::MediaConfig(), rtpTransport, threads->getMediaThread(), "out" + intToString(mediaContent.ssrc), false, NativeNetworkingImpl::getDefaulCryptoOptions(), randomIdGenerator, videoOptions, videoBitrateAllocatorFactory); + + auto videoCodecs = mediaContent.codecs; + + auto outgoingVideoDescription = std::make_unique(); + for (const auto &rtpExtension : mediaContent.rtpExtensions) { + outgoingVideoDescription->AddRtpHeaderExtension(rtpExtension); + } + + outgoingVideoDescription->set_rtcp_mux(true); + outgoingVideoDescription->set_rtcp_reduced_size(true); + outgoingVideoDescription->set_direction(webrtc::RtpTransceiverDirection::kSendOnly); + outgoingVideoDescription->set_codecs(videoCodecs); + outgoingVideoDescription->set_bandwidth(-1); + + cricket::StreamParams videoSendStreamParams; + + for (const auto &ssrcGroup : mediaContent.ssrcGroups) { + for (auto ssrc : ssrcGroup.ssrcs) { + videoSendStreamParams.ssrcs.push_back(ssrc); + } + + cricket::SsrcGroup mappedGroup(ssrcGroup.semantics, ssrcGroup.ssrcs); + videoSendStreamParams.ssrc_groups.push_back(std::move(mappedGroup)); + } + + videoSendStreamParams.cname = "cname"; + + outgoingVideoDescription->AddStream(videoSendStreamParams); + + auto incomingVideoDescription = std::make_unique(); + for (const auto &rtpExtension : mediaContent.rtpExtensions) { + incomingVideoDescription->AddRtpHeaderExtension(webrtc::RtpExtension(rtpExtension.uri, rtpExtension.id)); + } + incomingVideoDescription->set_rtcp_mux(true); + incomingVideoDescription->set_rtcp_reduced_size(true); + incomingVideoDescription->set_direction(webrtc::RtpTransceiverDirection::kRecvOnly); + incomingVideoDescription->set_codecs(videoCodecs); + incomingVideoDescription->set_bandwidth(-1); + + threads->getWorkerThread()->Invoke(RTC_FROM_HERE, [&]() { + _outgoingVideoChannel->SetPayloadTypeDemuxingEnabled(false); + _outgoingVideoChannel->SetLocalContent(outgoingVideoDescription.get(), webrtc::SdpType::kOffer, nullptr); + _outgoingVideoChannel->SetRemoteContent(incomingVideoDescription.get(), webrtc::SdpType::kAnswer, nullptr); + + webrtc::RtpParameters rtpParameters = _outgoingVideoChannel->media_channel()->GetRtpSendParameters(mediaContent.ssrc); + + _outgoingVideoChannel->media_channel()->SetRtpSendParameters(mediaContent.ssrc, rtpParameters); + }); + + _outgoingVideoChannel->Enable(false); + + threads->getWorkerThread()->Invoke(RTC_FROM_HERE, [&]() { + _outgoingVideoChannel->media_channel()->SetVideoSend(mediaContent.ssrc, NULL, nullptr); + }); + } + + ~OutgoingVideoChannel() { + _outgoingVideoChannel->Enable(false); + _channelManager->DestroyVideoChannel(_outgoingVideoChannel); + _outgoingVideoChannel = nullptr; + } + + void setVideoCapture(std::shared_ptr videoCapture) { + _videoCapture = videoCapture; + + if (_videoCapture) { + _outgoingVideoChannel->Enable(true); + auto videoCaptureImpl = GetVideoCaptureAssumingSameThread(_videoCapture.get()); + + _threads->getWorkerThread()->Invoke(RTC_FROM_HERE, [&]() { + _outgoingVideoChannel->media_channel()->SetVideoSend(_mainSsrc, NULL, videoCaptureImpl->source()); + }); + + const auto weak = std::weak_ptr(shared_from_this()); + videoCaptureImpl->setRotationUpdated([threads = _threads, weak](int angle) { + threads->getMediaThread()->PostTask(RTC_FROM_HERE, [=] { + const auto strong = weak.lock(); + if (!strong) { + return; + } + signaling_4_0_0::MediaStateMessage::VideoRotation videoRotation = signaling_4_0_0::MediaStateMessage::VideoRotation::Rotation0; + switch (angle) { + case 0: { + videoRotation = signaling_4_0_0::MediaStateMessage::VideoRotation::Rotation0; + break; + } + case 90: { + videoRotation = signaling_4_0_0::MediaStateMessage::VideoRotation::Rotation90; + break; + } + case 180: { + videoRotation = signaling_4_0_0::MediaStateMessage::VideoRotation::Rotation180; + break; + } + case 270: { + videoRotation = signaling_4_0_0::MediaStateMessage::VideoRotation::Rotation270; + break; + } + default: { + videoRotation = signaling_4_0_0::MediaStateMessage::VideoRotation::Rotation0; + break; + } + } + if (strong->_videoRotation != videoRotation) { + strong->_videoRotation = videoRotation; + strong->_rotationUpdated(); + } + }); + }); + + switch (videoCaptureImpl->getRotation()) { + case 0: { + _videoRotation = signaling_4_0_0::MediaStateMessage::VideoRotation::Rotation0; + break; + } + case 90: { + _videoRotation = signaling_4_0_0::MediaStateMessage::VideoRotation::Rotation90; + break; + } + case 180: { + _videoRotation = signaling_4_0_0::MediaStateMessage::VideoRotation::Rotation180; + break; + } + case 270: { + _videoRotation = signaling_4_0_0::MediaStateMessage::VideoRotation::Rotation270; + break; + } + default: { + _videoRotation = signaling_4_0_0::MediaStateMessage::VideoRotation::Rotation0; + break; + } + } + } else { + _videoRotation = signaling_4_0_0::MediaStateMessage::VideoRotation::Rotation0; + _outgoingVideoChannel->Enable(false); + + _threads->getWorkerThread()->Invoke(RTC_FROM_HERE, [&]() { + _outgoingVideoChannel->media_channel()->SetVideoSend(_mainSsrc, NULL, nullptr); + }); + } + } + +public: + std::shared_ptr videoCapture() { + return _videoCapture; + } + + signaling_4_0_0::MediaStateMessage::VideoRotation getRotation() { + return _videoRotation; + } + +private: + void OnSentPacket_w(const rtc::SentPacket& sent_packet) { + _call->OnSentPacket(sent_packet); + } + +private: + std::shared_ptr _threads; + + uint32_t _mainSsrc = 0; + webrtc::Call *_call = nullptr; + cricket::ChannelManager *_channelManager = nullptr; + cricket::VideoChannel *_outgoingVideoChannel = nullptr; + + std::function _rotationUpdated; + + std::shared_ptr _videoCapture; + signaling_4_0_0::MediaStateMessage::VideoRotation _videoRotation = signaling_4_0_0::MediaStateMessage::VideoRotation::Rotation0; +}; + +class VideoSinkImpl : public rtc::VideoSinkInterface { +public: + VideoSinkImpl() { + } + + virtual ~VideoSinkImpl() { + } + + virtual void OnFrame(const webrtc::VideoFrame& frame) override { + //_lastFrame = frame; + for (int i = (int)(_sinks.size()) - 1; i >= 0; i--) { + auto strong = _sinks[i].lock(); + if (!strong) { + _sinks.erase(_sinks.begin() + i); + } else { + strong->OnFrame(frame); + } + } + } + + virtual void OnDiscardedFrame() override { + for (int i = (int)(_sinks.size()) - 1; i >= 0; i--) { + auto strong = _sinks[i].lock(); + if (!strong) { + _sinks.erase(_sinks.begin() + i); + } else { + strong->OnDiscardedFrame(); + } + } + } + + void addSink(std::weak_ptr> impl) { + _sinks.push_back(impl); + if (_lastFrame) { + auto strong = impl.lock(); + if (strong) { + strong->OnFrame(_lastFrame.value()); + } + } + } + +private: + std::vector>> _sinks; + absl::optional _lastFrame; +}; + +class IncomingV2VideoChannel : public sigslot::has_slots<> { +public: + IncomingV2VideoChannel( + cricket::ChannelManager *channelManager, + webrtc::Call *call, + webrtc::RtpTransport *rtpTransport, + rtc::UniqueRandomIdGenerator *randomIdGenerator, + NegotiatedMediaContent const &mediaContent, + std::string const &streamId, + std::shared_ptr threads) : + _channelManager(channelManager), + _call(call) { + _videoSink.reset(new VideoSinkImpl()); + + _videoBitrateAllocatorFactory = webrtc::CreateBuiltinVideoBitrateAllocatorFactory(); + + _videoChannel = _channelManager->CreateVideoChannel(call, cricket::MediaConfig(), rtpTransport, threads->getMediaThread(), streamId, false, NativeNetworkingImpl::getDefaulCryptoOptions(), randomIdGenerator, cricket::VideoOptions(), _videoBitrateAllocatorFactory.get()); + + std::vector videoCodecs = mediaContent.codecs; + + auto outgoingVideoDescription = std::make_unique(); + for (const auto &rtpExtension : mediaContent.rtpExtensions) { + outgoingVideoDescription->AddRtpHeaderExtension(webrtc::RtpExtension(rtpExtension.uri, rtpExtension.id)); + } + outgoingVideoDescription->set_rtcp_mux(true); + outgoingVideoDescription->set_rtcp_reduced_size(true); + outgoingVideoDescription->set_direction(webrtc::RtpTransceiverDirection::kRecvOnly); + outgoingVideoDescription->set_codecs(videoCodecs); + outgoingVideoDescription->set_bandwidth(-1); + + cricket::StreamParams videoRecvStreamParams; + + _mainVideoSsrc = mediaContent.ssrc; + + std::vector allSsrcs; + for (const auto &group : mediaContent.ssrcGroups) { + for (auto ssrc : group.ssrcs) { + if (std::find(allSsrcs.begin(), allSsrcs.end(), ssrc) == allSsrcs.end()) { + allSsrcs.push_back(ssrc); + } + } + + cricket::SsrcGroup parsedGroup(group.semantics, group.ssrcs); + videoRecvStreamParams.ssrc_groups.push_back(parsedGroup); + } + videoRecvStreamParams.ssrcs = allSsrcs; + + videoRecvStreamParams.cname = "cname"; + videoRecvStreamParams.set_stream_ids({ streamId }); + + auto incomingVideoDescription = std::make_unique(); + for (const auto &rtpExtension : mediaContent.rtpExtensions) { + incomingVideoDescription->AddRtpHeaderExtension(webrtc::RtpExtension(rtpExtension.uri, rtpExtension.id)); + } + incomingVideoDescription->set_rtcp_mux(true); + incomingVideoDescription->set_rtcp_reduced_size(true); + incomingVideoDescription->set_direction(webrtc::RtpTransceiverDirection::kSendOnly); + incomingVideoDescription->set_codecs(videoCodecs); + incomingVideoDescription->set_bandwidth(-1); + + incomingVideoDescription->AddStream(videoRecvStreamParams); + + threads->getWorkerThread()->Invoke(RTC_FROM_HERE, [&]() { + _videoChannel->SetPayloadTypeDemuxingEnabled(false); + _videoChannel->SetLocalContent(outgoingVideoDescription.get(), webrtc::SdpType::kOffer, nullptr); + _videoChannel->SetRemoteContent(incomingVideoDescription.get(), webrtc::SdpType::kAnswer, nullptr); + + _videoChannel->media_channel()->SetSink(_mainVideoSsrc, _videoSink.get()); + }); + + _videoChannel->Enable(true); + } + + ~IncomingV2VideoChannel() { + _videoChannel->Enable(false); + _channelManager->DestroyVideoChannel(_videoChannel); + _videoChannel = nullptr; + } + + void addSink(std::weak_ptr> impl) { + _videoSink->addSink(impl); + } + +private: + void OnSentPacket_w(const rtc::SentPacket& sent_packet) { + _call->OnSentPacket(sent_packet); + } + +private: + uint32_t _mainVideoSsrc = 0; + std::unique_ptr _videoSink; + std::unique_ptr _videoBitrateAllocatorFactory; + // Memory is managed by _channelManager + cricket::VideoChannel *_videoChannel; + // Memory is managed externally + cricket::ChannelManager *_channelManager = nullptr; + webrtc::Call *_call = nullptr; +}; + +} // namespace + +class InstanceV2_4_0_0ImplInternal : public std::enable_shared_from_this { +public: + InstanceV2_4_0_0ImplInternal(Descriptor &&descriptor, std::shared_ptr threads) : + _threads(threads), + _rtcServers(descriptor.rtcServers), + _encryptionKey(std::move(descriptor.encryptionKey)), + _stateUpdated(descriptor.stateUpdated), + _signalBarsUpdated(descriptor.signalBarsUpdated), + _audioLevelUpdated(descriptor.audioLevelUpdated), + _remoteBatteryLevelIsLowUpdated(descriptor.remoteBatteryLevelIsLowUpdated), + _remoteMediaStateUpdated(descriptor.remoteMediaStateUpdated), + _remotePrefferedAspectRatioUpdated(descriptor.remotePrefferedAspectRatioUpdated), + _signalingDataEmitted(descriptor.signalingDataEmitted), + _createAudioDeviceModule(descriptor.createAudioDeviceModule), + _eventLog(std::make_unique()), + _taskQueueFactory(webrtc::CreateDefaultTaskQueueFactory()), + _videoCapture(descriptor.videoCapture), + _platformContext(descriptor.platformContext) { + } + + ~InstanceV2_4_0_0ImplInternal() { + _networking->perform(RTC_FROM_HERE, [](NativeNetworkingImpl *networking) { + networking->stop(); + }); + + _incomingAudioChannel.reset(); + _incomingVideoChannel.reset(); + _incomingScreencastChannel.reset(); + _outgoingAudioChannel.reset(); + _outgoingVideoChannel.reset(); + _outgoingScreencastChannel.reset(); + _currentSink.reset(); + + _threads->getWorkerThread()->Invoke(RTC_FROM_HERE, [&]() { + _channelManager.reset(); + _call.reset(); + _audioDeviceModule = nullptr; + }); + _threads->getNetworkThread()->Invoke(RTC_FROM_HERE, []() { + }); + } + + void start() { + const auto weak = std::weak_ptr(shared_from_this()); + + _networking.reset(new ThreadLocalObject(_threads->getNetworkThread(), [weak, threads = _threads, isOutgoing = _encryptionKey.isOutgoing, rtcServers = _rtcServers]() { + return new NativeNetworkingImpl(NativeNetworkingImpl::Configuration{ + .isOutgoing = isOutgoing, + .enableStunMarking = false, + .enableTCP = false, + .enableP2P = true, + .rtcServers = rtcServers, + .stateUpdated = [threads, weak](const NativeNetworkingImpl::State &state) { + threads->getMediaThread()->PostTask(RTC_FROM_HERE, [=] { + const auto strong = weak.lock(); + if (!strong) { + return; + } + strong->onNetworkStateUpdated(state); + }); + }, + .candidateGathered = [threads, weak](const cricket::Candidate &candidate) { + threads->getMediaThread()->PostTask(RTC_FROM_HERE, [=] { + const auto strong = weak.lock(); + if (!strong) { + return; + } + + strong->sendCandidate(candidate); + }); + }, + .transportMessageReceived = [threads, weak](rtc::CopyOnWriteBuffer const &packet, bool isMissing) { + threads->getMediaThread()->PostTask(RTC_FROM_HERE, [=] { + const auto strong = weak.lock(); + if (!strong) { + return; + } + }); + }, + .rtcpPacketReceived = [threads, weak](rtc::CopyOnWriteBuffer const &packet, int64_t timestamp) { + const auto strong = weak.lock(); + if (!strong) { + return; + } + strong->_call->Receiver()->DeliverPacket(webrtc::MediaType::ANY, packet, timestamp); + }, + .dataChannelStateUpdated = [threads, weak](bool isDataChannelOpen) { + threads->getMediaThread()->PostTask(RTC_FROM_HERE, [=] { + const auto strong = weak.lock(); + if (!strong) { + return; + } + strong->onDataChannelStateUpdated(isDataChannelOpen); + }); + }, + .dataChannelMessageReceived = [threads, weak](std::string const &message) { + threads->getMediaThread()->PostTask(RTC_FROM_HERE, [=] { + const auto strong = weak.lock(); + if (!strong) { + return; + } + strong->onDataChannelMessage(message); + }); + }, + .threads = threads + }); + })); + + PlatformInterface::SharedInstance()->configurePlatformAudio(); + + //setAudioInputDevice(_initialInputDeviceId); + //setAudioOutputDevice(_initialOutputDeviceId); + + _threads->getWorkerThread()->Invoke(RTC_FROM_HERE, [&]() { + cricket::MediaEngineDependencies mediaDeps; + mediaDeps.task_queue_factory = _taskQueueFactory.get(); + mediaDeps.audio_encoder_factory = webrtc::CreateAudioEncoderFactory(); + mediaDeps.audio_decoder_factory = webrtc::CreateAudioDecoderFactory(); + + mediaDeps.video_encoder_factory = PlatformInterface::SharedInstance()->makeVideoEncoderFactory(_platformContext, true); + mediaDeps.video_decoder_factory = PlatformInterface::SharedInstance()->makeVideoDecoderFactory(_platformContext); + + _audioDeviceModule = createAudioDeviceModule(); + /*if (!_audioDeviceModule) { + return; + }*/ + mediaDeps.adm = _audioDeviceModule; + + _availableVideoFormats = mediaDeps.video_encoder_factory->GetSupportedFormats(); + + std::unique_ptr mediaEngine = cricket::CreateMediaEngine(std::move(mediaDeps)); + + _channelManager = cricket::ChannelManager::Create( + std::move(mediaEngine), + true, + _threads->getWorkerThread(), + _threads->getNetworkThread() + ); + + webrtc::Call::Config callConfig(_eventLog.get()); + callConfig.task_queue_factory = _taskQueueFactory.get(); + callConfig.trials = &_fieldTrials; + callConfig.audio_state = _channelManager->media_engine()->voice().GetAudioState(); + + _call.reset(webrtc::Call::Create(callConfig, webrtc::Clock::GetRealTimeClock(), _threads->getSharedModuleThread(), webrtc::ProcessThread::Create("PacerThread"))); + }); + + _uniqueRandomIdGenerator.reset(new rtc::UniqueRandomIdGenerator()); + + _threads->getNetworkThread()->Invoke(RTC_FROM_HERE, [this]() { + _rtpTransport = _networking->getSyncAssumingSameThread()->getRtpTransport(); + }); + + _videoBitrateAllocatorFactory = webrtc::CreateBuiltinVideoBitrateAllocatorFactory(); + + _networking->perform(RTC_FROM_HERE, [](NativeNetworkingImpl *networking) { + networking->start(); + }); + + if (_videoCapture) { + setVideoCapture(_videoCapture); + } + + beginSignaling(); + + adjustBitratePreferences(true); + } + + void sendSignalingMessage(signaling_4_0_0::Message const &message) { + auto data = message.serialize(); + + RTC_LOG(LS_INFO) << "sendSignalingMessage: " << std::string(data.begin(), data.end()); + + if (_signalingEncryption) { + if (const auto encryptedData = _signalingEncryption->encryptOutgoing(data)) { + _signalingDataEmitted(std::vector(encryptedData->data(), encryptedData->data() + encryptedData->size())); + } else { + RTC_LOG(LS_ERROR) << "sendSignalingMessage: failed to encrypt payload"; + } + } else { + _signalingDataEmitted(data); + } + } + + void beginSignaling() { + _signalingEncryption.reset(new SignalingEncryption(_encryptionKey)); + + if (_encryptionKey.isOutgoing) { + _outgoingAudioContent = OutgoingAudioChannel::createOutgoingContentDescription(); + _outgoingVideoContent = OutgoingVideoChannel::createOutgoingContentDescription(_availableVideoFormats, false); + _outgoingScreencastContent = OutgoingVideoChannel::createOutgoingContentDescription(_availableVideoFormats, true); + + sendInitialSetup(); + } + } + + void createNegotiatedChannels() { + if (_negotiatedOutgoingVideoContent) { + const auto weak = std::weak_ptr(shared_from_this()); + + _outgoingVideoChannel.reset(new OutgoingVideoChannel( + _threads, + _channelManager.get(), + _call.get(), + _rtpTransport, + _uniqueRandomIdGenerator.get(), + _videoBitrateAllocatorFactory.get(), + [threads = _threads, weak]() { + threads->getMediaThread()->PostTask(RTC_FROM_HERE, [=] { + const auto strong = weak.lock(); + if (!strong) { + return; + } + strong->sendMediaState(); + }); + }, + _negotiatedOutgoingVideoContent.value(), + false + )); + + if (_videoCapture) { + _outgoingVideoChannel->setVideoCapture(_videoCapture); + } + } + + if (_negotiatedOutgoingScreencastContent) { + const auto weak = std::weak_ptr(shared_from_this()); + + _outgoingScreencastChannel.reset(new OutgoingVideoChannel( + _threads, + _channelManager.get(), + _call.get(), + _rtpTransport, + _uniqueRandomIdGenerator.get(), + _videoBitrateAllocatorFactory.get(), + [threads = _threads, weak]() { + threads->getMediaThread()->PostTask(RTC_FROM_HERE, [=] { + const auto strong = weak.lock(); + if (!strong) { + return; + } + strong->sendMediaState(); + }); + }, + _negotiatedOutgoingScreencastContent.value(), + true + )); + + if (_screencastCapture) { + _outgoingScreencastChannel->setVideoCapture(_screencastCapture); + } + } + + if (_negotiatedOutgoingAudioContent) { + _outgoingAudioChannel.reset(new OutgoingAudioChannel( + _call.get(), + _channelManager.get(), + _uniqueRandomIdGenerator.get(), + &_audioSource, + _rtpTransport, + _negotiatedOutgoingAudioContent.value(), + _threads + )); + } + + adjustBitratePreferences(true); + } + + void sendInitialSetup() { + const auto weak = std::weak_ptr(shared_from_this()); + + _networking->perform(RTC_FROM_HERE, [weak, threads = _threads, isOutgoing = _encryptionKey.isOutgoing](NativeNetworkingImpl *networking) { + auto localFingerprint = networking->getLocalFingerprint(); + std::string hash = localFingerprint->algorithm; + std::string fingerprint = localFingerprint->GetRfc4572Fingerprint(); + std::string setup; + if (isOutgoing) { + setup = "actpass"; + } else { + setup = "passive"; + } + + auto localIceParams = networking->getLocalIceParameters(); + std::string ufrag = localIceParams.ufrag; + std::string pwd = localIceParams.pwd; + + threads->getMediaThread()->PostTask(RTC_FROM_HERE, [weak, ufrag, pwd, hash, fingerprint, setup, localIceParams]() { + const auto strong = weak.lock(); + if (!strong) { + return; + } + + signaling_4_0_0::InitialSetupMessage data; + + if (strong->_outgoingAudioContent) { + data.audio = strong->_outgoingAudioContent.value(); + } + if (strong->_outgoingVideoContent) { + data.video = strong->_outgoingVideoContent.value(); + } + if (strong->_outgoingScreencastContent) { + data.screencast = strong->_outgoingScreencastContent.value(); + } + + data.ufrag = ufrag; + data.pwd = pwd; + + signaling_4_0_0::DtlsFingerprint dtlsFingerprint; + dtlsFingerprint.hash = hash; + dtlsFingerprint.fingerprint = fingerprint; + dtlsFingerprint.setup = setup; + data.fingerprints.push_back(std::move(dtlsFingerprint)); + + signaling_4_0_0::Message message; + message.data = std::move(data); + strong->sendSignalingMessage(message); + }); + }); + } + + void receiveSignalingData(const std::vector &data) { + std::vector decryptedData; + + if (_signalingEncryption) { + const auto rawDecryptedData = _signalingEncryption->decryptIncoming(data); + if (!rawDecryptedData) { + RTC_LOG(LS_ERROR) << "receiveSignalingData: could not decrypt payload"; + + return; + } + + decryptedData = std::vector(rawDecryptedData->data(), rawDecryptedData->data() + rawDecryptedData->size()); + } else { + decryptedData = data; + } + + processSignalingData(decryptedData); + } + + void processSignalingData(const std::vector &data) { + RTC_LOG(LS_INFO) << "processSignalingData: " << std::string(data.begin(), data.end()); + + const auto message = signaling_4_0_0::Message::parse(data); + if (!message) { + return; + } + const auto messageData = &message->data; + if (const auto initialSetup = absl::get_if(messageData)) { + PeerIceParameters remoteIceParameters; + remoteIceParameters.ufrag = initialSetup->ufrag; + remoteIceParameters.pwd = initialSetup->pwd; + + std::unique_ptr fingerprint; + std::string sslSetup; + if (initialSetup->fingerprints.size() != 0) { + fingerprint = rtc::SSLFingerprint::CreateUniqueFromRfc4572(initialSetup->fingerprints[0].hash, initialSetup->fingerprints[0].fingerprint); + sslSetup = initialSetup->fingerprints[0].setup; + } + + _networking->perform(RTC_FROM_HERE, [threads = _threads, remoteIceParameters = std::move(remoteIceParameters), fingerprint = std::move(fingerprint), sslSetup = std::move(sslSetup)](NativeNetworkingImpl *networking) { + networking->setRemoteParams(remoteIceParameters, fingerprint.get(), sslSetup); + }); + + if (const auto audio = initialSetup->audio) { + if (_encryptionKey.isOutgoing) { + if (_outgoingAudioContent) { + _negotiatedOutgoingAudioContent = negotiateMediaContent(_outgoingAudioContent.value(), _outgoingAudioContent.value(), audio.value(), false); + const auto incomingAudioContent = negotiateMediaContent(audio.value(), _outgoingAudioContent.value(), audio.value(), false); + + signaling_4_0_0::MediaContent outgoingAudioContent; + + outgoingAudioContent.ssrc = _outgoingAudioContent->ssrc; + outgoingAudioContent.ssrcGroups = _outgoingAudioContent->ssrcGroups; + outgoingAudioContent.rtpExtensions = _negotiatedOutgoingAudioContent->rtpExtensions; + outgoingAudioContent.payloadTypes = getPayloadTypesFromAudioCodecs(_negotiatedOutgoingAudioContent->codecs); + + _outgoingAudioContent = std::move(outgoingAudioContent); + + _incomingAudioChannel.reset(new IncomingV2AudioChannel( + _channelManager.get(), + _call.get(), + _rtpTransport, + _uniqueRandomIdGenerator.get(), + incomingAudioContent, + _threads + )); + } + } else { + const auto generatedOutgoingContent = OutgoingAudioChannel::createOutgoingContentDescription(); + + if (generatedOutgoingContent) { + _negotiatedOutgoingAudioContent = negotiateMediaContent(generatedOutgoingContent.value(), generatedOutgoingContent.value(), audio.value(), true); + const auto incomingAudioContent = negotiateMediaContent(audio.value(), generatedOutgoingContent.value(), audio.value(), true); + + if (_negotiatedOutgoingAudioContent) { + signaling_4_0_0::MediaContent outgoingAudioContent; + + outgoingAudioContent.ssrc = generatedOutgoingContent->ssrc; + outgoingAudioContent.ssrcGroups = generatedOutgoingContent->ssrcGroups; + outgoingAudioContent.rtpExtensions = _negotiatedOutgoingAudioContent->rtpExtensions; + outgoingAudioContent.payloadTypes = getPayloadTypesFromAudioCodecs(_negotiatedOutgoingAudioContent->codecs); + + _outgoingAudioContent = std::move(outgoingAudioContent); + + _incomingAudioChannel.reset(new IncomingV2AudioChannel( + _channelManager.get(), + _call.get(), + _rtpTransport, + _uniqueRandomIdGenerator.get(), + incomingAudioContent, + _threads + )); + } + } + } + } + + if (const auto video = initialSetup->video) { + if (_encryptionKey.isOutgoing) { + if (_outgoingVideoContent) { + _negotiatedOutgoingVideoContent = negotiateMediaContent(_outgoingVideoContent.value(), _outgoingVideoContent.value(), video.value(), false); + const auto incomingVideoContent = negotiateMediaContent(video.value(), _outgoingVideoContent.value(), video.value(), false); + + signaling_4_0_0::MediaContent outgoingVideoContent; + + outgoingVideoContent.ssrc = _outgoingVideoContent->ssrc; + outgoingVideoContent.ssrcGroups = _outgoingVideoContent->ssrcGroups; + outgoingVideoContent.rtpExtensions = _negotiatedOutgoingVideoContent->rtpExtensions; + outgoingVideoContent.payloadTypes = getPayloadTypesFromVideoCodecs(_negotiatedOutgoingVideoContent->codecs); + + _outgoingVideoContent = std::move(outgoingVideoContent); + + _incomingVideoChannel.reset(new IncomingV2VideoChannel( + _channelManager.get(), + _call.get(), + _rtpTransport, + _uniqueRandomIdGenerator.get(), + incomingVideoContent, + "1", + _threads + )); + _incomingVideoChannel->addSink(_currentSink); + } + } else { + const auto generatedOutgoingContent = OutgoingVideoChannel::createOutgoingContentDescription(_availableVideoFormats, false); + + if (generatedOutgoingContent) { + _negotiatedOutgoingVideoContent = negotiateMediaContent(generatedOutgoingContent.value(), generatedOutgoingContent.value(), video.value(), true); + const auto incomingVideoContent = negotiateMediaContent(video.value(), generatedOutgoingContent.value(), video.value(), true); + + if (_negotiatedOutgoingVideoContent) { + signaling_4_0_0::MediaContent outgoingVideoContent; + + outgoingVideoContent.ssrc = generatedOutgoingContent->ssrc; + outgoingVideoContent.ssrcGroups = generatedOutgoingContent->ssrcGroups; + outgoingVideoContent.rtpExtensions = _negotiatedOutgoingVideoContent->rtpExtensions; + outgoingVideoContent.payloadTypes = getPayloadTypesFromVideoCodecs(_negotiatedOutgoingVideoContent->codecs); + + _outgoingVideoContent = std::move(outgoingVideoContent); + + _incomingVideoChannel.reset(new IncomingV2VideoChannel( + _channelManager.get(), + _call.get(), + _rtpTransport, + _uniqueRandomIdGenerator.get(), + incomingVideoContent, + "1", + _threads + )); + _incomingVideoChannel->addSink(_currentSink); + } + } + } + } + + if (const auto screencast = initialSetup->screencast) { + if (_encryptionKey.isOutgoing) { + if (_outgoingScreencastContent) { + _negotiatedOutgoingScreencastContent = negotiateMediaContent(_outgoingScreencastContent.value(), _outgoingScreencastContent.value(), screencast.value(), false); + const auto incomingScreencastContent = negotiateMediaContent(screencast.value(), _outgoingScreencastContent.value(), screencast.value(), false); + + signaling_4_0_0::MediaContent outgoingScreencastContent; + + outgoingScreencastContent.ssrc = _outgoingScreencastContent->ssrc; + outgoingScreencastContent.ssrcGroups = _outgoingScreencastContent->ssrcGroups; + outgoingScreencastContent.rtpExtensions = _negotiatedOutgoingScreencastContent->rtpExtensions; + outgoingScreencastContent.payloadTypes = getPayloadTypesFromVideoCodecs(_negotiatedOutgoingScreencastContent->codecs); + + _outgoingScreencastContent = std::move(outgoingScreencastContent); + + _incomingScreencastChannel.reset(new IncomingV2VideoChannel( + _channelManager.get(), + _call.get(), + _rtpTransport, + _uniqueRandomIdGenerator.get(), + incomingScreencastContent, + "2", + _threads + )); + _incomingScreencastChannel->addSink(_currentSink); + } + } else { + const auto generatedOutgoingContent = OutgoingVideoChannel::createOutgoingContentDescription(_availableVideoFormats, true); + + if (generatedOutgoingContent) { + _negotiatedOutgoingScreencastContent = negotiateMediaContent(generatedOutgoingContent.value(), generatedOutgoingContent.value(), screencast.value(), true); + const auto incomingScreencastContent = negotiateMediaContent(screencast.value(), generatedOutgoingContent.value(), screencast.value(), true); + + if (_negotiatedOutgoingScreencastContent) { + signaling_4_0_0::MediaContent outgoingScreencastContent; + + outgoingScreencastContent.ssrc = generatedOutgoingContent->ssrc; + outgoingScreencastContent.ssrcGroups = generatedOutgoingContent->ssrcGroups; + outgoingScreencastContent.rtpExtensions = _negotiatedOutgoingScreencastContent->rtpExtensions; + outgoingScreencastContent.payloadTypes = getPayloadTypesFromVideoCodecs(_negotiatedOutgoingScreencastContent->codecs); + + _outgoingScreencastContent = std::move(outgoingScreencastContent); + + _incomingScreencastChannel.reset(new IncomingV2VideoChannel( + _channelManager.get(), + _call.get(), + _rtpTransport, + _uniqueRandomIdGenerator.get(), + incomingScreencastContent, + "2", + _threads + )); + _incomingScreencastChannel->addSink(_currentSink); + } + } + } + } + + createNegotiatedChannels(); + + if (!_encryptionKey.isOutgoing) { + sendInitialSetup(); + } + + _handshakeCompleted = true; + commitPendingIceCandidates(); + } else if (const auto candidatesList = absl::get_if(messageData)) { + for (const auto &candidate : candidatesList->iceCandidates) { + webrtc::JsepIceCandidate parseCandidate{ std::string(), 0 }; + if (!parseCandidate.Initialize(candidate.sdpString, nullptr)) { + RTC_LOG(LS_ERROR) << "Could not parse candidate: " << candidate.sdpString; + continue; + } + _pendingIceCandidates.push_back(parseCandidate.candidate()); + } + + if (_handshakeCompleted) { + commitPendingIceCandidates(); + } + } else if (const auto mediaState = absl::get_if(messageData)) { + AudioState mappedAudioState; + if (mediaState->isMuted) { + mappedAudioState = AudioState::Muted; + } else { + mappedAudioState = AudioState::Active; + } + + VideoState mappedVideoState; + switch (mediaState->videoState) { + case signaling_4_0_0::MediaStateMessage::VideoState::Inactive: { + mappedVideoState = VideoState::Inactive; + break; + } + case signaling_4_0_0::MediaStateMessage::VideoState::Suspended: { + mappedVideoState = VideoState::Paused; + break; + } + case signaling_4_0_0::MediaStateMessage::VideoState::Active: { + mappedVideoState = VideoState::Active; + break; + } + default: { + RTC_FATAL() << "Unknown videoState"; + break; + } + } + + VideoState mappedScreencastState; + switch (mediaState->screencastState) { + case signaling_4_0_0::MediaStateMessage::VideoState::Inactive: { + mappedScreencastState = VideoState::Inactive; + break; + } + case signaling_4_0_0::MediaStateMessage::VideoState::Suspended: { + mappedScreencastState = VideoState::Paused; + break; + } + case signaling_4_0_0::MediaStateMessage::VideoState::Active: { + mappedScreencastState = VideoState::Active; + break; + } + default: { + RTC_FATAL() << "Unknown videoState"; + break; + } + } + + VideoState effectiveVideoState = mappedVideoState; + if (mappedScreencastState == VideoState::Active || mappedScreencastState == VideoState::Paused) { + effectiveVideoState = mappedScreencastState; + } + + if (_remoteMediaStateUpdated) { + _remoteMediaStateUpdated(mappedAudioState, effectiveVideoState); + } + + if (_remoteBatteryLevelIsLowUpdated) { + _remoteBatteryLevelIsLowUpdated(mediaState->isBatteryLow); + } + } + } + + void commitPendingIceCandidates() { + if (_pendingIceCandidates.size() == 0) { + return; + } + _networking->perform(RTC_FROM_HERE, [threads = _threads, parsedCandidates = _pendingIceCandidates](NativeNetworkingImpl *networking) { + networking->addCandidates(parsedCandidates); + }); + _pendingIceCandidates.clear(); + } + + void onNetworkStateUpdated(NativeNetworkingImpl::State const &state) { + State mappedState; + if (state.isReadyToSendData) { + mappedState = State::Established; + } else { + mappedState = State::Reconnecting; + } + _stateUpdated(mappedState); + } + + void onDataChannelStateUpdated(bool isDataChannelOpen) { + if (_isDataChannelOpen != isDataChannelOpen) { + _isDataChannelOpen = isDataChannelOpen; + + if (_isDataChannelOpen) { + sendMediaState(); + } + } + } + + void sendDataChannelMessage(signaling_4_0_0::Message const &message) { + if (!_isDataChannelOpen) { + RTC_LOG(LS_ERROR) << "sendDataChannelMessage called, but data channel is not open"; + return; + } + auto data = message.serialize(); + std::string stringData(data.begin(), data.end()); + RTC_LOG(LS_INFO) << "sendDataChannelMessage: " << stringData; + _networking->perform(RTC_FROM_HERE, [stringData = std::move(stringData)](NativeNetworkingImpl *networking) { + networking->sendDataChannelMessage(stringData); + }); + } + + void onDataChannelMessage(std::string const &message) { + RTC_LOG(LS_INFO) << "dataChannelMessage received: " << message; + std::vector data(message.begin(), message.end()); + processSignalingData(data); + } + + void sendMediaState() { + if (!_isDataChannelOpen) { + return; + } + signaling_4_0_0::Message message; + signaling_4_0_0::MediaStateMessage data; + data.isMuted = _isMicrophoneMuted; + data.isBatteryLow = _isBatteryLow; + if (_outgoingVideoChannel) { + if (_outgoingVideoChannel->videoCapture()) { + data.videoState = signaling_4_0_0::MediaStateMessage::VideoState::Active; + } else{ + data.videoState = signaling_4_0_0::MediaStateMessage::VideoState::Inactive; + } + data.videoRotation = _outgoingVideoChannel->getRotation(); + } else { + data.videoState = signaling_4_0_0::MediaStateMessage::VideoState::Inactive; + data.videoRotation = signaling_4_0_0::MediaStateMessage::VideoRotation::Rotation0; + } + if (_outgoingScreencastChannel) { + if (_outgoingScreencastChannel->videoCapture()) { + data.screencastState = signaling_4_0_0::MediaStateMessage::VideoState::Active; + } else{ + data.screencastState = signaling_4_0_0::MediaStateMessage::VideoState::Inactive; + } + } else { + data.screencastState = signaling_4_0_0::MediaStateMessage::VideoState::Inactive; + } + message.data = std::move(data); + sendDataChannelMessage(message); + } + + void sendCandidate(const cricket::Candidate &candidate) { + cricket::Candidate patchedCandidate = candidate; + patchedCandidate.set_component(1); + + signaling_4_0_0::CandidatesMessage data; + + signaling_4_0_0::IceCandidate serializedCandidate; + + webrtc::JsepIceCandidate iceCandidate{ std::string(), 0 }; + iceCandidate.SetCandidate(patchedCandidate); + std::string serialized; + const auto success = iceCandidate.ToString(&serialized); + assert(success); + (void)success; + + serializedCandidate.sdpString = serialized; + + data.iceCandidates.push_back(std::move(serializedCandidate)); + + signaling_4_0_0::Message message; + message.data = std::move(data); + sendSignalingMessage(message); + } + + void setVideoCapture(std::shared_ptr videoCapture) { + auto videoCaptureImpl = GetVideoCaptureAssumingSameThread(videoCapture.get()); + if (videoCaptureImpl) { + if (videoCaptureImpl->isScreenCapture()) { + _videoCapture = nullptr; + _screencastCapture = videoCapture; + + if (_outgoingVideoChannel) { + _outgoingVideoChannel->setVideoCapture(nullptr); + } + + if (_outgoingScreencastChannel) { + _outgoingScreencastChannel->setVideoCapture(videoCapture); + } + + sendMediaState(); + adjustBitratePreferences(true); + } else { + _videoCapture = videoCapture; + _screencastCapture = nullptr; + + if (_outgoingVideoChannel) { + _outgoingVideoChannel->setVideoCapture(videoCapture); + } + + if (_outgoingScreencastChannel) { + _outgoingScreencastChannel->setVideoCapture(nullptr); + } + + sendMediaState(); + adjustBitratePreferences(true); + } + } else { + _videoCapture = nullptr; + _screencastCapture = nullptr; + + if (_outgoingVideoChannel) { + _outgoingVideoChannel->setVideoCapture(nullptr); + } + + if (_outgoingScreencastChannel) { + _outgoingScreencastChannel->setVideoCapture(nullptr); + } + + sendMediaState(); + adjustBitratePreferences(true); + } + } + + void setRequestedVideoAspect(float aspect) { + } + + void setNetworkType(NetworkType networkType) { + + } + + void setMuteMicrophone(bool muteMicrophone) { + if (_isMicrophoneMuted != muteMicrophone) { + _isMicrophoneMuted = muteMicrophone; + + if (_outgoingAudioChannel) { + _outgoingAudioChannel->setIsMuted(muteMicrophone); + } + + sendMediaState(); + } + } + + void setIncomingVideoOutput(std::weak_ptr> sink) { + _currentSink = sink; + if (_incomingVideoChannel) { + _incomingVideoChannel->addSink(sink); + } + if (_incomingScreencastChannel) { + _incomingScreencastChannel->addSink(sink); + } + } + + void setAudioInputDevice(std::string id) { + + } + + void setAudioOutputDevice(std::string id) { + + } + + void setIsLowBatteryLevel(bool isLowBatteryLevel) { + if (_isBatteryLow != isLowBatteryLevel) { + _isBatteryLow = isLowBatteryLevel; + sendMediaState(); + } + } + + void stop(std::function completion) { + completion({}); + } + + void adjustBitratePreferences(bool resetStartBitrate) { + webrtc::BitrateConstraints preferences; + if (_videoCapture || _screencastCapture) { + preferences.min_bitrate_bps = 64000; + if (resetStartBitrate) { + preferences.start_bitrate_bps = (100 + 800 + 32 + 100) * 1000; + } + preferences.max_bitrate_bps = (100 + 200 + 800 + 32 + 100) * 1000; + } else { + preferences.min_bitrate_bps = 32000; + if (resetStartBitrate) { + preferences.start_bitrate_bps = 32000; + } + preferences.max_bitrate_bps = 32000; + } + + _call->GetTransportControllerSend()->SetSdpBitrateParameters(preferences); + } + +private: + rtc::scoped_refptr createAudioDeviceModule() { + const auto create = [&](webrtc::AudioDeviceModule::AudioLayer layer) { +#ifdef WEBRTC_IOS + return rtc::make_ref_counted(false, false, 1); +#else + return webrtc::AudioDeviceModule::Create( + layer, + _taskQueueFactory.get()); +#endif + }; + const auto check = [&](const rtc::scoped_refptr &result) { + return (result && result->Init() == 0) ? result : nullptr; + }; + if (_createAudioDeviceModule) { + if (const auto result = check(_createAudioDeviceModule(_taskQueueFactory.get()))) { + return result; + } + } + return check(create(webrtc::AudioDeviceModule::kPlatformDefaultAudio)); + } + +private: + std::shared_ptr _threads; + std::vector _rtcServers; + EncryptionKey _encryptionKey; + std::function _stateUpdated; + std::function _signalBarsUpdated; + std::function _audioLevelUpdated; + std::function _remoteBatteryLevelIsLowUpdated; + std::function _remoteMediaStateUpdated; + std::function _remotePrefferedAspectRatioUpdated; + std::function &)> _signalingDataEmitted; + std::function(webrtc::TaskQueueFactory*)> _createAudioDeviceModule; + + std::unique_ptr _signalingEncryption; + + bool _handshakeCompleted = false; + std::vector _pendingIceCandidates; + bool _isDataChannelOpen = false; + + std::unique_ptr _eventLog; + std::unique_ptr _taskQueueFactory; + std::unique_ptr _mediaEngine; + std::unique_ptr _call; + webrtc::FieldTrialBasedConfig _fieldTrials; + webrtc::LocalAudioSinkAdapter _audioSource; + rtc::scoped_refptr _audioDeviceModule; + + std::unique_ptr _uniqueRandomIdGenerator; + webrtc::RtpTransport *_rtpTransport = nullptr; + std::unique_ptr _channelManager; + std::unique_ptr _videoBitrateAllocatorFactory; + + std::shared_ptr> _networking; + + absl::optional _outgoingAudioContent; + absl::optional> _negotiatedOutgoingAudioContent; + + std::unique_ptr _outgoingAudioChannel; + bool _isMicrophoneMuted = false; + + std::vector _availableVideoFormats; + + absl::optional _outgoingVideoContent; + absl::optional> _negotiatedOutgoingVideoContent; + + absl::optional _outgoingScreencastContent; + absl::optional> _negotiatedOutgoingScreencastContent; + + std::shared_ptr _outgoingVideoChannel; + std::shared_ptr _outgoingScreencastChannel; + + bool _isBatteryLow = false; + + std::unique_ptr _incomingAudioChannel; + std::unique_ptr _incomingVideoChannel; + std::unique_ptr _incomingScreencastChannel; + + std::weak_ptr> _currentSink; + + std::shared_ptr _videoCapture; + std::shared_ptr _screencastCapture; + std::shared_ptr _platformContext; +}; + +InstanceV2_4_0_0Impl::InstanceV2_4_0_0Impl(Descriptor &&descriptor) { + if (descriptor.config.logPath.data.size() != 0) { + _logSink = std::make_unique(descriptor.config.logPath); + } + rtc::LogMessage::LogToDebug(rtc::LS_INFO); + rtc::LogMessage::SetLogToStderr(false); + if (_logSink) { + rtc::LogMessage::AddLogToStream(_logSink.get(), rtc::LS_INFO); + } + + _threads = StaticThreads::getThreads(); + _internal.reset(new ThreadLocalObject(_threads->getMediaThread(), [descriptor = std::move(descriptor), threads = _threads]() mutable { + return new InstanceV2_4_0_0ImplInternal(std::move(descriptor), threads); + })); + _internal->perform(RTC_FROM_HERE, [](InstanceV2_4_0_0ImplInternal *internal) { + internal->start(); + }); +} + +InstanceV2_4_0_0Impl::~InstanceV2_4_0_0Impl() { + rtc::LogMessage::RemoveLogToStream(_logSink.get()); +} + +void InstanceV2_4_0_0Impl::receiveSignalingData(const std::vector &data) { + _internal->perform(RTC_FROM_HERE, [data](InstanceV2_4_0_0ImplInternal *internal) { + internal->receiveSignalingData(data); + }); +} + +void InstanceV2_4_0_0Impl::setVideoCapture(std::shared_ptr videoCapture) { + _internal->perform(RTC_FROM_HERE, [videoCapture](InstanceV2_4_0_0ImplInternal *internal) { + internal->setVideoCapture(videoCapture); + }); +} + +void InstanceV2_4_0_0Impl::setRequestedVideoAspect(float aspect) { + _internal->perform(RTC_FROM_HERE, [aspect](InstanceV2_4_0_0ImplInternal *internal) { + internal->setRequestedVideoAspect(aspect); + }); +} + +void InstanceV2_4_0_0Impl::setNetworkType(NetworkType networkType) { + _internal->perform(RTC_FROM_HERE, [networkType](InstanceV2_4_0_0ImplInternal *internal) { + internal->setNetworkType(networkType); + }); +} + +void InstanceV2_4_0_0Impl::setMuteMicrophone(bool muteMicrophone) { + _internal->perform(RTC_FROM_HERE, [muteMicrophone](InstanceV2_4_0_0ImplInternal *internal) { + internal->setMuteMicrophone(muteMicrophone); + }); +} + +void InstanceV2_4_0_0Impl::setIncomingVideoOutput(std::shared_ptr> sink) { + _internal->perform(RTC_FROM_HERE, [sink](InstanceV2_4_0_0ImplInternal *internal) { + internal->setIncomingVideoOutput(sink); + }); +} + +void InstanceV2_4_0_0Impl::setAudioInputDevice(std::string id) { + _internal->perform(RTC_FROM_HERE, [id](InstanceV2_4_0_0ImplInternal *internal) { + internal->setAudioInputDevice(id); + }); +} + +void InstanceV2_4_0_0Impl::setAudioOutputDevice(std::string id) { + _internal->perform(RTC_FROM_HERE, [id](InstanceV2_4_0_0ImplInternal *internal) { + internal->setAudioOutputDevice(id); + }); +} + +void InstanceV2_4_0_0Impl::setIsLowBatteryLevel(bool isLowBatteryLevel) { + _internal->perform(RTC_FROM_HERE, [isLowBatteryLevel](InstanceV2_4_0_0ImplInternal *internal) { + internal->setIsLowBatteryLevel(isLowBatteryLevel); + }); +} + +void InstanceV2_4_0_0Impl::setInputVolume(float level) { +} + +void InstanceV2_4_0_0Impl::setOutputVolume(float level) { +} + +void InstanceV2_4_0_0Impl::setAudioOutputDuckingEnabled(bool enabled) { +} + +void InstanceV2_4_0_0Impl::setAudioOutputGainControlEnabled(bool enabled) { +} + +void InstanceV2_4_0_0Impl::setEchoCancellationStrength(int strength) { +} + +std::vector InstanceV2_4_0_0Impl::GetVersions() { + std::vector result; + result.push_back("4.0.0"); + return result; +} + +int InstanceV2_4_0_0Impl::GetConnectionMaxLayer() { + return 92; +} + +std::string InstanceV2_4_0_0Impl::getLastError() { + return ""; +} + +std::string InstanceV2_4_0_0Impl::getDebugInfo() { + return ""; +} + +int64_t InstanceV2_4_0_0Impl::getPreferredRelayId() { + return 0; +} + +TrafficStats InstanceV2_4_0_0Impl::getTrafficStats() { + return {}; +} + +PersistentState InstanceV2_4_0_0Impl::getPersistentState() { + return {}; +} + +void InstanceV2_4_0_0Impl::stop(std::function completion) { + std::string debugLog; + if (_logSink) { + debugLog = _logSink->result(); + } + _internal->perform(RTC_FROM_HERE, [completion, debugLog = std::move(debugLog)](InstanceV2_4_0_0ImplInternal *internal) mutable { + internal->stop([completion, debugLog = std::move(debugLog)](FinalState finalState) mutable { + finalState.debugLog = debugLog; + completion(finalState); + }); + }); +} + +template <> +bool Register() { + return Meta::RegisterOne(); +} + +} // namespace tgcalls diff --git a/TMessagesProj/jni/voip/tgcalls/v2_4_0_0/InstanceV2_4_0_0Impl.h b/TMessagesProj/jni/voip/tgcalls/v2_4_0_0/InstanceV2_4_0_0Impl.h new file mode 100644 index 000000000..1a892de4b --- /dev/null +++ b/TMessagesProj/jni/voip/tgcalls/v2_4_0_0/InstanceV2_4_0_0Impl.h @@ -0,0 +1,59 @@ +#ifndef TGCALLS_INSTANCEV2_4_0_0_IMPL_H +#define TGCALLS_INSTANCEV2_4_0_0_IMPL_H + +#include "Instance.h" +#include "StaticThreads.h" + +namespace tgcalls { + +class LogSinkImpl; + +class Manager; +template +class ThreadLocalObject; + +class InstanceV2_4_0_0ImplInternal; + +class InstanceV2_4_0_0Impl final : public Instance { +public: + explicit InstanceV2_4_0_0Impl(Descriptor &&descriptor); + ~InstanceV2_4_0_0Impl() override; + + void receiveSignalingData(const std::vector &data) override; + void setVideoCapture(std::shared_ptr videoCapture) override; + void setRequestedVideoAspect(float aspect) override; + void setNetworkType(NetworkType networkType) override; + void setMuteMicrophone(bool muteMicrophone) override; + bool supportsVideo() override { + return true; + } + void setIncomingVideoOutput(std::shared_ptr> sink) override; + void setAudioOutputGainControlEnabled(bool enabled) override; + void setEchoCancellationStrength(int strength) override; + void setAudioInputDevice(std::string id) override; + void setAudioOutputDevice(std::string id) override; + void setInputVolume(float level) override; + void setOutputVolume(float level) override; + void setAudioOutputDuckingEnabled(bool enabled) override; + void setIsLowBatteryLevel(bool isLowBatteryLevel) override; + static std::vector GetVersions(); + static int GetConnectionMaxLayer(); + std::string getLastError() override; + std::string getDebugInfo() override; + int64_t getPreferredRelayId() override; + TrafficStats getTrafficStats() override; + PersistentState getPersistentState() override; + void stop(std::function completion) override; + void sendVideoDeviceUpdated() override { + } + +private: + std::shared_ptr _threads; + std::unique_ptr> _internal; + std::unique_ptr _logSink; + +}; + +} // namespace tgcalls + +#endif diff --git a/TMessagesProj/jni/voip/tgcalls/v2_4_0_0/Signaling_4_0_0.cpp b/TMessagesProj/jni/voip/tgcalls/v2_4_0_0/Signaling_4_0_0.cpp new file mode 100644 index 000000000..7d80f022c --- /dev/null +++ b/TMessagesProj/jni/voip/tgcalls/v2_4_0_0/Signaling_4_0_0.cpp @@ -0,0 +1,705 @@ +#include "v2_4_0_0/Signaling_4_0_0.h" + +#include "third-party/json11.hpp" + +#include "rtc_base/checks.h" + +#include + +namespace tgcalls { +namespace signaling_4_0_0 { + +static std::string uint32ToString(uint32_t value) { + std::ostringstream stringStream; + stringStream << value; + return stringStream.str(); +} + +static uint32_t stringToUInt32(std::string const &string) { + std::stringstream stringStream(string); + uint32_t value = 0; + stringStream >> value; + return value; +} + +json11::Json::object SsrcGroup_serialize(SsrcGroup const &ssrcGroup) { + json11::Json::object object; + + json11::Json::array ssrcs; + for (auto ssrc : ssrcGroup.ssrcs) { + ssrcs.push_back(json11::Json(uint32ToString(ssrc))); + } + object.insert(std::make_pair("semantics", json11::Json(ssrcGroup.semantics))); + object.insert(std::make_pair("ssrcs", json11::Json(std::move(ssrcs)))); + + return object; +} + +absl::optional SsrcGroup_parse(json11::Json::object const &object) { + SsrcGroup result; + + const auto semantics = object.find("semantics"); + if (semantics == object.end() || !semantics->second.is_string()) { + return absl::nullopt; + } + result.semantics = semantics->second.string_value(); + + const auto ssrcs = object.find("ssrcs"); + if (ssrcs == object.end() || !ssrcs->second.is_array()) { + return absl::nullopt; + } + for (const auto &ssrc : ssrcs->second.array_items()) { + if (ssrc.is_string()) { + uint32_t parsedSsrc = stringToUInt32(ssrc.string_value()); + if (parsedSsrc == 0) { + return absl::nullopt; + } + result.ssrcs.push_back(parsedSsrc); + } else if (ssrc.is_number()) { + uint32_t parsedSsrc = (uint32_t)ssrc.number_value(); + result.ssrcs.push_back(parsedSsrc); + } else { + return absl::nullopt; + } + } + + return result; +} + +json11::Json::object FeedbackType_serialize(FeedbackType const &feedbackType) { + json11::Json::object object; + + object.insert(std::make_pair("type", json11::Json(feedbackType.type))); + object.insert(std::make_pair("subtype", json11::Json(feedbackType.subtype))); + + return object; +} + +absl::optional FeedbackType_parse(json11::Json::object const &object) { + FeedbackType result; + + const auto type = object.find("type"); + if (type == object.end() || !type->second.is_string()) { + return absl::nullopt; + } + result.type = type->second.string_value(); + + const auto subtype = object.find("subtype"); + if (subtype == object.end() || !subtype->second.is_string()) { + return absl::nullopt; + } + result.subtype = subtype->second.string_value(); + + return result; +} + +json11::Json::object RtpExtension_serialize(webrtc::RtpExtension const &rtpExtension) { + json11::Json::object object; + + object.insert(std::make_pair("id", json11::Json(rtpExtension.id))); + object.insert(std::make_pair("uri", json11::Json(rtpExtension.uri))); + + return object; +} + +absl::optional RtpExtension_parse(json11::Json::object const &object) { + const auto id = object.find("id"); + if (id == object.end() || !id->second.is_number()) { + return absl::nullopt; + } + + const auto uri = object.find("uri"); + if (uri == object.end() || !uri->second.is_string()) { + return absl::nullopt; + } + + return webrtc::RtpExtension(uri->second.string_value(), id->second.int_value()); +} + +json11::Json::object PayloadType_serialize(PayloadType const &payloadType) { + json11::Json::object object; + + object.insert(std::make_pair("id", json11::Json((int)payloadType.id))); + object.insert(std::make_pair("name", json11::Json(payloadType.name))); + object.insert(std::make_pair("clockrate", json11::Json((int)payloadType.clockrate))); + object.insert(std::make_pair("channels", json11::Json((int)payloadType.channels))); + + json11::Json::array feedbackTypes; + for (const auto &feedbackType : payloadType.feedbackTypes) { + feedbackTypes.push_back(FeedbackType_serialize(feedbackType)); + } + object.insert(std::make_pair("feedbackTypes", json11::Json(std::move(feedbackTypes)))); + + json11::Json::object parameters; + for (auto it : payloadType.parameters) { + parameters.insert(std::make_pair(it.first, json11::Json(it.second))); + } + object.insert(std::make_pair("parameters", json11::Json(std::move(parameters)))); + + return object; +} + +absl::optional PayloadType_parse(json11::Json::object const &object) { + PayloadType result; + + const auto id = object.find("id"); + if (id == object.end() || !id->second.is_number()) { + return absl::nullopt; + } + result.id = id->second.int_value(); + + const auto name = object.find("name"); + if (name == object.end() || !name->second.is_string()) { + return absl::nullopt; + } + result.name = name->second.string_value(); + + const auto clockrate = object.find("clockrate"); + if (clockrate == object.end() || !clockrate->second.is_number()) { + return absl::nullopt; + } + result.clockrate = clockrate->second.int_value(); + + const auto channels = object.find("channels"); + if (channels != object.end()) { + if (!channels->second.is_number()) { + return absl::nullopt; + } + result.channels = channels->second.int_value(); + } + + const auto feedbackTypes = object.find("feedbackTypes"); + if (feedbackTypes != object.end()) { + if (!feedbackTypes->second.is_array()) { + return absl::nullopt; + } + for (const auto &feedbackType : feedbackTypes->second.array_items()) { + if (!feedbackType.is_object()) { + return absl::nullopt; + } + if (const auto parsedFeedbackType = FeedbackType_parse(feedbackType.object_items())) { + result.feedbackTypes.push_back(parsedFeedbackType.value()); + } else { + return absl::nullopt; + } + } + } + + const auto parameters = object.find("parameters"); + if (parameters != object.end()) { + if (!parameters->second.is_object()) { + return absl::nullopt; + } + for (const auto &item : parameters->second.object_items()) { + if (!item.second.is_string()) { + return absl::nullopt; + } + result.parameters.push_back(std::make_pair(item.first, item.second.string_value())); + } + } + + return result; +} + +json11::Json::object MediaContent_serialize(MediaContent const &mediaContent) { + json11::Json::object object; + + object.insert(std::make_pair("ssrc", json11::Json(uint32ToString(mediaContent.ssrc)))); + + if (mediaContent.ssrcGroups.size() != 0) { + json11::Json::array ssrcGroups; + for (const auto &group : mediaContent.ssrcGroups) { + ssrcGroups.push_back(SsrcGroup_serialize(group)); + } + object.insert(std::make_pair("ssrcGroups", json11::Json(std::move(ssrcGroups)))); + } + + if (mediaContent.payloadTypes.size() != 0) { + json11::Json::array payloadTypes; + for (const auto &payloadType : mediaContent.payloadTypes) { + payloadTypes.push_back(PayloadType_serialize(payloadType)); + } + object.insert(std::make_pair("payloadTypes", json11::Json(std::move(payloadTypes)))); + } + + json11::Json::array rtpExtensions; + for (const auto &rtpExtension : mediaContent.rtpExtensions) { + rtpExtensions.push_back(RtpExtension_serialize(rtpExtension)); + } + object.insert(std::make_pair("rtpExtensions", json11::Json(std::move(rtpExtensions)))); + + return object; +} + +absl::optional MediaContent_parse(json11::Json::object const &object) { + MediaContent result; + + const auto ssrc = object.find("ssrc"); + if (ssrc == object.end()) { + return absl::nullopt; + } + if (ssrc->second.is_string()) { + result.ssrc = stringToUInt32(ssrc->second.string_value()); + } else if (ssrc->second.is_number()) { + result.ssrc = (uint32_t)ssrc->second.number_value(); + } else { + return absl::nullopt; + } + + const auto ssrcGroups = object.find("ssrcGroups"); + if (ssrcGroups != object.end()) { + if (!ssrcGroups->second.is_array()) { + return absl::nullopt; + } + for (const auto &ssrcGroup : ssrcGroups->second.array_items()) { + if (!ssrcGroup.is_object()) { + return absl::nullopt; + } + if (const auto parsedSsrcGroup = SsrcGroup_parse(ssrcGroup.object_items())) { + result.ssrcGroups.push_back(parsedSsrcGroup.value()); + } else { + return absl::nullopt; + } + } + } + + const auto payloadTypes = object.find("payloadTypes"); + if (payloadTypes != object.end()) { + if (!payloadTypes->second.is_array()) { + return absl::nullopt; + } + for (const auto &payloadType : payloadTypes->second.array_items()) { + if (!payloadType.is_object()) { + return absl::nullopt; + } + if (const auto parsedPayloadType = PayloadType_parse(payloadType.object_items())) { + result.payloadTypes.push_back(parsedPayloadType.value()); + } else { + return absl::nullopt; + } + } + } + + const auto rtpExtensions = object.find("rtpExtensions"); + if (rtpExtensions != object.end()) { + if (!rtpExtensions->second.is_array()) { + return absl::nullopt; + } + for (const auto &rtpExtension : rtpExtensions->second.array_items()) { + if (!rtpExtension.is_object()) { + return absl::nullopt; + } + if (const auto parsedRtpExtension = RtpExtension_parse(rtpExtension.object_items())) { + result.rtpExtensions.push_back(parsedRtpExtension.value()); + } else { + return absl::nullopt; + } + } + } + + return result; +} + +std::vector InitialSetupMessage_serialize(const InitialSetupMessage * const message) { + json11::Json::object object; + + object.insert(std::make_pair("@type", json11::Json("InitialSetup"))); + object.insert(std::make_pair("ufrag", json11::Json(message->ufrag))); + object.insert(std::make_pair("pwd", json11::Json(message->pwd))); + + json11::Json::array jsonFingerprints; + for (const auto &fingerprint : message->fingerprints) { + json11::Json::object jsonFingerprint; + jsonFingerprint.insert(std::make_pair("hash", json11::Json(fingerprint.hash))); + jsonFingerprint.insert(std::make_pair("setup", json11::Json(fingerprint.setup))); + jsonFingerprint.insert(std::make_pair("fingerprint", json11::Json(fingerprint.fingerprint))); + jsonFingerprints.emplace_back(std::move(jsonFingerprint)); + } + object.insert(std::make_pair("fingerprints", json11::Json(std::move(jsonFingerprints)))); + + if (const auto audio = message->audio) { + object.insert(std::make_pair("audio", json11::Json(MediaContent_serialize(audio.value())))); + } + + if (const auto video = message->video) { + object.insert(std::make_pair("video", json11::Json(MediaContent_serialize(video.value())))); + } + + if (const auto screencast = message->screencast) { + object.insert(std::make_pair("screencast", json11::Json(MediaContent_serialize(screencast.value())))); + } + + auto json = json11::Json(std::move(object)); + std::string result = json.dump(); + return std::vector(result.begin(), result.end()); +} + +absl::optional InitialSetupMessage_parse(json11::Json::object const &object) { + const auto ufrag = object.find("ufrag"); + if (ufrag == object.end() || !ufrag->second.is_string()) { + return absl::nullopt; + } + const auto pwd = object.find("pwd"); + if (pwd == object.end() || !pwd->second.is_string()) { + return absl::nullopt; + } + const auto fingerprints = object.find("fingerprints"); + if (fingerprints == object.end() || !fingerprints->second.is_array()) { + return absl::nullopt; + } + std::vector parsedFingerprints; + for (const auto &fingerprintObject : fingerprints->second.array_items()) { + if (!fingerprintObject.is_object()) { + return absl::nullopt; + } + const auto hash = fingerprintObject.object_items().find("hash"); + if (hash == fingerprintObject.object_items().end() || !hash->second.is_string()) { + return absl::nullopt; + } + const auto setup = fingerprintObject.object_items().find("setup"); + if (setup == fingerprintObject.object_items().end() || !setup->second.is_string()) { + return absl::nullopt; + } + const auto fingerprint = fingerprintObject.object_items().find("fingerprint"); + if (fingerprint == fingerprintObject.object_items().end() || !fingerprint->second.is_string()) { + return absl::nullopt; + } + + DtlsFingerprint parsedFingerprint; + parsedFingerprint.hash = hash->second.string_value(); + parsedFingerprint.setup = setup->second.string_value(); + parsedFingerprint.fingerprint = fingerprint->second.string_value(); + + parsedFingerprints.push_back(std::move(parsedFingerprint)); + } + + InitialSetupMessage message; + message.ufrag = ufrag->second.string_value(); + message.pwd = pwd->second.string_value(); + message.fingerprints = std::move(parsedFingerprints); + + const auto audio = object.find("audio"); + if (audio != object.end()) { + if (!audio->second.is_object()) { + return absl::nullopt; + } + if (const auto parsedAudio = MediaContent_parse(audio->second.object_items())) { + message.audio = parsedAudio.value(); + } else { + return absl::nullopt; + } + } + + const auto video = object.find("video"); + if (video != object.end()) { + if (!video->second.is_object()) { + return absl::nullopt; + } + if (const auto parsedVideo = MediaContent_parse(video->second.object_items())) { + message.video = parsedVideo.value(); + } else { + return absl::nullopt; + } + } + + const auto screencast = object.find("screencast"); + if (screencast != object.end()) { + if (!screencast->second.is_object()) { + return absl::nullopt; + } + if (const auto parsedScreencast = MediaContent_parse(screencast->second.object_items())) { + message.screencast = parsedScreencast.value(); + } else { + return absl::nullopt; + } + } + + return message; +} + +json11::Json::object ConnectionAddress_serialize(ConnectionAddress const &connectionAddress) { + json11::Json::object object; + + object.insert(std::make_pair("ip", json11::Json(connectionAddress.ip))); + object.insert(std::make_pair("port", json11::Json(connectionAddress.port))); + + return object; +} + +absl::optional ConnectionAddress_parse(json11::Json::object const &object) { + const auto ip = object.find("ip"); + if (ip == object.end() || !ip->second.is_string()) { + return absl::nullopt; + } + + const auto port = object.find("port"); + if (port == object.end() || !port->second.is_number()) { + return absl::nullopt; + } + + ConnectionAddress address; + address.ip = ip->second.string_value(); + address.port = port->second.int_value(); + return address; +} + +std::vector CandidatesMessage_serialize(const CandidatesMessage * const message) { + json11::Json::array candidates; + for (const auto &candidate : message->iceCandidates) { + json11::Json::object candidateObject; + + candidateObject.insert(std::make_pair("sdpString", json11::Json(candidate.sdpString))); + + candidates.emplace_back(std::move(candidateObject)); + } + + json11::Json::object object; + + object.insert(std::make_pair("@type", json11::Json("Candidates"))); + object.insert(std::make_pair("candidates", json11::Json(std::move(candidates)))); + + auto json = json11::Json(std::move(object)); + std::string result = json.dump(); + return std::vector(result.begin(), result.end()); +} + +absl::optional CandidatesMessage_parse(json11::Json::object const &object) { + const auto candidates = object.find("candidates"); + if (candidates == object.end() || !candidates->second.is_array()) { + return absl::nullopt; + } + + std::vector parsedCandidates; + for (const auto &candidateObject : candidates->second.array_items()) { + if (!candidateObject.is_object()) { + return absl::nullopt; + } + + IceCandidate candidate; + + const auto sdpString = candidateObject.object_items().find("sdpString"); + if (sdpString == candidateObject.object_items().end() || !sdpString->second.is_string()) { + return absl::nullopt; + } + candidate.sdpString = sdpString->second.string_value(); + + parsedCandidates.push_back(std::move(candidate)); + } + + CandidatesMessage message; + message.iceCandidates = std::move(parsedCandidates); + + return message; +} + +std::vector MediaStateMessage_serialize(const MediaStateMessage * const message) { + json11::Json::object object; + + object.insert(std::make_pair("@type", json11::Json("MediaState"))); + object.insert(std::make_pair("muted", json11::Json(message->isMuted))); + object.insert(std::make_pair("lowBattery", json11::Json(message->isBatteryLow))); + + std::string videoStateValue; + switch (message->videoState) { + case MediaStateMessage::VideoState::Inactive: { + videoStateValue = "inactive"; + break; + } + case MediaStateMessage::VideoState::Suspended: { + videoStateValue = "suspended"; + break; + } + case MediaStateMessage::VideoState::Active: { + videoStateValue = "active"; + break; + } + default: { + RTC_FATAL() << "Unknown videoState"; + break; + } + } + object.insert(std::make_pair("videoState", json11::Json(videoStateValue))); + + int videoRotationValue = 0; + switch (message->videoRotation) { + case MediaStateMessage::VideoRotation::Rotation0: { + videoRotationValue = 0; + break; + } + case MediaStateMessage::VideoRotation::Rotation90: { + videoRotationValue = 90; + break; + } + case MediaStateMessage::VideoRotation::Rotation180: { + videoRotationValue = 180; + break; + } + case MediaStateMessage::VideoRotation::Rotation270: { + videoRotationValue = 270; + break; + } + default: { + RTC_FATAL() << "Unknown videoRotation"; + break; + } + } + object.insert(std::make_pair("videoRotation", json11::Json(videoRotationValue))); + + std::string screencastStateValue; + switch (message->screencastState) { + case MediaStateMessage::VideoState::Inactive: { + screencastStateValue = "inactive"; + break; + } + case MediaStateMessage::VideoState::Suspended: { + screencastStateValue = "suspended"; + break; + } + case MediaStateMessage::VideoState::Active: { + screencastStateValue = "active"; + break; + } + default: { + RTC_FATAL() << "Unknown videoState"; + break; + } + } + object.insert(std::make_pair("screencastState", json11::Json(screencastStateValue))); + + auto json = json11::Json(std::move(object)); + std::string result = json.dump(); + return std::vector(result.begin(), result.end()); +} + +absl::optional MediaStateMessage_parse(json11::Json::object const &object) { + MediaStateMessage message; + + const auto muted = object.find("muted"); + if (muted != object.end()) { + if (!muted->second.is_bool()) { + return absl::nullopt; + } + message.isMuted = muted->second.bool_value(); + } + + const auto lowBattery = object.find("lowBattery"); + if (lowBattery != object.end()) { + if (!lowBattery->second.is_bool()) { + return absl::nullopt; + } + message.isBatteryLow = lowBattery->second.bool_value(); + } + + const auto videoState = object.find("videoState"); + if (videoState != object.end()) { + if (!videoState->second.is_string()) { + return absl::nullopt; + } + if (videoState->second.string_value() == "inactive") { + message.videoState = MediaStateMessage::VideoState::Inactive; + } else if (videoState->second.string_value() == "suspended") { + message.videoState = MediaStateMessage::VideoState::Suspended; + } else if (videoState->second.string_value() == "active") { + message.videoState = MediaStateMessage::VideoState::Active; + } + } else { + message.videoState = MediaStateMessage::VideoState::Inactive; + } + + const auto screencastState = object.find("screencastState"); + if (screencastState != object.end()) { + if (!screencastState->second.is_string()) { + return absl::nullopt; + } + if (screencastState->second.string_value() == "inactive") { + message.screencastState = MediaStateMessage::VideoState::Inactive; + } else if (screencastState->second.string_value() == "suspended") { + message.screencastState = MediaStateMessage::VideoState::Suspended; + } else if (screencastState->second.string_value() == "active") { + message.screencastState = MediaStateMessage::VideoState::Active; + } + } else { + message.screencastState = MediaStateMessage::VideoState::Inactive; + } + + const auto videoRotation = object.find("videoRotation"); + if (videoRotation != object.end()) { + if (!videoRotation->second.is_number()) { + return absl::nullopt; + } + if (videoState->second.int_value() == 0) { + message.videoRotation = MediaStateMessage::VideoRotation::Rotation0; + } else if (videoState->second.int_value() == 90) { + message.videoRotation = MediaStateMessage::VideoRotation::Rotation90; + } else if (videoState->second.int_value() == 180) { + message.videoRotation = MediaStateMessage::VideoRotation::Rotation180; + } else if (videoState->second.int_value() == 270) { + message.videoRotation = MediaStateMessage::VideoRotation::Rotation270; + } else { + message.videoRotation = MediaStateMessage::VideoRotation::Rotation0; + } + } else { + message.videoRotation = MediaStateMessage::VideoRotation::Rotation0; + } + + return message; +} + +std::vector Message::serialize() const { + if (const auto initialSetup = absl::get_if(&data)) { + return InitialSetupMessage_serialize(initialSetup); + } else if (const auto candidates = absl::get_if(&data)) { + return CandidatesMessage_serialize(candidates); + } else if (const auto mediaState = absl::get_if(&data)) { + return MediaStateMessage_serialize(mediaState); + } else { + return {}; + } +} + +absl::optional Message::parse(const std::vector &data) { + std::string parsingError; + auto json = json11::Json::parse(std::string(data.begin(), data.end()), parsingError); + if (json.type() != json11::Json::OBJECT) { + return absl::nullopt; + } + + auto type = json.object_items().find("@type"); + if (type == json.object_items().end()) { + return absl::nullopt; + } + if (!type->second.is_string()) { + return absl::nullopt; + } + if (type->second.string_value() == "InitialSetup") { + auto parsed = InitialSetupMessage_parse(json.object_items()); + if (!parsed) { + return absl::nullopt; + } + Message message; + message.data = std::move(parsed.value()); + return message; + } else if (type->second.string_value() == "Candidates") { + auto parsed = CandidatesMessage_parse(json.object_items()); + if (!parsed) { + return absl::nullopt; + } + Message message; + message.data = std::move(parsed.value()); + return message; + } else if (type->second.string_value() == "MediaState") { + auto parsed = MediaStateMessage_parse(json.object_items()); + if (!parsed) { + return absl::nullopt; + } + Message message; + message.data = std::move(parsed.value()); + return message; + } else { + return absl::nullopt; + } +} + +} // namespace signaling + +} // namespace tgcalls diff --git a/TMessagesProj/jni/voip/tgcalls/v2_4_0_0/Signaling_4_0_0.h b/TMessagesProj/jni/voip/tgcalls/v2_4_0_0/Signaling_4_0_0.h new file mode 100644 index 000000000..75377a86e --- /dev/null +++ b/TMessagesProj/jni/voip/tgcalls/v2_4_0_0/Signaling_4_0_0.h @@ -0,0 +1,105 @@ +#ifndef TGCALLS_SIGNALING_4_0_0_H +#define TGCALLS_SIGNALING_4_0_0_H + +#include +#include + +#include "absl/types/variant.h" +#include "absl/types/optional.h" +#include "api/rtp_parameters.h" + +namespace tgcalls { + +namespace signaling_4_0_0 { + +struct DtlsFingerprint { + std::string hash; + std::string setup; + std::string fingerprint; +}; + +struct ConnectionAddress { + std::string ip; + int port = 0; +}; + +struct IceCandidate { + std::string sdpString; +}; + +struct SsrcGroup { + std::vector ssrcs; + std::string semantics; +}; + +struct FeedbackType { + std::string type; + std::string subtype; +}; + +struct PayloadType { + uint32_t id = 0; + std::string name; + uint32_t clockrate = 0; + uint32_t channels = 0; + std::vector feedbackTypes; + std::vector> parameters; +}; + +struct MediaContent { + uint32_t ssrc = 0; + std::vector ssrcGroups; + std::vector payloadTypes; + std::vector rtpExtensions; +}; + +struct InitialSetupMessage { + std::string ufrag; + std::string pwd; + std::vector fingerprints; + absl::optional audio; + absl::optional video; + absl::optional screencast; +}; + +struct CandidatesMessage { + std::vector iceCandidates; +}; + +struct MediaStateMessage { + enum class VideoState { + Inactive, + Suspended, + Active + }; + + enum class VideoRotation { + Rotation0, + Rotation90, + Rotation180, + Rotation270 + }; + + bool isMuted = false; + VideoState videoState = VideoState::Inactive; + VideoRotation videoRotation = VideoRotation::Rotation0; + VideoState screencastState = VideoState::Inactive; + bool isBatteryLow = false; + +}; + +struct Message { + absl::variant< + InitialSetupMessage, + CandidatesMessage, + MediaStateMessage> data; + + std::vector serialize() const; + static absl::optional parse(const std::vector &data); +}; + +}; + +} // namespace tgcalls + +#endif \ No newline at end of file diff --git a/TMessagesProj/jni/voip/webrtc/rtc_base/synchronization/mutex_pthread.h b/TMessagesProj/jni/voip/webrtc/rtc_base/synchronization/mutex_pthread.h index 7d8c17997..90c4a7ffe 100644 --- a/TMessagesProj/jni/voip/webrtc/rtc_base/synchronization/mutex_pthread.h +++ b/TMessagesProj/jni/voip/webrtc/rtc_base/synchronization/mutex_pthread.h @@ -61,6 +61,9 @@ class RTC_LOCKABLE MutexImpl final { owner_.SetOwner(); } ABSL_MUST_USE_RESULT bool TryLock() RTC_EXCLUSIVE_TRYLOCK_FUNCTION(true) { + if (!mutexEnabled()) { + return false; + } if (pthread_mutex_trylock(&mutex_) != 0) { return false; } diff --git a/TMessagesProj/src/main/AndroidManifest.xml b/TMessagesProj/src/main/AndroidManifest.xml index 8d2e38bc6..3d17fd82a 100644 --- a/TMessagesProj/src/main/AndroidManifest.xml +++ b/TMessagesProj/src/main/AndroidManifest.xml @@ -86,6 +86,7 @@ top) { animateTo = top - botCell.getTop(); diff --git a/TMessagesProj/src/main/java/com/google/android/exoplayer2/SimpleExoPlayer.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/SimpleExoPlayer.java index d7795d068..4fa7f58e2 100644 --- a/TMessagesProj/src/main/java/com/google/android/exoplayer2/SimpleExoPlayer.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/SimpleExoPlayer.java @@ -330,7 +330,6 @@ public class SimpleExoPlayer extends BasePlayer private final WakeLockManager wakeLockManager; private final WifiLockManager wifiLockManager; - private boolean needSetSurface = true; @Nullable private Format videoFormat; @Nullable private Format audioFormat; @@ -603,7 +602,6 @@ public class SimpleExoPlayer extends BasePlayer clearVideoDecoderOutputBufferRenderer(); } this.textureView = textureView; - needSetSurface = true; if (textureView == null) { setVideoSurfaceInternal(/* surface= */ null, /* ownsSurface= */ true); maybeNotifySurfaceSizeChanged(/* width= */ 0, /* height= */ 0); @@ -1795,10 +1793,6 @@ public class SimpleExoPlayer extends BasePlayer @Override public void onSurfaceTextureAvailable(SurfaceTexture surfaceTexture, int width, int height) { - if (needSetSurface) { - setVideoSurfaceInternal(new Surface(surfaceTexture), true); - needSetSurface = false; - } setVideoSurfaceInternal(new Surface(surfaceTexture), /* ownsSurface= */ true); maybeNotifySurfaceSizeChanged(width, height); } @@ -1817,7 +1811,6 @@ public class SimpleExoPlayer extends BasePlayer } setVideoSurfaceInternal(/* surface= */ null, /* ownsSurface= */ true); maybeNotifySurfaceSizeChanged(/* width= */ 0, /* height= */ 0); - needSetSurface = true; return true; } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/AndroidUtilities.java b/TMessagesProj/src/main/java/org/telegram/messenger/AndroidUtilities.java index e975c2dd8..05bd16af4 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/AndroidUtilities.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/AndroidUtilities.java @@ -64,6 +64,7 @@ import android.text.StaticLayout; import android.text.TextPaint; import android.text.TextUtils; import android.text.method.LinkMovementMethod; +import android.text.style.ClickableSpan; import android.text.style.URLSpan; import android.text.util.Linkify; import android.util.DisplayMetrics; @@ -94,6 +95,7 @@ import android.widget.ListView; import android.widget.ScrollView; import android.widget.TextView; +import androidx.annotation.NonNull; import androidx.core.content.FileProvider; import androidx.dynamicanimation.animation.DynamicAnimation; import androidx.dynamicanimation.animation.SpringAnimation; @@ -210,6 +212,7 @@ public class AndroidUtilities { public static Pattern BAD_CHARS_PATTERN = null; public static Pattern BAD_CHARS_MESSAGE_PATTERN = null; public static Pattern BAD_CHARS_MESSAGE_LONG_PATTERN = null; + private static Pattern singleTagPatter = null; static { try { @@ -403,6 +406,35 @@ public class AndroidUtilities { return null; } + public static CharSequence replaceSingleTag(String str, Runnable runnable) { + int startIndex = str.indexOf("**"); + int endIndex = str.indexOf("**", startIndex + 1); + str = str.replace("**", ""); + int index = -1; + int len = 0; + if (startIndex >= 0 && endIndex >= 0 && endIndex - startIndex > 2) { + len = endIndex - startIndex - 2; + index = startIndex; + } + SpannableStringBuilder spannableStringBuilder = new SpannableStringBuilder(str); + if (index >= 0) { + spannableStringBuilder.setSpan(new ClickableSpan() { + + @Override + public void updateDrawState(@NonNull TextPaint ds) { + super.updateDrawState(ds); + ds.setUnderlineText(false); + } + + @Override + public void onClick(@NonNull View view) { + runnable.run(); + } + }, index, index + len, 0); + } + return spannableStringBuilder; + } + private static class LinkSpec { String url; int start; @@ -2423,11 +2455,11 @@ public class AndroidUtilities { } public static void appCenterLog(Throwable e) { - + } public static boolean shouldShowClipboardToast() { - return Build.VERSION.SDK_INT < Build.VERSION_CODES.S || !OneUIUtilities.isOneUI(); + return Build.VERSION.SDK_INT < Build.VERSION_CODES.S || !OneUIUtilities.hasBuiltInClipboardToasts(); } public static void addToClipboard(CharSequence str) { @@ -3954,26 +3986,38 @@ public class AndroidUtilities { return false; } - public static void setLightNavigationBar(Window window, boolean enable) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - final View decorView = window.getDecorView(); - int flags = decorView.getSystemUiVisibility(); + public static void setLightNavigationBar(View view, boolean enable) { + if (view != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + int flags = view.getSystemUiVisibility(); if (enable) { flags |= View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR; } else { flags &= ~View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR; } - decorView.setSystemUiVisibility(flags); + view.setSystemUiVisibility(flags); + } + } + + public static void setLightNavigationBar(Window window, boolean enable) { + if (window != null) { + setLightNavigationBar(window.getDecorView(), enable); } } private static HashMap navigationBarColorAnimators; + public interface IntColorCallback { + public void run(int color); + } public static void setNavigationBarColor(Window window, int color) { setNavigationBarColor(window, color, true); } public static void setNavigationBarColor(Window window, int color, boolean animated) { + setNavigationBarColor(window, color, animated, null); + } + + public static void setNavigationBarColor(Window window, int color, boolean animated, IntColorCallback onUpdate) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { if (navigationBarColorAnimators != null) { ValueAnimator animator = navigationBarColorAnimators.get(window); @@ -3984,10 +4028,23 @@ public class AndroidUtilities { } if (!animated) { - window.setNavigationBarColor(color); + if (onUpdate != null) { + onUpdate.run(color); + } + try { + window.setNavigationBarColor(color); + } catch (Exception ignore) {} } else { ValueAnimator animator = ValueAnimator.ofArgb(window.getNavigationBarColor(), color); - animator.addUpdateListener(a -> window.setNavigationBarColor((int) a.getAnimatedValue())); + animator.addUpdateListener(a -> { + int tcolor = (int) a.getAnimatedValue(); + if (onUpdate != null) { + onUpdate.run(tcolor); + } + try { + window.setNavigationBarColor(tcolor); + } catch (Exception ignore) {} + }); animator.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { @@ -4207,7 +4264,7 @@ public class AndroidUtilities { bitmap.compress(format, 100, out); out.close(); return FileProvider.getUriForFile(ApplicationLoader.applicationContext, BuildConfig.APPLICATION_ID + ".provider", file); - } catch (IOException e) { + } catch (Exception e) { FileLog.e(e); } return null; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/ApplicationLoader.java b/TMessagesProj/src/main/java/org/telegram/messenger/ApplicationLoader.java index 78747ac02..f68809f98 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/ApplicationLoader.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/ApplicationLoader.java @@ -150,6 +150,7 @@ public class ApplicationLoader extends Application { } SharedConfig.loadConfig(); + SharedPrefsHelper.init(applicationContext); for (int a = 0; a < UserConfig.MAX_ACCOUNT_COUNT; a++) { //TODO improve account UserConfig.getInstance(a).loadConfig(); MessagesController.getInstance(a); diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/BuildVars.java b/TMessagesProj/src/main/java/org/telegram/messenger/BuildVars.java index 93ad7ea5d..f9854a56e 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/BuildVars.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/BuildVars.java @@ -20,8 +20,8 @@ public class BuildVars { public static boolean USE_CLOUD_STRINGS = true; public static boolean CHECK_UPDATES = true; public static boolean NO_SCOPED_STORAGE = Build.VERSION.SDK_INT <= 29; - public static int BUILD_VERSION = 2600; - public static String BUILD_VERSION_STRING = "8.6.2"; + public static int BUILD_VERSION = 2622; + public static String BUILD_VERSION_STRING = "8.7.0"; public static int APP_ID = 4; public static String APP_HASH = "014b35b6184100b085b0d0572f9b5103"; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/ChatThemeController.java b/TMessagesProj/src/main/java/org/telegram/messenger/ChatThemeController.java index 9a5d37123..9d8b8b2af 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/ChatThemeController.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/ChatThemeController.java @@ -127,6 +127,7 @@ public class ChatThemeController extends BaseController { private static SharedPreferences getSharedPreferences() { return ApplicationLoader.applicationContext.getSharedPreferences("chatthemeconfig", Context.MODE_PRIVATE); } + private static SharedPreferences getEmojiSharedPreferences() { return ApplicationLoader.applicationContext.getSharedPreferences("chatthemeconfig_emoji", Context.MODE_PRIVATE); } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/DownloadController.java b/TMessagesProj/src/main/java/org/telegram/messenger/DownloadController.java index 5689864dd..a88454f84 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/DownloadController.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/DownloadController.java @@ -1107,16 +1107,15 @@ public class DownloadController extends BaseController implements NotificationCe public void startDownloadFile(TLRPC.Document document, MessageObject parentObject) { + if (parentObject.getDocument() == null) { + return; + } AndroidUtilities.runOnUIThread(() -> { boolean contains = false; for (int i = 0; i < recentDownloadingFiles.size(); i++) { if (recentDownloadingFiles.get(i).getDocument().id == parentObject.getDocument().id) { - if (parentObject.mediaExists) { - contains = true; - } else { - recentDownloadingFiles.remove(i); - } + contains = true; break; } } @@ -1182,51 +1181,52 @@ public class DownloadController extends BaseController implements NotificationCe putToUnviewedDownloads(parentObject); } getNotificationCenter().postNotificationName(NotificationCenter.onDownloadingFilesChanged); + getMessagesStorage().getStorageQueue().postRunnable(() -> { + try { + String req = String.format(Locale.ENGLISH, "UPDATE downloading_documents SET state = 1, date = %d WHERE hash = %d AND id = %d", System.currentTimeMillis(), parentObject.getDocument().dc_id, parentObject.getDocument().id); + getMessagesStorage().getDatabase().executeFast(req).stepThis().dispose(); + SQLiteCursor cursor = getMessagesStorage().getDatabase().queryFinalized("SELECT COUNT(*) FROM downloading_documents WHERE state = 1"); + int count = 0; + if (cursor.next()) { + count = cursor.intValue(0); + } + cursor.dispose(); + + cursor = getMessagesStorage().getDatabase().queryFinalized("SELECT state FROM downloading_documents WHERE state = 1"); + if (cursor.next()) { + int state = cursor.intValue(0); + } + cursor.dispose(); + + int limitDownloadsDocuments = 100; + if (count > limitDownloadsDocuments) { + cursor = getMessagesStorage().getDatabase().queryFinalized("SELECT hash, id FROM downloading_documents WHERE state = 1 ORDER BY date ASC LIMIT " + (limitDownloadsDocuments - count)); + ArrayList entriesToRemove = new ArrayList<>(); + while (cursor.next()) { + DownloadingDocumentEntry entry = new DownloadingDocumentEntry(); + entry.hash = cursor.intValue(0); + entry.id = cursor.longValue(1); + entriesToRemove.add(entry); + } + cursor.dispose(); + + SQLitePreparedStatement state = getMessagesStorage().getDatabase().executeFast("DELETE FROM downloading_documents WHERE hash = ? AND id = ?"); + for (int i = 0; i < entriesToRemove.size(); i++) { + state.requery(); + state.bindInteger(1, entriesToRemove.get(i).hash); + state.bindLong(2, entriesToRemove.get(i).id); + state.step(); + } + state.dispose(); + } + } catch (Exception e) { + FileLog.e(e); + } + }); } }); - getMessagesStorage().getStorageQueue().postRunnable(() -> { - try { - String req = String.format(Locale.ENGLISH, "UPDATE downloading_documents SET state = 1, date = %d WHERE hash = %d AND id = %d", System.currentTimeMillis(), parentObject.getDocument().dc_id, parentObject.getDocument().id); - getMessagesStorage().getDatabase().executeFast(req).stepThis().dispose(); - SQLiteCursor cursor = getMessagesStorage().getDatabase().queryFinalized("SELECT COUNT(*) FROM downloading_documents WHERE state = 1"); - int count = 0; - if (cursor.next()) { - count = cursor.intValue(0); - } - cursor.dispose(); - cursor = getMessagesStorage().getDatabase().queryFinalized("SELECT state FROM downloading_documents WHERE state = 1"); - if (cursor.next()) { - int state = cursor.intValue(0); - } - cursor.dispose(); - - int limitDownloadsDocuments = 100; - if (count > limitDownloadsDocuments) { - cursor = getMessagesStorage().getDatabase().queryFinalized("SELECT hash, id FROM downloading_documents WHERE state = 1 ORDER BY date ASC LIMIT " + (limitDownloadsDocuments - count)); - ArrayList entriesToRemove = new ArrayList<>(); - while (cursor.next()) { - DownloadingDocumentEntry entry = new DownloadingDocumentEntry(); - entry.hash = cursor.intValue(0); - entry.id = cursor.longValue(1); - entriesToRemove.add(entry); - } - cursor.dispose(); - - SQLitePreparedStatement state = getMessagesStorage().getDatabase().executeFast("DELETE FROM downloading_documents WHERE hash = ? AND id = ?"); - for (int i = 0; i < entriesToRemove.size(); i++) { - state.requery(); - state.bindInteger(1, entriesToRemove.get(i).hash); - state.bindLong(2, entriesToRemove.get(i).id); - state.step(); - } - state.dispose(); - } - } catch (Exception e) { - FileLog.e(e); - } - }); } public void onDownloadFail(MessageObject parentObject, int reason) { @@ -1264,7 +1264,7 @@ public class DownloadController extends BaseController implements NotificationCe }); } - Runnable clearUnviewedDownloadsRunnbale = new Runnable() { + Runnable clearUnviewedDownloadsRunnale = new Runnable() { @Override public void run() { clearUnviewedDownloads(); @@ -1273,8 +1273,8 @@ public class DownloadController extends BaseController implements NotificationCe }; private void putToUnviewedDownloads(MessageObject parentObject) { unviewedDownloads.put(parentObject.getId(), parentObject); - AndroidUtilities.cancelRunOnUIThread(clearUnviewedDownloadsRunnbale); - AndroidUtilities.runOnUIThread(clearUnviewedDownloadsRunnbale, 60000); + AndroidUtilities.cancelRunOnUIThread(clearUnviewedDownloadsRunnale); + AndroidUtilities.runOnUIThread(clearUnviewedDownloadsRunnale, 60000); } public void clearUnviewedDownloads() { diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/FileLoader.java b/TMessagesProj/src/main/java/org/telegram/messenger/FileLoader.java index fa979297e..644668e13 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/FileLoader.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/FileLoader.java @@ -31,7 +31,7 @@ public class FileLoader extends BaseController { void fileUploadProgressChanged(FileUploadOperation operation, String location, long uploadedSize, long totalSize, boolean isEncrypted); void fileDidUploaded(String location, TLRPC.InputFile inputFile, TLRPC.InputEncryptedFile inputEncryptedFile, byte[] key, byte[] iv, long totalFileSize); void fileDidFailedUpload(String location, boolean isEncrypted); - void fileDidLoaded(String location, File finalFile, int type); + void fileDidLoaded(String location, File finalFile, Object parentObject, int type); void fileDidFailedLoad(String location, int state); void fileLoadProgressChanged(FileLoadOperation operation, String location, long uploadedSize, long totalSize); } @@ -42,6 +42,9 @@ public class FileLoader extends BaseController { public static final int MEDIA_DIR_DOCUMENT = 3; public static final int MEDIA_DIR_CACHE = 4; + public static final int MEDIA_DIR_IMAGE_PUBLIC = 100; + public static final int MEDIA_DIR_VIDEO_PUBLIC = 101; + public static final int IMAGE_TYPE_LOTTIE = 1; public static final int IMAGE_TYPE_ANIMATION = 2; public static final int IMAGE_TYPE_SVG = 3; @@ -707,14 +710,14 @@ public class FileLoader extends BaseController { if (!operation.isPreloadVideoOperation() && operation.isPreloadFinished()) { return; } - if (document != null && parentObject instanceof MessageObject) { + if (document != null && parentObject instanceof MessageObject && ((MessageObject) parentObject).putInDownloadsStore) { getDownloadController().onDownloadComplete((MessageObject) parentObject); } if (!operation.isPreloadVideoOperation()) { loadOperationPathsUI.remove(fileName); if (delegate != null) { - delegate.fileDidLoaded(fileName, finalFile, finalType); + delegate.fileDidLoaded(fileName, finalFile, parentObject, finalType); } } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/ForwardingMessagesParams.java b/TMessagesProj/src/main/java/org/telegram/messenger/ForwardingMessagesParams.java index 3bfc46f5f..6454df01a 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/ForwardingMessagesParams.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/ForwardingMessagesParams.java @@ -67,6 +67,7 @@ public class ForwardingMessagesParams { message.post = messageObject.messageOwner.post; message.legacy = messageObject.messageOwner.legacy; message.restriction_reason = messageObject.messageOwner.restriction_reason; + message.replyMessage = messageObject.messageOwner.replyMessage; TLRPC.MessageFwdHeader header = null; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/ImageLoader.java b/TMessagesProj/src/main/java/org/telegram/messenger/ImageLoader.java index 1ac00514e..b2e1dcedf 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/ImageLoader.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/ImageLoader.java @@ -1905,12 +1905,16 @@ public class ImageLoader { } @Override - public void fileDidLoaded(final String location, final File finalFile, final int type) { + public void fileDidLoaded(final String location, final File finalFile, Object parentObject, final int type) { fileProgresses.remove(location); AndroidUtilities.runOnUIThread(() -> { - if (SharedConfig.saveToGallery && telegramPath != null && finalFile != null && (location.endsWith(".mp4") || location.endsWith(".jpg"))) { - if (finalFile.toString().startsWith(telegramPath.toString())) { - AndroidUtilities.addMediaToGallery(finalFile.toString()); + if (SharedConfig.saveToGallery && finalFile != null && (location.endsWith(".mp4") || location.endsWith(".jpg"))) { + if (parentObject instanceof MessageObject) { + MessageObject messageObject = (MessageObject) parentObject; + // test add only for peer dialogs + if (messageObject.getDialogId() >= 0) { + AndroidUtilities.addMediaToGallery(finalFile.toString()); + } } } NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.fileLoaded, location, finalFile); @@ -2052,14 +2056,20 @@ public class ImageLoader { } } + File publicMediaDir = null; if (Build.VERSION.SDK_INT >= 30) { - File newPath = ApplicationLoader.applicationContext.getExternalFilesDir(null); + File newPath; + try { + if (ApplicationLoader.applicationContext.getExternalMediaDirs().length > 0) { + publicMediaDir = ApplicationLoader.applicationContext.getExternalMediaDirs()[0]; + publicMediaDir = new File(publicMediaDir, "Telegram"); + publicMediaDir.mkdirs(); + } + } catch (Exception e) { + FileLog.e(e); + } + newPath = ApplicationLoader.applicationContext.getExternalFilesDir(null); telegramPath = new File(newPath, "Telegram"); -// File oldPath = new File(path, "Telegram"); -// long moveStart = System.currentTimeMillis(); -// moveDirectory(oldPath, telegramPath); -// long dt = System.currentTimeMillis() - moveStart; -// FileLog.d("move time = " + dt); } else { telegramPath = new File(path, "Telegram"); } @@ -2133,6 +2143,33 @@ public class ImageLoader { FileLog.e(e); } } + if (publicMediaDir != null && publicMediaDir.isDirectory()) { + try { + File imagePath = new File(publicMediaDir, "Telegram Images"); + imagePath.mkdir(); + if (imagePath.isDirectory() && canMoveFiles(cachePath, imagePath, FileLoader.MEDIA_DIR_IMAGE)) { + mediaDirs.put(FileLoader.MEDIA_DIR_IMAGE_PUBLIC, imagePath); + if (BuildVars.LOGS_ENABLED) { + FileLog.d("image path = " + imagePath); + } + } + } catch (Exception e) { + FileLog.e(e); + } + + try { + File videoPath = new File(publicMediaDir, "Telegram Video"); + videoPath.mkdir(); + if (videoPath.isDirectory() && canMoveFiles(cachePath, videoPath, FileLoader.MEDIA_DIR_VIDEO)) { + mediaDirs.put(FileLoader.MEDIA_DIR_VIDEO_PUBLIC, videoPath); + if (BuildVars.LOGS_ENABLED) { + FileLog.d("video path = " + videoPath); + } + } + } catch (Exception e) { + FileLog.e(e); + } + } } else { if (BuildVars.LOGS_ENABLED) { FileLog.d("this Android can't rename files"); @@ -3844,6 +3881,10 @@ public class ImageLoader { return null; } + public DispatchQueue getCacheOutQueue() { + return cacheOutQueue; + } + public static class MessageThumb { BitmapDrawable drawable; String key; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/ImageReceiver.java b/TMessagesProj/src/main/java/org/telegram/messenger/ImageReceiver.java index 933e36975..a7445ae3e 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/ImageReceiver.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/ImageReceiver.java @@ -1552,11 +1552,12 @@ public class ImageReceiver implements NotificationCenter.NotificationCenterDeleg } public Bitmap getBitmap() { - AnimatedFileDrawable animation = getAnimation(); RLottieDrawable lottieDrawable = getLottieAnimation(); if (lottieDrawable != null && lottieDrawable.hasBitmap()) { return lottieDrawable.getAnimatedBitmap(); - } else if (animation != null && animation.hasBitmap()) { + } + AnimatedFileDrawable animation = getAnimation(); + if (animation != null && animation.hasBitmap()) { return animation.getAnimatedBitmap(); } else if (currentMediaDrawable instanceof BitmapDrawable && !(currentMediaDrawable instanceof AnimatedFileDrawable) && !(currentMediaDrawable instanceof RLottieDrawable)) { return ((BitmapDrawable) currentMediaDrawable).getBitmap(); @@ -2043,7 +2044,6 @@ public class ImageReceiver implements NotificationCenter.NotificationCenterDeleg } public AnimatedFileDrawable getAnimation() { - AnimatedFileDrawable animatedFileDrawable; if (currentMediaDrawable instanceof AnimatedFileDrawable) { return (AnimatedFileDrawable) currentMediaDrawable; } else if (currentImageDrawable instanceof AnimatedFileDrawable) { @@ -2057,7 +2057,6 @@ public class ImageReceiver implements NotificationCenter.NotificationCenterDeleg } public RLottieDrawable getLottieAnimation() { - RLottieDrawable animatedFileDrawable; if (currentMediaDrawable instanceof RLottieDrawable) { return (RLottieDrawable) currentMediaDrawable; } else if (currentImageDrawable instanceof RLottieDrawable) { diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/LanguageDetector.java b/TMessagesProj/src/main/java/org/telegram/messenger/LanguageDetector.java index f4e30e68b..26723e790 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/LanguageDetector.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/LanguageDetector.java @@ -13,18 +13,40 @@ public class LanguageDetector { } public static void detectLanguage(String text, StringCallback onSuccess, ExceptionCallback onFail) { + detectLanguage(text, onSuccess, onFail, false); + } + + public static void detectLanguage(String text, StringCallback onSuccess, ExceptionCallback onFail, boolean initializeFirst) { try { + if (initializeFirst) { + com.google.mlkit.common.sdkinternal.MlKitContext.zza(ApplicationLoader.applicationContext); + } com.google.mlkit.nl.languageid.LanguageIdentification.getClient() - .identifyLanguage(text) - .addOnSuccessListener(str -> { + .identifyLanguage(text) + .addOnSuccessListener(str -> { + if (onSuccess != null) { onSuccess.run(str); - }) - .addOnFailureListener(e -> { + } + }) + .addOnFailureListener(e -> { + if (onFail != null) { onFail.run(e); - }); + } + }); + } catch (IllegalStateException e) { + if (!initializeFirst) { + detectLanguage(text, onSuccess, onFail, true); + } else if (onFail != null) { + onFail.run(e); + } } catch (Exception e) { - FileLog.e(e); - onFail.run(e); + if (onFail != null) { + onFail.run(e); + } + } catch (Throwable t) { + if (onFail != null) { + onFail.run(null); + } } } } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/LocaleController.java b/TMessagesProj/src/main/java/org/telegram/messenger/LocaleController.java index c9f6c5213..3e49ebaa6 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/LocaleController.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/LocaleController.java @@ -948,13 +948,20 @@ public class LocaleController { reloadLastFile = false; } if (!isLoadingRemote) { - NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.reloadInterface); + if (init) { + AndroidUtilities.runOnUIThread(() -> NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.reloadInterface)); + } else { + NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.reloadInterface); + } } } catch (Exception e) { FileLog.e(e); changingConfiguration = false; } recreateFormatters(); + if (force) { + MediaDataController.getInstance(currentAccount).loadAttachMenuBots(false, true); + } } public LocaleInfo getCurrentLocaleInfo() { @@ -1085,6 +1092,14 @@ public class LocaleController { } } + public static String formatString(@StringRes int res, Object... args) { + String key = resourcesCacheMap.get(res); + if (key == null) { + resourcesCacheMap.put(res, key = ApplicationLoader.applicationContext.getResources().getResourceEntryName(res)); + } + return formatString(key, res, args); + } + public static String formatString(String key, int res, Object... args) { return formatString(key, null, res, args); } @@ -1121,15 +1136,15 @@ public class LocaleController { return LocaleController.formatPluralString("Hours", ttl / 60 / 60); } else if (ttl < 60 * 60 * 24 * 7) { return LocaleController.formatPluralString("Days", ttl / 60 / 60 / 24); - } else if (ttl >= 60 * 60 * 24 * 30 && ttl <= 60 * 60 * 24 * 31) { - return LocaleController.formatPluralString("Months", ttl / 60 / 60 / 24 / 30); - } else { + } else if (ttl < 60 * 60 * 24 * 31) { int days = ttl / 60 / 60 / 24; if (ttl % 7 == 0) { return LocaleController.formatPluralString("Weeks", days / 7); } else { return String.format("%s %s", LocaleController.formatPluralString("Weeks", days / 7), LocaleController.formatPluralString("Days", days % 7)); } + } else { + return LocaleController.formatPluralString("Months", ttl / 60 / 60 / 24 / 30); } } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/MediaController.java b/TMessagesProj/src/main/java/org/telegram/messenger/MediaController.java index 5fa715b5b..93582704a 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/MediaController.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/MediaController.java @@ -231,6 +231,33 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener, public float lockedAspectRatio; public boolean initied; + + @Override + public CropState clone() { + CropState cloned = new CropState(); + + cloned.cropPx = this.cropPx; + cloned.cropPy = this.cropPy; + cloned.cropScale = this.cropScale; + cloned.cropRotate = this.cropRotate; + cloned.cropPw = this.cropPw; + cloned.cropPh = this.cropPh; + cloned.transformWidth = this.transformWidth; + cloned.transformHeight = this.transformHeight; + cloned.transformRotation = this.transformRotation; + cloned.mirrored = this.mirrored; + + cloned.stateScale = this.stateScale; + cloned.scale = this.scale; + cloned.matrix = this.matrix; + cloned.width = this.width; + cloned.height = this.height; + cloned.freeform = this.freeform; + cloned.lockedAspectRatio = this.lockedAspectRatio; + + cloned.initied = this.initied; + return cloned; + } } public static class MediaEditState { @@ -4082,7 +4109,7 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener, try { int selectedType = type; ContentValues contentValues = new ContentValues(); - String extension = MimeTypeMap.getFileExtensionFromUrl(sourceFile.getAbsolutePath()); + String extension = FileLoader.getFileExtension(sourceFile); String mimeType = null; if (extension != null) { mimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension); @@ -4831,7 +4858,7 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener, resultWidth = temp; } - if (framerate > 30 && (Math.min(resultHeight, resultWidth) <= 480)) { + if (framerate > 40 && (Math.min(resultHeight, resultWidth) <= 480)) { framerate = 30; } @@ -4929,12 +4956,12 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener, minCompressFactor = 1f; } else if (Math.min(height, width) >= 720) { maxBitrate = 2600_000; - compressFactor = 0.8f; - minCompressFactor = 0.8f; + compressFactor = 1f; + minCompressFactor = 1f; } else if (Math.min(height, width) >= 480) { maxBitrate = 1000_000; - compressFactor = 0.7f; - minCompressFactor = 0.8f; + compressFactor = 0.75f; + minCompressFactor = 0.9f; } else { maxBitrate = 750_000; compressFactor = 0.6f; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/MediaDataController.java b/TMessagesProj/src/main/java/org/telegram/messenger/MediaDataController.java index 4d47c1358..3c85ae4c2 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/MediaDataController.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/MediaDataController.java @@ -34,6 +34,8 @@ import android.text.TextUtils; import android.text.style.CharacterStyle; import android.util.SparseArray; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import androidx.collection.LongSparseArray; import androidx.core.content.pm.ShortcutInfoCompat; import androidx.core.content.pm.ShortcutManagerCompat; @@ -43,6 +45,8 @@ import org.telegram.SQLite.SQLiteCursor; import org.telegram.SQLite.SQLiteDatabase; import org.telegram.SQLite.SQLiteException; import org.telegram.SQLite.SQLitePreparedStatement; +import org.telegram.messenger.ringtone.RingtoneDataStore; +import org.telegram.messenger.ringtone.RingtoneUploader; import org.telegram.messenger.support.SparseLongArray; import org.telegram.tgnet.ConnectionsManager; import org.telegram.tgnet.NativeByteBuffer; @@ -76,6 +80,14 @@ import java.util.regex.Pattern; @SuppressWarnings("unchecked") public class MediaDataController extends BaseController { + public final static String ATTACH_MENU_BOT_ANIMATED_ICON_KEY = "android_animated", + ATTACH_MENU_BOT_STATIC_ICON_KEY = "default_static", + ATTACH_MENU_BOT_PLACEHOLDER_STATIC_KEY = "placeholder_static", + ATTACH_MENU_BOT_COLOR_LIGHT_ICON = "light_icon", + ATTACH_MENU_BOT_COLOR_LIGHT_TEXT = "light_text", + ATTACH_MENU_BOT_COLOR_DARK_ICON = "dark_icon", + ATTACH_MENU_BOT_COLOR_DARK_TEXT = "dark_text"; + private static Pattern BOLD_PATTERN = Pattern.compile("\\*\\*(.+?)\\*\\*"), ITALIC_PATTERN = Pattern.compile("__(.+?)__"), SPOILER_PATTERN = Pattern.compile("\\|\\|(.+?)\\|\\|"), @@ -145,6 +157,7 @@ public class MediaDataController extends BaseController { } loadStickersByEmojiOrName(AndroidUtilities.STICKERS_PLACEHOLDER_PACK_NAME, false, true); + ringtoneDataStore = new RingtoneDataStore(currentAccount); } public static final int TYPE_IMAGE = 0; @@ -155,6 +168,11 @@ public class MediaDataController extends BaseController { public static final int TYPE_GREETINGS = 3; + private long menuBotsUpdateHash; + private TLRPC.TL_attachMenuBots attachMenuBots = new TLRPC.TL_attachMenuBots(); + private boolean isLoadingMenuBots; + private int menuBotsUpdateDate; + private int reactionsUpdateHash; private List reactionsList = new ArrayList<>(); private List enabledReactionsList = new ArrayList<>(); @@ -178,6 +196,7 @@ public class MediaDataController extends BaseController { private boolean[] stickersLoaded = new boolean[5]; private long[] loadHash = new long[5]; private int[] loadDate = new int[5]; + public HashMap ringtoneUploaderHashMap = new HashMap<>(); private HashMap> verifyingMessages = new HashMap<>(); @@ -205,6 +224,7 @@ public class MediaDataController extends BaseController { private boolean featuredStickersLoaded; private TLRPC.Document greetingsSticker; + public final RingtoneDataStore ringtoneDataStore; public void cleanup() { for (int a = 0; a < recentStickers.length; a++) { @@ -282,6 +302,108 @@ public class MediaDataController extends BaseController { } } + public void checkMenuBots() { + if (!isLoadingMenuBots && Math.abs(System.currentTimeMillis() / 1000 - menuBotsUpdateDate) >= 60 * 60) { + loadAttachMenuBots(true, false); + } + } + + public TLRPC.TL_attachMenuBots getAttachMenuBots() { + return attachMenuBots; + } + + public void loadAttachMenuBots(boolean cache, boolean force) { + isLoadingMenuBots = true; + if (cache) { + getMessagesStorage().getStorageQueue().postRunnable(() -> { + SQLiteCursor c = null; + long hash = 0; + int date = 0; + TLRPC.TL_attachMenuBots bots = null; + try { + c = getMessagesStorage().getDatabase().queryFinalized("SELECT data, hash, date FROM attach_menu_bots"); + if (c.next()) { + NativeByteBuffer data = c.byteBufferValue(0); + if (data != null) { + TLRPC.AttachMenuBots attachMenuBots = TLRPC.TL_attachMenuBots.TLdeserialize(data, data.readInt32(false), true); + if (attachMenuBots instanceof TLRPC.TL_attachMenuBots) { + bots = (TLRPC.TL_attachMenuBots) attachMenuBots; + } + data.reuse(); + } + hash = c.longValue(1); + date = c.intValue(2); + } + } catch (Exception e) { + FileLog.e(e, false); + } finally { + if (c != null) { + c.dispose(); + } + } + processLoadedMenuBots(bots, hash, date, true); + }); + } else { + TLRPC.TL_messages_getAttachMenuBots req = new TLRPC.TL_messages_getAttachMenuBots(); + req.hash = force ? 0 : menuBotsUpdateHash; + getConnectionsManager().sendRequest(req, (response, error) -> { + int date = (int) (System.currentTimeMillis() / 1000); + if (response instanceof TLRPC.TL_attachMenuBotsNotModified) { + processLoadedMenuBots(null, 0, date, false); + } else if (response instanceof TLRPC.TL_attachMenuBots) { + TLRPC.TL_attachMenuBots r = (TLRPC.TL_attachMenuBots) response; + processLoadedMenuBots(r, r.hash, date, false); + } + }); + } + } + + private void processLoadedMenuBots(TLRPC.TL_attachMenuBots bots, long hash, int date, boolean cache) { + if (bots != null && date != 0) { + attachMenuBots = bots; + menuBotsUpdateHash = hash; + } + menuBotsUpdateDate = date; + if (bots != null) { + getMessagesController().putUsers(bots.users, cache); + AndroidUtilities.runOnUIThread(() -> NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.attachMenuBotsDidLoad)); + } + + if (!cache) { + putMenuBotsToCache(bots, hash, date); + } else if (Math.abs(System.currentTimeMillis() / 1000 - date) >= 60 * 60) { + loadAttachMenuBots(false, true); + } + } + + private void putMenuBotsToCache(TLRPC.TL_attachMenuBots bots, long hash, int date) { + getMessagesStorage().getStorageQueue().postRunnable(() -> { + try { + if (bots != null) { + getMessagesStorage().getDatabase().executeFast("DELETE FROM attach_menu_bots").stepThis().dispose(); + SQLitePreparedStatement state = getMessagesStorage().getDatabase().executeFast("REPLACE INTO attach_menu_bots VALUES(?, ?, ?)"); + state.requery(); + NativeByteBuffer data = new NativeByteBuffer(bots.getObjectSize()); + bots.serializeToStream(data); + state.bindByteBuffer(1, data); + state.bindLong(2, hash); + state.bindInteger(3, date); + state.step(); + data.reuse(); + state.dispose(); + } else { + SQLitePreparedStatement state = getMessagesStorage().getDatabase().executeFast("UPDATE attach_menu_bots SET date = ?"); + state.requery(); + state.bindLong(1, date); + state.step(); + state.dispose(); + } + } catch (Exception e) { + FileLog.e(e); + } + }); + } + public List getReactionsList() { return reactionsList; } @@ -866,6 +988,36 @@ public class MediaDataController extends BaseController { return value != null ? value : ""; } + @Nullable + public static TLRPC.TL_attachMenuBotIcon getAnimatedAttachMenuBotIcon(@NonNull TLRPC.TL_attachMenuBot bot) { + for (TLRPC.TL_attachMenuBotIcon icon : bot.icons) { + if (icon.name.equals(ATTACH_MENU_BOT_ANIMATED_ICON_KEY)) { + return icon; + } + } + return null; + } + + @Nullable + public static TLRPC.TL_attachMenuBotIcon getStaticAttachMenuBotIcon(@NonNull TLRPC.TL_attachMenuBot bot) { + for (TLRPC.TL_attachMenuBotIcon icon : bot.icons) { + if (icon.name.equals(ATTACH_MENU_BOT_STATIC_ICON_KEY)) { + return icon; + } + } + return null; + } + + @Nullable + public static TLRPC.TL_attachMenuBotIcon getPlaceholderStaticAttachMenuBotIcon(@NonNull TLRPC.TL_attachMenuBot bot) { + for (TLRPC.TL_attachMenuBotIcon icon : bot.icons) { + if (icon.name.equals(ATTACH_MENU_BOT_PLACEHOLDER_STATIC_KEY)) { + return icon; + } + } + return null; + } + public static long calcDocumentsHash(ArrayList arrayList) { return calcDocumentsHash(arrayList, 200); } @@ -2640,9 +2792,9 @@ public class MediaDataController extends BaseController { type = MEDIA_MUSIC; } else if (searchCounter.filter instanceof TLRPC.TL_inputMessagesFilterGif) { type = MEDIA_GIF; - } else if (searchCounter.filter instanceof TLRPC.TL_inputMessagesFilterPhotos) { + } else if (searchCounter.filter instanceof TLRPC.TL_inputMessagesFilterPhotos) { type = MEDIA_PHOTOS_ONLY; - } else if (searchCounter.filter instanceof TLRPC.TL_inputMessagesFilterVideo) { + } else if (searchCounter.filter instanceof TLRPC.TL_inputMessagesFilterVideo) { type = MEDIA_VIDEOS_ONLY; } else { continue; @@ -4294,7 +4446,12 @@ public class MediaDataController extends BaseController { if (ids == null) { continue; } - SQLiteCursor cursor = getMessagesStorage().getDatabase().queryFinalized(String.format(Locale.US, "SELECT data, mid, date, uid FROM messages_v2 WHERE mid IN(%s) AND uid = %d", TextUtils.join(",", ids), dialogId)); + SQLiteCursor cursor; + if (scheduled) { + cursor = getMessagesStorage().getDatabase().queryFinalized(String.format(Locale.US, "SELECT data, mid, date, uid FROM scheduled_messages_v2 WHERE mid IN(%s) AND uid = %d", TextUtils.join(",", ids), dialogId)); + } else { + cursor = getMessagesStorage().getDatabase().queryFinalized(String.format(Locale.US, "SELECT data, mid, date, uid FROM messages_v2 WHERE mid IN(%s) AND uid = %d", TextUtils.join(",", ids), dialogId)); + } while (cursor.next()) { NativeByteBuffer data = cursor.byteBufferValue(0); if (data != null) { @@ -4331,7 +4488,30 @@ public class MediaDataController extends BaseController { if (!dialogReplyMessagesIds.isEmpty()) { for (int a = 0, N = dialogReplyMessagesIds.size(); a < N; a++) { long channelId = dialogReplyMessagesIds.keyAt(a); - if (channelId != 0) { + if (scheduled) { + TLRPC.TL_messages_getScheduledMessages req = new TLRPC.TL_messages_getScheduledMessages(); + req.peer = getMessagesController().getInputPeer(dialogId); + req.id = dialogReplyMessagesIds.valueAt(a); + getConnectionsManager().sendRequest(req, (response, error) -> { + if (error == null) { + TLRPC.messages_Messages messagesRes = (TLRPC.messages_Messages) response; + for (int i = 0; i < messagesRes.messages.size(); i++) { + TLRPC.Message message = messagesRes.messages.get(i); + if (message.dialog_id == 0) { + message.dialog_id = dialogId; + } + } + MessageObject.fixMessagePeer(messagesRes.messages, channelId); + ImageLoader.saveMessagesThumbs(messagesRes.messages); + broadcastReplyMessages(messagesRes.messages, replyMessageOwners, messagesRes.users, messagesRes.chats, dialogId, false); + getMessagesStorage().putUsersAndChats(messagesRes.users, messagesRes.chats, true, true); + saveReplyMessages(replyMessageOwners, messagesRes.messages, scheduled); + } + if (callback != null) { + AndroidUtilities.runOnUIThread(callback); + } + }); + } else if (channelId != 0) { TLRPC.TL_channels_getMessages req = new TLRPC.TL_channels_getMessages(); req.channel = getMessagesController().getInputChannel(channelId); req.id = dialogReplyMessagesIds.valueAt(a); @@ -4643,7 +4823,7 @@ public class MediaDataController extends BaseController { }); for (int a = 0, N = entitiesCopy.size(); a < N; a++) { TLRPC.MessageEntity entity = entitiesCopy.get(a); - if (entity.length <= 0 || entity.offset < 0 || entity.offset >= text.length()) { + if (entity == null || entity.length <= 0 || entity.offset < 0 || entity.offset >= text.length()) { continue; } else if (entity.offset + entity.length > text.length()) { entity.length = text.length() - entity.offset; @@ -5482,6 +5662,61 @@ public class MediaDataController extends BaseController { public List getEnabledReactionsList() { return enabledReactionsList; } + + public void uploadRingtone(String filePath) { + if (ringtoneUploaderHashMap.containsKey(filePath)) { + return; + } + ringtoneUploaderHashMap.put(filePath, new RingtoneUploader(filePath, currentAccount)); + ringtoneDataStore.addUploadingTone(filePath); + } + + public void onRingtoneUploaded(String filePath, TLRPC.Document document, boolean error) { + ringtoneUploaderHashMap.remove(filePath); + ringtoneDataStore.onRingtoneUploaded(filePath, document, error); + } + + public void checkRingtones() { + ringtoneDataStore.loadUserRingtones(); + } + + public boolean saveToRingtones(TLRPC.Document document) { + if (document == null) { + return false; + } + if (ringtoneDataStore.contains(document.id)) { + return true; + } + if (document.size > MessagesController.getInstance(currentAccount).ringtoneSizeMax) { + NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.showBulletin, Bulletin.TYPE_ERROR_SUBTITLE, LocaleController.formatString("TooLargeError", R.string.TooLargeError), LocaleController.formatString("ErrorRingtoneSizeTooBig", R.string.ErrorRingtoneSizeTooBig, (MessagesController.getInstance(UserConfig.selectedAccount).ringtoneSizeMax / 1024))); + return false; + } + for (int a = 0; a < document.attributes.size(); a++) { + TLRPC.DocumentAttribute attribute = document.attributes.get(a); + if (attribute instanceof TLRPC.TL_documentAttributeAudio) { + if (attribute.duration > MessagesController.getInstance(currentAccount).ringtoneDurationMax) { + NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.showBulletin, Bulletin.TYPE_ERROR_SUBTITLE, LocaleController.formatString("TooLongError", R.string.TooLongError), LocaleController.formatString("ErrorRingtoneDurationTooLong", R.string.ErrorRingtoneDurationTooLong, MessagesController.getInstance(UserConfig.selectedAccount).ringtoneDurationMax)); + return false; + } + } + } + TLRPC.TL_account_saveRingtone saveRingtone = new TLRPC.TL_account_saveRingtone(); + saveRingtone.id = new TLRPC.TL_inputDocument(); + saveRingtone.id.id = document.id; + saveRingtone.id.file_reference = document.file_reference; + saveRingtone.id.access_hash = document.access_hash; + ConnectionsManager.getInstance(currentAccount).sendRequest(saveRingtone, (response, error) -> AndroidUtilities.runOnUIThread(() -> { + if (response != null) { + if (response instanceof TLRPC.TL_account_savedRingtoneConverted) { + ringtoneDataStore.addTone(((TLRPC.TL_account_savedRingtoneConverted) response).document); + } else { + ringtoneDataStore.addTone(document); + } + } + })); + return true; + } + //---------------- BOT END ---------------- //---------------- EMOJI START ---------------- @@ -5491,6 +5726,7 @@ public class MediaDataController extends BaseController { public String keyword; } + public interface KeywordResultCallback { void run(ArrayList param, String alias); } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/MessageObject.java b/TMessagesProj/src/main/java/org/telegram/messenger/MessageObject.java index 601b53fb9..3d19da05e 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/MessageObject.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/MessageObject.java @@ -30,13 +30,13 @@ import androidx.collection.LongSparseArray; import org.telegram.PhoneFormat.PhoneFormat; import org.telegram.messenger.browser.Browser; +import org.telegram.messenger.ringtone.RingtoneDataStore; import org.telegram.tgnet.ConnectionsManager; import org.telegram.tgnet.SerializedData; import org.telegram.tgnet.TLObject; import org.telegram.tgnet.TLRPC; import org.telegram.ui.ActionBar.Theme; import org.telegram.ui.Cells.ChatMessageCell; -import org.telegram.ui.Components.spoilers.SpoilerEffect; import org.telegram.ui.Components.TextStyleSpan; import org.telegram.ui.Components.TypefaceSpan; import org.telegram.ui.Components.URLSpanBotCommand; @@ -46,6 +46,7 @@ import org.telegram.ui.Components.URLSpanNoUnderline; import org.telegram.ui.Components.URLSpanNoUnderlineBold; import org.telegram.ui.Components.URLSpanReplacement; import org.telegram.ui.Components.URLSpanUserMention; +import org.telegram.ui.Components.spoilers.SpoilerEffect; import java.io.BufferedReader; import java.io.File; @@ -205,6 +206,10 @@ public class MessageObject { public ImageLocation mediaThumb; public ImageLocation mediaSmallThumb; + // forwarding preview params + public boolean hideSendersName; + public TLRPC.Peer sendAsPeer; + static final String[] excludeWords = new String[] { " vs. ", " vs ", @@ -2532,7 +2537,11 @@ public class MessageObject { if (button instanceof TLRPC.TL_keyboardButtonBuy && (messageOwner.media.flags & 4) != 0) { text = LocaleController.getString("PaymentReceipt", R.string.PaymentReceipt); } else { - text = Emoji.replaceEmoji(button.text, Theme.chat_msgBotButtonPaint.getFontMetricsInt(), AndroidUtilities.dp(15), false); + String str = button.text; + if (str == null) { + str = ""; + } + text = Emoji.replaceEmoji(str, Theme.chat_msgBotButtonPaint.getFontMetricsInt(), AndroidUtilities.dp(15), false); } StaticLayout staticLayout = new StaticLayout(text, Theme.chat_msgBotButtonPaint, AndroidUtilities.dp(2000), Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); if (staticLayout.getLineCount() > 0) { @@ -3058,6 +3067,9 @@ public class MessageObject { user = getUser(users, sUsers, messageOwner.peer_id.user_id); } messageText = LocaleController.formatString("ActionBotDocuments", R.string.ActionBotDocuments, UserObject.getFirstName(user), str.toString()); + } else if (messageOwner.action instanceof TLRPC.TL_messageActionWebViewDataSent) { + TLRPC.TL_messageActionWebViewDataSent dataSent = (TLRPC.TL_messageActionWebViewDataSent) messageOwner.action; + messageText = LocaleController.formatString("ActionBotWebViewData", R.string.ActionBotWebViewData, dataSent.text); } else if (messageOwner.action instanceof TLRPC.TL_messageActionSetChatTheme) { String emoticon = ((TLRPC.TL_messageActionSetChatTheme) messageOwner.action).emoticon; String userName = UserObject.getFirstName(fromUser); @@ -5513,7 +5525,7 @@ public class MessageObject { } public boolean isMusic() { - return isMusicMessage(messageOwner); + return isMusicMessage(messageOwner) && !isVideo(); } public boolean isDocument() { @@ -6399,4 +6411,18 @@ public class MessageObject { reactionsChanged = true; return true; } + + public boolean probablyRingtone() { + 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); + if (attribute instanceof TLRPC.TL_documentAttributeAudio) { + if (attribute.duration < MessagesController.getInstance(currentAccount).ringtoneDurationMax * 2) { + return true; + } + } + } + } + return false; + } } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/MessagesController.java b/TMessagesProj/src/main/java/org/telegram/messenger/MessagesController.java index 756c74f81..aa7be0def 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/MessagesController.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/MessagesController.java @@ -8,6 +8,9 @@ package org.telegram.messenger; +import static org.telegram.messenger.NotificationsController.TYPE_CHANNEL; +import static org.telegram.messenger.NotificationsController.TYPE_PRIVATE; + import android.app.Activity; import android.appwidget.AppWidgetManager; import android.content.Context; @@ -45,6 +48,7 @@ import org.telegram.ui.ActionBar.AlertDialog; import org.telegram.ui.ActionBar.BaseFragment; import org.telegram.ui.ActionBar.Theme; import org.telegram.ui.ChatActivity; +import org.telegram.ui.ChatRightsEditActivity; import org.telegram.ui.Components.AlertsCreator; import org.telegram.ui.Components.BulletinFactory; import org.telegram.ui.Components.JoinCallAlert; @@ -88,6 +92,8 @@ public class MessagesController extends BaseController implements NotificationCe public ArrayList dialogsForward = new ArrayList<>(); public ArrayList dialogsServerOnly = new ArrayList<>(); public ArrayList dialogsCanAddUsers = new ArrayList<>(); + public ArrayList dialogsMyChannels = new ArrayList<>(); + public ArrayList dialogsMyGroups = new ArrayList<>(); public ArrayList dialogsChannelsOnly = new ArrayList<>(); public ArrayList dialogsUsersOnly = new ArrayList<>(); public ArrayList dialogsForBlock = new ArrayList<>(); @@ -97,13 +103,7 @@ public class MessagesController extends BaseController implements NotificationCe public int unreadUnmutedDialogs; public ConcurrentHashMap dialogs_read_inbox_max = new ConcurrentHashMap<>(100, 1.0f, 2); public ConcurrentHashMap dialogs_read_outbox_max = new ConcurrentHashMap<>(100, 1.0f, 2); - public LongSparseArray dialogs_dict = new LongSparseArray() { - - @Override - public void put(long key, TLRPC.Dialog value) { - super.put(key, value); - } - }; + public LongSparseArray dialogs_dict = new LongSparseArray<>(); public LongSparseArray dialogMessage = new LongSparseArray<>(); public LongSparseArray dialogMessagesByRandomIds = new LongSparseArray<>(); public LongSparseIntArray deletedHistory = new LongSparseIntArray(); @@ -332,6 +332,8 @@ public class MessagesController extends BaseController implements NotificationCe public HashMap emojiSounds = new HashMap<>(); public HashMap> emojiInteractions = new HashMap<>(); public boolean remoteConfigLoaded; + public int ringtoneDurationMax; + public int ringtoneSizeMax; private SharedPreferences notificationsPreferences; private SharedPreferences mainPreferences; @@ -835,6 +837,9 @@ public class MessagesController extends BaseController implements NotificationCe groupCallVideoMaxParticipants = mainPreferences.getInt("groipCallVideoMaxParticipants", 30); chatReadMarkSizeThreshold = mainPreferences.getInt("chatReadMarkSizeThreshold", 50); chatReadMarkExpirePeriod = mainPreferences.getInt("chatReadMarkExpirePeriod", 7 * 86400); + ringtoneDurationMax = mainPreferences.getInt("ringtoneDurationMax", 5); + ringtoneSizeMax = mainPreferences.getInt("ringtoneSizeMax", 1024_00); + chatReadMarkExpirePeriod = mainPreferences.getInt("chatReadMarkExpirePeriod", 7 * 86400); suggestStickersApiOnly = mainPreferences.getBoolean("suggestStickersApiOnly", false); roundVideoSize = mainPreferences.getInt("roundVideoSize", 384); roundVideoBitrate = mainPreferences.getInt("roundVideoBitrate", 1000); @@ -1900,6 +1905,28 @@ public class MessagesController extends BaseController implements NotificationCe } break; } + case "ringtone_size_max": { + if (value.value instanceof TLRPC.TL_jsonNumber) { + TLRPC.TL_jsonNumber number = (TLRPC.TL_jsonNumber) value.value; + if (number.value != ringtoneSizeMax) { + ringtoneSizeMax = (int) number.value; + editor.putInt("ringtoneSizeMax", ringtoneSizeMax); + changed = true; + } + } + break; + } + case "ringtone_duration_max": { + if (value.value instanceof TLRPC.TL_jsonNumber) { + TLRPC.TL_jsonNumber number = (TLRPC.TL_jsonNumber) value.value; + if (number.value != ringtoneDurationMax) { + ringtoneDurationMax = (int) number.value; + editor.putInt("ringtoneDurationMax", ringtoneDurationMax); + changed = true; + } + } + break; + } } } if (changed) { @@ -2665,6 +2692,8 @@ public class MessagesController extends BaseController implements NotificationCe allDialogs.clear(); dialogsLoadedTillDate = Integer.MAX_VALUE; dialogsCanAddUsers.clear(); + dialogsMyChannels.clear(); + dialogsMyGroups.clear(); dialogsChannelsOnly.clear(); dialogsGroupsOnly.clear(); dialogsUsersOnly.clear(); @@ -4183,7 +4212,11 @@ public class MessagesController extends BaseController implements NotificationCe }); } - public void setUserAdminRole(long chatId, TLRPC.User user, TLRPC.TL_chatAdminRights rights, String rank, boolean isChannel, BaseFragment parentFragment, boolean addingNew) { + public void setUserAdminRole(long chatId, TLRPC.User user, TLRPC.TL_chatAdminRights rights, String rank, boolean isChannel, BaseFragment parentFragment, boolean addingNew, boolean forceAdmin, String botHash, Runnable onSuccess) { + setUserAdminRole(chatId, user, rights, rank, isChannel, parentFragment, addingNew, forceAdmin, botHash, onSuccess, null); + } + + public void setUserAdminRole(long chatId, TLRPC.User user, TLRPC.TL_chatAdminRights rights, String rank, boolean isChannel, BaseFragment parentFragment, boolean addingNew, boolean forceAdmin, String botHash, Runnable onSuccess, Runnable onError) { if (user == null || rights == null) { return; } @@ -4194,28 +4227,49 @@ public class MessagesController extends BaseController implements NotificationCe req.user_id = getInputUser(user); req.admin_rights = rights; req.rank = rank; - getConnectionsManager().sendRequest(req, (response, error) -> { + RequestDelegate requestDelegate = (response, error) -> { if (error == null) { processUpdates((TLRPC.Updates) response, false); - AndroidUtilities.runOnUIThread(() -> loadFullChat(chatId, 0, true), 1000); + AndroidUtilities.runOnUIThread(() -> { + loadFullChat(chatId, 0, true); + if (onSuccess != null) { + onSuccess.run(); + } + }, 1000); } else { AndroidUtilities.runOnUIThread(() -> AlertsCreator.processError(currentAccount, error, parentFragment, req, isChannel)); + if (onError != null) { + AndroidUtilities.runOnUIThread(onError); + } } - }); + }; + if (chat.megagroup && addingNew) { + addUserToChat(chatId, user, 0, botHash, parentFragment, true, () -> getConnectionsManager().sendRequest(req, requestDelegate), onError); + } else { + getConnectionsManager().sendRequest(req, requestDelegate); + } } else { TLRPC.TL_messages_editChatAdmin req = new TLRPC.TL_messages_editChatAdmin(); req.chat_id = chatId; req.user_id = getInputUser(user); - req.is_admin = rights.change_info || rights.delete_messages || rights.ban_users || rights.invite_users || rights.pin_messages || rights.add_admins || rights.manage_call; + req.is_admin = forceAdmin || rights.change_info || rights.delete_messages || rights.ban_users || rights.invite_users || rights.pin_messages || rights.add_admins || rights.manage_call; RequestDelegate requestDelegate = (response, error) -> { if (error == null) { - AndroidUtilities.runOnUIThread(() -> loadFullChat(chatId, 0, true), 1000); + AndroidUtilities.runOnUIThread(() -> { + loadFullChat(chatId, 0, true); + if (onSuccess != null) { + onSuccess.run(); + } + }, 1000); } else { AndroidUtilities.runOnUIThread(() -> AlertsCreator.processError(currentAccount, error, parentFragment, req, false)); + if (onError != null) { + AndroidUtilities.runOnUIThread(onError); + } } }; - if (req.is_admin && addingNew) { - addUserToChat(chatId, user, 0, null, parentFragment, () -> getConnectionsManager().sendRequest(req, requestDelegate)); + if (req.is_admin || addingNew) { + addUserToChat(chatId, user, 0, botHash, parentFragment, true, () -> getConnectionsManager().sendRequest(req, requestDelegate), onError); } else { getConnectionsManager().sendRequest(req, requestDelegate); } @@ -4939,6 +4993,8 @@ public class MessagesController extends BaseController implements NotificationCe }); } allDialogs.remove(dialog); + dialogsMyChannels.remove(dialog); + dialogsMyGroups.remove(dialog); dialogsCanAddUsers.remove(dialog); dialogsChannelsOnly.remove(dialog); dialogsGroupsOnly.remove(dialog); @@ -5221,6 +5277,7 @@ public class MessagesController extends BaseController implements NotificationCe } TLRPC.TL_channels_deleteHistory req = new TLRPC.TL_channels_deleteHistory(); req.channel = new TLRPC.TL_inputChannel(); + req.for_everyone = revoke; req.channel.channel_id = peer.channel_id; req.channel.access_hash = peer.access_hash; req.max_id = max_id_delete > 0 ? max_id_delete : Integer.MAX_VALUE; @@ -5228,6 +5285,9 @@ public class MessagesController extends BaseController implements NotificationCe if (newTaskId != 0) { getMessagesStorage().removePendingTask(newTaskId); } + if (response != null) { + processUpdates((TLRPC.Updates) response, false); + } }, ConnectionsManager.RequestFlagInvokeAfter); } else { TLRPC.TL_messages_deleteHistory req = new TLRPC.TL_messages_deleteHistory(); @@ -6585,6 +6645,10 @@ public class MessagesController extends BaseController implements NotificationCe reload = ((SystemClock.elapsedRealtime() - lastScheduledServerQueryTime.get(dialogId, 0L)) > 60 * 1000); } else { reload = resCount == 0 && (!isInitialLoading || (SystemClock.elapsedRealtime() - lastServerQueryTime.get(dialogId, 0L)) > 60 * 1000); + if (mode == 0 && isCache && dialogId < 0 && !dialogs_dict.containsKey(dialogId) && (SystemClock.elapsedRealtime() - lastServerQueryTime.get(dialogId, 0L)) > 24 * 60 * 60 * 1000) { + messagesRes.messages.clear(); + reload = true; + } } if (!DialogObject.isEncryptedDialog(dialogId) && isCache && reload) { int hash; @@ -7119,6 +7183,7 @@ public class MessagesController extends BaseController implements NotificationCe editor.putInt("EnableChannel2", notify_settings.mute_until); } } + applySoundSettings(notify_settings.android_sound, editor, 0, type, false); editor.commit(); if (loadingNotificationSettings == 0) { getUserConfig().notificationsSettingsLoaded = true; @@ -8148,6 +8213,7 @@ public class MessagesController extends BaseController implements NotificationCe } getMessagesStorage().setDialogFlags(dialogId, 0); } + applySoundSettings(notify_settings.android_sound, editor, dialogId, 0, false); editor.commit(); if (updated) { getNotificationCenter().postNotificationName(NotificationCenter.notificationsSettingsUpdated); @@ -9398,6 +9464,10 @@ public class MessagesController extends BaseController implements NotificationCe } public void addUserToChat(long chatId, TLRPC.User user, int forwardCount, String botHash, BaseFragment fragment, Runnable onFinishRunnable) { + addUserToChat(chatId, user, forwardCount, botHash, fragment, false, onFinishRunnable, null); + } + + public void addUserToChat(long chatId, TLRPC.User user, int forwardCount, String botHash, BaseFragment fragment, boolean ignoreIfAlreadyExists, Runnable onFinishRunnable, Runnable onError) { if (user == null) { return; } @@ -9449,6 +9519,15 @@ public class MessagesController extends BaseController implements NotificationCe AndroidUtilities.runOnUIThread(() -> joiningToChannels.remove(chatId)); } if (error != null) { + if ("USER_ALREADY_PARTICIPANT".equals(error.text) && ignoreIfAlreadyExists) { + if (onFinishRunnable != null) { + AndroidUtilities.runOnUIThread(onFinishRunnable); + } + return; + } + if (onError != null) { + AndroidUtilities.runOnUIThread(onError); + } AndroidUtilities.runOnUIThread(() -> { AlertsCreator.processError(currentAccount, error, fragment, request, isChannel && !isMegagroup); if (isChannel && inputUser instanceof TLRPC.TL_inputUserSelf) { @@ -9711,6 +9790,7 @@ public class MessagesController extends BaseController implements NotificationCe getConnectionsManager().cleanup(type == 2); } getUserConfig().clearConfig(); + SharedPrefsHelper.cleanupAccount(currentAccount); boolean shouldHandle = true; ArrayList observers = getNotificationCenter().getObservers(NotificationCenter.appDidLogout); @@ -12996,6 +13076,16 @@ public class MessagesController extends BaseController implements NotificationCe updatesOnMainThread = new ArrayList<>(); } updatesOnMainThread.add(baseUpdate); + } else if (baseUpdate instanceof TLRPC.TL_updateWebViewResultSent) { + if (updatesOnMainThread == null) { + updatesOnMainThread = new ArrayList<>(); + } + updatesOnMainThread.add(baseUpdate); + } else if (baseUpdate instanceof TLRPC.TL_updateAttachMenuBots) { + if (updatesOnMainThread == null) { + updatesOnMainThread = new ArrayList<>(); + } + updatesOnMainThread.add(baseUpdate); } else if (baseUpdate instanceof TLRPC.TL_updateReadChannelDiscussionInbox) { if (updatesOnMainThread == null) { updatesOnMainThread = new ArrayList<>(); @@ -13016,6 +13106,11 @@ public class MessagesController extends BaseController implements NotificationCe updatesOnMainThread = new ArrayList<>(); } updatesOnMainThread.add(baseUpdate); + } else if (baseUpdate instanceof TLRPC.TL_updateSavedRingtones) { + if (updatesOnMainThread == null) { + updatesOnMainThread = new ArrayList<>(); + } + updatesOnMainThread.add(baseUpdate); } } if (messages != null) { @@ -13292,6 +13387,7 @@ public class MessagesController extends BaseController implements NotificationCe editor.remove("notify2_" + dialogId); getMessagesStorage().setDialogFlags(dialogId, 0); } + applySoundSettings(update.notify_settings.android_sound, editor, dialogId, 0, true); } else if (update.peer instanceof TLRPC.TL_notifyChats) { if ((update.notify_settings.flags & 1) != 0) { editor.putBoolean("EnablePreviewGroup", update.notify_settings.show_previews); @@ -13310,6 +13406,7 @@ public class MessagesController extends BaseController implements NotificationCe AndroidUtilities.runOnUIThread(() -> getNotificationsController().deleteNotificationChannelGlobal(NotificationsController.TYPE_GROUP)); } } + applySoundSettings(update.notify_settings.android_sound, editor, 0, NotificationsController.TYPE_GROUP, false); } else if (update.peer instanceof TLRPC.TL_notifyUsers) { if ((update.notify_settings.flags & 1) != 0) { editor.putBoolean("EnablePreviewAll", update.notify_settings.show_previews); @@ -13321,11 +13418,12 @@ public class MessagesController extends BaseController implements NotificationCe editor.remove("GlobalSoundPath"); }*/ } + applySoundSettings(update.notify_settings.android_sound, editor, 0, TYPE_PRIVATE, false); if ((update.notify_settings.flags & 4) != 0) { if (notificationsPreferences.getInt("EnableAll2", 0) != update.notify_settings.mute_until) { editor.putInt("EnableAll2", update.notify_settings.mute_until); editor.putBoolean("overwrite_private", true); - AndroidUtilities.runOnUIThread(() -> getNotificationsController().deleteNotificationChannelGlobal(NotificationsController.TYPE_PRIVATE)); + AndroidUtilities.runOnUIThread(() -> getNotificationsController().deleteNotificationChannelGlobal(TYPE_PRIVATE)); } } } else if (update.peer instanceof TLRPC.TL_notifyBroadcasts) { @@ -13346,6 +13444,7 @@ public class MessagesController extends BaseController implements NotificationCe AndroidUtilities.runOnUIThread(() -> getNotificationsController().deleteNotificationChannelGlobal(NotificationsController.TYPE_CHANNEL)); } } + applySoundSettings(update.notify_settings.android_sound, editor, 0, TYPE_CHANNEL, false); } getMessagesStorage().updateMutedDialogsFiltersCounters(); } @@ -13617,6 +13716,11 @@ public class MessagesController extends BaseController implements NotificationCe loadRemoteFilters(true); } else if (baseUpdate instanceof TLRPC.TL_updateDialogFilters) { loadRemoteFilters(true); + } else if (baseUpdate instanceof TLRPC.TL_updateWebViewResultSent) { + TLRPC.TL_updateWebViewResultSent resultSent = (TLRPC.TL_updateWebViewResultSent) baseUpdate; + getNotificationCenter().postNotificationName(NotificationCenter.webViewResultSent, resultSent.query_id); + } else if (baseUpdate instanceof TLRPC.TL_updateAttachMenuBots) { + getMediaDataController().loadAttachMenuBots(false, true); } else if (baseUpdate instanceof TLRPC.TL_updateReadChannelDiscussionInbox) { TLRPC.TL_updateReadChannelDiscussionInbox update = (TLRPC.TL_updateReadChannelDiscussionInbox) baseUpdate; getNotificationCenter().postNotificationName(NotificationCenter.threadMessagesRead, -update.channel_id, update.top_msg_id, update.read_max_id, 0); @@ -13671,6 +13775,8 @@ public class MessagesController extends BaseController implements NotificationCe } else if (baseUpdate instanceof TLRPC.TL_updatePendingJoinRequests) { TLRPC.TL_updatePendingJoinRequests update = (TLRPC.TL_updatePendingJoinRequests) baseUpdate; getMemberRequestsController().onPendingRequestsUpdated(update); + } else if (baseUpdate instanceof TLRPC.TL_updateSavedRingtones) { + getMediaDataController().ringtoneDataStore.loadUserRingtones(); } } if (editor != null) { @@ -14063,7 +14169,6 @@ public class MessagesController extends BaseController implements NotificationCe if (reactionsMentionsMessageIds.get(messageId) != hasUnreadReaction) { newUnreadCount += hasUnreadReaction ? 1 : -1; changed = true; - } } else { needReload = true; @@ -14086,13 +14191,14 @@ public class MessagesController extends BaseController implements NotificationCe } } if (needReload) { - TLRPC.TL_messages_getUnreadReactions req = new TLRPC.TL_messages_getUnreadReactions(); - req.limit = 1; - req.peer = getInputPeer(dialogId); + TLRPC.TL_messages_getPeerDialogs req = new TLRPC.TL_messages_getPeerDialogs(); + TLRPC.TL_inputDialogPeer inputDialogPeer = new TLRPC.TL_inputDialogPeer(); + inputDialogPeer.peer = getInputPeer(dialogId); + req.peers.add(inputDialogPeer); ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> { if (response != null) { - TLRPC.messages_Messages messages = (TLRPC.messages_Messages) response; - int count = Math.max(messages.count, messages.messages.size()); + TLRPC.TL_messages_peerDialogs dialogs = (TLRPC.TL_messages_peerDialogs) response; + int count = dialogs.dialogs.size() == 0 ? 0 : dialogs.dialogs.get(0).unread_reactions_count; AndroidUtilities.runOnUIThread(() -> { TLRPC.Dialog dialog = dialogs_dict.get(dialogId); if (dialog == null) { @@ -14128,6 +14234,10 @@ public class MessagesController extends BaseController implements NotificationCe return isDialogMuted(dialogId, null); } + public boolean isDialogNotificationsSoundEnabled(long dialogId) { + return notificationsPreferences.getBoolean("sound_enabled_" + dialogId, true); + } + public boolean isDialogMuted(long dialogId, TLRPC.Chat chat) { int mute_type = notificationsPreferences.getInt("notify2_" + dialogId, -1); if (mute_type == -1) { @@ -14431,6 +14541,8 @@ public class MessagesController extends BaseController implements NotificationCe allDialogs.remove(dialog); dialogsServerOnly.remove(dialog); dialogsCanAddUsers.remove(dialog); + dialogsMyGroups.remove(dialog); + dialogsMyChannels.remove(dialog); dialogsChannelsOnly.remove(dialog); dialogsGroupsOnly.remove(dialog); for (int a = 0; a < selectedDialogFilter.length; a++) { @@ -14591,6 +14703,8 @@ public class MessagesController extends BaseController implements NotificationCe public void sortDialogs(LongSparseArray chatsDict) { dialogsServerOnly.clear(); dialogsCanAddUsers.clear(); + dialogsMyGroups.clear(); + dialogsMyChannels.clear(); dialogsChannelsOnly.clear(); dialogsGroupsOnly.clear(); for (int a = 0; a < selectedDialogFilter.length; a++) { @@ -14657,8 +14771,16 @@ public class MessagesController extends BaseController implements NotificationCe dialogsServerOnly.add(d); if (DialogObject.isChannel(d)) { TLRPC.Chat chat = getChat(-d.id); - if (chat != null && chat.megagroup && (chat.admin_rights != null && (chat.admin_rights.post_messages || chat.admin_rights.add_admins) || chat.creator)) { - dialogsCanAddUsers.add(d); + if (chat != null && (chat.creator || chat.megagroup && (chat.admin_rights != null && (chat.admin_rights.post_messages || chat.admin_rights.add_admins) || chat.default_banned_rights == null || !chat.default_banned_rights.invite_users) || !chat.megagroup && chat.admin_rights != null && chat.admin_rights.add_admins)) { + if (chat.creator || chat.megagroup && chat.admin_rights != null || !chat.megagroup && chat.admin_rights != null) { + if (chat.megagroup) { + dialogsMyGroups.add(d); + } else { + dialogsMyChannels.add(d); + } + } else { + dialogsCanAddUsers.add(d); + } } if (chat != null && chat.megagroup) { dialogsGroupsOnly.add(d); @@ -14677,7 +14799,14 @@ public class MessagesController extends BaseController implements NotificationCe continue; } } - dialogsCanAddUsers.add(d); + TLRPC.Chat chat = getChat(-d.id); + if (chat != null && (chat.admin_rights != null && (chat.admin_rights.add_admins || chat.admin_rights.invite_users) || chat.creator)) { + if (chat.creator) { + dialogsMyGroups.add(d); + } else { + dialogsCanAddUsers.add(d); + } + } dialogsGroupsOnly.add(d); } else if (d.id != selfId) { dialogsUsersOnly.add(d); @@ -15008,9 +15137,9 @@ public class MessagesController extends BaseController implements NotificationCe int lastMessageId = (int) args[4]; if ((size < count / 2 && !isEnd) && isCache) { if (finalMessageId != 0) { - loadMessagesInternal(dialogId, 0, false, count, finalMessageId, 0, false, 0, classGuid, 3, lastMessageId, 0, 0, 0, 0, 0, 0, false, 0, true, false); + loadMessagesInternal(dialogId, 0, false, count, finalMessageId, 0, false, 0, classGuid, 3, lastMessageId, 0, 0, -1, 0, 0, 0, false, 0, true, false); } else { - loadMessagesInternal(dialogId, 0, false, count, finalMessageId, 0, false, 0, classGuid, 2, lastMessageId, 0, 0, 0, 0, 0, 0, false, 0, true, false); + loadMessagesInternal(dialogId, 0, false, count, finalMessageId, 0, false, 0, classGuid, 2, lastMessageId, 0, 0, -1, 0, 0, 0, false, 0, true, false); } } else { getNotificationCenter().removeObserver(this, NotificationCenter.messagesDidLoadWithoutProcess); @@ -15034,9 +15163,9 @@ public class MessagesController extends BaseController implements NotificationCe getNotificationCenter().addObserver(delegate, NotificationCenter.loadingMessagesFailed); if (messageId != 0) { - loadMessagesInternal(dialogId, 0, true, count, finalMessageId, 0, true, 0, classGuid, 3, 0, 0, 0, 0, 0, 0, 0, false, 0, true, false); + loadMessagesInternal(dialogId, 0, true, count, finalMessageId, 0, true, 0, classGuid, 3, 0, 0, 0, -1, 0, 0, 0, false, 0, true, false); } else { - loadMessagesInternal(dialogId, 0, true, count, finalMessageId, 0, true, 0, classGuid, 2, 0, 0, 0, 0, 0, 0, 0, false, 0, true, false); + loadMessagesInternal(dialogId, 0, true, count, finalMessageId, 0, true, 0, classGuid, 2, 0, 0, 0, -1, 0, 0, 0, false, 0, true, false); } } @@ -15106,6 +15235,111 @@ public class MessagesController extends BaseController implements NotificationCe }); } + public void checkIsInChat(TLRPC.Chat chat, TLRPC.User user, IsInChatCheckedCallback callback) { + if (chat == null || user == null) { + if (callback != null) { + callback.run(false, null, null); + } + return; + } + if (chat.megagroup || ChatObject.isChannel(chat)) { + TLRPC.TL_channels_getParticipant req = new TLRPC.TL_channels_getParticipant(); + req.channel = getInputChannel(chat.id); + req.participant = getInputPeer(user); + getConnectionsManager().sendRequest(req, (res, err) -> { + if (callback != null) { + TLRPC.ChannelParticipant participant = res instanceof TLRPC.TL_channels_channelParticipant ? ((TLRPC.TL_channels_channelParticipant) res).participant : null; + callback.run( + err == null && participant != null && !participant.left, + participant != null ? participant.admin_rights : null, + participant != null ? participant.rank : null + ); + } + }); + } else { + TLRPC.ChatFull chatFull = getChatFull(chat.id); + if (chatFull != null) { + TLRPC.ChatParticipant userParticipant = null; + if (chatFull.participants != null && chatFull.participants.participants != null) { + final int count = chatFull.participants.participants.size(); + for (int i = 0; i < count; ++i) { + TLRPC.ChatParticipant participant = chatFull.participants.participants.get(i); + if (participant != null && participant.user_id == user.id) { + userParticipant = participant; + break; + } + } + } + if (callback != null) { + callback.run( + userParticipant != null, + chatFull.participants != null && chatFull.participants.admin_id == user.id ? ChatRightsEditActivity.emptyAdminRights(true) : null, + null + ); + } + } else { + if (callback != null) { + callback.run(false, null, null); + } + } + } + } + + private void applySoundSettings(TLRPC.NotificationSound settings, SharedPreferences.Editor editor, long dialogId, int globalType, boolean serverUpdate) { + if (settings == null) { + return; + } + String soundPref; + String soundPathPref; + String soundDocPref; + if (dialogId != 0) { + soundPref = "sound_" + dialogId; + soundPathPref = "sound_path_" + dialogId; + soundDocPref = "sound_document_id_" + dialogId; + } else { + if (globalType == NotificationsController.TYPE_GROUP) { + soundPref = "GroupSound"; + soundDocPref = "GroupSoundDocId"; + soundPathPref = "GroupSoundPath"; + } else if (globalType == TYPE_PRIVATE) { + soundPref = "GlobalSound"; + soundDocPref = "GlobalSoundDocId"; + soundPathPref = "GlobalSoundPath"; + } else { + soundPref = "ChannelSound"; + soundDocPref = "ChannelSoundDocId"; + soundPathPref = "ChannelSoundPath"; + } + } + + if (settings instanceof TLRPC.TL_notificationSoundDefault) { + editor.putString(soundPref, "Default"); + editor.putString(soundPathPref, "Default"); + editor.remove(soundDocPref); + } else if (settings instanceof TLRPC.TL_notificationSoundNone) { + editor.putString(soundPref, "NoSound"); + editor.putString(soundPathPref, "NoSound"); + editor.remove(soundDocPref); + } else if (settings instanceof TLRPC.TL_notificationSoundLocal) { + TLRPC.TL_notificationSoundLocal localSound = (TLRPC.TL_notificationSoundLocal) settings; + editor.putString(soundPref, localSound.title); + editor.putString(soundPathPref, localSound.data); + editor.remove(soundDocPref); + } else if (settings instanceof TLRPC.TL_notificationSoundRingtone) { + TLRPC.TL_notificationSoundRingtone soundRingtone = (TLRPC.TL_notificationSoundRingtone) settings; + editor.putLong(soundDocPref, soundRingtone.id); + getMediaDataController().checkRingtones(); + if (serverUpdate && dialogId != 0) { + editor.putBoolean("custom_" + dialogId, true); + } + getMediaDataController().ringtoneDataStore.getDocument(soundRingtone.id); + } + } + + public interface IsInChatCheckedCallback { + void run(boolean isInChat, TLRPC.TL_chatAdminRights currentAdminRights, String rank); + } + public interface MessagesLoadedCallback { void onMessagesLoaded(boolean fromCache); diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/MessagesStorage.java b/TMessagesProj/src/main/java/org/telegram/messenger/MessagesStorage.java index f7d87e04d..8ce3b2678 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/MessagesStorage.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/MessagesStorage.java @@ -82,7 +82,7 @@ public class MessagesStorage extends BaseController { private CountDownLatch openSync = new CountDownLatch(1); private static volatile MessagesStorage[] Instance = new MessagesStorage[UserConfig.MAX_ACCOUNT_COUNT]; - private final static int LAST_DB_VERSION = 92; + private final static int LAST_DB_VERSION = 93; private boolean databaseMigrationInProgress; public boolean showClearDatabaseAlert; @@ -394,6 +394,8 @@ public class MessagesStorage extends BaseController { database.executeFast("CREATE INDEX IF NOT EXISTS reaction_mentions_did ON reaction_mentions(dialog_id);").stepThis().dispose(); database.executeFast("CREATE TABLE downloading_documents(data BLOB, hash INTEGER, id INTEGER, state INTEGER, date INTEGER, PRIMARY KEY(hash, id));").stepThis().dispose(); + + database.executeFast("CREATE TABLE attach_menu_bots(data BLOB, hash INTEGER, date INTEGER);").stepThis().dispose(); //version database.executeFast("PRAGMA user_version = " + LAST_DB_VERSION).stepThis().dispose(); } else { @@ -1560,6 +1562,11 @@ public class MessagesStorage extends BaseController { version = 92; } + if (version == 92) { + database.executeFast("CREATE TABLE IF NOT EXISTS attach_menu_bots(data BLOB, hash INTEGER, date INTEGER);").stepThis().dispose(); + database.executeFast("PRAGMA user_version = 93").stepThis().dispose(); + } + FileLog.d("MessagesStorage db migration finished"); AndroidUtilities.runOnUIThread(() -> { databaseMigrationInProgress = false; @@ -2081,6 +2088,7 @@ public class MessagesStorage extends BaseController { database.executeFast("DELETE FROM reaction_mentions").stepThis().dispose(); database.executeFast("DELETE FROM downloading_documents").stepThis().dispose(); + database.executeFast("DELETE FROM attach_menu_bots").stepThis().dispose(); SQLiteCursor cursor = database.queryFinalized("SELECT did FROM dialogs WHERE 1"); StringBuilder ids = new StringBuilder(); @@ -2156,6 +2164,7 @@ public class MessagesStorage extends BaseController { } finally { AndroidUtilities.runOnUIThread(() -> { NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.didClearDatabase); + getMediaDataController().loadAttachMenuBots(false, true); }); } }); @@ -3354,7 +3363,7 @@ public class MessagesStorage extends BaseController { arrayList.add(message); } - protected void loadReplyMessages(LongSparseArray>> replyMessageOwners, LongSparseArray> dialogReplyMessagesIds, ArrayList usersToLoad, ArrayList chatsToLoad) throws SQLiteException { + protected void loadReplyMessages(LongSparseArray>> replyMessageOwners, LongSparseArray> dialogReplyMessagesIds, ArrayList usersToLoad, ArrayList chatsToLoad, boolean scheduled) throws SQLiteException { if (replyMessageOwners.isEmpty()) { return; } @@ -3366,7 +3375,12 @@ public class MessagesStorage extends BaseController { if (ids == null) { continue; } - SQLiteCursor cursor = database.queryFinalized(String.format(Locale.US, "SELECT data, mid, date, uid FROM messages_v2 WHERE mid IN(%s) AND uid = %d", TextUtils.join(",", ids), dialogId)); + SQLiteCursor cursor; + if (scheduled) { + cursor = database.queryFinalized(String.format(Locale.US, "SELECT data, mid, date, uid FROM scheduled_messages_v2 WHERE mid IN(%s) AND uid = %d", TextUtils.join(",", ids), dialogId)); + } else { + cursor = database.queryFinalized(String.format(Locale.US, "SELECT data, mid, date, uid FROM messages_v2 WHERE mid IN(%s) AND uid = %d", TextUtils.join(",", ids), dialogId)); + } while (cursor.next()) { NativeByteBuffer data = cursor.byteBufferValue(0); if (data != null) { @@ -3533,7 +3547,7 @@ public class MessagesStorage extends BaseController { } cursor.dispose(); - loadReplyMessages(replyMessageOwners, dialogReplyMessagesIds, usersToLoad, chatsToLoad); + loadReplyMessages(replyMessageOwners, dialogReplyMessagesIds, usersToLoad, chatsToLoad, false); if (!encryptedChatIds.isEmpty()) { getEncryptedChatsInternal(TextUtils.join(",", encryptedChatIds), encryptedChats, usersToLoad); @@ -7446,7 +7460,7 @@ public class MessagesStorage extends BaseController { } } } else { - loadReplyMessages(replyMessageOwners, dialogReplyMessagesIds, usersToLoad, chatsToLoad); + loadReplyMessages(replyMessageOwners, dialogReplyMessagesIds, usersToLoad, chatsToLoad, scheduled); } if (!usersToLoad.isEmpty()) { getUsersInternal(TextUtils.join(",", usersToLoad), res.users); @@ -11540,7 +11554,7 @@ public class MessagesStorage extends BaseController { cursor.dispose(); } - loadReplyMessages(replyMessageOwners, dialogReplyMessagesIds, usersToLoad, chatsToLoad); + loadReplyMessages(replyMessageOwners, dialogReplyMessagesIds, usersToLoad, chatsToLoad, false); if (draftsDialogIds != null) { ArrayList unloadedDialogs = new ArrayList<>(); diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/NotificationCenter.java b/TMessagesProj/src/main/java/org/telegram/messenger/NotificationCenter.java index aa32d6975..1f094179c 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/NotificationCenter.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/NotificationCenter.java @@ -123,6 +123,7 @@ public class NotificationCenter { public static final int stickersImportProgressChanged = totalEvents++; public static final int stickersImportComplete = totalEvents++; public static final int dialogDeleted = totalEvents++; + public static final int webViewResultSent = totalEvents++; public static final int didGenerateFingerprintKeyPair = totalEvents++; @@ -233,10 +234,14 @@ public class NotificationCenter { public static final int onEmojiInteractionsReceived = totalEvents++; public static final int emojiPreviewThemesChanged = totalEvents++; public static final int reactionsDidLoad = totalEvents++; + public static final int attachMenuBotsDidLoad = totalEvents++; public static final int chatAvailableReactionsUpdated = totalEvents++; public static final int dialogsUnreadReactionsCounterChanged = totalEvents++; public static final int onDatabaseOpened = totalEvents++; public static final int onDownloadingFilesChanged = totalEvents++; + public static final int onActivityResultReceived = totalEvents++; + public static final int onRequestPermissionResultReceived = totalEvents++; + public static final int onUserRingtonesUpdated = totalEvents++; private SparseArray> observers = new SparseArray<>(); private SparseArray> removeAfterBroadcast = new SparseArray<>(); diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/NotificationsController.java b/TMessagesProj/src/main/java/org/telegram/messenger/NotificationsController.java index ad8238939..2a9e77d4b 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/NotificationsController.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/NotificationsController.java @@ -42,6 +42,10 @@ import android.os.Build; import android.os.PowerManager; import android.os.SystemClock; import android.provider.Settings; +import android.text.TextUtils; +import android.util.Log; +import android.util.SparseArray; +import android.util.SparseBooleanArray; import androidx.collection.LongSparseArray; import androidx.core.app.NotificationCompat; @@ -53,9 +57,6 @@ import androidx.core.content.LocusIdCompat; import androidx.core.content.pm.ShortcutInfoCompat; import androidx.core.content.pm.ShortcutManagerCompat; import androidx.core.graphics.drawable.IconCompat; -import android.text.TextUtils; -import android.util.SparseArray; -import android.util.SparseBooleanArray; import org.telegram.messenger.support.LongSparseIntArray; import org.telegram.tgnet.ConnectionsManager; @@ -131,6 +132,9 @@ public class NotificationsController extends BaseController { private int notificationId; private String notificationGroup; + public static final int SETTING_SOUND_ON = 0; + public static final int SETTING_SOUND_OFF = 1; + static { if (Build.VERSION.SDK_INT >= 26 && ApplicationLoader.applicationContext != null) { notificationManager = NotificationManagerCompat.from(ApplicationLoader.applicationContext); @@ -240,6 +244,40 @@ public class NotificationsController extends BaseController { } } + public void muteUntil(long did, int selectedTimeInSeconds) { + if (did != 0) { + SharedPreferences preferences = MessagesController.getNotificationsSettings(currentAccount); + SharedPreferences.Editor editor = preferences.edit(); + long flags; + boolean defaultEnabled = NotificationsController.getInstance(currentAccount).isGlobalNotificationsEnabled(did); + + if (selectedTimeInSeconds == Integer.MAX_VALUE) { + if (!defaultEnabled) { + editor.remove("notify2_" + did); + flags = 0; + } else { + editor.putInt("notify2_" + did, 2); + flags = 1; + } + } else { + editor.putInt("notify2_" + did, 3); + editor.putInt("notifyuntil_" + did, getConnectionsManager().getCurrentTime() + selectedTimeInSeconds); + flags = ((long) selectedTimeInSeconds << 32) | 1; + } + NotificationsController.getInstance(currentAccount).removeNotificationsForDialog(did); + MessagesStorage.getInstance(currentAccount).setDialogFlags(did, flags); + editor.commit(); + TLRPC.Dialog dialog = MessagesController.getInstance(currentAccount).dialogs_dict.get(did); + if (dialog != null) { + dialog.notify_settings = new TLRPC.TL_peerNotifySettings(); + if (selectedTimeInSeconds != Integer.MAX_VALUE || defaultEnabled) { + dialog.notify_settings.mute_until = selectedTimeInSeconds; + } + } + NotificationsController.getInstance(currentAccount).updateServerNotificationsSettings(did); + } + } + public void cleanup() { popupMessages.clear(); popupReplyMessages.clear(); @@ -3062,6 +3100,10 @@ public class NotificationsController extends BaseController { boolean secretChat = !isDefault && DialogObject.isEncryptedDialog(dialogId); boolean shouldOverwrite = !isInApp && overwriteKey != null && preferences.getBoolean(overwriteKey, false); + String soundHash = Utilities.MD5(sound == null ? "NoSound" : sound.toString()); + if (soundHash != null && soundHash.length() > 5) { + soundHash = soundHash.substring(0, 5); + } if (isSilent) { name = LocaleController.getString("NotificationsSilent", R.string.NotificationsSilent); key = "silent"; @@ -3080,6 +3122,7 @@ public class NotificationsController extends BaseController { } key = (isInApp ? "org.telegram.keyia" : "org.telegram.key") + dialogId; } + key += "_" + soundHash; String channelId = preferences.getString(key, null); String settings = preferences.getString(key + "_s", null); boolean edited = false; @@ -3163,66 +3206,6 @@ public class NotificationsController extends BaseController { } edited = true; } - if (channelSound == null && sound != null || channelSound != null && (sound == null || !TextUtils.equals(channelSound.toString(), sound.toString()))) { - if (!isInApp) { - if (editor == null) { - editor = preferences.edit(); - } - String newSound; - if (channelSound == null) { - newSound = "NoSound"; - if (isDefault) { - if (type == TYPE_CHANNEL) { - editor.putString("ChannelSound", "NoSound"); - } else if (type == TYPE_GROUP) { - editor.putString("GroupSound", "NoSound"); - } else { - editor.putString("GlobalSound", "NoSound"); - } - } else { - editor.putString("sound_" + dialogId, "NoSound"); - } - } else { - newSound = channelSound.toString(); - Ringtone rng = RingtoneManager.getRingtone(ApplicationLoader.applicationContext, channelSound); - String ringtoneName = null; - if (rng != null) { - if (channelSound.equals(Settings.System.DEFAULT_RINGTONE_URI)) { - ringtoneName = LocaleController.getString("DefaultRingtone", R.string.DefaultRingtone); - } else { - ringtoneName = rng.getTitle(ApplicationLoader.applicationContext); - } - rng.stop(); - } - if (ringtoneName != null) { - if (isDefault) { - if (type == TYPE_CHANNEL) { - editor.putString("ChannelSound", ringtoneName); - } else if (type == TYPE_GROUP) { - editor.putString("GroupSound", ringtoneName); - } else { - editor.putString("GlobalSound", ringtoneName); - } - } else { - editor.putString("sound_" + dialogId, ringtoneName); - } - } - } - if (isDefault) { - if (type == TYPE_CHANNEL) { - editor.putString("ChannelSoundPath", newSound); - } else if (type == TYPE_GROUP) { - editor.putString("GroupSoundPath", newSound); - } else { - editor.putString("GlobalSoundPath", newSound); - } - } else { - editor.putString("sound_path_" + dialogId, newSound); - } - } - sound = channelSound; - edited = true; - } boolean hasVibration = !isEmptyVibration(vibrationPattern); if (hasVibration != vibrate) { if (!isInApp) { @@ -3334,7 +3317,7 @@ public class NotificationsController extends BaseController { if (sound != null) { notificationChannel.setSound(sound, builder.build()); } else { - notificationChannel.setSound(null, builder.build()); + notificationChannel.setSound(null, null); } if (BuildVars.LOGS_ENABLED) { FileLog.d("create new channel " + channelId); @@ -3390,6 +3373,7 @@ public class NotificationsController extends BaseController { boolean notifyDisabled = false; int vibrate = 0; String soundPath = null; + boolean isInternalSoundFile = false; int ledColor = 0xff0000ff; int importance = 0; @@ -3541,6 +3525,10 @@ public class NotificationsController extends BaseController { } } + if (!notifyDisabled && !preferences.getBoolean("sound_enabled_" + dialog_id, true)) { + notifyDisabled = true; + } + String defaultPath = Settings.System.DEFAULT_NOTIFICATION_URI.getPath(); boolean isDefault = true; @@ -3548,13 +3536,20 @@ public class NotificationsController extends BaseController { int chatType = TYPE_PRIVATE; String customSoundPath; + boolean customIsInternalSound = false; int customVibrate; int customImportance; Integer customLedColor; if (preferences.getBoolean("custom_" + dialog_id, false)) { customVibrate = preferences.getInt("vibrate_" + dialog_id, 0); customImportance = preferences.getInt("priority_" + dialog_id, 3); - customSoundPath = preferences.getString("sound_path_" + dialog_id, null); + long soundDocumentId = preferences.getLong("sound_document_id_" + dialog_id, 0); + if (soundDocumentId != 0) { + customIsInternalSound = true; + customSoundPath = getMediaDataController().ringtoneDataStore.getSoundPath(soundDocumentId); + } else { + customSoundPath = preferences.getString("sound_path_" + dialog_id, null); + } if (preferences.contains("color_" + dialog_id)) { customLedColor = preferences.getInt("color_" + dialog_id, 0); } else { @@ -3570,20 +3565,38 @@ public class NotificationsController extends BaseController { if (chatId != 0) { if (isChannel) { - soundPath = preferences.getString("ChannelSoundPath", defaultPath); + long soundDocumentId = preferences.getLong("ChannelSoundDocId", 0); + if (soundDocumentId != 0) { + isInternalSoundFile = true; + soundPath = getMediaDataController().ringtoneDataStore.getSoundPath(soundDocumentId); + } else { + soundPath = preferences.getString("ChannelSoundPath", defaultPath); + } vibrate = preferences.getInt("vibrate_channel", 0); importance = preferences.getInt("priority_channel", 1); ledColor = preferences.getInt("ChannelLed", 0xff0000ff); chatType = TYPE_CHANNEL; } else { - soundPath = preferences.getString("GroupSoundPath", defaultPath); + long soundDocumentId = preferences.getLong("GroupSoundDocId", 0); + if (soundDocumentId != 0) { + isInternalSoundFile = true; + soundPath = getMediaDataController().ringtoneDataStore.getSoundPath(soundDocumentId); + } else { + soundPath = preferences.getString("GroupSoundPath", defaultPath); + } vibrate = preferences.getInt("vibrate_group", 0); importance = preferences.getInt("priority_group", 1); ledColor = preferences.getInt("GroupLed", 0xff0000ff); chatType = TYPE_GROUP; } } else if (userId != 0) { - soundPath = preferences.getString("GlobalSoundPath", defaultPath); + long soundDocumentId = preferences.getLong("GlobalSoundDocId", 0); + if (soundDocumentId != 0) { + isInternalSoundFile = true; + soundPath = getMediaDataController().ringtoneDataStore.getSoundPath(soundDocumentId); + } else { + soundPath = preferences.getString("GlobalSoundPath", defaultPath); + } vibrate = preferences.getInt("vibrate_messages", 0); importance = preferences.getInt("priority_messages", 1); ledColor = preferences.getInt("MessagesLed", 0xff0000ff); @@ -3593,7 +3606,8 @@ public class NotificationsController extends BaseController { vibrateOnlyIfSilent = true; vibrate = 0; } - if (customSoundPath != null && !TextUtils.equals(soundPath, customSoundPath)) { + if (!TextUtils.isEmpty(customSoundPath) && !TextUtils.equals(soundPath, customSoundPath)) { + isInternalSoundFile = customIsInternalSound; soundPath = customSoundPath; isDefault = false; } @@ -3760,10 +3774,15 @@ public class NotificationsController extends BaseController { } if (soundPath != null && !soundPath.equals("NoSound")) { if (Build.VERSION.SDK_INT >= 26) { - if (soundPath.equals(defaultPath)) { + if (soundPath.equals("Default") || soundPath.equals(defaultPath)) { sound = Settings.System.DEFAULT_NOTIFICATION_URI; } else { - sound = Uri.parse(soundPath); + if (isInternalSoundFile) { + sound = FileProvider.getUriForFile(ApplicationLoader.applicationContext, BuildConfig.APPLICATION_ID + ".provider", new File(soundPath)); + ApplicationLoader.applicationContext.grantUriPermission("com.android.systemui", sound, Intent.FLAG_GRANT_READ_URI_PERMISSION); + } else { + sound = Uri.parse(soundPath); + } } } else { if (soundPath.equals(defaultPath)) { @@ -3920,7 +3939,6 @@ public class NotificationsController extends BaseController { arrayList.add(messageObject); } - LongSparseArray oldIdsWear = new LongSparseArray<>(); for (int i = 0; i < wearNotificationsIds.size(); i++) { oldIdsWear.put(wearNotificationsIds.keyAt(i), wearNotificationsIds.valueAt(i)); @@ -4586,6 +4604,7 @@ public class NotificationsController extends BaseController { public static final int SETTING_MUTE_2_DAYS = 2; public static final int SETTING_MUTE_FOREVER = 3; public static final int SETTING_MUTE_UNMUTE = 4; + public static final int SETTING_MUTE_CUSTOM = 5; public void clearDialogNotificationsSettings(long did) { SharedPreferences preferences = getAccountInstance().getNotificationsSettings(); @@ -4677,7 +4696,28 @@ public class NotificationsController extends BaseController { } } + long soundDocumentId = preferences.getLong("sound_document_id_" + dialogId, 0); + String soundPath = preferences.getString("sound_path_" + dialogId, null); + req.settings.flags |= 8; + if (soundDocumentId != 0) { + TLRPC.TL_notificationSoundRingtone ringtoneSound = new TLRPC.TL_notificationSoundRingtone(); + ringtoneSound.id = soundDocumentId; + req.settings.sound = ringtoneSound; + } else if (soundPath != null) { + if (soundPath.equals("NoSound")){ + req.settings.sound = new TLRPC.TL_notificationSoundNone(); + } else { + TLRPC.TL_notificationSoundLocal localSound = new TLRPC.TL_notificationSoundLocal(); + localSound.title = preferences.getString("sound_" + dialogId, null); + localSound.data = soundPath; + req.settings.sound = localSound; + } + } else { + req.settings.sound = new TLRPC.TL_notificationSoundDefault(); + } + req.peer = new TLRPC.TL_inputNotifyPeer(); + ((TLRPC.TL_inputNotifyPeer) req.peer).peer = getMessagesController().getInputPeer(dialogId); getConnectionsManager().sendRequest(req, (response, error) -> { @@ -4693,18 +4733,51 @@ public class NotificationsController extends BaseController { TLRPC.TL_account_updateNotifySettings req = new TLRPC.TL_account_updateNotifySettings(); req.settings = new TLRPC.TL_inputPeerNotifySettings(); req.settings.flags = 5; + String soundDocumentIdPref; + String soundPathPref; + String soundNamePref; if (type == TYPE_GROUP) { req.peer = new TLRPC.TL_inputNotifyChats(); req.settings.mute_until = preferences.getInt("EnableGroup2", 0); req.settings.show_previews = preferences.getBoolean("EnablePreviewGroup", true); + soundNamePref = "GroupSound"; + soundDocumentIdPref = "GroupSoundDocId"; + soundPathPref = "GroupSoundPath"; } else if (type == TYPE_PRIVATE) { req.peer = new TLRPC.TL_inputNotifyUsers(); req.settings.mute_until = preferences.getInt("EnableAll2", 0); req.settings.show_previews = preferences.getBoolean("EnablePreviewAll", true); + soundNamePref = "GlobalSound"; + soundDocumentIdPref = "GlobalSoundDocId"; + soundPathPref = "GlobalSoundPath"; } else { req.peer = new TLRPC.TL_inputNotifyBroadcasts(); req.settings.mute_until = preferences.getInt("EnableChannel2", 0); req.settings.show_previews = preferences.getBoolean("EnablePreviewChannel", true); + soundNamePref = "ChannelSound"; + soundDocumentIdPref = "ChannelSoundDocId"; + soundPathPref = "ChannelSoundPath"; + } + + req.settings.flags |= 8; + long soundDocumentId = preferences.getLong(soundDocumentIdPref, 0); + String soundPath = preferences.getString(soundPathPref, "NoSound"); + + if (soundDocumentId != 0) { + TLRPC.TL_notificationSoundRingtone ringtoneSound = new TLRPC.TL_notificationSoundRingtone(); + ringtoneSound.id = soundDocumentId; + req.settings.sound = ringtoneSound; + } else if (soundPath != null) { + if (soundPath.equals("NoSound")){ + req.settings.sound = new TLRPC.TL_notificationSoundNone(); + } else { + TLRPC.TL_notificationSoundLocal localSound = new TLRPC.TL_notificationSoundLocal(); + localSound.title = preferences.getString(soundNamePref, null); + localSound.data = soundPath; + req.settings.sound = localSound; + } + } else { + req.settings.sound = new TLRPC.TL_notificationSoundDefault(); } getConnectionsManager().sendRequest(req, (response, error) -> { @@ -4758,4 +4831,26 @@ public class NotificationsController extends BaseController { return "EnableChannel2"; } } + + public void muteDialog(long dialog_id, boolean mute) { + if (mute) { + NotificationsController.getInstance(currentAccount).muteUntil(dialog_id, Integer.MAX_VALUE); + } else { + boolean defaultEnabled = NotificationsController.getInstance(currentAccount).isGlobalNotificationsEnabled(dialog_id); + SharedPreferences preferences = MessagesController.getNotificationsSettings(currentAccount); + SharedPreferences.Editor editor = preferences.edit(); + if (defaultEnabled) { + editor.remove("notify2_" + dialog_id); + } else { + editor.putInt("notify2_" + dialog_id, 0); + } + getMessagesStorage().setDialogFlags(dialog_id, 0); + editor.apply(); + TLRPC.Dialog dialog = getMessagesController().dialogs_dict.get(dialog_id); + if (dialog != null) { + dialog.notify_settings = new TLRPC.TL_peerNotifySettings(); + } + updateServerNotificationsSettings(dialog_id); + } + } } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/OneUIUtilities.java b/TMessagesProj/src/main/java/org/telegram/messenger/OneUIUtilities.java index 1f83a748d..1afbc7646 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/OneUIUtilities.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/OneUIUtilities.java @@ -2,8 +2,15 @@ package org.telegram.messenger; import android.os.Build; +import java.lang.reflect.Field; + public class OneUIUtilities { + public final static int ONE_UI_4_0 = 40000; + private static Boolean isOneUI; + private static int oneUIEncodedVersion; + private static int oneUIMajorVersion; + private static float oneUIMinorVersion; @SuppressWarnings("JavaReflectionMemberAccess") public static boolean isOneUI() { @@ -12,11 +19,46 @@ public class OneUIUtilities { } try { - Build.VERSION.class.getDeclaredField("SEM_PLATFORM_INT"); + Field f = Build.VERSION.class.getDeclaredField("SEM_PLATFORM_INT"); + f.setAccessible(true); + int semPlatformInt = (int) f.get(null); + if (semPlatformInt < 100000) { + // Samsung Experience then + return false; + } + + oneUIEncodedVersion = semPlatformInt - 90000; + oneUIMajorVersion = oneUIEncodedVersion / 10000; + oneUIMinorVersion = (oneUIEncodedVersion % 10000) / 100F; isOneUI = true; - } catch (NoSuchFieldException e) { + } catch (Exception e) { isOneUI = false; } return isOneUI; } + + public static boolean hasBuiltInClipboardToasts() { + return isOneUI() && getOneUIEncodedVersion() == ONE_UI_4_0; + } + + public static int getOneUIMajorVersion() { + if (!isOneUI()) { + return 0; + } + return oneUIMajorVersion; + } + + public static int getOneUIEncodedVersion() { + if (!isOneUI()) { + return 0; + } + return oneUIEncodedVersion; + } + + public static float getOneUIMinorVersion() { + if (!isOneUI()) { + return 0; + } + return oneUIMinorVersion; + } } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/SendMessagesHelper.java b/TMessagesProj/src/main/java/org/telegram/messenger/SendMessagesHelper.java index bdced2950..2baedb789 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/SendMessagesHelper.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/SendMessagesHelper.java @@ -1934,6 +1934,16 @@ public class SendMessagesHelper extends BaseController implements NotificationCe objArr.add(newMsgObj); arr.add(newMsg); + if (msgObj.replyMessageObject != null) { + for (int i = 0; i < messages.size(); i++) { + if (messages.get(i).getId() == msgObj.replyMessageObject.getId()) { + newMsgObj.messageOwner.replyMessage = msgObj.replyMessageObject.messageOwner; + newMsgObj.replyMessageObject = msgObj.replyMessageObject; + break; + } + } + } + putToSendingMessages(newMsg, scheduleDate != 0); boolean differentDialog = false; @@ -2746,6 +2756,27 @@ public class SendMessagesHelper extends BaseController implements NotificationCe passwordFragment.needHideProgress(); passwordFragment.finishFragment(); } + + long uid = messageObject.getFromChatId(); + if (messageObject.messageOwner.via_bot_id != 0) { + uid = messageObject.messageOwner.via_bot_id; + } + String name = null; + if (uid > 0) { + TLRPC.User user = getMessagesController().getUser(uid); + if (user != null) { + name = ContactsController.formatName(user.first_name, user.last_name); + } + } else { + TLRPC.Chat chat = getMessagesController().getChat(-uid); + if (chat != null) { + name = chat.title; + } + } + if (name == null) { + name = "bot"; + } + if (button instanceof TLRPC.TL_keyboardButtonUrlAuth) { if (response instanceof TLRPC.TL_urlAuthResultRequest) { TLRPC.TL_urlAuthResultRequest res = (TLRPC.TL_urlAuthResultRequest) response; @@ -2770,26 +2801,8 @@ public class SendMessagesHelper extends BaseController implements NotificationCe if (!cacheFinal && res.cache_time != 0 && !button.requires_password) { getMessagesStorage().saveBotCache(key, res); } + if (res.message != null) { - long uid = messageObject.getFromChatId(); - if (messageObject.messageOwner.via_bot_id != 0) { - uid = messageObject.messageOwner.via_bot_id; - } - String name = null; - if (uid > 0) { - TLRPC.User user = getMessagesController().getUser(uid); - if (user != null) { - name = ContactsController.formatName(user.first_name, user.last_name); - } - } else { - TLRPC.Chat chat = getMessagesController().getChat(-uid); - if (chat != null) { - name = chat.title; - } - } - if (name == null) { - name = "bot"; - } if (res.alert) { if (parentFragment.getParentActivity() == null) { return; @@ -2806,10 +2819,6 @@ public class SendMessagesHelper extends BaseController implements NotificationCe if (parentFragment.getParentActivity() == null) { return; } - long uid = messageObject.getFromChatId(); - if (messageObject.messageOwner.via_bot_id != 0) { - uid = messageObject.messageOwner.via_bot_id; - } TLRPC.User user = getMessagesController().getUser(uid); boolean verified = user != null && user.verified; if (button instanceof TLRPC.TL_keyboardButtonGame) { @@ -7868,7 +7877,7 @@ public class SendMessagesHelper extends BaseController implements NotificationCe selectedCompression = compressionsCount; } boolean needCompress = false; - if (selectedCompression != compressionsCount - 1 || Math.max(videoEditedInfo.originalWidth, videoEditedInfo.originalHeight) > 1280) { + if (selectedCompression != compressionsCount || Math.max(videoEditedInfo.originalWidth, videoEditedInfo.originalHeight) > 1280) { needCompress = true; switch (selectedCompression) { case 1: diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/SharedConfig.java b/TMessagesProj/src/main/java/org/telegram/messenger/SharedConfig.java index e7462b352..39f0cca36 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/SharedConfig.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/SharedConfig.java @@ -806,7 +806,10 @@ public class SharedConfig { SharedPreferences.Editor editor = preferences.edit(); editor.putBoolean("save_gallery", saveToGallery); editor.commit(); - checkSaveToGalleryFiles(); + ImageLoader.getInstance().checkMediaPaths(); + ImageLoader.getInstance().getCacheOutQueue().postRunnable(() -> { + checkSaveToGalleryFiles(); + }); } public static void toggleAutoplayGifs() { diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/SharedPrefsHelper.java b/TMessagesProj/src/main/java/org/telegram/messenger/SharedPrefsHelper.java new file mode 100644 index 000000000..33e7f44bb --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/SharedPrefsHelper.java @@ -0,0 +1,36 @@ +package org.telegram.messenger; + +import android.content.Context; +import android.content.SharedPreferences; + +public class SharedPrefsHelper { + private static String WEB_VIEW_SHOWN_DIALOG_FORMAT = "confirm_shown_%d_%d"; + + private static SharedPreferences webViewBotsPrefs; + + public static void init(Context ctx) { + webViewBotsPrefs = ctx.getSharedPreferences("webview_bots", Context.MODE_PRIVATE); + } + + public static boolean isWebViewConfirmShown(int currentAccount, long botId) { + return webViewBotsPrefs.getBoolean(String.format(WEB_VIEW_SHOWN_DIALOG_FORMAT, currentAccount, botId), false); + } + + public static void setWebViewConfirmShown(int currentAccount, long botId, boolean shown) { + webViewBotsPrefs.edit().putBoolean(String.format(WEB_VIEW_SHOWN_DIALOG_FORMAT, currentAccount, botId), shown).apply(); + } + + public static void cleanupAccount(int account) { + SharedPreferences.Editor editor = webViewBotsPrefs.edit(); + for (String key : webViewBotsPrefs.getAll().keySet()) { + if (key.startsWith("confirm_shown_" + account + "_")) { + editor.remove(key); + } + } + editor.apply(); + } + + public static SharedPreferences getWebViewBotsPrefs() { + return webViewBotsPrefs; + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/Utilities.java b/TMessagesProj/src/main/java/org/telegram/messenger/Utilities.java index 9470e1a97..ea3f1862a 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/Utilities.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/Utilities.java @@ -27,7 +27,6 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; public class Utilities { - public static Pattern pattern = Pattern.compile("[\\-0-9]+"); public static SecureRandom random = new SecureRandom(); public static Random fastRandom = new Xoroshiro128PlusRandom(random.nextLong()); @@ -39,6 +38,8 @@ public class Utilities { public static volatile DispatchQueue phoneBookQueue = new DispatchQueue("phoneBookQueue"); public static volatile DispatchQueue themeQueue = new DispatchQueue("themeQueue"); + private final static String RANDOM_STRING_CHARS = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; + final protected static char[] hexArray = "0123456789ABCDEF".toCharArray(); static { @@ -405,4 +406,16 @@ public class Utilities { public static float clamp(float value, float top, float bottom) { return Math.max(Math.min(value, top), bottom); } + + public static String generateRandomString() { + return generateRandomString(16); + } + + public static String generateRandomString(int chars) { + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < chars; i++) { + sb.append(RANDOM_STRING_CHARS.charAt(fastRandom.nextInt(RANDOM_STRING_CHARS.length()))); + } + return sb.toString(); + } } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/VideoEditedInfo.java b/TMessagesProj/src/main/java/org/telegram/messenger/VideoEditedInfo.java index f0b59ae0e..ae3bbf151 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/VideoEditedInfo.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/VideoEditedInfo.java @@ -13,6 +13,7 @@ import android.view.View; import org.telegram.tgnet.SerializedData; import org.telegram.tgnet.TLRPC; +import org.telegram.ui.Components.AnimatedFileDrawable; import org.telegram.ui.Components.PhotoFilterView; import org.telegram.ui.Components.Point; @@ -84,6 +85,7 @@ public class VideoEditedInfo { public Bitmap bitmap; public View view; + public AnimatedFileDrawable animatedFileDrawable; public MediaEntity() { diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/ringtone/RingtoneDataStore.java b/TMessagesProj/src/main/java/org/telegram/messenger/ringtone/RingtoneDataStore.java new file mode 100644 index 000000000..14ac394ea --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/ringtone/RingtoneDataStore.java @@ -0,0 +1,318 @@ +package org.telegram.messenger.ringtone; + +import android.content.Context; +import android.content.SharedPreferences; +import android.text.TextUtils; + +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.ApplicationLoader; +import org.telegram.messenger.BuildVars; +import org.telegram.messenger.FileLoader; +import org.telegram.messenger.FileLog; +import org.telegram.messenger.NotificationCenter; +import org.telegram.messenger.UserConfig; +import org.telegram.messenger.Utilities; +import org.telegram.tgnet.ConnectionsManager; +import org.telegram.tgnet.SerializedData; +import org.telegram.tgnet.TLRPC; + +import java.io.File; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; + +public class RingtoneDataStore { + + private final long clientUserId; + String prefName = null; + + private static volatile long queryHash; + private static volatile long lastReloadTimeMs; + private final int currentAccount; + private int localIds; + + private static final long reloadTimeoutMs = 24 * 60 * 60 * 1000;//1 day + + public final ArrayList userRingtones = new ArrayList<>(); + private boolean loaded; + + public final static HashSet ringtoneSupportedMimeType = new HashSet<>(Arrays.asList("audio/mpeg", "audio/ogg", "audio/m4a")); + + public RingtoneDataStore(int currentAccount) { + this.currentAccount = currentAccount; + this.clientUserId = UserConfig.getInstance(currentAccount).clientUserId; + SharedPreferences preferences = getSharedPreferences(); + try { + queryHash = preferences.getLong("hash", 0); + lastReloadTimeMs = preferences.getLong("lastReload", 0); + } catch (Exception e) { + FileLog.e(e); + } + loadUserRingtones(); + } + + public void loadUserRingtones() { + boolean needReload = System.currentTimeMillis() - lastReloadTimeMs > reloadTimeoutMs; + TLRPC.TL_account_getSavedRingtones req = new TLRPC.TL_account_getSavedRingtones(); + req.hash = queryHash; + if (needReload) { + ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> AndroidUtilities.runOnUIThread(() -> { + if (response != null) { + if (response instanceof TLRPC.TL_account_savedRingtonesNotModified) { + loadFromPrefs(true); + } else if (response instanceof TLRPC.TL_account_savedRingtones) { + TLRPC.TL_account_savedRingtones res = (TLRPC.TL_account_savedRingtones) response; + saveTones(res.ringtones); + getSharedPreferences().edit() + .putLong("hash", queryHash = res.hash) + .putLong("lastReload", lastReloadTimeMs = System.currentTimeMillis()) + .apply(); + } + checkRingtoneSoundsLoaded(); + } + })); + } else { + if (!loaded) { + loadFromPrefs(true); + loaded = true; + } + checkRingtoneSoundsLoaded(); + } + } + + private void loadFromPrefs(boolean notify) { + SharedPreferences preferences = getSharedPreferences(); + int count = preferences.getInt("count", 0); + userRingtones.clear(); + for (int i = 0; i < count; ++i) { + String value = preferences.getString("tone_document" + i, ""); + String localPath = preferences.getString("tone_local_path" + i, ""); + SerializedData serializedData = new SerializedData(Utilities.hexToBytes(value)); + try { + TLRPC.Document document = TLRPC.Document.TLdeserialize(serializedData, serializedData.readInt32(true), true); + CachedTone tone = new CachedTone(); + tone.document = document; + tone.localUri = localPath; + tone.localId = localIds++; + userRingtones.add(tone); + } catch (Throwable e) { + if (BuildVars.DEBUG_PRIVATE_VERSION) { + throw e; + } + FileLog.e(e); + } + } + if (notify) { + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.onUserRingtonesUpdated); + } + } + + private void saveTones(ArrayList ringtones) { + if (!loaded) { + loadFromPrefs(false); + loaded = true; + } + HashMap documentIdToLocalFilePath = new HashMap<>(); + for (CachedTone cachedTone : userRingtones) { + if (cachedTone.localUri != null && cachedTone.document != null) { + documentIdToLocalFilePath.put(cachedTone.document.id, cachedTone.localUri); + } + } + userRingtones.clear(); + SharedPreferences preferences = getSharedPreferences(); + preferences.edit().clear().apply(); + SharedPreferences.Editor editor = preferences.edit(); + editor.putInt("count", ringtones.size()); + + for (int i = 0; i < ringtones.size(); i++) { + TLRPC.Document document = ringtones.get(i); + String localPath = documentIdToLocalFilePath.get(document.id); + SerializedData data = new SerializedData(document.getObjectSize()); + document.serializeToStream(data); + editor.putString("tone_document" + i, Utilities.bytesToHex(data.toByteArray())); + if (localPath != null) { + editor.putString("tone_local_path" + i, localPath); + } + CachedTone tone = new CachedTone(); + tone.document = document; + tone.localUri = localPath; + tone.localId = localIds++; + userRingtones.add(tone); + } + editor.apply(); + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.onUserRingtonesUpdated); + } + + public void saveTones() { + SharedPreferences preferences = getSharedPreferences(); + preferences.edit().clear().apply(); + SharedPreferences.Editor editor = preferences.edit(); + + int count = 0; + for (int i = 0; i < userRingtones.size(); i++) { + if (userRingtones.get(i).uploading) { + continue; + } + count++; + TLRPC.Document document = userRingtones.get(i).document; + String localPath = userRingtones.get(i).localUri; + SerializedData data = new SerializedData(document.getObjectSize()); + document.serializeToStream(data); + editor.putString("tone_document" + i, Utilities.bytesToHex(data.toByteArray())); + if (localPath != null) { + editor.putString("tone_local_path" + i, localPath); + } + } + + editor.putInt("count", count); + editor.apply(); + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.onUserRingtonesUpdated); + } + + + private SharedPreferences getSharedPreferences() { + if (prefName == null) { + prefName = "ringtones_pref_" + clientUserId; + } + return ApplicationLoader.applicationContext.getSharedPreferences(prefName, Context.MODE_PRIVATE); + } + + public void addUploadingTone(String filePath) { + CachedTone cachedTone = new CachedTone(); + cachedTone.localUri = filePath; + cachedTone.localId = localIds++; + cachedTone.uploading = true; + userRingtones.add(cachedTone); + } + + public void onRingtoneUploaded(String filePath, TLRPC.Document document, boolean error) { + boolean changed = false; + if (error) { + for (int i = 0; i < userRingtones.size(); i++) { + if (userRingtones.get(i).uploading && filePath.equals(userRingtones.get(i).localUri)) { + userRingtones.remove(i); + changed = true; + break; + } + } + } else { + for (int i = 0; i < userRingtones.size(); i++) { + if (userRingtones.get(i).uploading && filePath.equals(userRingtones.get(i).localUri)) { + userRingtones.get(i).uploading = false; + userRingtones.get(i).document = document; + changed = true; + break; + } + } + if (changed) { + saveTones(); + } + } + if (changed) { + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.onUserRingtonesUpdated); + } + } + + public String getSoundPath(long id) { + if (!loaded) { + loadFromPrefs(true); + loaded = true; + } + for (int i = 0; i < userRingtones.size(); i++) { + if (userRingtones.get(i).document != null && userRingtones.get(i).document.id == id) { + if (!TextUtils.isEmpty(userRingtones.get(i).localUri)) { + return userRingtones.get(i).localUri; + } + return FileLoader.getPathToAttach(userRingtones.get(i).document).toString(); + } + } + return "NoSound"; + } + + public void checkRingtoneSoundsLoaded() { + if (!loaded) { + loadFromPrefs(true); + loaded = true; + } + final ArrayList cachedTones = new ArrayList<>(userRingtones); + Utilities.globalQueue.postRunnable(() -> { + for (int i = 0; i < cachedTones.size(); i++) { + CachedTone tone = cachedTones.get(i); + if (!TextUtils.isEmpty(tone.localUri)) { + File file = new File(tone.localUri); + if (file.exists()) { + continue; + } + } + + if (tone.document != null) { + TLRPC.Document document = tone.document; + File file = FileLoader.getPathToAttach(document); + if (file == null || !file.exists()) { + AndroidUtilities.runOnUIThread(() -> { + FileLoader.getInstance(currentAccount).loadFile(document, null, 0, 0); + }); + } + } + } + }); + + } + + public boolean isLoaded() { + return loaded; + } + + public void remove(TLRPC.Document document) { + if (document == null) { + return; + } + if (!loaded) { + loadFromPrefs(true); + loaded = true; + } + for (int i = 0; i < userRingtones.size(); i++) { + if (userRingtones.get(i).document != null && userRingtones.get(i).document.id == document.id) { + userRingtones.remove(i); + break; + } + } + } + + public boolean contains(long id) { + return getDocument(id) != null; + } + + public void addTone(TLRPC.Document document) { + if (document == null || contains(document.id)) { + return; + } + CachedTone cachedTone = new CachedTone(); + cachedTone.document = document; + cachedTone.localId = localIds++; + cachedTone.uploading = false; + userRingtones.add(cachedTone); + saveTones(); + } + + public TLRPC.Document getDocument(long id) { + if (!loaded) { + loadFromPrefs(true); + loaded = true; + } + for (int i = 0; i < userRingtones.size(); i++) { + if (userRingtones.get(i).document != null && userRingtones.get(i).document.id == id) { + return userRingtones.get(i).document; + } + } + return null; + } + + public class CachedTone { + public TLRPC.Document document; + public String localUri; + public int localId; + public boolean uploading; + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/ringtone/RingtoneUploader.java b/TMessagesProj/src/main/java/org/telegram/messenger/ringtone/RingtoneUploader.java new file mode 100644 index 000000000..f0566c216 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/ringtone/RingtoneUploader.java @@ -0,0 +1,97 @@ +package org.telegram.messenger.ringtone; + +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.FileLoader; +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.tgnet.ConnectionsManager; +import org.telegram.tgnet.TLRPC; +import org.telegram.ui.Components.Bulletin; + +import java.io.File; + +public class RingtoneUploader implements NotificationCenter.NotificationCenterDelegate { + + private int currentAccount; + public final String filePath; + private boolean canceled; + + public RingtoneUploader(String filePath, int currentAccount) { + this.currentAccount = currentAccount; + this.filePath = filePath; + subscribe(); + FileLoader.getInstance(currentAccount).uploadFile(filePath, false, true, ConnectionsManager.FileTypeAudio); + } + + @Override + public void didReceivedNotification(int id, int account, Object... args) { + if (id == NotificationCenter.fileUploaded) { + final String location = (String) args[0]; + if (canceled) { + return; + } + if (location.equals(filePath)) { + final TLRPC.InputFile file = (TLRPC.InputFile) args[1]; + TLRPC.TL_account_uploadRingtone req = new TLRPC.TL_account_uploadRingtone(); + req.file = file; + req.file_name = file.name; + req.mime_type = FileLoader.getFileExtension(new File(file.name)); + if ("ogg".equals(req.mime_type)) { + req.mime_type = "audio/ogg"; + } else { + req.mime_type = "audio/mpeg"; + } + ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> { + AndroidUtilities.runOnUIThread(() -> { + if (response != null) { + onComplete((TLRPC.Document) response); + } else { + error(error); + } + unsubscribe(); + }); + }); + } + } + } + + private void subscribe() { + NotificationCenter.getInstance(currentAccount).addObserver(this, NotificationCenter.fileUploaded); + NotificationCenter.getInstance(currentAccount).addObserver(this, NotificationCenter.fileUploadFailed); + } + + private void unsubscribe() { + NotificationCenter.getInstance(currentAccount).removeObserver(this, NotificationCenter.fileUploaded); + NotificationCenter.getInstance(currentAccount).removeObserver(this, NotificationCenter.fileUploadFailed); + } + + private void onComplete(TLRPC.Document document) { + MediaDataController.getInstance(currentAccount).onRingtoneUploaded(filePath, document, false); + } + + public void cancel() { + canceled = true; + unsubscribe(); + FileLoader.getInstance(currentAccount).cancelFileUpload(filePath, false); + MediaDataController.getInstance(currentAccount).onRingtoneUploaded(filePath, null, true); + } + + public void error(TLRPC.TL_error error) { + unsubscribe(); + MediaDataController.getInstance(currentAccount).onRingtoneUploaded(filePath, null, true); + if (error != null) { + NotificationCenter.getInstance(currentAccount).doOnIdle(() -> { + if (error.text.equals("RINGTONE_DURATION_TOO_LONG")) { + NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.showBulletin, Bulletin.TYPE_ERROR_SUBTITLE, LocaleController.formatString("TooLongError", R.string.TooLongError), LocaleController.formatString("ErrorRingtoneDurationTooLong", R.string.ErrorRingtoneDurationTooLong, MessagesController.getInstance(currentAccount).ringtoneDurationMax)); + } else if (error.text.equals("RINGTONE_SIZE_TOO_BIG")) { + NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.showBulletin, Bulletin.TYPE_ERROR_SUBTITLE, LocaleController.formatString("TooLargeError", R.string.TooLargeError), LocaleController.formatString("ErrorRingtoneSizeTooBig", R.string.ErrorRingtoneSizeTooBig, (MessagesController.getInstance(currentAccount).ringtoneSizeMax / 1024))); + } else { + NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.showBulletin, Bulletin.TYPE_ERROR_SUBTITLE, LocaleController.formatString("InvalidFormatError", R.string.InvalidFormatError), LocaleController.formatString("ErrorRingtoneInvalidFormat", R.string.ErrorRingtoneInvalidFormat)); + } + }); + } + } +} 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 989ba9d37..f7a34449c 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/video/MediaCodecVideoConvertor.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/video/MediaCodecVideoConvertor.java @@ -330,6 +330,12 @@ public class MediaCodecVideoConvertor { long additionalPresentationTime = 0; long minPresentationTime = Integer.MIN_VALUE; long frameDelta = 1000 / framerate * 1000; + long frameDeltaFroSkipFrames; + if (framerate < 30) { + frameDeltaFroSkipFrames = 1000 / (framerate + 5) * 1000; + } else { + frameDeltaFroSkipFrames = 1000 / (framerate + 1) * 1000; + } extractor.selectTrack(videoIndex); MediaFormat videoFormat = extractor.getTrackFormat(videoIndex); @@ -681,7 +687,7 @@ public class MediaCodecVideoConvertor { decoder.flush(); flushed = true; } - if (lastFramePts > 0 && info.presentationTimeUs - lastFramePts < frameDelta && (info.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) == 0) { + if (lastFramePts > 0 && info.presentationTimeUs - lastFramePts < frameDeltaFroSkipFrames && (info.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) == 0) { doRender = false; } trueStartTime = avatarStartTime >= 0 ? avatarStartTime : startTime; 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 1d34cb14a..9445351e3 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/video/TextureRenderer.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/video/TextureRenderer.java @@ -8,14 +8,6 @@ package org.telegram.messenger.video; -import java.io.File; -import java.io.RandomAccessFile; -import java.nio.ByteBuffer; -import java.nio.ByteOrder; -import java.nio.FloatBuffer; -import java.nio.channels.FileChannel; -import java.util.ArrayList; - import android.annotation.SuppressLint; import android.graphics.Bitmap; import android.graphics.BitmapFactory; @@ -35,22 +27,32 @@ import android.view.Gravity; import android.view.View; import android.view.inputmethod.EditorInfo; +import androidx.annotation.RequiresApi; +import androidx.exifinterface.media.ExifInterface; + import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.ApplicationLoader; import org.telegram.messenger.Bitmaps; import org.telegram.messenger.BuildVars; import org.telegram.messenger.FileLog; import org.telegram.messenger.MediaController; +import org.telegram.messenger.UserConfig; import org.telegram.messenger.Utilities; import org.telegram.messenger.VideoEditedInfo; +import org.telegram.ui.Components.AnimatedFileDrawable; import org.telegram.ui.Components.FilterShaders; import org.telegram.ui.Components.Paint.Views.EditTextOutline; import org.telegram.ui.Components.RLottieDrawable; -import javax.microedition.khronos.opengles.GL10; +import java.io.File; +import java.io.RandomAccessFile; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.nio.FloatBuffer; +import java.nio.channels.FileChannel; +import java.util.ArrayList; -import androidx.annotation.RequiresApi; -import androidx.exifinterface.media.ExifInterface; +import javax.microedition.khronos.opengles.GL10; public class TextureRenderer { @@ -121,6 +123,7 @@ public class TextureRenderer { private int[] paintTexture; private int[] stickerTexture; private Bitmap stickerBitmap; + private Canvas stickerCanvas; private float videoFps; private int imageOrientation; @@ -398,10 +401,31 @@ public class TextureRenderer { entity.currentFrame = 0; } drawTexture(false, stickerTexture[0], entity.x, entity.y, entity.width, entity.height, entity.rotation, (entity.subType & 2) != 0); - } else if (entity.bitmap != null) { - GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, stickerTexture[0]); - GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, entity.bitmap, 0); - 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--; + } + Bitmap frameBitmap = entity.animatedFileDrawable.getBackgroundBitmap(); + if (stickerCanvas == null && stickerBitmap != null) { + stickerCanvas = new Canvas(stickerBitmap); + } + if (stickerBitmap != null && frameBitmap != null) { + stickerBitmap.eraseColor(Color.TRANSPARENT); + stickerCanvas.drawBitmap(frameBitmap, 0, 0, null); + GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, stickerTexture[0]); + GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, stickerBitmap, 0); + drawTexture(false, stickerTexture[0], entity.x, entity.y, entity.width, entity.height, entity.rotation, (entity.subType & 2) != 0); + } + } else { + if (entity.bitmap != null) { + GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, stickerTexture[0]); + GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, entity.bitmap, 0); + drawTexture(false, stickerTexture[0], entity.x, entity.y, entity.width, entity.height, entity.rotation, (entity.subType & 2) != 0); + } } } } @@ -608,6 +632,10 @@ public class TextureRenderer { entity.metadata = new int[3]; entity.ptr = RLottieDrawable.create(entity.text, null, 512, 512, entity.metadata, false, null, false, 0); entity.framesPerDraw = entity.metadata[1] / videoFps; + } else if ((entity.subType & 4) != 0) { + entity.animatedFileDrawable = new AnimatedFileDrawable(new File(entity.text), true, 0, null, null, null, 0, UserConfig.selectedAccount, true, 512, 512); + entity.framesPerDraw = videoFps / 30f; + entity.currentFrame = 0; } else { if (Build.VERSION.SDK_INT >= 19) { entity.bitmap = BitmapFactory.decodeFile(entity.text); @@ -713,6 +741,9 @@ public class TextureRenderer { if (entity.ptr != 0) { RLottieDrawable.destroy(entity.ptr); } + if (entity.animatedFileDrawable != null) { + entity.animatedFileDrawable.recycle(); + } } } } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/voip/Instance.java b/TMessagesProj/src/main/java/org/telegram/messenger/voip/Instance.java index 85a387160..06256befb 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/voip/Instance.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/voip/Instance.java @@ -15,7 +15,7 @@ import java.util.List; public final class Instance { - public static final List AVAILABLE_VERSIONS = Build.VERSION.SDK_INT >= 18 ? Arrays.asList("4.0.0", "3.0.0", "2.7.7", "2.4.4") : Arrays.asList("2.4.4"); + public static final List AVAILABLE_VERSIONS = Build.VERSION.SDK_INT >= 18 ? Arrays.asList("4.0.1", "4.0.0", "3.0.0", "2.7.7", "2.4.4") : Arrays.asList("2.4.4"); public static final int AUDIO_STATE_MUTED = 0; public static final int AUDIO_STATE_ACTIVE = 1; @@ -283,7 +283,7 @@ public final class Instance { public static final class FinalState { public final byte[] persistentState; - public final String debugLog; + public String debugLog; public final TrafficStats trafficStats; public final boolean isRatingSuggested; 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 399b4e89f..9eefe7afd 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/voip/VoIPService.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/voip/VoIPService.java @@ -108,7 +108,6 @@ import org.telegram.messenger.UserObject; import org.telegram.messenger.Utilities; import org.telegram.messenger.XiaomiUtilities; import org.telegram.tgnet.ConnectionsManager; -import org.telegram.tgnet.RequestDelegate; import org.telegram.tgnet.TLObject; import org.telegram.tgnet.TLRPC; import org.telegram.ui.ActionBar.BottomSheet; @@ -124,9 +123,13 @@ import org.webrtc.VideoFrame; import org.webrtc.VideoSink; import org.webrtc.voiceengine.WebRtcAudioTrack; +import java.io.BufferedReader; import java.io.ByteArrayOutputStream; import java.io.File; +import java.io.FileInputStream; import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.math.BigInteger; @@ -2332,11 +2335,11 @@ public class VoIPService extends Service implements SensorEventListener, AudioMa final boolean enableAec = !(sysAecAvailable && serverConfig.useSystemAec); final boolean enableNs = !(sysNsAvailable && serverConfig.useSystemNs); final String logFilePath = BuildVars.DEBUG_VERSION ? VoIPHelper.getLogFilePath("voip" + privateCall.id) : VoIPHelper.getLogFilePath(privateCall.id, false); - final String statisLogFilePath = ""; - final Instance.Config config = new Instance.Config(initializationTimeout, receiveTimeout, voipDataSaving, privateCall.p2p_allowed, enableAec, enableNs, true, false, serverConfig.enableStunMarking, logFilePath, statisLogFilePath, privateCall.protocol.max_layer); + final String statsLogFilePath = VoIPHelper.getLogFilePath(privateCall.id, true); + final Instance.Config config = new Instance.Config(initializationTimeout, receiveTimeout, voipDataSaving, privateCall.p2p_allowed, enableAec, enableNs, true, false, serverConfig.enableStunMarking, logFilePath, statsLogFilePath, privateCall.protocol.max_layer); // persistent state - final String persistentStateFilePath = new File(ApplicationLoader.applicationContext.getFilesDir(), "voip_persistent_state.json").getAbsolutePath(); + final String persistentStateFilePath = new File(ApplicationLoader.applicationContext.getCacheDir(), "voip_persistent_state.json").getAbsolutePath(); // endpoints final boolean forceTcp = preferences.getBoolean("dbg_force_tcp_in_calls", false); @@ -3362,10 +3365,37 @@ public class VoIPService extends Service implements SensorEventListener, AudioMa }*/ } + public static String convertStreamToString(InputStream is) throws Exception { + BufferedReader reader = new BufferedReader(new InputStreamReader(is)); + StringBuilder sb = new StringBuilder(); + String line = null; + while ((line = reader.readLine()) != null) { + sb.append(line).append("\n"); + } + reader.close(); + return sb.toString(); + } + + public static String getStringFromFile(String filePath) throws Exception { + File fl = new File(filePath); + FileInputStream fin = new FileInputStream(fl); + String ret = convertStreamToString(fin); + fin.close(); + return ret; + } + private void onTgVoipStop(Instance.FinalState finalState) { if (user == null) { return; } + if (TextUtils.isEmpty(finalState.debugLog)) { + try { + finalState.debugLog = getStringFromFile(VoIPHelper.getLogFilePath(privateCall.id, true)); + } catch (Exception e) { + e.printStackTrace(); + } + } + if (needRateCall || forceRating || finalState.isRatingSuggested) { startRatingActivity(); needRateCall = false; diff --git a/TMessagesProj/src/main/java/org/telegram/tgnet/TLRPC.java b/TMessagesProj/src/main/java/org/telegram/tgnet/TLRPC.java index 49bb8bc2b..af0091477 100644 --- a/TMessagesProj/src/main/java/org/telegram/tgnet/TLRPC.java +++ b/TMessagesProj/src/main/java/org/telegram/tgnet/TLRPC.java @@ -66,7 +66,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 = 139; + public static final int LAYER = 140; public static class TL_stats_megagroupStats extends TLObject { public static int constructor = 0xef7ff916; @@ -7975,6 +7975,85 @@ public class TLRPC { } } + public static class TL_notificationSoundDefault extends NotificationSound { + public static int constructor = 0x97e8bebe; + + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } + + public static class TL_notificationSoundNone extends NotificationSound { + public static int constructor = 0x6f0c34df; + + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } + + public static class TL_notificationSoundRingtone extends NotificationSound { + public static int constructor = 0xff6c8049; + + public long id; + + public void readParams(AbstractSerializedData stream, boolean exception) { + id = stream.readInt64(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt64(id); + } + } + + public static class TL_notificationSoundLocal extends NotificationSound { + public static int constructor = 0x830b9ae4; + + public String title; + public String data; + + public void readParams(AbstractSerializedData stream, boolean exception) { + title = stream.readString(exception); + data = stream.readString(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeString(title); + stream.writeString(data); + } + } + + public static abstract class NotificationSound extends TLObject { + + public static NotificationSound TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + NotificationSound result = null; + switch (constructor) { + case 0x97e8bebe: + result = new TL_notificationSoundDefault(); + break; + case 0x6f0c34df: + result = new TL_notificationSoundNone(); + break; + case 0xff6c8049: + result = new TL_notificationSoundRingtone(); + break; + case 0x830b9ae4: + result = new TL_notificationSoundLocal(); + break; + } + if (result == null && exception) { + throw new RuntimeException(String.format("can't parse magic %x in NotificationSound", constructor)); + } + if (result != null) { + result.readParams(stream, exception); + } + return result; + } + } + public static abstract class PeerNotifySettings extends TLObject { public int flags; public int mute_until; @@ -7982,15 +8061,21 @@ public class TLRPC { public boolean show_previews; public int events_mask; public boolean silent; + public NotificationSound ios_sound; + public NotificationSound android_sound; + public NotificationSound other_sound; public static PeerNotifySettings TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { PeerNotifySettings result = null; switch (constructor) { + case 0xa83b0426: + result = new TL_peerNotifySettings(); + break; case 0x9acda4c0: result = new TL_peerNotifySettings_layer77(); break; case 0xaf509d20: - result = new TL_peerNotifySettings(); + result = new TL_peerNotifySettings_layer139(); break; case 0x8d5e11ee: result = new TL_peerNotifySettings_layer47(); @@ -8031,6 +8116,55 @@ public class TLRPC { } public static class TL_peerNotifySettings extends PeerNotifySettings { + public static int constructor = 0xa83b0426; + + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + if ((flags & 1) != 0) { + show_previews = stream.readBool(exception); + } + if ((flags & 2) != 0) { + silent = stream.readBool(exception); + } + if ((flags & 4) != 0) { + mute_until = stream.readInt32(exception); + } + if ((flags & 8) != 0) { + ios_sound = NotificationSound.TLdeserialize(stream, stream.readInt32(exception), exception); + } + if ((flags & 16) != 0) { + android_sound = NotificationSound.TLdeserialize(stream, stream.readInt32(exception), exception); + } + if ((flags & 32) != 0) { + other_sound = NotificationSound.TLdeserialize(stream, stream.readInt32(exception), exception); + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(flags); + if ((flags & 1) != 0) { + stream.writeBool(show_previews); + } + if ((flags & 2) != 0) { + stream.writeBool(silent); + } + if ((flags & 4) != 0) { + stream.writeInt32(mute_until); + } + if ((flags & 8) != 0) { + ios_sound.serializeToStream(stream); + } + if ((flags & 16) != 0) { + android_sound.serializeToStream(stream); + } + if ((flags & 32) != 0) { + other_sound.serializeToStream(stream); + } + } + } + + public static class TL_peerNotifySettings_layer139 extends TL_peerNotifySettings { public static int constructor = 0xaf509d20; public void readParams(AbstractSerializedData stream, boolean exception) { @@ -9097,6 +9231,7 @@ public class TLRPC { public String description; public ArrayList commands = new ArrayList<>(); public int version; + public BotMenuButton menu_button; public static BotInfo TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { BotInfo result = null; @@ -9111,6 +9246,9 @@ public class TLRPC { result = new TL_botInfo_layer48(); break; case 0x1b74b335: + result = new TL_botInfo_layer139(); + break; + case 0xe4169b5d: result = new TL_botInfo(); break; } @@ -9211,7 +9349,7 @@ public class TLRPC { } } - public static class TL_botInfo extends BotInfo { + public static class TL_botInfo_layer139 extends BotInfo { public static int constructor = 0x1b74b335; @@ -9248,6 +9386,45 @@ public class TLRPC { } } + public static class TL_botInfo extends BotInfo { + public static int constructor = 0xe4169b5d; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + user_id = stream.readInt64(exception); + description = 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_botCommand object = TL_botCommand.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + commands.add(object); + } + menu_button = BotMenuButton.TLdeserialize(stream, stream.readInt32(exception), exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt64(user_id); + stream.writeString(description); + stream.writeInt32(0x1cb5c415); + int count = commands.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + commands.get(a).serializeToStream(stream); + } + menu_button.serializeToStream(stream); + } + } + public static abstract class InputGame extends TLObject { public InputUser bot_id; public String short_name; @@ -10505,6 +10682,8 @@ public class TLRPC { public int requests_pending; public Peer default_send_as; public ArrayList available_reactions = new ArrayList<>(); + public int flags2; + public boolean can_delete_channel; public long inviterId; //custom public int invitesCount; //custom @@ -10515,9 +10694,12 @@ public class TLRPC { case 0xd18ee226: result = new TL_chatFull(); break; - case 0xe13c3d20: + case 0xea68a619: result = new TL_channelFull(); break; + case 0xe13c3d20: + result = new TL_channelFull_layer139(); + break; case 0x56662e2e: result = new TL_channelFull_layer135(); break; @@ -12810,6 +12992,277 @@ public class TLRPC { } public static class TL_channelFull extends ChatFull { + public static int constructor = 0xea68a619; + + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + can_view_participants = (flags & 8) != 0; + can_set_username = (flags & 64) != 0; + can_set_stickers = (flags & 128) != 0; + hidden_prehistory = (flags & 1024) != 0; + can_set_location = (flags & 65536) != 0; + has_scheduled = (flags & 524288) != 0; + can_view_stats = (flags & 1048576) != 0; + blocked = (flags & 4194304) != 0; + flags2 = stream.readInt32(exception); + can_delete_channel = (flags2 & 1) != 0; + id = stream.readInt64(exception); + about = stream.readString(exception); + if ((flags & 1) != 0) { + participants_count = stream.readInt32(exception); + } + if ((flags & 2) != 0) { + admins_count = stream.readInt32(exception); + } + if ((flags & 4) != 0) { + kicked_count = stream.readInt32(exception); + } + if ((flags & 4) != 0) { + banned_count = stream.readInt32(exception); + } + if ((flags & 8192) != 0) { + online_count = stream.readInt32(exception); + } + read_inbox_max_id = stream.readInt32(exception); + read_outbox_max_id = stream.readInt32(exception); + unread_count = stream.readInt32(exception); + chat_photo = Photo.TLdeserialize(stream, stream.readInt32(exception), exception); + notify_settings = PeerNotifySettings.TLdeserialize(stream, stream.readInt32(exception), exception); + if ((flags & 8388608) != 0) { + exported_invite = ExportedChatInvite.TLdeserialize(stream, stream.readInt32(exception), exception); + } + int magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + int count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + BotInfo object = BotInfo.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + bot_info.add(object); + } + if ((flags & 16) != 0) { + migrated_from_chat_id = stream.readInt64(exception); + } + if ((flags & 16) != 0) { + migrated_from_max_id = stream.readInt32(exception); + } + if ((flags & 32) != 0) { + pinned_msg_id = stream.readInt32(exception); + } + if ((flags & 256) != 0) { + stickerset = StickerSet.TLdeserialize(stream, stream.readInt32(exception), exception); + } + if ((flags & 512) != 0) { + available_min_id = stream.readInt32(exception); + } + if ((flags & 2048) != 0) { + folder_id = stream.readInt32(exception); + } + if ((flags & 16384) != 0) { + linked_chat_id = stream.readInt64(exception); + } + if ((flags & 32768) != 0) { + location = ChannelLocation.TLdeserialize(stream, stream.readInt32(exception), exception); + } + if ((flags & 131072) != 0) { + slowmode_seconds = stream.readInt32(exception); + } + if ((flags & 262144) != 0) { + slowmode_next_send_date = stream.readInt32(exception); + } + if ((flags & 4096) != 0) { + stats_dc = stream.readInt32(exception); + } + pts = stream.readInt32(exception); + if ((flags & 2097152) != 0) { + call = TL_inputGroupCall.TLdeserialize(stream, stream.readInt32(exception), exception); + } + if ((flags & 16777216) != 0) { + ttl_period = stream.readInt32(exception); + } + if ((flags & 33554432) != 0) { + magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + pending_suggestions.add(stream.readString(exception)); + } + } + if ((flags & 67108864) != 0) { + groupcall_default_join_as = Peer.TLdeserialize(stream, stream.readInt32(exception), exception); + } + if ((flags & 134217728) != 0) { + theme_emoticon = stream.readString(exception); + } + if ((flags & 268435456) != 0) { + requests_pending = stream.readInt32(exception); + } + if ((flags & 268435456) != 0) { + magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + recent_requesters.add(stream.readInt64(exception)); + } + } + if ((flags & 536870912) != 0) { + default_send_as = Peer.TLdeserialize(stream, stream.readInt32(exception), exception); + } + if ((flags & 1073741824) != 0) { + 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.add(stream.readString(exception)); + } + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + flags = can_view_participants ? (flags | 8) : (flags &~ 8); + flags = can_set_username ? (flags | 64) : (flags &~ 64); + flags = can_set_stickers ? (flags | 128) : (flags &~ 128); + flags = hidden_prehistory ? (flags | 1024) : (flags &~ 1024); + flags = can_set_location ? (flags | 65536) : (flags &~ 65536); + flags = has_scheduled ? (flags | 524288) : (flags &~ 524288); + flags = can_view_stats ? (flags | 1048576) : (flags &~ 1048576); + flags = blocked ? (flags | 4194304) : (flags &~ 4194304); + stream.writeInt32(flags); + flags2 = can_delete_channel ? (flags2 | 1) : (flags2 &~ 1); + stream.writeInt32(flags2); + stream.writeInt64(id); + stream.writeString(about); + if ((flags & 1) != 0) { + stream.writeInt32(participants_count); + } + if ((flags & 2) != 0) { + stream.writeInt32(admins_count); + } + if ((flags & 4) != 0) { + stream.writeInt32(kicked_count); + } + if ((flags & 4) != 0) { + stream.writeInt32(banned_count); + } + if ((flags & 8192) != 0) { + stream.writeInt32(online_count); + } + stream.writeInt32(read_inbox_max_id); + stream.writeInt32(read_outbox_max_id); + stream.writeInt32(unread_count); + chat_photo.serializeToStream(stream); + notify_settings.serializeToStream(stream); + if ((flags & 8388608) != 0) { + exported_invite.serializeToStream(stream); + } + stream.writeInt32(0x1cb5c415); + int count = bot_info.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + bot_info.get(a).serializeToStream(stream); + } + if ((flags & 16) != 0) { + stream.writeInt64(migrated_from_chat_id); + } + if ((flags & 16) != 0) { + stream.writeInt32(migrated_from_max_id); + } + if ((flags & 32) != 0) { + stream.writeInt32(pinned_msg_id); + } + if ((flags & 256) != 0) { + stickerset.serializeToStream(stream); + } + if ((flags & 512) != 0) { + stream.writeInt32(available_min_id); + } + if ((flags & 2048) != 0) { + stream.writeInt32(folder_id); + } + if ((flags & 16384) != 0) { + stream.writeInt64(linked_chat_id); + } + if ((flags & 32768) != 0) { + location.serializeToStream(stream); + } + if ((flags & 131072) != 0) { + stream.writeInt32(slowmode_seconds); + } + if ((flags & 262144) != 0) { + stream.writeInt32(slowmode_next_send_date); + } + if ((flags & 4096) != 0) { + stream.writeInt32(stats_dc); + } + stream.writeInt32(pts); + if ((flags & 2097152) != 0) { + call.serializeToStream(stream); + } + if ((flags & 16777216) != 0) { + stream.writeInt32(ttl_period); + } + if ((flags & 33554432) != 0) { + stream.writeInt32(0x1cb5c415); + count = pending_suggestions.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + stream.writeString(pending_suggestions.get(a)); + } + } + if ((flags & 67108864) != 0) { + groupcall_default_join_as.serializeToStream(stream); + } + if ((flags & 134217728) != 0) { + stream.writeString(theme_emoticon); + } + if ((flags & 268435456) != 0) { + stream.writeInt32(requests_pending); + } + if ((flags & 268435456) != 0) { + stream.writeInt32(0x1cb5c415); + count = recent_requesters.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + stream.writeInt64(recent_requesters.get(a)); + } + } + if ((flags & 536870912) != 0) { + default_send_as.serializeToStream(stream); + } + if ((flags & 1073741824) != 0) { + stream.writeInt32(0x1cb5c415); + count = available_reactions.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + stream.writeString(available_reactions.get(a)); + } + } + } + } + + public static class TL_channelFull_layer139 extends ChatFull { public static int constructor = 0xe13c3d20; public void readParams(AbstractSerializedData stream, boolean exception) { @@ -15272,13 +15725,13 @@ public class TLRPC { } public static class TL_inputPeerNotifySettings extends TLObject { - public static int constructor = 0x9c3d198e; + public static int constructor = 0xdf1f002b; public int flags; public boolean show_previews; public boolean silent; public int mute_until; - public String sound; + public NotificationSound sound; public static TL_inputPeerNotifySettings TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { if (TL_inputPeerNotifySettings.constructor != constructor) { @@ -15305,7 +15758,7 @@ public class TLRPC { mute_until = stream.readInt32(exception); } if ((flags & 8) != 0) { - sound = stream.readString(exception); + sound = NotificationSound.TLdeserialize(stream, stream.readInt32(exception), exception); } } @@ -15322,7 +15775,7 @@ public class TLRPC { stream.writeInt32(mute_until); } if ((flags & 8) != 0) { - stream.writeString(sound); + sound.serializeToStream(stream); } } } @@ -16266,6 +16719,9 @@ public class TLRPC { public static KeyboardButton TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { KeyboardButton result = null; switch (constructor) { + case 0xa0c0505c: + result = new TL_keyboardButtonSimpleWebView(); + break; case 0xb16a6c29: result = new TL_keyboardButtonRequestPhone(); break; @@ -16308,6 +16764,9 @@ public class TLRPC { case 0x308660c1: result = new TL_keyboardButtonUserProfile(); break; + case 0x13767230: + result = new TL_keyboardButtonWebView(); + break; } if (result == null && exception) { throw new RuntimeException(String.format("can't parse magic %x in KeyboardButton", constructor)); @@ -19749,6 +20208,8 @@ public class TLRPC { public boolean inactive; public boolean explicit_content; public ArrayList restriction_reason = new ArrayList<>(); + public boolean bot_attach_menu; + public boolean bot_menu_webview; public static User TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { User result = null; @@ -19907,6 +20368,8 @@ public class TLRPC { scam = (flags & 16777216) != 0; apply_min_photo = (flags & 33554432) != 0; fake = (flags & 67108864) != 0; + bot_attach_menu = (flags & 134217728) != 0; + bot_menu_webview = (flags & 268435456) != 0; id = stream.readInt64(exception); if ((flags & 1) != 0) { access_hash = stream.readInt64(exception); @@ -19974,6 +20437,8 @@ public class TLRPC { flags = scam ? (flags | 16777216) : (flags &~ 16777216); flags = apply_min_photo ? (flags | 33554432) : (flags &~ 33554432); flags = fake ? (flags | 67108864) : (flags &~ 67108864); + flags = bot_attach_menu ? (flags | 134217728) : (flags &~ 134217728); + flags = bot_menu_webview ? (flags | 268435456) : (flags &~ 268435456); stream.writeInt32(flags); stream.writeInt64(id); if ((flags & 1) != 0) { @@ -21319,6 +21784,12 @@ public class TLRPC { case 0xd95c6154: result = new TL_messageActionSecureValuesSent(); break; + case 0x47dd8079: + result = new TL_messageActionWebViewDataSentMe(); + break; + case 0xb4c38cb5: + result = new TL_messageActionWebViewDataSent(); + break; case 0xf89cf5e8: result = new TL_messageActionChatJoinedByLink_layer131(); break; @@ -21818,6 +22289,39 @@ public class TLRPC { } } + public static class TL_messageActionWebViewDataSentMe extends MessageAction { + public static int constructor = 0x47dd8079; + + public String text; + public String data; + + public void readParams(AbstractSerializedData stream, boolean exception) { + text = stream.readString(exception); + data = stream.readString(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeString(text); + stream.writeString(data); + } + } + + public static class TL_messageActionWebViewDataSent extends MessageAction { + public static int constructor = 0xb4c38cb5; + + public String text; + + public void readParams(AbstractSerializedData stream, boolean exception) { + text = stream.readString(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeString(text); + } + } + public static class TL_messageActionUserJoined extends MessageAction { public static int constructor = 0x55555550; @@ -27440,6 +27944,9 @@ public class TLRPC { case 0x62ba04d9: result = new TL_updateNewChannelMessage(); break; + case 0x1592b79d: + result = new TL_updateWebViewResultSent(); + break; case 0x6e6fe51c: result = new TL_updateDialogPinned(); break; @@ -27581,6 +28088,9 @@ public class TLRPC { case 0xfa0f3ca2: result = new TL_updatePinnedDialogs(); break; + case 0x74d8be99: + result = new TL_updateSavedRingtones(); + break; case 0xb4afcfb0: result = new TL_updatePeerLocated(); break; @@ -27617,6 +28127,9 @@ public class TLRPC { case 0xf227868c: result = new TL_updateUserPhoto(); break; + case 0x17b7a20b: + result = new TL_updateAttachMenuBots(); + break; case 0x3504914f: result = new TL_updateDialogFilters(); break; @@ -27656,6 +28169,9 @@ public class TLRPC { case 0x54c01850: result = new TL_updateChatDefaultBannedRights(); break; + case 0x14b85813: + result = new TL_updateBotMenuButton(); + break; } if (result == null && exception) { throw new RuntimeException(String.format("can't parse magic %x in Update", constructor)); @@ -28669,6 +29185,14 @@ public class TLRPC { } } + public static class TL_updateSavedRingtones extends Update { + public static int constructor = 0x74d8be99; + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } + public static class TL_updateLangPack extends Update { public static int constructor = 0x56022f4d; @@ -41981,13 +42505,18 @@ public class TLRPC { public String theme_emoticon; public long id; public String private_forward_name; + public TL_chatAdminRights bot_group_admin_rights; + public TL_chatAdminRights bot_broadcast_admin_rights; public static UserFull TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { UserFull result = null; switch (constructor) { - case 0xcf366521: + case 0x8c72ea81: result = new TL_userFull(); break; + case 0xcf366521: + result = new TL_userFull_layer139(); + break; case 0xd697ff05: result = new TL_userFull_layer134(); break; @@ -42015,6 +42544,99 @@ public class TLRPC { } public static class TL_userFull extends UserFull { + public static int constructor = 0x8c72ea81; + + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + blocked = (flags & 1) != 0; + phone_calls_available = (flags & 16) != 0; + phone_calls_private = (flags & 32) != 0; + can_pin_message = (flags & 128) != 0; + has_scheduled = (flags & 4096) != 0; + video_calls_available = (flags & 8192) != 0; + id = stream.readInt64(exception); + if ((flags & 2) != 0) { + about = stream.readString(exception); + } + settings = TL_peerSettings.TLdeserialize(stream, stream.readInt32(exception), exception); + if ((flags & 4) != 0) { + profile_photo = Photo.TLdeserialize(stream, stream.readInt32(exception), exception); + } + notify_settings = PeerNotifySettings.TLdeserialize(stream, stream.readInt32(exception), exception); + if ((flags & 8) != 0) { + bot_info = BotInfo.TLdeserialize(stream, stream.readInt32(exception), exception); + } + if ((flags & 64) != 0) { + pinned_msg_id = stream.readInt32(exception); + } + common_chats_count = stream.readInt32(exception); + if ((flags & 2048) != 0) { + folder_id = stream.readInt32(exception); + } + if ((flags & 16384) != 0) { + ttl_period = stream.readInt32(exception); + } + if ((flags & 32768) != 0) { + theme_emoticon = stream.readString(exception); + } + if ((flags & 65536) != 0) { + private_forward_name = stream.readString(exception); + } + if ((flags & 131072) != 0) { + bot_group_admin_rights = TL_chatAdminRights.TLdeserialize(stream, stream.readInt32(exception), exception); + } + if ((flags & 262144) != 0) { + bot_broadcast_admin_rights = TL_chatAdminRights.TLdeserialize(stream, stream.readInt32(exception), exception); + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + flags = blocked ? (flags | 1) : (flags &~ 1); + flags = phone_calls_available ? (flags | 16) : (flags &~ 16); + flags = phone_calls_private ? (flags | 32) : (flags &~ 32); + flags = can_pin_message ? (flags | 128) : (flags &~ 128); + flags = has_scheduled ? (flags | 4096) : (flags &~ 4096); + flags = video_calls_available ? (flags | 8192) : (flags &~ 8192); + stream.writeInt32(flags); + stream.writeInt64(id); + if ((flags & 2) != 0) { + stream.writeString(about); + } + settings.serializeToStream(stream); + if ((flags & 4) != 0) { + profile_photo.serializeToStream(stream); + } + notify_settings.serializeToStream(stream); + if ((flags & 8) != 0) { + bot_info.serializeToStream(stream); + } + if ((flags & 64) != 0) { + stream.writeInt32(pinned_msg_id); + } + stream.writeInt32(common_chats_count); + if ((flags & 2048) != 0) { + stream.writeInt32(folder_id); + } + if ((flags & 16384) != 0) { + stream.writeInt32(ttl_period); + } + if ((flags & 32768) != 0) { + stream.writeString(theme_emoticon); + } + if ((flags & 65536) != 0) { + stream.writeString(private_forward_name); + } + if ((flags & 131072) != 0) { + bot_group_admin_rights.serializeToStream(stream); + } + if ((flags & 262144) != 0) { + bot_broadcast_admin_rights.serializeToStream(stream); + } + } + } + + public static class TL_userFull_layer139 extends UserFull { public static int constructor = 0xcf366521; public void readParams(AbstractSerializedData stream, boolean exception) { @@ -49879,6 +50501,27 @@ public class TLRPC { } } + public static class TL_messages_sendWebViewData extends TLObject { + public static int constructor = 0xdc0242c8; + + public InputUser bot; + public long random_id; + public String button_text; + public String data; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return Updates.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + bot.serializeToStream(stream); + stream.writeInt64(random_id); + stream.writeString(button_text); + stream.writeString(data); + } + } + public static class TL_messages_getMessagesReactions extends TLObject { public static int constructor = 0x8bba90e6; @@ -51478,17 +52121,21 @@ public class TLRPC { } public static class TL_channels_deleteHistory extends TLObject { - public static int constructor = 0xaf369d42; + public static int constructor = 0x9baa9647; + public int flags; + public boolean for_everyone; public InputChannel channel; public int max_id; public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { - return Bool.TLdeserialize(stream, constructor, exception); + return Updates.TLdeserialize(stream, constructor, exception); } public void serializeToStream(AbstractSerializedData stream) { stream.writeInt32(constructor); + flags = for_everyone ? (flags | 1) : (flags &~ 1); + stream.writeInt32(flags); channel.serializeToStream(stream); stream.writeInt32(max_id); } @@ -57562,6 +58209,956 @@ public class TLRPC { } } + public static class TL_attachMenuBot extends TLObject { + public static int constructor = 0xe93cb772; + + public int flags; + public boolean inactive; + public long bot_id; + public String short_name; + public ArrayList icons = new ArrayList<>(); + + public static TL_attachMenuBot TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + if (TL_attachMenuBot.constructor != constructor) { + if (exception) { + throw new RuntimeException(String.format("can't parse magic %x in TL_attachMenuBot", constructor)); + } else { + return null; + } + } + TL_attachMenuBot result = new TL_attachMenuBot(); + result.readParams(stream, exception); + return result; + } + + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + inactive = (flags & 1) != 0; + bot_id = stream.readInt64(exception); + short_name = 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_attachMenuBotIcon object = TL_attachMenuBotIcon.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + icons.add(object); + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + flags = inactive ? (flags | 1) : (flags &~ 1); + stream.writeInt32(flags); + stream.writeInt64(bot_id); + stream.writeString(short_name); + stream.writeInt32(0x1cb5c415); + int count = icons.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + icons.get(a).serializeToStream(stream); + } + } + } + + public static abstract class AttachMenuBots extends TLObject { + + public static AttachMenuBots TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + AttachMenuBots result = null; + switch (constructor) { + case 0xf1d88a5c: + result = new TL_attachMenuBotsNotModified(); + break; + case 0x3c4301c0: + result = new TL_attachMenuBots(); + break; + } + if (result == null && exception) { + throw new RuntimeException(String.format("can't parse magic %x in AttachMenuBots", constructor)); + } + if (result != null) { + result.readParams(stream, exception); + } + return result; + } + } + + public static class TL_attachMenuBotsNotModified extends AttachMenuBots { + public static int constructor = 0xf1d88a5c; + + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } + + public static class TL_attachMenuBots extends AttachMenuBots { + public static int constructor = 0x3c4301c0; + + public long hash; + public ArrayList bots = new ArrayList<>(); + public ArrayList users = new ArrayList<>(); + + public void readParams(AbstractSerializedData stream, boolean exception) { + hash = stream.readInt64(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_attachMenuBot object = TL_attachMenuBot.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + bots.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.writeInt64(hash); + stream.writeInt32(0x1cb5c415); + int count = bots.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + bots.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 class TL_updateAttachMenuBots extends Update { + public static int constructor = 0x17b7a20b; + + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } + + public static class TL_messages_webViewResult extends TLObject { + public static int constructor = 0xaadf159b; + + public BotInlineResult result; + public ArrayList users = new ArrayList<>(); + + public static TL_messages_webViewResult TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + if (TL_messages_webViewResult.constructor != constructor) { + if (exception) { + throw new RuntimeException(String.format("can't parse magic %x in TL_messages_webViewResult", constructor)); + } else { + return null; + } + } + TL_messages_webViewResult result = new TL_messages_webViewResult(); + result.readParams(stream, exception); + return result; + } + + public void readParams(AbstractSerializedData stream, boolean exception) { + result = BotInlineResult.TLdeserialize(stream, stream.readInt32(exception), exception); + int magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + int count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + User object = User.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + users.add(object); + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + result.serializeToStream(stream); + stream.writeInt32(0x1cb5c415); + int count = users.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + users.get(a).serializeToStream(stream); + } + } + } + + public static class TL_keyboardButtonWebView extends KeyboardButton { + public static int constructor = 0x13767230; + + public void readParams(AbstractSerializedData stream, boolean exception) { + text = stream.readString(exception); + url = stream.readString(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeString(text); + stream.writeString(url); + } + } + + public static class TL_messages_getAttachMenuBots extends TLObject { + public static int constructor = 0x16fcc2cb; + + public long hash; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return AttachMenuBots.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt64(hash); + } + } + + public static class TL_messages_toggleBotInAttachMenu extends TLObject { + public static int constructor = 0x1aee33af; + + public InputUser bot; + public boolean enabled; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return Bool.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + bot.serializeToStream(stream); + stream.writeBool(enabled); + } + } + + public static class TL_webViewResultUrl extends TLObject { + public static int constructor = 0xc14557c; + + public long query_id; + public String url; + + public static TL_webViewResultUrl TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + if (TL_webViewResultUrl.constructor != constructor) { + if (exception) { + throw new RuntimeException(String.format("can't parse magic %x in TL_webViewResultUrl", constructor)); + } else { + return null; + } + } + TL_webViewResultUrl result = new TL_webViewResultUrl(); + result.readParams(stream, exception); + return result; + } + + public void readParams(AbstractSerializedData stream, boolean exception) { + query_id = stream.readInt64(exception); + url = stream.readString(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt64(query_id); + stream.writeString(url); + } + } + + public static class TL_messages_requestWebView extends TLObject { + public static int constructor = 0xfa04dff; + + public int flags; + public boolean silent; + public boolean background; + public InputPeer peer; + public InputUser bot; + public String url; + public String start_param; + public TL_dataJSON theme_params; + public int reply_to_msg_id; + public boolean from_bot_menu; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return TL_webViewResultUrl.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + flags = silent ? (flags | 32) : (flags &~ 32); + flags = background ? (flags | 64) : (flags &~ 64); + flags = from_bot_menu ? (flags | 16) : (flags &~ 16); + stream.writeInt32(flags); + peer.serializeToStream(stream); + bot.serializeToStream(stream); + if ((flags & 2) != 0) { + stream.writeString(url); + } + if ((flags & 8) != 0) { + stream.writeString(start_param); + } + if ((flags & 4) != 0) { + theme_params.serializeToStream(stream); + } + if ((flags & 1) != 0) { + stream.writeInt32(reply_to_msg_id); + } + } + } + + public static class TL_messages_prolongWebView extends TLObject { + public static int constructor = 0xd22ad148; + + public int flags; + public boolean silent; + public InputPeer peer; + public InputUser bot; + public long query_id; + public int reply_to_msg_id; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return Bool.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + flags = silent ? (flags | 32) : (flags &~ 32); + stream.writeInt32(flags); + peer.serializeToStream(stream); + bot.serializeToStream(stream); + stream.writeInt64(query_id); + if ((flags & 1) != 0) { + stream.writeInt32(reply_to_msg_id); + } + } + } + + public static class TL_messages_requestSimpleWebView extends TLObject { + public static int constructor = 0x6abb2f73; + + public int flags; + public InputUser bot; + public String url; + public TL_dataJSON theme_params; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return TL_simpleWebViewResultUrl.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(flags); + bot.serializeToStream(stream); + stream.writeString(url); + if ((flags & 1) != 0) { + theme_params.serializeToStream(stream); + } + } + } + + public static class TL_messages_sendWebViewResultMessage extends TLObject { + public static int constructor = 0xddcf50eb; + + public long query_id; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return TL_webViewMessageSent.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt64(query_id); + } + } + + public static class TL_messages_setWebViewResult extends TLObject { + public static int constructor = 0xe41cd11d; + + public long query_id; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return Bool.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt64(query_id); + } + } + + public static class TL_messages_getWebViewResult extends TLObject { + public static int constructor = 0x22b6c214; + + public InputPeer peer; + public InputUser bot; + public long query_id; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return TL_messages_webViewResult.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + peer.serializeToStream(stream); + bot.serializeToStream(stream); + stream.writeInt64(query_id); + } + } + + public static class TL_attachMenuBotsBot extends TLObject { + public static int constructor = 0x93bf667f; + + public TL_attachMenuBot bot; + public ArrayList users = new ArrayList<>(); + + public static TL_attachMenuBotsBot TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + if (TL_attachMenuBotsBot.constructor != constructor) { + if (exception) { + throw new RuntimeException(String.format("can't parse magic %x in TL_attachMenuBotsBot", constructor)); + } else { + return null; + } + } + TL_attachMenuBotsBot result = new TL_attachMenuBotsBot(); + result.readParams(stream, exception); + return result; + } + + public void readParams(AbstractSerializedData stream, boolean exception) { + bot = TL_attachMenuBot.TLdeserialize(stream, stream.readInt32(exception), exception); + int magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + int count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + User object = User.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + users.add(object); + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + bot.serializeToStream(stream); + stream.writeInt32(0x1cb5c415); + int count = users.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + users.get(a).serializeToStream(stream); + } + } + } + + public static class TL_simpleWebViewResultUrl extends TLObject { + public static int constructor = 0x882f76bb; + + public String url; + + public static TL_simpleWebViewResultUrl TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + if (TL_simpleWebViewResultUrl.constructor != constructor) { + if (exception) { + throw new RuntimeException(String.format("can't parse magic %x in TL_simpleWebViewResultUrl", constructor)); + } else { + return null; + } + } + TL_simpleWebViewResultUrl result = new TL_simpleWebViewResultUrl(); + result.readParams(stream, exception); + return result; + } + + public void readParams(AbstractSerializedData stream, boolean exception) { + url = stream.readString(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeString(url); + } + } + + public static class TL_webViewMessageSent extends TLObject { + public static int constructor = 0xc94511c; + + public int flags; + public TL_inputBotInlineMessageID msg_id; + + public static TL_webViewMessageSent TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + if (TL_webViewMessageSent.constructor != constructor) { + if (exception) { + throw new RuntimeException(String.format("can't parse magic %x in TL_webViewMessageSent", constructor)); + } else { + return null; + } + } + TL_webViewMessageSent result = new TL_webViewMessageSent(); + result.readParams(stream, exception); + return result; + } + + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + if ((flags & 1) != 0) { + msg_id = TL_inputBotInlineMessageID.TLdeserialize(stream, stream.readInt32(exception), exception); + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(flags); + if ((flags & 1) != 0) { + msg_id.serializeToStream(stream); + } + } + } + + public static class TL_updateWebViewResultSent extends Update { + public static int constructor = 0x1592b79d; + + public long query_id; + + public void readParams(AbstractSerializedData stream, boolean exception) { + query_id = stream.readInt64(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt64(query_id); + } + } + + public static class TL_keyboardButtonSimpleWebView extends KeyboardButton { + public static int constructor = 0xa0c0505c; + + public void readParams(AbstractSerializedData stream, boolean exception) { + text = stream.readString(exception); + url = stream.readString(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeString(text); + stream.writeString(url); + } + } + + public static class TL_messages_getAttachMenuBot extends TLObject { + public static int constructor = 0x77216192; + + public InputUser bot; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return TL_attachMenuBotsBot.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + bot.serializeToStream(stream); + } + } + + public static abstract class account_SavedRingtones extends TLObject { + + public static account_SavedRingtones TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + account_SavedRingtones result = null; + switch (constructor) { + case 0xfbf6e8b1: + result = new TL_account_savedRingtonesNotModified(); + break; + case 0xc1e92cc5: + result = new TL_account_savedRingtones(); + break; + } + if (result == null && exception) { + throw new RuntimeException(String.format("can't parse magic %x in account_SavedRingtones", constructor)); + } + if (result != null) { + result.readParams(stream, exception); + } + return result; + } + } + + public static class TL_account_savedRingtonesNotModified extends account_SavedRingtones { + public static int constructor = 0xfbf6e8b1; + + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } + + public static class TL_account_savedRingtones extends account_SavedRingtones { + public static int constructor = 0xc1e92cc5; + + public long hash; + public ArrayList ringtones = new ArrayList<>(); + + public void readParams(AbstractSerializedData stream, boolean exception) { + hash = stream.readInt64(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++) { + Document object = Document.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + ringtones.add(object); + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt64(hash); + stream.writeInt32(0x1cb5c415); + int count = ringtones.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + ringtones.get(a).serializeToStream(stream); + } + } + } + + public static class TL_account_uploadRingtone extends TLObject { + public static int constructor = 0x831a83a2; + + public InputFile file; + public String file_name; + public String mime_type; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return Document.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + file.serializeToStream(stream); + stream.writeString(file_name); + stream.writeString(mime_type); + } + } + + public static class TL_account_getSavedRingtones extends TLObject { + public static int constructor = 0xe1902288; + + public long hash; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return account_SavedRingtones.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt64(hash); + } + } + + public static class TL_account_saveRingtone extends TLObject { + public static int constructor = 0x3dea5b03; + + public InputDocument id; + public boolean unsave; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return account_SavedRingtone.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + id.serializeToStream(stream); + stream.writeBool(unsave); + } + } + + public static class TL_attachMenuBotIconColor extends TLObject { + public static int constructor = 0x4576f3f0; + + public String name; + public int color; + + public static TL_attachMenuBotIconColor TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + if (TL_attachMenuBotIconColor.constructor != constructor) { + if (exception) { + throw new RuntimeException(String.format("can't parse magic %x in TL_attachMenuBotIconColor", constructor)); + } else { + return null; + } + } + TL_attachMenuBotIconColor result = new TL_attachMenuBotIconColor(); + result.readParams(stream, exception); + return result; + } + + public void readParams(AbstractSerializedData stream, boolean exception) { + name = stream.readString(exception); + color = stream.readInt32(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeString(name); + stream.writeInt32(color); + } + } + + public static class TL_attachMenuBotIcon extends TLObject { + public static int constructor = 0xb2a7386b; + + public int flags; + public String name; + public Document icon; + public ArrayList colors = new ArrayList<>(); + + public static TL_attachMenuBotIcon TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + if (TL_attachMenuBotIcon.constructor != constructor) { + if (exception) { + throw new RuntimeException(String.format("can't parse magic %x in TL_attachMenuBotIcon", constructor)); + } else { + return null; + } + } + TL_attachMenuBotIcon result = new TL_attachMenuBotIcon(); + result.readParams(stream, exception); + return result; + } + + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + name = stream.readString(exception); + icon = Document.TLdeserialize(stream, stream.readInt32(exception), 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 a = 0; a < count; a++) { + TL_attachMenuBotIconColor object = TL_attachMenuBotIconColor.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + colors.add(object); + } + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(flags); + stream.writeString(name); + icon.serializeToStream(stream); + if ((flags & 1) != 0) { + stream.writeInt32(0x1cb5c415); + int count = colors.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + colors.get(a).serializeToStream(stream); + } + } + } + } + + public static abstract class BotMenuButton extends TLObject { + + public static BotMenuButton TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + BotMenuButton result = null; + switch (constructor) { + case 0xc7b57ce6: + result = new TL_botMenuButton(); + break; + case 0x7533a588: + result = new TL_botMenuButtonDefault(); + break; + case 0x4258c205: + result = new TL_botMenuButtonCommands(); + break; + } + if (result == null && exception) { + throw new RuntimeException(String.format("can't parse magic %x in BotMenuButton", constructor)); + } + if (result != null) { + result.readParams(stream, exception); + } + return result; + } + } + + public static class TL_botMenuButton extends BotMenuButton { + public static int constructor = 0xc7b57ce6; + + public String text; + public String url; + + public void readParams(AbstractSerializedData stream, boolean exception) { + text = stream.readString(exception); + url = stream.readString(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeString(text); + stream.writeString(url); + } + } + + public static class TL_botMenuButtonDefault extends BotMenuButton { + public static int constructor = 0x7533a588; + + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } + + public static class TL_botMenuButtonCommands extends BotMenuButton { + public static int constructor = 0x4258c205; + + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } + + public static class TL_updateBotMenuButton extends Update { + public static int constructor = 0x14b85813; + + public long bot_id; + public BotMenuButton button; + + public void readParams(AbstractSerializedData stream, boolean exception) { + bot_id = stream.readInt64(exception); + button = BotMenuButton.TLdeserialize(stream, stream.readInt32(exception), exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt64(bot_id); + button.serializeToStream(stream); + } + } + + public static class TL_bots_setBotMenuButton extends TLObject { + public static int constructor = 0x4504d54f; + + public InputUser user_id; + public BotMenuButton button; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return Bool.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + user_id.serializeToStream(stream); + button.serializeToStream(stream); + } + } + + public static class TL_bots_getBotMenuButton extends TLObject { + public static int constructor = 0x9c60eb28; + + public InputUser user_id; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return BotMenuButton.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + user_id.serializeToStream(stream); + } + } + + public static abstract class account_SavedRingtone extends TLObject { + + public static account_SavedRingtone TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + account_SavedRingtone result = null; + switch (constructor) { + case 0x1f307eb7: + result = new TL_account_savedRingtoneConverted(); + break; + case 0xb7263f6d: + result = new TL_account_savedRingtone(); + break; + } + if (result == null && exception) { + throw new RuntimeException(String.format("can't parse magic %x in account_SavedRingtone", constructor)); + } + if (result != null) { + result.readParams(stream, exception); + } + return result; + } + } + + public static class TL_account_savedRingtoneConverted extends account_SavedRingtone { + public static int constructor = 0x1f307eb7; + + public Document document; + + public void readParams(AbstractSerializedData stream, boolean exception) { + document = Document.TLdeserialize(stream, stream.readInt32(exception), exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + document.serializeToStream(stream); + } + } + + public static class TL_account_savedRingtone extends account_SavedRingtone { + public static int constructor = 0xb7263f6d; + + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } //functions public static class Vector extends TLObject { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBarMenu.java b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBarMenu.java index 7290a988a..283670468 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBarMenu.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBarMenu.java @@ -14,7 +14,10 @@ import android.view.View; import android.view.ViewGroup; import android.widget.LinearLayout; +import com.google.android.exoplayer2.util.Log; + import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.R; import org.telegram.ui.Adapters.FiltersView; import org.telegram.ui.Components.RLottieDrawable; @@ -91,7 +94,15 @@ public class ActionBarMenu extends LinearLayout { } public ActionBarMenuItem addItem(int id, int icon, CharSequence text, int backgroundColor, Drawable drawable, int width, CharSequence title, Theme.ResourcesProvider resourcesProvider) { - ActionBarMenuItem menuItem = new ActionBarMenuItem(getContext(), this, backgroundColor, isActionMode ? parentActionBar.itemsActionModeColor : parentActionBar.itemsColor, text != null, resourcesProvider); + ActionBarMenuItem menuItem = new ActionBarMenuItem(getContext(), this, backgroundColor, isActionMode ? parentActionBar.itemsActionModeColor : parentActionBar.itemsColor, text != null, resourcesProvider) { + @Override + public void setVisibility(int visibility) { + super.setVisibility(visibility); + if (icon == R.drawable.ic_ab_other && (id == 0 || id == 14)) { + Log.d("kek", id + " " + (View.VISIBLE == visibility)); + } + } + }; menuItem.setTag(id); if (text != null) { menuItem.textView.setText(text); 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 4598a8f6b..af93f999e 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBarMenuItem.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBarMenuItem.java @@ -50,6 +50,7 @@ import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.TextView; +import androidx.annotation.Nullable; import androidx.core.content.ContextCompat; import androidx.core.graphics.ColorUtils; @@ -169,6 +170,8 @@ public class ActionBarMenuItem extends FrameLayout { private View showSubMenuFrom; private final Theme.ResourcesProvider resourcesProvider; + private OnClickListener onClickListener; + public ActionBarMenuItem(Context context, ActionBarMenu menu, int backgroundColor, int iconColor) { this(context, menu, backgroundColor, iconColor, false); } @@ -337,7 +340,7 @@ public class ActionBarMenuItem extends FrameLayout { } rect = new Rect(); location = new int[2]; - popupLayout = new ActionBarPopupWindow.ActionBarPopupWindowLayout(getContext(), resourcesProvider); + popupLayout = new ActionBarPopupWindow.ActionBarPopupWindowLayout(getContext(), R.drawable.popup_fixed_alert2, resourcesProvider, ActionBarPopupWindow.ActionBarPopupWindowLayout.FLAG_USE_SWIPEBACK); popupLayout.setOnTouchListener((v, event) -> { if (event.getActionMasked() == MotionEvent.ACTION_DOWN) { if (popupWindow != null && popupWindow.isShowing()) { @@ -354,6 +357,14 @@ public class ActionBarMenuItem extends FrameLayout { popupWindow.dismiss(); } }); + + if (popupLayout.getSwipeBack() != null) { + popupLayout.getSwipeBack().setOnClickListener(view -> { + if (popupWindow != null) { + popupWindow.dismiss(); + } + }); + } } public void removeAllSubItems() { @@ -511,6 +522,35 @@ public class ActionBarMenuItem extends FrameLayout { return cell; } + public ActionBarMenuSubItem addSwipeBackItem(int icon, Drawable iconDrawable, String text, View viewToSwipeBack) { + createPopupLayout(); + + ActionBarMenuSubItem cell = new ActionBarMenuSubItem(getContext(), false, false, false, resourcesProvider); + cell.setTextAndIcon(text, icon, iconDrawable); + cell.setMinimumWidth(AndroidUtilities.dp(196)); + cell.setRightIcon(R.drawable.msg_arrowright); + popupLayout.addView(cell); + LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams) cell.getLayoutParams(); + if (LocaleController.isRTL) { + layoutParams.gravity = Gravity.RIGHT; + } + layoutParams.width = LayoutHelper.MATCH_PARENT; + layoutParams.height = AndroidUtilities.dp(48); + cell.setLayoutParams(layoutParams); + int swipeBackIndex = popupLayout.addViewToSwipeBack(viewToSwipeBack); + cell.openSwipeBackLayout = () -> { + if (popupLayout.getSwipeBack() != null) { + popupLayout.getSwipeBack().openForeground(swipeBackIndex); + } + }; + cell.setOnClickListener(view -> { + cell.openSwipeBack(); + }); + + popupLayout.swipeBackGravityRight = true; + return cell; + } + public View addDivider(int color) { createPopupLayout(); @@ -579,6 +619,9 @@ public class ActionBarMenuItem extends FrameLayout { } public ActionBarPopupWindow.ActionBarPopupWindowLayout getPopupLayout() { + if (popupLayout == null) { + createPopupLayout(); + } return popupLayout; } @@ -613,7 +656,11 @@ public class ActionBarMenuItem extends FrameLayout { @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { popupLayout.measure(widthMeasureSpec, heightMeasureSpec); - topView.getLayoutParams().width = popupLayout.getMeasuredWidth() - AndroidUtilities.dp(16); + if (popupLayout.getSwipeBack() != null) { + topView.getLayoutParams().width = popupLayout.getSwipeBack().getChildAt(0).getMeasuredWidth(); + } else { + topView.getLayoutParams().width = popupLayout.getMeasuredWidth() - AndroidUtilities.dp(16); + } super.onMeasure(widthMeasureSpec, heightMeasureSpec); } }; @@ -629,6 +676,7 @@ public class ActionBarMenuItem extends FrameLayout { linearLayout.addView(frameLayout, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT)); linearLayout.addView(popupLayout, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, 0, 0, -AndroidUtilities.dp(4), 0, 0)); container = linearLayout; + popupLayout.setTopView(frameLayout); } popupWindow = new ActionBarPopupWindow(container, LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT); if (animationEnabled && Build.VERSION.SDK_INT >= 19) { @@ -673,6 +721,9 @@ public class ActionBarMenuItem extends FrameLayout { updateOrShowPopup(true, false); } popupLayout.updateRadialSelectors(); + if (popupLayout.getSwipeBack() != null) { + popupLayout.getSwipeBack().closeForeground(false); + } popupWindow.startAnimation(); } public void toggleSubMenu() { @@ -1389,6 +1440,15 @@ public class ActionBarMenuItem extends FrameLayout { return this; } + public OnClickListener getOnClickListener() { + return onClickListener; + } + + @Override + public void setOnClickListener(@Nullable OnClickListener l) { + super.setOnClickListener(onClickListener = l); + } + private void checkClearButton() { if (clearButton != null) { if (!hasRemovableFilters() && TextUtils.isEmpty(searchField.getText()) && @@ -1853,4 +1913,27 @@ public class ActionBarMenuItem extends FrameLayout { return color != null ? color : Theme.getColor(key); } } + + public View addColoredGap() { + createPopupLayout(); + View gap = new ActionBarPopupWindow.GapView(getContext(), Theme.key_graySection); + gap.setTag(R.id.fit_width_tag, 1); + popupLayout.addView(gap, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 8)); + return gap; + } + + public static ActionBarMenuSubItem addItem(ActionBarPopupWindow.ActionBarPopupWindowLayout windowLayout, int icon, String text, boolean needCheck, Theme.ResourcesProvider resourcesProvider) { + ActionBarMenuSubItem cell = new ActionBarMenuSubItem(windowLayout.getContext(), needCheck, false, false, resourcesProvider); + cell.setTextAndIcon(text, icon); + cell.setMinimumWidth(AndroidUtilities.dp(196)); + windowLayout.addView(cell); + LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams) cell.getLayoutParams(); + if (LocaleController.isRTL) { + layoutParams.gravity = Gravity.RIGHT; + } + layoutParams.width = LayoutHelper.MATCH_PARENT; + layoutParams.height = AndroidUtilities.dp(48); + cell.setLayoutParams(layoutParams); + return cell; + } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBarMenuSubItem.java b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBarMenuSubItem.java index c52acdb62..6e97e7e0c 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBarMenuSubItem.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBarMenuSubItem.java @@ -34,6 +34,7 @@ public class ActionBarMenuSubItem extends FrameLayout { private int itemHeight = 48; private final Theme.ResourcesProvider resourcesProvider; + Runnable openSwipeBackLayout; public ActionBarMenuSubItem(Context context, boolean top, boolean bottom) { this(context, false, top, bottom); @@ -108,7 +109,7 @@ public class ActionBarMenuSubItem extends FrameLayout { if (rightIcon == null) { rightIcon = new ImageView(getContext()); rightIcon.setScaleType(ImageView.ScaleType.CENTER); - rightIcon.setColorFilter(textColor, PorterDuff.Mode.MULTIPLY); + rightIcon.setColorFilter(iconColor, PorterDuff.Mode.MULTIPLY); if (LocaleController.isRTL) { rightIcon.setScaleX(-1); } @@ -237,4 +238,14 @@ public class ActionBarMenuSubItem extends FrameLayout { public CheckBox2 getCheckView() { return checkView; } + + public void openSwipeBack() { + if (openSwipeBackLayout != null) { + openSwipeBackLayout.run(); + } + } + + public ImageView getRightIcon() { + return rightIcon; + } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBarPopupWindow.java b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBarPopupWindow.java index 067161535..743185e4a 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBarPopupWindow.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBarPopupWindow.java @@ -16,13 +16,13 @@ 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.Rect; import android.graphics.drawable.Drawable; import android.os.Build; import android.view.KeyEvent; -import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; import android.view.ViewTreeObserver; @@ -36,8 +36,6 @@ import android.widget.ScrollView; import androidx.annotation.Keep; import androidx.annotation.Nullable; -import com.google.android.exoplayer2.util.Log; - import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.FileLog; import org.telegram.messenger.NotificationCenter; @@ -90,6 +88,8 @@ public class ActionBarPopupWindow extends PopupWindow { public static class ActionBarPopupWindowLayout extends FrameLayout { public final static int FLAG_USE_SWIPEBACK = 1; + public boolean updateAnimation; + public boolean swipeBackGravityRight; private OnDispatchKeyEventListener mOnDispatchKeyEventListener; private float backScaleX = 1; @@ -114,6 +114,7 @@ public class ActionBarPopupWindow extends PopupWindow { private boolean fitItems; private final Theme.ResourcesProvider resourcesProvider; + private View topView; public ActionBarPopupWindowLayout(Context context) { this(context, null); @@ -130,14 +131,16 @@ public class ActionBarPopupWindow extends PopupWindow { public ActionBarPopupWindowLayout(Context context, int resId, Theme.ResourcesProvider resourcesProvider, int flags) { super(context); this.resourcesProvider = resourcesProvider; - - backgroundDrawable = getResources().getDrawable(resId).mutate(); + if (resId != 0) { + backgroundDrawable = getResources().getDrawable(resId).mutate(); + setPadding(AndroidUtilities.dp(8), AndroidUtilities.dp(8), AndroidUtilities.dp(8), AndroidUtilities.dp(8)); + } if (backgroundDrawable != null) { backgroundDrawable.getPadding(bgPaddings); + setBackgroundColor(getThemedColor(Theme.key_actionBarDefaultSubmenuBackground)); } - setBackgroundColor(getThemedColor(Theme.key_actionBarDefaultSubmenuBackground)); - setPadding(AndroidUtilities.dp(8), AndroidUtilities.dp(8), AndroidUtilities.dp(8), AndroidUtilities.dp(8)); + setWillNotDraw(false); if ((flags & FLAG_USE_SWIPEBACK) > 0) { @@ -171,11 +174,14 @@ public class ActionBarPopupWindow extends PopupWindow { } Object tag = view.getTag(R.id.width_tag); Object tag2 = view.getTag(R.id.object_tag); + Object fitToWidth = view.getTag(R.id.fit_width_tag); if (tag != null) { view.getLayoutParams().width = LayoutHelper.WRAP_CONTENT; } measureChildWithMargins(view, widthMeasureSpec, 0, heightMeasureSpec, 0); - if (!(tag instanceof Integer) && tag2 == null) { + if (fitToWidth != null) { + + } else if (!(tag instanceof Integer) && tag2 == null) { maxWidth = Math.max(maxWidth, view.getMeasuredWidth()); continue; } else if (tag instanceof Integer) { @@ -213,7 +219,7 @@ public class ActionBarPopupWindow extends PopupWindow { } public int addViewToSwipeBack(View v) { - swipeBackLayout.addView(v); + swipeBackLayout.addView(v, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT)); return swipeBackLayout.getChildCount() - 1; } @@ -234,7 +240,7 @@ public class ActionBarPopupWindow extends PopupWindow { } public void setBackgroundColor(int color) { - if (backgroundColor != color) { + if (backgroundColor != color && backgroundDrawable != null) { backgroundDrawable.setColorFilter(new PorterDuffColorFilter(backgroundColor = color, PorterDuff.Mode.MULTIPLY)); } } @@ -265,12 +271,12 @@ public class ActionBarPopupWindow extends PopupWindow { public void setBackScaleY(float value) { if (backScaleY != value) { backScaleY = value; - if (animationEnabled) { + if (animationEnabled && updateAnimation) { int height = getMeasuredHeight() - AndroidUtilities.dp(16); if (shownFromBotton) { for (int a = lastStartedChild; a >= 0; a--) { View child = getItemAt(a); - if (child.getVisibility() != VISIBLE) { + if (child.getVisibility() != VISIBLE || child instanceof GapView) { continue; } Integer position = positions.get(child); @@ -371,20 +377,50 @@ public class ActionBarPopupWindow extends PopupWindow { return super.dispatchKeyEvent(event); } + @Override + protected void dispatchDraw(Canvas canvas) { + if (swipeBackGravityRight) { + setTranslationX(getMeasuredWidth() * (1f - backScaleX)); + if (topView != null) { + topView.setTranslationX(getMeasuredWidth() * (1f - backScaleX)); + topView.setAlpha(1f - swipeBackLayout.transitionProgress); + float h = topView.getMeasuredHeight() - AndroidUtilities.dp(16); + float yOffset = -h * swipeBackLayout.transitionProgress; + topView.setTranslationY(yOffset); + setTranslationY(yOffset); + } + } + super.dispatchDraw(canvas); + } + @Override protected void onDraw(Canvas canvas) { if (backgroundDrawable != null) { int start = gapStartY - scrollView.getScrollY(); int end = gapEndY - scrollView.getScrollY(); + boolean hasGap = false; + for (int i = 0; i < linearLayout.getChildCount(); i++) { + if (linearLayout.getChildAt(i) instanceof GapView) { + hasGap = true; + break; + } + } for (int a = 0; a < 2; a++) { if (a == 1 && start < -AndroidUtilities.dp(16)) { break; } - if (gapStartY != -1000000) { + boolean needRestore = false; + boolean applyAlpha = true; + if (hasGap && backAlpha != 255) { + canvas.saveLayerAlpha(0, bgPaddings.top, getMeasuredWidth(), getMeasuredHeight(), backAlpha, Canvas.ALL_SAVE_FLAG); + needRestore = true; + applyAlpha = false; + } else if (gapStartY != -1000000) { + needRestore = true; canvas.save(); canvas.clipRect(0, bgPaddings.top, getMeasuredWidth(), getMeasuredHeight()); } - backgroundDrawable.setAlpha(backAlpha); + backgroundDrawable.setAlpha(applyAlpha ? backAlpha : 255); if (shownFromBotton) { final int height = getMeasuredHeight(); backgroundDrawable.setBounds(0, (int) (height * (1.0f - backScaleY)), (int) (getMeasuredWidth() * backScaleX), height); @@ -407,7 +443,33 @@ public class ActionBarPopupWindow extends PopupWindow { } } backgroundDrawable.draw(canvas); - if (gapStartY != -1000000) { + + if (hasGap) { + canvas.save(); + AndroidUtilities.rectTmp2.set(backgroundDrawable.getBounds()); + AndroidUtilities.rectTmp2.inset(AndroidUtilities.dp(8), AndroidUtilities.dp(8)); + canvas.clipRect(AndroidUtilities.rectTmp2); + for (int i = 0; i < linearLayout.getChildCount(); i++) { + if (linearLayout.getChildAt(i) instanceof GapView) { + canvas.save(); + float x = 0, y = 0; + View view = linearLayout.getChildAt(i) ; + while (view != this) { + x += view.getX(); + y += view.getY(); + view = (View) view.getParent(); + if (view == null) { + return; + } + } + canvas.translate(x, y); + linearLayout.getChildAt(i).draw(canvas); + canvas.restore(); + } + } + canvas.restore(); + } + if (needRestore) { canvas.restore(); } } @@ -485,6 +547,10 @@ public class ActionBarPopupWindow extends PopupWindow { public int getVisibleHeight() { return (int) (getMeasuredHeight() * backScaleY); } + + public void setTopView(View topView) { + this.topView = topView; + } } public ActionBarPopupWindow() { @@ -582,6 +648,26 @@ public class ActionBarPopupWindow extends PopupWindow { wm.updateViewLayout(container, p); } + private void dismissDim() { + View container = getContentView().getRootView(); + Context context = getContentView().getContext(); + WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); + + if (container.getLayoutParams() == null || !(container.getLayoutParams() instanceof WindowManager.LayoutParams)) { + return; + } + WindowManager.LayoutParams p = (WindowManager.LayoutParams) container.getLayoutParams(); + try { + if ((p.flags & WindowManager.LayoutParams.FLAG_DIM_BEHIND) != 0) { + p.flags &= ~WindowManager.LayoutParams.FLAG_DIM_BEHIND; + p.dimAmount = 0.0f; + wm.updateViewLayout(container, p); + } + } catch (Exception e) { + + } + } + @Override public void showAsDropDown(View anchor, int xoff, int yoff) { try { @@ -630,9 +716,14 @@ public class ActionBarPopupWindow extends PopupWindow { } else { content.lastStartedChild = 0; } + float finalsScaleY = 1f; + if (content.getSwipeBack() != null) { + content.getSwipeBack().invalidateTransforms(); + finalsScaleY = content.backScaleY; + } windowAnimatorSet = new AnimatorSet(); windowAnimatorSet.playTogether( - ObjectAnimator.ofFloat(content, "backScaleY", 0.0f, 1.0f), + ObjectAnimator.ofFloat(content, "backScaleY", 0.0f, finalsScaleY), ObjectAnimator.ofInt(content, "backAlpha", 0, 255)); windowAnimatorSet.setDuration(150 + 16 * visibleCount); windowAnimatorSet.addListener(new AnimatorListenerAdapter() { @@ -653,6 +744,9 @@ public class ActionBarPopupWindow extends PopupWindow { int count = content.getItemsCount(); for (int a = 0; a < count; a++) { View child = content.getItemAt(a); + if (child instanceof GapView) { + continue; + } child.setAlpha(child.isEnabled() ? 1f : 0.5f); } } @@ -690,6 +784,7 @@ public class ActionBarPopupWindow extends PopupWindow { public void dismiss(boolean animated) { setFocusable(false); + dismissDim(); if (windowAnimatorSet != null) { if (animated && isClosingAnimated) { return; @@ -766,4 +861,20 @@ public class ActionBarPopupWindow extends PopupWindow { public interface onSizeChangedListener { void onSizeChanged(); } + + public static class GapView extends FrameLayout { + + Paint paint = new Paint(); + String colorKey; + public GapView(Context context, String colorKey) { + super(context); + this.colorKey = colorKey; + } + + @Override + protected void onDraw(Canvas canvas) { + paint.setColor(Theme.getColor(colorKey)); + canvas.drawRect(0, 0, getMeasuredWidth(), getMeasuredHeight(), paint); + } + } } \ No newline at end of file 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 b7b6dc3f0..960089a8e 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/AlertDialog.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/AlertDialog.java @@ -139,6 +139,7 @@ public class AlertDialog extends Dialog implements Drawable.Callback { private ArrayList itemViews = new ArrayList<>(); private float aspectRatio; private boolean dimEnabled = true; + private float dimAlpha = 0.6f; private final Theme.ResourcesProvider resourcesProvider; private boolean topAnimationAutoRepeat = true; @@ -867,7 +868,7 @@ public class AlertDialog extends Dialog implements Drawable.Callback { params.width = WindowManager.LayoutParams.MATCH_PARENT; } else { if (dimEnabled) { - params.dimAmount = 0.6f; + params.dimAmount = dimAlpha; params.flags |= WindowManager.LayoutParams.FLAG_DIM_BEHIND; } else { params.dimAmount = 0f; @@ -1375,6 +1376,11 @@ public class AlertDialog extends Dialog implements Drawable.Callback { return this; } + public Builder setDimAlpha(float dimAlpha) { + alertDialog.dimAlpha = dimAlpha; + return this; + } + public void notDrawBackgroundOnTopView(boolean b) { alertDialog.notDrawBackgroundOnTopView = b; } 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 aa930a356..7d38023e6 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/BaseFragment.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/BaseFragment.java @@ -772,10 +772,14 @@ public abstract class BaseFragment { } Theme.ResourcesProvider resourcesProvider = getResourceProvider(); int color; + String key = Theme.key_actionBarDefault; + if (actionBar != null && actionBar.isActionModeShowed()) { + key = Theme.key_actionBarActionModeDefault; + } if (resourcesProvider != null) { - color = resourcesProvider.getColorOrDefault(Theme.key_actionBarDefault); + color = resourcesProvider.getColorOrDefault(key); } else { - color = Theme.getColor(Theme.key_actionBarDefault, null, true); + color = Theme.getColor(key, null, true); } return ColorUtils.calculateLuminance(color) > 0.7f; } 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 6cf920d2d..159923c23 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/BottomSheet.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/BottomSheet.java @@ -23,6 +23,7 @@ import android.graphics.Paint; import android.graphics.PorterDuff; import android.graphics.PorterDuffColorFilter; import android.graphics.Rect; +import android.graphics.Region; import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; import android.os.Build; @@ -55,6 +56,7 @@ import org.telegram.messenger.LocaleController; import org.telegram.messenger.NotificationCenter; import org.telegram.messenger.R; import org.telegram.messenger.UserConfig; +import org.telegram.messenger.camera.CameraView; import org.telegram.ui.Components.AnimationProperties; import org.telegram.ui.Components.Bulletin; import org.telegram.ui.Components.CubicBezierInterpolator; @@ -70,8 +72,8 @@ public class BottomSheet extends Dialog { protected ContainerView container; protected boolean keyboardVisible; private WindowInsets lastInsets; - protected boolean drawNavigationBar; - protected boolean scrollNavBar; + public boolean drawNavigationBar; + public boolean scrollNavBar; protected boolean useSmoothKeyboard; @@ -576,7 +578,83 @@ public class BottomSheet extends Dialog { @Override protected void dispatchDraw(Canvas canvas) { - super.dispatchDraw(canvas); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + if (navBarColorKey != null) { + backgroundPaint.setColor(getThemedColor(navBarColorKey)); + } else { + backgroundPaint.setColor(navBarColor); + } + } else { + backgroundPaint.setColor(0xff000000); + } + if (backgroundPaint.getAlpha() < 255 && drawNavigationBar) { + float translation = 0; + if (scrollNavBar || Build.VERSION.SDK_INT >= 29 && getAdditionalMandatoryOffsets() > 0) { + float dist = containerView.getMeasuredHeight() - containerView.getTranslationY(); + translation = Math.max(0, getBottomInset() - dist); + } + int navBarHeight = drawNavigationBar ? getBottomInset() : 0; + canvas.save(); + canvas.clipRect(containerView.getLeft() + backgroundPaddingLeft, getMeasuredHeight() - navBarHeight + translation - currentPanTranslationY, containerView.getRight() - backgroundPaddingLeft, getMeasuredHeight() + translation, Region.Op.DIFFERENCE); + super.dispatchDraw(canvas); + canvas.restore(); + } else { + super.dispatchDraw(canvas); + } + if (!shouldOverlayCameraViewOverNavBar()) { + drawNavigationBar(canvas); + } + if (drawNavigationBar && rightInset != 0 && rightInset > leftInset && fullWidth && AndroidUtilities.displaySize.x > AndroidUtilities.displaySize.y) { + canvas.drawRect(containerView.getRight() - backgroundPaddingLeft, containerView.getTranslationY(), containerView.getRight() + rightInset, getMeasuredHeight(), backgroundPaint); + } + + if (drawNavigationBar && leftInset != 0 && leftInset > rightInset && fullWidth && AndroidUtilities.displaySize.x > AndroidUtilities.displaySize.y) { + canvas.drawRect(0, containerView.getTranslationY(), containerView.getLeft() + backgroundPaddingLeft, getMeasuredHeight(), backgroundPaint); + } + + if (containerView.getTranslationY() < 0) { + backgroundPaint.setColor(behindKeyboardColorKey != null ? getThemedColor(behindKeyboardColorKey) : behindKeyboardColor); + canvas.drawRect(containerView.getLeft() + backgroundPaddingLeft, containerView.getY() + containerView.getMeasuredHeight(), containerView.getRight() - backgroundPaddingLeft, getMeasuredHeight(), backgroundPaint); + } + } + + @Override + protected boolean drawChild(Canvas canvas, View child, long drawingTime) { + if (child instanceof CameraView) { + if (shouldOverlayCameraViewOverNavBar()) { + drawNavigationBar(canvas); + } + return super.drawChild(canvas, child, drawingTime); + } + return super.drawChild(canvas, child, drawingTime); + } + + @Override + protected void onDraw(Canvas canvas) { + boolean restore = false; + if (backgroundPaint.getAlpha() < 255 && drawNavigationBar) { + float translation = 0; + if (scrollNavBar || Build.VERSION.SDK_INT >= 29 && getAdditionalMandatoryOffsets() > 0) { + float dist = containerView.getMeasuredHeight() - containerView.getTranslationY(); + translation = Math.max(0, getBottomInset() - dist); + } + int navBarHeight = drawNavigationBar ? getBottomInset() : 0; + canvas.save(); + canvas.clipRect(containerView.getLeft() + backgroundPaddingLeft, getMeasuredHeight() - navBarHeight + translation - currentPanTranslationY, containerView.getRight() - backgroundPaddingLeft, getMeasuredHeight() + translation, Region.Op.DIFFERENCE); + restore = true; + } + super.onDraw(canvas); + if (lastInsets != null && keyboardHeight != 0) { + backgroundPaint.setColor(behindKeyboardColorKey != null ? getThemedColor(behindKeyboardColorKey) : behindKeyboardColor); + canvas.drawRect(containerView.getLeft() + backgroundPaddingLeft, getMeasuredHeight() - keyboardHeight - (drawNavigationBar ? getBottomInset() : 0), containerView.getRight() - backgroundPaddingLeft, getMeasuredHeight() - (drawNavigationBar ? getBottomInset() : 0), backgroundPaint); + } + onContainerDraw(canvas); + if (restore) { + canvas.restore(); + } + } + + public void drawNavigationBar(Canvas canvas) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { if (navBarColorKey != null) { backgroundPaint.setColor(getThemedColor(navBarColorKey)); @@ -600,29 +678,11 @@ public class BottomSheet extends Dialog { canvas.drawRect(containerView.getLeft() + backgroundPaddingLeft, getMeasuredHeight() - navBarHeight + translation - currentPanTranslationY, containerView.getRight() - backgroundPaddingLeft, getMeasuredHeight() + translation, backgroundPaint); } } - if (drawNavigationBar && rightInset != 0 && rightInset > leftInset && fullWidth && AndroidUtilities.displaySize.x > AndroidUtilities.displaySize.y) { - canvas.drawRect(containerView.getRight() - backgroundPaddingLeft, containerView.getTranslationY(), containerView.getRight() + rightInset, getMeasuredHeight(), backgroundPaint); - } - - if (drawNavigationBar && leftInset != 0 && leftInset > rightInset && fullWidth && AndroidUtilities.displaySize.x > AndroidUtilities.displaySize.y) { - canvas.drawRect(0, containerView.getTranslationY(), containerView.getLeft() + backgroundPaddingLeft, getMeasuredHeight(), backgroundPaint); - } - - if (containerView.getTranslationY() < 0) { - backgroundPaint.setColor(behindKeyboardColorKey != null ? getThemedColor(behindKeyboardColorKey) : behindKeyboardColor); - canvas.drawRect(containerView.getLeft() + backgroundPaddingLeft, containerView.getY() + containerView.getMeasuredHeight(), containerView.getRight() - backgroundPaddingLeft, getMeasuredHeight(), backgroundPaint); - } } + } - @Override - protected void onDraw(Canvas canvas) { - super.onDraw(canvas); - if (lastInsets != null && keyboardHeight != 0) { - backgroundPaint.setColor(behindKeyboardColorKey != null ? getThemedColor(behindKeyboardColorKey) : behindKeyboardColor); - canvas.drawRect(containerView.getLeft() + backgroundPaddingLeft, getMeasuredHeight() - keyboardHeight - (drawNavigationBar ? getBottomInset() : 0), containerView.getRight() - backgroundPaddingLeft, getMeasuredHeight() - (drawNavigationBar ? getBottomInset() : 0), backgroundPaint); - } - onContainerDraw(canvas); - } + protected boolean shouldOverlayCameraViewOverNavBar() { + return false; } public void setHideSystemVerticalInsets(boolean hideSystemVerticalInsets) { @@ -1035,7 +1095,7 @@ public class BottomSheet extends Dialog { backDrawable.setAlpha(0); if (Build.VERSION.SDK_INT >= 18) { layoutCount = 2; - containerView.setTranslationY((Build.VERSION.SDK_INT >= 21 ? AndroidUtilities.statusBarHeight * (1f - hideSystemVerticalInsetsProgress) : 0) + containerView.getMeasuredHeight()); + containerView.setTranslationY((Build.VERSION.SDK_INT >= 21 ? AndroidUtilities.statusBarHeight * (1f - hideSystemVerticalInsetsProgress) : 0) + containerView.getMeasuredHeight() + (scrollNavBar ? getBottomInset() : 0)); AndroidUtilities.runOnUIThread(startAnimationRunnable = new Runnable() { @Override public void run() { @@ -1152,7 +1212,7 @@ public class BottomSheet extends Dialog { if (Build.VERSION.SDK_INT >= 20 && useHardwareLayer) { container.setLayerType(View.LAYER_TYPE_HARDWARE, null); } - containerView.setTranslationY(containerView.getMeasuredHeight()); + containerView.setTranslationY(containerView.getMeasuredHeight() + (scrollNavBar ? getBottomInset() : 0)); currentSheetAnimationType = 1; currentSheetAnimation = new AnimatorSet(); currentSheetAnimation.playTogether( @@ -1267,7 +1327,7 @@ public class BottomSheet extends Dialog { currentSheetAnimationType = 2; currentSheetAnimation = new AnimatorSet(); currentSheetAnimation.playTogether( - ObjectAnimator.ofFloat(containerView, View.TRANSLATION_Y, containerView.getMeasuredHeight() + AndroidUtilities.dp(10)), + ObjectAnimator.ofFloat(containerView, View.TRANSLATION_Y, containerView.getMeasuredHeight() + AndroidUtilities.dp(10) + (scrollNavBar ? getBottomInset() : 0)), ObjectAnimator.ofInt(backDrawable, AnimationProperties.COLOR_DRAWABLE_ALPHA, 0) ); currentSheetAnimation.setDuration(180); @@ -1333,7 +1393,7 @@ public class BottomSheet extends Dialog { currentSheetAnimationType = 2; currentSheetAnimation = new AnimatorSet(); currentSheetAnimation.playTogether( - ObjectAnimator.ofFloat(containerView, View.TRANSLATION_Y, containerView.getMeasuredHeight() + container.keyboardHeight + AndroidUtilities.dp(10)), + ObjectAnimator.ofFloat(containerView, View.TRANSLATION_Y, containerView.getMeasuredHeight() + container.keyboardHeight + AndroidUtilities.dp(10) + (scrollNavBar ? getBottomInset() : 0)), ObjectAnimator.ofInt(backDrawable, AnimationProperties.COLOR_DRAWABLE_ALPHA, 0) ); if (useFastDismiss) { @@ -1509,6 +1569,13 @@ public class BottomSheet extends Dialog { bottomSheet.setOnHideListener(onDismissListener); return this; } + + public Builder fixNavigationBar() { + bottomSheet.drawNavigationBar = true; + bottomSheet.scrollNavBar = true; + bottomSheet.setOverlayNavBarColor(bottomSheet.getThemedColor(Theme.key_dialogBackground)); + return this; + } } public int getLeftInset() { @@ -1570,13 +1637,15 @@ public class BottomSheet extends Dialog { container.invalidate(); } - if (Color.alpha(color) > 120) { - AndroidUtilities.setLightStatusBar(getWindow(), false); - AndroidUtilities.setLightNavigationBar(getWindow(), false); - } else { - AndroidUtilities.setLightNavigationBar(getWindow(), !useLightNavBar); - AndroidUtilities.setLightStatusBar(getWindow(), !useLightStatusBar); - } +// if (Color.alpha(color) > 120) { +// AndroidUtilities.setLightStatusBar(getWindow(), false); +// AndroidUtilities.setLightNavigationBar(getWindow(), false); +// } else { +// AndroidUtilities.setLightStatusBar(getWindow(), !useLightStatusBar); +// AndroidUtilities.setLightNavigationBar(getWindow(), !useLightNavBar); +// } + AndroidUtilities.setNavigationBarColor(getWindow(), overlayDrawNavBarColor); + AndroidUtilities.setLightNavigationBar(getWindow(), AndroidUtilities.computePerceivedBrightness(overlayDrawNavBarColor) > .721); } public ViewGroup getContainerView() { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/DrawerLayoutContainer.java b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/DrawerLayoutContainer.java index 8babd13fa..01a0e252f 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/DrawerLayoutContainer.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/DrawerLayoutContainer.java @@ -311,6 +311,13 @@ public class DrawerLayoutContainer extends FrameLayout { parentActionBarLayout = layout; } + public void presentFragment(BaseFragment fragment) { + if (parentActionBarLayout != null) { + parentActionBarLayout.presentFragment(fragment); + } + closeDrawer(false); + } + public void closeDrawer() { if (drawerPosition != 0) { setDrawerPosition(0); 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 ae3bc8b95..9b8511c32 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/Theme.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/Theme.java @@ -1529,6 +1529,14 @@ public class Theme { currentColors.put(key_chat_wallpaper_gradient_rotation, backgroundRotation); } + Integer outBubble = currentColors.get(key_chat_outBubble); + if (outBubble == null) { + outBubble = getColor(key_chat_outBubble); + } + Integer inBubble = currentColors.get(key_chat_inBubble); + if (inBubble == null) { + inBubble = getColor(key_chat_inBubble); + } if (info != null && info.emoticon != null && !isDarkTheme) { currentColors.remove(key_chat_selectedBackground); int gradientAverageColor = averageColor(currentColors, key_chat_wallpaper_gradient_to1, key_chat_wallpaper_gradient_to2, key_chat_wallpaper_gradient_to3); @@ -1539,24 +1547,27 @@ public class Theme { gradientAverageColor = accentColor; } - Integer outBubble = currentColors.get(key_chat_outBubble); - if (outBubble == null) { - outBubble = getColor(key_chat_outBubble); - } int outOverlay = bubbleSelectedOverlay(outBubble, gradientAverageColor); currentColors.put(key_chat_outBubbleSelectedOverlay, outOverlay); currentColors.put(key_chat_outBubbleGradientSelectedOverlay, outOverlay); currentColors.put(key_chat_outBubbleSelected, Theme.blendOver(outBubble, outOverlay)); - Integer inBubble = currentColors.get(key_chat_inBubble); - if (inBubble == null) { - inBubble = getColor(key_chat_inBubble); - } int inOverlay = bubbleSelectedOverlay(inBubble, accentColor); currentColors.put(key_chat_inBubbleSelectedOverlay, inOverlay); currentColors.put(key_chat_inBubbleSelected, Theme.blendOver(inBubble, inOverlay)); } + Integer inMsgLink = currentColors.get(key_chat_messageLinkIn); + if (inMsgLink == null) { + inMsgLink = getColor(key_chat_messageLinkIn); + } + Integer outMsgLink = currentColors.get(key_chat_messageLinkOut); + if (outMsgLink == null) { + outMsgLink = getColor(key_chat_messageLinkOut); + } + currentColors.put(key_chat_linkSelectBackground, linkSelectionBackground(inMsgLink, inBubble, isDarkTheme)); + currentColors.put(key_chat_outLinkSelectBackground, linkSelectionBackground(outMsgLink, outBubble, isDarkTheme)); + return !isMyMessagesGradientColorsNear; } @@ -1572,6 +1583,12 @@ public class Theme { tempHSV[2] = Math.max(0, Math.min(1, tempHSV[2] - .05f)); return Color.HSVToColor(30, tempHSV); } + private int linkSelectionBackground(int linkColor, int bgColor, boolean isDarkTheme) { + Color.colorToHSV(ColorUtils.blendARGB(linkColor, bgColor, .25f), tempHSV); + tempHSV[1] = Math.max(0, Math.min(1, tempHSV[1] - .1f)); + tempHSV[2] = Math.max(0, Math.min(1, tempHSV[2] + (isDarkTheme ? .1f : 0))); + return Color.HSVToColor(0x33, tempHSV); + } private int averageColor(HashMap colors, String ...keys) { int r = 0, g = 0, b = 0, c = 0; for (int i = 0; i < keys.length; ++i) { @@ -2817,6 +2834,7 @@ public class Theme { public static Paint chat_deleteProgressPaint; public static Paint chat_botProgressPaint; public static Paint chat_urlPaint; + public static Paint chat_outUrlPaint; public static Paint chat_textSearchSelectionPaint; public static Paint chat_instantViewRectPaint; public static Paint chat_pollTimerPaint; @@ -2936,9 +2954,11 @@ public class Theme { public static Drawable chat_shareIconDrawable; public static Drawable chat_replyIconDrawable; public static Drawable chat_goIconDrawable; - public static Drawable chat_botLinkDrawalbe; - public static Drawable chat_botCardDrawalbe; + public static Drawable chat_botLinkDrawable; + public static Drawable chat_botCardDrawable; public static Drawable chat_botInlineDrawable; + public static Drawable chat_botWebViewDrawable; + public static Drawable chat_botInviteDrawable; public static Drawable chat_commentDrawable; public static Drawable chat_commentStickerDrawable; public static Drawable chat_commentArrowDrawable; @@ -3432,6 +3452,7 @@ public class Theme { public static final String key_chat_outVenueInfoSelectedText = "chat_outVenueInfoSelectedText"; public static final String key_chat_mediaInfoText = "chat_mediaInfoText"; public static final String key_chat_linkSelectBackground = "chat_linkSelectBackground"; + public static final String key_chat_outLinkSelectBackground = "chat_outLinkSelectBackground"; public static final String key_chat_textSelectBackground = "chat_textSelectBackground"; public static final String key_chat_wallpaper = "chat_wallpaper"; public static final String key_chat_wallpaper_gradient_to1 = "chat_wallpaper_gradient_to"; @@ -3782,6 +3803,8 @@ public class Theme { public static final String key_drawable_botInline = "drawableBotInline"; public static final String key_drawable_botLink = "drawableBotLink"; + public static final String key_drawable_botWebView = "drawableBotWebView"; + public static final String key_drawable_botInvite = "drawable_botInvite"; public static final String key_drawable_commentSticker = "drawableCommentSticker"; public static final String key_drawable_goIcon = "drawableGoIcon"; public static final String key_drawable_msgError = "drawableMsgError"; @@ -4289,6 +4312,7 @@ public class Theme { defaultColors.put(key_chat_outVenueInfoSelectedText, 0xff65b05b); defaultColors.put(key_chat_mediaInfoText, 0xffffffff); defaultColors.put(key_chat_linkSelectBackground, 0x3362a9e3); + defaultColors.put(key_chat_outLinkSelectBackground, 0x3362a9e3); defaultColors.put(key_chat_textSelectBackground, 0x6662a9e3); defaultColors.put(key_chat_emojiPanelBackground, 0xfff0f2f5); defaultColors.put(key_chat_emojiPanelBadgeBackground, 0xff4da6ea); @@ -4729,6 +4753,7 @@ public class Theme { fallbackKeys.put(key_actionBarTabSelector, key_actionBarDefaultSelector); fallbackKeys.put(key_profile_status, key_avatar_subtitleInProfileBlue); fallbackKeys.put(key_chats_menuTopBackgroundCats, key_avatar_backgroundActionBarBlue); + fallbackKeys.put(key_chat_outLinkSelectBackground, key_chat_linkSelectBackground); //fallbackKeys.put(key_chat_attachActiveTab, 0xff33a7f5); //fallbackKeys.put(key_chat_attachUnactiveTab, 0xff92999e); fallbackKeys.put(key_chat_attachPermissionImage, key_dialogTextBlack); @@ -5771,6 +5796,12 @@ public class Theme { return defaultDrawable; } + public static Drawable createRoundRectDrawable(int topRad, int bottomRad, int defaultColor) { + ShapeDrawable defaultDrawable = new ShapeDrawable(new RoundRectShape(new float[]{topRad, topRad, topRad, topRad, bottomRad, bottomRad, bottomRad, bottomRad}, null, null)); + defaultDrawable.getPaint().setColor(defaultColor); + return defaultDrawable; + } + public static Drawable createServiceDrawable(int rad, View view, View containerView) { return createServiceDrawable(rad, view, containerView, chat_actionBackgroundPaint); } @@ -5861,6 +5892,23 @@ public class Theme { } } + public static Drawable getRoundRectSelectorWithBackgroundDrawable(int corners, int bgColor, int color) { + if (Build.VERSION.SDK_INT >= 21) { + Drawable maskDrawable = createRoundRectDrawable(corners, 0xffffffff); + ColorStateList colorStateList = new ColorStateList( + new int[][]{StateSet.WILD_CARD}, + new int[]{color} + ); + return new RippleDrawable(colorStateList, createRoundRectDrawable(corners, bgColor), maskDrawable); + } else { + StateListDrawable stateListDrawable = new StateListDrawable(); + stateListDrawable.addState(new int[]{android.R.attr.state_pressed}, createRoundRectDrawable(corners, color)); + stateListDrawable.addState(new int[]{android.R.attr.state_selected}, createRoundRectDrawable(corners, color)); + stateListDrawable.addState(StateSet.WILD_CARD, new ColorDrawable(bgColor)); + return stateListDrawable; + } + } + public static Drawable createSelectorWithBackgroundDrawable(int backgroundColor, int color) { if (Build.VERSION.SDK_INT >= 21) { Drawable maskDrawable = new ColorDrawable(backgroundColor); @@ -6034,8 +6082,8 @@ public class Theme { public static class RippleRadMaskDrawable extends Drawable { private Path path = new Path(); - private RectF rect = new RectF(); private float[] radii = new float[8]; + boolean invalidatePath = true; public RippleRadMaskDrawable(float top, float bottom) { radii[0] = radii[1] = radii[2] = radii[3] = AndroidUtilities.dp(top); @@ -6051,6 +6099,7 @@ public class Theme { public void setRadius(float top, float bottom) { radii[0] = radii[1] = radii[2] = radii[3] = AndroidUtilities.dp(top); radii[4] = radii[5] = radii[6] = radii[7] = AndroidUtilities.dp(bottom); + invalidatePath = true; invalidateSelf(); } public void setRadius(float topLeft, float topRight, float bottomRight, float bottomLeft) { @@ -6058,13 +6107,23 @@ public class Theme { radii[2] = radii[3] = AndroidUtilities.dp(topRight); radii[4] = radii[5] = AndroidUtilities.dp(bottomRight); radii[6] = radii[7] = AndroidUtilities.dp(bottomLeft); + invalidatePath = true; invalidateSelf(); } + @Override + protected void onBoundsChange(Rect bounds) { + invalidatePath = true; + } + @Override public void draw(Canvas canvas) { - rect.set(getBounds()); - path.addRoundRect(rect, radii, Path.Direction.CW); + if (invalidatePath) { + invalidatePath = false; + path.reset(); + AndroidUtilities.rectTmp.set(getBounds()); + path.addRoundRect(AndroidUtilities.rectTmp, radii, Path.Direction.CW); + } canvas.drawPath(path, maskPaint); } @@ -8046,7 +8105,7 @@ public class Theme { checkboxSquare_backgroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG); linkSelectionPaint = new Paint(); - linkSelectionPaint.setPathEffect(LinkPath.roundedEffect); + linkSelectionPaint.setPathEffect(LinkPath.getRoundedEffect()); Resources resources = context.getResources(); @@ -8368,9 +8427,11 @@ public class Theme { chat_locationTitlePaint.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); chat_locationAddressPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG); chat_urlPaint = new Paint(); - chat_urlPaint.setPathEffect(LinkPath.roundedEffect); + chat_urlPaint.setPathEffect(LinkPath.getRoundedEffect()); + chat_outUrlPaint = new Paint(); + chat_outUrlPaint.setPathEffect(LinkPath.getRoundedEffect()); chat_textSearchSelectionPaint = new Paint(); - chat_textSearchSelectionPaint.setPathEffect(LinkPath.roundedEffect); + chat_textSearchSelectionPaint.setPathEffect(LinkPath.getRoundedEffect()); chat_radialProgressPaint = new Paint(Paint.ANTI_ALIAS_FLAG); chat_radialProgressPaint.setStrokeCap(Paint.Cap.ROUND); chat_radialProgressPaint.setStyle(Paint.Style.STROKE); @@ -8540,9 +8601,11 @@ public class Theme { chat_inlineResultLocation = resources.getDrawable(R.drawable.bot_location); chat_redLocationIcon = resources.getDrawable(R.drawable.map_pin).mutate(); - chat_botLinkDrawalbe = resources.getDrawable(R.drawable.bot_link); + chat_botLinkDrawable = resources.getDrawable(R.drawable.bot_link); chat_botInlineDrawable = resources.getDrawable(R.drawable.bot_lines); - chat_botCardDrawalbe = resources.getDrawable(R.drawable.bot_card); + chat_botCardDrawable = resources.getDrawable(R.drawable.bot_card); + chat_botWebViewDrawable = resources.getDrawable(R.drawable.bot_webview); + chat_botInviteDrawable = resources.getDrawable(R.drawable.bot_invite); chat_commentDrawable = resources.getDrawable(R.drawable.msg_msgbubble); chat_commentStickerDrawable = resources.getDrawable(R.drawable.msg_msgbubble2); @@ -8685,7 +8748,9 @@ public class Theme { defaultChatDrawableColorKeys.clear(); addChatDrawable(key_drawable_botInline, chat_botInlineDrawable, key_chat_serviceIcon); - addChatDrawable(key_drawable_botLink, chat_botLinkDrawalbe, key_chat_serviceIcon); + addChatDrawable(key_drawable_botWebView, chat_botWebViewDrawable, key_chat_serviceIcon); + addChatDrawable(key_drawable_botLink, chat_botLinkDrawable, key_chat_serviceIcon); + addChatDrawable(key_drawable_botInvite, chat_botInviteDrawable, key_chat_serviceIcon); addChatDrawable(key_drawable_goIcon, chat_goIconDrawable, key_chat_serviceIcon); addChatDrawable(key_drawable_commentSticker, chat_commentStickerDrawable, key_chat_serviceIcon); addChatDrawable(key_drawable_msgError, chat_msgErrorDrawable, key_chat_sentErrorIcon); @@ -8808,6 +8873,7 @@ public class Theme { chat_durationPaint.setColor(getColor(key_chat_previewDurationText)); chat_botButtonPaint.setColor(getColor(key_chat_botButtonText)); chat_urlPaint.setColor(getColor(key_chat_linkSelectBackground)); + chat_outUrlPaint.setColor(getColor(key_chat_outLinkSelectBackground)); chat_botProgressPaint.setColor(getColor(key_chat_botProgress)); chat_deleteProgressPaint.setColor(getColor(key_chat_secretTimeText)); chat_textSearchSelectionPaint.setColor(getColor(key_chat_textSelectBackground)); @@ -8841,7 +8907,9 @@ public class Theme { setDrawableColorByKey(chat_replyIconDrawable, key_chat_serviceIcon); setDrawableColorByKey(chat_goIconDrawable, key_chat_serviceIcon); setDrawableColorByKey(chat_botInlineDrawable, key_chat_serviceIcon); - setDrawableColorByKey(chat_botLinkDrawalbe, key_chat_serviceIcon); + setDrawableColorByKey(chat_botWebViewDrawable, key_chat_serviceIcon); + setDrawableColorByKey(chat_botInviteDrawable, key_chat_serviceIcon); + setDrawableColorByKey(chat_botLinkDrawable, key_chat_serviceIcon); setDrawableColorByKey(chat_msgInViewsDrawable, key_chat_inViews); setDrawableColorByKey(chat_msgInViewsSelectedDrawable, key_chat_inViewsSelected); setDrawableColorByKey(chat_msgOutViewsDrawable, key_chat_outViews); @@ -9084,7 +9152,9 @@ public class Theme { setDrawableColor(chat_replyIconDrawable, 0xffffffff); setDrawableColor(chat_goIconDrawable, 0xffffffff); setDrawableColor(chat_botInlineDrawable, 0xffffffff); - setDrawableColor(chat_botLinkDrawalbe, 0xffffffff); + setDrawableColor(chat_botWebViewDrawable, 0xffffffff); + setDrawableColor(chat_botInviteDrawable, 0xffffffff); + setDrawableColor(chat_botLinkDrawable, 0xffffffff); } else { serviceBitmap = null; serviceBitmapShader = null; @@ -9101,7 +9171,9 @@ public class Theme { setDrawableColorByKey(chat_replyIconDrawable, key_chat_serviceIcon); setDrawableColorByKey(chat_goIconDrawable, key_chat_serviceIcon); setDrawableColorByKey(chat_botInlineDrawable, key_chat_serviceIcon); - setDrawableColorByKey(chat_botLinkDrawalbe, key_chat_serviceIcon); + setDrawableColorByKey(chat_botWebViewDrawable, key_chat_serviceIcon); + setDrawableColorByKey(chat_botInviteDrawable, key_chat_serviceIcon); + setDrawableColorByKey(chat_botLinkDrawable, key_chat_serviceIcon); chat_botButtonPaint.setColor(getColor(key_chat_botButtonText)); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ActionIntroActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ActionIntroActivity.java index b59690039..b04e7c3e9 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ActionIntroActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ActionIntroActivity.java @@ -14,8 +14,6 @@ import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; import android.graphics.Canvas; -import android.graphics.PorterDuff; -import android.graphics.PorterDuffColorFilter; import android.graphics.drawable.Drawable; import android.location.Location; import android.location.LocationManager; @@ -35,6 +33,7 @@ import android.widget.LinearLayout; import android.widget.TextView; import androidx.annotation.IntDef; +import androidx.core.graphics.ColorUtils; import org.telegram.PhoneFormat.PhoneFormat; import org.telegram.messenger.AndroidUtilities; @@ -52,7 +51,6 @@ import org.telegram.ui.ActionBar.BaseFragment; import org.telegram.ui.ActionBar.Theme; import org.telegram.ui.ActionBar.ThemeDescription; import org.telegram.ui.Components.AlertsCreator; -import org.telegram.ui.Components.CombinedDrawable; import org.telegram.ui.Components.LayoutHelper; import org.telegram.ui.Components.RLottieImageView; import org.telegram.ui.Components.ShareLocationDrawable; @@ -131,9 +129,6 @@ public class ActionIntroActivity extends BaseFragment implements LocationControl actionBar.setItemsBackgroundColor(Theme.getColor(Theme.key_actionBarWhiteSelector), false); actionBar.setCastShadows(false); actionBar.setAddToContainer(false); - if (!AndroidUtilities.isTablet()) { - actionBar.showActionModeTop(); - } actionBar.setActionBarMenuOnItemClick(new ActionBar.ActionBarMenuOnItemClick() { @Override public void onItemClick(int id) { @@ -231,18 +226,18 @@ public class ActionIntroActivity extends BaseFragment implements LocationControl break; } case ACTION_TYPE_CHANGE_PHONE_NUMBER: { + imageView.measure(MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(150), MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(150), MeasureSpec.EXACTLY)); + if (width > height) { - imageView.measure(MeasureSpec.makeMeasureSpec((int) (width * 0.45f), MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec((int) (height * 0.78f), MeasureSpec.AT_MOST)); subtitleTextView.measure(MeasureSpec.makeMeasureSpec((int) (width * 0.45f), MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(height, MeasureSpec.UNSPECIFIED)); titleTextView.measure(MeasureSpec.makeMeasureSpec((int) (width * 0.6f), MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(height, MeasureSpec.UNSPECIFIED)); descriptionText.measure(MeasureSpec.makeMeasureSpec((int) (width * 0.6f), MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(height, MeasureSpec.UNSPECIFIED)); buttonTextView.measure(MeasureSpec.makeMeasureSpec((int) (width * 0.6f), MeasureSpec.AT_MOST), MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(42), MeasureSpec.EXACTLY)); } else { - imageView.measure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec((int) (height * 0.44f), MeasureSpec.AT_MOST)); titleTextView.measure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(height, MeasureSpec.UNSPECIFIED)); - subtitleTextView.measure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(height, MeasureSpec.UNSPECIFIED)); descriptionText.measure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(height, MeasureSpec.UNSPECIFIED)); - buttonTextView.measure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.AT_MOST), MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(42), MeasureSpec.EXACTLY)); + subtitleTextView.measure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(height, MeasureSpec.UNSPECIFIED)); + buttonTextView.measure(MeasureSpec.makeMeasureSpec(width - AndroidUtilities.dp(24 * 2), MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(50), MeasureSpec.EXACTLY)); } break; } @@ -432,10 +427,9 @@ public class ActionIntroActivity extends BaseFragment implements LocationControl case ACTION_TYPE_CHANGE_PHONE_NUMBER: { if (r > b) { int y = (int) (height * 0.95f - imageView.getMeasuredHeight()) / 2; - imageView.layout(0, y, imageView.getMeasuredWidth(), y + imageView.getMeasuredHeight()); - y += imageView.getMeasuredHeight() + AndroidUtilities.dp(10); - subtitleTextView.layout(0, y, subtitleTextView.getMeasuredWidth(), y + subtitleTextView.getMeasuredHeight()); - int x = (int) (width * 0.4f); + int x = (int) (getWidth() * 0.35f - imageView.getMeasuredWidth()); + imageView.layout(x, y, x + imageView.getMeasuredWidth(), y + imageView.getMeasuredHeight()); + x = (int) (width * 0.4f); y = (int) (height * 0.12f); titleTextView.layout(x, y, x + titleTextView.getMeasuredWidth(), y + titleTextView.getMeasuredHeight()); x = (int) (width * 0.4f); @@ -444,18 +438,25 @@ public class ActionIntroActivity extends BaseFragment implements LocationControl x = (int) (width * 0.4f + (width * 0.6f - buttonTextView.getMeasuredWidth()) / 2); y = (int) (height * 0.8f); buttonTextView.layout(x, y, x + buttonTextView.getMeasuredWidth(), y + buttonTextView.getMeasuredHeight()); + + x = (int) (width * 0.4f + (width * 0.6f - subtitleTextView.getMeasuredWidth()) / 2); + y -= subtitleTextView.getMeasuredHeight() + AndroidUtilities.dp(16); + subtitleTextView.layout(x, y, x + subtitleTextView.getMeasuredWidth(), y + subtitleTextView.getMeasuredHeight()); } else { - int y = (int) (height * 0.2229f); - imageView.layout(0, y, imageView.getMeasuredWidth(), y + imageView.getMeasuredHeight()); - y = (int) (height * 0.352f); + int y = (int) (height * 0.3f); + int x = (width - imageView.getMeasuredWidth()) / 2; + imageView.layout(x, y, x + imageView.getMeasuredWidth(), y + imageView.getMeasuredHeight()); + y += imageView.getMeasuredHeight() + AndroidUtilities.dp(24); titleTextView.layout(0, y, titleTextView.getMeasuredWidth(), y + titleTextView.getMeasuredHeight()); - y = (int) (height * 0.409f); - subtitleTextView.layout(0, y, subtitleTextView.getMeasuredWidth(), y + subtitleTextView.getMeasuredHeight()); - y = (int) (height * 0.468f); + y += titleTextView.getTextSize() + AndroidUtilities.dp(16); descriptionText.layout(0, y, descriptionText.getMeasuredWidth(), y + descriptionText.getMeasuredHeight()); - int x = (width - buttonTextView.getMeasuredWidth()) / 2; - y = (int) (height * 0.805f); + x = (width - buttonTextView.getMeasuredWidth()) / 2; + y = height - buttonTextView.getMeasuredHeight() - AndroidUtilities.dp(48); buttonTextView.layout(x, y, x + buttonTextView.getMeasuredWidth(), y + buttonTextView.getMeasuredHeight()); + + x = (width - subtitleTextView.getMeasuredWidth()) / 2; + y -= subtitleTextView.getMeasuredHeight() + AndroidUtilities.dp(32); + subtitleTextView.layout(x, y, x + subtitleTextView.getMeasuredWidth(), y + subtitleTextView.getMeasuredHeight()); } break; } @@ -481,7 +482,7 @@ public class ActionIntroActivity extends BaseFragment implements LocationControl viewGroup.addView(titleTextView); subtitleTextView = new TextView(context); - subtitleTextView.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlackText)); + subtitleTextView.setTextColor(Theme.getColor(currentType == ACTION_TYPE_CHANGE_PHONE_NUMBER ? Theme.key_featuredStickers_addButton : Theme.key_windowBackgroundWhiteBlackText)); subtitleTextView.setGravity(Gravity.CENTER_HORIZONTAL); subtitleTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 15); subtitleTextView.setSingleLine(true); @@ -499,7 +500,7 @@ public class ActionIntroActivity extends BaseFragment implements LocationControl descriptionText.setGravity(Gravity.CENTER_HORIZONTAL); descriptionText.setLineSpacing(AndroidUtilities.dp(2), 1); descriptionText.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 15); - if (currentType == ACTION_TYPE_SET_PASSCODE) { + if (currentType == ACTION_TYPE_SET_PASSCODE || currentType == ACTION_TYPE_CHANGE_PHONE_NUMBER) { descriptionText.setPadding(AndroidUtilities.dp(48), 0, AndroidUtilities.dp(48), 0); } else if (currentType == ACTION_TYPE_NEARBY_GROUP_CREATE) { descriptionText.setPadding(AndroidUtilities.dp(24), 0, AndroidUtilities.dp(24), 0); @@ -601,7 +602,7 @@ public class ActionIntroActivity extends BaseFragment implements LocationControl buttonTextView.setTextColor(Theme.getColor(Theme.key_featuredStickers_buttonText)); buttonTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); buttonTextView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); - int buttonRadiusDp = currentType == ACTION_TYPE_SET_PASSCODE ? 6 : 4; + int buttonRadiusDp = currentType == ACTION_TYPE_SET_PASSCODE || currentType == ACTION_TYPE_CHANGE_PHONE_NUMBER ? 6 : 4; buttonTextView.setBackground(Theme.createSimpleSelectorRoundRectDrawable(AndroidUtilities.dp(buttonRadiusDp), Theme.getColor(Theme.key_featuredStickers_addButton), Theme.getColor(Theme.key_featuredStickers_addButtonPressed))); viewGroup.addView(buttonTextView); buttonTextView.setOnClickListener(v -> { @@ -736,23 +737,29 @@ public class ActionIntroActivity extends BaseFragment implements LocationControl } case ACTION_TYPE_CHANGE_PHONE_NUMBER: { subtitleTextView.setVisibility(View.VISIBLE); - drawable1 = context.getResources().getDrawable(R.drawable.sim_old); - drawable2 = context.getResources().getDrawable(R.drawable.sim_new); - drawable1.setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_changephoneinfo_image), PorterDuff.Mode.MULTIPLY)); - drawable2.setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_changephoneinfo_image2), PorterDuff.Mode.MULTIPLY)); - imageView.setImageDrawable(new CombinedDrawable(drawable1, drawable2)); - imageView.setScaleType(ImageView.ScaleType.CENTER); + imageView.setScaleType(ImageView.ScaleType.FIT_CENTER); + imageView.setAnimation(R.raw.utyan_change_number, 200, 200); + imageView.setOnClickListener(v -> { + if (!imageView.getAnimatedDrawable().isRunning()) { + imageView.getAnimatedDrawable().setCurrentFrame(0, false); + imageView.playAnimation(); + } + }); + UserConfig userConfig = getUserConfig(); TLRPC.User user = getMessagesController().getUser(userConfig.clientUserId); if (user == null) { user = userConfig.getCurrentUser(); } if (user != null) { - subtitleTextView.setText(PhoneFormat.getInstance().format("+" + user.phone)); + subtitleTextView.setText(LocaleController.formatString("PhoneNumberKeepButton", R.string.PhoneNumberKeepButton, PhoneFormat.getInstance().format("+" + user.phone))); } + subtitleTextView.setOnClickListener(v -> getParentLayout().closeLastFragment(true)); titleTextView.setText(LocaleController.getString("PhoneNumberChange2", R.string.PhoneNumberChange2)); descriptionText.setText(AndroidUtilities.replaceTags(LocaleController.getString("PhoneNumberHelp", R.string.PhoneNumberHelp))); buttonTextView.setText(LocaleController.getString("PhoneNumberChange2", R.string.PhoneNumberChange2)); + imageView.playAnimation(); + flickerButton = true; break; } } @@ -765,11 +772,6 @@ public class ActionIntroActivity extends BaseFragment implements LocationControl return fragmentView; } - @Override - public boolean hasForceLightStatusBar() { - return true; - } - @Override public void onLocationAddressAvailable(String address, String displayAddress, Location location) { if (subtitleTextView == null) { @@ -921,4 +923,10 @@ public class ActionIntroActivity extends BaseFragment implements LocationControl return themeDescriptions; } + + @Override + public boolean isLightStatusBar() { + int color = Theme.getColor(Theme.key_windowBackgroundWhite, null, true); + return ColorUtils.calculateLuminance(color) > 0.7f; + } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Adapters/DialogsAdapter.java b/TMessagesProj/src/main/java/org/telegram/ui/Adapters/DialogsAdapter.java index d1095b389..f1fd62971 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Adapters/DialogsAdapter.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Adapters/DialogsAdapter.java @@ -17,6 +17,7 @@ import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; import android.os.Build; import android.os.SystemClock; +import android.text.TextUtils; import android.util.TypedValue; import android.view.Gravity; import android.view.View; @@ -27,8 +28,10 @@ import android.widget.TextView; import androidx.recyclerview.widget.RecyclerView; import androidx.viewpager.widget.ViewPager; +import org.telegram.messenger.AccountInstance; import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.BuildVars; +import org.telegram.messenger.ChatObject; import org.telegram.messenger.ContactsController; import org.telegram.messenger.DialogObject; import org.telegram.messenger.FileLog; @@ -47,6 +50,7 @@ import org.telegram.ui.Cells.DialogCell; import org.telegram.ui.Cells.DialogMeUrlCell; import org.telegram.ui.Cells.DialogsEmptyCell; import org.telegram.ui.Cells.HeaderCell; +import org.telegram.ui.Cells.ProfileSearchCell; import org.telegram.ui.Cells.ShadowSectionCell; import org.telegram.ui.Cells.TextCell; import org.telegram.ui.Cells.TextInfoPrivacyCell; @@ -77,7 +81,8 @@ public class DialogsAdapter extends RecyclerListView.SelectionAdapter { VIEW_TYPE_LAST_EMPTY = 10, VIEW_TYPE_NEW_CHAT_HINT = 11, VIEW_TYPE_TEXT = 12, - VIEW_TYPE_CONTACTS_FLICKER = 13; + VIEW_TYPE_CONTACTS_FLICKER = 13, + VIEW_TYPE_HEADER_2 = 14; private Context mContext; private ArchiveHintCell archiveHintCell; @@ -400,10 +405,14 @@ public class DialogsAdapter extends RecyclerListView.SelectionAdapter { View view; switch (viewType) { case VIEW_TYPE_DIALOG: - DialogCell dialogCell = new DialogCell(parentFragment, mContext, true, false, currentAccount, null); - dialogCell.setArchivedPullAnimation(pullForegroundDrawable); - dialogCell.setPreloader(preloader); - view = dialogCell; + if (dialogsType == 2) { + view = new ProfileSearchCell(mContext); + } else { + DialogCell dialogCell = new DialogCell(parentFragment, mContext, true, false, currentAccount, null); + dialogCell.setArchivedPullAnimation(pullForegroundDrawable); + dialogCell.setPreloader(preloader); + view = dialogCell; + } break; case VIEW_TYPE_FLICKER: case VIEW_TYPE_CONTACTS_FLICKER: @@ -462,6 +471,12 @@ public class DialogsAdapter extends RecyclerListView.SelectionAdapter { view = new HeaderCell(mContext); view.setPadding(0, 0, 0, AndroidUtilities.dp(12)); break; + case VIEW_TYPE_HEADER_2: + HeaderCell cell = new HeaderCell(mContext, Theme.key_graySectionText, 16, 0, false); + cell.setHeight(32); + view = cell; + view.setClickable(false); + break; case VIEW_TYPE_SHADOW: { view = new ShadowSectionCell(mContext); Drawable drawable = Theme.getThemedDrawable(mContext, R.drawable.greydivider, Theme.key_windowBackgroundGrayShadow); @@ -559,20 +574,72 @@ public class DialogsAdapter extends RecyclerListView.SelectionAdapter { public void onBindViewHolder(RecyclerView.ViewHolder holder, int i) { switch (holder.getItemViewType()) { case VIEW_TYPE_DIALOG: { - DialogCell cell = (DialogCell) holder.itemView; TLRPC.Dialog dialog = (TLRPC.Dialog) getItem(i); TLRPC.Dialog nextDialog = (TLRPC.Dialog) getItem(i + 1); - cell.useSeparator = nextDialog != null; - cell.fullSeparator = dialog.pinned && nextDialog != null && !nextDialog.pinned; - if (dialogsType == 0) { - if (AndroidUtilities.isTablet()) { - cell.setDialogSelected(dialog.id == openedDialogId); + if (dialogsType == 2) { + ProfileSearchCell cell = (ProfileSearchCell) holder.itemView; + long oldDialogId = cell.getDialogId(); + + TLRPC.Chat chat = null; + CharSequence title = null; + CharSequence subtitle; + boolean isRecent = false; + + if (dialog.id != 0) { + chat = MessagesController.getInstance(currentAccount).getChat(-dialog.id); + if (chat != null && chat.migrated_to != null) { + TLRPC.Chat chat2 = MessagesController.getInstance(currentAccount).getChat(chat.migrated_to.channel_id); + if (chat2 != null) { + chat = chat2; + } + } + } + + if (chat != null) { + title = chat.title; + if (ChatObject.isChannel(chat) && !chat.megagroup) { + if (chat.participants_count != 0) { + subtitle = LocaleController.formatPluralStringComma("Subscribers", chat.participants_count); + } else { + if (TextUtils.isEmpty(chat.username)) { + subtitle = LocaleController.getString("ChannelPrivate", R.string.ChannelPrivate).toLowerCase(); + } else { + subtitle = LocaleController.getString("ChannelPublic", R.string.ChannelPublic).toLowerCase(); + } + } + } else { + if (chat.participants_count != 0) { + subtitle = LocaleController.formatPluralStringComma("Members", chat.participants_count); + } else { + if (chat.has_geo) { + subtitle = LocaleController.getString("MegaLocation", R.string.MegaLocation); + } else if (TextUtils.isEmpty(chat.username)) { + subtitle = LocaleController.getString("MegaPrivate", R.string.MegaPrivate).toLowerCase(); + } else { + subtitle = LocaleController.getString("MegaPublic", R.string.MegaPublic).toLowerCase(); + } + } + } + } else { + subtitle = ""; + } + cell.useSeparator = nextDialog != null; + cell.setData(chat, null, title, subtitle, isRecent, false); + cell.setChecked(selectedDialogs.contains(cell.getDialogId()), oldDialogId == cell.getDialogId()); + } else { + DialogCell cell = (DialogCell) holder.itemView; + cell.useSeparator = nextDialog != null; + cell.fullSeparator = dialog.pinned && nextDialog != null && !nextDialog.pinned; + if (dialogsType == 0) { + if (AndroidUtilities.isTablet()) { + cell.setDialogSelected(dialog.id == openedDialogId); + } + } + cell.setChecked(selectedDialogs.contains(dialog.id), false); + cell.setDialog(dialog, dialogsType, folderId); + if (preloader != null && i < 10) { + preloader.add(dialog.id); } - } - cell.setChecked(selectedDialogs.contains(dialog.id), false); - cell.setDialog(dialog, dialogsType, folderId); - if (preloader != null && i < 10) { - preloader.add(dialog.id); } break; } @@ -631,6 +698,32 @@ public class DialogsAdapter extends RecyclerListView.SelectionAdapter { } break; } + case VIEW_TYPE_HEADER_2: { + HeaderCell cell = (HeaderCell) holder.itemView; + cell.setTextSize(14); + cell.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteGrayText)); + cell.setBackgroundColor(Theme.getColor(Theme.key_graySection)); + try { + MessagesController messagesController = AccountInstance.getInstance(currentAccount).getMessagesController(); + int j = 0; + if (messagesController.dialogsMyChannels.size() > 0) { + if (i == j) { + cell.setText(LocaleController.getString("MyChannels", R.string.MyChannels)); + } + j += 1 + messagesController.dialogsMyChannels.size(); + } + if (messagesController.dialogsMyGroups.size() > 0) { + if (i == j) { + cell.setText(LocaleController.getString("MyGroups", R.string.MyGroups)); + } + j += 1 + messagesController.dialogsMyGroups.size(); + } + if (messagesController.dialogsCanAddUsers.size() > 0 && i == j) { + cell.setText(LocaleController.getString("FilterGroups", R.string.FilterGroups)); + } + } catch (Exception ignore) {} + break; + } case VIEW_TYPE_NEW_CHAT_HINT: { TextInfoPrivacyCell cell = (TextInfoPrivacyCell) holder.itemView; cell.setText(LocaleController.getString("TapOnThePencil", R.string.TapOnThePencil)); @@ -746,6 +839,9 @@ public class DialogsAdapter extends RecyclerListView.SelectionAdapter { } else if (i > size) { return VIEW_TYPE_LAST_EMPTY; } + if (dialogsType == 2 && getItem(i) == null) { + return VIEW_TYPE_HEADER_2; + } return VIEW_TYPE_DIALOG; } @@ -929,6 +1025,7 @@ public class DialogsAdapter extends RecyclerListView.SelectionAdapter { blurOffset = ((BlurredRecyclerView) parent).blurTopPadding; } int paddingTop = parent.getPaddingTop(); + paddingTop -= blurOffset; if (size == 0 || paddingTop == 0 && !hasArchive) { height = 0; } else { 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 fddb6e882..70ecdca10 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Adapters/DialogsSearchAdapter.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Adapters/DialogsSearchAdapter.java @@ -59,6 +59,14 @@ import androidx.recyclerview.widget.RecyclerView; public class DialogsSearchAdapter extends RecyclerListView.SelectionAdapter { + private final int VIEW_TYPE_PROFILE_CELL = 0; + private final int VIEW_TYPE_GRAY_SECTION = 1; + private final int VIEW_TYPE_DIALOG_CELL = 2; + private final int VIEW_TYPE_LOADING = 3; + private final int VIEW_TYPE_HASHTAG_CELL = 4; + private final int VIEW_TYPE_CATEGORY_LIST = 5; + private final int VIEW_TYPE_ADD_BY_PHONE = 6; + private Context mContext; private Runnable searchRunnable; private Runnable searchRunnable2; @@ -932,25 +940,25 @@ public class DialogsSearchAdapter extends RecyclerListView.SelectionAdapter { public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View view; switch (viewType) { - case 0: + case VIEW_TYPE_PROFILE_CELL: view = new ProfileSearchCell(mContext); break; - case 1: + case VIEW_TYPE_GRAY_SECTION: view = new GraySectionCell(mContext); break; - case 2: + case VIEW_TYPE_DIALOG_CELL: view = new DialogCell(null, mContext, false, true); break; - case 3: + case VIEW_TYPE_LOADING: FlickerLoadingView flickerLoadingView = new FlickerLoadingView(mContext); flickerLoadingView.setViewType(FlickerLoadingView.DIALOG_TYPE); flickerLoadingView.setIsSingleCell(true); view = flickerLoadingView; break; - case 4: + case VIEW_TYPE_HASHTAG_CELL: view = new HashtagSearchCell(mContext); break; - case 5: + case VIEW_TYPE_CATEGORY_LIST: RecyclerListView horizontalListView = new RecyclerListView(mContext) { @Override public boolean onInterceptTouchEvent(MotionEvent e) { @@ -960,7 +968,6 @@ public class DialogsSearchAdapter extends RecyclerListView.SelectionAdapter { return super.onInterceptTouchEvent(e); } }; - horizontalListView.setSelectorRadius(AndroidUtilities.dp(4)); horizontalListView.setSelectorDrawableColor(Theme.getColor(Theme.key_listSelector)); horizontalListView.setTag(9); horizontalListView.setItemAnimator(null); @@ -989,7 +996,7 @@ public class DialogsSearchAdapter extends RecyclerListView.SelectionAdapter { view = horizontalListView; innerListView = horizontalListView; break; - case 6: + case VIEW_TYPE_ADD_BY_PHONE: default: view = new TextCell(mContext, 16, false); break; @@ -1005,7 +1012,7 @@ public class DialogsSearchAdapter extends RecyclerListView.SelectionAdapter { @Override public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { switch (holder.getItemViewType()) { - case 0: { + case VIEW_TYPE_PROFILE_CELL: { ProfileSearchCell cell = (ProfileSearchCell) holder.itemView; long oldDialogId = cell.getDialogId(); @@ -1127,7 +1134,7 @@ public class DialogsSearchAdapter extends RecyclerListView.SelectionAdapter { cell.setChecked(delegate.isSelected(cell.getDialogId()), oldDialogId == cell.getDialogId()); break; } - case 1: { + case VIEW_TYPE_GRAY_SECTION: { GraySectionCell cell = (GraySectionCell) holder.itemView; if (isRecentSearchDisplayed()) { int offset = (!MediaDataController.getInstance(currentAccount).hints.isEmpty() ? 1 : 0); @@ -1197,25 +1204,25 @@ public class DialogsSearchAdapter extends RecyclerListView.SelectionAdapter { } break; } - case 2: { + case VIEW_TYPE_DIALOG_CELL: { DialogCell cell = (DialogCell) holder.itemView; cell.useSeparator = (position != getItemCount() - 1); MessageObject messageObject = (MessageObject) getItem(position); cell.setDialog(messageObject.getDialogId(), messageObject, messageObject.messageOwner.date, false); break; } - case 4: { + case VIEW_TYPE_HASHTAG_CELL: { HashtagSearchCell cell = (HashtagSearchCell) holder.itemView; cell.setText(searchResultHashtags.get(position - 1)); cell.setNeedDivider(position != searchResultHashtags.size()); break; } - case 5: { + case VIEW_TYPE_CATEGORY_LIST: { RecyclerListView recyclerListView = (RecyclerListView) holder.itemView; ((CategoryAdapterRecycler) recyclerListView.getAdapter()).setIndex(position / 2); break; } - case 6: { + case VIEW_TYPE_ADD_BY_PHONE: { String str = (String) getItem(position); TextCell cell = (TextCell) holder.itemView; cell.setColors(null, Theme.key_windowBackgroundWhiteBlueText2); @@ -1233,15 +1240,15 @@ public class DialogsSearchAdapter extends RecyclerListView.SelectionAdapter { if (isRecentSearchDisplayed()) { int offset = (!MediaDataController.getInstance(currentAccount).hints.isEmpty() ? 1 : 0); if (i < offset) { - return 5; + return VIEW_TYPE_CATEGORY_LIST; } if (i == offset) { - return 1; + return VIEW_TYPE_GRAY_SECTION; } - return 0; + return VIEW_TYPE_PROFILE_CELL; } if (!searchResultHashtags.isEmpty()) { - return i == 0 ? 1 : 4; + return i == 0 ? VIEW_TYPE_GRAY_SECTION : VIEW_TYPE_HASHTAG_CELL; } ArrayList globalSearch = searchAdapterHelper.getGlobalSearch(); int localCount = searchResult.size(); @@ -1257,11 +1264,11 @@ public class DialogsSearchAdapter extends RecyclerListView.SelectionAdapter { int messagesCount = searchResultMessages.isEmpty() ? 0 : searchResultMessages.size() + 1; if (i >= 0 && i < localCount) { - return 0; + return VIEW_TYPE_PROFILE_CELL; } else { i -= localCount; if (i >= 0 && i < localServerCount) { - return 0; + return VIEW_TYPE_PROFILE_CELL; } else { i -= localServerCount; if (i >= 0 && i < phoneCount) { @@ -1269,34 +1276,34 @@ public class DialogsSearchAdapter extends RecyclerListView.SelectionAdapter { if (object instanceof String) { String str = (String) object; if ("section".equals(str)) { - return 1; + return VIEW_TYPE_GRAY_SECTION; } else { - return 6; + return VIEW_TYPE_ADD_BY_PHONE; } } - return 0; + return VIEW_TYPE_PROFILE_CELL; } else { i -= phoneCount; if (i >= 0 && i < globalCount) { if (i == 0) { - return 1; + return VIEW_TYPE_GRAY_SECTION; } else { - return 0; + return VIEW_TYPE_PROFILE_CELL; } } else { i -= globalCount; if (i >= 0 && i < messagesCount) { if (i == 0) { - return 1; + return VIEW_TYPE_GRAY_SECTION; } else { - return 2; + return VIEW_TYPE_DIALOG_CELL; } } } } } } - return 3; + return VIEW_TYPE_LOADING; } public void setFiltersDelegate(FilteredSearchView.Delegate filtersDelegate, boolean update) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Adapters/DrawerLayoutAdapter.java b/TMessagesProj/src/main/java/org/telegram/ui/Adapters/DrawerLayoutAdapter.java index a863a977a..741297e35 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Adapters/DrawerLayoutAdapter.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Adapters/DrawerLayoutAdapter.java @@ -19,6 +19,8 @@ import org.telegram.messenger.LocaleController; import org.telegram.messenger.MessagesController; import org.telegram.messenger.R; import org.telegram.messenger.UserConfig; +import org.telegram.ui.ActionBar.ActionBarLayout; +import org.telegram.ui.ActionBar.DrawerLayoutContainer; import org.telegram.ui.ActionBar.Theme; import org.telegram.ui.Cells.DrawerActionCell; import org.telegram.ui.Cells.DividerCell; @@ -37,6 +39,7 @@ import androidx.recyclerview.widget.RecyclerView; public class DrawerLayoutAdapter extends RecyclerListView.SelectionAdapter { private Context mContext; + private DrawerLayoutContainer mDrawerLayoutContainer; private ArrayList items = new ArrayList<>(11); private ArrayList accountNumbers = new ArrayList<>(); private boolean accountsShown; @@ -44,8 +47,9 @@ public class DrawerLayoutAdapter extends RecyclerListView.SelectionAdapter { private SideMenultItemAnimator itemAnimator; private boolean hasGps; - public DrawerLayoutAdapter(Context context, SideMenultItemAnimator animator) { + public DrawerLayoutAdapter(Context context, SideMenultItemAnimator animator, DrawerLayoutContainer drawerLayoutContainer) { mContext = context; + mDrawerLayoutContainer = drawerLayoutContainer; itemAnimator = animator; accountsShown = UserConfig.getActivatedAccountsCount() > 1 && MessagesController.getGlobalMainSettings().getBoolean("accountsShown", true); Theme.createCommonDialogResources(context); @@ -116,7 +120,7 @@ public class DrawerLayoutAdapter extends RecyclerListView.SelectionAdapter { View view; switch (viewType) { case 0: - view = profileCell = new DrawerProfileCell(mContext); + view = profileCell = new DrawerProfileCell(mContext, mDrawerLayoutContainer); break; case 2: view = new DividerCell(mContext); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ArticleViewer.java b/TMessagesProj/src/main/java/org/telegram/ui/ArticleViewer.java index e32c5b715..7bc02653a 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ArticleViewer.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ArticleViewer.java @@ -149,6 +149,7 @@ import org.telegram.ui.Components.EditTextBoldCursor; import org.telegram.ui.Components.LayoutHelper; import org.telegram.ui.Components.LineProgressView; import org.telegram.ui.Components.LinkPath; +import org.telegram.ui.Components.LinkSpanDrawable; import org.telegram.ui.Components.MediaActionDrawable; import org.telegram.ui.Components.RadialProgress2; import org.telegram.ui.Components.RadioButton; @@ -274,7 +275,8 @@ public class ArticleViewer implements NotificationCenter.NotificationCenterDeleg private int pressCount = 0; private CheckForTap pendingCheckForTap = null; - private TextPaintUrlSpan pressedLink; + private LinkSpanDrawable pressedLink; + private LinkSpanDrawable.LinkCollector links = new LinkSpanDrawable.LinkCollector(); private BottomSheet linkSheet; private int pressedLayoutY; private DrawingText pressedLinkOwnerLayout; @@ -380,6 +382,8 @@ public class ArticleViewer implements NotificationCenter.NotificationCenterDeleg } public class DrawingText implements TextSelectionHelper.TextLayoutBlock { + public View latestParentView; + public StaticLayout textLayout; public LinkPath textPath; public LinkPath markPath; @@ -392,7 +396,9 @@ public class ArticleViewer implements NotificationCenter.NotificationCenterDeleg public int row; public CharSequence prefix; - public void draw(Canvas canvas) { + public void draw(Canvas canvas, View view) { + latestParentView = view; + if (!searchResults.isEmpty()) { SearchResult result = searchResults.get(currentSearchIndex); if (result.block == parentBlock && (result.text == parentText || result.text instanceof String && parentText == null)) { @@ -421,7 +427,21 @@ public class ArticleViewer implements NotificationCenter.NotificationCenterDeleg if (markPath != null) { canvas.drawPath(markPath, webpageMarkPaint); } - drawLayoutLink(canvas, this); + if (links.draw(canvas, this)) { + view.invalidate(); + } + if (pressedLinkOwnerLayout == this && pressedLink == null && drawBlockSelection) { + float width; + float x; + if (getLineCount() == 1) { + width = getLineWidth(0); + x = getLineLeft(0); + } else { + width = getWidth(); + x = 0; + } + canvas.drawRect(-AndroidUtilities.dp(2) + x, 0, x + width + AndroidUtilities.dp(2), getHeight(), urlPaint); + } textLayout.draw(canvas); } @@ -1084,8 +1104,8 @@ public class ArticleViewer implements NotificationCenter.NotificationCenterDeleg if (checkingForLongPress && windowView != null) { checkingForLongPress = false; if (pressedLink != null) { - windowView.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS); - showCopyPopup(pressedLink.getUrl()); + windowView.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS, HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING); + showCopyPopup(pressedLink.getSpan().getUrl()); pressedLink = null; pressedLinkOwnerLayout = null; if (pressedLinkOwnerView != null) { @@ -1098,10 +1118,10 @@ public class ArticleViewer implements NotificationCenter.NotificationCenterDeleg textSelectionHelper.trySelect(pressedLinkOwnerView); } if (textSelectionHelper.isSelectionMode()) { - windowView.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS); + windowView.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS, HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING); } } else if (pressedLinkOwnerLayout != null && pressedLinkOwnerView != null) { - windowView.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS); + windowView.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS, HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING);; int[] location = new int[2]; pressedLinkOwnerView.getLocationInWindow(location); @@ -1150,16 +1170,16 @@ public class ArticleViewer implements NotificationCenter.NotificationCenterDeleg float lightness = (0.2126f * Color.red(color2) + 0.7152f * Color.green(color2) + 0.0722f * Color.blue(color2)) / 255.0f; webpageSearchPaint.setColor(lightness <= 0.705f ? 0xffd1982e : 0xffffe669); webpageUrlPaint.setColor(Theme.getColor(Theme.key_windowBackgroundWhiteLinkSelection) & 0x33ffffff); - webpageUrlPaint.setPathEffect(LinkPath.roundedEffect); + webpageUrlPaint.setPathEffect(LinkPath.getRoundedEffect()); urlPaint.setColor(Theme.getColor(Theme.key_windowBackgroundWhiteLinkSelection) & 0x33ffffff); - urlPaint.setPathEffect(LinkPath.roundedEffect); + urlPaint.setPathEffect(LinkPath.getRoundedEffect()); tableHalfLinePaint.setColor(Theme.getColor(Theme.key_windowBackgroundWhiteInputField)); tableLinePaint.setColor(Theme.getColor(Theme.key_windowBackgroundWhiteInputField)); photoBackgroundPaint.setColor(0x0f000000); dividerPaint.setColor(Theme.getColor(Theme.key_divider)); webpageMarkPaint.setColor(Theme.getColor(Theme.key_windowBackgroundWhiteLinkSelection) & 0x33ffffff); - webpageMarkPaint.setPathEffect(LinkPath.roundedEffect); + webpageMarkPaint.setPathEffect(LinkPath.getRoundedEffect()); int color = Theme.getColor(Theme.key_switchTrack); int r = Color.red(color); @@ -1228,6 +1248,7 @@ public class ArticleViewer implements NotificationCenter.NotificationCenterDeleg AndroidUtilities.addToClipboard(url); } }); + builder.setOnPreDismissListener(di -> links.clear()); BottomSheet sheet = builder.create(); showDialog(sheet); } @@ -2577,26 +2598,6 @@ public class ArticleViewer implements NotificationCenter.NotificationCenterDeleg return drawingText; } - private void drawLayoutLink(Canvas canvas, DrawingText layout) { - if (canvas == null || layout == null || pressedLinkOwnerLayout != layout) { - return; - } - if (pressedLink != null) { - canvas.drawPath(urlPath, urlPaint); - } else if (drawBlockSelection && layout != null) { - float width; - float x; - if (layout.getLineCount() == 1) { - width = layout.getLineWidth(0); - x = layout.getLineLeft(0); - } else { - width = layout.getWidth(); - x = 0; - } - canvas.drawRect(-AndroidUtilities.dp(2) + x, 0, x + width + AndroidUtilities.dp(2), layout.getHeight(), urlPaint); - } - } - private boolean checkLayoutForLinks(WebpageAdapter adapter, MotionEvent event, View parentView, DrawingText drawingText, int layoutX, int layoutY) { if (pageSwitchAnimation != null || parentView == null || !textSelectionHelper.isSelectable(parentView)) { return false; @@ -2616,7 +2617,6 @@ public class ArticleViewer implements NotificationCenter.NotificationCenterDeleg } if (x >= layoutX + left && x <= left + layoutX + width && y >= layoutY && y <= layoutY + layout.getHeight()) { pressedLinkOwnerLayout = drawingText; - pressedLinkOwnerView = parentView; pressedLayoutY = layoutY; CharSequence text = layout.getText(); if (text instanceof Spannable) { @@ -2630,25 +2630,32 @@ public class ArticleViewer implements NotificationCenter.NotificationCenterDeleg Spannable buffer = (Spannable) layout.getText(); TextPaintUrlSpan[] link = buffer.getSpans(off, off, TextPaintUrlSpan.class); if (link != null && link.length > 0) { - pressedLink = link[0]; - int pressedStart = buffer.getSpanStart(pressedLink); - int pressedEnd = buffer.getSpanEnd(pressedLink); + TextPaintUrlSpan selectedLink = link[0]; + int pressedStart = buffer.getSpanStart(selectedLink); + int pressedEnd = buffer.getSpanEnd(selectedLink); for (int a = 1; a < link.length; a++) { TextPaintUrlSpan span = link[a]; int start = buffer.getSpanStart(span); int end = buffer.getSpanEnd(span); if (pressedStart > start || end > pressedEnd) { - pressedLink = span; + selectedLink = span; pressedStart = start; pressedEnd = end; } } + if (pressedLink != null) { + links.removeLink(pressedLink); + } + pressedLink = new LinkSpanDrawable(selectedLink, null, x, y); + pressedLink.setColor(Theme.getColor(Theme.key_windowBackgroundWhiteLinkSelection) & 0x33ffffff); + links.addLink(pressedLink, pressedLinkOwnerLayout); try { - urlPath.setUseRoundRect(true); - urlPath.setCurrentLayout(layout, pressedStart, 0); - int shift = pressedLink.getTextPaint() != null ? pressedLink.getTextPaint().baselineShift : 0; - urlPath.setBaselineShift(shift != 0 ? shift + AndroidUtilities.dp(shift > 0 ? 5 : -2) : 0); - layout.getSelectionPath(pressedStart, pressedEnd, urlPath); + LinkPath path = pressedLink.obtainNewPath(); + path.setCurrentLayout(layout, pressedStart, 0); + TextPaint textPaint = selectedLink.getTextPaint(); + int shift = textPaint != null ? textPaint.baselineShift : 0; + path.setBaselineShift(shift != 0 ? shift + AndroidUtilities.dp(shift > 0 ? 5 : -2) : 0); + layout.getSelectionPath(pressedStart, pressedEnd, path); parentView.invalidate(); } catch (Exception e) { FileLog.e(e); @@ -2663,7 +2670,7 @@ public class ArticleViewer implements NotificationCenter.NotificationCenterDeleg } else if (event.getAction() == MotionEvent.ACTION_UP) { if (pressedLink != null) { removeLink = true; - String url = pressedLink.getUrl(); + String url = pressedLink.getSpan().getUrl(); if (url != null) { if (linkSheet != null) { linkSheet.dismiss(); @@ -2697,7 +2704,7 @@ public class ArticleViewer implements NotificationCenter.NotificationCenterDeleg anchor = null; } if (!isAnchor) { - openWebpageUrl(pressedLink.getUrl(), anchor); + openWebpageUrl(pressedLink.getSpan().getUrl(), anchor); } } } @@ -2726,6 +2733,7 @@ public class ArticleViewer implements NotificationCenter.NotificationCenterDeleg return; } View parentView = pressedLinkOwnerView; + links.clear(); pressedLink = null; pressedLinkOwnerLayout = null; pressedLinkOwnerView = null; @@ -6189,14 +6197,14 @@ public class ArticleViewer implements NotificationCenter.NotificationCenterDeleg canvas.save(); canvas.translate(textX, textY); drawTextSelection(canvas, this, count++); - captionLayout.draw(canvas); + captionLayout.draw(canvas, this); canvas.restore(); } if (creditLayout != null) { canvas.save(); canvas.translate(textX, textY + creditOffset); drawTextSelection(canvas, this, count); - creditLayout.draw(canvas); + creditLayout.draw(canvas, this); canvas.restore(); } if (currentBlock.level > 0) { @@ -6555,7 +6563,7 @@ public class ArticleViewer implements NotificationCenter.NotificationCenterDeleg titleLayout.y = seekBarY - AndroidUtilities.dp(16); canvas.translate(titleLayout.x, titleLayout.y); drawTextSelection(canvas, this, count++); - titleLayout.draw(canvas); + titleLayout.draw(canvas, this); canvas.restore(); } if (captionLayout != null) { @@ -6564,7 +6572,7 @@ public class ArticleViewer implements NotificationCenter.NotificationCenterDeleg captionLayout.y = textY; canvas.translate(textX, textY); drawTextSelection(canvas, this, count++); - captionLayout.draw(canvas); + captionLayout.draw(canvas, this); canvas.restore(); } if (creditLayout != null) { @@ -6573,7 +6581,7 @@ public class ArticleViewer implements NotificationCenter.NotificationCenterDeleg creditLayout.y = textY + creditOffset; canvas.translate(textX, textY + creditOffset); drawTextSelection(canvas, this, count); - creditLayout.draw(canvas); + creditLayout.draw(canvas, this); canvas.restore(); } if (currentBlock.level > 0) { @@ -6886,14 +6894,14 @@ public class ArticleViewer implements NotificationCenter.NotificationCenterDeleg canvas.save(); canvas.translate(AndroidUtilities.dp(18 + 14 + (avatarVisible ? 40 + 14 : 0)), AndroidUtilities.dp(dateLayout != null ? 10 : 19)); drawTextSelection(canvas, this, count++); - nameLayout.draw(canvas); + nameLayout.draw(canvas, this); canvas.restore(); } if (dateLayout != null) { canvas.save(); canvas.translate(AndroidUtilities.dp(18 + 14 + (avatarVisible ? 40 + 14 : 0)), AndroidUtilities.dp(29)); drawTextSelection(canvas, this, count++); - dateLayout.draw(canvas); + dateLayout.draw(canvas, this); canvas.restore(); } canvas.drawRect(AndroidUtilities.dp(18), AndroidUtilities.dp(6), AndroidUtilities.dp(20), lineHeight - (currentBlock.level != 0 ? 0 : AndroidUtilities.dp(6)), quoteLinePaint); @@ -6902,14 +6910,14 @@ public class ArticleViewer implements NotificationCenter.NotificationCenterDeleg canvas.save(); canvas.translate(textX, textY); drawTextSelection(canvas, this, count++); - captionLayout.draw(canvas); + captionLayout.draw(canvas, this); canvas.restore(); } if (creditLayout != null) { canvas.save(); canvas.translate(textX, textY + creditOffset); drawTextSelection(canvas, this, count); - creditLayout.draw(canvas); + creditLayout.draw(canvas, this); canvas.restore(); } } @@ -6998,7 +7006,7 @@ public class ArticleViewer implements NotificationCenter.NotificationCenterDeleg canvas.save(); canvas.translate(textX, textY); drawTextSelection(canvas, this); - textLayout.draw(canvas); + textLayout.draw(canvas, this); canvas.restore(); } if (currentBlock.level > 0) { @@ -7129,7 +7137,7 @@ public class ArticleViewer implements NotificationCenter.NotificationCenterDeleg } @Override - public TextureView onSwitchInlineMode(View controlsView, boolean inline, float aspectRatio, int rotation, boolean animated) { + public TextureView onSwitchInlineMode(View controlsView, boolean inline, int videoWidth, int videoHeight, int rotation, boolean animated) { return null; } @@ -7430,14 +7438,14 @@ public class ArticleViewer implements NotificationCenter.NotificationCenterDeleg canvas.save(); canvas.translate(textX, textY); drawTextSelection(canvas, this, count++); - captionLayout.draw(canvas); + captionLayout.draw(canvas, this); canvas.restore(); } if (creditLayout != null) { canvas.save(); canvas.translate(textX, textY + creditOffset); drawTextSelection(canvas, this, count); - creditLayout.draw(canvas); + creditLayout.draw(canvas, this); canvas.restore(); } if (currentBlock.level > 0) { @@ -7715,7 +7723,7 @@ public class ArticleViewer implements NotificationCenter.NotificationCenterDeleg canvas.save(); canvas.translate(textX, textY); drawTextSelection(canvas, this, 0); - titleLayout.draw(canvas); + titleLayout.draw(canvas, this); canvas.restore(); } if (currentBlock.level > 0) { @@ -8319,14 +8327,14 @@ public class ArticleViewer implements NotificationCenter.NotificationCenterDeleg canvas.save(); canvas.translate(textX, textY); drawTextSelection(canvas, this, count++); - captionLayout.draw(canvas); + captionLayout.draw(canvas, this); canvas.restore(); } if (creditLayout != null) { canvas.save(); canvas.translate(textX, textY + creditOffset); drawTextSelection(canvas, this, count); - creditLayout.draw(canvas); + creditLayout.draw(canvas, this); canvas.restore(); } if (currentBlock.level > 0) { @@ -8579,14 +8587,14 @@ public class ArticleViewer implements NotificationCenter.NotificationCenterDeleg canvas.save(); canvas.translate(textX, textY); drawTextSelection(canvas, this, count++); - captionLayout.draw(canvas); + captionLayout.draw(canvas, this); canvas.restore(); } if (creditLayout != null) { canvas.save(); canvas.translate(textX, textY + creditOffset); drawTextSelection(canvas, this, count); - creditLayout.draw(canvas); + creditLayout.draw(canvas, this); canvas.restore(); } } @@ -8803,14 +8811,14 @@ public class ArticleViewer implements NotificationCenter.NotificationCenterDeleg } else { canvas.translate(AndroidUtilities.dp(15) + currentBlock.parent.maxNumWidth - (int) Math.ceil(currentBlock.numLayout.getLineWidth(0)) + currentBlock.parent.level * AndroidUtilities.dp(12), textY + numOffsetY - (drawDot ? AndroidUtilities.dp(1) : 0)); } - currentBlock.numLayout.draw(canvas); + currentBlock.numLayout.draw(canvas, this); canvas.restore(); } if (textLayout != null) { canvas.save(); canvas.translate(textX, textY); drawTextSelection(canvas,this); - textLayout.draw(canvas); + textLayout.draw(canvas, this); canvas.restore(); } } @@ -9039,14 +9047,14 @@ public class ArticleViewer implements NotificationCenter.NotificationCenterDeleg } else { canvas.translate(AndroidUtilities.dp(18) + currentBlock.parent.maxNumWidth - (int) Math.ceil(currentBlock.numLayout.getLineWidth(0)) + currentBlock.parent.level * AndroidUtilities.dp(20), textY + numOffsetY); } - currentBlock.numLayout.draw(canvas); + currentBlock.numLayout.draw(canvas, this); canvas.restore(); } if (textLayout != null) { canvas.save(); canvas.translate(textX, textY); drawTextSelection(canvas, this); - textLayout.draw(canvas); + textLayout.draw(canvas, this); canvas.restore(); } } @@ -9155,7 +9163,7 @@ public class ArticleViewer implements NotificationCenter.NotificationCenterDeleg canvas.save(); canvas.translate(textX, textY); drawTextSelection(canvas,this); - textLayout.draw(canvas); + textLayout.draw(canvas, this); canvas.restore(); } @@ -9262,7 +9270,7 @@ public class ArticleViewer implements NotificationCenter.NotificationCenterDeleg canvas.save(); canvas.translate(textX, textY); drawTextSelection(canvas, this); - textLayout.draw(canvas); + textLayout.draw(canvas, this); canvas.restore(); } } @@ -9398,12 +9406,12 @@ public class ArticleViewer implements NotificationCenter.NotificationCenterDeleg canvas.translate(textX, AndroidUtilities.dp(10)); if (textLayout != null) { drawTextSelection(canvas, this, count++); - textLayout.draw(canvas); + textLayout.draw(canvas, this); } if (textLayout2 != null) { canvas.translate(0, textOffset); drawTextSelection(canvas, this, count); - textLayout2.draw(canvas); + textLayout2.draw(canvas, this); } canvas.restore(); if (divider) { @@ -9476,7 +9484,7 @@ public class ArticleViewer implements NotificationCenter.NotificationCenterDeleg canvas.save(); canvas.translate(textX, textY); drawTextSelection(canvas, this); - textLayout.draw(canvas); + textLayout.draw(canvas, this); canvas.restore(); } } @@ -9573,7 +9581,7 @@ public class ArticleViewer implements NotificationCenter.NotificationCenterDeleg canvas.save(); canvas.translate(textX, textY); drawTextSelection(canvas, this); - textLayout.draw(canvas); + textLayout.draw(canvas, this); canvas.restore(); } } @@ -9662,14 +9670,14 @@ public class ArticleViewer implements NotificationCenter.NotificationCenterDeleg canvas.save(); canvas.translate(textX, textY); drawTextSelection(canvas, this, count++); - textLayout.draw(canvas); + textLayout.draw(canvas, this); canvas.restore(); } if (textLayout2 != null) { canvas.save(); canvas.translate(textX, textY2); drawTextSelection(canvas, this, count); - textLayout2.draw(canvas); + textLayout2.draw(canvas, this); canvas.restore(); } } @@ -9773,14 +9781,14 @@ public class ArticleViewer implements NotificationCenter.NotificationCenterDeleg canvas.save(); canvas.translate(textX, textY); drawTextSelection(canvas, this, counter++); - textLayout.draw(canvas); + textLayout.draw(canvas, this); canvas.restore(); } if (textLayout2 != null) { canvas.save(); canvas.translate(textX, textY2); drawTextSelection(canvas, this, counter); - textLayout2.draw(canvas); + textLayout2.draw(canvas, this); canvas.restore(); } if (parentAdapter.isRtl) { @@ -10074,14 +10082,14 @@ public class ArticleViewer implements NotificationCenter.NotificationCenterDeleg canvas.save(); canvas.translate(textX, textY); drawTextSelection(canvas,this, count++); - captionLayout.draw(canvas); + captionLayout.draw(canvas, this); canvas.restore(); } if (creditLayout != null) { canvas.save(); canvas.translate(textX, textY + creditOffset); drawTextSelection(canvas,this, count); - creditLayout.draw(canvas); + creditLayout.draw(canvas, this); canvas.restore(); } if (currentBlock.level > 0) { @@ -10369,14 +10377,14 @@ public class ArticleViewer implements NotificationCenter.NotificationCenterDeleg canvas.save(); canvas.translate(textX, textY); drawTextSelection(canvas, this, count++); - captionLayout.draw(canvas); + captionLayout.draw(canvas, this); canvas.restore(); } if (creditLayout != null) { canvas.save(); canvas.translate(textX, textY + creditOffset); drawTextSelection(canvas, this, count); - creditLayout.draw(canvas); + creditLayout.draw(canvas, this); canvas.restore(); } if (currentBlock.level > 0) { @@ -10580,7 +10588,7 @@ public class ArticleViewer implements NotificationCenter.NotificationCenterDeleg if (currentType == 0) { drawTextSelection(canvas, this); } - textLayout.draw(canvas); + textLayout.draw(canvas, this); canvas.restore(); } } @@ -10683,7 +10691,7 @@ public class ArticleViewer implements NotificationCenter.NotificationCenterDeleg canvas.save(); canvas.translate(textX, textY); drawTextSelection(canvas, this); - textLayout.draw(canvas); + textLayout.draw(canvas, this); canvas.restore(); } } @@ -10765,7 +10773,7 @@ public class ArticleViewer implements NotificationCenter.NotificationCenterDeleg canvas.save(); canvas.translate(textX, textY); drawTextSelection(canvas,this); - textLayout.draw(canvas); + textLayout.draw(canvas, this); canvas.restore(); } } @@ -10847,7 +10855,7 @@ public class ArticleViewer implements NotificationCenter.NotificationCenterDeleg canvas.save(); canvas.translate(textX, textY); drawTextSelection(canvas, this); - textLayout.draw(canvas); + textLayout.draw(canvas, this); canvas.restore(); } } @@ -10926,7 +10934,7 @@ public class ArticleViewer implements NotificationCenter.NotificationCenterDeleg canvas.save(); canvas.translate(textX, textY); drawTextSelection(canvas, this); - textLayout.draw(canvas); + textLayout.draw(canvas, this); canvas.restore(); } if (currentBlock.level > 0) { @@ -11007,7 +11015,7 @@ public class ArticleViewer implements NotificationCenter.NotificationCenterDeleg if (textLayout != null) { canvas.save(); drawTextSelection(canvas, BlockPreformattedCell.this); - textLayout.draw(canvas); + textLayout.draw(canvas, this); canvas.restore(); textLayout.x = (int) getX(); textLayout.y = (int) getY(); @@ -11119,7 +11127,7 @@ public class ArticleViewer implements NotificationCenter.NotificationCenterDeleg canvas.save(); canvas.translate(textX, textY); drawTextSelection(canvas, this); - textLayout.draw(canvas); + textLayout.draw(canvas, this); canvas.restore(); } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/CacheControlActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/CacheControlActivity.java index 68a0814af..aae03c136 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/CacheControlActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/CacheControlActivity.java @@ -121,10 +121,12 @@ public class CacheControlActivity extends BaseFragment implements NotificationCe return; } photoSize = getDirectorySize(FileLoader.checkDirectory(FileLoader.MEDIA_DIR_IMAGE), 0); + photoSize += getDirectorySize(FileLoader.checkDirectory(FileLoader.MEDIA_DIR_IMAGE_PUBLIC), 0); if (canceled) { return; } videoSize = getDirectorySize(FileLoader.checkDirectory(FileLoader.MEDIA_DIR_VIDEO), 0); + videoSize += getDirectorySize(FileLoader.checkDirectory(FileLoader.MEDIA_DIR_VIDEO_PUBLIC), 0); if (canceled) { return; } @@ -320,6 +322,19 @@ public class CacheControlActivity extends BaseFragment implements NotificationCe if (file != null) { Utilities.clearDir(file.getAbsolutePath(), documentsMusicType, Long.MAX_VALUE, false); } + if (type == FileLoader.MEDIA_DIR_IMAGE || type == FileLoader.MEDIA_DIR_VIDEO) { + int publicDirectoryType; + if (type == FileLoader.MEDIA_DIR_IMAGE) { + publicDirectoryType = FileLoader.MEDIA_DIR_IMAGE_PUBLIC; + } else { + publicDirectoryType = FileLoader.MEDIA_DIR_VIDEO_PUBLIC; + } + file = FileLoader.checkDirectory(publicDirectoryType); + + if (file != null) { + Utilities.clearDir(file.getAbsolutePath(), documentsMusicType, Long.MAX_VALUE, false); + } + } if (type == FileLoader.MEDIA_DIR_CACHE) { cacheSize = getDirectorySize(FileLoader.checkDirectory(FileLoader.MEDIA_DIR_CACHE), documentsMusicType); imagesCleared = true; @@ -334,8 +349,10 @@ public class CacheControlActivity extends BaseFragment implements NotificationCe } else if (type == FileLoader.MEDIA_DIR_IMAGE) { imagesCleared = true; photoSize = getDirectorySize(FileLoader.checkDirectory(FileLoader.MEDIA_DIR_IMAGE), documentsMusicType); + photoSize += getDirectorySize(FileLoader.checkDirectory(FileLoader.MEDIA_DIR_IMAGE_PUBLIC), documentsMusicType); } else if (type == FileLoader.MEDIA_DIR_VIDEO) { videoSize = getDirectorySize(FileLoader.checkDirectory(FileLoader.MEDIA_DIR_VIDEO), documentsMusicType); + videoSize += getDirectorySize(FileLoader.checkDirectory(FileLoader.MEDIA_DIR_VIDEO_PUBLIC), documentsMusicType); } else if (type == 100) { imagesCleared = true; stickersSize = getDirectorySize(new File(FileLoader.checkDirectory(FileLoader.MEDIA_DIR_CACHE), "acache"), documentsMusicType); @@ -384,8 +401,11 @@ public class CacheControlActivity extends BaseFragment implements NotificationCe FileLog.e(e); } + getMediaDataController().ringtoneDataStore.checkRingtoneSoundsLoaded(); cacheRemovedTooltip.setInfoText(LocaleController.formatString("CacheWasCleared", R.string.CacheWasCleared, AndroidUtilities.formatFileSize(finalClearedSize))); cacheRemovedTooltip.showWithAction(0, UndoView.ACTION_CACHE_WAS_CLEARED, null, null); + + getMediaDataController().loadAttachMenuBots(false, true); }); }); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/CalendarActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/CalendarActivity.java index 400ab0249..dc9c3f422 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/CalendarActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/CalendarActivity.java @@ -308,7 +308,7 @@ public class CalendarActivity extends BaseFragment { selectDaysHint.showForView(bottomBar, true); return; } - AlertsCreator.createClearDaysDialogAlert(this, lastDaysSelected, getMessagesController().getUser(dialogId), new MessagesStorage.BooleanCallback() { + AlertsCreator.createClearDaysDialogAlert(this, lastDaysSelected, getMessagesController().getUser(dialogId), null, false, new MessagesStorage.BooleanCallback() { @Override public void run(boolean forAll) { finishFragment(); @@ -743,7 +743,7 @@ public class CalendarActivity extends BaseFragment { if (parentLayout.fragmentsStack.size() >= 3) { BaseFragment fragment = parentLayout.fragmentsStack.get(parentLayout.fragmentsStack.size() - 3); if (fragment instanceof ChatActivity) { - AlertsCreator.createClearDaysDialogAlert(CalendarActivity.this, 1, getMessagesController().getUser(dialogId), new MessagesStorage.BooleanCallback() { + AlertsCreator.createClearDaysDialogAlert(CalendarActivity.this, 1, getMessagesController().getUser(dialogId), null, false, new MessagesStorage.BooleanCallback() { @Override public void run(boolean forAll) { finishFragment(); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/CameraScanActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/CameraScanActivity.java index 5abde8de1..988847827 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/CameraScanActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/CameraScanActivity.java @@ -27,13 +27,19 @@ import android.os.Build; import android.os.Handler; import android.os.HandlerThread; import android.os.SystemClock; +import android.text.Layout; +import android.text.Spannable; import android.text.SpannableStringBuilder; import android.text.Spanned; +import android.text.StaticLayout; import android.text.TextUtils; +import android.text.style.ClickableSpan; import android.util.SparseArray; import android.util.TypedValue; import android.view.Gravity; +import android.view.MotionEvent; import android.view.View; +import android.view.ViewConfiguration; import android.view.ViewGroup; import android.view.Window; import android.view.WindowManager; @@ -81,6 +87,7 @@ import org.telegram.ui.Components.AnimationProperties; 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.TypefaceSpan; import org.telegram.ui.Components.URLSpanNoUnderline; @@ -418,7 +425,7 @@ public class CameraScanActivity extends BaseFragment { fragmentView = viewGroup; if (currentType == TYPE_QR || currentType == TYPE_QR_LOGIN) { - fragmentView.postDelayed(this::initCameraView, 200); + fragmentView.postDelayed(this::initCameraView, 350); } else { initCameraView(); } @@ -440,10 +447,12 @@ public class CameraScanActivity extends BaseFragment { } Paint selectionPaint = new Paint(Paint.ANTI_ALIAS_FLAG); - selectionPaint.setPathEffect(LinkPath.roundedEffect); - selectionPaint.setColor(ColorUtils.setAlphaComponent(Color.WHITE, 50)); + selectionPaint.setPathEffect(LinkPath.getRoundedEffect()); + selectionPaint.setColor(ColorUtils.setAlphaComponent(Color.WHITE, 40)); titleTextView = new TextView(context) { LinkPath textPath; + private LinkSpanDrawable pressedLink; + LinkSpanDrawable.LinkCollector links = new LinkSpanDrawable.LinkCollector(this); @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { @@ -467,11 +476,56 @@ public class CameraScanActivity extends BaseFragment { } } + @Override + public boolean onTouchEvent(MotionEvent e) { + final Layout textLayout = getLayout(); + int textX = 0, textY = 0; + int x = (int) (e.getX() - textX); + int y = (int) (e.getY() - textY); + if (e.getAction() == MotionEvent.ACTION_DOWN || e.getAction() == MotionEvent.ACTION_UP) { + final int line = textLayout.getLineForVertical(y); + final int off = textLayout.getOffsetForHorizontal(line, x); + + final float left = textLayout.getLineLeft(line); + if (left <= x && left + textLayout.getLineWidth(line) >= x && y >= 0 && y <= textLayout.getHeight()) { + Spannable buffer = (Spannable) textLayout.getText(); + ClickableSpan[] link = buffer.getSpans(off, off, ClickableSpan.class); + if (link.length != 0) { + links.clear(); + if (e.getAction() == MotionEvent.ACTION_DOWN) { + pressedLink = new LinkSpanDrawable(link[0], null, e.getX(), e.getY()); + pressedLink.setColor(0x2dffffff); + links.addLink(pressedLink); + int start = buffer.getSpanStart(pressedLink.getSpan()); + int end = buffer.getSpanEnd(pressedLink.getSpan()); + LinkPath path = pressedLink.obtainNewPath(); + path.setCurrentLayout(textLayout, start, textY); + textLayout.getSelectionPath(start, end, path); + } else if (e.getAction() == MotionEvent.ACTION_UP) { + if (pressedLink != null && pressedLink.getSpan() == link[0]) { + link[0].onClick(this); + } + pressedLink = null; + } + return true; + } + } + } + if (e.getAction() == MotionEvent.ACTION_UP || e.getAction() == MotionEvent.ACTION_CANCEL) { + links.clear(); + pressedLink = null; + } + return super.onTouchEvent(e); + } + @Override protected void onDraw(Canvas canvas) { if (textPath != null) { canvas.drawPath(textPath, selectionPaint); } + if (links.draw(canvas)) { + invalidate(); + } super.onDraw(canvas); } }; @@ -507,8 +561,8 @@ public class CameraScanActivity extends BaseFragment { SpannableStringBuilder spanned = new SpannableStringBuilder(text); String[] links = new String[] { - LocaleController.getString("AuthAnotherWebClientUrl", R.string.AuthAnotherWebClientUrl), - LocaleController.getString("AuthAnotherClientDownloadClientUrl", R.string.AuthAnotherClientDownloadClientUrl) + LocaleController.getString("AuthAnotherClientDownloadClientUrl", R.string.AuthAnotherClientDownloadClientUrl), + LocaleController.getString("AuthAnotherWebClientUrl", R.string.AuthAnotherWebClientUrl) }; for (int i = 0; i < links.length; ++i) { text = spanned.toString(); @@ -521,15 +575,14 @@ public class CameraScanActivity extends BaseFragment { spanned.replace(index1, index1 + 1, " "); index1 += 1; index2 += 1; - spanned.setSpan(new URLSpanNoUnderline(links[i]), index1, index2 - 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + spanned.setSpan(new URLSpanNoUnderline(links[i], true), index1, index2 - 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); spanned.setSpan(new TypefaceSpan(AndroidUtilities.getTypeface("fonts/rmedium.ttf")), index1, index2 - 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); } else { break; } } - titleTextView.setLinkTextColor(Color.WHITE); - titleTextView.setHighlightColor(Theme.getColor(Theme.key_windowBackgroundWhiteLinkSelection)); + titleTextView.setLinkTextColor(0xffffffff); titleTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16); titleTextView.setLineSpacing(AndroidUtilities.dp(2), 1.0f); @@ -771,9 +824,9 @@ public class CameraScanActivity extends BaseFragment { if (normalBounds == null) { normalBounds = new RectF(); } - int width = AndroidUtilities.displaySize.x, - height = AndroidUtilities.displaySize.y, - side = (int) (Math.min(width, height) / 1.5f); + int width = Math.max(AndroidUtilities.displaySize.x, fragmentView.getWidth()), + height = Math.max(AndroidUtilities.displaySize.y, fragmentView.getHeight()), + side = (int) (Math.min(width, height) / 1.5f); normalBounds.set( (width - side) / 2f / (float) width, (height - side) / 2f / (float) height, diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/AboutLinkCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/AboutLinkCell.java index 1ebb676cf..1fea1d142 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/AboutLinkCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/AboutLinkCell.java @@ -29,6 +29,7 @@ import android.text.style.ClickableSpan; import android.text.style.URLSpan; import android.util.TypedValue; import android.view.Gravity; +import android.view.HapticFeedbackConstants; import android.view.MotionEvent; import android.view.View; import android.view.ViewConfiguration; @@ -54,6 +55,7 @@ import org.telegram.ui.Components.AlertsCreator; import org.telegram.ui.Components.BulletinFactory; import org.telegram.ui.Components.LayoutHelper; import org.telegram.ui.Components.LinkPath; +import org.telegram.ui.Components.LinkSpanDrawable; import org.telegram.ui.Components.StaticLayoutEx; import org.telegram.ui.Components.URLSpanNoUnderline; @@ -72,7 +74,8 @@ public class AboutLinkCell extends FrameLayout { private FrameLayout bottomShadow; private Drawable showMoreBackgroundDrawable; - private ClickableSpan pressedLink; + private LinkSpanDrawable pressedLink; + private LinkSpanDrawable.LinkCollector links; private Point urlPathOffset = new Point(); private LinkPath urlPath = new LinkPath(true); @@ -122,7 +125,7 @@ public class AboutLinkCell extends FrameLayout { } } else if (pressedLink != null) { try { - onLinkClick(pressedLink); + onLinkClick((ClickableSpan) pressedLink.getSpan()); } catch (Exception e) { FileLog.e(e); } @@ -136,6 +139,7 @@ public class AboutLinkCell extends FrameLayout { return result || super.onTouchEvent(event); } }; + links = new LinkSpanDrawable.LinkCollector(container); container.setClickable(true); rippleBackground = Theme.createRadSelectorDrawable(Theme.getColor(Theme.key_listSelector), 0, 0); @@ -257,15 +261,12 @@ public class AboutLinkCell extends FrameLayout { final float SPACE = AndroidUtilities.dp(3f); private void drawText(Canvas canvas) { canvas.save(); - AndroidUtilities.rectTmp.set(AndroidUtilities.dp(23 - 8), AndroidUtilities.dp(8), getWidth() - AndroidUtilities.dp(23), getHeight()); - canvas.clipRect(AndroidUtilities.rectTmp); - if (pressedLink != null) { - canvas.save(); - canvas.translate(urlPathOffset.x, urlPathOffset.y); - canvas.drawPath(urlPath, Theme.linkSelectionPaint); - canvas.restore(); + canvas.clipRect(AndroidUtilities.dp(23 - 8), AndroidUtilities.dp(8), getWidth() - AndroidUtilities.dp(23), getHeight()); + canvas.translate(textX = AndroidUtilities.dp(23), 0); + if (links != null && links.draw(canvas)) { + invalidate(); } - canvas.translate(textX = AndroidUtilities.dp(23), textY = AndroidUtilities.dp(8)); + canvas.translate(0, textY = AndroidUtilities.dp(8)); try { if (firstThreeLinesLayout == null || !shouldExpand) { @@ -324,10 +325,8 @@ public class AboutLinkCell extends FrameLayout { protected void didExtend() {} private void resetPressedLink() { - if (pressedLink != null) { - pressedLink = null; - container.invalidate(); - } + links.clear(); + pressedLink = null; AndroidUtilities.cancelRunOnUIThread(longPressedRunnable); invalidate(); } @@ -371,15 +370,19 @@ public class AboutLinkCell extends FrameLayout { public void run() { if (pressedLink != null) { String url; - if (pressedLink instanceof URLSpanNoUnderline) { - url = ((URLSpanNoUnderline) pressedLink).getURL(); - } else if (pressedLink instanceof URLSpan) { - url = ((URLSpan) pressedLink).getURL(); + if (pressedLink.getSpan() instanceof URLSpanNoUnderline) { + url = ((URLSpanNoUnderline) pressedLink.getSpan()).getURL(); + } else if (pressedLink.getSpan() instanceof URLSpan) { + url = ((URLSpan) pressedLink.getSpan()).getURL(); } else { - url = pressedLink.toString(); + url = pressedLink.getSpan().toString(); } - ClickableSpan pressedLinkFinal = pressedLink; + try { + performHapticFeedback(HapticFeedbackConstants.LONG_PRESS, HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING); + } catch (Exception ignore) {} + + ClickableSpan pressedLinkFinal = (ClickableSpan) pressedLink.getSpan(); BottomSheet.Builder builder = new BottomSheet.Builder(parentFragment.getParentActivity()); builder.setTitle(url); builder.setItems(new CharSequence[]{LocaleController.getString("Open", R.string.Open), LocaleController.getString("Copy", R.string.Copy)}, (dialog, which) -> { @@ -398,8 +401,10 @@ public class AboutLinkCell extends FrameLayout { } } }); + builder.setOnPreDismissListener(di -> resetPressedLink()); builder.show(); - resetPressedLink(); + + pressedLink = null; } } }; @@ -417,16 +422,13 @@ public class AboutLinkCell extends FrameLayout { ClickableSpan[] link = buffer.getSpans(off, off, ClickableSpan.class); if (link.length != 0) { resetPressedLink(); - pressedLink = link[0]; - try { - int start = buffer.getSpanStart(pressedLink); - urlPathOffset.set(textX, textY); - urlPath.setCurrentLayout(textLayout, start, 0); - textLayout.getSelectionPath(start, buffer.getSpanEnd(pressedLink), urlPath); - } catch (Exception e) { - FileLog.e(e); - } - container.invalidate(); + pressedLink = new LinkSpanDrawable(link[0], parentFragment.getResourceProvider(), ex, ey); + links.addLink(pressedLink); + int start = buffer.getSpanStart(pressedLink.getSpan()); + int end = buffer.getSpanEnd(pressedLink.getSpan()); + LinkPath path = pressedLink.obtainNewPath(); + path.setCurrentLayout(textLayout, start, textY); + textLayout.getSelectionPath(start, end, path); AndroidUtilities.runOnUIThread(longPressedRunnable, ViewConfiguration.getLongPressTimeout()); return true; } else { @@ -599,7 +601,6 @@ public class AboutLinkCell extends FrameLayout { int height = updateHeight(); super.onMeasure( widthMeasureSpec, -// heightMeasureSpec MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY) ); } 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 7c8fa4458..df47f8b6d 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatActionCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatActionCell.java @@ -73,7 +73,8 @@ public class ChatActionCell extends BaseCell implements DownloadController.FileD default void didClickImage(ChatActionCell cell) { } - default void didLongPress(ChatActionCell cell, float x, float y) { + default boolean didLongPress(ChatActionCell cell, float x, float y) { + return false; } default void needOpenUserProfile(long uid) { @@ -283,9 +284,9 @@ public class ChatActionCell extends BaseCell implements DownloadController.FileD @Override protected boolean onLongPress() { if (delegate != null) { - delegate.didLongPress(this, lastTouchX, lastTouchY); + return delegate.didLongPress(this, lastTouchX, lastTouchY); } - return true; + return false; } @Override 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 39e69ef8a..2220dcafc 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatMessageCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatMessageCell.java @@ -71,6 +71,7 @@ import android.widget.Toast; import androidx.core.graphics.ColorUtils; import org.telegram.PhoneFormat.PhoneFormat; +import org.telegram.messenger.AccountInstance; import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.ChatObject; import org.telegram.messenger.ContactsController; @@ -115,6 +116,7 @@ import org.telegram.ui.Components.EmptyStubSpan; import org.telegram.ui.Components.FloatSeekBarAccessibilityDelegate; import org.telegram.ui.Components.InfiniteProgress; import org.telegram.ui.Components.LinkPath; +import org.telegram.ui.Components.LinkSpanDrawable; import org.telegram.ui.Components.MediaActionDrawable; import org.telegram.ui.Components.MessageBackgroundDrawable; import org.telegram.ui.Components.MotionBackgroundDrawable; @@ -284,6 +286,9 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate default void didPressHiddenForward(ChatMessageCell cell) { } + default void didPressViaBotNotInline(ChatMessageCell cell, long botId) { + } + default void didPressViaBot(ChatMessageCell cell, String username) { } @@ -425,6 +430,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate private int angle; private float progressAlpha; private long lastUpdateTime; + private boolean isInviteButton; } public static class PollButton { @@ -635,12 +641,12 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate private boolean mediaWasInvisible; private boolean timeWasInvisible; - private CharacterStyle pressedLink; + private LinkSpanDrawable pressedLink; + private LinkSpanDrawable.LinkCollector links = new LinkSpanDrawable.LinkCollector(this); private int pressedLinkType; private boolean linkPreviewPressed; private boolean gamePreviewPressed; private ArrayList urlPathCache = new ArrayList<>(); - private ArrayList urlPath = new ArrayList<>(); private ArrayList urlPathSelection = new ArrayList<>(); private Path rectPath = new Path(); @@ -1084,47 +1090,38 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } } - private void resetPressedLink(int type) { + public void resetPressedLink(int type) { + if (type != -1) { + links.removeLinks(type); + } else { + links.clear(); + } if (pressedLink == null || pressedLinkType != type && type != -1) { return; } - resetUrlPaths(false); pressedLink = null; pressedLinkType = -1; invalidate(); } - private void resetUrlPaths(boolean text) { - if (text) { - if (urlPathSelection.isEmpty()) { - return; - } - urlPathCache.addAll(urlPathSelection); - urlPathSelection.clear(); - } else { - if (urlPath.isEmpty()) { - return; - } - urlPathCache.addAll(urlPath); - urlPath.clear(); + private void resetUrlPaths() { + if (urlPathSelection.isEmpty()) { + return; } + urlPathCache.addAll(urlPathSelection); + urlPathSelection.clear(); } - private LinkPath obtainNewUrlPath(boolean text) { + private LinkPath obtainNewUrlPath() { LinkPath linkPath; if (!urlPathCache.isEmpty()) { linkPath = urlPathCache.get(0); urlPathCache.remove(0); } else { - linkPath = new LinkPath(); - linkPath.setUseRoundRect(true); + linkPath = new LinkPath(true); } linkPath.reset(); - if (text) { - urlPathSelection.add(linkPath); - } else { - urlPath.add(linkPath); - } + urlPathSelection.add(linkPath); return linkPath; } @@ -1186,70 +1183,74 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } if (!ignore) { if (event.getAction() == MotionEvent.ACTION_DOWN) { - pressedLink = link[0]; - linkBlockNum = blockNum; - pressedLinkType = 1; - resetUrlPaths(false); - try { - LinkPath path = obtainNewUrlPath(false); - int[] pos = getRealSpanStartAndEnd(buffer, pressedLink); - pos[0] -= block.charactersOffset; - pos[1] -= block.charactersOffset; - path.setCurrentLayout(block.textLayout, pos[0], 0); - block.textLayout.getSelectionPath(pos[0], pos[1], path); - if (pos[1] >= block.charactersEnd) { - for (int a = blockNum + 1; a < currentMessageObject.textLayoutBlocks.size(); a++) { - MessageObject.TextLayoutBlock nextBlock = currentMessageObject.textLayoutBlocks.get(a); - CharacterStyle[] nextLink; - if (isMono) { - nextLink = buffer.getSpans(nextBlock.charactersOffset, nextBlock.charactersOffset, URLSpanMono.class); - } else { - nextLink = buffer.getSpans(nextBlock.charactersOffset, nextBlock.charactersOffset, ClickableSpan.class); - } - if (nextLink == null || nextLink.length == 0 || nextLink[0] != pressedLink) { - break; - } - path = obtainNewUrlPath(false); - path.setCurrentLayout(nextBlock.textLayout, 0, nextBlock.textYOffset - block.textYOffset); - int p1 = pos[1] + block.charactersOffset - nextBlock.charactersOffset; - nextBlock.textLayout.getSelectionPath(0, p1, path); - if (p1 < nextBlock.charactersEnd - 1) { - break; + if (pressedLink == null || pressedLink.getSpan() != link[0]) { + links.removeLink(pressedLink); + pressedLink = new LinkSpanDrawable(link[0], resourcesProvider, x, y, spanSupportsLongPress(link[0])); + pressedLink.setColor(getThemedColor(currentMessageObject.isOutOwner() ? Theme.key_chat_outLinkSelectBackground : Theme.key_chat_linkSelectBackground)); + linkBlockNum = blockNum; + pressedLinkType = 1; + try { + LinkPath path = pressedLink.obtainNewPath(); + int[] pos = getRealSpanStartAndEnd(buffer, pressedLink.getSpan()); + pos[0] -= block.charactersOffset; + pos[1] -= block.charactersOffset; + path.setCurrentLayout(block.textLayout, pos[0], 0); + block.textLayout.getSelectionPath(pos[0], pos[1], path); + if (pos[1] >= block.charactersEnd) { + for (int a = blockNum + 1; a < currentMessageObject.textLayoutBlocks.size(); a++) { + MessageObject.TextLayoutBlock nextBlock = currentMessageObject.textLayoutBlocks.get(a); + CharacterStyle[] nextLink; + if (isMono) { + nextLink = buffer.getSpans(nextBlock.charactersOffset, nextBlock.charactersOffset, URLSpanMono.class); + } else { + nextLink = buffer.getSpans(nextBlock.charactersOffset, nextBlock.charactersOffset, ClickableSpan.class); + } + if (nextLink == null || nextLink.length == 0 || nextLink[0] != pressedLink.getSpan()) { + break; + } + path = pressedLink.obtainNewPath(); + path.setCurrentLayout(nextBlock.textLayout, 0, nextBlock.textYOffset - block.textYOffset); + int p1 = pos[1] + block.charactersOffset - nextBlock.charactersOffset; + nextBlock.textLayout.getSelectionPath(0, p1, path); + if (p1 < nextBlock.charactersEnd - 1) { + break; + } } } - } - if (pos[0] <= block.charactersOffset) { - int offsetY = 0; - for (int a = blockNum - 1; a >= 0; a--) { - MessageObject.TextLayoutBlock nextBlock = currentMessageObject.textLayoutBlocks.get(a); - CharacterStyle[] nextLink; - if (isMono) { - nextLink = buffer.getSpans(nextBlock.charactersEnd - 1, nextBlock.charactersEnd - 1, URLSpanMono.class); - } else { - nextLink = buffer.getSpans(nextBlock.charactersEnd - 1, nextBlock.charactersEnd - 1, ClickableSpan.class); - } - if (nextLink == null || nextLink.length == 0 || nextLink[0] != pressedLink) { - break; - } - path = obtainNewUrlPath(false); - offsetY -= nextBlock.height; - int p0 = pos[0] + block.charactersOffset - nextBlock.charactersOffset; - int p1 = pos[1] + block.charactersOffset - nextBlock.charactersOffset; - path.setCurrentLayout(nextBlock.textLayout, p0, offsetY); - nextBlock.textLayout.getSelectionPath(p0, p1, path); - if (p0 > nextBlock.charactersOffset) { - break; + if (pos[0] <= block.charactersOffset) { + int offsetY = 0; + for (int a = blockNum - 1; a >= 0; a--) { + MessageObject.TextLayoutBlock nextBlock = currentMessageObject.textLayoutBlocks.get(a); + CharacterStyle[] nextLink; + if (isMono) { + nextLink = buffer.getSpans(nextBlock.charactersEnd - 1, nextBlock.charactersEnd - 1, URLSpanMono.class); + } else { + nextLink = buffer.getSpans(nextBlock.charactersEnd - 1, nextBlock.charactersEnd - 1, ClickableSpan.class); + } + if (nextLink == null || nextLink.length == 0 || nextLink[0] != pressedLink.getSpan()) { + break; + } + path = pressedLink.obtainNewPath(); + offsetY -= nextBlock.height; + int p0 = pos[0] + block.charactersOffset - nextBlock.charactersOffset; + int p1 = pos[1] + block.charactersOffset - nextBlock.charactersOffset; + path.setCurrentLayout(nextBlock.textLayout, p0, offsetY); + nextBlock.textLayout.getSelectionPath(p0, p1, path); + if (p0 > nextBlock.charactersOffset) { + break; + } } } + } catch (Exception e) { + FileLog.e(e); } - } catch (Exception e) { - FileLog.e(e); + links.addLink(pressedLink, 1); } invalidate(); return true; } else { - if (link[0] == pressedLink) { - delegate.didPressUrl(this, pressedLink, false); + if (link[0] == pressedLink.getSpan()) { + delegate.didPressUrl(this, pressedLink.getSpan(), false); resetPressedLink(1); return true; } @@ -1293,16 +1294,20 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate ignore = true; } if (!ignore) { - pressedLink = link[0]; - pressedLinkType = 3; - resetUrlPaths(false); - try { - LinkPath path = obtainNewUrlPath(false); - int[] pos = getRealSpanStartAndEnd(buffer, pressedLink); - path.setCurrentLayout(captionLayout, pos[0], 0); - captionLayout.getSelectionPath(pos[0], pos[1], path); - } catch (Exception e) { - FileLog.e(e); + if (pressedLink == null || pressedLink.getSpan() != link[0]) { + links.removeLink(pressedLink); + pressedLink = new LinkSpanDrawable(link[0], resourcesProvider, x, y, spanSupportsLongPress(link[0])); + pressedLink.setColor(getThemedColor(currentMessageObject.isOutOwner() ? Theme.key_chat_outLinkSelectBackground : Theme.key_chat_linkSelectBackground)); + pressedLinkType = 3; + try { + LinkPath path = pressedLink.obtainNewPath(); + int[] pos = getRealSpanStartAndEnd(buffer, pressedLink.getSpan()); + path.setCurrentLayout(captionLayout, pos[0], 0); + captionLayout.getSelectionPath(pos[0], pos[1], path); + } catch (Exception e) { + FileLog.e(e); + } + links.addLink(pressedLink, 3); } invalidateWithParent(); return true; @@ -1312,7 +1317,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate FileLog.e(e); } } else if (pressedLinkType == 3) { - delegate.didPressUrl(this, pressedLink, false); + delegate.didPressUrl(this, pressedLink.getSpan(), false); resetPressedLink(3); return true; } @@ -1354,17 +1359,21 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate ignore = true; } if (!ignore) { - pressedLink = link[0]; - linkBlockNum = -10; - pressedLinkType = 2; - resetUrlPaths(false); - try { - LinkPath path = obtainNewUrlPath(false); - int[] pos = getRealSpanStartAndEnd(buffer, pressedLink); - path.setCurrentLayout(descriptionLayout, pos[0], 0); - descriptionLayout.getSelectionPath(pos[0], pos[1], path); - } catch (Exception e) { - FileLog.e(e); + if (pressedLink == null || pressedLink.getSpan() != link[0]) { + links.removeLink(pressedLink); + pressedLink = new LinkSpanDrawable(link[0], resourcesProvider, x, y, spanSupportsLongPress(link[0])); + pressedLink.setColor(getThemedColor(currentMessageObject.isOutOwner() ? Theme.key_chat_outLinkSelectBackground : Theme.key_chat_linkSelectBackground)); + linkBlockNum = -10; + pressedLinkType = 2; + try { + LinkPath path = pressedLink.obtainNewPath(); + int[] pos = getRealSpanStartAndEnd(buffer, pressedLink.getSpan()); + path.setCurrentLayout(descriptionLayout, pos[0], 0); + descriptionLayout.getSelectionPath(pos[0], pos[1], path); + } catch (Exception e) { + FileLog.e(e); + } + links.addLink(pressedLink, 2); } invalidate(); return true; @@ -1382,10 +1391,10 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate didPressButton(true, false); invalidate(); } else if (pressedLink != null) { - if (pressedLink instanceof URLSpan) { - Browser.openUrl(getContext(), ((URLSpan) pressedLink).getURL()); - } else if (pressedLink instanceof ClickableSpan) { - ((ClickableSpan) pressedLink).onClick(this); + if (pressedLink.getSpan() instanceof URLSpan) { + Browser.openUrl(getContext(), ((URLSpan) pressedLink.getSpan()).getURL()); + } else if (pressedLink.getSpan() instanceof ClickableSpan) { + ((ClickableSpan) pressedLink.getSpan()).onClick(this); } resetPressedLink(2); } else { @@ -1435,18 +1444,22 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate ignore = true; } if (!ignore) { - pressedLink = link[0]; - linkBlockNum = -10; - pressedLinkType = 2; - resetUrlPaths(false); - startCheckLongPress(); - try { - LinkPath path = obtainNewUrlPath(false); - int[] pos = getRealSpanStartAndEnd(buffer, pressedLink); - path.setCurrentLayout(descriptionLayout, pos[0], 0); - descriptionLayout.getSelectionPath(pos[0], pos[1], path); - } catch (Exception e) { - FileLog.e(e); + if (pressedLink == null || pressedLink.getSpan() != link[0]) { + links.removeLink(pressedLink); + pressedLink = new LinkSpanDrawable(link[0], resourcesProvider, x, y, spanSupportsLongPress(link[0])); + pressedLink.setColor(getThemedColor(currentMessageObject.isOutOwner() ? Theme.key_chat_outLinkSelectBackground : Theme.key_chat_linkSelectBackground)); + linkBlockNum = -10; + pressedLinkType = 2; + startCheckLongPress(); + try { + LinkPath path = pressedLink.obtainNewPath(); + int[] pos = getRealSpanStartAndEnd(buffer, pressedLink.getSpan()); + path.setCurrentLayout(descriptionLayout, pos[0], 0); + descriptionLayout.getSelectionPath(pos[0], pos[1], path); + } catch (Exception e) { + FileLog.e(e); + } + links.addLink(pressedLink, 2); } invalidate(); return true; @@ -1530,10 +1543,10 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate didPressMiniButton(true); invalidate(); } else if (pressedLink != null) { - if (pressedLink instanceof URLSpan) { - delegate.didPressUrl(this, pressedLink, false); - } else if (pressedLink instanceof ClickableSpan) { - ((ClickableSpan) pressedLink).onClick(this); + if (pressedLink.getSpan() instanceof URLSpan) { + delegate.didPressUrl(this, pressedLink.getSpan(), false); + } else if (pressedLink.getSpan() instanceof ClickableSpan) { + ((ClickableSpan) pressedLink.getSpan()).onClick(this); } resetPressedLink(2); } else { @@ -1574,7 +1587,8 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate resetPressedLink(2); return true; } - } else { + } else if (!hadLongPress) { + hadLongPress = false; resetPressedLink(2); } } else if (event.getAction() == MotionEvent.ACTION_MOVE) { @@ -2419,7 +2433,15 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } } result = false; - resetPressedLink(-1); + if (hadLongPress) { + if (pressedLinkType != 2) { + hadLongPress = false; + } + pressedLink = null; + pressedLinkType = -1; + } else { + resetPressedLink(-1); + } } updateRadialProgressBackground(); if (!disallowLongPress && result && event.getAction() == MotionEvent.ACTION_DOWN) { @@ -2556,7 +2578,11 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate forwardBotPressed = false; playSoundEffect(SoundEffectConstants.CLICK); if (delegate != null) { - delegate.didPressViaBot(this, currentViaBotUser != null ? currentViaBotUser.username : currentMessageObject.messageOwner.via_bot_name); + if (currentViaBotUser.bot_inline_placeholder == null) { + delegate.didPressViaBotNotInline(this, currentViaBotUser != null ? currentViaBotUser.id : 0); + } else { + delegate.didPressViaBot(this, currentViaBotUser != null ? currentViaBotUser.username : currentMessageObject.messageOwner.via_bot_name); + } } } else if (event.getAction() == MotionEvent.ACTION_CANCEL) { forwardBotPressed = false; @@ -3547,8 +3573,9 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate AndroidUtilities.cancelRunOnUIThread(invalidateRunnable); scheduledInvalidate = false; } - - resetPressedLink(-1); + links.clear(); + pressedLink = null; + pressedLinkType = -1; messageObject.forceUpdate = false; drawPhotoImage = false; drawMediaCheckBox = false; @@ -6545,7 +6572,8 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate if (botButton.button instanceof TLRPC.TL_keyboardButtonBuy && (messageObject.messageOwner.media.flags & 4) != 0) { buttonText = LocaleController.getString("PaymentReceipt", R.string.PaymentReceipt); } else { - buttonText = Emoji.replaceEmoji(botButton.button.text, botButtonPaint.getFontMetricsInt(), AndroidUtilities.dp(15), false); + buttonText = botButton.button.text == null ? "" : botButton.button.text; + buttonText = Emoji.replaceEmoji(buttonText, botButtonPaint.getFontMetricsInt(), AndroidUtilities.dp(15), false); buttonText = TextUtils.ellipsize(buttonText, botButtonPaint, buttonWidth - AndroidUtilities.dp(10), TextUtils.TruncateAt.END); } botButton.title = new StaticLayout(buttonText, botButtonPaint, buttonWidth - AndroidUtilities.dp(10), Layout.Alignment.ALIGN_CENTER, 1.0f, 0.0f, false); @@ -6553,6 +6581,16 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate if (b == row.buttons.size() - 1) { maxButtonsWidth = Math.max(maxButtonsWidth, botButton.x + botButton.width); } + if (messageObject.isFromUser() && botButton.button instanceof TLRPC.TL_keyboardButtonUrl) { // TODO(dkaraush): or instanceof TLRPC.TL_keyboardButtonInvite in the future + try { + final Uri uri = Uri.parse(botButton.button.url); + final String host = uri.getHost().toLowerCase(); + botButton.isInviteButton = (uri.getQueryParameter("startgroup") != null && ( + ("http".equals(uri.getScheme()) || "https".equals(uri.getScheme())) && ("t.me".equals(host) || "telegram.me".equals(host) || "telegram.dog".equals(host)) || + "tg".equals(uri.getScheme()) && (botButton.button.url.startsWith("tg:resolve") || botButton.button.url.startsWith("tg://resolve")) + )); + } catch (Exception ignore) {} + } } } } @@ -6740,6 +6778,10 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate private boolean hadLongPress = false; + private static boolean spanSupportsLongPress(CharacterStyle span) { + return span instanceof URLSpanMono || span instanceof URLSpan; + } + @Override protected boolean onLongPress() { if (isRoundVideo && isPlayingRound && MediaController.getInstance().isPlayingMessage(currentMessageObject)) { @@ -6790,18 +6832,23 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate return false; } } - if (pressedLink instanceof URLSpanMono) { - delegate.didPressUrl(this, pressedLink, true); - return true; - } else if (pressedLink instanceof URLSpanNoUnderline) { - URLSpanNoUnderline url = (URLSpanNoUnderline) pressedLink; - if (ChatActivity.isClickableLink(url.getURL()) || url.getURL().startsWith("/")) { - delegate.didPressUrl(this, pressedLink, true); + if (pressedLink != null) { + if (pressedLink.getSpan() instanceof URLSpanMono) { + hadLongPress = true; + delegate.didPressUrl(this, pressedLink.getSpan(), true); + return true; + } else if (pressedLink.getSpan() instanceof URLSpanNoUnderline) { + URLSpanNoUnderline url = (URLSpanNoUnderline) pressedLink.getSpan(); + if (ChatActivity.isClickableLink(url.getURL()) || url.getURL().startsWith("/")) { + hadLongPress = true; + delegate.didPressUrl(this, pressedLink.getSpan(), true); + return true; + } + } else if (pressedLink.getSpan() instanceof URLSpan) { + hadLongPress = true; + delegate.didPressUrl(this, pressedLink.getSpan(), true); return true; } - } else if (pressedLink instanceof URLSpan) { - delegate.didPressUrl(this, pressedLink, true); - return true; } resetPressedLink(-1); if (buttonPressed != 0 || miniButtonPressed != 0 || videoButtonPressed != 0 || pressedBotButton != -1) { @@ -6915,7 +6962,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate return; } super.invalidate(); - if (invalidatesParent && getParent() != null) { + if ((invalidatesParent || currentMessagesGroup != null && !links.isEmpty()) && getParent() != null) { View parent = (View) getParent(); if (parent.getParent() != null) { parent.invalidate(); @@ -7081,6 +7128,16 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } seekBarWaveform.setMessageObject(messageObject); return 0; + } else if (MessageObject.isVideoDocument(documentAttach)) { + documentAttachType = DOCUMENT_ATTACH_TYPE_VIDEO; + if (!messageObject.needDrawBluredPreview()) { + updatePlayingMessageProgress(); + String str; + str = String.format("%s", AndroidUtilities.formatFileSize(documentAttach.size)); + docTitleWidth = (int) Math.ceil(Theme.chat_infoPaint.measureText(str)); + docTitleLayout = new StaticLayout(str, Theme.chat_infoPaint, docTitleWidth, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); + } + return 0; } else if (MessageObject.isMusicDocument(documentAttach)) { documentAttachType = DOCUMENT_ATTACH_TYPE_MUSIC; @@ -7113,16 +7170,6 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate widthBeforeNewTimeLine = backgroundWidth - AndroidUtilities.dp(10 + 76) - durationWidth; availableTimeWidth = backgroundWidth - AndroidUtilities.dp(28); return durationWidth; - } else if (MessageObject.isVideoDocument(documentAttach)) { - documentAttachType = DOCUMENT_ATTACH_TYPE_VIDEO; - if (!messageObject.needDrawBluredPreview()) { - updatePlayingMessageProgress(); - String str; - str = String.format("%s", AndroidUtilities.formatFileSize(documentAttach.size)); - docTitleWidth = (int) Math.ceil(Theme.chat_infoPaint.measureText(str)); - docTitleLayout = new StaticLayout(str, Theme.chat_infoPaint, docTitleWidth, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); - } - return 0; } else if (MessageObject.isGifDocument(documentAttach, messageObject.hasValidGroupId())) { documentAttachType = DOCUMENT_ATTACH_TYPE_GIF; if (!messageObject.needDrawBluredPreview()) { @@ -7224,7 +7271,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate if (messageObject == null || messageObject.messageOwner.message == null || TextUtils.isEmpty(text)) { if (!urlPathSelection.isEmpty()) { linkSelectionBlockNum = -1; - resetUrlPaths(true); + resetUrlPaths(); invalidate(); } return; @@ -7257,7 +7304,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate if (start == -1) { if (!urlPathSelection.isEmpty()) { linkSelectionBlockNum = -1; - resetUrlPaths(true); + resetUrlPaths(); invalidate(); } return; @@ -7271,9 +7318,9 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } int end = start + length; if (captionLayout != null && !TextUtils.isEmpty(messageObject.caption)) { - resetUrlPaths(true); + resetUrlPaths(); try { - LinkPath path = obtainNewUrlPath(true); + LinkPath path = obtainNewUrlPath(); path.setCurrentLayout(captionLayout, start, 0); captionLayout.getSelectionPath(start, end, path); } catch (Exception e) { @@ -7285,16 +7332,16 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate MessageObject.TextLayoutBlock block = messageObject.textLayoutBlocks.get(c); if (start >= block.charactersOffset && start < block.charactersEnd) { linkSelectionBlockNum = c; - resetUrlPaths(true); + resetUrlPaths(); try { - LinkPath path = obtainNewUrlPath(true); + LinkPath path = obtainNewUrlPath(); path.setCurrentLayout(block.textLayout, start, 0); block.textLayout.getSelectionPath(start, end, path); if (end >= block.charactersOffset + length) { for (int a = c + 1; a < messageObject.textLayoutBlocks.size(); a++) { MessageObject.TextLayoutBlock nextBlock = messageObject.textLayoutBlocks.get(a); length = nextBlock.charactersEnd - nextBlock.charactersOffset; - path = obtainNewUrlPath(true); + path = obtainNewUrlPath(); path.setCurrentLayout(nextBlock.textLayout, 0, nextBlock.height); nextBlock.textLayout.getSelectionPath(0, end - nextBlock.charactersOffset, path); if (end < block.charactersOffset + length - 1) { @@ -8569,7 +8616,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate if (hasNewLineForTime) { reactionsLayoutInBubble.y -= AndroidUtilities.dp(16); } - if (captionLayout != null && ((currentMessageObject.type != 2 && !(currentMessageObject.type == 9 && drawPhotoImage)) || (currentPosition != null && currentMessagesGroup != null))) { + if (captionLayout != null && ((currentMessageObject.type != 2 && !(currentMessageObject.isOut() && drawForwardedName && !drawPhotoImage) && !(currentMessageObject.type == 9 && drawPhotoImage)) || (currentPosition != null && currentMessagesGroup != null))) { reactionsLayoutInBubble.y -= AndroidUtilities.dp(14); } reactionsLayoutInBubble.y = reactionsLayoutInBubble.y + reactionsLayoutInBubble.positionOffsetY; @@ -8772,9 +8819,9 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate descriptionY = linkPreviewY - AndroidUtilities.dp(3); canvas.save(); canvas.translate(linkX + (hasInvoicePreview ? 0 : AndroidUtilities.dp(10)) + descriptionX, descriptionY); - if (pressedLink != null && linkBlockNum == -10) { - for (int b = 0; b < urlPath.size(); b++) { - canvas.drawPath(urlPath.get(b), Theme.chat_urlPaint); + if (linkBlockNum == -10) { + if (links.draw(canvas)) { + invalidate(); } } if (delegate != null && delegate.getTextSelectionHelper() != null && getDelegate().getTextSelectionHelper().isSelected(currentMessageObject)) { @@ -8951,8 +8998,18 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate canvas.translate(button.x + addX + AndroidUtilities.dp(5), y + (AndroidUtilities.dp(44) - button.title.getLineBottom(button.title.getLineCount() - 1)) / 2); button.title.draw(canvas); canvas.restore(); - if (button.button instanceof TLRPC.TL_keyboardButtonUrl) { - Drawable drawable = getThemedDrawable(Theme.key_drawable_botLink); + if (button.button instanceof TLRPC.TL_keyboardButtonWebView) { + Drawable drawable = getThemedDrawable(Theme.key_drawable_botWebView); + int x = button.x + button.width - AndroidUtilities.dp(3) - drawable.getIntrinsicWidth() + addX; + setDrawableBounds(drawable, x, y + AndroidUtilities.dp(3)); + drawable.draw(canvas); + } else if (button.button instanceof TLRPC.TL_keyboardButtonUrl) { + Drawable drawable; + if (button.isInviteButton) { + drawable = getThemedDrawable(Theme.key_drawable_botInvite); + } else { + drawable = getThemedDrawable(Theme.key_drawable_botLink); + } int x = button.x + button.width - AndroidUtilities.dp(3) - drawable.getIntrinsicWidth() + addX; setDrawableBounds(drawable, x, y + AndroidUtilities.dp(3)); drawable.draw(canvas); @@ -8963,9 +9020,9 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate drawable.draw(canvas); } else if (button.button instanceof TLRPC.TL_keyboardButtonCallback || button.button instanceof TLRPC.TL_keyboardButtonRequestGeoLocation || button.button instanceof TLRPC.TL_keyboardButtonGame || button.button instanceof TLRPC.TL_keyboardButtonBuy || button.button instanceof TLRPC.TL_keyboardButtonUrlAuth) { if (button.button instanceof TLRPC.TL_keyboardButtonBuy) { - int x = button.x + button.width - AndroidUtilities.dp(5) - Theme.chat_botCardDrawalbe.getIntrinsicWidth() + addX; - setDrawableBounds(Theme.chat_botCardDrawalbe, x, y + AndroidUtilities.dp(4)); - Theme.chat_botCardDrawalbe.draw(canvas); + int x = button.x + button.width - AndroidUtilities.dp(5) - Theme.chat_botCardDrawable.getIntrinsicWidth() + addX; + setDrawableBounds(Theme.chat_botCardDrawable, x, y + AndroidUtilities.dp(4)); + Theme.chat_botCardDrawable.draw(canvas); } boolean drawProgress = (button.button instanceof TLRPC.TL_keyboardButtonCallback || button.button instanceof TLRPC.TL_keyboardButtonGame || button.button instanceof TLRPC.TL_keyboardButtonBuy || button.button instanceof TLRPC.TL_keyboardButtonUrlAuth) && SendMessagesHelper.getInstance(currentAccount).isSendingCallback(currentMessageObject, button.button) || button.button instanceof TLRPC.TL_keyboardButtonRequestGeoLocation && SendMessagesHelper.getInstance(currentAccount).isSendingCurrentLocation(currentMessageObject, button.button); @@ -9071,9 +9128,9 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate MessageObject.TextLayoutBlock block = textLayoutBlocks.get(a); canvas.save(); canvas.translate(textX - (block.isRtl() ? (int) Math.ceil(currentMessageObject.textXOffset) : 0), textY + block.textYOffset + transitionYOffsetForDrawables); - if (pressedLink != null && a == linkBlockNum && !drawOnlyText) { - for (int b = 0; b < urlPath.size(); b++) { - canvas.drawPath(urlPath.get(b), Theme.chat_urlPaint); + if (a == linkBlockNum && !drawOnlyText) { + if (links.draw(canvas)) { + invalidate(); } } if (a == linkSelectionBlockNum && !urlPathSelection.isEmpty() && !drawOnlyText) { @@ -10685,24 +10742,41 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate maxWidth -= AndroidUtilities.dp(44); } - if (messageObject.customReplyName != null) { - name = messageObject.customReplyName; - } else { - long fromId = messageObject.replyMessageObject.getFromChatId(); - if (fromId > 0) { - TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(fromId); - if (user != null) { + if (messageObject.hideSendersName) { + if (messageObject.sendAsPeer != null) { + if (messageObject.sendAsPeer.channel_id != 0) { + TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(messageObject.sendAsPeer.channel_id); + if (chat != null) { + name = chat.title; + } + } else { + TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(messageObject.sendAsPeer.user_id); name = UserObject.getUserName(user); } - } else if (fromId < 0) { - TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(-fromId); - if (chat != null) { - name = chat.title; - } } else { - TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(messageObject.replyMessageObject.messageOwner.peer_id.channel_id); - if (chat != null) { - name = chat.title; + name = UserObject.getUserName(AccountInstance.getInstance(currentAccount).getUserConfig().getCurrentUser()); + } + } else if (messageObject.customReplyName != null) { + name = messageObject.customReplyName; + } else { + name = messageObject.replyMessageObject.getForwardedName(); + if (name == null) { + long fromId = messageObject.replyMessageObject.getFromChatId(); + if (fromId > 0) { + TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(fromId); + if (user != null) { + name = UserObject.getUserName(user); + } + } else if (fromId < 0) { + TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(-fromId); + if (chat != null) { + name = chat.title; + } + } else { + TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(messageObject.replyMessageObject.messageOwner.peer_id.channel_id); + if (chat != null) { + name = chat.title; + } } } } @@ -11119,7 +11193,11 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } else { replyStartX = backgroundDrawableLeft + backgroundDrawableRight + AndroidUtilities.dp(17); } - replyStartY = AndroidUtilities.dp(12); + if (drawForwardedName) { + replyStartY = forwardNameY + AndroidUtilities.dp(38); + } else { + replyStartY = AndroidUtilities.dp(12); + } } else { if (currentMessageObject.isOutOwner()) { replyStartX = backgroundDrawableLeft + AndroidUtilities.dp(12) + getExtraTextX(); @@ -11998,6 +12076,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } boolean drawForwardedNameLocal = drawForwardedName; + boolean hasReply = replyNameLayout != null; StaticLayout[] forwardedNameLayoutLocal = forwardedNameLayout; float animatingAlpha = 1f; int forwardedNameWidthLocal = forwardedNameWidth; @@ -12013,6 +12092,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } float forwardNameXLocal; + boolean needDrawReplyBackground = true; if (drawForwardedNameLocal && forwardedNameLayoutLocal[0] != null && forwardedNameLayoutLocal[1] != null && (currentPosition == null || currentPosition.minY == 0 && currentPosition.minX == 0)) { if (currentMessageObject.type == MessageObject.TYPE_ROUND_VIDEO || currentMessageObject.isAnyKindOfSticker()) { Theme.chat_forwardNamePaint.setColor(getThemedColor(Theme.key_chat_stickerReplyNameText)); @@ -12031,8 +12111,13 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate forwardNameY = AndroidUtilities.dp(12); int backWidth = forwardedNameWidthLocal + AndroidUtilities.dp(14); - - rect.set((int) forwardNameXLocal - AndroidUtilities.dp(7), forwardNameY - AndroidUtilities.dp(6), (int) forwardNameXLocal - AndroidUtilities.dp(7) + backWidth, forwardNameY + AndroidUtilities.dp(38)); + if (hasReply) { + needDrawReplyBackground = false; + int replyBackWidth = Math.max(replyNameWidth, replyTextWidth) + AndroidUtilities.dp(14); + rect.set((int) forwardNameXLocal - AndroidUtilities.dp(7), forwardNameY - AndroidUtilities.dp(6), (int) forwardNameXLocal - AndroidUtilities.dp(7) + Math.max(backWidth, replyBackWidth), forwardNameY + AndroidUtilities.dp(38) + AndroidUtilities.dp(41)); + } else { + rect.set((int) forwardNameXLocal - AndroidUtilities.dp(7), forwardNameY - AndroidUtilities.dp(6), (int) forwardNameXLocal - AndroidUtilities.dp(7) + backWidth, forwardNameY + AndroidUtilities.dp(38)); + } applyServiceShaderMatrix(); int oldAlpha1 = -1, oldAlpha2 = -1; if (animatingAlpha != 1f || replyForwardAlpha != 1f) { @@ -12157,8 +12242,9 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } } - if (replyNameLayout != null) { + if (hasReply) { float replyStartX = this.replyStartX; + float replyStartY = this.replyStartY; if (currentMessagesGroup != null && currentMessagesGroup.transitionParams.backgroundChangeBounds) { replyStartX += currentMessagesGroup.transitionParams.offsetLeft; } @@ -12168,6 +12254,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } else { replyStartX += transitionParams.deltaLeft; } + replyStartY = this.replyStartY * transitionParams.animateChangeProgress + transitionParams.animateFromReplyY * (1f - transitionParams.animateChangeProgress); } if (currentMessageObject.shouldDrawWithoutBackground()) { Theme.chat_replyLinePaint.setColor(getThemedColor(Theme.key_chat_stickerReplyLine)); @@ -12179,19 +12266,20 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate Theme.chat_replyTextPaint.setColor(getThemedColor(Theme.key_chat_stickerReplyMessageText)); oldAlpha = Theme.chat_replyTextPaint.getAlpha(); Theme.chat_replyTextPaint.setAlpha((int) (oldAlpha * timeAlpha * replyForwardAlpha)); - int backWidth = Math.max(replyNameWidth, replyTextWidth) + AndroidUtilities.dp(14); - - rect.set((int) replyStartX - AndroidUtilities.dp(7), replyStartY - AndroidUtilities.dp(6), (int) replyStartX - AndroidUtilities.dp(7) + backWidth, replyStartY + AndroidUtilities.dp(41)); - applyServiceShaderMatrix(); - oldAlpha = getThemedPaint(Theme.key_paint_chatActionBackground).getAlpha(); - getThemedPaint(Theme.key_paint_chatActionBackground).setAlpha((int) (oldAlpha * timeAlpha * replyForwardAlpha)); - canvas.drawRoundRect(rect, AndroidUtilities.dp(6), AndroidUtilities.dp(6), getThemedPaint(Theme.key_paint_chatActionBackground)); - getThemedPaint(Theme.key_paint_chatActionBackground).setAlpha(oldAlpha); - if (hasGradientService()) { - oldAlpha = Theme.chat_actionBackgroundGradientDarkenPaint.getAlpha(); - Theme.chat_actionBackgroundGradientDarkenPaint.setAlpha((int) (oldAlpha * timeAlpha * replyForwardAlpha)); - canvas.drawRoundRect(rect, AndroidUtilities.dp(6), AndroidUtilities.dp(6), Theme.chat_actionBackgroundGradientDarkenPaint); - Theme.chat_actionBackgroundGradientDarkenPaint.setAlpha(oldAlpha); + if (needDrawReplyBackground) { + int backWidth = Math.max(replyNameWidth, replyTextWidth) + AndroidUtilities.dp(14); + rect.set((int) replyStartX - AndroidUtilities.dp(7), replyStartY - AndroidUtilities.dp(6), (int) replyStartX - AndroidUtilities.dp(7) + backWidth, replyStartY + AndroidUtilities.dp(41)); + applyServiceShaderMatrix(); + oldAlpha = getThemedPaint(Theme.key_paint_chatActionBackground).getAlpha(); + getThemedPaint(Theme.key_paint_chatActionBackground).setAlpha((int) (oldAlpha * timeAlpha * replyForwardAlpha)); + canvas.drawRoundRect(rect, AndroidUtilities.dp(6), AndroidUtilities.dp(6), getThemedPaint(Theme.key_paint_chatActionBackground)); + getThemedPaint(Theme.key_paint_chatActionBackground).setAlpha(oldAlpha); + if (hasGradientService()) { + oldAlpha = Theme.chat_actionBackgroundGradientDarkenPaint.getAlpha(); + Theme.chat_actionBackgroundGradientDarkenPaint.setAlpha((int) (oldAlpha * timeAlpha * replyForwardAlpha)); + canvas.drawRoundRect(rect, AndroidUtilities.dp(6), AndroidUtilities.dp(6), Theme.chat_actionBackgroundGradientDarkenPaint); + Theme.chat_actionBackgroundGradientDarkenPaint.setAlpha(oldAlpha); + } } } else { if (currentMessageObject.isOutOwner()) { @@ -12214,7 +12302,8 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } forwardNameX = replyStartX - replyTextOffset + AndroidUtilities.dp(10 + (needReplyImage ? 44 : 0)); if ((currentPosition == null || currentPosition.minY == 0 && currentPosition.minX == 0) && !(enterTransitionInProgress && !currentMessageObject.isVoice())) { - canvas.drawRect(replyStartX, replyStartY, replyStartX + AndroidUtilities.dp(2), replyStartY + AndroidUtilities.dp(35), Theme.chat_replyLinePaint); + AndroidUtilities.rectTmp.set(replyStartX, replyStartY, replyStartX + AndroidUtilities.dp(2), replyStartY + AndroidUtilities.dp(35)); + canvas.drawRoundRect(AndroidUtilities.rectTmp, AndroidUtilities.dp(1), AndroidUtilities.dp(1), Theme.chat_replyLinePaint); if (needReplyImage) { replyImageReceiver.setAlpha(replyForwardAlpha); replyImageReceiver.setImageCoords(replyStartX + AndroidUtilities.dp(10), replyStartY, AndroidUtilities.dp(35), AndroidUtilities.dp(35)); @@ -12604,7 +12693,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } } - if (captionLayout == null || selectionOnly && pressedLink == null || (currentMessageObject.deleted && currentPosition != null) || alpha == 0) { + if (captionLayout == null || selectionOnly && links.isEmpty() || (currentMessageObject.deleted && currentPosition != null) || alpha == 0) { return; } if (currentMessageObject.isOutOwner()) { @@ -12660,10 +12749,8 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } canvas.translate(captionX, captionY); - if (pressedLink != null) { - for (int b = 0; b < urlPath.size(); b++) { - canvas.drawPath(urlPath.get(b), Theme.chat_urlPaint); - } + if (links.draw(canvas)) { + invalidate(); } if (!urlPathSelection.isEmpty()) { for (int b = 0; b < urlPathSelection.size(); b++) { @@ -15473,6 +15560,9 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate public boolean animateRoundVideoDotY; public float lastDrawRoundVideoDotY; public float animateFromRoundVideoDotY; + public boolean animateReplyY; + public float lastDrawReplyY; + public float animateFromReplyY; private boolean lastIsPinned; private boolean animatePinned; @@ -15671,6 +15761,11 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate lastBackgroundRight = currentBackgroundDrawable.getBounds().right; reactionsLayoutInBubble.recordDrawingState(); + if (replyNameLayout != null) { + lastDrawReplyY = replyStartY; + } else { + lastDrawReplyY = 0; + } } public void recordDrawingStatePreview() { @@ -15897,6 +15992,12 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } } + if (replyNameLayout != null && replyStartX != lastDrawReplyY && lastDrawReplyY != 0) { + animateReplyY = true; + animateFromReplyY = lastDrawReplyY; + changed = true; + } + return changed; } @@ -15959,6 +16060,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate animatingForwardedNameLayout[0] = null; animatingForwardedNameLayout[1] = null; animateRoundVideoDotY = false; + animateReplyY = false; reactionsLayoutInBubble.resetAnimation(); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/CreationTextCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/CreationTextCell.java new file mode 100644 index 000000000..458abdb8f --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/CreationTextCell.java @@ -0,0 +1,79 @@ +package org.telegram.ui.Cells; + +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.drawable.Drawable; +import android.view.Gravity; +import android.widget.FrameLayout; +import android.widget.ImageView; + +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.LocaleController; +import org.telegram.ui.ActionBar.SimpleTextView; +import org.telegram.ui.ActionBar.Theme; + +public class CreationTextCell extends FrameLayout { + + private SimpleTextView textView; + private ImageView imageView; + boolean divider; + public int startPadding = 70; + + public CreationTextCell(Context context) { + super(context); + + textView = new SimpleTextView(context); + textView.setTextSize(16); + textView.setGravity(LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT); + textView.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlueText2)); + textView.setTag(Theme.key_windowBackgroundWhiteBlueText2); + addView(textView); + + imageView = new ImageView(context); + imageView.setScaleType(ImageView.ScaleType.CENTER); + addView(imageView); + setWillNotDraw(false); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + int width = MeasureSpec.getSize(widthMeasureSpec); + int height = AndroidUtilities.dp(48); + + textView.measure(MeasureSpec.makeMeasureSpec(width - AndroidUtilities.dp(71 + 23), MeasureSpec.AT_MOST), MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(20), MeasureSpec.EXACTLY)); + imageView.measure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.AT_MOST), MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(50), MeasureSpec.EXACTLY)); + setMeasuredDimension(width, AndroidUtilities.dp(50)); + } + + @Override + protected void onLayout(boolean changed, int left, int top, int right, int bottom) { + int height = bottom - top; + int width = right - left; + + int viewLeft; + int viewTop = (height - textView.getTextHeight()) / 2; + if (LocaleController.isRTL) { + viewLeft = getMeasuredWidth() - textView.getMeasuredWidth() - AndroidUtilities.dp(imageView.getVisibility() == VISIBLE ? startPadding : 25); + } else { + viewLeft = AndroidUtilities.dp(imageView.getVisibility() == VISIBLE ? startPadding : 25); + } + textView.layout(viewLeft, viewTop, viewLeft + textView.getMeasuredWidth(), viewTop + textView.getMeasuredHeight()); + + viewLeft = !LocaleController.isRTL ? (AndroidUtilities.dp(startPadding) - imageView.getMeasuredWidth()) / 2 : width - imageView.getMeasuredWidth() - AndroidUtilities.dp(25); + imageView.layout(viewLeft, 0, viewLeft + imageView.getMeasuredWidth(), imageView.getMeasuredHeight()); + } + + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + if (divider) { + canvas.drawLine(AndroidUtilities.dp(startPadding), getMeasuredHeight() - 1, getMeasuredWidth() + AndroidUtilities.dp(23), getMeasuredHeight(), Theme.dividerPaint); + } + } + + public void setTextAndIcon(String text, Drawable icon, boolean divider) { + textView.setText(text); + imageView.setImageDrawable(icon); + this.divider = divider; + } +} \ No newline at end of file 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 da1a124e5..74b1e0e68 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/DialogCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/DialogCell.java @@ -264,6 +264,7 @@ public class DialogCell extends BaseCell { private int pinLeft; private boolean drawCount; + private boolean drawCount2 = true; private int countTop; private int countLeft; private int countWidth; @@ -525,6 +526,7 @@ public class DialogCell extends BaseCell { bottomClip = getMeasuredHeight(); } + int lastSize; @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { if (currentDialogId == 0 && customDialog == null) { @@ -535,7 +537,9 @@ public class DialogCell extends BaseCell { int y = AndroidUtilities.dp(useForceThreeLines || SharedConfig.useThreeLinesLayout ? 48 : 42); checkBox.layout(x, y, x + checkBox.getMeasuredWidth(), y + checkBox.getMeasuredHeight()); } - if (changed) { + int size = getMeasuredHeight() + getMeasuredWidth() << 16; + if (size != lastSize) { + lastSize = size; try { buildLayout(); } catch (Exception e) { @@ -1012,7 +1016,39 @@ public class DialogCell extends BaseCell { } else { fromChat = MessagesController.getInstance(currentAccount).getChat(-fromId); } - if (dialogsType == 3 && UserObject.isUserSelf(user)) { + drawCount2 = true; + if (dialogsType == 2) { + if (chat != null) { + if (ChatObject.isChannel(chat) && !chat.megagroup) { + if (chat.participants_count != 0) { + messageString = LocaleController.formatPluralStringComma("Subscribers", chat.participants_count); + } else { + if (TextUtils.isEmpty(chat.username)) { + messageString = LocaleController.getString("ChannelPrivate", R.string.ChannelPrivate).toLowerCase(); + } else { + messageString = LocaleController.getString("ChannelPublic", R.string.ChannelPublic).toLowerCase(); + } + } + } else { + if (chat.participants_count != 0) { + messageString = LocaleController.formatPluralStringComma("Members", chat.participants_count); + } else { + if (chat.has_geo) { + messageString = LocaleController.getString("MegaLocation", R.string.MegaLocation); + } else if (TextUtils.isEmpty(chat.username)) { + messageString = LocaleController.getString("MegaPrivate", R.string.MegaPrivate).toLowerCase(); + } else { + messageString = LocaleController.getString("MegaPublic", R.string.MegaPublic).toLowerCase(); + } + } + } + } else { + messageString = ""; + } + drawCount2 = false; + showChecks = false; + drawTime = false; + } else if (dialogsType == 3 && UserObject.isUserSelf(user)) { messageString = LocaleController.getString("SavedMessagesInfo", R.string.SavedMessagesInfo); showChecks = false; drawTime = false; @@ -2092,6 +2128,9 @@ public class DialogCell extends BaseCell { } else { drawPin = false; } + if (dialogsType == 2) { + drawPin = false; + } if (mask != 0) { boolean continueUpdate = false; @@ -2272,7 +2311,7 @@ public class DialogCell extends BaseCell { countAnimator.setDuration(430); countAnimator.setInterpolator(CubicBezierInterpolator.DEFAULT); } - if (drawCount && countLayout != null) { + if (drawCount && drawCount2 && countLayout != null) { String oldStr = String.valueOf(oldUnreadCount); String newStr = String.valueOf(unreadCount); @@ -2769,7 +2808,7 @@ public class DialogCell extends BaseCell { lastStatusDrawableParams = (this.drawClock ? 1 : 0) + (this.drawCheck1 ? 2 : 0) + (this.drawCheck2 ? 4 : 0); } - if ((dialogMuted || dialogMutedProgress > 0) && !drawVerified && drawScam == 0) { + if (dialogsType != 2 && (dialogMuted || dialogMutedProgress > 0) && !drawVerified && drawScam == 0) { if (dialogMuted && dialogMutedProgress != 1f) { dialogMutedProgress += 16 / 150f; if (dialogMutedProgress > 1f) { @@ -2818,8 +2857,8 @@ public class DialogCell extends BaseCell { canvas.drawRoundRect(rect, 11.5f * AndroidUtilities.density, 11.5f * AndroidUtilities.density, Theme.dialogs_errorPaint); setDrawableBounds(Theme.dialogs_errorDrawable, errorLeft + AndroidUtilities.dp(5.5f), errorTop + AndroidUtilities.dp(5)); Theme.dialogs_errorDrawable.draw(canvas); - } else if (drawCount || drawMention || countChangeProgress != 1f || drawReactionMention || reactionsMentionsChangeProgress != 1f) { - if (drawCount || countChangeProgress != 1f) { + } else if ((drawCount || drawMention) && drawCount2 || countChangeProgress != 1f || drawReactionMention || reactionsMentionsChangeProgress != 1f) { + if (drawCount && drawCount2 || countChangeProgress != 1f) { final float progressFinal = (unreadCount == 0 && !markUnread) ? 1f - countChangeProgress : countChangeProgress; if (countOldLayout == null || unreadCount == 0) { StaticLayout drawLayout = unreadCount == 0 ? countOldLayout : countLayout; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/DrawerProfileCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/DrawerProfileCell.java index 096210cb6..f6101d400 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/DrawerProfileCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/DrawerProfileCell.java @@ -41,6 +41,9 @@ import org.telegram.messenger.UserObject; import org.telegram.messenger.FileLog; import org.telegram.messenger.R; import org.telegram.tgnet.TLRPC; +import org.telegram.ui.ActionBar.ActionBarLayout; +import org.telegram.ui.ActionBar.BaseFragment; +import org.telegram.ui.ActionBar.DrawerLayoutContainer; import org.telegram.ui.Components.AvatarDrawable; import org.telegram.ui.Components.BackupImageView; import org.telegram.ui.Components.CubicBezierInterpolator; @@ -49,6 +52,7 @@ import org.telegram.ui.ActionBar.Theme; import org.telegram.ui.Components.RLottieDrawable; import org.telegram.ui.Components.RLottieImageView; import org.telegram.ui.Components.SnowflakesEffect; +import org.telegram.ui.ThemeActivity; public class DrawerProfileCell extends FrameLayout { @@ -71,7 +75,7 @@ public class DrawerProfileCell extends FrameLayout { private int darkThemeBackgroundColor; public static boolean switchingTheme; - public DrawerProfileCell(Context context) { + public DrawerProfileCell(Context context, DrawerLayoutContainer drawerLayoutContainer) { super(context); shadowView = new ImageView(context); @@ -127,6 +131,7 @@ public class DrawerProfileCell extends FrameLayout { } } }; + darkThemeView.setBackground(Theme.createCircleSelectorDrawable(Theme.getColor(Theme.key_dialogButtonSelector), 0, 0)); sunDrawable.beginApplyLayerColors(); int color = Theme.getColor(Theme.key_chats_menuName); sunDrawable.setLayerColor("Sunny.**", color); @@ -180,6 +185,13 @@ public class DrawerProfileCell extends FrameLayout { } switchTheme(themeInfo, toDark); }); + darkThemeView.setOnLongClickListener(e -> { + if (drawerLayoutContainer != null) { + drawerLayoutContainer.presentFragment(new ThemeActivity(ThemeActivity.THEME_TYPE_BASIC)); + return true; + } + return false; + }); addView(darkThemeView, LayoutHelper.createFrame(48, 48, Gravity.RIGHT | Gravity.BOTTOM, 0, 0, 6, 90)); if (Theme.getEventType() == 0) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/HeaderCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/HeaderCell.java index 4cb684855..aadad0a6a 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/HeaderCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/HeaderCell.java @@ -93,6 +93,14 @@ public class HeaderCell extends FrameLayout { super.onMeasure(MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED)); } + public void setTextSize(float dip) { + textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, dip); + } + + public void setTextColor(int color) { + textView.setTextColor(color); + } + public void setText(CharSequence text) { textView.setText(text); } 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 290a578dd..97d086b14 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/NotificationsCheckCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/NotificationsCheckCell.java @@ -37,6 +37,7 @@ public class NotificationsCheckCell extends FrameLayout { private boolean drawLine = true; private boolean isMultiline; private int currentHeight; + private boolean animationsEnabled; public NotificationsCheckCell(Context context) { this(context, 21, 70, false); @@ -103,7 +104,7 @@ public class NotificationsCheckCell extends FrameLayout { public void setTextAndValueAndCheck(String text, CharSequence value, boolean checked, int iconType, boolean multiline, boolean divider) { textView.setText(text); valueTextView.setText(value); - checkBox.setChecked(checked, iconType, false); + checkBox.setChecked(checked, iconType, animationsEnabled); valueTextView.setVisibility(VISIBLE); needDivider = divider; isMultiline = multiline; @@ -151,4 +152,8 @@ public class NotificationsCheckCell extends FrameLayout { canvas.drawRect(x, y, x + 2, y + AndroidUtilities.dp(22), Theme.dividerPaint); } } + + public void setAnimationsEnabled(boolean animationsEnabled) { + this.animationsEnabled = animationsEnabled; + } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/RadioButtonCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/RadioButtonCell.java index 05241c71d..8982ce84b 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/RadioButtonCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/RadioButtonCell.java @@ -26,7 +26,7 @@ import org.telegram.ui.Components.RadioButton; public class RadioButtonCell extends FrameLayout { private TextView textView; - private TextView valueTextView; + public TextView valueTextView; private RadioButton radioButton; private boolean needDivider; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/TextCheckCell2.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/TextCheckCell2.java index 99676b052..c9e0ecf9e 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/TextCheckCell2.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/TextCheckCell2.java @@ -113,6 +113,9 @@ public class TextCheckCell2 extends FrameLayout { @Override public void setEnabled(boolean value) { super.setEnabled(value); + textView.clearAnimation(); + valueTextView.clearAnimation(); + checkBox.clearAnimation(); if (value) { textView.setAlpha(1.0f); valueTextView.setAlpha(1.0f); @@ -124,6 +127,28 @@ public class TextCheckCell2 extends FrameLayout { } } + public void setEnabled(boolean value, boolean animated) { + super.setEnabled(value); + if (animated) { + textView.clearAnimation(); + valueTextView.clearAnimation(); + checkBox.clearAnimation(); + textView.animate().alpha(value ? 1 : .5f).start(); + valueTextView.animate().alpha(value ? 1 : .5f).start(); + checkBox.animate().alpha(value ? 1 : .5f).start(); + } else { + if (value) { + textView.setAlpha(1.0f); + valueTextView.setAlpha(1.0f); + checkBox.setAlpha(1.0f); + } else { + checkBox.setAlpha(0.5f); + textView.setAlpha(0.5f); + valueTextView.setAlpha(0.5f); + } + } + } + public void setChecked(boolean checked) { checkBox.setChecked(checked, true); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/TextSelectionHelper.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/TextSelectionHelper.java index d1aad0464..da2ad6957 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/TextSelectionHelper.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/TextSelectionHelper.java @@ -55,7 +55,6 @@ import org.telegram.ui.ActionBar.FloatingToolbar; import org.telegram.ui.ActionBar.Theme; import org.telegram.ui.ArticleViewer; import org.telegram.ui.Components.LayoutHelper; -import org.telegram.ui.Components.LinkPath; import org.telegram.ui.Components.RecyclerListView; import org.telegram.ui.RestrictedLanguagesSelectActivity; @@ -1473,7 +1472,7 @@ public abstract class TextSelectionHelper { @@ -1246,6 +1246,7 @@ public class ChannelAdminLogActivity extends BaseFragment implements Notificatio builder.setTitle(LocaleController.getString("Message", R.string.Message)); showDialog(builder.create()); + return true; } private String getMessageContent(MessageObject messageObject, int previousUid, boolean name) { @@ -2361,8 +2362,8 @@ public class ChannelAdminLogActivity extends BaseFragment implements Notificatio } @Override - public void didLongPress(ChatActionCell cell, float x, float y) { - createMenu(cell); + public boolean didLongPress(ChatActionCell cell, float x, float y) { + return createMenu(cell); } @Override @@ -2764,7 +2765,7 @@ public class ChannelAdminLogActivity extends BaseFragment implements Notificatio themeDescriptions.add(new ThemeDescription(chatListView, ThemeDescription.FLAG_TEXTCOLOR, new Class[]{ChatActionCell.class}, Theme.chat_actionTextPaint, null, null, Theme.key_chat_serviceText)); themeDescriptions.add(new ThemeDescription(chatListView, ThemeDescription.FLAG_LINKCOLOR, new Class[]{ChatActionCell.class}, Theme.chat_actionTextPaint, null, null, Theme.key_chat_serviceLink)); - themeDescriptions.add(new ThemeDescription(chatListView, 0, new Class[]{ChatMessageCell.class}, null, new Drawable[]{Theme.chat_botCardDrawalbe, Theme.chat_shareIconDrawable, Theme.chat_botInlineDrawable, Theme.chat_botLinkDrawalbe, Theme.chat_goIconDrawable, Theme.chat_commentStickerDrawable}, null, Theme.key_chat_serviceIcon)); + themeDescriptions.add(new ThemeDescription(chatListView, 0, new Class[]{ChatMessageCell.class}, null, new Drawable[]{Theme.chat_botCardDrawable, Theme.chat_shareIconDrawable, Theme.chat_botInlineDrawable, Theme.chat_botLinkDrawable, Theme.chat_goIconDrawable, Theme.chat_commentStickerDrawable}, null, Theme.key_chat_serviceIcon)); themeDescriptions.add(new ThemeDescription(chatListView, 0, new Class[]{ChatMessageCell.class, ChatActionCell.class}, null, null, null, Theme.key_chat_serviceBackground)); themeDescriptions.add(new ThemeDescription(chatListView, 0, new Class[]{ChatMessageCell.class, ChatActionCell.class}, null, null, null, Theme.key_chat_serviceBackgroundSelected)); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ChatActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ChatActivity.java index c1049a4df..01fdb6151 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ChatActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ChatActivity.java @@ -129,6 +129,7 @@ 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; import org.telegram.messenger.SecretChatHelper; import org.telegram.messenger.SendMessagesHelper; @@ -176,6 +177,8 @@ import org.telegram.ui.Cells.TextSelectionHelper; import org.telegram.ui.Components.AlertsCreator; import org.telegram.ui.Components.AnimatedFileDrawable; import org.telegram.ui.Components.AnimationProperties; +import org.telegram.ui.Components.AttachBotIntroTopView; +import org.telegram.ui.Components.AutoDeletePopupWrapper; import org.telegram.ui.Components.BackButtonMenu; import org.telegram.ui.Components.BackupImageView; import org.telegram.ui.Components.BlurBehindDrawable; @@ -191,10 +194,10 @@ 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.ClearHistoryAlert; import org.telegram.ui.Components.ClippingImageView; import org.telegram.ui.Components.CombinedDrawable; import org.telegram.ui.Components.CounterView; @@ -308,6 +311,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not private boolean searchItemVisible; private RadialProgressView progressBar; private ActionBarMenuSubItem addContactItem; + private ActionBarMenuSubItem clearHistoryItem; private ClippingImageView animatingImageView; private RecyclerListView chatListView; private ChatListItemAnimator chatListItemAnimator; @@ -336,6 +340,8 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not private StickersAdapter stickersAdapter; private FrameLayout stickersPanel; private ActionBarMenuSubItem muteItem; + private View muteItemGap; + private ChatNotificationsPopupWrapper chatNotificationsPopupWrapper; private float pagedownButtonEnterProgress; private float mentionsButtonEnterProgress; private float reactionsMentionButtonEnterProgress; @@ -402,11 +408,13 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not private boolean setPinnedTextTranslationX; private AnimatorSet pinnedMessageViewAnimator; private BackupImageView[] pinnedMessageImageView = new BackupImageView[2]; - private SimpleTextView[] pinnedNameTextView = new SimpleTextView[2]; + private TrackingWidthSimpleTextView[] pinnedNameTextView = new TrackingWidthSimpleTextView[2]; private SimpleTextView[] pinnedMessageTextView = new SimpleTextView[2]; + private PinnedMessageButton[] pinnedMessageButton = new PinnedMessageButton[2]; private NumberTextView pinnedCounterTextView; private int pinnedCounterTextViewX; private AnimatorSet[] pinnedNextAnimation = new AnimatorSet[2]; + private boolean pinnedMessageButtonShown = false; private ImageView closePinned; private RadialProgressView pinnedProgress; private ImageView pinnedListButton; @@ -667,10 +675,13 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not private long inlineReturn; private String voiceChatHash; private boolean livestream; + private String attachMenuBotToOpen; + private String attachMenuBotStartCommand; private MessageObject botButtons; private MessageObject botReplyButtons; private int botsCount; private boolean hasBotsCommands; + private boolean hasBotWebView; private long chatEnterTime; private long chatLeaveTime; @@ -889,7 +900,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not private EmojiAnimationsOverlay emojiAnimationsOverlay; public float drawingChatLisViewYoffset; public int blurredViewTopOffset; - private int blurredViewBottomOffset; + public int blurredViewBottomOffset; public void deleteHistory(int dateSelectedStart, int dateSelectedEnd, boolean forAll) { chatAdapter.frozenMessages.clear(); @@ -922,6 +933,34 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not }); } + public void showHeaderItem(boolean show) { + if (show) { + if (chatActivityEnterView.hasText() && TextUtils.isEmpty(chatActivityEnterView.getSlowModeTimer())) { + if (attachItem != null) { + attachItem.setVisibility(View.VISIBLE); + } + if (headerItem != null) { + headerItem.setVisibility(View.GONE); + } + } else { + if (attachItem != null) { + attachItem.setVisibility(View.GONE); + } + if (headerItem != null) { + headerItem.setVisibility(View.VISIBLE); + } + } + } else { + if (attachItem != null) { + attachItem.setVisibility(View.GONE); + } + if (headerItem != null) { + headerItem.setVisibility(View.GONE); + } + } + + } + private interface ChatActivityDelegate { default void openReplyMessage(int mid) { @@ -929,6 +968,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not default void openSearch(String text) { + } default void onUnpin(boolean all, boolean hide) { @@ -1271,8 +1311,9 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not return false; } wasManualScroll = true; - if (!actionBar.isActionModeShowed() && reportType < 0) { - createMenu(view, false, true, x, y); + boolean result = true; + if (!actionBar.isActionModeShowed() && (reportType < 0 || (view instanceof ChatActionCell && ((ChatActionCell) view).getMessageObject().messageOwner.action instanceof TLRPC.TL_messageActionSetMessagesTTL))) { + result = createMenu(view, false, true, x, y); } else { boolean outside = false; if (view instanceof ChatMessageCell) { @@ -1282,8 +1323,9 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } if (view instanceof ChatMessageCell) { startMultiselect(position); + result = true; } - return true; + return result; } }; @@ -1502,6 +1544,8 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not chatMode = arguments.getInt("chatMode", 0); voiceChatHash = arguments.getString("voicechat", null); livestream = !TextUtils.isEmpty(arguments.getString("livestream", null)); + attachMenuBotToOpen = arguments.getString("attach_bot", null); + attachMenuBotStartCommand = arguments.getString("attach_bot_start_command", null); inlineReturn = arguments.getLong("inline_return", 0); String inlineQuery = arguments.getString("inline_query"); startLoadFromMessageId = arguments.getInt("message_id", 0); @@ -2253,37 +2297,27 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (getParentActivity() == null) { return; } - if (id == auto_delete_timer || id == clear_history && currentEncryptedChat == null && (currentUser != null && !UserObject.isUserSelf(currentUser) && !UserObject.isDeleted(currentUser) || ChatObject.canUserDoAdminAction(currentChat, ChatObject.ACTION_DELETE_MESSAGES) && (!ChatObject.isChannel(currentChat) || currentChat.megagroup && TextUtils.isEmpty(currentChat.username)))) { - ClearHistoryAlert alert = new ClearHistoryAlert(getParentActivity(), currentUser, currentChat, id != auto_delete_timer, themeDelegate); - alert.setDelegate(new ClearHistoryAlert.ClearHistoryAlertDelegate() { + boolean canDeleteHistory = chatInfo != null && chatInfo.can_delete_channel; + if (id == auto_delete_timer || id == clear_history && currentEncryptedChat == null && ((currentUser != null && !UserObject.isUserSelf(currentUser) && !UserObject.isDeleted(currentUser)) || (chatInfo != null && chatInfo.can_delete_channel))) { + AlertsCreator.createClearDaysDialogAlert(ChatActivity.this, -1, currentUser, currentChat, canDeleteHistory, new MessagesStorage.BooleanCallback() { @Override - public void onClearHistory(boolean revoke) { - if (revoke && currentUser != null) { - getMessagesStorage().getMessagesCount(currentUser.id, (count) -> { + public void run(boolean revoke) { + if (revoke && (currentUser != null || canDeleteHistory)) { + getMessagesStorage().getMessagesCount(dialog_id, (count) -> { if (count >= 50) { - AlertsCreator.createClearOrDeleteDialogAlert(ChatActivity.this, true, false, true, null, currentUser, false, false, (param) -> performHistoryClear(true), themeDelegate); + AlertsCreator.createClearOrDeleteDialogAlert(ChatActivity.this, true, false, true, currentChat, currentUser, false, false, canDeleteHistory, (param) -> performHistoryClear(true, canDeleteHistory), themeDelegate); } else { - performHistoryClear(true); + performHistoryClear(true, canDeleteHistory); } }); } else { - performHistoryClear(revoke); + performHistoryClear(revoke, canDeleteHistory); } } - - @Override - public void onAutoDeleteHistory(int ttl, int action) { - getMessagesController().setDialogHistoryTTL(dialog_id, ttl); - if (userInfo != null || chatInfo != null) { - undoView.showWithAction(dialog_id, action, currentUser, userInfo != null ? userInfo.ttl_period : chatInfo.ttl_period, null, null); - } - } - }); - showDialog(alert); + }, getResourceProvider()); return; } - - AlertsCreator.createClearOrDeleteDialogAlert(ChatActivity.this, id == clear_history, currentChat, currentUser, currentEncryptedChat != null, true, (param) -> { + AlertsCreator.createClearOrDeleteDialogAlert(ChatActivity.this, id == clear_history, currentChat, currentUser, currentEncryptedChat != null, true, canDeleteHistory, (param) -> { if (id == clear_history && ChatObject.isChannel(currentChat) && (!currentChat.megagroup || !TextUtils.isEmpty(currentChat.username))) { getMessagesController().deleteDialog(dialog_id, 2, param); } else { @@ -2293,7 +2327,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not finishFragment(); getNotificationCenter().postNotificationName(NotificationCenter.needDeleteDialog, dialog_id, currentUser, currentChat, param); } else { - performHistoryClear(param); + performHistoryClear(param, canDeleteHistory); } } }, themeDelegate); @@ -2708,6 +2742,66 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } headerItem = menu.addItem(0, R.drawable.ic_ab_other, themeDelegate); headerItem.setContentDescription(LocaleController.getString("AccDescrMoreOptions", R.string.AccDescrMoreOptions)); + + if (currentUser == null || !currentUser.self) { + chatNotificationsPopupWrapper = new ChatNotificationsPopupWrapper(context, currentAccount, headerItem.getPopupLayout().getSwipeBack(), false, false, new ChatNotificationsPopupWrapper.Callback() { + @Override + public void dismiss() { + headerItem.toggleSubMenu(); + } + + @Override + public void toggleSound() { + SharedPreferences preferences = MessagesController.getNotificationsSettings(currentAccount); + boolean enabled = !preferences.getBoolean("sound_enabled_" + dialog_id, true); + preferences.edit().putBoolean("sound_enabled_" + dialog_id, enabled).apply(); + if (BulletinFactory.canShowBulletin(ChatActivity.this)) { + BulletinFactory.createSoundEnabledBulletin(ChatActivity.this, enabled ? NotificationsController.SETTING_SOUND_ON : NotificationsController.SETTING_SOUND_OFF, getResourceProvider()).show(); + } + updateTitleIcons(); + } + + @Override + public void muteFor(int timeInSeconds) { + getNotificationsController().muteUntil(dialog_id, timeInSeconds); + if (BulletinFactory.canShowBulletin(ChatActivity.this)) { + BulletinFactory.createMuteBulletin(ChatActivity.this, NotificationsController.SETTING_MUTE_CUSTOM, timeInSeconds, getResourceProvider()).show(); + } + } + + @Override + public void showCustomize() { + if (dialog_id != 0) { + if (currentUser != null) { + getMessagesController().putUser(currentUser, true); + } + Bundle args = new Bundle(); + args.putLong("dialog_id", dialog_id); + presentFragment(new ProfileNotificationsActivity(args)); + } + } + + @Override + public void toggleMute() { + ChatActivity.this.toggleMute(true); + BulletinFactory.createMuteBulletin(ChatActivity.this, getMessagesController().isDialogMuted(dialog_id), themeDelegate).show(); + } + }, getResourceProvider()); + muteItem = headerItem.addSwipeBackItem(R.drawable.msg_mute, null, null, chatNotificationsPopupWrapper.windowLayout); + muteItem.setOnClickListener(view -> { + boolean muted = MessagesController.getInstance(currentAccount).isDialogMuted(dialog_id); + if (muted) { + AndroidUtilities.runOnUIThread(() -> { + ChatActivity.this.toggleMute(true); + }, 150); + headerItem.toggleSubMenu(); + BulletinFactory.createMuteBulletin(ChatActivity.this, false, themeDelegate).show(); + } else { + muteItem.openSwipeBack(); + } + }); + muteItemGap = headerItem.addColoredGap(); + } if (currentUser != null) { headerItem.addSubItem(call, R.drawable.msg_callback, LocaleController.getString("Call", R.string.Call), themeDelegate); if (Build.VERSION.SDK_INT >= 18) { @@ -2768,17 +2862,12 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (currentEncryptedChat != null) { timeItem2 = headerItem.addSubItem(chat_enc_timer, R.drawable.msg_timer, LocaleController.getString("SetTimer", R.string.SetTimer), themeDelegate); } - if (!ChatObject.isChannel(currentChat) || currentChat.megagroup && TextUtils.isEmpty(currentChat.username)) { - headerItem.addSubItem(clear_history, R.drawable.msg_clear, LocaleController.getString("ClearHistory", R.string.ClearHistory), themeDelegate); - } else if (ChatObject.canUserDoAdminAction(currentChat, ChatObject.ACTION_DELETE_MESSAGES)) { - headerItem.addSubItem(auto_delete_timer, R.drawable.msg_timer, LocaleController.getString("AutoDeleteSetTimer", R.string.AutoDeleteSetTimer), themeDelegate); - } + + clearHistoryItem = headerItem.addSubItem(clear_history, R.drawable.msg_clear, LocaleController.getString("ClearHistory", R.string.ClearHistory), themeDelegate); + if (themeDelegate.isThemeChangeAvailable()) { headerItem.addSubItem(change_colors, R.drawable.msg_colors, LocaleController.getString("ChangeColors", R.string.ChangeColors), themeDelegate); } - if (currentUser == null || !currentUser.self) { - muteItem = headerItem.addSubItem(mute, R.drawable.msg_mute, null, themeDelegate); - } if (ChatObject.isChannel(currentChat) && !currentChat.creator) { if (!ChatObject.isNotInChat(currentChat)) { if (currentChat.megagroup) { @@ -2926,7 +3015,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not protected void onTransitionStart(boolean keyboardVisible, int contentHeight) { wasManualScroll = true; if (chatActivityEnterView != null) { - chatActivityEnterView.onAdjustPanTransitionStart(keyboardVisible); + chatActivityEnterView.onAdjustPanTransitionStart(keyboardVisible, contentHeight); } } @@ -2960,6 +3049,9 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } chatListView.invalidate(); updateBulletinLayout(); + if (chatActivityEnterView != null) { + chatActivityEnterView.onAdjustPanTransitionUpdate(y, progress, keyboardVisible); + } } @Override @@ -3078,7 +3170,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not @Override protected boolean drawChild(Canvas canvas, View child, long drawingTime) { - if ((scrimView != null || messageEnterTransitionContainer.isRunning()) && (child == pagedownButton || child == mentiondownButton || child == floatingDateView || child == fireworksOverlay || child == reactionsMentiondownButton || child == gifHintTextView)) { + if ((scrimView != null || messageEnterTransitionContainer.isRunning()) && (child == pagedownButton || child == mentiondownButton || child == floatingDateView || child == fireworksOverlay || child == reactionsMentiondownButton || child == gifHintTextView || child == undoView || child == topUndoView)) { return false; } if (child == fragmentContextView && fragmentContextView.isCallStyle()) { @@ -3473,6 +3565,12 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (gifHintTextView != null) { super.drawChild(canvas, gifHintTextView, SystemClock.uptimeMillis()); } + if (undoView != null && undoView.getVisibility() == View.VISIBLE) { + super.drawChild(canvas, undoView, SystemClock.uptimeMillis()); + } + if (topUndoView != null && undoView.getVisibility() == View.VISIBLE) { + super.drawChild(canvas, topUndoView, SystemClock.uptimeMillis()); + } } if (fixedKeyboardHeight > 0 && keyboardHeight < AndroidUtilities.dp(20)) { @@ -4528,7 +4626,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not View child = getChildAt(a); if (chatAdapter.isBot && child instanceof BotHelpCell) { BotHelpCell botCell = (BotHelpCell) child; - float top = getMeasuredHeight() / 2 - child.getMeasuredHeight() / 2 + chatListViewPaddingTop; + float top = (getMeasuredHeight() - chatListViewPaddingTop - blurredViewBottomOffset) / 2 - child.getMeasuredHeight() / 2 + chatListViewPaddingTop; if (!botCell.animating() && !chatListView.fastScrollAnimationRunning) { if (child.getTop() > top) { child.setTranslationY(top - child.getTop()); @@ -4943,11 +5041,13 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not r - AndroidUtilities.dp(8), b - AndroidUtilities.dp(8) ); } - canvas.translate(canvasOffsetX, canvasOffsetY); - cell.setInvalidatesParent(true); - cell.drawCaptionLayout(canvas, selectionOnly, alpha); - cell.setInvalidatesParent(false); - canvas.restore(); + if (cell.getTransitionParams().wasDraw) { + canvas.translate(canvasOffsetX, canvasOffsetY); + cell.setInvalidatesParent(true); + cell.drawCaptionLayout(canvas, selectionOnly, alpha); + cell.setInvalidatesParent(false); + canvas.restore(); + } } drawCaptionAfter.clear(); } @@ -5012,7 +5112,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not ); } canvas.translate(canvasOffsetX, canvasOffsetY); - if (position == null || (position.flags & MessageObject.POSITION_FLAG_BOTTOM) != 0) { + if (chatMessageCell.getTransitionParams().wasDraw && (position == null || (position.flags & MessageObject.POSITION_FLAG_BOTTOM) != 0)) { boolean selectionOnly = position != null && (position.flags & MessageObject.POSITION_FLAG_LEFT) == 0; chatMessageCell.setInvalidatesParent(true); chatMessageCell.drawCaptionLayout(canvas, selectionOnly, alpha); @@ -5947,19 +6047,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not pinnedMessageView.addView(pinnedCounterTextView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 18, Gravity.TOP | Gravity.LEFT, 18, 7, 44, 0)); for (int a = 0; a < 2; a++) { - pinnedNameTextView[a] = new SimpleTextView(context) { - @Override - protected boolean createLayout(int width) { - boolean result = super.createLayout(width); - if (this == pinnedNameTextView[0] && pinnedCounterTextView != null) { - int newX = getTextWidth() + AndroidUtilities.dp(4); - if (newX != pinnedCounterTextViewX) { - pinnedCounterTextView.setTranslationX(pinnedCounterTextViewX = newX); - } - } - return result; - } - }; + pinnedNameTextView[a] = new TrackingWidthSimpleTextView(context); pinnedNameTextView[a].setTextSize(14); pinnedNameTextView[a].setTextColor(getThemedColor(Theme.key_chat_topPanelTitle)); pinnedNameTextView[a].setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); @@ -5982,12 +6070,16 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not pinnedMessageTextView[a].setTextColor(getThemedColor(Theme.key_chat_topPanelMessage)); pinnedMessageView.addView(pinnedMessageTextView[a], LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 18, Gravity.TOP | Gravity.LEFT, 18, 25.3f, 44, 0)); + pinnedMessageButton[a] = new PinnedMessageButton(context); + pinnedMessageView.addView(pinnedMessageButton[a], LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, 28, Gravity.TOP | Gravity.RIGHT, 0, 10, 14, 0)); + pinnedMessageImageView[a] = new BackupImageView(context); pinnedMessageImageView[a].setRoundRadius(AndroidUtilities.dp(2)); pinnedMessageView.addView(pinnedMessageImageView[a], LayoutHelper.createFrame(32, 32, Gravity.TOP | Gravity.LEFT, 17, 8, 0, 0)); if (a == 1) { - pinnedMessageTextView[a].setVisibility(View.INVISIBLE); pinnedNameTextView[a].setVisibility(View.INVISIBLE); + pinnedMessageButton[a].setVisibility(View.INVISIBLE); + pinnedMessageTextView[a].setVisibility(View.INVISIBLE); pinnedMessageImageView[a].setVisibility(View.INVISIBLE); } } @@ -6123,7 +6215,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not reportSpamButton = new TextView(context); reportSpamButton.setTextColor(getThemedColor(Theme.key_chat_reportSpam)); if (Build.VERSION.SDK_INT >= 21) { - reportSpamButton.setBackground(Theme.createSelectorDrawable(getThemedColor(Theme.key_chat_reportSpam) & 0x19ffffff, 2)); + reportSpamButton.setBackground(Theme.createSelectorDrawable(getThemedColor(Theme.key_chat_reportSpam) & 0x19ffffff, 3)); } reportSpamButton.setTag(Theme.key_chat_reportSpam); reportSpamButton.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); @@ -6150,7 +6242,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not addToContactsButton.setPadding(AndroidUtilities.dp(4), 0, AndroidUtilities.dp(4), 0); addToContactsButton.setGravity(Gravity.CENTER); if (Build.VERSION.SDK_INT >= 21) { - addToContactsButton.setBackground(Theme.createSelectorDrawable(getThemedColor(Theme.key_chat_addContact) & 0x19ffffff, 2)); + addToContactsButton.setBackground(Theme.createSelectorDrawable(getThemedColor(Theme.key_chat_addContact) & 0x19ffffff, 3)); } topChatPanelView.addView(addToContactsButton, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.LEFT | Gravity.TOP, 0, 0, 0, 1)); addToContactsButton.setOnClickListener(v -> { @@ -6348,7 +6440,6 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not return true; }); - mentionContainer = new FrameLayout(context) { private Rect padding; @@ -6398,6 +6489,10 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not mentionContainer.setVisibility(View.GONE); updateMessageListAccessibilityVisibility(); mentionContainer.setWillNotDraw(false); + + reactionsMentiondownButton = new FrameLayout(context); + contentView.addView(reactionsMentiondownButton, LayoutHelper.createFrame(46, 61, Gravity.RIGHT | Gravity.BOTTOM, 0, 0, 7, 5)); + contentView.addView(mentionContainer, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 110, Gravity.LEFT | Gravity.BOTTOM)); final ContentPreviewViewer.ContentPreviewViewerDelegate contentPreviewViewerDelegate = new ContentPreviewViewer.ContentPreviewViewerDelegate() { @@ -7036,7 +7131,6 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not mentiondownButton.addView(mentiondownButtonCounter, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, 23, Gravity.TOP | Gravity.CENTER_HORIZONTAL)); mentiondownButton.setContentDescription(LocaleController.getString("AccDescrMentionDown", R.string.AccDescrMentionDown)); - reactionsMentiondownButton = new FrameLayout(context); reactionsMentiondownButton.setOnClickListener(view -> { wasManualScroll = true; getMessagesController().getNextReactionMention(dialog_id, reactionsMentionCount, (messageId) -> { @@ -7077,7 +7171,6 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not return false; }); reactionsMentiondownButton.setVisibility(View.INVISIBLE); - contentView.addView(reactionsMentiondownButton, LayoutHelper.createFrame(46, 61, Gravity.RIGHT | Gravity.BOTTOM, 0, 0, 7, 5)); reactionsMentiondownButtonImage = new ImageView(context); reactionsMentiondownButtonImage.setImageResource(R.drawable.reactionbutton); reactionsMentiondownButtonImage.setScaleType(ImageView.ScaleType.CENTER); @@ -7721,6 +7814,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } chatActivityEnterView.setId(id_chat_compose_panel); chatActivityEnterView.setBotsCount(botsCount, hasBotsCommands, false); + chatActivityEnterView.updateBotWebView(false); chatActivityEnterView.setMinimumHeight(AndroidUtilities.dp(51)); chatActivityEnterView.setAllowStickersAndGifs(true, currentEncryptedChat == null || AndroidUtilities.getPeerLayerVersion(currentEncryptedChat.layer) >= 46); if (inPreviewMode) { @@ -8201,7 +8295,8 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not toggleMute(true); } } else { - AlertsCreator.createClearOrDeleteDialogAlert(ChatActivity.this, false, currentChat, currentUser, currentEncryptedChat != null, true, (param) -> { + boolean canDeleteHistory = chatInfo != null && chatInfo.can_delete_channel; + AlertsCreator.createClearOrDeleteDialogAlert(ChatActivity.this, false, currentChat, currentUser, currentEncryptedChat != null, true, canDeleteHistory, (param) -> { getNotificationCenter().removeObserver(ChatActivity.this, NotificationCenter.closeChats); getNotificationCenter().postNotificationName(NotificationCenter.closeChats); finishFragment(); @@ -8485,6 +8580,10 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not return fragmentView; } + public ActionBarMenuItem getHeaderItem() { + return headerItem; + } + private void playReactionAnimation(Integer messageId) { if (fragmentView == null) { return; @@ -8510,7 +8609,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not dimBehindView(value, view != reactionsMentiondownButton && view != mentiondownButton); } - private void dimBehindView(boolean enable) { + public void dimBehindView(boolean enable) { dimBehindView(enable ? 0.2f : 0, true); } @@ -8577,6 +8676,31 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not scrimAnimatorSet.start(); } + private class PinnedMessageButton extends TextView { + public PinnedMessageButton(Context context) { + super(context); + + setSingleLine(true); + setLines(1); + setMaxLines(1); + setEllipsize(TextUtils.TruncateAt.END); + setTextColor(getThemedColor(Theme.key_featuredStickers_buttonText)); + setBackground(Theme.getRoundRectSelectorWithBackgroundDrawable(AndroidUtilities.dp(16), getThemedColor(Theme.key_featuredStickers_addButton), 0x60ffffff)); + setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); + setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); + setGravity(Gravity.CENTER); + setPadding(AndroidUtilities.dp(14), 0, AndroidUtilities.dp(14), 0); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure( + View.MeasureSpec.makeMeasureSpec(Math.min(View.MeasureSpec.getSize(widthMeasureSpec), (int) (AndroidUtilities.displaySize.x * 0.35f)), View.MeasureSpec.AT_MOST), + heightMeasureSpec + ); + } + }; + private void updatePagedownButtonsPosition() { float baseTranslationY = chatActivityEnterView.getAnimatedTop() + chatActivityEnterView.getTranslationY() + (chatActivityEnterTopView.getVisibility() == View.VISIBLE ? chatActivityEnterTopView.getTranslationY() : 0); if (pagedownButton != null) { @@ -8591,7 +8715,10 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } private void updateReactionsMentionButton(boolean animated) { - boolean visible = reactionsMentionCount > 0; + if (reactionsMentiondownButtonCounter == null || getParentActivity() == null) { + return; + } + boolean visible = reactionsMentionCount > 0 && chatMode == 0; reactionsMentiondownButtonCounter.setCount(reactionsMentionCount, animated); if (visible && reactionsMentiondownButton.getTag() == null) { reactionsMentiondownButton.setTag(1); @@ -8714,6 +8841,11 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not chatActivityEnterView.getSendButton().callOnClick(); } }; + TLRPC.Peer defPeer = chatInfo != null ? chatInfo.default_send_as : null; + if (defPeer == null && sendAsPeersObj != null && !sendAsPeersObj.peers.isEmpty()) { + defPeer = sendAsPeersObj.peers.get(0); + } + forwardingPreviewView.setSendAsPeer(defPeer); checkShowBlur(true); contentView.addView(forwardingPreviewView); @@ -9786,7 +9918,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not chatAttachAlert = new ChatAttachAlert(getParentActivity(), this, false, false, themeDelegate) { @Override public void dismissInternal() { - if (chatAttachAlert.isShowing()) { + if (chatAttachAlert != null && chatAttachAlert.isShowing()) { AndroidUtilities.requestAdjustResize(getParentActivity(), classGuid); } super.dismissInternal(); @@ -9862,7 +9994,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not @Override public void didSelectBot(TLRPC.User user) { - if (chatActivityEnterView == null || TextUtils.isEmpty(user.username)) { + if (chatActivityEnterView == null || user == null || TextUtils.isEmpty(user.username)) { return; } chatActivityEnterView.setFieldText("@" + user.username + " "); @@ -9912,7 +10044,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not NotificationCenter.getInstance(currentAccount).doOnIdle(runnable); } - public void performHistoryClear(boolean revoke) { + public void performHistoryClear(boolean revoke, boolean canDeleteHistory) { clearingHistory = true; undoView.showWithAction(dialog_id, UndoView.ACTION_CLEAR, () -> { if (!pinnedMessageIds.isEmpty()) { @@ -11436,8 +11568,10 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not CharSequence sourceText = null; if (!TextUtils.isEmpty(restrictionReason)) { replyObjectText = restrictionReason; + sourceText = restrictionReason; } else if (messageObjectToReply.messageOwner.media instanceof TLRPC.TL_messageMediaGame) { replyObjectText = Emoji.replaceEmoji(messageObjectToReply.messageOwner.media.game.title, replyObjectTextView.getPaint().getFontMetricsInt(), AndroidUtilities.dp(14), false); + sourceText = messageObjectToReply.messageOwner.media.game.title; } else if (messageObjectToReply.messageText != null || messageObjectToReply.caption != null) { String mess = messageObjectToReply.caption != null ? messageObjectToReply.caption.toString() : messageObjectToReply.messageText.toString(); sourceText = mess; @@ -11448,8 +11582,9 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not replyObjectText = Emoji.replaceEmoji(mess, replyObjectTextView.getPaint().getFontMetricsInt(), AndroidUtilities.dp(14), false); } if (replyObjectText != null) { - if (replyObjectText instanceof Spannable) + if (replyObjectText instanceof Spannable && sourceText != null) { MediaDataController.addTextStyleRuns(messageObjectToReply.messageOwner.entities, sourceText, (Spannable) replyObjectText); + } replyObjectTextView.setText(replyObjectText); } @@ -12472,36 +12607,14 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not boolean muted = getMessagesController().isDialogMuted(dialog_id); if (!muted) { if (instant) { - long flags; - SharedPreferences preferences = MessagesController.getNotificationsSettings(currentAccount); - SharedPreferences.Editor editor = preferences.edit(); - editor.putInt("notify2_" + dialog_id, 2); - flags = 1; - getMessagesStorage().setDialogFlags(dialog_id, flags); - editor.commit(); - TLRPC.Dialog dialog = getMessagesController().dialogs_dict.get(dialog_id); - if (dialog != null) { - dialog.notify_settings = new TLRPC.TL_peerNotifySettings(); - dialog.notify_settings.mute_until = Integer.MAX_VALUE; - } - getNotificationsController().updateServerNotificationsSettings(dialog_id); - getNotificationsController().removeNotificationsForDialog(dialog_id); + getNotificationsController().muteDialog(dialog_id, true); } else { BottomSheet alert = AlertsCreator.createMuteAlert(this, dialog_id, themeDelegate); alert.setCalcMandatoryInsets(isKeyboardVisible()); showDialog(alert); } } else { - SharedPreferences preferences = MessagesController.getNotificationsSettings(currentAccount); - SharedPreferences.Editor editor = preferences.edit(); - editor.putInt("notify2_" + dialog_id, 0); - getMessagesStorage().setDialogFlags(dialog_id, 0); - editor.commit(); - TLRPC.Dialog dialog = getMessagesController().dialogs_dict.get(dialog_id); - if (dialog != null) { - dialog.notify_settings = new TLRPC.TL_peerNotifySettings(); - } - getNotificationsController().updateServerNotificationsSettings(dialog_id); + getNotificationsController().muteDialog(dialog_id, false); if (!instant) { BulletinFactory.createMuteBulletin(this, false, themeDelegate).show(); } @@ -12553,7 +12666,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not private boolean nextScrollForce; private int nextScrollForcePinnedMessageId; - private boolean pinnedPorgressIsShowing; + private boolean pinnedProgressIsShowing; Runnable updatePinnedProgressRunnable; public void scrollToMessageId(int id, int fromMessageId, boolean select, int loadIndex, boolean forceScroll, int forcePinnedMessageId) { @@ -12738,7 +12851,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (show) { if (updatePinnedProgressRunnable == null) { updatePinnedProgressRunnable = () -> { - pinnedPorgressIsShowing = true; + pinnedProgressIsShowing = true; updatePinnedListButton(true); }; AndroidUtilities.runOnUIThread(updatePinnedProgressRunnable, 100); @@ -12748,7 +12861,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not AndroidUtilities.cancelRunOnUIThread(updatePinnedProgressRunnable); } updatePinnedProgressRunnable = null; - pinnedPorgressIsShowing = false; + pinnedProgressIsShowing = false; updatePinnedListButton(true); } } @@ -13036,13 +13149,17 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } if (avatarContainer != null) { if (currentEncryptedChat != null) { - avatarContainer.setTime(currentEncryptedChat.ttl); + avatarContainer.setTime(currentEncryptedChat.ttl, animated); } else if (userInfo != null) { - avatarContainer.setTime(userInfo.ttl_period); + avatarContainer.setTime(userInfo.ttl_period, animated); } else if (chatInfo != null) { - avatarContainer.setTime(chatInfo.ttl_period); + avatarContainer.setTime(chatInfo.ttl_period, animated); } } + if (clearHistoryItem != null && chatInfo != null) { + boolean visible = chatInfo.can_delete_channel || !ChatObject.isChannel(currentChat) || currentChat.megagroup && TextUtils.isEmpty(currentChat.username); + clearHistoryItem.setVisibility(visible ? View.VISIBLE : View.GONE); + } checkAndUpdateAvatar(); } @@ -13657,15 +13774,25 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (avatarContainer == null || chatMode != 0) { return; } - Drawable rightIcon = getMessagesController().isDialogMuted(dialog_id) ? getThemedDrawable(Theme.key_drawable_muteIconDrawable) : null; + boolean isMuted = getMessagesController().isDialogMuted(dialog_id); + Drawable rightIcon = isMuted ? getThemedDrawable(Theme.key_drawable_muteIconDrawable) : null; avatarContainer.setTitleIcons(currentEncryptedChat != null ? getThemedDrawable(Theme.key_drawable_lockIconDrawable) : null, !UserObject.isReplyUser(currentUser) && !isThreadChat() ? rightIcon : null); if (muteItem != null) { - if (rightIcon != null) { - muteItem.setTextAndIcon(LocaleController.getString("UnmuteNotifications", R.string.UnmuteNotifications), R.drawable.msg_unmute); + if (isMuted) { + muteItem.getRightIcon().setVisibility(View.GONE); + muteItem.setTextAndIcon(LocaleController.getString("Unmute", R.string.Unmute), R.drawable.msg_mute); } else { - muteItem.setTextAndIcon(LocaleController.getString("MuteNotifications", R.string.MuteNotifications), R.drawable.msg_mute); + muteItem.getRightIcon().setVisibility(View.VISIBLE); + if (getMessagesController().isDialogNotificationsSoundEnabled(dialog_id)) { + muteItem.setTextAndIcon(LocaleController.getString("Mute", R.string.Mute), R.drawable.msg_unmute); + } else { + muteItem.setTextAndIcon(LocaleController.getString("Mute", R.string.Mute), R.drawable.msg_silent); + } } } + if (chatNotificationsPopupWrapper != null) { + chatNotificationsPopupWrapper.update(dialog_id); + } } private void checkAndUpdateAvatar() { @@ -14390,7 +14517,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not endReached[0] = cacheEndReached[0] = true; forwardEndReached[0] = forwardEndReached[0] = true; } - if (ChatObject.isChannel(currentChat) && !getMessagesController().dialogs_dict.containsKey(dialog_id) && load_type == 2 && isCache && loadIndex == 0) { + if (ChatObject.isChannel(currentChat) && !getMessagesController().dialogs_dict.containsKey(dialog_id) && load_type == 2 && loadIndex == 0) { forwardEndReached[0] = false; hideForwardEndReached = true; } @@ -15823,9 +15950,9 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); if (reason == 0) { if (currentChat.has_link) { - builder.setMessage(LocaleController.getString("ChannelCantOpenBannedByAdmin", R.string.ChannelCantOpenBannedByAdmin)); - } else { builder.setMessage(LocaleController.getString("ChannelCantOpenPrivate", R.string.ChannelCantOpenPrivate)); + } else { + builder.setMessage(LocaleController.getString("ChannelCantOpenBannedByAdmin", R.string.ChannelCantOpenBannedByAdmin)); } } else if (reason == 1) { builder.setMessage(LocaleController.getString("ChannelCantOpenNa", R.string.ChannelCantOpenNa)); @@ -16504,6 +16631,8 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } if (chatActivityEnterView != null) { chatActivityEnterView.setBotsCount(botsCount, hasBotsCommands, true); + hasBotWebView = getMessagesController().getUser(info.user_id).bot_menu_webview; + chatActivityEnterView.updateBotWebView(true); } } updateBotButtons(); @@ -16761,7 +16890,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } } } - checkActionBarMenu(false); + checkActionBarMenu(fragmentOpened); if (!inMenuMode && !loadingPinnedMessagesList && !pinnedMessageIds.isEmpty() && userInfo.pinned_msg_id > pinnedMessageIds.get(0)) { getMediaDataController().loadPinnedMessages(dialog_id, 0, userInfo.pinned_msg_id); loadingPinnedMessagesList = true; @@ -17101,16 +17230,11 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (BuildVars.LOGS_ENABLED) { FileLog.d("clear history by overwrite firstLoading=" + firstLoading + " minMessage=" + minMessageId[0] + " topMessage=" + differenceTooLong.dialog.top_message); } - if (firstLoading) { - waitingForLoad.clear(); - chatWasReset = true; - last_message_id = differenceTooLong.dialog.top_message; - createUnreadMessageAfterId = 0; - } else { - if (differenceTooLong.dialog.top_message > minMessageId[0]) { - createUnreadMessageAfterId = Math.max(minMessageId[0] + 1, differenceTooLong.dialog.read_inbox_max_id); - } + + if (differenceTooLong.dialog.top_message > minMessageId[0]) { + createUnreadMessageAfterId = Math.max(minMessageId[0] + 1, differenceTooLong.dialog.read_inbox_max_id); } + forwardEndReached[0] = false; hideForwardEndReached = false; if (chatAdapter != null && chatAdapter.loadingDownRow < 0) { @@ -17457,7 +17581,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } TLRPC.MessageAction action = obj.messageOwner.action; if (avatarContainer != null && currentEncryptedChat != null && action instanceof TLRPC.TL_messageEncryptedAction && action.encryptedAction instanceof TLRPC.TL_decryptedMessageActionSetMessageTTL) { - avatarContainer.setTime(action.encryptedAction.ttl_seconds); + avatarContainer.setTime(action.encryptedAction.ttl_seconds, true); } if (action instanceof TLRPC.TL_messageActionChatMigrateTo) { migrateToNewChat(obj); @@ -17578,7 +17702,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } TLRPC.MessageAction action = obj.messageOwner.action; if (avatarContainer != null && currentEncryptedChat != null && action instanceof TLRPC.TL_messageEncryptedAction && action.encryptedAction instanceof TLRPC.TL_decryptedMessageActionSetMessageTTL) { - avatarContainer.setTime(action.encryptedAction.ttl_seconds); + avatarContainer.setTime(action.encryptedAction.ttl_seconds, true); } if (obj.type < 0 || messagesDict[0].indexOfKey(messageId) >= 0) { continue; @@ -18656,6 +18780,66 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not getNotificationCenter().onAnimationFinish(transitionAnimationIndex); } contentView.invalidate(); + + if (!TextUtils.isEmpty(attachMenuBotToOpen)) { + if (getCurrentUser() != null) { + TLRPC.TL_contacts_resolveUsername req = new TLRPC.TL_contacts_resolveUsername(); + req.username = attachMenuBotToOpen; + getConnectionsManager().sendRequest(req, (response, error) -> AndroidUtilities.runOnUIThread(()->{ + if (response != null) { + TLRPC.TL_contacts_resolvedPeer resolvedPeer = (TLRPC.TL_contacts_resolvedPeer) response; + if (!resolvedPeer.users.isEmpty()) { + TLRPC.User user = resolvedPeer.users.get(0); + if (user.bot && user.bot_attach_menu) { + TLRPC.TL_messages_getAttachMenuBot getAttachMenuBot = new TLRPC.TL_messages_getAttachMenuBot(); + getAttachMenuBot.bot = MessagesController.getInstance(currentAccount).getInputUser(user.id); + ConnectionsManager.getInstance(currentAccount).sendRequest(getAttachMenuBot, (response1, error1) -> AndroidUtilities.runOnUIThread(()-> { + if (response1 instanceof TLRPC.TL_attachMenuBotsBot) { + TLRPC.TL_attachMenuBotsBot attachMenuBotsBot = (TLRPC.TL_attachMenuBotsBot) response1; + MessagesController.getInstance(currentAccount).putUsers(attachMenuBotsBot.users, false); + TLRPC.TL_attachMenuBot attachMenuBot = attachMenuBotsBot.bot; + + if (!attachMenuBot.inactive) { + openAttachBotLayout(user.id, attachMenuBotStartCommand); + } else { + AttachBotIntroTopView introTopView = new AttachBotIntroTopView(getParentActivity()); + introTopView.setColor(Theme.getColor(Theme.key_chat_attachContactIcon)); + introTopView.setBackgroundColor(Theme.getColor(Theme.key_dialogTopBackground)); + introTopView.setAttachBot(attachMenuBot); + new AlertDialog.Builder(getParentActivity()) + .setTopView(introTopView) + .setMessage(AndroidUtilities.replaceTags(LocaleController.formatString("BotRequestAttachPermission", R.string.BotRequestAttachPermission, UserObject.getUserName(user)))) + .setPositiveButton(LocaleController.getString(R.string.BotAddToMenu), (dialog, which) -> { + TLRPC.TL_messages_toggleBotInAttachMenu botRequest = new TLRPC.TL_messages_toggleBotInAttachMenu(); + botRequest.bot = MessagesController.getInstance(currentAccount).getInputUser(user.id); + botRequest.enabled = true; + ConnectionsManager.getInstance(currentAccount).sendRequest(botRequest, (response2, error2) -> AndroidUtilities.runOnUIThread(() -> { + if (error2 == null) { + MediaDataController.getInstance(currentAccount).loadAttachMenuBots(false, true); + + openAttachBotLayout(user.id, attachMenuBotStartCommand); + } + }), ConnectionsManager.RequestFlagInvokeAfter | ConnectionsManager.RequestFlagFailOnServerErrors); + }) + .setNegativeButton(LocaleController.getString(R.string.Cancel), null) + .show(); + } + } + })); + } + } + } + })); + } else { + BulletinFactory.of(this).createErrorBulletin(LocaleController.getString(ChatObject.isChannelAndNotMegaGroup(currentChat) ? R.string.BotCantOpenAttachMenuChannel : R.string.BotCantOpenAttachMenuGroup)).show(); + } + attachMenuBotToOpen = null; + } + } + + public void openAttachBotLayout(long botId, String startCommand) { + openAttachMenu(); + chatAttachAlert.showBotLayout(botId, startCommand); } @Override @@ -18860,8 +19044,10 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (muteItem != null) { if (currentChat != null && ChatObject.isNotInChat(currentChat)) { muteItem.setVisibility(View.GONE); + muteItemGap.setVisibility(View.GONE); } else { muteItem.setVisibility(View.VISIBLE); + muteItemGap.setVisibility(View.VISIBLE); } } if (reportType >= 0) { @@ -19094,25 +19280,28 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (isThreadChat() || pinnedListButton == null || inMenuMode) { return; } - boolean show = pinnedMessageIds.size() > 1; + boolean show = pinnedMessageIds.size() > 1 && !pinnedMessageButtonShown; boolean visible = pinnedListButton.getTag() != null; boolean progressIsVisible = pinnedProgress.getTag() != null; + boolean closeIsVisible = closePinned.getTag() != null; - if (show != visible || progressIsVisible != pinnedPorgressIsShowing) { + boolean showClosed = !show && !pinnedProgressIsShowing && !pinnedMessageButtonShown; + boolean showPinned = show && !pinnedProgressIsShowing && !pinnedMessageButtonShown; + boolean showProgress = pinnedProgressIsShowing && !pinnedMessageButtonShown; + + if (visible != show || progressIsVisible != showProgress || closeIsVisible != showClosed) { if (pinnedListAnimator != null) { pinnedListAnimator.cancel(); pinnedListAnimator = null; } - boolean showClosed = !show && !pinnedPorgressIsShowing; - boolean showPinned = show && !pinnedPorgressIsShowing; if (animated) { if (show) { pinnedListButton.setVisibility(View.VISIBLE); - } else { + } else if (showClosed) { closePinned.setVisibility(View.VISIBLE); } - if (pinnedPorgressIsShowing) { + if (showProgress) { pinnedProgress.setVisibility(View.VISIBLE); pinnedProgress.setAlpha(0); pinnedProgress.setScaleX(0.4f); @@ -19127,9 +19316,9 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not ObjectAnimator.ofFloat(closePinned, View.ALPHA, showClosed ? 1.0f : 0.0f), ObjectAnimator.ofFloat(closePinned, View.SCALE_X, showClosed ? 1.0f : 0.4f), ObjectAnimator.ofFloat(closePinned, View.SCALE_Y, showClosed ? 1.0f : 0.4f), - ObjectAnimator.ofFloat(pinnedProgress, View.ALPHA, !pinnedPorgressIsShowing ? 0.0f : 1.0f), - ObjectAnimator.ofFloat(pinnedProgress, View.SCALE_X, !pinnedPorgressIsShowing ? 0.4f : 1.0f), - ObjectAnimator.ofFloat(pinnedProgress, View.SCALE_Y, !pinnedPorgressIsShowing ? 0.4f : 1.0f) + ObjectAnimator.ofFloat(pinnedProgress, View.ALPHA, !showProgress ? 0.0f : 1.0f), + ObjectAnimator.ofFloat(pinnedProgress, View.SCALE_X, !showProgress ? 0.4f : 1.0f), + ObjectAnimator.ofFloat(pinnedProgress, View.SCALE_Y, !showProgress ? 0.4f : 1.0f) ); pinnedListAnimator.setDuration(180); @@ -19140,7 +19329,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not closePinned.setVisibility(showClosed ? View.VISIBLE : View.INVISIBLE); pinnedListButton.setVisibility(showPinned ? View.VISIBLE : View.INVISIBLE); - pinnedProgress.setVisibility(pinnedPorgressIsShowing ? View.VISIBLE : View.INVISIBLE); + pinnedProgress.setVisibility(showProgress ? View.VISIBLE : View.INVISIBLE); } }); pinnedListAnimator.start(); @@ -19153,14 +19342,14 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not pinnedListButton.setScaleX(showPinned ? 1.0f : 0.4f); pinnedListButton.setScaleY(showPinned ? 1.0f : 0.4f); pinnedListButton.setVisibility(showPinned ? View.VISIBLE : View.INVISIBLE); - - pinnedProgress.setAlpha(pinnedPorgressIsShowing ? 1.0f : 0.0f); - pinnedProgress.setScaleX(pinnedPorgressIsShowing ? 1.0f : 0.4f); - pinnedProgress.setScaleY(pinnedPorgressIsShowing ? 1.0f : 0.4f); - pinnedProgress.setVisibility(pinnedPorgressIsShowing ? View.VISIBLE : View.GONE); + pinnedProgress.setAlpha(showProgress ? 1.0f : 0.0f); + pinnedProgress.setScaleX(showProgress ? 1.0f : 0.4f); + pinnedProgress.setScaleY(showProgress ? 1.0f : 0.4f); + pinnedProgress.setVisibility(showProgress ? View.VISIBLE : View.GONE); } + closePinned.setTag(showClosed ? 1 : null); pinnedListButton.setTag(show ? 1 : null); - pinnedProgress.setTag(pinnedPorgressIsShowing ? 1 : null); + pinnedProgress.setTag(showProgress ? 1 : null); } if (pinnedLineView != null) { if (isThreadChat()) { @@ -19172,6 +19361,16 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } } + private TLRPC.KeyboardButton pinnedButton(MessageObject message) { + return (message != null && message.messageOwner != null && message.messageOwner.reply_markup != null && + message.messageOwner.reply_markup.rows != null && message.messageOwner.reply_markup.rows.size() == 1 && + message.messageOwner.reply_markup.rows.get(0) != null && message.messageOwner.reply_markup.rows.get(0).buttons != null && + message.messageOwner.reply_markup.rows.get(0).buttons.size() == 1 ? + message.messageOwner.reply_markup.rows.get(0).buttons.get(0) : + null + ); + } + private void updatePinnedMessageView(boolean animated, int animateToNext) { if (pinnedMessageView == null || chatMode != 0 || inMenuMode) { return; @@ -19197,6 +19396,8 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not pinnedMessageObject = null; pinned_msg_id = 0; } + TLRPC.KeyboardButton botButton = pinnedButton(pinnedMessageObject); + pinnedMessageButtonShown = botButton != null; SharedPreferences preferences = MessagesController.getNotificationsSettings(currentAccount); if (threadMessageObject == null && (chatInfo == null && userInfo == null || pinned_msg_id == 0 || !pinnedMessageIds.isEmpty() && pinnedMessageIds.get(0) == preferences.getInt("pin_" + dialog_id, 0)) || reportType >= 0 || actionBar != null && (actionBar.isActionModeShowed() || actionBar.isSearchFieldVisible())) { changed = hidePinnedMessageView(animated); @@ -19254,9 +19455,45 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not pinnedNextAnimation[a] = null; } } + setPinnedTextTranslationX = false; - SimpleTextView nameTextView = pinnedNameTextView[animateToNext != 0 && loadedPinnedMessagesCount == 2 ? 1 : 0]; + TrackingWidthSimpleTextView nameTextView = pinnedNameTextView[animateToNext != 0 ? 1 : 0]; SimpleTextView messageTextView = pinnedMessageTextView[animateToNext != 0 ? 1 : 0]; + PinnedMessageButton buttonTextView = pinnedMessageButton[animateToNext != 0 ? 1 : 0]; + + buttonTextView.setVisibility(botButton != null ? View.VISIBLE : View.GONE); + pinnedMessageButton[animateToNext != 0 ? 0 : 1].setOnClickListener(null); + if (botButton == null) { + buttonTextView.setText(null); + buttonTextView.setOnClickListener(null); + } else { + SpannableString string = new SpannableString(botButton.text); + Emoji.replaceEmoji(string, buttonTextView.getPaint().getFontMetricsInt(), AndroidUtilities.dp(20), false); + buttonTextView.setText(string); + final MessageObject buttonMessage = pinnedMessageObject; + buttonTextView.setOnClickListener(e -> { + if (getParentActivity() == null || bottomOverlayChat.getVisibility() == View.VISIBLE && + !(botButton instanceof TLRPC.TL_keyboardButtonSwitchInline) && !(botButton instanceof TLRPC.TL_keyboardButtonCallback) && + !(botButton instanceof TLRPC.TL_keyboardButtonGame) && !(botButton instanceof TLRPC.TL_keyboardButtonUrl) && + !(botButton instanceof TLRPC.TL_keyboardButtonBuy) && !(botButton instanceof TLRPC.TL_keyboardButtonUrlAuth) && + !(botButton instanceof TLRPC.TL_keyboardButtonUserProfile)) { + return; + } + chatActivityEnterView.didPressedBotButton(botButton, buttonMessage, buttonMessage); + }); + } + buttonTextView.measure(View.MeasureSpec.makeMeasureSpec(999999, View.MeasureSpec.AT_MOST), View.MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(28), View.MeasureSpec.EXACTLY)); + if (messageTextView.getLayoutParams() instanceof ViewGroup.MarginLayoutParams) { + ((ViewGroup.MarginLayoutParams) messageTextView.getLayoutParams()).rightMargin = ( + (botButton == null ? AndroidUtilities.dp(44) : buttonTextView.getMeasuredWidth() + AndroidUtilities.dp(14 + 8)) + ); + } + if (nameTextView.getLayoutParams() instanceof ViewGroup.MarginLayoutParams) { + ((ViewGroup.MarginLayoutParams) nameTextView.getLayoutParams()).rightMargin = ( + (botButton == null ? AndroidUtilities.dp(44) : buttonTextView.getMeasuredWidth() + AndroidUtilities.dp(14 + 8)) + ); + } + FrameLayout.LayoutParams layoutParams1 = (FrameLayout.LayoutParams) pinnedNameTextView[0].getLayoutParams(); FrameLayout.LayoutParams layoutParams2 = (FrameLayout.LayoutParams) pinnedNameTextView[1].getLayoutParams(); FrameLayout.LayoutParams layoutParams3 = (FrameLayout.LayoutParams) pinnedCounterTextView.getLayoutParams(); @@ -19318,6 +19555,9 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not pinnedMessageTextView[0].setLayoutParams(layoutParams4); pinnedMessageTextView[1].setLayoutParams(layoutParams5); + boolean showCounter = false; + boolean shouldAnimateName = loadedPinnedMessagesCount == 2 || !pinnedNameTextView[animateToNext != 0 ? 0 : 1].getTrackWidth(); + nameTextView.setTrackWidth(true); if (threadMessageId != 0) { MessagesController messagesController = getMessagesController(); TLRPC.MessageFwdHeader fwd_from = threadMessageObject.messageOwner.fwd_from; @@ -19362,14 +19602,24 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not nameTextView.setText(chat.title); } } else { - if (currentPinnedMessageIndex[0] == 0 || loadedPinnedMessagesCount != 2) { - nameTextView.setText(LocaleController.getString("PinnedMessage", R.string.PinnedMessage)); + if (pinnedMessageObject.isInvoice() && + pinnedMessageObject.messageOwner != null && pinnedMessageObject.messageOwner.media != null && + pinnedMessageObject.messageOwner.media.title != null) { + nameTextView.setTrackWidth(false); + nameTextView.setText(pinnedMessageObject.messageOwner.media.title); + shouldAnimateName = true; + showCounter = false; } else { - nameTextView.setText(LocaleController.getString("PreviousPinnedMessage", R.string.PreviousPinnedMessage)); - } - if (currentPinnedMessageIndex[0] != 0) { - int total = getPinnedMessagesCount(); - pinnedCounterTextView.setNumber(Math.min(total - 1, Math.max(1, total - currentPinnedMessageIndex[0])), animated && pinnedCounterTextView.getTag() == null); + if (currentPinnedMessageIndex[0] == 0 || loadedPinnedMessagesCount != 2) { + nameTextView.setText(LocaleController.getString("PinnedMessage", R.string.PinnedMessage)); + } else { + nameTextView.setText(LocaleController.getString("PreviousPinnedMessage", R.string.PreviousPinnedMessage)); + } + if (currentPinnedMessageIndex[0] != 0) { + int total = getPinnedMessagesCount(); + pinnedCounterTextView.setNumber(Math.min(total - 1, Math.max(1, total - currentPinnedMessageIndex[0])), animated && pinnedCounterTextView.getTag() == null); + showCounter = true; + } } } CharSequence pinnedText = null; @@ -19401,9 +19651,9 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not pinnedText = Emoji.replaceEmoji(mess, messageTextView.getPaint().getFontMetricsInt(), AndroidUtilities.dp(14), false); } if (pinnedText != null) { - if (pinnedText instanceof Spannable) + if (pinnedText instanceof Spannable) { MediaDataController.addTextStyleRuns(pinnedMessageObject, (Spannable) pinnedText); - + } messageTextView.setText(pinnedText); } if (animateToNext != 0) { @@ -19413,8 +19663,11 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not ArrayList animators2 = new ArrayList<>(); messageTextView.setVisibility(View.VISIBLE); nameTextView.setVisibility(View.VISIBLE); + if (botButton != null) { + buttonTextView.setVisibility(View.VISIBLE); + } - if (loadedPinnedMessagesCount == 2 || currentPinnedMessageIndex[0] == 0) { + if (!showCounter) { if (pinnedCounterTextView.getTag() == null) { animators.add(ObjectAnimator.ofFloat(pinnedCounterTextView, View.ALPHA, 1.0f, 0.0f)); animators.add(ObjectAnimator.ofFloat(pinnedCounterTextView, View.TRANSLATION_Y, 0.0f, -AndroidUtilities.dp(4))); @@ -19430,13 +19683,20 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } } - if (loadedPinnedMessagesCount == 2 && !TextUtils.equals(nameTextView.getText(), pinnedNameTextView[0].getText())) { + boolean animateName; + if (shouldAnimateName && !TextUtils.equals(nameTextView.getText(), pinnedNameTextView[0].getText())) { nameTextView.setAlpha(0); animators.add(ObjectAnimator.ofFloat(nameTextView, View.ALPHA, 0.0f, 1.0f)); animators.add(ObjectAnimator.ofFloat(pinnedNameTextView[0], View.ALPHA, 1.0f, 0.0f)); animators.add(ObjectAnimator.ofFloat(nameTextView, View.TRANSLATION_Y, AndroidUtilities.dp(animateToNext == 2 ? 4 : -4), 0.0f)); + if (animateName = forceScrollToFirst && loadedPinnedMessagesCount > 5) { + animators2.add(ObjectAnimator.ofFloat(nameTextView, View.TRANSLATION_Y, AndroidUtilities.dp(4), AndroidUtilities.dp(-2))); + } else { + animators.add(ObjectAnimator.ofFloat(nameTextView, View.TRANSLATION_Y, AndroidUtilities.dp(animateToNext == 2 ? 4 : -4), 0.0f)); + } animators.add(ObjectAnimator.ofFloat(pinnedNameTextView[0], View.TRANSLATION_Y, 0.0f, AndroidUtilities.dp(animateToNext == 2 ? -4 : 4))); } else { + animateName = false; if (nameTextView != pinnedNameTextView[0]) { nameTextView.setAlpha(1.0f); pinnedNameTextView[0].setAlpha(0.0f); @@ -19469,6 +19729,25 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not pinnedMessageTextView[0].setTranslationY(0.0f); } + boolean animateButton; + if (!TextUtils.equals(buttonTextView.getText(), pinnedMessageButton[0].getText())) { + buttonTextView.setAlpha(0); + animators.add(ObjectAnimator.ofFloat(buttonTextView, View.ALPHA, 0.0f, 1.0f)); + animators.add(ObjectAnimator.ofFloat(pinnedMessageButton[0], View.ALPHA, 1.0f, 0.0f)); + if (animateButton = forceScrollToFirst && loadedPinnedMessagesCount > 5) { + animators2.add(ObjectAnimator.ofFloat(buttonTextView, View.TRANSLATION_Y, AndroidUtilities.dp(4), AndroidUtilities.dp(-2))); + } else { + animators.add(ObjectAnimator.ofFloat(buttonTextView, View.TRANSLATION_Y, AndroidUtilities.dp(animateToNext == 2 ? 4 : -4), 0.0f)); + } + animators.add(ObjectAnimator.ofFloat(pinnedMessageButton[0], View.TRANSLATION_Y, 0.0f, AndroidUtilities.dp(animateToNext == 2 ? -4 : 4))); + } else { + animateButton = false; + buttonTextView.setAlpha(1.0f); + pinnedMessageButton[0].setAlpha(0.0f); + buttonTextView.setTranslationY(0.0f); + pinnedMessageButton[0].setTranslationY(0.0f); + } + BackupImageView animateImage; if (layoutParams1.leftMargin != prevMargin) { animateImage = null; @@ -19478,6 +19757,8 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not animators.add(ObjectAnimator.ofFloat(pinnedMessageTextView[1], View.TRANSLATION_X, diff, 0.0f)); animators.add(ObjectAnimator.ofFloat(pinnedNameTextView[0], View.TRANSLATION_X, diff, 0.0f)); animators.add(ObjectAnimator.ofFloat(pinnedNameTextView[1], View.TRANSLATION_X, diff, 0.0f)); + animators.add(ObjectAnimator.ofFloat(pinnedMessageButton[0], View.TRANSLATION_X, diff, 0.0f)); + animators.add(ObjectAnimator.ofFloat(pinnedMessageButton[1], View.TRANSLATION_X, diff, 0.0f)); animators.add(ObjectAnimator.ofFloat(pinnedCounterTextView, View.TRANSLATION_X, pinnedCounterTextViewX + diff, pinnedCounterTextViewX)); if (diff > 0) { pinnedMessageImageView[0].setAlpha(1f); @@ -19495,6 +19776,8 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not pinnedMessageTextView[0].setTranslationX(0); nameTextView.setTranslationX(0); pinnedNameTextView[0].setTranslationX(0); + buttonTextView.setTranslationX(0); + pinnedMessageButton[0].setTranslationX(0); pinnedCounterTextView.setTranslationX(pinnedCounterTextViewX); pinnedMessageImageView[1].setAlpha(1.0f); if (!noImage) { @@ -19524,23 +19807,35 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not @Override public void onAnimationEnd(Animator animation) { if (animation.equals(pinnedNextAnimation[1])) { - if (animateText || animateImage != null) { + if (animateName || animateText || animateImage != null) { pinnedNextAnimation[1] = new AnimatorSet(); pinnedNextAnimation[1].setInterpolator(CubicBezierInterpolator.EASE_OUT); pinnedNextAnimation[1].setDuration(180); ArrayList animators1 = new ArrayList<>(); + if (animateName) { + animators1.add(ObjectAnimator.ofFloat(nameTextView, View.TRANSLATION_Y, 0.0f)); + } if (animateText) { animators1.add(ObjectAnimator.ofFloat(messageTextView, View.TRANSLATION_Y, 0.0f)); } + if (animateButton) { + animators1.add(ObjectAnimator.ofFloat(buttonTextView, View.TRANSLATION_Y, 0.0f)); + } if (animateImage != null) { animators1.add(ObjectAnimator.ofFloat(animateImage, View.TRANSLATION_Y, 0.0f)); } pinnedNextAnimation[1].addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { + if (animateName) { + nameTextView.setTranslationY(0.0f); + } if (animateText) { messageTextView.setTranslationY(0.0f); } + if (animateButton) { + buttonTextView.setTranslationY(0.0f); + } if (animateImage != null) { animateImage.setTranslationY(0.0f); } @@ -19577,10 +19872,16 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not pinnedMessageTextView[0].setTranslationX(0); pinnedMessageTextView[1].setTranslationX(0); pinnedCounterTextView.setTranslationX(pinnedCounterTextViewX); + nameTextView.setTranslationY(0.0f); + if (!animateText) { + nameTextView.setTranslationY(0.0f); + } if (!animateText) { messageTextView.setTranslationY(0.0f); } - nameTextView.setTranslationY(0.0f); + if (!animateButton) { + buttonTextView.setTranslationY(0.0f); + } pinnedNameTextView[0].setTranslationX(0); pinnedNameTextView[1].setTranslationX(0); pinnedMessageImageView[1].setAlpha(1.0f); @@ -19592,6 +19893,9 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not pinnedMessageTextView[1] = pinnedMessageTextView[0]; pinnedMessageTextView[0] = messageTextView; pinnedMessageTextView[1].setVisibility(View.INVISIBLE); + pinnedMessageButton[1] = pinnedMessageButton[0]; + pinnedMessageButton[0] = buttonTextView; + pinnedMessageButton[1].setVisibility(View.INVISIBLE); if (nameTextView != pinnedNameTextView[0]) { pinnedNameTextView[1] = pinnedNameTextView[0]; pinnedNameTextView[0] = nameTextView; @@ -19619,12 +19923,11 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not pinnedNextAnimation[1].start(); } } else { - if (loadedPinnedMessagesCount == 2 || currentPinnedMessageIndex[0] == 0) { + if (!showCounter || currentPinnedMessageIndex[0] == 0) { if (pinnedCounterTextView.getTag() == null) { pinnedCounterTextView.setAlpha(0.0f); pinnedCounterTextView.setVisibility(View.INVISIBLE); pinnedCounterTextView.setTag(1); - } } else { if (pinnedCounterTextView.getTag() != null) { @@ -19636,7 +19939,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not pinnedCounterTextView.setTranslationY(0.0f); pinnedCounterTextView.setTranslationX(pinnedCounterTextViewX); - pinnedCounterTextView.setAlpha(loadedPinnedMessagesCount == 2 || currentPinnedMessageIndex[0] == 0 ? 0.0f : 1.0f); + pinnedCounterTextView.setAlpha(shouldAnimateName || currentPinnedMessageIndex[0] == 0 ? 0.0f : 1.0f); messageTextView.setVisibility(View.VISIBLE); messageTextView.setAlpha(1.0f); @@ -19649,6 +19952,9 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not pinnedMessageTextView[1].setVisibility(View.INVISIBLE); pinnedMessageTextView[1].setTranslationX(0); pinnedMessageTextView[1].setTranslationY(0); + pinnedMessageButton[1].setVisibility(View.INVISIBLE); + pinnedMessageButton[1].setTranslationX(0); + pinnedMessageButton[1].setTranslationY(0); pinnedNameTextView[1].setVisibility(View.INVISIBLE); pinnedNameTextView[1].setTranslationX(0); pinnedNameTextView[1].setTranslationY(0); @@ -19690,6 +19996,32 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } } + private class TrackingWidthSimpleTextView extends SimpleTextView { + public TrackingWidthSimpleTextView(Context context) { + super(context); + } + + private boolean trackWidth = true; + public void setTrackWidth(boolean value) { + this.trackWidth = value; + } + public boolean getTrackWidth() { + return this.trackWidth; + } + + @Override + protected boolean createLayout(int width) { + boolean result = super.createLayout(width); + if (trackWidth && getVisibility() == View.VISIBLE && pinnedCounterTextView != null) { + int newX = getTextWidth() + AndroidUtilities.dp(4); + if (newX != pinnedCounterTextViewX) { + pinnedCounterTextView.setTranslationX(pinnedCounterTextViewX = newX); + } + } + return result; + } + } + private void updateTopPanel(boolean animated) { if (topChatPanelView == null || chatMode != 0 || inMenuMode) { return; @@ -20607,13 +20939,17 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } private void createDeleteMessagesAlert(final MessageObject finalSelectedObject, final MessageObject.GroupedMessages finalSelectedGroup, int loadParticipant) { + createDeleteMessagesAlert(finalSelectedObject, finalSelectedGroup, loadParticipant, false); + } + + private void createDeleteMessagesAlert(final MessageObject finalSelectedObject, final MessageObject.GroupedMessages finalSelectedGroup, int loadParticipant, boolean hideDimAfter) { if (finalSelectedObject == null && (selectedMessagesIds[0].size() + selectedMessagesIds[1].size()) == 0) { return; } AlertsCreator.createDeleteMessagesAlert(this, currentUser, currentChat, currentEncryptedChat, chatInfo, mergeDialogId, finalSelectedObject, selectedMessagesIds, finalSelectedGroup, chatMode == MODE_SCHEDULED, loadParticipant, () -> { hideActionMode(); updatePinnedMessageView(true); - }, () -> dimBehindView(false), themeDelegate); + }, hideDimAfter ? () -> dimBehindView(false) : null, themeDelegate); } private void hideActionMode() { @@ -20650,8 +20986,8 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not textSelectionHintWasShowed = false; } - private void createMenu(View v, boolean single, boolean listView, float x, float y) { - createMenu(v, single, listView, x, y, true); + private boolean createMenu(View v, boolean single, boolean listView, float x, float y) { + return createMenu(v, single, listView, x, y, true); } private CharSequence getMessageCaption(MessageObject messageObject, MessageObject.GroupedMessages group) { @@ -20692,9 +21028,9 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not "[\u231A\u231B\u2328\u23CF\u23E9-\u23F3\u23F8-\u23FA]\uFE0F?)+"); } @SuppressLint("ClickableViewAccessibility") - private void createMenu(View v, boolean single, boolean listView, float x, float y, boolean searchGroup) { + private boolean createMenu(View v, boolean single, boolean listView, float x, float y, boolean searchGroup) { if (actionBar.isActionModeShowed() || reportType >= 0) { - return; + return false; } MessageObject message; @@ -20710,7 +21046,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not message = null; } if (message == null) { - return; + return false; } final int type = getMessageType(message); if (single) { @@ -20720,12 +21056,8 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } else { Toast.makeText(getParentActivity(), LocaleController.getString("MessageNotFound", R.string.MessageNotFound), Toast.LENGTH_SHORT).show(); } - return; - } else if (message.messageOwner.action instanceof TLRPC.TL_messageActionSetMessagesTTL) { - if (avatarContainer.openSetTimer()) { - return; - } - } else if (message.messageOwner.action instanceof TLRPC.TL_messageActionPaymentSent && message.replyMessageObject != null && message.replyMessageObject.isInvoice()) { + return true; + } if (message.messageOwner.action instanceof TLRPC.TL_messageActionPaymentSent && message.replyMessageObject != null && message.replyMessageObject.isInvoice()) { TLRPC.TL_payments_getPaymentReceipt req = new TLRPC.TL_payments_getPaymentReceipt(); req.msg_id = message.getId(); req.peer = getMessagesController().getInputPeer(message.messageOwner.peer_id); @@ -20734,10 +21066,10 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not presentFragment(new PaymentFormActivity((TLRPC.TL_payments_paymentReceipt) response)); } }), ConnectionsManager.RequestFlagFailOnServerErrors); - return; + return true; } else if (message.messageOwner.action instanceof TLRPC.TL_messageActionGroupCall || message.messageOwner.action instanceof TLRPC.TL_messageActionInviteToGroupCall || message.messageOwner.action instanceof TLRPC.TL_messageActionGroupCallScheduled) { if (getParentActivity() == null) { - return; + return false; } VoIPService sharedInstance = VoIPService.getSharedInstance(); if (sharedInstance != null) { @@ -20753,25 +21085,25 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not createGroupCall = getGroupCall() == null; VoIPHelper.startCall(currentChat, null, null, createGroupCall, getParentActivity(), ChatActivity.this, getAccountInstance()); } - return; + return true; } else if (fragmentContextView != null && getGroupCall() != null) { if (VoIPService.getSharedInstance() != null) { GroupCallActivity.create((LaunchActivity) getParentActivity(), AccountInstance.getInstance(VoIPService.getSharedInstance().getAccount()), null, null, false, null); } else { ChatObject.Call call = getGroupCall(); if (call == null) { - return; + return false; } VoIPHelper.startCall(getMessagesController().getChat(call.chatId), null, null, false, getParentActivity(), ChatActivity.this, getAccountInstance()); } - return; + return true; } else if (ChatObject.canManageCalls(currentChat)) { VoIPHelper.showGroupCallAlert(ChatActivity.this, currentChat, null, true, getAccountInstance()); - return; + return true; } } else if (message.messageOwner.action instanceof TLRPC.TL_messageActionSetChatTheme) { showChatThemeBottomSheet(); - return; + return true; } } if (message.isSponsored() || threadMessageObjects != null && threadMessageObjects.contains(message)) { @@ -20843,14 +21175,34 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (single || type < 2 || type == 20) { if (getParentActivity() == null) { - return; + return false; } ArrayList icons = new ArrayList<>(); ArrayList items = new ArrayList<>(); final ArrayList options = new ArrayList<>(); + View optionsView = null; CharSequence messageText = null; - if (type >= 0 || type == -1 && single && (message.isSending() || message.isEditing()) && currentEncryptedChat == null) { + if (message.messageOwner.action instanceof TLRPC.TL_messageActionSetMessagesTTL && single && (dialog_id >= 0 || (currentChat != null && ChatObject.canUserDoAdminAction(currentChat, ChatObject.ACTION_DELETE_MESSAGES)))) { + AutoDeletePopupWrapper autoDeletePopupWrapper = new AutoDeletePopupWrapper(contentView.getContext(), null, new AutoDeletePopupWrapper.Callback() { + @Override + public void dismiss() { + if (scrimPopupWindow != null) { + scrimPopupWindow.dismiss(); + } + } + + @Override + public void setAutoDeleteHistory(int time, int action) { + getMessagesController().setDialogHistoryTTL(dialog_id, time); + if (userInfo != null || chatInfo != null) { + undoView.showWithAction(dialog_id, action, currentUser, userInfo != null ? userInfo.ttl_period : chatInfo.ttl_period, null, null); + } + } + }, true, getResourceProvider()); + autoDeletePopupWrapper.updateItems(userInfo != null ? userInfo.ttl_period : chatInfo.ttl_period); + optionsView = autoDeletePopupWrapper.windowLayout; + } else if (type >= 0 || type == -1 && single && (message.isSending() || message.isEditing()) && currentEncryptedChat == null) { selectedObject = message; selectedObjectGroup = groupedMessages; messageText = getMessageCaption(selectedObject, selectedObjectGroup); // used only in translations @@ -20867,8 +21219,9 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (messageText == null) messageText = getMessageContent(selectedObject, 0, false); if (messageText != null) { - if (isEmoji(messageText.toString())) + if (isEmoji(messageText.toString())) { messageText = null; // message fully consists of emojis, do not translate + } } if (type == -1) { @@ -20908,7 +21261,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not options.add(OPTION_PIN); icons.add(R.drawable.msg_pin); } - if (selectedObject != null && selectedObject.contentType == 0 && (messageText != null && messageText.length() > 0 && !selectedObject.isAnimatedEmoji() && !selectedObject.isDice()) && MessagesController.getGlobalMainSettings().getBoolean("translate_button", false)) { + if (selectedObject != null && selectedObject.contentType == 0 && (messageText != null && messageText.length() > 0 && !selectedObject.isAnimatedEmoji() && !selectedObject.isDice())) { items.add(LocaleController.getString("TranslateMessage", R.string.TranslateMessage)); options.add(29); icons.add(R.drawable.msg_translate); @@ -21167,7 +21520,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not options.add(13); icons.add(R.drawable.msg_pin); } - if (selectedObject != null && selectedObject.contentType == 0 && (messageText != null && messageText.length() > 0 && !selectedObject.isAnimatedEmoji() && !selectedObject.isDice()) && MessagesController.getGlobalMainSettings().getBoolean("translate_button", false)) { + if (selectedObject != null && selectedObject.contentType == 0 && (messageText != null && messageText.length() > 0 && !selectedObject.isAnimatedEmoji() && !selectedObject.isDice())) { items.add(LocaleController.getString("TranslateMessage", R.string.TranslateMessage)); options.add(29); icons.add(R.drawable.msg_translate); @@ -21286,15 +21639,15 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } } - if (options.isEmpty()) { - return; + if (options.isEmpty() && optionsView == null) { + return false; } if (scrimPopupWindow != null) { closeMenu(); menuDeleteItem = null; scrimPopupWindowItems = null; - return; + return false; } final AtomicBoolean waitForLangDetection = new AtomicBoolean(false); @@ -21328,427 +21681,461 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not Drawable shadowDrawable = getParentActivity().getResources().getDrawable(R.drawable.popup_fixed_alert).mutate(); shadowDrawable.getPadding(backgroundPaddings); popupLayout.setBackgroundColor(getThemedColor(Theme.key_actionBarDefaultSubmenuBackground)); + MessageSeenView messageSeenView = null; - if (isReactionsViewAvailable) { - ReactedHeaderView reactedView = new ReactedHeaderView(contentView.getContext(), currentAccount, message, dialog_id); + boolean addGap = false; - int count = 0; - if (message.messageOwner.reactions != null) { - for (TLRPC.TL_reactionCount r : message.messageOwner.reactions.results) { - count += r.count; - } - } - boolean hasHeader = count > 10 && message.messageOwner.reactions.results.size() > 1; - LinearLayout linearLayout = new LinearLayout(contentView.getContext()) { - @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - int size = MeasureSpec.getSize(widthMeasureSpec); - if (size < AndroidUtilities.dp(240)) { - size = AndroidUtilities.dp(240); + if (optionsView == null) { + if (isReactionsViewAvailable) { + ReactedHeaderView reactedView = new ReactedHeaderView(contentView.getContext(), currentAccount, message, dialog_id); + + int count = 0; + if (message.messageOwner.reactions != null) { + for (TLRPC.TL_reactionCount r : message.messageOwner.reactions.results) { + count += r.count; } - if (size < 0) { - size = 0; - } - super.onMeasure(MeasureSpec.makeMeasureSpec(size, MeasureSpec.EXACTLY), heightMeasureSpec); } - }; - linearLayout.setOrientation(LinearLayout.VERTICAL); - linearLayout.setLayoutParams(new FrameLayout.LayoutParams(AndroidUtilities.dp(200), AndroidUtilities.dp(6 * 48 + (hasHeader ? 44 * 2 + 8 : 44)) + (!hasHeader ? 1 : 0))); - ActionBarMenuSubItem backCell = new ActionBarMenuSubItem(getParentActivity(), true, false, themeDelegate); - backCell.setItemHeight(44); - backCell.setTextAndIcon(LocaleController.getString("Back", R.string.Back), R.drawable.msg_arrow_back); - backCell.getTextView().setPadding(LocaleController.isRTL ? 0 : AndroidUtilities.dp(40), 0, LocaleController.isRTL ? AndroidUtilities.dp(40) : 0, 0); - backCell.setOnClickListener(v1 -> popupLayout.getSwipeBack().closeForeground()); - linearLayout.addView(backCell, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); - - int[] foregroundIndex = new int[1]; - - if (hasHeader) { - List counters = message.messageOwner.reactions.results; - LinearLayout tabsView = new LinearLayout(contentView.getContext()); - tabsView.setOrientation(LinearLayout.HORIZONTAL); - ViewPager pager = new ViewPager(contentView.getContext()); - HorizontalScrollView tabsScrollView = new HorizontalScrollView(contentView.getContext()); - - AtomicBoolean suppressTabsScroll = new AtomicBoolean(); - boolean showAllReactionsTab = counters.size() > 1; - int size = counters.size() + (showAllReactionsTab ? 1 : 0); - for (int i = 0; i < size; i++) { - ReactionTabHolderView hv = new ReactionTabHolderView(contentView.getContext()); - int index = i; - if (showAllReactionsTab) { - index--; - } - if (index < 0) { - hv.setCounter(count); - } else { - hv.setCounter(currentAccount, counters.get(index)); - } - int finalI = i; - hv.setOnClickListener(v1 -> { - int from = pager.getCurrentItem(); - if (finalI == from) return; - - ReactionTabHolderView fv = (ReactionTabHolderView) tabsView.getChildAt(from); - suppressTabsScroll.set(true); - pager.setCurrentItem(finalI, true); - float fSX = tabsScrollView.getScrollX(), tSX = hv.getX() - (tabsScrollView.getWidth() - hv.getWidth()) / 2f; - ValueAnimator a = ValueAnimator.ofFloat(0, 1).setDuration(150); - a.setInterpolator(CubicBezierInterpolator.DEFAULT); - a.addUpdateListener(animation -> { - float f = (float) animation.getAnimatedValue(); - tabsScrollView.setScrollX((int) (fSX + (tSX - fSX) * f)); - fv.setOutlineProgress(1f - f); - hv.setOutlineProgress(f); - }); - a.start(); - }); - tabsView.addView(hv, LayoutHelper.createFrameRelatively(LayoutHelper.WRAP_CONTENT, LayoutHelper.MATCH_PARENT, Gravity.CENTER_VERTICAL, i == 0 ? 6 : 0, 6, 6, 6)); - } - tabsScrollView.setHorizontalScrollBarEnabled(false); - tabsScrollView.addView(tabsView); - linearLayout.addView(tabsScrollView, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 44)); - - View divider = new FrameLayout(contentView.getContext()); - divider.setBackgroundColor(Theme.getColor(Theme.key_graySection)); - linearLayout.addView(divider, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, (int) Theme.dividerPaint.getStrokeWidth())); - - int head = AndroidUtilities.dp(44 * 2) + 1; - SparseArray cachedViews = new SparseArray<>(); - SparseIntArray cachedHeights = new SparseIntArray(); - for (int i = 0; i < counters.size() + 1; i++) { - cachedHeights.put(i, head + AndroidUtilities.dp(ReactedUsersListView.ITEM_HEIGHT_DP * ReactedUsersListView.VISIBLE_ITEMS)); - } - pager.setAdapter(new PagerAdapter() { + boolean hasHeader = count > 10 && message.messageOwner.reactions.results.size() > 1; + LinearLayout linearLayout = new LinearLayout(contentView.getContext()) { @Override - public int getCount() { - return size; - } - - @Override - public boolean isViewFromObject(View view, Object object) { - return view == object; - } - - @Override - public Object instantiateItem(ViewGroup container, int position) { - View cached = cachedViews.get(position); - if (cached != null) { - container.addView(cached); - return cached; + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + int size = MeasureSpec.getSize(widthMeasureSpec); + if (size < AndroidUtilities.dp(240)) { + size = AndroidUtilities.dp(240); } - int index = position; + if (size < 0) { + size = 0; + } + super.onMeasure(MeasureSpec.makeMeasureSpec(size, MeasureSpec.EXACTLY), heightMeasureSpec); + } + }; + linearLayout.setOrientation(LinearLayout.VERTICAL); + linearLayout.setLayoutParams(new FrameLayout.LayoutParams(AndroidUtilities.dp(200), AndroidUtilities.dp(6 * 48 + (hasHeader ? 44 * 2 + 8 : 44)) + (!hasHeader ? 1 : 0))); + ActionBarMenuSubItem backCell = new ActionBarMenuSubItem(getParentActivity(), true, false, themeDelegate); + backCell.setItemHeight(44); + backCell.setTextAndIcon(LocaleController.getString("Back", R.string.Back), R.drawable.msg_arrow_back); + backCell.getTextView().setPadding(LocaleController.isRTL ? 0 : AndroidUtilities.dp(40), 0, LocaleController.isRTL ? AndroidUtilities.dp(40) : 0, 0); + backCell.setOnClickListener(v1 -> popupLayout.getSwipeBack().closeForeground()); + linearLayout.addView(backCell, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); + + int[] foregroundIndex = new int[1]; + + if (hasHeader) { + List counters = message.messageOwner.reactions.results; + LinearLayout tabsView = new LinearLayout(contentView.getContext()); + tabsView.setOrientation(LinearLayout.HORIZONTAL); + ViewPager pager = new ViewPager(contentView.getContext()); + HorizontalScrollView tabsScrollView = new HorizontalScrollView(contentView.getContext()); + + AtomicBoolean suppressTabsScroll = new AtomicBoolean(); + boolean showAllReactionsTab = counters.size() > 1; + int size = counters.size() + (showAllReactionsTab ? 1 : 0); + for (int i = 0; i < size; i++) { + ReactionTabHolderView hv = new ReactionTabHolderView(contentView.getContext()); + int index = i; if (showAllReactionsTab) { index--; } - TLRPC.TL_reactionCount reactionCount = null; - if (index >= 0) { - reactionCount = counters.get(index); - } - ReactedUsersListView v = new ReactedUsersListView(container.getContext(), themeDelegate, currentAccount, message, reactionCount, true) - .setSeenUsers(reactedView.getSeenUsers()) - .setOnProfileSelectedListener((view, userId) -> { - Bundle args = new Bundle(); - args.putLong("user_id", userId); - ProfileActivity fragment = new ProfileActivity(args); - presentFragment(fragment); - closeMenu(); - }).setOnHeightChangedListener((view, newHeight) -> { - cachedHeights.put(position, head + newHeight); - if (pager.getCurrentItem() == position) - popupLayout.getSwipeBack().setNewForegroundHeight(foregroundIndex[0], head + newHeight); - }); if (index < 0) { - reactedView.setSeenCallback(v::setSeenUsers); + hv.setCounter(count); + } else { + hv.setCounter(currentAccount, counters.get(index)); + } + int finalI = i; + hv.setOnClickListener(v1 -> { + int from = pager.getCurrentItem(); + if (finalI == from) return; + + ReactionTabHolderView fv = (ReactionTabHolderView) tabsView.getChildAt(from); + suppressTabsScroll.set(true); + pager.setCurrentItem(finalI, true); + float fSX = tabsScrollView.getScrollX(), tSX = hv.getX() - (tabsScrollView.getWidth() - hv.getWidth()) / 2f; + ValueAnimator a = ValueAnimator.ofFloat(0, 1).setDuration(150); + a.setInterpolator(CubicBezierInterpolator.DEFAULT); + a.addUpdateListener(animation -> { + float f = (float) animation.getAnimatedValue(); + tabsScrollView.setScrollX((int) (fSX + (tSX - fSX) * f)); + fv.setOutlineProgress(1f - f); + hv.setOutlineProgress(f); + }); + a.start(); + }); + tabsView.addView(hv, LayoutHelper.createFrameRelatively(LayoutHelper.WRAP_CONTENT, LayoutHelper.MATCH_PARENT, Gravity.CENTER_VERTICAL, i == 0 ? 6 : 0, 6, 6, 6)); + } + tabsScrollView.setHorizontalScrollBarEnabled(false); + tabsScrollView.addView(tabsView); + linearLayout.addView(tabsScrollView, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 44)); + + View divider = new FrameLayout(contentView.getContext()); + divider.setBackgroundColor(Theme.getColor(Theme.key_graySection)); + linearLayout.addView(divider, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, (int) Theme.dividerPaint.getStrokeWidth())); + + int head = AndroidUtilities.dp(44 * 2) + 1; + SparseArray cachedViews = new SparseArray<>(); + SparseIntArray cachedHeights = new SparseIntArray(); + for (int i = 0; i < counters.size() + 1; i++) { + cachedHeights.put(i, head + AndroidUtilities.dp(ReactedUsersListView.ITEM_HEIGHT_DP * ReactedUsersListView.VISIBLE_ITEMS)); + } + pager.setAdapter(new PagerAdapter() { + @Override + public int getCount() { + return size; } - container.addView(v); - cachedViews.put(position, v); - return v; - } + @Override + public boolean isViewFromObject(View view, Object object) { + return view == object; + } - @Override - public void destroyItem(ViewGroup container, int position, Object object) { - container.removeView((View) object); - } - }); - pager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() { - @Override - public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { - if (!suppressTabsScroll.get()) { - float fX = -1, tX = -1; - for (int i = 0; i < tabsView.getChildCount(); i++) { - ReactionTabHolderView ch = (ReactionTabHolderView) tabsView.getChildAt(i); - ch.setOutlineProgress(i == position ? 1f - positionOffset : i == (position + 1) % size ? positionOffset : 0); - if (i == position) { - fX = ch.getX() - (tabsScrollView.getWidth() - ch.getWidth()) / 2f; - } - if (i == position + 1) { - tX = ch.getX() - (tabsScrollView.getWidth() - ch.getWidth()) / 2f; - } + @Override + public Object instantiateItem(ViewGroup container, int position) { + View cached = cachedViews.get(position); + if (cached != null) { + container.addView(cached); + return cached; + } + int index = position; + if (showAllReactionsTab) { + index--; + } + TLRPC.TL_reactionCount reactionCount = null; + if (index >= 0) { + reactionCount = counters.get(index); + } + ReactedUsersListView v = new ReactedUsersListView(container.getContext(), themeDelegate, currentAccount, message, reactionCount, true) + .setSeenUsers(reactedView.getSeenUsers()) + .setOnProfileSelectedListener((view, userId) -> { + Bundle args = new Bundle(); + args.putLong("user_id", userId); + ProfileActivity fragment = new ProfileActivity(args); + presentFragment(fragment); + closeMenu(); + }).setOnHeightChangedListener((view, newHeight) -> { + cachedHeights.put(position, head + newHeight); + if (pager.getCurrentItem() == position) + popupLayout.getSwipeBack().setNewForegroundHeight(foregroundIndex[0], head + newHeight); + }); + if (index < 0) { + reactedView.setSeenCallback(v::setSeenUsers); } - if (fX != -1 && tX != -1) - tabsScrollView.setScrollX((int) (fX + (tX - fX) * positionOffset)); + container.addView(v); + cachedViews.put(position, v); + return v; } - } - @Override - public void onPageSelected(int position) { - int h = cachedHeights.get(position); - popupLayout.getSwipeBack().setNewForegroundHeight(foregroundIndex[0], h); - } - - @Override - public void onPageScrollStateChanged(int state) { - if (state == ViewPager.SCROLL_STATE_IDLE) { - suppressTabsScroll.set(false); + @Override + public void destroyItem(ViewGroup container, int position, Object object) { + container.removeView((View) object); } + }); + pager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() { + @Override + public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { + if (!suppressTabsScroll.get()) { + float fX = -1, tX = -1; + for (int i = 0; i < tabsView.getChildCount(); i++) { + ReactionTabHolderView ch = (ReactionTabHolderView) tabsView.getChildAt(i); + ch.setOutlineProgress(i == position ? 1f - positionOffset : i == (position + 1) % size ? positionOffset : 0); + if (i == position) { + fX = ch.getX() - (tabsScrollView.getWidth() - ch.getWidth()) / 2f; + } + if (i == position + 1) { + tX = ch.getX() - (tabsScrollView.getWidth() - ch.getWidth()) / 2f; + } + } + + if (fX != -1 && tX != -1) + tabsScrollView.setScrollX((int) (fX + (tX - fX) * positionOffset)); + } + } + + @Override + public void onPageSelected(int position) { + int h = cachedHeights.get(position); + popupLayout.getSwipeBack().setNewForegroundHeight(foregroundIndex[0], h); + } + + @Override + public void onPageScrollStateChanged(int state) { + if (state == ViewPager.SCROLL_STATE_IDLE) { + suppressTabsScroll.set(false); + } + } + }); + linearLayout.addView(pager, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 0, 1f)); + } else { + View gap = new FrameLayout(contentView.getContext()); + gap.setBackgroundColor(Theme.getColor(Theme.key_graySection)); + linearLayout.addView(gap, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 8)); + + ReactedUsersListView lv = new ReactedUsersListView(contentView.getContext(), themeDelegate, currentAccount, message, null, true) + .setSeenUsers(reactedView.getSeenUsers()) + .setOnProfileSelectedListener((view, userId) -> { + Bundle args = new Bundle(); + args.putLong("user_id", userId); + ProfileActivity fragment = new ProfileActivity(args); + presentFragment(fragment); + closeMenu(); + }).setOnHeightChangedListener((view, newHeight) -> popupLayout.getSwipeBack().setNewForegroundHeight(foregroundIndex[0], AndroidUtilities.dp(44 + 8) + newHeight)); + reactedView.setSeenCallback(lv::setSeenUsers); + linearLayout.addView(lv, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 0, 1f)); + } + + foregroundIndex[0] = popupLayout.addViewToSwipeBack(linearLayout); + + reactedView.setOnClickListener(v1 -> { + popupLayout.getSwipeBack().openForeground(foregroundIndex[0]); + }); + popupLayout.addView(reactedView, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 48)); + addGap = true; + } + + if (showMessageSeen) { + messageSeenView = new MessageSeenView(contentView.getContext(), currentAccount, message, currentChat); + FrameLayout messageSeenLayout = new FrameLayout(contentView.getContext()); + messageSeenLayout.addView(messageSeenView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); + MessageSeenView finalMessageSeenView = messageSeenView; + + ActionBarMenuSubItem cell = new ActionBarMenuSubItem(getParentActivity(), true, true, themeDelegate); + cell.setItemHeight(44); + cell.setTextAndIcon(LocaleController.getString("Back", R.string.Back), R.drawable.msg_arrow_back); + cell.getTextView().setPadding(LocaleController.isRTL ? 0 : AndroidUtilities.dp(40), 0, LocaleController.isRTL ? AndroidUtilities.dp(40) : 0, 0); + + FrameLayout backContainer = new FrameLayout(contentView.getContext()); + + LinearLayout linearLayout = new LinearLayout(contentView.getContext()); + linearLayout.setBackgroundColor(getThemedColor(Theme.key_actionBarDefaultSubmenuBackground)); + linearLayout.setOrientation(LinearLayout.VERTICAL); + RecyclerListView listView2 = finalMessageSeenView.createListView(); + backContainer.addView(cell); + linearLayout.addView(backContainer); + backContainer.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + popupLayout.getSwipeBack().closeForeground(); } }); - linearLayout.addView(pager, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 0, 1f)); - } else { - View gap = new FrameLayout(contentView.getContext()); - gap.setBackgroundColor(Theme.getColor(Theme.key_graySection)); - linearLayout.addView(gap, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 8)); - ReactedUsersListView lv = new ReactedUsersListView(contentView.getContext(), themeDelegate, currentAccount, message, null, true) - .setSeenUsers(reactedView.getSeenUsers()) - .setOnProfileSelectedListener((view, userId) -> { + int[] foregroundIndex = new int[1]; + messageSeenView.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + if (scrimPopupWindow == null || finalMessageSeenView.users.isEmpty()) { + return; + } + if (finalMessageSeenView.users.size() == 1) { + TLRPC.User user = finalMessageSeenView.users.get(0); + if (user == null) { + return; + } Bundle args = new Bundle(); - args.putLong("user_id", userId); + args.putLong("user_id", user.id); ProfileActivity fragment = new ProfileActivity(args); presentFragment(fragment); closeMenu(); - }).setOnHeightChangedListener((view, newHeight) -> popupLayout.getSwipeBack().setNewForegroundHeight(foregroundIndex[0], AndroidUtilities.dp(44 + 8) + newHeight)); - reactedView.setSeenCallback(lv::setSeenUsers); - linearLayout.addView(lv, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 0, 1f)); - } - - foregroundIndex[0] = popupLayout.addViewToSwipeBack(linearLayout); - - reactedView.setOnClickListener(v1 -> { - popupLayout.getSwipeBack().openForeground(foregroundIndex[0]); - }); - popupLayout.addView(reactedView, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 48)); - - View gap = new FrameLayout(contentView.getContext()); - gap.setBackgroundColor(Theme.getColor(Theme.key_graySection)); - popupLayout.addView(gap, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 8)); - } - - MessageSeenView messageSeenView = null; - if (showMessageSeen) { - messageSeenView = new MessageSeenView(contentView.getContext(), currentAccount, message, currentChat); - FrameLayout messageSeenLayout = new FrameLayout(contentView.getContext()); - messageSeenLayout.addView(messageSeenView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); - MessageSeenView finalMessageSeenView = messageSeenView; - - ActionBarMenuSubItem cell = new ActionBarMenuSubItem(getParentActivity(), true, true, themeDelegate); - cell.setItemHeight(44); - cell.setTextAndIcon(LocaleController.getString("Back", R.string.Back), R.drawable.msg_arrow_back); - cell.getTextView().setPadding(LocaleController.isRTL ? 0 : AndroidUtilities.dp(40), 0, LocaleController.isRTL ? AndroidUtilities.dp(40) : 0, 0); - - FrameLayout backContainer = new FrameLayout(contentView.getContext()); - - LinearLayout linearLayout = new LinearLayout(contentView.getContext()); - linearLayout.setBackgroundColor(getThemedColor(Theme.key_actionBarDefaultSubmenuBackground)); - linearLayout.setOrientation(LinearLayout.VERTICAL); - RecyclerListView listView2 = finalMessageSeenView.createListView(); - backContainer.addView(cell); - linearLayout.addView(backContainer); - backContainer.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View view) { - popupLayout.getSwipeBack().closeForeground(); - } - }); - - int[] foregroundIndex = new int[1]; - messageSeenView.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View view) { - if (scrimPopupWindow == null || finalMessageSeenView.users.isEmpty()) { - return; - } - if (finalMessageSeenView.users.size() == 1) { - TLRPC.User user = finalMessageSeenView.users.get(0); - if (user == null) { return; } - Bundle args = new Bundle(); - args.putLong("user_id", user.id); - ProfileActivity fragment = new ProfileActivity(args); - presentFragment(fragment); - closeMenu(); - return; - } - int totalHeight = contentView.getHeightWithKeyboard(); - int availableHeight = totalHeight - scrimPopupY - AndroidUtilities.dp(46 + 16) - (isReactionsAvailable ? AndroidUtilities.dp(52) : 0); + int totalHeight = contentView.getHeightWithKeyboard(); + int availableHeight = totalHeight - scrimPopupY - AndroidUtilities.dp(46 + 16) - (isReactionsAvailable ? AndroidUtilities.dp(52) : 0); - if (SharedConfig.messageSeenHintCount > 0 && contentView.getKeyboardHeight() < AndroidUtilities.dp(20)) { - availableHeight -= AndroidUtilities.dp(52); - Bulletin bulletin = BulletinFactory.of(ChatActivity.this).createErrorBulletin(AndroidUtilities.replaceTags(LocaleController.getString("MessageSeenTooltipMessage", R.string.MessageSeenTooltipMessage))); - bulletin.tag = 1; - bulletin.setDuration(4000); - bulletin.show(); - SharedConfig.updateMessageSeenHintCount(SharedConfig.messageSeenHintCount - 1); - } else if (contentView.getKeyboardHeight() > AndroidUtilities.dp(20)) { - availableHeight -=contentView.getKeyboardHeight() / 3f; - } - - int listViewTotalHeight = AndroidUtilities.dp(8) + AndroidUtilities.dp(44) * listView2.getAdapter().getItemCount(); - - if (listViewTotalHeight > availableHeight) { - if (availableHeight > AndroidUtilities.dp(620)) { - listView2.getLayoutParams().height = AndroidUtilities.dp(620); - } else { - listView2.getLayoutParams().height = availableHeight; + if (SharedConfig.messageSeenHintCount > 0 && contentView.getKeyboardHeight() < AndroidUtilities.dp(20)) { + availableHeight -= AndroidUtilities.dp(52); + Bulletin bulletin = BulletinFactory.of(ChatActivity.this).createErrorBulletin(AndroidUtilities.replaceTags(LocaleController.getString("MessageSeenTooltipMessage", R.string.MessageSeenTooltipMessage))); + bulletin.tag = 1; + bulletin.setDuration(4000); + bulletin.show(); + SharedConfig.updateMessageSeenHintCount(SharedConfig.messageSeenHintCount - 1); + } else if (contentView.getKeyboardHeight() > AndroidUtilities.dp(20)) { + availableHeight -= contentView.getKeyboardHeight() / 3f; } - } else { - listView2.getLayoutParams().height = listViewTotalHeight; + + int listViewTotalHeight = AndroidUtilities.dp(8) + AndroidUtilities.dp(44) * listView2.getAdapter().getItemCount(); + + if (listViewTotalHeight > availableHeight) { + if (availableHeight > AndroidUtilities.dp(620)) { + listView2.getLayoutParams().height = AndroidUtilities.dp(620); + } else { + listView2.getLayoutParams().height = availableHeight; + } + } else { + listView2.getLayoutParams().height = listViewTotalHeight; + } + linearLayout.getLayoutParams().height = AndroidUtilities.dp(44) + listView2.getLayoutParams().height; + listView2.requestLayout(); + linearLayout.requestLayout(); + listView2.getAdapter().notifyDataSetChanged(); + popupLayout.getSwipeBack().openForeground(foregroundIndex[0]); } - linearLayout.getLayoutParams().height = AndroidUtilities.dp(44) + listView2.getLayoutParams().height; - listView2.requestLayout(); - linearLayout.requestLayout(); - listView2.getAdapter().notifyDataSetChanged(); - popupLayout.getSwipeBack().openForeground(foregroundIndex[0]); - } - }); - linearLayout.addView(listView2, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 320)); + }); + linearLayout.addView(listView2, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 320)); - listView2.setOnItemClickListener((view1, position) -> { - TLRPC.User user = finalMessageSeenView.users.get(position); - if (user == null) { - return; - } - Bundle args = new Bundle(); - args.putLong("user_id", user.id); - ProfileActivity fragment = new ProfileActivity(args); - presentFragment(fragment); - }); - - foregroundIndex[0] = popupLayout.addViewToSwipeBack(linearLayout); - - popupLayout.addView(messageSeenLayout, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 44)); - - View gap = new FrameLayout(contentView.getContext()); - gap.setBackgroundColor(Theme.getColor(Theme.key_graySection)); - popupLayout.addView(gap, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 8)); - } - - if (popupLayout.getSwipeBack() != null) { - popupLayout.getSwipeBack().setOnClickListener(e -> closeMenu()); - } - - scrimPopupWindowItems = new ActionBarMenuSubItem[items.size() + (selectedObject.isSponsored() ? 1 : 0)]; - for (int a = 0, N = items.size(); a < N; a++) { - if (a == 0 && selectedObject.isSponsored()) { - ActionBarMenuSubItem cell = new ActionBarMenuSubItem(getParentActivity(), true, true, themeDelegate); - cell.setTextAndIcon(LocaleController.getString("SponsoredMessageInfo", R.string.SponsoredMessageInfo), R.drawable.menu_info); - cell.setItemHeight(56); - cell.setTag(R.id.width_tag, 240); - cell.setMultiline(); - scrimPopupWindowItems[scrimPopupWindowItems.length - 1] = cell; - popupLayout.addView(cell); - cell.setOnClickListener(v1 -> { - if (contentView == null || getParentActivity() == null) { + listView2.setOnItemClickListener((view1, position) -> { + TLRPC.User user = finalMessageSeenView.users.get(position); + if (user == null) { return; } - BottomSheet.Builder builder = new BottomSheet.Builder(contentView.getContext()); - builder.setCustomView(new SponsoredMessageInfoView(getParentActivity(), themeDelegate)); - builder.show(); + Bundle args = new Bundle(); + args.putLong("user_id", user.id); + ProfileActivity fragment = new ProfileActivity(args); + presentFragment(fragment); }); - View gap = new View(getParentActivity()); - gap.setMinimumWidth(AndroidUtilities.dp(196)); - gap.setTag(1000); - gap.setTag(R.id.object_tag, 1); - popupLayout.addView(gap); - LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams) cell.getLayoutParams(); - if (LocaleController.isRTL) { - layoutParams.gravity = Gravity.RIGHT; - } - layoutParams.width = LayoutHelper.MATCH_PARENT; - layoutParams.height = AndroidUtilities.dp(6); - gap.setLayoutParams(layoutParams); + foregroundIndex[0] = popupLayout.addViewToSwipeBack(linearLayout); + + popupLayout.addView(messageSeenLayout, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 44)); + addGap = true; } - ActionBarMenuSubItem cell = new ActionBarMenuSubItem(getParentActivity(), a == 0, a == N - 1, themeDelegate); - cell.setMinimumWidth(AndroidUtilities.dp(200)); - cell.setTextAndIcon(items.get(a), icons.get(a)); - Integer option = options.get(a); - if (option == 1 && selectedObject.messageOwner.ttl_period != 0) { - menuDeleteItem = cell; - updateDeleteItemRunnable.run(); - cell.setSubtextColor(getThemedColor(Theme.key_windowBackgroundWhiteGrayText6)); + + if (message.probablyRingtone()) { + ActionBarMenuSubItem cell = new ActionBarMenuSubItem(getParentActivity(), true, false, themeDelegate); + cell.setMinimumWidth(AndroidUtilities.dp(200)); + cell.setTextAndIcon(LocaleController.getString("SaveForNotifications", R.string.SaveForNotifications), R.drawable.msg_tone_add); + popupLayout.addView(cell); + cell.setOnClickListener(v1 -> { + if (getMediaDataController().saveToRingtones(message.getDocument())) { + getUndoView().showWithAction(dialog_id, UndoView.ACTION_RINGTONE_ADDED, new Runnable() { + boolean clicked; + + @Override + public void run() { + if (clicked || dialog_id == 0 || getUserConfig().clientUserId == dialog_id) { + return; + } + clicked = true; + presentFragment(new NotificationsSettingsActivity()); + } + }); + } + closeMenu(true); + }); + addGap = true; } - scrimPopupWindowItems[a] = cell; - popupLayout.addView(cell); - final int i = a; - cell.setOnClickListener(v1 -> { - if (selectedObject == null || i >= options.size()) { - return; - } - processSelectedOption(options.get(i)); - }); - if (option == 29) { // "Translate" button - String toLang = LocaleController.getInstance().getCurrentLocale().getLanguage(); - final CharSequence finalMessageText = messageText; - TranslateAlert.OnLinkPress onLinkPress = (link) -> { - didPressMessageUrl(link, false, selectedObject, v instanceof ChatMessageCell ? (ChatMessageCell) v : null); - }; - TLRPC.InputPeer inputPeer = getMessagesController().getInputPeer(dialog_id); - int messageId = selectedObject.messageOwner.id; - if (LanguageDetector.hasSupport()) { - final String[] fromLang = { null }; - cell.setVisibility(View.GONE); - waitForLangDetection.set(true); - LanguageDetector.detectLanguage( - finalMessageText.toString(), - (String lang) -> { - fromLang[0] = lang; - if (fromLang[0] != null && (!fromLang[0].equals(toLang) || fromLang[0].equals("und")) && - !RestrictedLanguagesSelectActivity.getRestrictedLanguages().contains(fromLang[0])) { - cell.setVisibility(View.VISIBLE); - } - waitForLangDetection.set(false); - if (onLangDetectionDone.get() != null) { - onLangDetectionDone.get().run(); - onLangDetectionDone.set(null); - } - }, - (Exception e) -> { - FileLog.e("mlkit: failed to detect language in message"); - waitForLangDetection.set(false); - if (onLangDetectionDone.get() != null) { - onLangDetectionDone.get().run(); - onLangDetectionDone.set(null); - } - } - ); - cell.setOnClickListener(e -> { - if (selectedObject == null || i >= options.size() || getParentActivity() == null) { + + if (addGap) { + View gap = new FrameLayout(contentView.getContext()); + gap.setBackgroundColor(Theme.getColor(Theme.key_graySection)); + popupLayout.addView(gap, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 8)); + } + + if (popupLayout.getSwipeBack() != null) { + popupLayout.getSwipeBack().setOnClickListener(e -> closeMenu()); + } + + final boolean translateButtonEnabled = MessagesController.getGlobalMainSettings().getBoolean("translate_button", false); + scrimPopupWindowItems = new ActionBarMenuSubItem[items.size() + (selectedObject.isSponsored() ? 1 : 0)]; + for (int a = 0, N = items.size(); a < N; a++) { + if (a == 0 && selectedObject.isSponsored()) { + ActionBarMenuSubItem cell = new ActionBarMenuSubItem(getParentActivity(), true, true, themeDelegate); + cell.setTextAndIcon(LocaleController.getString("SponsoredMessageInfo", R.string.SponsoredMessageInfo), R.drawable.menu_info); + cell.setItemHeight(56); + cell.setTag(R.id.width_tag, 240); + cell.setMultiline(); + scrimPopupWindowItems[scrimPopupWindowItems.length - 1] = cell; + popupLayout.addView(cell); + cell.setOnClickListener(v1 -> { + if (contentView == null || getParentActivity() == null) { return; } - TranslateAlert alert = TranslateAlert.showAlert(getParentActivity(), this, currentAccount, inputPeer, messageId, fromLang[0], toLang, finalMessageText, noforwards, onLinkPress, () -> dimBehindView(false)); - alert.showDim(false); - closeMenu(false); - }); - cell.postDelayed(() -> { - if (onLangDetectionDone.get() != null) { - onLangDetectionDone.getAndSet(null).run(); - } - }, 250); - } else { - cell.setOnClickListener(e -> { - if (selectedObject == null || i >= options.size() || getParentActivity() == null) { - return; - } - TranslateAlert alert = TranslateAlert.showAlert(getParentActivity(), this, currentAccount, inputPeer, messageId, "und", toLang, finalMessageText, noforwards, onLinkPress, () -> dimBehindView(false)); - alert.showDim(false); - closeMenu(false); + BottomSheet.Builder builder = new BottomSheet.Builder(contentView.getContext()); + builder.setCustomView(new SponsoredMessageInfoView(getParentActivity(), themeDelegate)); + builder.show(); }); + + View gap = new View(getParentActivity()); + gap.setMinimumWidth(AndroidUtilities.dp(196)); + gap.setTag(1000); + gap.setTag(R.id.object_tag, 1); + popupLayout.addView(gap); + LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams) cell.getLayoutParams(); + if (LocaleController.isRTL) { + layoutParams.gravity = Gravity.RIGHT; + } + layoutParams.width = LayoutHelper.MATCH_PARENT; + layoutParams.height = AndroidUtilities.dp(6); + gap.setLayoutParams(layoutParams); + } + ActionBarMenuSubItem cell = new ActionBarMenuSubItem(getParentActivity(), a == 0, a == N - 1, themeDelegate); + cell.setMinimumWidth(AndroidUtilities.dp(200)); + cell.setTextAndIcon(items.get(a), icons.get(a)); + Integer option = options.get(a); + if (option == 1 && selectedObject.messageOwner.ttl_period != 0) { + menuDeleteItem = cell; + updateDeleteItemRunnable.run(); + cell.setSubtextColor(getThemedColor(Theme.key_windowBackgroundWhiteGrayText6)); + } + scrimPopupWindowItems[a] = cell; + popupLayout.addView(cell); + final int i = a; + cell.setOnClickListener(v1 -> { + if (selectedObject == null || i >= options.size()) { + return; + } + processSelectedOption(options.get(i)); + }); + if (option == 29) { // "Translate" button + String toLang = LocaleController.getInstance().getCurrentLocale().getLanguage(); + final CharSequence finalMessageText = messageText; + TranslateAlert.OnLinkPress onLinkPress = (link) -> { + didPressMessageUrl(link, false, selectedObject, v instanceof ChatMessageCell ? (ChatMessageCell) v : null); + }; + TLRPC.InputPeer inputPeer = getMessagesController().getInputPeer(dialog_id); + int messageId = selectedObject.messageOwner.id; + if (LanguageDetector.hasSupport()) { + final String[] fromLang = {null}; + cell.setVisibility(View.GONE); + waitForLangDetection.set(true); + LanguageDetector.detectLanguage( + finalMessageText.toString(), + (String lang) -> { + fromLang[0] = lang; + if (fromLang[0] != null && (!fromLang[0].equals(toLang) || fromLang[0].equals("und")) && ( + translateButtonEnabled && !RestrictedLanguagesSelectActivity.getRestrictedLanguages().contains(fromLang[0]) || + (currentChat != null && (currentChat.has_link || currentChat.username != null)) && ("uk".equals(fromLang[0]) || "ru".equals(fromLang[0])) + )) { + cell.setVisibility(View.VISIBLE); + } + waitForLangDetection.set(false); + if (onLangDetectionDone.get() != null) { + onLangDetectionDone.get().run(); + onLangDetectionDone.set(null); + } + }, + (Exception e) -> { + FileLog.e("mlkit: failed to detect language in message"); + waitForLangDetection.set(false); + if (onLangDetectionDone.get() != null) { + onLangDetectionDone.get().run(); + onLangDetectionDone.set(null); + } + } + ); + cell.setOnClickListener(e -> { + if (selectedObject == null || i >= options.size() || getParentActivity() == null) { + return; + } + TranslateAlert alert = TranslateAlert.showAlert(getParentActivity(), this, currentAccount, inputPeer, messageId, fromLang[0], toLang, finalMessageText, noforwards, onLinkPress, () -> dimBehindView(false)); + alert.showDim(false); + closeMenu(false); + }); + cell.postDelayed(() -> { + if (onLangDetectionDone.get() != null) { + onLangDetectionDone.getAndSet(null).run(); + } + }, 250); + } else if (translateButtonEnabled) { + cell.setOnClickListener(e -> { + if (selectedObject == null || i >= options.size() || getParentActivity() == null) { + return; + } + TranslateAlert alert = TranslateAlert.showAlert(getParentActivity(), this, currentAccount, inputPeer, messageId, "und", toLang, finalMessageText, noforwards, onLinkPress, () -> dimBehindView(false)); + alert.showDim(false); + closeMenu(false); + }); + } else { + cell.setVisibility(View.GONE); + } } } } @@ -21793,58 +22180,64 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } }); - ReactionsContainerLayout reactionsLayout = new ReactionsContainerLayout(contentView.getContext(), currentAccount, getResourceProvider()); - if (isReactionsAvailable) { - int pad = 22; - int sPad = 24; - reactionsLayout.setPadding(AndroidUtilities.dp(4) + (LocaleController.isRTL ? 0 : sPad), AndroidUtilities.dp(4), AndroidUtilities.dp(4) + (LocaleController.isRTL ? sPad : 0), AndroidUtilities.dp(pad)); + ReactionsContainerLayout reactionsLayout = null; + if (optionsView != null) { + scrimPopupContainerLayout.addView(optionsView); + } else { + reactionsLayout = new ReactionsContainerLayout(contentView.getContext(), currentAccount, getResourceProvider()); + if (isReactionsAvailable) { + int pad = 22; + int sPad = 24; + reactionsLayout.setPadding(AndroidUtilities.dp(4) + (LocaleController.isRTL ? 0 : sPad), AndroidUtilities.dp(4), AndroidUtilities.dp(4) + (LocaleController.isRTL ? sPad : 0), AndroidUtilities.dp(pad)); - reactionsLayout.setDelegate((rView, reaction, longress) -> { - selectReaction(primaryMessage, reactionsLayout, 0, 0, reaction, false, longress); - }); - - LinearLayout.LayoutParams params = LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 52 + pad, Gravity.RIGHT, 0, 50, 0, -20); - scrimPopupContainerLayout.addView(reactionsLayout, params); - scrimPopupContainerLayout.setReactionsLayout(reactionsLayout); - scrimPopupContainerLayout.setClipChildren(false); - reactionsLayout.setMessage(message, chatInfo); - - reactionsLayout.setTransitionProgress(0); - if (popupLayout.getSwipeBack() != null) { - popupLayout.getSwipeBack().addOnSwipeBackProgressListener((layout, toProgress, progress) -> { - if (toProgress == 0) { - reactionsLayout.startEnterAnimation(); - } else if (toProgress == 1) - reactionsLayout.setAlpha(1f - progress); + ReactionsContainerLayout finalReactionsLayout = reactionsLayout; + reactionsLayout.setDelegate((rView, reaction, longress) -> { + selectReaction(primaryMessage, finalReactionsLayout, 0, 0, reaction, false, longress); }); + + LinearLayout.LayoutParams params = LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 52 + pad, Gravity.RIGHT, 0, 50, 0, -20); + scrimPopupContainerLayout.addView(reactionsLayout, params); + scrimPopupContainerLayout.setReactionsLayout(reactionsLayout); + scrimPopupContainerLayout.setClipChildren(false); + reactionsLayout.setMessage(message, chatInfo); + + reactionsLayout.setTransitionProgress(0); + if (popupLayout.getSwipeBack() != null) { + popupLayout.getSwipeBack().addOnSwipeBackProgressListener((layout, toProgress, progress) -> { + if (toProgress == 0) { + finalReactionsLayout.startEnterAnimation(); + } else if (toProgress == 1) + finalReactionsLayout.setAlpha(1f - progress); + }); + } } - } - boolean showNoForwards = noforwards && message.messageOwner.action == null && message.isSent() && !message.isEditing() && chatMode != MODE_SCHEDULED; - scrimPopupContainerLayout.addView(popupLayout, LayoutHelper.createLinearRelatively(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.LEFT, isReactionsAvailable ? 16 : 0, 0, isReactionsAvailable ? 36 : 0, 0)); - scrimPopupContainerLayout.setPopupWindowLayout(popupLayout); - if (showNoForwards) { - popupLayout.measure(View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED), View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED)); - boolean isChannel = ChatObject.isChannel(currentChat) && !currentChat.megagroup; - TextView tv = new TextView(contentView.getContext()); - tv.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); - tv.setTextColor(Theme.getColor(Theme.key_actionBarDefaultSubmenuItem)); - if (getMessagesController().isChatNoForwards(currentChat)) { - tv.setText(isChannel ? LocaleController.getString("ForwardsRestrictedInfoChannel", R.string.ForwardsRestrictedInfoChannel) : - LocaleController.getString("ForwardsRestrictedInfoGroup", R.string.ForwardsRestrictedInfoGroup)); - } else { - tv.setText(LocaleController.getString("ForwardsRestrictedInfoBot", R.string.ForwardsRestrictedInfoBot)); + boolean showNoForwards = noforwards && message.messageOwner.action == null && message.isSent() && !message.isEditing() && chatMode != MODE_SCHEDULED; + scrimPopupContainerLayout.addView(popupLayout, LayoutHelper.createLinearRelatively(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.LEFT, isReactionsAvailable ? 16 : 0, 0, isReactionsAvailable ? 36 : 0, 0)); + scrimPopupContainerLayout.setPopupWindowLayout(popupLayout); + if (showNoForwards) { + popupLayout.measure(View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED), View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED)); + boolean isChannel = ChatObject.isChannel(currentChat) && !currentChat.megagroup; + TextView tv = new TextView(contentView.getContext()); + tv.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); + tv.setTextColor(Theme.getColor(Theme.key_actionBarDefaultSubmenuItem)); + if (getMessagesController().isChatNoForwards(currentChat)) { + tv.setText(isChannel ? LocaleController.getString("ForwardsRestrictedInfoChannel", R.string.ForwardsRestrictedInfoChannel) : + LocaleController.getString("ForwardsRestrictedInfoGroup", R.string.ForwardsRestrictedInfoGroup)); + } else { + tv.setText(LocaleController.getString("ForwardsRestrictedInfoBot", R.string.ForwardsRestrictedInfoBot)); + } + tv.setMaxWidth(popupLayout.getMeasuredWidth() - AndroidUtilities.dp(38)); + + Drawable shadowDrawable2 = ContextCompat.getDrawable(contentView.getContext(), R.drawable.popup_fixed_alert).mutate(); + shadowDrawable2.setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_actionBarDefaultSubmenuBackground), PorterDuff.Mode.MULTIPLY)); + + FrameLayout fl = new FrameLayout(contentView.getContext()); + fl.setBackground(shadowDrawable2); + fl.addView(tv, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, 0, 11, 11, 11, 11)); + scrimPopupContainerLayout.addView(fl, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.LEFT, isReactionsAvailable ? 16 : 0, -8, isReactionsAvailable ? 36 : 0, 0)); + scrimPopupContainerLayout.applyViewBottom(fl); } - tv.setMaxWidth(popupLayout.getMeasuredWidth() - AndroidUtilities.dp(38)); - - Drawable shadowDrawable2 = ContextCompat.getDrawable(contentView.getContext(), R.drawable.popup_fixed_alert).mutate(); - shadowDrawable2.setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_actionBarDefaultSubmenuBackground), PorterDuff.Mode.MULTIPLY)); - - FrameLayout fl = new FrameLayout(contentView.getContext()); - fl.setBackground(shadowDrawable2); - fl.addView(tv, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, 0, 11, 11, 11, 11)); - scrimPopupContainerLayout.addView(fl, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.LEFT, isReactionsAvailable ? 16 : 0, -8, isReactionsAvailable ? 36 : 0, 0)); - scrimPopupContainerLayout.applyViewBottom(fl); } scrimPopupWindow = new ActionBarPopupWindow(scrimPopupContainerLayout, LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT) { @@ -21913,13 +22306,14 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } final int finalPopupX = scrimPopupX = popupX; final int finalPopupY = scrimPopupY = popupY; + ReactionsContainerLayout finalReactionsLayout = reactionsLayout; Runnable showMenu = () -> { if (scrimPopupWindow == null || fragmentView == null) { return; } scrimPopupWindow.showAtLocation(chatListView, Gravity.LEFT | Gravity.TOP, finalPopupX, finalPopupY); - if (isReactionsAvailable) { - reactionsLayout.startEnterAnimation(); + if (isReactionsAvailable && finalReactionsLayout != null) { + finalReactionsLayout.startEnterAnimation(); } }; if (waitForLangDetection.get()) { @@ -21940,11 +22334,11 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (chatActivityEnterView != null) { chatActivityEnterView.getEditField().setAllowDrawCursor(false); } - return; + return true; } if (chatActivityEnterView != null && (chatActivityEnterView.isRecordingAudioVideo() || chatActivityEnterView.isRecordLocked())) { - return; + return false; } final ActionBarMenu actionMode = actionBar.createActionMode(); @@ -22001,6 +22395,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (chatActivityEnterView != null) { chatActivityEnterView.hideBotCommands(); } + return false; } private void closeMenu() { closeMenu(true); @@ -22034,6 +22429,9 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not Runnable updateReactionRunnable; private void selectReaction(MessageObject primaryMessage, ReactionsContainerLayout reactionsLayout, float x, float y, TLRPC.TL_availableReaction reaction, boolean fromDoubleTap, boolean bigEmoji) { + if (isInScheduleMode()) { + return; + } ReactionsEffectOverlay.removeCurrent(false); boolean added = primaryMessage.selectReaction(reaction.reaction, bigEmoji, fromDoubleTap); int messageIdForCell = primaryMessage.getId(); @@ -22339,7 +22737,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not return; } preserveDim = true; - createDeleteMessagesAlert(selectedObject, selectedObjectGroup); + createDeleteMessagesAlert(selectedObject, selectedObjectGroup, 1,true); break; } case 2: { @@ -22623,7 +23021,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity(), themeDelegate); builder.setTitle(LocaleController.getString("PinMessageAlertTitle", R.string.PinMessageAlertTitle)); preserveDim = true; - builder.setDimEnabled(false); + builder.setDimAlpha(.5f); builder.setOnPreDismissListener(di -> dimBehindView(false)); final boolean[] checks; @@ -22879,7 +23277,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not presentFragment(new MessageStatisticActivity(selectedObject)); break; } - case 100: { + case OPTION_SEND_NOW: { if (!checkSlowMode(chatActivityEnterView.getSendButton())) { if (getMediaController().isPlayingMessage(selectedObject)) { getMediaController().cleanupPlayer(true, true); @@ -23897,11 +24295,17 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not ((URLSpanMono) url).copyToClipboard(); getUndoView().showWithAction(0, UndoView.ACTION_TEXT_COPIED, null); } + if (longPress) { + cell.resetPressedLink(-1); + } } else if (url instanceof URLSpanUserMention) { TLRPC.User user = getMessagesController().getUser(Utilities.parseLong(((URLSpanUserMention) url).getURL())); if (user != null) { MessagesController.openChatOrProfileWith(user, null, ChatActivity.this, 0, false); } + if (longPress) { + cell.resetPressedLink(-1); + } } else if (url instanceof URLSpanNoUnderline) { String str = ((URLSpanNoUnderline) url).getURL(); if (messageObject != null && str.startsWith("/")) { @@ -23911,6 +24315,9 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not hideFieldPanel(false); } } + if (longPress) { + cell.resetPressedLink(-1); + } } else if (messageObject != null && str.startsWith("video") && !longPress) { int seekTime = Utilities.parseInt(str); TLRPC.WebPage webPage; @@ -23954,7 +24361,11 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not messageObject.forceSeekTo = seekTime / (float) messageObject.getDuration(); mediaController.playMessage(messageObject); } + if (longPress) { + cell.resetPressedLink(-1); + } } else if (str.startsWith("card:")) { + final ChatMessageCell finalCell = cell; String number = str.substring(5); final AlertDialog[] progressDialog = new AlertDialog[]{new AlertDialog(getParentActivity(), 3, themeDelegate)}; TLRPC.TL_payments_getBankCardData req = new TLRPC.TL_payments_getBankCardData(); @@ -23986,14 +24397,21 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not Toast.makeText(ApplicationLoader.applicationContext, LocaleController.getString("CardNumberCopied", R.string.CardNumberCopied), Toast.LENGTH_SHORT).show(); } }); + builder.setOnPreDismissListener(di -> finalCell.resetPressedLink(-1)); + builder.fixNavigationBar(); showDialog(builder.create()); + } else { + finalCell.resetPressedLink(-1); } }), null, null, 0, getMessagesController().webFileDatacenterId, ConnectionsManager.ConnectionTypeGeneric, true); AndroidUtilities.runOnUIThread(() -> { if (progressDialog[0] == null) { return; } - progressDialog[0].setOnCancelListener(dialog -> getConnectionsManager().cancelRequest(requestId, true)); + progressDialog[0].setOnCancelListener(dialog -> { + getConnectionsManager().cancelRequest(requestId, true); + finalCell.resetPressedLink(-1); + }); showDialog(progressDialog[0]); }, 500); } else { @@ -24067,14 +24485,22 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } }); + builder.setOnPreDismissListener(di -> { + finalCell.resetPressedLink(-1); + }); + builder.fixNavigationBar(); showDialog(builder.create()); } else { openClickableLink(str); + if (longPress) { + cell.resetPressedLink(-1); + } } } } else { final String urlFinal = ((URLSpan) url).getURL(); if (longPress) { + final ChatMessageCell finalCell = cell; BottomSheet.Builder builder = new BottomSheet.Builder(getParentActivity(), false, themeDelegate); builder.setTitle(urlFinal); builder.setItems(noforwards ? new CharSequence[] {LocaleController.getString("Open", R.string.Open)} : new CharSequence[]{LocaleController.getString("Open", R.string.Open), LocaleController.getString("Copy", R.string.Copy)}, (dialog, which) -> { @@ -24101,6 +24527,10 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } } }); + builder.setOnPreDismissListener(di -> { + finalCell.resetPressedLink(-1); + }); + builder.fixNavigationBar(); showDialog(builder.create()); } else { boolean forceAlert = url instanceof URLSpanReplacement; @@ -24898,6 +25328,15 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } } + @Override + public void didPressViaBotNotInline(ChatMessageCell cell, long botId) { + Bundle args = new Bundle(); + args.putLong("user_id", botId); + if (getMessagesController().checkCanOpenChat(args, ChatActivity.this, cell.getMessageObject())) { + presentFragment(new ChatActivity(args)); + } + } + @Override public void didPressViaBot(ChatMessageCell cell, String username) { if (bottomOverlayChat != null && bottomOverlayChat.getVisibility() == View.VISIBLE || bottomOverlay != null && bottomOverlay.getVisibility() == View.VISIBLE) { @@ -25183,8 +25622,8 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } @Override - public void didLongPress(ChatActionCell cell, float x, float y) { - createMenu(cell, false, false, x, y); + public boolean didLongPress(ChatActionCell cell, float x, float y) { + return createMenu(cell, false, false, x, y); } @Override @@ -25780,12 +26219,11 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } public void updateRowAtPosition(int index) { - if (chatLayoutManager == null) { + if (chatLayoutManager == null || isFrozen) { return; } int lastVisibleItem = RecyclerView.NO_POSITION; int top = 0; - ArrayList messages = isFrozen ? frozenMessages : ChatActivity.this.messages; if (!wasManualScroll && unreadMessageObject != null) { int n = chatListView.getChildCount(); @@ -26359,7 +26797,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not themeDescriptions.add(new ThemeDescription(chatListView, ThemeDescription.FLAG_TEXTCOLOR, new Class[]{ChatActionCell.class}, getThemedPaint(Theme.key_paint_chatActionText), null, null, Theme.key_chat_serviceText)); themeDescriptions.add(new ThemeDescription(chatListView, ThemeDescription.FLAG_LINKCOLOR, new Class[]{ChatActionCell.class}, getThemedPaint(Theme.key_paint_chatActionText), null, null, Theme.key_chat_serviceLink)); - themeDescriptions.add(new ThemeDescription(chatListView, 0, new Class[]{ChatMessageCell.class}, null, new Drawable[]{Theme.chat_botCardDrawalbe, getThemedDrawable(Theme.key_drawable_shareIcon), getThemedDrawable(Theme.key_drawable_replyIcon), getThemedDrawable(Theme.key_drawable_botInline), getThemedDrawable(Theme.key_drawable_botLink), getThemedDrawable(Theme.key_drawable_goIcon), getThemedDrawable(Theme.key_drawable_commentSticker)}, null, Theme.key_chat_serviceIcon)); + themeDescriptions.add(new ThemeDescription(chatListView, 0, new Class[]{ChatMessageCell.class}, null, new Drawable[]{Theme.chat_botCardDrawable, getThemedDrawable(Theme.key_drawable_shareIcon), getThemedDrawable(Theme.key_drawable_replyIcon), getThemedDrawable(Theme.key_drawable_botInline), getThemedDrawable(Theme.key_drawable_botLink), getThemedDrawable(Theme.key_drawable_botInvite), getThemedDrawable(Theme.key_drawable_goIcon), getThemedDrawable(Theme.key_drawable_commentSticker)}, null, Theme.key_chat_serviceIcon)); themeDescriptions.add(new ThemeDescription(chatListView, 0, new Class[]{ChatMessageCell.class, ChatActionCell.class}, null, null, null, Theme.key_chat_serviceBackground)); themeDescriptions.add(new ThemeDescription(chatListView, 0, new Class[]{ChatMessageCell.class, ChatActionCell.class}, null, null, null, Theme.key_chat_serviceBackgroundSelected)); @@ -26500,6 +26938,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not themeDescriptions.add(new ThemeDescription(chatListView, 0, new Class[]{ChatMessageCell.class}, null, null, null, Theme.key_chat_outVenueInfoSelectedText)); themeDescriptions.add(new ThemeDescription(chatListView, 0, new Class[]{ChatMessageCell.class}, null, null, null, Theme.key_chat_mediaInfoText)); themeDescriptions.add(new ThemeDescription(chatListView, 0, new Class[]{ChatMessageCell.class}, Theme.chat_urlPaint, null, null, Theme.key_chat_linkSelectBackground)); + themeDescriptions.add(new ThemeDescription(chatListView, 0, new Class[]{ChatMessageCell.class}, Theme.chat_outUrlPaint, null, null, Theme.key_chat_outLinkSelectBackground)); themeDescriptions.add(new ThemeDescription(chatListView, 0, new Class[]{ChatMessageCell.class}, Theme.chat_textSearchSelectionPaint, null, null, Theme.key_chat_textSelectBackground)); themeDescriptions.add(new ThemeDescription(chatListView, 0, new Class[]{ChatMessageCell.class}, null, null, null, Theme.key_chat_outLoader)); themeDescriptions.add(new ThemeDescription(chatListView, 0, new Class[]{ChatMessageCell.class}, null, null, null, Theme.key_chat_outMediaIcon)); @@ -27023,7 +27462,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not @Override public int getThemedColor(String key) { - Integer color = themeDelegate.getColor(key); + Integer color = themeDelegate != null ? themeDelegate.getColor(key) : null; return color != null ? color : super.getThemedColor(key); } @@ -27264,6 +27703,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not animationSettings.animationProgress = new ActionBarLayout.ThemeAnimationSettings.onAnimationProgress() { @Override public void setProgress(float p) { + chatListView.invalidate(); animatingMessageDrawable.crossfadeProgress = p; animatingMessageMediaDrawable.crossfadeProgress = p; updateServiceMessageColor(p); @@ -27286,6 +27726,10 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not animatingColors = null; updateServiceMessageColor(1f); }; + } else { + if (contentView != null) { + contentView.setBackgroundImage(Theme.getCachedWallpaper(), Theme.isWallpaperMotion()); + } } animationSettings.onlyTopFragment = true; animationSettings.resourcesProvider = this; @@ -27384,7 +27828,6 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not initServiceMessageColors(backgroundDrawable); updateServiceMessageColor(1f); } - } } @@ -27598,6 +28041,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not Theme.setDrawableColor(getDrawable(Theme.key_drawable_botInline), serviceIconColor); Theme.setDrawableColor(getDrawable(Theme.key_drawable_botLink), serviceIconColor); + Theme.setDrawableColor(getDrawable(Theme.key_drawable_botInvite), serviceIconColor); Theme.setDrawableColor(getDrawable(Theme.key_drawable_commentSticker), serviceIconColor); Theme.setDrawableColor(getDrawable(Theme.key_drawable_goIcon), serviceIconColor); Theme.setDrawableColor(getDrawable(Theme.key_drawable_replyIcon), serviceIconColor); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ChatEditActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ChatEditActivity.java index 46d91ffdb..fe178c691 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ChatEditActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ChatEditActivity.java @@ -929,7 +929,7 @@ public class ChatEditActivity extends BaseFragment implements ImageUpdater.Image deleteCell.setText(LocaleController.getString("DeleteAndExitButton", R.string.DeleteAndExitButton), false); } deleteContainer.addView(deleteCell, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); - deleteCell.setOnClickListener(v -> AlertsCreator.createClearOrDeleteDialogAlert(ChatEditActivity.this, false, true, false, currentChat, null, false, true, (param) -> { + deleteCell.setOnClickListener(v -> AlertsCreator.createClearOrDeleteDialogAlert(ChatEditActivity.this, false, true, false, currentChat, null, false, true, false, (param) -> { if (AndroidUtilities.isTablet()) { getNotificationCenter().postNotificationName(NotificationCenter.closeChats, -chatId); } else { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ChatReactionsEditActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ChatReactionsEditActivity.java index 8ec0d785d..4f62abb80 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ChatReactionsEditActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ChatReactionsEditActivity.java @@ -104,7 +104,6 @@ public class ChatReactionsEditActivity extends BaseFragment implements Notificat enableReactionsCell.setTextAndCheck(LocaleController.getString("EnableReactions", R.string.EnableReactions), !chatReactions.isEmpty(), false); enableReactionsCell.setBackgroundColor(Theme.getColor(enableReactionsCell.isChecked() ? Theme.key_windowBackgroundChecked : Theme.key_windowBackgroundUnchecked)); enableReactionsCell.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); - enableReactionsCell.setAnimatingToThumbInsteadOfTouch(true); enableReactionsCell.setOnClickListener(v -> { setCheckedEnableReactionCell(!enableReactionsCell.isChecked()); }); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ChatRightsEditActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ChatRightsEditActivity.java index 5a34f7110..a882f6789 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ChatRightsEditActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ChatRightsEditActivity.java @@ -8,19 +8,27 @@ package org.telegram.ui; +import android.animation.ValueAnimator; import android.app.DatePickerDialog; import android.app.TimePickerDialog; import android.content.Context; import android.content.DialogInterface; +import android.graphics.Canvas; +import android.graphics.Paint; import android.graphics.PorterDuff; import android.graphics.PorterDuffColorFilter; +import android.graphics.drawable.Drawable; import android.os.Build; import android.os.Bundle; import android.os.Vibrator; import android.text.Editable; +import android.text.Layout; +import android.text.StaticLayout; +import android.text.TextPaint; import android.text.TextWatcher; import android.util.TypedValue; import android.view.Gravity; +import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; import android.view.inputmethod.EditorInfo; @@ -58,6 +66,10 @@ import org.telegram.ui.Cells.TextInfoPrivacyCell; import org.telegram.ui.Cells.TextSettingsCell; import org.telegram.ui.Cells.UserCell2; import org.telegram.ui.Components.AlertsCreator; +import org.telegram.ui.Components.BulletinFactory; +import org.telegram.ui.Components.CircularProgressDrawable; +import org.telegram.ui.Components.CrossfadeDrawable; +import org.telegram.ui.Components.CubicBezierInterpolator; import org.telegram.ui.Components.LayoutHelper; import org.telegram.ui.Components.RecyclerListView; @@ -72,15 +84,25 @@ public class ChatRightsEditActivity extends BaseFragment { private ListAdapter listViewAdapter; private RecyclerListView listView; + private LinearLayoutManager linearLayoutManager; + + private FrameLayout addBotButtonContainer; + private FrameLayout addBotButton; + private PollEditTextCell rankEditTextCell; + private CrossfadeDrawable doneDrawable; private long chatId; private TLRPC.User currentUser; private TLRPC.Chat currentChat; private int currentType; private boolean isChannel; + private boolean loading = false; private boolean canEdit; + private float asAdminT = 0; + private boolean asAdmin = false; + private boolean initialAsAdmin = false; private TLRPC.TL_chatAdminRights adminRights; private TLRPC.TL_chatAdminRights myAdminRights; private TLRPC.TL_chatBannedRights bannedRights; @@ -90,6 +112,9 @@ public class ChatRightsEditActivity extends BaseFragment { private String initialRank; private int rowCount; + private int manageRow; + private int permissionsStartRow; + private int permissionsEndRow; private int changeInfoRow; private int postMessagesRow; private int editMesagesRow; @@ -108,6 +133,7 @@ public class ChatRightsEditActivity extends BaseFragment { private int rankHeaderRow; private int rankRow; private int rankInfoRow; + private int addBotButtonRow; private int sendMessagesRow; private int sendMediaRow; @@ -120,11 +146,15 @@ public class ChatRightsEditActivity extends BaseFragment { private ChatRightsEditActivityDelegate delegate; + private String botHash; private boolean isAddingNew; private boolean initialIsSet; public static final int TYPE_ADMIN = 0; public static final int TYPE_BANNED = 1; + public static final int TYPE_ADD_BOT = 2; + + private boolean closingKeyboardAfterFinish = false; public interface ChatRightsEditActivityDelegate { void didSetRights(int rights, TLRPC.TL_chatAdminRights rightsAdmin, TLRPC.TL_chatBannedRights rightsBanned, String rank); @@ -133,13 +163,14 @@ public class ChatRightsEditActivity extends BaseFragment { private final static int done_button = 1; - public ChatRightsEditActivity(long userId, long channelId, TLRPC.TL_chatAdminRights rightsAdmin, TLRPC.TL_chatBannedRights rightsBannedDefault, TLRPC.TL_chatBannedRights rightsBanned, String rank, int type, boolean edit, boolean addingNew) { + public ChatRightsEditActivity(long userId, long channelId, TLRPC.TL_chatAdminRights rightsAdmin, TLRPC.TL_chatBannedRights rightsBannedDefault, TLRPC.TL_chatBannedRights rightsBanned, String rank, int type, boolean edit, boolean addingNew, String addingNewBotHash) { super(); isAddingNew = addingNew; chatId = channelId; currentUser = MessagesController.getInstance(currentAccount).getUser(userId); currentType = type; canEdit = edit; + botHash = addingNewBotHash; currentChat = MessagesController.getInstance(currentAccount).getChat(chatId); if (rank == null) { rank = ""; @@ -150,24 +181,31 @@ public class ChatRightsEditActivity extends BaseFragment { myAdminRights = currentChat.admin_rights; } if (myAdminRights == null) { - myAdminRights = new TLRPC.TL_chatAdminRights(); - myAdminRights.change_info = myAdminRights.post_messages = myAdminRights.edit_messages = - myAdminRights.delete_messages = myAdminRights.ban_users = myAdminRights.invite_users = - myAdminRights.pin_messages = myAdminRights.add_admins = myAdminRights.manage_call = true; + myAdminRights = emptyAdminRights(currentType != TYPE_ADD_BOT || (currentChat != null && currentChat.creator)); } - if (type == TYPE_ADMIN) { - adminRights = new TLRPC.TL_chatAdminRights(); + if (type == TYPE_ADMIN || type == TYPE_ADD_BOT) { if (rightsAdmin == null) { - adminRights.change_info = myAdminRights.change_info; - adminRights.post_messages = myAdminRights.post_messages; - adminRights.edit_messages = myAdminRights.edit_messages; - adminRights.delete_messages = myAdminRights.delete_messages; - adminRights.manage_call = myAdminRights.manage_call; - adminRights.ban_users = myAdminRights.ban_users; - adminRights.invite_users = myAdminRights.invite_users; - adminRights.pin_messages = myAdminRights.pin_messages; - initialIsSet = false; + initialAsAdmin = false; + if (type == TYPE_ADD_BOT) { + adminRights = emptyAdminRights(false); + asAdmin = isChannel; + asAdminT = asAdmin ? 1 : 0; + initialIsSet = false; + } else { + adminRights = new TLRPC.TL_chatAdminRights(); + adminRights.change_info = myAdminRights.change_info; + adminRights.post_messages = myAdminRights.post_messages; + adminRights.edit_messages = myAdminRights.edit_messages; + adminRights.delete_messages = myAdminRights.delete_messages; + adminRights.manage_call = myAdminRights.manage_call; + adminRights.ban_users = myAdminRights.ban_users; + adminRights.invite_users = myAdminRights.invite_users; + adminRights.pin_messages = myAdminRights.pin_messages; + initialIsSet = false; + } } else { + initialAsAdmin = true; + adminRights = new TLRPC.TL_chatAdminRights(); adminRights.change_info = rightsAdmin.change_info; adminRights.post_messages = rightsAdmin.post_messages; adminRights.edit_messages = rightsAdmin.edit_messages; @@ -182,8 +220,32 @@ public class ChatRightsEditActivity extends BaseFragment { initialIsSet = adminRights.change_info || adminRights.post_messages || adminRights.edit_messages || adminRights.delete_messages || adminRights.ban_users || adminRights.invite_users || adminRights.pin_messages || adminRights.add_admins || adminRights.manage_call || adminRights.anonymous; + + if (type == TYPE_ADD_BOT) { + asAdmin = isChannel || initialIsSet; + asAdminT = asAdmin ? 1 : 0; + initialIsSet = false; + } } - } else { + + if (currentChat != null) { + defaultBannedRights = currentChat.default_banned_rights; + } + if (defaultBannedRights == null) { + defaultBannedRights = new TLRPC.TL_chatBannedRights(); + defaultBannedRights.view_messages = defaultBannedRights.send_media = defaultBannedRights.send_messages = + defaultBannedRights.embed_links = defaultBannedRights.send_stickers = defaultBannedRights.send_gifs = + defaultBannedRights.send_games = defaultBannedRights.send_inline = defaultBannedRights.send_polls = + defaultBannedRights.invite_users = defaultBannedRights.change_info = defaultBannedRights.pin_messages = true; + } + + if (!defaultBannedRights.change_info) { + adminRights.change_info = true; + } + if (!defaultBannedRights.pin_messages) { + adminRights.pin_messages = true; + } + } else if (type == TYPE_BANNED) { defaultBannedRights = rightsBannedDefault; if (defaultBannedRights == null) { defaultBannedRights = new TLRPC.TL_chatBannedRights(); @@ -258,12 +320,24 @@ public class ChatRightsEditActivity extends BaseFragment { updateRows(false); } + public static TLRPC.TL_chatAdminRights emptyAdminRights(boolean value) { + TLRPC.TL_chatAdminRights adminRights = new TLRPC.TL_chatAdminRights(); + adminRights.change_info = adminRights.post_messages = adminRights.edit_messages = + adminRights.delete_messages = adminRights.ban_users = adminRights.invite_users = + adminRights.pin_messages = adminRights.add_admins = adminRights.manage_call = value; + return adminRights; + } + + @Override public View createView(Context context) { actionBar.setBackButtonImage(R.drawable.ic_ab_back); actionBar.setAllowOverlayTitle(true); + if (currentType == TYPE_ADMIN) { actionBar.setTitle(LocaleController.getString("EditAdmin", R.string.EditAdmin)); + } else if (currentType == TYPE_ADD_BOT) { + actionBar.setTitle(LocaleController.getString("AddBot", R.string.AddBot)); } else { actionBar.setTitle(LocaleController.getString("UserRestrictions", R.string.UserRestrictions)); } @@ -283,19 +357,60 @@ public class ChatRightsEditActivity extends BaseFragment { if (canEdit || !isChannel && currentChat.creator && UserObject.isUserSelf(currentUser)) { ActionBarMenu menu = actionBar.createMenu(); - menu.addItemWithWidth(done_button, R.drawable.ic_done, AndroidUtilities.dp(56), LocaleController.getString("Done", R.string.Done)); + doneDrawable = new CrossfadeDrawable(context.getResources().getDrawable(R.drawable.ic_done), new CircularProgressDrawable(Theme.getColor(Theme.key_actionBarDefaultIcon))); + menu.addItemWithWidth(done_button, 0, AndroidUtilities.dp(56), LocaleController.getString("Done", R.string.Done)); + menu.getItem(done_button).setIcon(doneDrawable); } - fragmentView = new FrameLayout(context); + fragmentView = new FrameLayout(context) { + private int previousHeight = -1; + @Override + protected void onLayout(boolean changed, int left, int top, int right, int bottom) { + super.onLayout(changed, left, top, right, bottom); + int height = bottom - top; + if (previousHeight != -1 && Math.abs(previousHeight - height) > AndroidUtilities.dp(20)) { + listView.smoothScrollToPosition(rowCount - 1); + } + previousHeight = height; + } + }; fragmentView.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundGray)); FrameLayout frameLayout = (FrameLayout) fragmentView; fragmentView.setFocusableInTouchMode(true); - listView = new RecyclerListView(context); - LinearLayoutManager linearLayoutManager = new LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false); - ((DefaultItemAnimator) listView.getItemAnimator()).setDelayAnimations(false); + listView = new RecyclerListView(context) { + @Override + public boolean onTouchEvent(MotionEvent e) { + if (loading) { + return false; + } + return super.onTouchEvent(e); + } + + @Override + public boolean onInterceptTouchEvent(MotionEvent e) { + if (loading) { + return false; + } + return super.onInterceptTouchEvent(e); + } + }; + listView.setClipChildren(currentType != TYPE_ADD_BOT); + linearLayoutManager = new LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false) { + @Override + protected int getExtraLayoutSpace(RecyclerView.State state) { + return 5000; + } + }; + linearLayoutManager.setInitialPrefetchItemCount(100); listView.setLayoutManager(linearLayoutManager); listView.setAdapter(listViewAdapter = new ListAdapter(context)); + DefaultItemAnimator itemAnimator = new DefaultItemAnimator(); + if (currentType == TYPE_ADD_BOT) { + listView.setResetSelectorOnChanged(false); + } + itemAnimator.setDelayAnimations(false); + listView.setItemAnimator(itemAnimator); listView.setVerticalScrollbarPosition(LocaleController.isRTL ? RecyclerListView.SCROLLBAR_POSITION_LEFT : RecyclerListView.SCROLLBAR_POSITION_RIGHT); frameLayout.addView(listView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); @@ -318,7 +433,7 @@ public class ChatRightsEditActivity extends BaseFragment { presentFragment(new ProfileActivity(args)); } else if (position == removeAdminRow) { if (currentType == TYPE_ADMIN) { - MessagesController.getInstance(currentAccount).setUserAdminRole(chatId, currentUser, new TLRPC.TL_chatAdminRights(), currentRank, isChannel, getFragmentForAlert(0), isAddingNew); + MessagesController.getInstance(currentAccount).setUserAdminRole(chatId, currentUser, new TLRPC.TL_chatAdminRights(), currentRank, isChannel, getFragmentForAlert(0), isAddingNew, false, null,null); if (delegate != null) { delegate.didSetRights(0, adminRights, bannedRights, currentRank); } @@ -481,57 +596,81 @@ public class ChatRightsEditActivity extends BaseFragment { } else if (view instanceof TextCheckCell2) { TextCheckCell2 checkCell = (TextCheckCell2) view; if (checkCell.hasIcon()) { - Toast.makeText(getParentActivity(), LocaleController.getString("UserRestrictionsDisabled", R.string.UserRestrictionsDisabled), Toast.LENGTH_SHORT).show(); + if (currentType != TYPE_ADD_BOT) { + new AlertDialog.Builder(getParentActivity()) + .setTitle(LocaleController.getString("UserRestrictionsCantModify", R.string.UserRestrictionsCantModify)) + .setMessage(LocaleController.getString("UserRestrictionsCantModifyDisabled", R.string.UserRestrictionsCantModifyDisabled)) + .setPositiveButton(LocaleController.getString("OK", R.string.OK), null) + .create() + .show(); + } return; } + if (!checkCell.isEnabled()) { + if ((currentType == TYPE_ADD_BOT || currentType == TYPE_ADMIN) && + (position == changeInfoRow && defaultBannedRights != null && !defaultBannedRights.change_info || + position == pinMessagesRow && defaultBannedRights != null && !defaultBannedRights.pin_messages)) { + new AlertDialog.Builder(getParentActivity()) + .setTitle(LocaleController.getString("UserRestrictionsCantModify", R.string.UserRestrictionsCantModify)) + .setMessage(LocaleController.getString("UserRestrictionsCantModifyEnabled", R.string.UserRestrictionsCantModifyEnabled)) + .setPositiveButton(LocaleController.getString("OK", R.string.OK), null) + .create() + .show(); + } return; } - checkCell.setChecked(!checkCell.isChecked()); - if (position == changeInfoRow) { - if (currentType == TYPE_ADMIN) { - adminRights.change_info = !adminRights.change_info; + if (currentType != TYPE_ADD_BOT) { + checkCell.setChecked(!checkCell.isChecked()); + } + boolean value = checkCell.isChecked(); + if (position == manageRow) { + value = asAdmin = !asAdmin; + updateAsAdmin(true); + } else if (position == changeInfoRow) { + if (currentType == TYPE_ADMIN || currentType == TYPE_ADD_BOT) { + value = adminRights.change_info = !adminRights.change_info; } else { - bannedRights.change_info = !bannedRights.change_info; + value = bannedRights.change_info = !bannedRights.change_info; } } else if (position == postMessagesRow) { - adminRights.post_messages = !adminRights.post_messages; + value = adminRights.post_messages = !adminRights.post_messages; } else if (position == editMesagesRow) { - adminRights.edit_messages = !adminRights.edit_messages; + value = adminRights.edit_messages = !adminRights.edit_messages; } else if (position == deleteMessagesRow) { - adminRights.delete_messages = !adminRights.delete_messages; + value = adminRights.delete_messages = !adminRights.delete_messages; } else if (position == addAdminsRow) { - adminRights.add_admins = !adminRights.add_admins; + value = adminRights.add_admins = !adminRights.add_admins; } else if (position == anonymousRow) { - adminRights.anonymous = !adminRights.anonymous; + value = adminRights.anonymous = !adminRights.anonymous; } else if (position == banUsersRow) { - adminRights.ban_users = !adminRights.ban_users; + value = adminRights.ban_users = !adminRights.ban_users; } else if (position == startVoiceChatRow) { - adminRights.manage_call = !adminRights.manage_call; + value = adminRights.manage_call = !adminRights.manage_call; } else if (position == addUsersRow) { - if (currentType == TYPE_ADMIN) { - adminRights.invite_users = !adminRights.invite_users; + if (currentType == TYPE_ADMIN || currentType == TYPE_ADD_BOT) { + value = adminRights.invite_users = !adminRights.invite_users; } else { - bannedRights.invite_users = !bannedRights.invite_users; + value = bannedRights.invite_users = !bannedRights.invite_users; } } else if (position == pinMessagesRow) { - if (currentType == TYPE_ADMIN) { - adminRights.pin_messages = !adminRights.pin_messages; + if (currentType == TYPE_ADMIN || currentType == TYPE_ADD_BOT) { + value = adminRights.pin_messages = !adminRights.pin_messages; } else { - bannedRights.pin_messages = !bannedRights.pin_messages; + value = bannedRights.pin_messages = !bannedRights.pin_messages; } - } else if (bannedRights != null) { + } else if (currentType == TYPE_BANNED && bannedRights != null) { boolean disabled = !checkCell.isChecked(); if (position == sendMessagesRow) { - bannedRights.send_messages = !bannedRights.send_messages; + value = bannedRights.send_messages = !bannedRights.send_messages; } else if (position == sendMediaRow) { - bannedRights.send_media = !bannedRights.send_media; + value = bannedRights.send_media = !bannedRights.send_media; } else if (position == sendStickersRow) { - bannedRights.send_stickers = bannedRights.send_games = bannedRights.send_gifs = bannedRights.send_inline = !bannedRights.send_stickers; + value = bannedRights.send_stickers = bannedRights.send_games = bannedRights.send_gifs = bannedRights.send_inline = !bannedRights.send_stickers; } else if (position == embedLinksRow) { - bannedRights.embed_links = !bannedRights.embed_links; + value = bannedRights.embed_links = !bannedRights.embed_links; } else if (position == sendPollsRow) { - bannedRights.send_polls = !bannedRights.send_polls; + value = bannedRights.send_polls = !bannedRights.send_polls; } if (disabled) { if (bannedRights.view_messages && !bannedRights.send_messages) { @@ -582,9 +721,13 @@ public class ChatRightsEditActivity extends BaseFragment { } } } + if (currentType == TYPE_ADD_BOT) { + checkCell.setChecked(asAdmin && value); + } updateRows(true); } }); + return fragmentView; } @@ -770,6 +913,7 @@ public class ChatRightsEditActivity extends BaseFragment { private void updateRows(boolean update) { int transferOwnerShadowRowPrev = Math.min(transferOwnerShadowRow, transferOwnerRow); + manageRow = -1; changeInfoRow = -1; postMessagesRow = -1; editMesagesRow = -1; @@ -797,9 +941,11 @@ public class ChatRightsEditActivity extends BaseFragment { startVoiceChatRow = -1; untilSectionRow = -1; untilDateRow = -1; + addBotButtonRow = -1; rowCount = 3; - if (currentType == TYPE_ADMIN) { + permissionsStartRow = rowCount; + if (currentType == TYPE_ADMIN || currentType == TYPE_ADD_BOT) { if (isChannel) { changeInfoRow = rowCount++; postMessagesRow = rowCount++; @@ -809,6 +955,9 @@ public class ChatRightsEditActivity extends BaseFragment { startVoiceChatRow = rowCount++; addAdminsRow = rowCount++; } else { + if (currentType == TYPE_ADD_BOT) { + manageRow = rowCount++; + } changeInfoRow = rowCount++; deleteMessagesRow = rowCount++; banUsersRow = rowCount++; @@ -830,9 +979,10 @@ public class ChatRightsEditActivity extends BaseFragment { untilSectionRow = rowCount++; untilDateRow = rowCount++; } + permissionsEndRow = rowCount; if (canEdit) { - if (!isChannel && currentType == TYPE_ADMIN) { + if (!isChannel && (currentType == TYPE_ADMIN || currentType == TYPE_ADD_BOT && asAdmin)) { rightsShadowRow = rowCount++; rankHeaderRow = rowCount++; rankRow = rowCount++; @@ -856,7 +1006,7 @@ public class ChatRightsEditActivity extends BaseFragment { } } else { if (currentType == TYPE_ADMIN) { - if (!isChannel && currentType == TYPE_ADMIN && (!currentRank.isEmpty() || currentChat.creator && UserObject.isUserSelf(currentUser))) { + if (!isChannel && (!currentRank.isEmpty() || currentChat.creator && UserObject.isUserSelf(currentUser))) { rightsShadowRow = rowCount++; rankHeaderRow = rowCount++; rankRow = rowCount++; @@ -872,6 +1022,10 @@ public class ChatRightsEditActivity extends BaseFragment { rightsShadowRow = rowCount++; } } + if (currentType == TYPE_ADD_BOT) { + addBotButtonRow = rowCount++; + } + if (update) { if (transferOwnerShadowRowPrev == -1 && transferOwnerShadowRow != -1) { listViewAdapter.notifyItemRangeInserted(Math.min(transferOwnerShadowRow, transferOwnerRow), 2); @@ -882,7 +1036,10 @@ public class ChatRightsEditActivity extends BaseFragment { } private void onDonePressed() { - if (!ChatObject.isChannel(currentChat) && (currentType == TYPE_BANNED || currentType == TYPE_ADMIN && (!isDefaultAdminRights() || rankRow != -1 && currentRank.codePointCount(0, currentRank.length()) > MAX_RANK_LENGTH))) { + if (loading) { + return; + } + if (!ChatObject.isChannel(currentChat) && (currentType == TYPE_BANNED || currentType == TYPE_ADMIN && (!isDefaultAdminRights() || rankRow != -1 && currentRank.codePointCount(0, currentRank.length()) > MAX_RANK_LENGTH) || currentType == TYPE_ADD_BOT && (currentRank != null || !isDefaultAdminRights()))) { MessagesController.getInstance(currentAccount).convertToMegaGroup(getParentActivity(), chatId, this, param -> { if (param != 0) { chatId = param; @@ -892,7 +1049,7 @@ public class ChatRightsEditActivity extends BaseFragment { }); return; } - if (currentType == TYPE_ADMIN) { + if (currentType == TYPE_ADMIN || currentType == TYPE_ADD_BOT) { if (rankRow != -1 && currentRank.codePointCount(0, currentRank.length()) > MAX_RANK_LENGTH) { listView.smoothScrollToPosition(rankRow); Vibrator v = (Vibrator) getParentActivity().getSystemService(Context.VIBRATOR_SERVICE); @@ -917,14 +1074,23 @@ public class ChatRightsEditActivity extends BaseFragment { } else { adminRights.other = false; } - MessagesController.getInstance(currentAccount).setUserAdminRole(chatId, currentUser, adminRights, currentRank, isChannel, getFragmentForAlert(1), isAddingNew); - if (delegate != null) { - delegate.didSetRights( + } + boolean finishFragment = true; + if (currentType == TYPE_ADMIN) { + finishFragment = delegate == null; + setLoading(true); + MessagesController.getInstance(currentAccount).setUserAdminRole(chatId, currentUser, adminRights, currentRank, isChannel, this, isAddingNew, false, null, () -> { + if (delegate != null) { + delegate.didSetRights( adminRights.change_info || adminRights.post_messages || adminRights.edit_messages || adminRights.delete_messages || adminRights.ban_users || adminRights.invite_users || adminRights.pin_messages || adminRights.add_admins || adminRights.anonymous || adminRights.manage_call || adminRights.other ? 1 : 0, adminRights, bannedRights, currentRank); - } + finishFragment(); + } + }, () -> { + setLoading(false); + }); } else if (currentType == TYPE_BANNED) { MessagesController.getInstance(currentAccount).setParticipantBannedRole(chatId, currentUser, null, bannedRights, isChannel, getFragmentForAlert(1)); int rights; @@ -938,8 +1104,78 @@ public class ChatRightsEditActivity extends BaseFragment { if (delegate != null) { delegate.didSetRights(rights, adminRights, bannedRights, currentRank); } + } else if (currentType == TYPE_ADD_BOT) { + AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); + builder.setTitle(asAdmin ? + LocaleController.getString("AddBotAdmin", R.string.AddBotAdmin) : + LocaleController.getString("AddBot", R.string.AddBot) + ); + boolean isChannel = ChatObject.isChannel(currentChat) && !currentChat.megagroup; + String chatName = currentChat == null ? "" : currentChat.title; + builder.setMessage(AndroidUtilities.replaceTags( + asAdmin ? ( + isChannel ? + LocaleController.formatString("AddBotMessageAdminChannel", R.string.AddBotMessageAdminChannel, chatName) : + LocaleController.formatString("AddBotMessageAdminGroup", R.string.AddBotMessageAdminGroup, chatName) + ) : LocaleController.formatString("AddMembersAlertNamesText", R.string.AddMembersAlertNamesText, UserObject.getUserName(currentUser), chatName) + )); + builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); + builder.setPositiveButton(asAdmin ? LocaleController.getString("AddAsAdmin", R.string.AddAsAdmin) : LocaleController.getString("AddBot", R.string.AddBot), (di, i) -> { + setLoading(true); + Runnable onFinish = () -> { + if (delegate != null) { + delegate.didSetRights(0, asAdmin ? adminRights : null, null, currentRank); + } + closingKeyboardAfterFinish = true; + + Bundle args1 = new Bundle(); + args1.putBoolean("scrollToTopOnResume", true); + args1.putLong("chat_id", currentChat.id); + if (!getMessagesController().checkCanOpenChat(args1, this)) { + setLoading(false); + return; + } + ChatActivity chatActivity = new ChatActivity(args1); + presentFragment(chatActivity, true); + if (BulletinFactory.canShowBulletin(chatActivity)) { + if (isAddingNew && asAdmin) { + BulletinFactory.createAddedAsAdminBulletin(chatActivity, currentUser.first_name).show(); + } else if (!isAddingNew && !initialAsAdmin && asAdmin) { + BulletinFactory.createPromoteToAdminBulletin(chatActivity, currentUser.first_name).show(); + } + } + }; + if (asAdmin || initialAsAdmin) { + getMessagesController().setUserAdminRole(currentChat.id, currentUser, asAdmin ? adminRights : emptyAdminRights(false), currentRank, false, this, isAddingNew, asAdmin, botHash, onFinish, () -> setLoading(false)); + } else { + getMessagesController().addUserToChat(currentChat.id, currentUser, 0, botHash, this, true, onFinish, () -> setLoading(false)); + } + }); + showDialog(builder.create()); + finishFragment = false; + } + if (finishFragment) { + finishFragment(); + } + } + + private ValueAnimator doneDrawableAnimator; + + public void setLoading(boolean enable) { + if (doneDrawableAnimator != null) { + doneDrawableAnimator.cancel(); + } + loading = !enable; + actionBar.getBackButton().setEnabled(!enable); + if (doneDrawable != null) { + doneDrawableAnimator = ValueAnimator.ofFloat(doneDrawable.getProgress(), enable ? 1f : 0f); + doneDrawableAnimator.addUpdateListener(a -> { + doneDrawable.setProgress((float) a.getAnimatedValue()); + doneDrawable.invalidateSelf(); + }); + doneDrawableAnimator.setDuration((long) (150 * Math.abs(doneDrawable.getProgress() - (enable ? 1 : 0)))); + doneDrawableAnimator.start(); } - finishFragment(); } public void setDelegate(ChatRightsEditActivityDelegate channelRightsEditActivityDelegate) { @@ -947,6 +1183,9 @@ public class ChatRightsEditActivity extends BaseFragment { } private boolean checkDiscard() { + if (currentType == TYPE_ADD_BOT) { + return true; + } boolean changed; if (currentType == TYPE_BANNED) { String newBannedRights = ChatObject.getBannedRightsString(bannedRights); @@ -992,47 +1231,104 @@ public class ChatRightsEditActivity extends BaseFragment { private class ListAdapter extends RecyclerListView.SelectionAdapter { + private final int VIEW_TYPE_USER_CELL = 0; + private final int VIEW_TYPE_INFO_CELL = 1; + private final int VIEW_TYPE_TRANSFER_CELL = 2; + private final int VIEW_TYPE_HEADER_CELL = 3; + private final int VIEW_TYPE_SWITCH_CELL = 4; + private final int VIEW_TYPE_SHADOW_CELL = 5; + private final int VIEW_TYPE_UNTIL_DATE_CELL = 6; + private final int VIEW_TYPE_RANK_CELL = 7; + private final int VIEW_TYPE_ADD_BOT_CELL = 8; + private Context mContext; private boolean ignoreTextChange; public ListAdapter(Context context) { + if (currentType == TYPE_ADD_BOT) { + setHasStableIds(true); + } mContext = context; } + @Override + public long getItemId(int position) { + if (currentType == TYPE_ADD_BOT) { + if (position == manageRow) return 1; + if (position == changeInfoRow) return 2; + if (position == postMessagesRow) return 3; + if (position == editMesagesRow) return 4; + if (position == deleteMessagesRow) return 5; + if (position == addAdminsRow) return 6; + if (position == anonymousRow) return 7; + if (position == banUsersRow) return 8; + if (position == addUsersRow) return 9; + if (position == pinMessagesRow) return 10; + if (position == rightsShadowRow) return 11; + if (position == removeAdminRow) return 12; + if (position == removeAdminShadowRow) return 13; + if (position == cantEditInfoRow) return 14; + if (position == transferOwnerShadowRow) return 15; + if (position == transferOwnerRow) return 16; + if (position == rankHeaderRow) return 17; + if (position == rankRow) return 18; + if (position == rankInfoRow) return 19; + if (position == sendMessagesRow) return 20; + if (position == sendMediaRow) return 21; + if (position == sendStickersRow) return 22; + if (position == sendPollsRow) return 23; + if (position == embedLinksRow) return 24; + if (position == startVoiceChatRow) return 25; + if (position == untilSectionRow) return 26; + if (position == untilDateRow) return 27; + if (position == addBotButtonRow) return 28; + return 0; + } else { + return super.getItemId(position); + } + } + @Override public boolean isEnabled(RecyclerView.ViewHolder holder) { int type = holder.getItemViewType(); - if (currentChat.creator && currentType == TYPE_ADMIN && type == 4 && holder.getAdapterPosition() == anonymousRow) { + if (currentChat.creator && (currentType == TYPE_ADMIN || currentType == TYPE_ADD_BOT && asAdmin) && type == VIEW_TYPE_SWITCH_CELL && holder.getAdapterPosition() == anonymousRow) { return true; } if (!canEdit) { return false; } - if (currentType == TYPE_ADMIN && type == 4) { + if ((currentType == TYPE_ADMIN || currentType == TYPE_ADD_BOT) && type == VIEW_TYPE_SWITCH_CELL) { int position = holder.getAdapterPosition(); - if (position == changeInfoRow) { - return myAdminRights.change_info; - } else if (position == postMessagesRow) { - return myAdminRights.post_messages; - } else if (position == editMesagesRow) { - return myAdminRights.edit_messages; - } else if (position == deleteMessagesRow) { - return myAdminRights.delete_messages; - } else if (position == startVoiceChatRow) { - return myAdminRights.manage_call; - } else if (position == addAdminsRow) { - return myAdminRights.add_admins; - } else if (position == anonymousRow) { - return myAdminRights.anonymous; - } else if (position == banUsersRow) { - return myAdminRights.ban_users; - } else if (position == addUsersRow) { - return myAdminRights.invite_users; - } else if (position == pinMessagesRow) { - return myAdminRights.pin_messages; + if (position == manageRow) { + return myAdminRights.add_admins || (currentChat != null && currentChat.creator); + } else { + if (currentType == TYPE_ADD_BOT && !asAdmin) { + return false; + } + if (position == changeInfoRow) { + return myAdminRights.change_info && (defaultBannedRights == null || defaultBannedRights.change_info); + } else if (position == postMessagesRow) { + return myAdminRights.post_messages; + } else if (position == editMesagesRow) { + return myAdminRights.edit_messages; + } else if (position == deleteMessagesRow) { + return myAdminRights.delete_messages; + } else if (position == startVoiceChatRow) { + return myAdminRights.manage_call; + } else if (position == addAdminsRow) { + return myAdminRights.add_admins; + } else if (position == anonymousRow) { + return myAdminRights.anonymous; + } else if (position == banUsersRow) { + return myAdminRights.ban_users; + } else if (position == addUsersRow) { + return myAdminRights.invite_users; + } else if (position == pinMessagesRow) { + return myAdminRights.pin_messages && (defaultBannedRights == null || defaultBannedRights.pin_messages); + } } } - return type != 3 && type != 1 && type != 5; + return type != VIEW_TYPE_HEADER_CELL && type != VIEW_TYPE_INFO_CELL && type != VIEW_TYPE_SHADOW_CELL && type != VIEW_TYPE_ADD_BOT_CELL; } @Override @@ -1044,36 +1340,112 @@ public class ChatRightsEditActivity extends BaseFragment { public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View view; switch (viewType) { - case 0: + case VIEW_TYPE_USER_CELL: view = new UserCell2(mContext, 4, 0); view.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); break; - case 1: + case VIEW_TYPE_INFO_CELL: view = new TextInfoPrivacyCell(mContext); view.setBackgroundDrawable(Theme.getThemedDrawable(mContext, R.drawable.greydivider_bottom, Theme.key_windowBackgroundGrayShadow)); break; - case 2: + case VIEW_TYPE_TRANSFER_CELL: + default: view = new TextSettingsCell(mContext); view.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); break; - case 3: + case VIEW_TYPE_HEADER_CELL: view = new HeaderCell(mContext, Theme.key_windowBackgroundWhiteBlueHeader, 21, 15, true); view.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); break; - case 4: + case VIEW_TYPE_SWITCH_CELL: view = new TextCheckCell2(mContext); view.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); break; - case 5: + case VIEW_TYPE_SHADOW_CELL: view = new ShadowSectionCell(mContext); break; - case 6: + case VIEW_TYPE_UNTIL_DATE_CELL: view = new TextDetailCell(mContext); view.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); break; - case 7: - default: - PollEditTextCell cell = new PollEditTextCell(mContext, null); + case VIEW_TYPE_ADD_BOT_CELL: + addBotButtonContainer = new FrameLayout(mContext); + addBotButtonContainer.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundGray)); + addBotButton = new FrameLayout(mContext) { + + private TextPaint textPaint; + private StaticLayout mainText; + private StaticLayout asMemberText; + private StaticLayout asAdminText; { + textPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG); + textPaint.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); + textPaint.setTextSize(AndroidUtilities.dp(14)); + textPaint.setColor(0xffffffff); + mainText = new StaticLayout(LocaleController.getString("AddBotButton", R.string.AddBotButton) + " ", textPaint, 9999, Layout.Alignment.ALIGN_NORMAL, 1f, 0f, false); + asMemberText = new StaticLayout(LocaleController.getString("AddBotButtonAsMember", R.string.AddBotButtonAsMember), textPaint, 9999, Layout.Alignment.ALIGN_NORMAL, 1f, 0f, false); + asAdminText = new StaticLayout(LocaleController.getString("AddBotButtonAsAdmin", R.string.AddBotButtonAsAdmin), textPaint, 9999, Layout.Alignment.ALIGN_NORMAL, 1f, 0f, false); + } + + private long lastFrame; + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + + float t = CubicBezierInterpolator.EASE_BOTH.getInterpolation(asAdminT); + + float mainWidth = mainText.getLineWidth(0); + float asWidth; + if (asAdminT <= 0) { + asWidth = asMemberText.getLineWidth(0); + } else if (asAdminT >= 1) { + asWidth = asAdminText.getLineWidth(0); + } else { + asWidth = AndroidUtilities.lerp(asMemberText.getLineWidth(0), asAdminText.getLineWidth(0), t); + } + float width = mainWidth + asWidth; + + canvas.save(); + canvas.translate((getWidth() - width) / 2, (getHeight() - mainText.getHeight()) / 2); + textPaint.setAlpha(255); + mainText.draw(canvas); + canvas.translate(mainWidth, 0); + if (t <= 0) { + asMemberText.draw(canvas); + } else { + canvas.save(); + canvas.translate(0, AndroidUtilities.dp(8) * t); + canvas.scale(1, 1 - 0.2f * t); + textPaint.setAlpha((int) (255 * (1f - t))); + asMemberText.draw(canvas); + canvas.restore(); + } + if (t >= 1) { + textPaint.setAlpha(255); + asAdminText.draw(canvas); + } else { + canvas.save(); + canvas.translate(0, -AndroidUtilities.dp(8) * (1f - t)); + canvas.scale(1, 1 - 0.2f * (1f - t)); + textPaint.setAlpha((int) (255 * t)); + asAdminText.draw(canvas); + canvas.restore(); + } + canvas.restore(); + } + }; + addBotButton.setBackground(Theme.createSimpleSelectorRoundRectDrawable(AndroidUtilities.dp(4), Theme.getColor(Theme.key_featuredStickers_addButton), 0x40ffffff)); + addBotButton.setOnClickListener(e -> onDonePressed()); + addBotButtonContainer.addView(addBotButton, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 48, Gravity.FILL, 14, 28, 14, 14)); + addBotButtonContainer.setLayoutParams(new RecyclerView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)); + View bg = new View(mContext); + bg.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundGray)); + addBotButtonContainer.setClipChildren(false); + addBotButtonContainer.setClipToPadding(false); + addBotButtonContainer.addView(bg, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 800, Gravity.BOTTOM | Gravity.FILL_HORIZONTAL, 0, 0, 0, -800)); + view = addBotButtonContainer; + break; + case VIEW_TYPE_RANK_CELL: + PollEditTextCell cell = rankEditTextCell = new PollEditTextCell(mContext, null); cell.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); cell.addTextWatcher(new TextWatcher() { @Override @@ -1107,11 +1479,15 @@ public class ChatRightsEditActivity extends BaseFragment { @Override public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { switch (holder.getItemViewType()) { - case 0: + case VIEW_TYPE_USER_CELL: UserCell2 userCell2 = (UserCell2) holder.itemView; - userCell2.setData(currentUser, null, null, 0); + String status = null; + if (currentType == TYPE_ADD_BOT) { + status = LocaleController.getString("Bot", R.string.Bot); + } + userCell2.setData(currentUser, null, status, 0); break; - case 1: + case VIEW_TYPE_INFO_CELL: TextInfoPrivacyCell privacyCell = (TextInfoPrivacyCell) holder.itemView; if (position == cantEditInfoRow) { privacyCell.setText(LocaleController.getString("EditAdminCantEdit", R.string.EditAdminCantEdit)); @@ -1125,7 +1501,7 @@ public class ChatRightsEditActivity extends BaseFragment { privacyCell.setText(LocaleController.formatString("EditAdminRankInfo", R.string.EditAdminRankInfo, hint)); } break; - case 2: + case VIEW_TYPE_TRANSFER_CELL: TextSettingsCell actionCell = (TextSettingsCell) holder.itemView; if (position == removeAdminRow) { actionCell.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteRedText5)); @@ -1145,10 +1521,12 @@ public class ChatRightsEditActivity extends BaseFragment { } } break; - case 3: + case VIEW_TYPE_HEADER_CELL: HeaderCell headerCell = (HeaderCell) holder.itemView; if (position == 2) { - if (currentType == TYPE_ADMIN) { + if (currentType == TYPE_ADD_BOT || (currentUser != null && currentUser.bot)) { + headerCell.setText(LocaleController.getString("BotRestrictionsCanDo", R.string.BotRestrictionsCanDo)); + } else if (currentType == TYPE_ADMIN) { headerCell.setText(LocaleController.getString("EditAdminWhatCanDo", R.string.EditAdminWhatCanDo)); } else if (currentType == TYPE_BANNED) { headerCell.setText(LocaleController.getString("UserRestrictionsCanDo", R.string.UserRestrictionsCanDo)); @@ -1157,37 +1535,66 @@ public class ChatRightsEditActivity extends BaseFragment { headerCell.setText(LocaleController.getString("EditAdminRank", R.string.EditAdminRank)); } break; - case 4: + case VIEW_TYPE_SWITCH_CELL: TextCheckCell2 checkCell = (TextCheckCell2) holder.itemView; - if (position == changeInfoRow) { - if (currentType == TYPE_ADMIN) { + boolean asAdminValue = currentType != TYPE_ADD_BOT || asAdmin; + boolean isCreator = (currentChat != null && currentChat.creator); + if (position == manageRow) { + checkCell.setTextAndCheck(LocaleController.getString("ManageGroup", R.string.ManageGroup), asAdmin, true); + checkCell.setIcon(myAdminRights.add_admins || isCreator ? 0 : R.drawable.permission_locked); + } else if (position == changeInfoRow) { + if (currentType == TYPE_ADMIN || currentType == TYPE_ADD_BOT) { if (isChannel) { - checkCell.setTextAndCheck(LocaleController.getString("EditAdminChangeChannelInfo", R.string.EditAdminChangeChannelInfo), adminRights.change_info, true); + checkCell.setTextAndCheck(LocaleController.getString("EditAdminChangeChannelInfo", R.string.EditAdminChangeChannelInfo), asAdminValue && adminRights.change_info || !defaultBannedRights.change_info, true); } else { - checkCell.setTextAndCheck(LocaleController.getString("EditAdminChangeGroupInfo", R.string.EditAdminChangeGroupInfo), adminRights.change_info, true); + checkCell.setTextAndCheck(LocaleController.getString("EditAdminChangeGroupInfo", R.string.EditAdminChangeGroupInfo), asAdminValue && adminRights.change_info || !defaultBannedRights.change_info, true); + } + if (currentType == TYPE_ADD_BOT) { + checkCell.setIcon(myAdminRights.change_info || isCreator ? 0 : R.drawable.permission_locked); } } else if (currentType == TYPE_BANNED) { checkCell.setTextAndCheck(LocaleController.getString("UserRestrictionsChangeInfo", R.string.UserRestrictionsChangeInfo), !bannedRights.change_info && !defaultBannedRights.change_info, false); checkCell.setIcon(defaultBannedRights.change_info ? R.drawable.permission_locked : 0); } } else if (position == postMessagesRow) { - checkCell.setTextAndCheck(LocaleController.getString("EditAdminPostMessages", R.string.EditAdminPostMessages), adminRights.post_messages, true); + checkCell.setTextAndCheck(LocaleController.getString("EditAdminPostMessages", R.string.EditAdminPostMessages), asAdminValue && adminRights.post_messages, true); + if (currentType == TYPE_ADD_BOT) { + checkCell.setIcon(myAdminRights.post_messages || isCreator ? 0 : R.drawable.permission_locked); + } } else if (position == editMesagesRow) { - checkCell.setTextAndCheck(LocaleController.getString("EditAdminEditMessages", R.string.EditAdminEditMessages), adminRights.edit_messages, true); + checkCell.setTextAndCheck(LocaleController.getString("EditAdminEditMessages", R.string.EditAdminEditMessages), asAdminValue && adminRights.edit_messages, true); + if (currentType == TYPE_ADD_BOT) { + checkCell.setIcon(myAdminRights.edit_messages || isCreator ? 0 : R.drawable.permission_locked); + } } else if (position == deleteMessagesRow) { if (isChannel) { - checkCell.setTextAndCheck(LocaleController.getString("EditAdminDeleteMessages", R.string.EditAdminDeleteMessages), adminRights.delete_messages, true); + checkCell.setTextAndCheck(LocaleController.getString("EditAdminDeleteMessages", R.string.EditAdminDeleteMessages), asAdminValue && adminRights.delete_messages, true); } else { - checkCell.setTextAndCheck(LocaleController.getString("EditAdminGroupDeleteMessages", R.string.EditAdminGroupDeleteMessages), adminRights.delete_messages, true); + checkCell.setTextAndCheck(LocaleController.getString("EditAdminGroupDeleteMessages", R.string.EditAdminGroupDeleteMessages), asAdminValue && adminRights.delete_messages, true); + } + if (currentType == TYPE_ADD_BOT) { + checkCell.setIcon(myAdminRights.delete_messages || isCreator ? 0 : R.drawable.permission_locked); } } else if (position == addAdminsRow) { - checkCell.setTextAndCheck(LocaleController.getString("EditAdminAddAdmins", R.string.EditAdminAddAdmins), adminRights.add_admins, anonymousRow != -1); + checkCell.setTextAndCheck(LocaleController.getString("EditAdminAddAdmins", R.string.EditAdminAddAdmins), asAdminValue && adminRights.add_admins, anonymousRow != -1); + if (currentType == TYPE_ADD_BOT) { + checkCell.setIcon(myAdminRights.add_admins || isCreator ? 0 : R.drawable.permission_locked); + } } else if (position == anonymousRow) { - checkCell.setTextAndCheck(LocaleController.getString("EditAdminSendAnonymously", R.string.EditAdminSendAnonymously), adminRights.anonymous, false); + checkCell.setTextAndCheck(LocaleController.getString("EditAdminSendAnonymously", R.string.EditAdminSendAnonymously), asAdminValue && adminRights.anonymous, false); + if (currentType == TYPE_ADD_BOT) { + checkCell.setIcon(myAdminRights.anonymous || isCreator ? 0 : R.drawable.permission_locked); + } } else if (position == banUsersRow) { - checkCell.setTextAndCheck(LocaleController.getString("EditAdminBanUsers", R.string.EditAdminBanUsers), adminRights.ban_users, true); + checkCell.setTextAndCheck(LocaleController.getString("EditAdminBanUsers", R.string.EditAdminBanUsers), asAdminValue && adminRights.ban_users, true); + if (currentType == TYPE_ADD_BOT) { + checkCell.setIcon(myAdminRights.ban_users || isCreator ? 0 : R.drawable.permission_locked); + } } else if (position == startVoiceChatRow) { - checkCell.setTextAndCheck(LocaleController.getString("StartVoipChatPermission", R.string.StartVoipChatPermission), adminRights.manage_call, true); + checkCell.setTextAndCheck(LocaleController.getString("StartVoipChatPermission", R.string.StartVoipChatPermission), asAdminValue && adminRights.manage_call, true); + if (currentType == TYPE_ADD_BOT) { + checkCell.setIcon(myAdminRights.manage_call || isCreator ? 0 : R.drawable.permission_locked); + } } else if (position == addUsersRow) { if (currentType == TYPE_ADMIN) { if (ChatObject.isActionBannedByDefault(currentChat, ChatObject.ACTION_INVITE)) { @@ -1198,10 +1605,16 @@ public class ChatRightsEditActivity extends BaseFragment { } else if (currentType == TYPE_BANNED) { checkCell.setTextAndCheck(LocaleController.getString("UserRestrictionsInviteUsers", R.string.UserRestrictionsInviteUsers), !bannedRights.invite_users && !defaultBannedRights.invite_users, true); checkCell.setIcon(defaultBannedRights.invite_users ? R.drawable.permission_locked : 0); + } else if (currentType == TYPE_ADD_BOT) { + checkCell.setTextAndCheck(LocaleController.getString("EditAdminAddUsersViaLink", R.string.EditAdminAddUsersViaLink), asAdminValue && adminRights.invite_users, true); + checkCell.setIcon(myAdminRights.invite_users || isCreator ? 0 : R.drawable.permission_locked); } } else if (position == pinMessagesRow) { - if (currentType == TYPE_ADMIN) { - checkCell.setTextAndCheck(LocaleController.getString("EditAdminPinMessages", R.string.EditAdminPinMessages), adminRights.pin_messages, true); + if (currentType == TYPE_ADMIN || currentType == TYPE_ADD_BOT) { + checkCell.setTextAndCheck(LocaleController.getString("EditAdminPinMessages", R.string.EditAdminPinMessages), asAdminValue && adminRights.pin_messages || !defaultBannedRights.pin_messages, true); + if (currentType == TYPE_ADD_BOT) { + checkCell.setIcon(myAdminRights.pin_messages || isCreator ? 0 : R.drawable.permission_locked); + } } else if (currentType == TYPE_BANNED) { checkCell.setTextAndCheck(LocaleController.getString("UserRestrictionsPinMessages", R.string.UserRestrictionsPinMessages), !bannedRights.pin_messages && !defaultBannedRights.pin_messages, true); checkCell.setIcon(defaultBannedRights.pin_messages ? R.drawable.permission_locked : 0); @@ -1223,14 +1636,23 @@ public class ChatRightsEditActivity extends BaseFragment { checkCell.setIcon(defaultBannedRights.send_polls ? R.drawable.permission_locked : 0); } - if (position == sendMediaRow || position == sendStickersRow || position == embedLinksRow || position == sendPollsRow) { - checkCell.setEnabled(!bannedRights.send_messages && !bannedRights.view_messages && !defaultBannedRights.send_messages && !defaultBannedRights.view_messages); - } else if (position == sendMessagesRow) { - checkCell.setEnabled(!bannedRights.view_messages && !defaultBannedRights.view_messages); + if (currentType == TYPE_ADD_BOT) { +// checkCell.setEnabled((asAdmin || position == manageRow) && !checkCell.hasIcon(), false); + } else { + if (position == sendMediaRow || position == sendStickersRow || position == embedLinksRow || position == sendPollsRow) { + checkCell.setEnabled(!bannedRights.send_messages && !bannedRights.view_messages && !defaultBannedRights.send_messages && !defaultBannedRights.view_messages); + } else if (position == sendMessagesRow) { + checkCell.setEnabled(!bannedRights.view_messages && !defaultBannedRights.view_messages); + } } break; - case 5: + case VIEW_TYPE_SHADOW_CELL: ShadowSectionCell shadowCell = (ShadowSectionCell) holder.itemView; + if (currentType == TYPE_ADD_BOT && (position == rightsShadowRow || position == rankInfoRow)) { + shadowCell.setAlpha(asAdminT); + } else { + shadowCell.setAlpha(1); + } if (position == rightsShadowRow) { shadowCell.setBackgroundDrawable(Theme.getThemedDrawable(mContext, removeAdminRow == -1 && rankRow == -1 ? R.drawable.greydivider_bottom : R.drawable.greydivider, Theme.key_windowBackgroundGrayShadow)); } else if (position == removeAdminShadowRow) { @@ -1241,7 +1663,7 @@ public class ChatRightsEditActivity extends BaseFragment { shadowCell.setBackgroundDrawable(Theme.getThemedDrawable(mContext, R.drawable.greydivider, Theme.key_windowBackgroundGrayShadow)); } break; - case 6: + case VIEW_TYPE_UNTIL_DATE_CELL: TextDetailCell detailCell = (TextDetailCell) holder.itemView; if (position == untilDateRow) { String value; @@ -1253,7 +1675,7 @@ public class ChatRightsEditActivity extends BaseFragment { detailCell.setTextAndValue(LocaleController.getString("UserRestrictionsDuration", R.string.UserRestrictionsDuration), value, false); } break; - case 7: + case VIEW_TYPE_RANK_CELL: PollEditTextCell textCell = (PollEditTextCell) holder.itemView; String hint; if (UserObject.isUserSelf(currentUser) && currentChat.creator) { @@ -1288,24 +1710,118 @@ public class ChatRightsEditActivity extends BaseFragment { @Override public int getItemViewType(int position) { if (position == 0) { - return 0; + return VIEW_TYPE_USER_CELL; } else if (position == 1 || position == rightsShadowRow || position == removeAdminShadowRow || position == untilSectionRow || position == transferOwnerShadowRow) { - return 5; + return VIEW_TYPE_SHADOW_CELL; } else if (position == 2 || position == rankHeaderRow) { - return 3; + return VIEW_TYPE_HEADER_CELL; } else if (position == changeInfoRow || position == postMessagesRow || position == editMesagesRow || position == deleteMessagesRow || position == addAdminsRow || position == banUsersRow || position == addUsersRow || position == pinMessagesRow || position == sendMessagesRow || position == sendMediaRow || position == sendStickersRow || position == embedLinksRow || - position == sendPollsRow || position == anonymousRow || position == startVoiceChatRow) { - return 4; + position == sendPollsRow || position == anonymousRow || position == startVoiceChatRow || position == manageRow) { + return VIEW_TYPE_SWITCH_CELL; } else if (position == cantEditInfoRow || position == rankInfoRow) { - return 1; + return VIEW_TYPE_INFO_CELL; } else if (position == untilDateRow) { - return 6; + return VIEW_TYPE_UNTIL_DATE_CELL; } else if (position == rankRow) { - return 7; + return VIEW_TYPE_RANK_CELL; + } else if (position == addBotButtonRow) { + return VIEW_TYPE_ADD_BOT_CELL; } else { - return 2; + return VIEW_TYPE_TRANSFER_CELL; + } + } + } + + private ValueAnimator asAdminAnimator; + private void updateAsAdmin(boolean animated) { + if (addBotButton != null) { + addBotButton.invalidate(); + } + final int count = listView.getChildCount(); + for (int i = 0; i < count; ++i) { + View child = listView.getChildAt(i); + int childPosition = listView.getChildAdapterPosition(child); + if (child instanceof TextCheckCell2) { + if (!asAdmin) { + if (childPosition == changeInfoRow && !defaultBannedRights.change_info || + childPosition == pinMessagesRow && !defaultBannedRights.pin_messages) { + ((TextCheckCell2) child).setChecked(true); + ((TextCheckCell2) child).setEnabled(false, false); + } else { + ((TextCheckCell2) child).setChecked(false); + ((TextCheckCell2) child).setEnabled(childPosition == manageRow, animated); + } + } else { + boolean childValue = false, childEnabled = false; + if (childPosition == manageRow) { + childValue = asAdmin; + childEnabled = myAdminRights.add_admins || (currentChat != null && currentChat.creator); + } else if (childPosition == changeInfoRow) { + childValue = adminRights.change_info; + childEnabled = myAdminRights.change_info && defaultBannedRights.change_info; + } else if (childPosition == postMessagesRow) { + childValue = adminRights.post_messages; + childEnabled = myAdminRights.post_messages; + } else if (childPosition == editMesagesRow) { + childValue = adminRights.edit_messages; + childEnabled = myAdminRights.edit_messages; + } else if (childPosition == deleteMessagesRow) { + childValue = adminRights.delete_messages; + childEnabled = myAdminRights.delete_messages; + } else if (childPosition == banUsersRow) { + childValue = adminRights.ban_users; + childEnabled = myAdminRights.ban_users; + } else if (childPosition == addUsersRow) { + childValue = adminRights.invite_users; + childEnabled = myAdminRights.invite_users; + } else if (childPosition == pinMessagesRow) { + childValue = adminRights.pin_messages; + childEnabled = myAdminRights.pin_messages && defaultBannedRights.pin_messages; + } else if (childPosition == startVoiceChatRow) { + childValue = adminRights.manage_call; + childEnabled = myAdminRights.manage_call; + } else if (childPosition == addAdminsRow) { + childValue = adminRights.add_admins; + childEnabled = myAdminRights.add_admins; + } else if (childPosition == anonymousRow) { + childValue = adminRights.anonymous; + childEnabled = myAdminRights.anonymous || (currentChat != null && currentChat.creator); + } + ((TextCheckCell2) child).setChecked(childValue); + ((TextCheckCell2) child).setEnabled(childEnabled, animated); + } + } + } +// listViewAdapter.notifyItemRangeChanged(permissionsStartRow, permissionsEndRow - permissionsStartRow); +// if (asAdmin) { +// listViewAdapter.notifyItemMoved(addBotButtonRow, rightsShadowRow + 1); +// listViewAdapter.notifyItemRangeInserted(rightsShadowRow, rankInfoRow - rightsShadowRow + 1); +// } else { +// listViewAdapter.notifyItemRangeRemoved(rightsShadowRow, rankInfoRow - rightsShadowRow + 1); +// listViewAdapter.notifyItemMoved(addBotButtonRow, permissionsEndRow + 1); +// } + listViewAdapter.notifyDataSetChanged(); + + if (asAdminAnimator != null) { + asAdminAnimator.cancel(); + asAdminAnimator = null; + } + if (animated) { + asAdminAnimator = ValueAnimator.ofFloat(asAdminT, asAdmin ? 1f : 0f); + asAdminAnimator.addUpdateListener(a -> { + asAdminT = (float) a.getAnimatedValue(); + if (addBotButton != null) { + addBotButton.invalidate(); + } + }); + asAdminAnimator.setDuration((long) (Math.abs(asAdminT - (asAdmin ? 1f : 0f)) * 200)); + asAdminAnimator.start(); + } else { + asAdminT = asAdmin ? 1f : 0f; + if (addBotButton != null) { + addBotButton.invalidate(); } } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ChatUsersActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ChatUsersActivity.java index d878e280f..a5b57b345 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ChatUsersActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ChatUsersActivity.java @@ -23,7 +23,6 @@ import android.text.Spanned; import android.text.TextPaint; import android.text.TextUtils; import android.text.style.ForegroundColorSpan; -import android.util.Log; import android.util.SparseIntArray; import android.util.TypedValue; import android.view.Gravity; @@ -86,7 +85,6 @@ import org.telegram.ui.Components.UndoView; import java.util.ArrayList; import java.util.Collections; -import java.util.HashMap; import java.util.concurrent.atomic.AtomicInteger; public class ChatUsersActivity extends BaseFragment implements NotificationCenter.NotificationCenterDelegate { @@ -1045,9 +1043,11 @@ public class ChatUsersActivity extends BaseFragment implements NotificationCente } }); } else if (position == addNew2Row) { - ManageLinksActivity fragment = new ManageLinksActivity(chatId, 0, 0); - fragment.setInfo(info, info.exported_invite); - presentFragment(fragment); + if (info != null) { + ManageLinksActivity fragment = new ManageLinksActivity(chatId, 0, 0); + fragment.setInfo(info, info.exported_invite); + presentFragment(fragment); + } return; } else if (position > permissionsSectionRow && position <= changeInfoRow) { TextCheckCell2 checkCell = (TextCheckCell2) view; @@ -1257,7 +1257,7 @@ public class ChatUsersActivity extends BaseFragment implements NotificationCente bannedRights.invite_users = true; bannedRights.change_info = true; } - ChatRightsEditActivity fragment = new ChatRightsEditActivity(peerId, chatId, adminRights, defaultBannedRights, bannedRights, rank, type == TYPE_ADMIN ? ChatRightsEditActivity.TYPE_ADMIN : ChatRightsEditActivity.TYPE_BANNED, canEdit, participant == null); + ChatRightsEditActivity fragment = new ChatRightsEditActivity(peerId, chatId, adminRights, defaultBannedRights, bannedRights, rank, type == TYPE_ADMIN ? ChatRightsEditActivity.TYPE_ADMIN : ChatRightsEditActivity.TYPE_BANNED, canEdit, participant == null, null); fragment.setDelegate(new ChatRightsEditActivity.ChatRightsEditActivityDelegate() { @Override public void didSetRights(int rights, TLRPC.TL_chatAdminRights rightsAdmin, TLRPC.TL_chatBannedRights rightsBanned, String rank) { @@ -1482,7 +1482,7 @@ public class ChatUsersActivity extends BaseFragment implements NotificationCente private void openRightsEdit2(long peerId, int date, TLObject participant, TLRPC.TL_chatAdminRights adminRights, TLRPC.TL_chatBannedRights bannedRights, String rank, boolean canEditAdmin, int type, boolean removeFragment) { boolean[] needShowBulletin = new boolean[1]; final boolean isAdmin = participant instanceof TLRPC.TL_channelParticipantAdmin || participant instanceof TLRPC.TL_chatParticipantAdmin; - ChatRightsEditActivity fragment = new ChatRightsEditActivity(peerId, chatId, adminRights, defaultBannedRights, bannedRights, rank, type, true, false) { + ChatRightsEditActivity fragment = new ChatRightsEditActivity(peerId, chatId, adminRights, defaultBannedRights, bannedRights, rank, type, true, false, null) { @Override protected void onTransitionAnimationEnd(boolean isOpen, boolean backward) { if (!isOpen && backward && needShowBulletin[0] && BulletinFactory.canShowBulletin(ChatUsersActivity.this)) { @@ -1573,7 +1573,7 @@ public class ChatUsersActivity extends BaseFragment implements NotificationCente } private void openRightsEdit(long user_id, TLObject participant, TLRPC.TL_chatAdminRights adminRights, TLRPC.TL_chatBannedRights bannedRights, String rank, boolean canEditAdmin, int type, boolean removeFragment) { - ChatRightsEditActivity fragment = new ChatRightsEditActivity(user_id, chatId, adminRights, defaultBannedRights, bannedRights, rank, type, canEditAdmin, participant == null); + ChatRightsEditActivity fragment = new ChatRightsEditActivity(user_id, chatId, adminRights, defaultBannedRights, bannedRights, rank, type, canEditAdmin, participant == null, null); fragment.setDelegate(new ChatRightsEditActivity.ChatRightsEditActivityDelegate() { @Override public void didSetRights(int rights, TLRPC.TL_chatAdminRights rightsAdmin, TLRPC.TL_chatBannedRights rightsBanned, String rank) { @@ -1662,7 +1662,7 @@ public class ChatUsersActivity extends BaseFragment implements NotificationCente map.remove(peerId); arrayList.remove(p); updated = true; - if (type == TYPE_BANNED) { + if (type == TYPE_BANNED && info != null) { info.kicked_count--; } } @@ -1870,7 +1870,7 @@ public class ChatUsersActivity extends BaseFragment implements NotificationCente builder.setItems(items, icons, (dialogInterface, i) -> { if (type == TYPE_ADMIN) { if (i == 0 && items.length == 2) { - ChatRightsEditActivity fragment = new ChatRightsEditActivity(peerId, chatId, adminRights, null, null, rank, ChatRightsEditActivity.TYPE_ADMIN, true, false); + ChatRightsEditActivity fragment = new ChatRightsEditActivity(peerId, chatId, adminRights, null, null, rank, ChatRightsEditActivity.TYPE_ADMIN, true, false, null); fragment.setDelegate(new ChatRightsEditActivity.ChatRightsEditActivityDelegate() { @Override public void didSetRights(int rights, TLRPC.TL_chatAdminRights rightsAdmin, TLRPC.TL_chatBannedRights rightsBanned, String rank) { @@ -1890,13 +1890,13 @@ public class ChatUsersActivity extends BaseFragment implements NotificationCente }); presentFragment(fragment); } else { - getMessagesController().setUserAdminRole(chatId, getMessagesController().getUser(peerId), new TLRPC.TL_chatAdminRights(), "", !isChannel, ChatUsersActivity.this, false); + getMessagesController().setUserAdminRole(chatId, getMessagesController().getUser(peerId), new TLRPC.TL_chatAdminRights(), "", !isChannel, ChatUsersActivity.this, false, false, null,null); removeParticipants(peerId); } } else if (type == TYPE_BANNED || type == TYPE_KICKED) { if (i == 0) { if (type == TYPE_KICKED) { - ChatRightsEditActivity fragment = new ChatRightsEditActivity(peerId, chatId, null, defaultBannedRights, bannedRights, rank, ChatRightsEditActivity.TYPE_BANNED, true, false); + ChatRightsEditActivity fragment = new ChatRightsEditActivity(peerId, chatId, null, defaultBannedRights, bannedRights, rank, ChatRightsEditActivity.TYPE_BANNED, true, false, null); fragment.setDelegate(new ChatRightsEditActivity.ChatRightsEditActivityDelegate() { @Override public void didSetRights(int rights, TLRPC.TL_chatAdminRights rightsAdmin, TLRPC.TL_chatBannedRights rightsBanned, String rank) { 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 ca6db7107..b38a4e755 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/AlertsCreator.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/AlertsCreator.java @@ -42,7 +42,6 @@ import android.text.TextUtils; import android.text.TextWatcher; import android.text.style.URLSpan; import android.util.Base64; -import android.util.Log; import android.util.SparseArray; import android.util.TypedValue; import android.view.Gravity; @@ -60,7 +59,9 @@ import android.widget.LinearLayout; import android.widget.TextView; import android.widget.Toast; +import androidx.annotation.RawRes; import androidx.annotation.RequiresApi; +import androidx.core.util.Consumer; import org.telegram.messenger.AccountInstance; import org.telegram.messenger.AndroidUtilities; @@ -119,6 +120,7 @@ import java.util.HashMap; import java.util.List; import java.util.Locale; import java.util.concurrent.CountDownLatch; +import java.util.concurrent.atomic.AtomicBoolean; public class AlertsCreator { public final static int PERMISSIONS_REQUEST_TOP_ICON_SIZE = 72; @@ -168,6 +170,48 @@ public class AlertsCreator { .create(); } + public static Dialog createWebViewPermissionsRequestDialog(Context ctx, Theme.ResourcesProvider resourcesProvider, String[] systemPermissions, @RawRes int animationId, String title, String titleWithHint, Consumer callback) { + boolean showSettings = false; + if (systemPermissions != null && ctx instanceof Activity && Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + Activity activity = (Activity) ctx; + for (String perm : systemPermissions) { + if (activity.checkSelfPermission(perm) != PackageManager.PERMISSION_GRANTED && activity.shouldShowRequestPermissionRationale(perm)) { + showSettings = true; + break; + } + } + } + AtomicBoolean gotCallback = new AtomicBoolean(); + boolean finalShowSettings = showSettings; + return new AlertDialog.Builder(ctx, resourcesProvider) + .setTopAnimation(animationId, AlertsCreator.PERMISSIONS_REQUEST_TOP_ICON_SIZE, false, Theme.getColor(Theme.key_dialogTopBackground)) + .setMessage(AndroidUtilities.replaceTags(showSettings ? titleWithHint : title)) + .setPositiveButton(LocaleController.getString(showSettings ? R.string.PermissionOpenSettings : R.string.BotWebViewRequestAllow), (dialogInterface, i) -> { + if (finalShowSettings) { + try { + Intent intent = new Intent(android.provider.Settings.ACTION_APPLICATION_DETAILS_SETTINGS); + intent.setData(Uri.parse("package:" + ApplicationLoader.applicationContext.getPackageName())); + ctx.startActivity(intent); + } catch (Exception e) { + FileLog.e(e); + } + } else { + gotCallback.set(true); + callback.accept(true); + } + }) + .setNegativeButton(LocaleController.getString(R.string.BotWebViewRequestDontAllow), (dialog, which) -> { + gotCallback.set(true); + callback.accept(false); + }) + .setOnDismissListener(dialog -> { + if (!gotCallback.get()) { + callback.accept(false); + } + }) + .create(); + } + @RequiresApi(api = Build.VERSION_CODES.O) public static Dialog createApkRestrictedDialog(Context ctx, Theme.ResourcesProvider resourcesProvider) { return new AlertDialog.Builder(ctx, resourcesProvider) @@ -884,49 +928,17 @@ public class AlertsCreator { } else if (i == 4) { untilTime = Integer.MAX_VALUE; } - - if (did != 0) { - SharedPreferences preferences = MessagesController.getNotificationsSettings(currentAccount); - SharedPreferences.Editor editor = preferences.edit(); - long flags; - if (i == 4) { - if (!defaultEnabled) { - editor.remove("notify2_" + did); - flags = 0; - } else { - editor.putInt("notify2_" + did, 2); - flags = 1; - } + NotificationsController.getInstance(currentAccount).muteUntil(did, untilTime); + if (did != 0 && resultCallback != null) { + if (i == 4 && !defaultEnabled) { + resultCallback.run(0); } else { - editor.putInt("notify2_" + did, 3); - editor.putInt("notifyuntil_" + did, untilTime); - flags = ((long) untilTime << 32) | 1; - } - NotificationsController.getInstance(currentAccount).removeNotificationsForDialog(did); - MessagesStorage.getInstance(currentAccount).setDialogFlags(did, flags); - editor.commit(); - TLRPC.Dialog dialog = MessagesController.getInstance(currentAccount).dialogs_dict.get(did); - if (dialog != null) { - dialog.notify_settings = new TLRPC.TL_peerNotifySettings(); - if (i != 4 || defaultEnabled) { - dialog.notify_settings.mute_until = untilTime; - } - } - NotificationsController.getInstance(currentAccount).updateServerNotificationsSettings(did); - if (resultCallback != null) { - if (i == 4 && !defaultEnabled) { - resultCallback.run(0); - } else { - resultCallback.run(1); - } - } - } else { - if (i == 4) { - NotificationsController.getInstance(currentAccount).setGlobalNotificationsEnabled(globalType, Integer.MAX_VALUE); - } else { - NotificationsController.getInstance(currentAccount).setGlobalNotificationsEnabled(globalType, untilTime); + resultCallback.run(1); } } + if (did == 0) { + NotificationsController.getInstance(currentAccount).setGlobalNotificationsEnabled(globalType, Integer.MAX_VALUE); + } } if (callback != null) { @@ -1279,20 +1291,20 @@ public class AlertsCreator { fragment.showDialog(alertDialog); } - public static void createClearOrDeleteDialogAlert(BaseFragment fragment, boolean clear, TLRPC.Chat chat, TLRPC.User user, boolean secret, MessagesStorage.BooleanCallback onProcessRunnable) { - createClearOrDeleteDialogAlert(fragment, clear, false, false, chat, user, secret, false, onProcessRunnable, null); + public static void createClearOrDeleteDialogAlert(BaseFragment fragment, boolean clear, TLRPC.Chat chat, TLRPC.User user, boolean secret, boolean canDeleteHistory, MessagesStorage.BooleanCallback onProcessRunnable) { + createClearOrDeleteDialogAlert(fragment, clear, false, false, chat, user, secret, false, canDeleteHistory, onProcessRunnable, null); } - public static void createClearOrDeleteDialogAlert(BaseFragment fragment, boolean clear, TLRPC.Chat chat, TLRPC.User user, boolean secret, boolean checkDeleteForAll, MessagesStorage.BooleanCallback onProcessRunnable) { - createClearOrDeleteDialogAlert(fragment, clear, chat != null && chat.creator, false, chat, user, secret, checkDeleteForAll, onProcessRunnable, null); + public static void createClearOrDeleteDialogAlert(BaseFragment fragment, boolean clear, TLRPC.Chat chat, TLRPC.User user, boolean secret, boolean checkDeleteForAll, boolean canDeleteHistory, MessagesStorage.BooleanCallback onProcessRunnable) { + createClearOrDeleteDialogAlert(fragment, clear, chat != null && chat.creator, false, chat, user, secret, checkDeleteForAll, canDeleteHistory, onProcessRunnable, null); } - public static void createClearOrDeleteDialogAlert(BaseFragment fragment, boolean clear, TLRPC.Chat chat, TLRPC.User user, boolean secret, boolean checkDeleteForAll, MessagesStorage.BooleanCallback onProcessRunnable, Theme.ResourcesProvider resourcesProvider) { - createClearOrDeleteDialogAlert(fragment, clear, chat != null && chat.creator, false, chat, user, secret, checkDeleteForAll, onProcessRunnable, resourcesProvider); + public static void createClearOrDeleteDialogAlert(BaseFragment fragment, boolean clear, TLRPC.Chat chat, TLRPC.User user, boolean secret, boolean checkDeleteForAll, boolean canDeleteHistory, MessagesStorage.BooleanCallback onProcessRunnable, Theme.ResourcesProvider resourcesProvider) { + createClearOrDeleteDialogAlert(fragment, clear, chat != null && chat.creator, false, chat, user, secret, checkDeleteForAll, canDeleteHistory, onProcessRunnable, resourcesProvider); } - public static void createClearOrDeleteDialogAlert(BaseFragment fragment, boolean clear, boolean admin, boolean second, TLRPC.Chat chat, TLRPC.User user, boolean secret, boolean checkDeleteForAll, MessagesStorage.BooleanCallback onProcessRunnable, Theme.ResourcesProvider resourcesProvider) { - if (fragment == null || fragment.getParentActivity() == null || chat == null && user == null) { + public static void createClearOrDeleteDialogAlert(BaseFragment fragment, boolean clear, boolean admin, boolean second, TLRPC.Chat chat, TLRPC.User user, boolean secret, boolean checkDeleteForAll, boolean canDeleteHistory, MessagesStorage.BooleanCallback onProcessRunnable, Theme.ResourcesProvider resourcesProvider) { + if (fragment == null || fragment.getParentActivity() == null || (chat == null && user == null)) { return; } int account = fragment.getCurrentAccount(); @@ -1308,7 +1320,7 @@ public class AlertsCreator { messageTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16); messageTextView.setGravity((LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.TOP); - boolean clearingCache = ChatObject.isChannel(chat) && !TextUtils.isEmpty(chat.username); + boolean clearingCache = !canDeleteHistory && ChatObject.isChannel(chat) && !TextUtils.isEmpty(chat.username); FrameLayout frameLayout = new FrameLayout(context) { @Override @@ -1529,12 +1541,12 @@ public class AlertsCreator { builder.setPositiveButton(actionText, (dialogInterface, i) -> { if (!clearingCache && !second && !secret) { if (UserObject.isUserSelf(user)) { - createClearOrDeleteDialogAlert(fragment, clear, admin, true, chat, user, false, checkDeleteForAll, onProcessRunnable, resourcesProvider); + createClearOrDeleteDialogAlert(fragment, clear, admin, true, chat, user, false, checkDeleteForAll, canDeleteHistory, onProcessRunnable, resourcesProvider); return; } else if (user != null && deleteForAll[0]) { MessagesStorage.getInstance(fragment.getCurrentAccount()).getMessagesCount(user.id, (count) -> { if (count >= 50) { - createClearOrDeleteDialogAlert(fragment, clear, admin, true, chat, user, false, checkDeleteForAll, onProcessRunnable, resourcesProvider); + createClearOrDeleteDialogAlert(fragment, clear, admin, true, chat, user, false, checkDeleteForAll, canDeleteHistory, onProcessRunnable, resourcesProvider); } else { if (onProcessRunnable != null) { onProcessRunnable.run(deleteForAll[0]); @@ -1557,8 +1569,8 @@ public class AlertsCreator { } } - public static void createClearDaysDialogAlert(BaseFragment fragment, int days, TLRPC.User user, MessagesStorage.BooleanCallback onProcessRunnable, Theme.ResourcesProvider resourcesProvider) { - if (fragment == null || fragment.getParentActivity() == null || user == null) { + public static void createClearDaysDialogAlert(BaseFragment fragment, int days, TLRPC.User user, TLRPC.Chat chat, boolean canDeleteHistory, MessagesStorage.BooleanCallback onProcessRunnable, Theme.ResourcesProvider resourcesProvider) { + if (fragment == null || fragment.getParentActivity() == null || (user == null && chat == null)) { return; } int account = fragment.getCurrentAccount(); @@ -1595,18 +1607,40 @@ public class AlertsCreator { textView.setGravity((LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.CENTER_VERTICAL); textView.setEllipsize(TextUtils.TruncateAt.END); - textView.setText(LocaleController.formatPluralString("DeleteDays", days)); - frameLayout.addView(textView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.TOP, 24, 11, 24, 0)); frameLayout.addView(messageTextView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.TOP, 24, 48, 24, 18)); - messageTextView.setText(LocaleController.getString("DeleteHistoryByDaysMessage", R.string.DeleteHistoryByDaysMessage)); + + if (days == -1) { + textView.setText(LocaleController.formatString("ClearHistory", R.string.ClearHistory)); + if (user != null) { + messageTextView.setText(AndroidUtilities.replaceTags(LocaleController.formatString("AreYouSureClearHistoryWithUser", R.string.AreYouSureClearHistoryWithUser, UserObject.getUserName(user)))); + } else { + if (chat != null && canDeleteHistory) { + messageTextView.setText(AndroidUtilities.replaceTags(LocaleController.formatString("AreYouSureClearHistoryWithChat", R.string.AreYouSureClearHistoryWithChat, chat.title))); + } else if (chat.megagroup) { + messageTextView.setText(LocaleController.getString("AreYouSureClearHistoryGroup", R.string.AreYouSureClearHistoryGroup)); + } else { + messageTextView.setText(LocaleController.getString("AreYouSureClearHistoryChannel", R.string.AreYouSureClearHistoryChannel)); + } + } + } else { + textView.setText(LocaleController.formatPluralString("DeleteDays", days)); + messageTextView.setText(LocaleController.getString("DeleteHistoryByDaysMessage", R.string.DeleteHistoryByDaysMessage)); + } final boolean[] deleteForAll = new boolean[]{false}; - if (user.id != selfUserId) { + if (chat != null && canDeleteHistory && !TextUtils.isEmpty(chat.username)) { + deleteForAll[0] = true; + } + if ((user != null && user.id != selfUserId) || (chat != null && canDeleteHistory && TextUtils.isEmpty(chat.username))) { cell[0] = new CheckBoxCell(context, 1, resourcesProvider); cell[0].setBackgroundDrawable(Theme.getSelectorDrawable(false)); - cell[0].setText(LocaleController.formatString("DeleteMessagesOptionAlso", R.string.DeleteMessagesOptionAlso, UserObject.getFirstName(user)), "", false, false); + if (chat != null) { + cell[0].setText(LocaleController.getString("DeleteMessagesOptionAlsoChat", R.string.DeleteMessagesOptionAlsoChat), "", false, false); + } else { + cell[0].setText(LocaleController.formatString("DeleteMessagesOptionAlso", R.string.DeleteMessagesOptionAlso, UserObject.getFirstName(user)), "", false, false); + } cell[0].setPadding(LocaleController.isRTL ? AndroidUtilities.dp(16) : AndroidUtilities.dp(8), 0, LocaleController.isRTL ? AndroidUtilities.dp(8) : AndroidUtilities.dp(16), 0); frameLayout.addView(cell[0], LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 48, Gravity.BOTTOM | Gravity.LEFT, 0, 0, 0, 0)); @@ -2369,9 +2403,9 @@ public class AlertsCreator { dayPicker.setItemCount(count); hourPicker.setItemCount(count); minutePicker.setItemCount(count); - dayPicker.getLayoutParams().height = AndroidUtilities.dp(54) * count; - hourPicker.getLayoutParams().height = AndroidUtilities.dp(54) * count; - minutePicker.getLayoutParams().height = AndroidUtilities.dp(54) * count; + dayPicker.getLayoutParams().height = AndroidUtilities.dp(NumberPicker.DEFAULT_SIZE_PER_COUNT) * count; + hourPicker.getLayoutParams().height = AndroidUtilities.dp(NumberPicker.DEFAULT_SIZE_PER_COUNT) * count; + minutePicker.getLayoutParams().height = AndroidUtilities.dp(NumberPicker.DEFAULT_SIZE_PER_COUNT) * count; ignoreLayout = false; super.onMeasure(widthMeasureSpec, heightMeasureSpec); } @@ -2435,7 +2469,7 @@ public class AlertsCreator { LinearLayout linearLayout = new LinearLayout(context); linearLayout.setOrientation(LinearLayout.HORIZONTAL); linearLayout.setWeightSum(1.0f); - container.addView(linearLayout, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); + container.addView(linearLayout, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, 1f, 0, 0, 12, 0, 12)); long currentTime = System.currentTimeMillis(); Calendar calendar = Calendar.getInstance(); @@ -2589,9 +2623,9 @@ public class AlertsCreator { dayPicker.setItemCount(count); hourPicker.setItemCount(count); minutePicker.setItemCount(count); - dayPicker.getLayoutParams().height = AndroidUtilities.dp(54) * count; - hourPicker.getLayoutParams().height = AndroidUtilities.dp(54) * count; - minutePicker.getLayoutParams().height = AndroidUtilities.dp(54) * count; + dayPicker.getLayoutParams().height = AndroidUtilities.dp(NumberPicker.DEFAULT_SIZE_PER_COUNT) * count; + hourPicker.getLayoutParams().height = AndroidUtilities.dp(NumberPicker.DEFAULT_SIZE_PER_COUNT) * count; + minutePicker.getLayoutParams().height = AndroidUtilities.dp(NumberPicker.DEFAULT_SIZE_PER_COUNT) * count; ignoreLayout = false; super.onMeasure(widthMeasureSpec, heightMeasureSpec); } @@ -2621,7 +2655,7 @@ public class AlertsCreator { LinearLayout linearLayout = new LinearLayout(context); linearLayout.setOrientation(LinearLayout.HORIZONTAL); linearLayout.setWeightSum(1.0f); - container.addView(linearLayout, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); + container.addView(linearLayout, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, 1f, 0, 0, 12, 0, 12)); long currentTime = System.currentTimeMillis(); Calendar calendar = Calendar.getInstance(); @@ -2720,6 +2754,483 @@ public class AlertsCreator { return builder; } + public static BottomSheet.Builder createAutoDeleteDatePickerDialog(Context context, final ScheduleDatePickerDelegate datePickerDelegate) { + if (context == null) { + return null; + } + + ScheduleDatePickerColors datePickerColors = new ScheduleDatePickerColors(); + BottomSheet.Builder builder = new BottomSheet.Builder(context, false); + builder.setApplyBottomPadding(false); + + int[] values = new int[]{ + 0, + 60 * 24, + 2 * 60 * 24, + 3 * 60 * 24, + 4 * 60 * 24, + 5 * 60 * 24, + 6 * 60 * 24, + 7 * 60 * 24, + 2 * 7 * 60 * 24, + 3 * 7 * 60 * 24, + 31 * 60 * 24, + 2 * 31 * 60 * 24, + 3 * 31 * 60 * 24, + 4 * 31 * 60 * 24, + 5 * 31 * 60 * 24, + 6 * 31 * 60 * 24, + 365 * 60 * 24 + }; + + final NumberPicker numberPicker = new NumberPicker(context) { + @Override + protected CharSequence getContentDescription(int index) { + if (values[index] == 0) { + return LocaleController.getString("AutoDeleteNever", R.string.AutoDeleteNever); + } else if (values[index] < 7 * 60 * 24) { + return LocaleController.formatPluralString("Days", values[index] / (60 * 24)); + } else if (values[index] < 31 * 60 * 24) { + return LocaleController.formatPluralString("Weeks", values[index] / (60 * 24)); + } else if (values[index] < 365 * 60 * 24) { + return LocaleController.formatPluralString("Months", values[index] / (7 * 60 * 24)); + } else { + return LocaleController.formatPluralString("Years", values[index] * 5 / 31 * 60 * 24); + } + } + }; + numberPicker.setMinValue(0); + numberPicker.setMaxValue(values.length - 1); + numberPicker.setTextColor(datePickerColors.textColor); + numberPicker.setValue(0); + numberPicker.setWrapSelectorWheel(false); + numberPicker.setFormatter(index -> { + if (values[index] == 0) { + return LocaleController.getString("AutoDeleteNever", R.string.AutoDeleteNever); + } else if (values[index] < 7 * 60 * 24) { + return LocaleController.formatPluralString("Days", values[index] / (60 * 24)); + } else if (values[index] < 31 * 60 * 24) { + return LocaleController.formatPluralString("Weeks", values[index] / (7 * 60 * 24)); + } else if (values[index] < 365 * 60 * 24) { + return LocaleController.formatPluralString("Months", values[index] / (31 * 60 * 24)); + } else { + return LocaleController.formatPluralString("Years", values[index] / (365 * 60 * 24)); + } + }); + + LinearLayout container = new LinearLayout(context) { + + boolean ignoreLayout = false; + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + ignoreLayout = true; + int count; + if (AndroidUtilities.displaySize.x > AndroidUtilities.displaySize.y) { + count = 3; + } else { + count = 5; + } + numberPicker.setItemCount(count); + numberPicker.getLayoutParams().height = AndroidUtilities.dp(NumberPicker.DEFAULT_SIZE_PER_COUNT) * count; + ignoreLayout = false; + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + } + + @Override + public void requestLayout() { + if (ignoreLayout) { + return; + } + super.requestLayout(); + } + }; + container.setOrientation(LinearLayout.VERTICAL); + + FrameLayout titleLayout = new FrameLayout(context); + container.addView(titleLayout, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.LEFT | Gravity.TOP, 22, 0, 0, 4)); + + TextView titleView = new TextView(context); + titleView.setText(LocaleController.getString("AutoDeleteAfteTitle", R.string.AutoDeleteAfteTitle)); + + titleView.setTextColor(datePickerColors.textColor); + titleView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 20); + titleView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); + titleLayout.addView(titleView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.LEFT | Gravity.TOP, 0, 12, 0, 0)); + titleView.setOnTouchListener((v, event) -> true); + + LinearLayout linearLayout = new LinearLayout(context); + linearLayout.setOrientation(LinearLayout.HORIZONTAL); + linearLayout.setWeightSum(1.0f); + container.addView(linearLayout, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, 1f, 0, 0, 12, 0, 12)); + + TextView buttonTextView = new TextView(context) { + @Override + public CharSequence getAccessibilityClassName() { + return Button.class.getName(); + } + }; + + linearLayout.addView(numberPicker, LayoutHelper.createLinear(0, 54 * 5, 1f)); + + buttonTextView.setPadding(AndroidUtilities.dp(34), 0, AndroidUtilities.dp(34), 0); + buttonTextView.setGravity(Gravity.CENTER); + 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.setText(LocaleController.getString("AutoDeleteConfirm", R.string.AutoDeleteConfirm)); + container.addView(buttonTextView, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 48, Gravity.LEFT | Gravity.BOTTOM, 16, 15, 16, 16)); + + final NumberPicker.OnValueChangeListener onValueChangeListener = (picker, oldVal, newVal) -> { + try { + container.performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP, HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING); + } catch (Exception ignore) { + + } + }; + numberPicker.setOnValueChangedListener(onValueChangeListener); + + buttonTextView.setOnClickListener(v -> { + int time = values[numberPicker.getValue()]; + datePickerDelegate.didSelectDate(true, time); + builder.getDismissRunnable().run(); + }); + + builder.setCustomView(container); + BottomSheet bottomSheet = builder.show(); + bottomSheet.setBackgroundColor(datePickerColors.backgroundColor); + return builder; + } + + public static BottomSheet.Builder createSoundFrequencyPickerDialog(Context context, int notifyMaxCount, int notifyDelay, final SoundFrequencyDelegate delegate) { + if (context == null) { + return null; + } + + ScheduleDatePickerColors datePickerColors = new ScheduleDatePickerColors(); + BottomSheet.Builder builder = new BottomSheet.Builder(context, false); + builder.setApplyBottomPadding(false); + + final NumberPicker times = new NumberPicker(context) { + @Override + protected CharSequence getContentDescription(int index) { + return LocaleController.formatPluralString("Times", index + 1); + } + }; + times.setMinValue(0); + times.setMaxValue(10); + times.setTextColor(datePickerColors.textColor); + times.setValue(notifyMaxCount - 1); + times.setWrapSelectorWheel(false); + times.setFormatter(index -> LocaleController.formatPluralString("Times", index + 1)); + + final NumberPicker minutes = new NumberPicker(context) { + @Override + protected CharSequence getContentDescription(int index) { + return LocaleController.formatPluralString("Times", index + 1); + } + }; + minutes.setMinValue(0); + minutes.setMaxValue(10); + minutes.setTextColor(datePickerColors.textColor); + minutes.setValue(notifyDelay / 60 - 1); + minutes.setWrapSelectorWheel(false); + minutes.setFormatter(index -> LocaleController.formatPluralString("Minutes", index + 1)); + + NumberPicker divider = new NumberPicker(context); + divider.setMinValue(0); + divider.setMaxValue(0); + divider.setTextColor(datePickerColors.textColor); + divider.setValue(0); + divider.setWrapSelectorWheel(false); + divider.setFormatter(index -> LocaleController.getString("NotificationsFrequencyDivider", R.string.NotificationsFrequencyDivider)); + + LinearLayout container = new LinearLayout(context) { + + boolean ignoreLayout = false; + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + ignoreLayout = true; + int count; + if (AndroidUtilities.displaySize.x > AndroidUtilities.displaySize.y) { + count = 3; + } else { + count = 5; + } + times.setItemCount(count); + times.getLayoutParams().height = AndroidUtilities.dp(NumberPicker.DEFAULT_SIZE_PER_COUNT) * count; + minutes.setItemCount(count); + minutes.getLayoutParams().height = AndroidUtilities.dp(NumberPicker.DEFAULT_SIZE_PER_COUNT) * count; + divider.setItemCount(count); + divider.getLayoutParams().height = AndroidUtilities.dp(NumberPicker.DEFAULT_SIZE_PER_COUNT) * count; + ignoreLayout = false; + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + } + + @Override + public void requestLayout() { + if (ignoreLayout) { + return; + } + super.requestLayout(); + } + }; + container.setOrientation(LinearLayout.VERTICAL); + + FrameLayout titleLayout = new FrameLayout(context); + container.addView(titleLayout, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.LEFT | Gravity.TOP, 22, 0, 0, 4)); + + TextView titleView = new TextView(context); + titleView.setText(LocaleController.getString("NotfificationsFrequencyTitle", R.string.NotfificationsFrequencyTitle)); + + titleView.setTextColor(datePickerColors.textColor); + titleView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 20); + titleView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); + titleLayout.addView(titleView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.LEFT | Gravity.TOP, 0, 12, 0, 0)); + titleView.setOnTouchListener((v, event) -> true); + + LinearLayout linearLayout = new LinearLayout(context); + linearLayout.setOrientation(LinearLayout.HORIZONTAL); + linearLayout.setWeightSum(1.0f); + container.addView(linearLayout, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, 1f, 0, 0, 12, 0, 12)); + + TextView buttonTextView = new TextView(context) { + @Override + public CharSequence getAccessibilityClassName() { + return Button.class.getName(); + } + }; + + linearLayout.addView(times, LayoutHelper.createLinear(0, 54 * 5, 0.4f)); + linearLayout.addView(divider, LayoutHelper.createLinear(0, LayoutHelper.WRAP_CONTENT, 0.2f, Gravity.CENTER_VERTICAL)); + linearLayout.addView(minutes, LayoutHelper.createLinear(0, 54 * 5, 0.4f)); + + buttonTextView.setPadding(AndroidUtilities.dp(34), 0, AndroidUtilities.dp(34), 0); + buttonTextView.setGravity(Gravity.CENTER); + 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.setText(LocaleController.getString("AutoDeleteConfirm", R.string.AutoDeleteConfirm)); + container.addView(buttonTextView, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 48, Gravity.LEFT | Gravity.BOTTOM, 16, 15, 16, 16)); + + final NumberPicker.OnValueChangeListener onValueChangeListener = (picker, oldVal, newVal) -> { + try { + container.performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP, HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING); + } catch (Exception ignore) { + + } + }; + times.setOnValueChangedListener(onValueChangeListener); + minutes.setOnValueChangedListener(onValueChangeListener); + + buttonTextView.setOnClickListener(v -> { + int time = times.getValue() + 1; + int minute = (minutes.getValue() + 1) * 60; + delegate.didSelectValues(time, minute); + builder.getDismissRunnable().run(); + }); + + builder.setCustomView(container); + BottomSheet bottomSheet = builder.show(); + bottomSheet.setBackgroundColor(datePickerColors.backgroundColor); + return builder; + } + + public static BottomSheet.Builder createMuteForPickerDialog(Context context, final ScheduleDatePickerDelegate datePickerDelegate) { + if (context == null) { + return null; + } + + ScheduleDatePickerColors datePickerColors = new ScheduleDatePickerColors(); + BottomSheet.Builder builder = new BottomSheet.Builder(context, false); + builder.setApplyBottomPadding(false); + + final NumberPicker dayPicker = new NumberPicker(context); + dayPicker.setTextColor(datePickerColors.textColor); + dayPicker.setTextOffset(AndroidUtilities.dp(10)); + dayPicker.setItemCount(5); + final NumberPicker hourPicker = new NumberPicker(context) { + @Override + protected CharSequence getContentDescription(int value) { + return LocaleController.formatPluralString("Hours", value); + } + }; + hourPicker.setItemCount(5); + hourPicker.setTextColor(datePickerColors.textColor); + + LinearLayout container = new LinearLayout(context) { + + boolean ignoreLayout = false; + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + ignoreLayout = true; + int count; + if (AndroidUtilities.displaySize.x > AndroidUtilities.displaySize.y) { + count = 3; + } else { + count = 5; + } + dayPicker.setItemCount(count); + hourPicker.setItemCount(count); + dayPicker.getLayoutParams().height = AndroidUtilities.dp(NumberPicker.DEFAULT_SIZE_PER_COUNT) * count; + hourPicker.getLayoutParams().height = AndroidUtilities.dp(NumberPicker.DEFAULT_SIZE_PER_COUNT) * count; + ignoreLayout = false; + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + } + + @Override + public void requestLayout() { + if (ignoreLayout) { + return; + } + super.requestLayout(); + } + }; + container.setOrientation(LinearLayout.VERTICAL); + + FrameLayout titleLayout = new FrameLayout(context); + container.addView(titleLayout, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.LEFT | Gravity.TOP, 22, 0, 0, 4)); + + TextView titleView = new TextView(context); + titleView.setText(LocaleController.getString("MuteForAlert", R.string.MuteForAlert)); + titleView.setTextColor(datePickerColors.textColor); + titleView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 20); + titleView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); + titleLayout.addView(titleView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.LEFT | Gravity.TOP, 0, 12, 0, 0)); + titleView.setOnTouchListener((v, event) -> true); + + LinearLayout linearLayout = new LinearLayout(context); + linearLayout.setOrientation(LinearLayout.HORIZONTAL); + linearLayout.setWeightSum(1.0f); + container.addView(linearLayout, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, 1f, 0, 0, 12, 0, 12)); + + TextView buttonTextView = new TextView(context) { + @Override + public CharSequence getAccessibilityClassName() { + return Button.class.getName(); + } + }; + + linearLayout.addView(dayPicker, LayoutHelper.createLinear(0, 54 * 5, 0.5f)); + dayPicker.setMinValue(0); + dayPicker.setMaxValue(365); + dayPicker.setWrapSelectorWheel(false); + dayPicker.setFormatter(value -> LocaleController.formatPluralString("Days", value)); + final NumberPicker.OnValueChangeListener onValueChangeListener = (picker, oldVal, newVal) -> { + try { + container.performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP, HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING); + } catch (Exception ignore) { + + } + checkMuteForButton(dayPicker, hourPicker, buttonTextView, true); + }; + dayPicker.setOnValueChangedListener(onValueChangeListener); + + hourPicker.setMinValue(0); + hourPicker.setMaxValue(23); + linearLayout.addView(hourPicker, LayoutHelper.createLinear(0, 54 * 5, 0.5f)); + hourPicker.setFormatter(value -> LocaleController.formatPluralString("Hours", value)); + hourPicker.setOnValueChangedListener(onValueChangeListener); + + buttonTextView.setPadding(AndroidUtilities.dp(34), 0, AndroidUtilities.dp(34), 0); + buttonTextView.setGravity(Gravity.CENTER); + 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.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 -> { + int time = hourPicker.getValue() * 60 + dayPicker.getValue() * 60 * 24; + datePickerDelegate.didSelectDate(true, time); + builder.getDismissRunnable().run(); + }); + + builder.setCustomView(container); + BottomSheet bottomSheet = builder.show(); + bottomSheet.setBackgroundColor(datePickerColors.backgroundColor); + checkMuteForButton(dayPicker, hourPicker, buttonTextView, false); + return builder; + } + + private static void checkMuteForButton(NumberPicker dayPicker, NumberPicker hourPicker, TextView buttonTextView, boolean animated) { + StringBuilder stringBuilder = new StringBuilder(); + if (dayPicker.getValue() != 0) { + stringBuilder.append(dayPicker.getValue()).append(LocaleController.getString("SecretChatTimerDays", R.string.SecretChatTimerDays)); + } + if (hourPicker.getValue() != 0) { + if (stringBuilder.length() > 0) { + stringBuilder.append(" "); + } + stringBuilder.append(hourPicker.getValue()).append(LocaleController.getString("SecretChatTimerHours", R.string.SecretChatTimerHours)); + } + if (stringBuilder.length() == 0) { + buttonTextView.setText(LocaleController.getString("ChooseTimeForMute", R.string.ChooseTimeForMute)); + if (buttonTextView.isEnabled()) { + buttonTextView.setEnabled(false); + if (animated) { + buttonTextView.animate().alpha(0.5f); + } else { + buttonTextView.setAlpha(0.5f); + } + } + } else { + buttonTextView.setText(LocaleController.formatString("MuteForButton", R.string.MuteForButton, stringBuilder.toString())); + if (!buttonTextView.isEnabled()) { + buttonTextView.setEnabled(true); + if (animated) { + buttonTextView.animate().alpha(1f); + } else { + buttonTextView.setAlpha(1f); + } + } + } + } + + private static void checkAutoDeleteButton(NumberPicker dayPicker, NumberPicker hourPicker, NumberPicker minutePicker, TextView buttonTextView, boolean animated) { + StringBuilder stringBuilder = new StringBuilder(); + if (dayPicker.getValue() != 0) { + stringBuilder.append(dayPicker.getValue()).append(LocaleController.getString("SecretChatTimerDays", R.string.SecretChatTimerDays)); + } + if (hourPicker.getValue() != 0) { + if (stringBuilder.length() > 0) { + stringBuilder.append(" "); + } + stringBuilder.append(hourPicker.getValue()).append(LocaleController.getString("SecretChatTimerHours", R.string.SecretChatTimerHours)); + } + if (minutePicker.getValue() != 0) { + if (stringBuilder.length() > 0) { + stringBuilder.append(" "); + } + stringBuilder.append(minutePicker.getValue() * 5).append(LocaleController.getString("SecretChatTimerMinutes", R.string.SecretChatTimerMinutes)); + } + if (stringBuilder.length() == 0) { + buttonTextView.setText(LocaleController.formatString("ChooseTimeForAutoDelete", R.string.ChooseTimeForAutoDelete)); + if (buttonTextView.isEnabled()) { + buttonTextView.setEnabled(false); + if (animated) { + buttonTextView.animate().alpha(0.5f); + } else { + buttonTextView.setAlpha(0.5f); + } + } + } else { + buttonTextView.setText(LocaleController.formatString("AutoDeleteAfter", R.string.AutoDeleteAfter, stringBuilder.toString())); + if (!buttonTextView.isEnabled()) { + buttonTextView.setEnabled(true); + if (animated) { + buttonTextView.animate().alpha(1f); + } else { + buttonTextView.setAlpha(1f); + } + } + } + } + private static void checkCalendarDate(long minDate, NumberPicker dayPicker, NumberPicker monthPicker, NumberPicker yearPicker) { int day = dayPicker.getValue(); int month = monthPicker.getValue(); @@ -2808,9 +3319,9 @@ public class AlertsCreator { dayPicker.setItemCount(count); monthPicker.setItemCount(count); yearPicker.setItemCount(count); - dayPicker.getLayoutParams().height = AndroidUtilities.dp(54) * count; - monthPicker.getLayoutParams().height = AndroidUtilities.dp(54) * count; - yearPicker.getLayoutParams().height = AndroidUtilities.dp(54) * count; + dayPicker.getLayoutParams().height = AndroidUtilities.dp(NumberPicker.DEFAULT_SIZE_PER_COUNT) * count; + monthPicker.getLayoutParams().height = AndroidUtilities.dp(NumberPicker.DEFAULT_SIZE_PER_COUNT) * count; + yearPicker.getLayoutParams().height = AndroidUtilities.dp(NumberPicker.DEFAULT_SIZE_PER_COUNT) * count; ignoreLayout = false; super.onMeasure(widthMeasureSpec, heightMeasureSpec); } @@ -2839,7 +3350,7 @@ public class AlertsCreator { LinearLayout linearLayout = new LinearLayout(context); linearLayout.setOrientation(LinearLayout.HORIZONTAL); linearLayout.setWeightSum(1.0f); - container.addView(linearLayout, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); + container.addView(linearLayout, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, 1f, 0, 0, 12, 0, 12)); long currentTime = System.currentTimeMillis(); @@ -2981,7 +3492,7 @@ public class AlertsCreator { } NotificationsController.getInstance(UserConfig.selectedAccount).setDialogNotificationsSettings(dialog_id, setting); if (BulletinFactory.canShowBulletin(fragment)) { - BulletinFactory.createMuteBulletin(fragment, setting, resourcesProvider).show(); + BulletinFactory.createMuteBulletin(fragment, setting, 0, resourcesProvider).show(); } } ); @@ -4169,42 +4680,6 @@ public class AlertsCreator { return alertDialog[0] = builder.create(); } -// public static AlertDialog createExpireDateAlert(final Context context, final boolean month, final int[] result, final Runnable callback) { -// AlertDialog.Builder builder = new AlertDialog.Builder(context); -// builder.setTitle(month ? LocaleController.getString("PaymentCardExpireDateMonth", R.string.PaymentCardExpireDateMonth) : LocaleController.getString("PaymentCardExpireDateYear", R.string.PaymentCardExpireDateYear)); -// final NumberPicker numberPicker = new NumberPicker(context); -// final int currentYear; -// if (month) { -// numberPicker.setMinValue(1); -// numberPicker.setMaxValue(12); -// currentYear = 0; -// } else { -// Calendar rightNow = Calendar.getInstance(); -// currentYear = rightNow.get(Calendar.YEAR); -// numberPicker.setMinValue(0); -// numberPicker.setMaxValue(30); -// } -// numberPicker.setFormatter(new NumberPicker.Formatter() { -// @Override -// public String format(int value) { -// if (month) { -// return String.format(Locale.US, "%02d", value); -// } else { -// return String.format(Locale.US, "%02d", value + currentYear); -// } -// } -// }); -// builder.setView(numberPicker); -// builder.setNegativeButton(LocaleController.getString("Done", R.string.Done), new DialogInterface.OnClickListener() { -// @Override -// public void onClick(DialogInterface dialog, int which) { -// result[0] = month ? numberPicker.getValue() : ((numberPicker.getValue() + currentYear) % 100); -// callback.run(); -// } -// }); -// return builder.create(); -// } - public interface PaymentAlertDelegate { void didPressedNewCard(); } @@ -4220,7 +4695,7 @@ public class AlertsCreator { int currentAccount = fragment.getCurrentAccount(); AlertDialog.Builder builder = new AlertDialog.Builder(activity, resourcesProvider); - builder.setDimEnabled(hideDim == null); + builder.setDimAlpha(hideDim != null ? .5f : .6f); int count; if (selectedGroup != null) { count = selectedGroup.messages.size(); @@ -5092,4 +5567,8 @@ public class AlertsCreator { }); return popupWindow; } + + public interface SoundFrequencyDelegate { + void didSelectValues(int time, int minute); + } } 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 0fcc486b9..47cf91eab 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/AnimatedFileDrawable.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/AnimatedFileDrawable.java @@ -136,18 +136,6 @@ public class AnimatedFileDrawable extends BitmapDrawable implements Animatable { private static ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(8, new ThreadPoolExecutor.DiscardPolicy()); - protected final Runnable mInvalidateTask = () -> { - invalidateTaskIsRunning = false; - if (!secondParentViews.isEmpty()) { - for (int a = 0, N = secondParentViews.size(); a < N; a++) { - secondParentViews.get(a).invalidate(); - } - } - if ((secondParentViews.isEmpty() || invalidateParentViewWithSecond) && parentView != null) { - parentView.invalidate(); - } - }; - private Runnable uiRunnableNoFrame = new Runnable() { @Override public void run() { @@ -832,4 +820,12 @@ public class AnimatedFileDrawable extends BitmapDrawable implements Animatable { public boolean isRecycled() { return isRecycled; } + + public Bitmap getNextFrame() { + if (backgroundBitmap == null) { + backgroundBitmap = Bitmap.createBitmap((int) (metaData[0] * scaleFactor), (int) (metaData[1] * scaleFactor), Bitmap.Config.ARGB_8888); + } + getVideoFrame(nativePtr, backgroundBitmap, metaData, backgroundBitmap.getRowBytes(), false, startTime, endTime) ; + return backgroundBitmap; + } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/AnimationProperties.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/AnimationProperties.java index e8cebf3b5..c07ae1882 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/AnimationProperties.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/AnimationProperties.java @@ -53,6 +53,18 @@ public class AnimationProperties { } }; + public static final Property PAINT_COLOR = new IntProperty("color") { + @Override + public void setValue(Paint object, int value) { + object.setColor(value); + } + + @Override + public Integer get(Paint object) { + return object.getColor(); + } + }; + public static final Property COLOR_DRAWABLE_ALPHA = new IntProperty("alpha") { @Override public void setValue(ColorDrawable object, int value) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/AttachBotIntroTopView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/AttachBotIntroTopView.java new file mode 100644 index 000000000..875acaf2a --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/AttachBotIntroTopView.java @@ -0,0 +1,101 @@ +package org.telegram.ui.Components; + +import android.animation.ValueAnimator; +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.PorterDuff; +import android.graphics.PorterDuffColorFilter; +import android.graphics.drawable.Drawable; +import android.view.View; + +import androidx.core.content.ContextCompat; + +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.DocumentObject; +import org.telegram.messenger.ImageLocation; +import org.telegram.messenger.ImageReceiver; +import org.telegram.messenger.MediaDataController; +import org.telegram.messenger.R; +import org.telegram.tgnet.TLRPC; +import org.telegram.ui.ActionBar.Theme; + +public class AttachBotIntroTopView extends View { + private final static int ICONS_SIZE_DP = 42; + private final static int ICONS_SIDE_PADDING = 24; + + private ImageReceiver imageReceiver; + private Drawable attachDrawable; + private Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG); + private Paint backgroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + + public AttachBotIntroTopView(Context context) { + super(context); + + imageReceiver = new ImageReceiver(this) { + @Override + protected boolean setImageBitmapByKey(Drawable drawable, String key, int type, boolean memCache, int guid) { + boolean set = super.setImageBitmapByKey(drawable, key, type, memCache, guid); + ValueAnimator anim = ValueAnimator.ofFloat(0, 1).setDuration(150); + anim.addUpdateListener(animation -> { + imageReceiver.setAlpha((Float) animation.getAnimatedValue()); + invalidate(); + }); + anim.start(); + return set; + } + }; + imageReceiver.setAlpha(0); + + attachDrawable = ContextCompat.getDrawable(context, R.drawable.input_attach).mutate().getConstantState().newDrawable(); + paint.setStyle(Paint.Style.STROKE); + paint.setStrokeWidth(AndroidUtilities.dp(3)); + paint.setStrokeCap(Paint.Cap.ROUND); + } + + public void setAttachBot(TLRPC.TL_attachMenuBot bot) { + TLRPC.TL_attachMenuBotIcon icon = MediaDataController.getStaticAttachMenuBotIcon(bot); + if (icon != null) { + imageReceiver.setImage(ImageLocation.getForDocument(icon.icon), "42_42", DocumentObject.getSvgThumb(icon.icon, Theme.key_dialogTextGray2, 1.0f), "svg", bot, 0); + } + } + + public void setBackgroundColor(int color) { + backgroundPaint.setColor(color); + } + + public void setColor(int color) { + attachDrawable.setColorFilter(color, PorterDuff.Mode.SRC_IN); + paint.setColor(color); + imageReceiver.setColorFilter(new PorterDuffColorFilter(color, PorterDuff.Mode.SRC_IN)); + } + + @Override + protected void onAttachedToWindow() { + super.onAttachedToWindow(); + imageReceiver.onAttachedToWindow(); + } + + @Override + protected void onDetachedFromWindow() { + super.onDetachedFromWindow(); + imageReceiver.onDetachedFromWindow(); + } + + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + + AndroidUtilities.rectTmp.set(0, 0, getWidth(), getHeight() + AndroidUtilities.dp(6)); + canvas.drawRoundRect(AndroidUtilities.rectTmp, AndroidUtilities.dp(6), AndroidUtilities.dp(6), backgroundPaint); + + imageReceiver.setImageCoords(getWidth() / 2f - AndroidUtilities.dp(ICONS_SIDE_PADDING + ICONS_SIZE_DP), getHeight() / 2f - AndroidUtilities.dp(ICONS_SIZE_DP) / 2f, AndroidUtilities.dp(ICONS_SIZE_DP), AndroidUtilities.dp(ICONS_SIZE_DP)); + imageReceiver.draw(canvas); + + canvas.drawLine(getWidth() / 2f - AndroidUtilities.dp(8), getHeight() / 2f, getWidth() / 2f + AndroidUtilities.dp(8), getHeight() / 2f, paint); + canvas.drawLine(getWidth() / 2f, getHeight() / 2f - AndroidUtilities.dp(8), getWidth() / 2f, getHeight() / 2f + AndroidUtilities.dp(8), paint); + + attachDrawable.setBounds(getWidth() / 2 + AndroidUtilities.dp(ICONS_SIDE_PADDING), getHeight() / 2 - AndroidUtilities.dp(ICONS_SIZE_DP) / 2, getWidth() / 2 + AndroidUtilities.dp(ICONS_SIDE_PADDING + ICONS_SIZE_DP), getHeight() / 2 + AndroidUtilities.dp(ICONS_SIZE_DP) / 2); + attachDrawable.draw(canvas); + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/AutoDeletePopupWrapper.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/AutoDeletePopupWrapper.java new file mode 100644 index 000000000..b526a38b4 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/AutoDeletePopupWrapper.java @@ -0,0 +1,105 @@ +package org.telegram.ui.Components; + +import android.content.Context; +import android.util.TypedValue; +import android.view.View; +import android.widget.FrameLayout; +import android.widget.TextView; + +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.LocaleController; +import org.telegram.messenger.R; +import org.telegram.ui.ActionBar.ActionBarMenuItem; +import org.telegram.ui.ActionBar.ActionBarMenuSubItem; +import org.telegram.ui.ActionBar.ActionBarPopupWindow; +import org.telegram.ui.ActionBar.Theme; + +public class AutoDeletePopupWrapper { + + View backItem; + public ActionBarPopupWindow.ActionBarPopupWindowLayout windowLayout; + private final ActionBarMenuSubItem disableItem; + Callback callback; + long lastDismissTime; + + public AutoDeletePopupWrapper(Context context, PopupSwipeBackLayout swipeBackLayout, Callback callback, boolean createBackground, Theme.ResourcesProvider resourcesProvider) { + windowLayout = new ActionBarPopupWindow.ActionBarPopupWindowLayout(context, createBackground ? R.drawable.popup_fixed_alert : 0, resourcesProvider); + windowLayout.setFitItems(true); + this.callback = callback; + + if (swipeBackLayout != null) { + backItem = ActionBarMenuItem.addItem(windowLayout, R.drawable.msg_arrow_back, LocaleController.getString("Back", R.string.Back), false, resourcesProvider); + backItem.setOnClickListener(view -> { + swipeBackLayout.closeForeground(); + }); + } + + ActionBarMenuSubItem item = ActionBarMenuItem.addItem(windowLayout, R.drawable.msg_autodelete_1d, LocaleController.getString("AutoDelete1Day", R.string.AutoDelete1Day), false, resourcesProvider); + item.setOnClickListener(view -> { + dismiss(); + callback.setAutoDeleteHistory(24 * 60 * 60, UndoView.ACTION_AUTO_DELETE_ON); + }); + item = ActionBarMenuItem.addItem(windowLayout, R.drawable.msg_autodelete_1w, LocaleController.getString("AutoDelete7Days", R.string.AutoDelete7Days), false, resourcesProvider); + item.setOnClickListener(view -> { + dismiss(); + callback.setAutoDeleteHistory(7 * 24 * 60 * 60, UndoView.ACTION_AUTO_DELETE_ON); + }); + item = ActionBarMenuItem.addItem(windowLayout, R.drawable.msg_autodelete_1m, LocaleController.getString("AutoDelete1Month", R.string.AutoDelete1Month), false, resourcesProvider); + item.setOnClickListener(view -> { + dismiss(); + callback.setAutoDeleteHistory(31 * 24 * 60 * 60, UndoView.ACTION_AUTO_DELETE_ON); + }); + item = ActionBarMenuItem.addItem(windowLayout, R.drawable.msg_customize, LocaleController.getString("AutoDeleteCustom", R.string.AutoDeleteCustom), false, resourcesProvider); + item.setOnClickListener(view -> { + dismiss(); + AlertsCreator.createAutoDeleteDatePickerDialog(context, (notify, timeInMinutes) -> { + callback.setAutoDeleteHistory(timeInMinutes * 60, timeInMinutes == 0 ? UndoView.ACTION_AUTO_DELETE_OFF : UndoView.ACTION_AUTO_DELETE_ON); + }); + }); + disableItem = ActionBarMenuItem.addItem(windowLayout, R.drawable.msg_disable, LocaleController.getString("AutoDeleteDisable", R.string.AutoDeleteDisable), false, resourcesProvider); + disableItem.setOnClickListener(view -> { + dismiss(); + callback.setAutoDeleteHistory(0, UndoView.ACTION_AUTO_DELETE_OFF); + }); + disableItem.setColors(Theme.getColor(Theme.key_dialogTextRed2), Theme.getColor(Theme.key_dialogTextRed2)); + + + View gap = new FrameLayout(context); + gap.setBackgroundColor(Theme.getColor(Theme.key_graySection)); + gap.setTag(R.id.fit_width_tag, 1); + windowLayout.addView(gap, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 8)); + + TextView textView = new TextView(context); + textView.setTag(R.id.fit_width_tag, 1); + textView.setPadding(AndroidUtilities.dp(13), AndroidUtilities.dp(8), AndroidUtilities.dp(13), AndroidUtilities.dp(8)); + textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 13); + textView.setTextColor(Theme.getColor(Theme.key_actionBarDefaultSubmenuItem)); + textView.setText(LocaleController.getString("AutoDeletePopupDescription", R.string.AutoDeletePopupDescription)); + windowLayout.addView(textView, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); + } + + private void dismiss() { + callback.dismiss(); + lastDismissTime = System.currentTimeMillis(); + } + + public void updateItems(int ttl) { + if (System.currentTimeMillis() - lastDismissTime < 200) { + AndroidUtilities.runOnUIThread(() -> { + updateItems(ttl); + }); + return; + } + if (ttl == 0) { + disableItem.setVisibility(View.GONE); + } else { + disableItem.setVisibility(View.VISIBLE); + } + } + + + public interface Callback { + void dismiss(); + void setAutoDeleteHistory(int time, int action); + } +} 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 d9f1f36ea..00d5713c5 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/BackupImageView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/BackupImageView.java @@ -11,6 +11,7 @@ package org.telegram.ui.Components; import android.content.Context; import android.graphics.Bitmap; import android.graphics.Canvas; +import android.graphics.ColorFilter; import android.graphics.PorterDuff; import android.graphics.PorterDuffColorFilter; import android.graphics.drawable.BitmapDrawable; @@ -164,6 +165,7 @@ public class BackupImageView extends View { public void setSize(int w, int h) { width = w; height = h; + invalidate(); } @Override @@ -187,4 +189,8 @@ public class BackupImageView extends View { } imageReceiver.draw(canvas); } + + public void setColorFilter(ColorFilter colorFilter) { + imageReceiver.setColorFilter(colorFilter); + } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/BotCommandsMenuView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/BotCommandsMenuView.java index 99b67b2d0..acf1394ed 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/BotCommandsMenuView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/BotCommandsMenuView.java @@ -42,13 +42,31 @@ public class BotCommandsMenuView extends View { invalidate(); } }; + RLottieDrawable webViewAnimation = new RLottieDrawable(R.raw.bot_webview_sheet_to_cross, String.valueOf(R.raw.bot_webview_sheet_to_cross) + hashCode(), AndroidUtilities.dp(20), AndroidUtilities.dp(20)) { + @Override + public void invalidateSelf() { + super.invalidateSelf(); + invalidate(); + } + + @Override + protected void invalidateInternal() { + super.invalidateInternal(); + invalidate(); + } + }; boolean expanded; float expandProgress; - StaticLayout menuText; + private String menuText = LocaleController.getString(R.string.BotsMenuTitle); + StaticLayout menuTextLayout; boolean isOpened; + boolean isWebView; + boolean isWebViewOpened; + Drawable backgroundDrawable; + boolean drawBackgroundDrawable = true; public BotCommandsMenuView(Context context) { super(context); @@ -59,10 +77,35 @@ public class BotCommandsMenuView extends View { backDrawable.setCallback(this); textPaint.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); backDrawable.setRoundCap(); - backgroundDrawable = Theme.createSimpleSelectorRoundRectDrawable(AndroidUtilities.dp(16), Color.TRANSPARENT, Theme.getColor(Theme.key_windowBackgroundWhite)); + backgroundDrawable = Theme.createSimpleSelectorRoundRectDrawable(AndroidUtilities.dp(16), Color.TRANSPARENT, Theme.getColor(Theme.key_featuredStickers_addButtonPressed)); backgroundDrawable.setCallback(this); } + public void setDrawBackgroundDrawable(boolean drawBackgroundDrawable) { + this.drawBackgroundDrawable = drawBackgroundDrawable; + invalidate(); + } + + @Override + protected void onAttachedToWindow() { + super.onAttachedToWindow(); + + webViewAnimation.addParentView(this); + webViewAnimation.setCurrentParentView(this); + } + + @Override + protected void onDetachedFromWindow() { + super.onDetachedFromWindow(); + + webViewAnimation.removeParentView(this); + } + + public void setWebView(boolean webView) { + isWebView = webView; + invalidate(); + } + private void updateColors() { paint.setColor(Theme.getColor(Theme.key_chat_messagePanelVoiceBackground)); int textColor = Theme.getColor(Theme.key_chat_messagePanelVoicePressed); @@ -76,18 +119,17 @@ public class BotCommandsMenuView extends View { @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int size = MeasureSpec.getSize(widthMeasureSpec) + MeasureSpec.getSize(heightMeasureSpec) << 16; - if (lastSize != size || menuText == null) { + if (lastSize != size || menuTextLayout == null) { backDrawable.setBounds(0, 0, getMeasuredWidth(), getMeasuredHeight()); textPaint.setTextSize(AndroidUtilities.dp(15)); lastSize = size; - String string = LocaleController.getString("BotsMenuTitle", R.string.BotsMenuTitle); - int w = (int) textPaint.measureText(string); - menuText = StaticLayoutEx.createStaticLayout(string, textPaint, w, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0f, false, TextUtils.TruncateAt.END, w, 1); + int w = (int) textPaint.measureText(menuText); + menuTextLayout = StaticLayoutEx.createStaticLayout(menuText, textPaint, w, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0f, false, TextUtils.TruncateAt.END, w, 1); } - onTranslationChanged((menuText.getWidth() + AndroidUtilities.dp(4)) * expandProgress); + onTranslationChanged((menuTextLayout.getWidth() + AndroidUtilities.dp(4)) * expandProgress); int width = AndroidUtilities.dp(40); if (expanded) { - width += menuText.getWidth() + AndroidUtilities.dp(4); + width += menuTextLayout.getWidth() + AndroidUtilities.dp(4); } super.onMeasure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(32), MeasureSpec.EXACTLY)); @@ -95,7 +137,7 @@ public class BotCommandsMenuView extends View { @Override protected void dispatchDraw(Canvas canvas) { - if (menuText != null) { + if (menuTextLayout != null) { boolean update = false; if (expanded && expandProgress != 1f) { expandProgress += 16f / 150f; @@ -119,24 +161,41 @@ public class BotCommandsMenuView extends View { if (update && expandProgress > 0) { textPaint.setAlpha((int) (255 * expandProgress)); } - rectTmp.set(0, 0, AndroidUtilities.dp(40) + (menuText.getWidth() + AndroidUtilities.dp(4)) * expandProgress, getMeasuredHeight()); - canvas.drawRoundRect(rectTmp, AndroidUtilities.dp(16), AndroidUtilities.dp(16), paint); - backgroundDrawable.setBounds((int) rectTmp.left, (int) rectTmp.top, (int) rectTmp.right, (int) rectTmp.bottom); - backgroundDrawable.draw(canvas); - canvas.save(); - canvas.translate(AndroidUtilities.dp(8), AndroidUtilities.dp(4)); - backDrawable.draw(canvas); - canvas.restore(); + + if (drawBackgroundDrawable) { + rectTmp.set(0, 0, AndroidUtilities.dp(40) + (menuTextLayout.getWidth() + AndroidUtilities.dp(4)) * expandProgress, getMeasuredHeight()); + canvas.drawRoundRect(rectTmp, AndroidUtilities.dp(16), AndroidUtilities.dp(16), paint); + backgroundDrawable.setBounds((int) rectTmp.left, (int) rectTmp.top, (int) rectTmp.right, (int) rectTmp.bottom); + backgroundDrawable.draw(canvas); + } + + if (isWebView) { + canvas.save(); + canvas.translate(AndroidUtilities.dp(9.5f), AndroidUtilities.dp(6)); + RLottieDrawable drawable = webViewAnimation; + drawable.setBounds(0, 0, drawable.width, drawable.height); + drawable.draw(canvas); + canvas.restore(); + + if (drawable.isRunning()) { + invalidate(); + } + } else { + canvas.save(); + canvas.translate(AndroidUtilities.dp(8), AndroidUtilities.dp(4)); + backDrawable.draw(canvas); + canvas.restore(); + } if (expandProgress > 0) { canvas.save(); - canvas.translate(AndroidUtilities.dp(34), (getMeasuredHeight() - menuText.getHeight()) / 2f); - menuText.draw(canvas); + canvas.translate(AndroidUtilities.dp(34), (getMeasuredHeight() - menuTextLayout.getHeight()) / 2f); + menuTextLayout.draw(canvas); canvas.restore(); } if (update) { - onTranslationChanged((menuText.getWidth() + AndroidUtilities.dp(4)) * expandProgress); + onTranslationChanged((menuTextLayout.getWidth() + AndroidUtilities.dp(4)) * expandProgress); } } super.dispatchDraw(canvas); @@ -146,6 +205,12 @@ public class BotCommandsMenuView extends View { } + public void setMenuText(String menuText) { + this.menuText = menuText; + menuTextLayout = null; + requestLayout(); + } + public void setExpanded(boolean expanded, boolean animated) { if (this.expanded != expanded) { this.expanded = expanded; @@ -225,7 +290,21 @@ public class BotCommandsMenuView extends View { if (isOpened != opened) { isOpened = opened; } - backDrawable.setRotation(opened ? 1f : 0f, true); + if (isWebView) { + if (isWebViewOpened != opened) { + RLottieDrawable drawable = webViewAnimation; + if (!drawable.hasParentView()) { + drawable.addParentView(this); + } + drawable.stop(); + drawable.setPlayInDirectionOfCustomEndFrame(true); + drawable.setCustomEndFrame(opened ? drawable.getFramesCount() : 1); + drawable.start(); + isWebViewOpened = opened; + } + } else { + backDrawable.setRotation(opened ? 1f : 0f, true); + } } public static class BotCommandView extends LinearLayout { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/BotKeyboardView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/BotKeyboardView.java index 53fb3d62b..6a34acdef 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/BotKeyboardView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/BotKeyboardView.java @@ -12,12 +12,15 @@ import android.content.Context; import android.util.TypedValue; import android.view.Gravity; import android.view.View; +import android.widget.FrameLayout; +import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.ScrollView; import android.widget.TextView; import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.Emoji; +import org.telegram.messenger.R; import org.telegram.tgnet.TLRPC; import org.telegram.ui.ActionBar.Theme; @@ -33,6 +36,7 @@ public class BotKeyboardView extends LinearLayout { private boolean isFullSize; private int buttonHeight; private ArrayList buttonViews = new ArrayList<>(); + private ArrayList buttonIcons = new ArrayList<>(); private ScrollView scrollView; public interface BotKeyboardViewDelegate { @@ -58,7 +62,8 @@ public class BotKeyboardView extends LinearLayout { setBackgroundColor(getThemedColor(Theme.key_chat_emojiPanelBackground)); for (int i = 0; i < buttonViews.size(); i++) { buttonViews.get(i).setTextColor(getThemedColor(Theme.key_chat_botKeyboardButtonText)); - buttonViews.get(i).setBackgroundDrawable(Theme.createSimpleSelectorRoundRectDrawable(AndroidUtilities.dp(4), getThemedColor(Theme.key_chat_botKeyboardButtonBackground), getThemedColor(Theme.key_chat_botKeyboardButtonBackgroundPressed))); + buttonViews.get(i).setBackground(Theme.createSimpleSelectorRoundRectDrawable(AndroidUtilities.dp(4), getThemedColor(Theme.key_chat_botKeyboardButtonBackground), getThemedColor(Theme.key_chat_botKeyboardButtonBackgroundPressed))); + buttonIcons.get(i).setColorFilter(getThemedColor(Theme.key_chat_botKeyboardButtonText)); } invalidate(); } @@ -87,6 +92,7 @@ public class BotKeyboardView extends LinearLayout { public void invalidateViews() { for (int a = 0; a < buttonViews.size(); a++) { buttonViews.get(a).invalidate(); + buttonIcons.get(a).invalidate(); } } @@ -98,6 +104,7 @@ public class BotKeyboardView extends LinearLayout { botButtons = buttons; container.removeAllViews(); buttonViews.clear(); + buttonIcons.clear(); scrollView.scrollTo(0, 0); if (buttons != null && botButtons.rows.size() != 0) { @@ -116,15 +123,29 @@ public class BotKeyboardView extends LinearLayout { TextView textView = new TextView(getContext()); textView.setTag(button); textView.setTextColor(getThemedColor(Theme.key_chat_botKeyboardButtonText)); - textView.setBackgroundDrawable(Theme.createSimpleSelectorRoundRectDrawable(AndroidUtilities.dp(4), getThemedColor(Theme.key_chat_botKeyboardButtonBackground), getThemedColor(Theme.key_chat_botKeyboardButtonBackgroundPressed))); + textView.setBackground(Theme.createSimpleSelectorRoundRectDrawable(AndroidUtilities.dp(4), getThemedColor(Theme.key_chat_botKeyboardButtonBackground), getThemedColor(Theme.key_chat_botKeyboardButtonBackgroundPressed))); textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16); textView.setGravity(Gravity.CENTER); + FrameLayout frame = new FrameLayout(getContext()); + frame.addView(textView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); + textView.setPadding(AndroidUtilities.dp(4), 0, AndroidUtilities.dp(4), 0); textView.setText(Emoji.replaceEmoji(button.text, textView.getPaint().getFontMetricsInt(), AndroidUtilities.dp(16), false)); - layout.addView(textView, LayoutHelper.createLinear(0, LayoutHelper.MATCH_PARENT, weight, 0, 0, b != row.buttons.size() - 1 ? 10 : 0, 0)); + layout.addView(frame, LayoutHelper.createLinear(0, LayoutHelper.MATCH_PARENT, weight, 0, 0, b != row.buttons.size() - 1 ? 10 : 0, 0)); textView.setOnClickListener(v -> delegate.didPressedButton((TLRPC.KeyboardButton) v.getTag())); buttonViews.add(textView); + + ImageView icon = new ImageView(getContext()); + icon.setColorFilter(getThemedColor(Theme.key_chat_botKeyboardButtonText)); + if (button instanceof TLRPC.TL_keyboardButtonWebView || button instanceof TLRPC.TL_keyboardButtonSimpleWebView) { + icon.setImageResource(R.drawable.bot_webview); + icon.setVisibility(VISIBLE); + } else { + icon.setVisibility(GONE); + } + buttonIcons.add(icon); + frame.addView(icon, LayoutHelper.createFrame(12, 12, Gravity.RIGHT | Gravity.TOP, 0, 8, 8, 0)); } } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/BotWebViewContainer.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/BotWebViewContainer.java new file mode 100644 index 000000000..ce812854f --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/BotWebViewContainer.java @@ -0,0 +1,800 @@ +package org.telegram.ui.Components; + +import android.Manifest; +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.animation.AnimatorSet; +import android.animation.ObjectAnimator; +import android.animation.ValueAnimator; +import android.annotation.SuppressLint; +import android.app.Activity; +import android.app.Dialog; +import android.content.Context; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.PorterDuff; +import android.graphics.PorterDuffColorFilter; +import android.graphics.drawable.Drawable; +import android.net.Uri; +import android.os.Build; +import android.text.TextUtils; +import android.view.Gravity; +import android.view.View; +import android.webkit.GeolocationPermissions; +import android.webkit.JavascriptInterface; +import android.webkit.PermissionRequest; +import android.webkit.ValueCallback; +import android.webkit.WebChromeClient; +import android.webkit.WebSettings; +import android.webkit.WebView; +import android.webkit.WebViewClient; +import android.widget.FrameLayout; + +import androidx.annotation.NonNull; +import androidx.annotation.RequiresApi; +import androidx.core.util.Consumer; + +import org.json.JSONException; +import org.json.JSONObject; +import org.telegram.messenger.AndroidUtilities; +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.SvgHelper; +import org.telegram.messenger.UserObject; +import org.telegram.messenger.browser.Browser; +import org.telegram.tgnet.ConnectionsManager; +import org.telegram.tgnet.TLRPC; +import org.telegram.ui.ActionBar.ActionBar; +import org.telegram.ui.ActionBar.AlertDialog; +import org.telegram.ui.ActionBar.Theme; +import org.telegram.ui.Components.voip.CellFlickerDrawable; + +import java.io.UnsupportedEncodingException; +import java.net.URLEncoder; +import java.util.Arrays; +import java.util.List; +import java.util.Objects; + +public class BotWebViewContainer extends FrameLayout implements NotificationCenter.NotificationCenterDelegate { + private final static String DURGER_KING_USERNAME = "DurgerKingBot"; + private final static int REQUEST_CODE_WEB_VIEW_FILE = 3000, REQUEST_CODE_WEB_PERMISSION = 4000; + + private final static List WHITELISTED_SCHEMES = Arrays.asList("http", "https"); + + private WebView webView; + private String mUrl; + private Delegate delegate; + private WebViewScrollListener webViewScrollListener; + private Theme.ResourcesProvider resourcesProvider; + + private CellFlickerDrawable flickerDrawable = new CellFlickerDrawable(); + private BackupImageView flickerView; + private boolean isFlickeringCenter; + + private Consumer webViewProgressListener; + + private ValueCallback mFilePathCallback; + + private int lastButtonColor = Theme.getColor(Theme.key_featuredStickers_addButton); + private int lastButtonTextColor = Theme.getColor(Theme.key_featuredStickers_buttonText); + private String lastButtonText = ""; + private String buttonData; + + private boolean isPageLoaded; + private int viewPortOffset; + private boolean lastExpanded; + + private boolean hasUserPermissions; + private TLRPC.User botUser; + private Runnable onPermissionsRequestResultCallback; + + private Activity parentActivity; + + @SuppressLint({"SetJavaScriptEnabled", "AddJavascriptInterface"}) + public BotWebViewContainer(@NonNull Context context, Theme.ResourcesProvider resourcesProvider, int backgroundColor) { + super(context); + this.resourcesProvider = resourcesProvider; + + if (context instanceof Activity) { + this.parentActivity = (Activity) context; + } + + flickerDrawable.drawFrame = false; + flickerDrawable.setColors(backgroundColor, 0x99, 0xCC); + flickerView = new BackupImageView(context) { + { + imageReceiver = new ImageReceiver(this) { + @Override + protected boolean setImageBitmapByKey(Drawable drawable, String key, int type, boolean memCache, int guid) { + boolean set = super.setImageBitmapByKey(drawable, key, type, memCache, guid); + ValueAnimator anim = ValueAnimator.ofFloat(0, 1).setDuration(300); + anim.addUpdateListener(animation -> { + imageReceiver.setAlpha((Float) animation.getAnimatedValue()); + invalidate(); + }); + anim.start(); + return set; + } + }; + } + + @Override + protected void onDraw(Canvas canvas) { + if (isFlickeringCenter) { + super.onDraw(canvas); + } else { + Drawable drawable = imageReceiver.getDrawable(); + if (drawable != null) { + imageReceiver.setImageCoords(0, 0, getWidth(), drawable.getIntrinsicHeight() * ((float) getWidth() / drawable.getIntrinsicWidth())); + imageReceiver.draw(canvas); + } + } + } + }; + flickerView.setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_windowBackgroundGray), PorterDuff.Mode.SRC_IN)); + flickerView.getImageReceiver().setAspectFit(true); + addView(flickerView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.TOP)); + + webView = new WebView(context) { + private int prevScrollX, prevScrollY; + + @Override + protected void onScrollChanged(int l, int t, int oldl, int oldt) { + super.onScrollChanged(l, t, oldl, oldt); + + if (webViewScrollListener != null) { + webViewScrollListener.onWebViewScrolled(this, getScrollX() - prevScrollX, getScrollY() - prevScrollY); + } + + prevScrollX = getScrollX(); + prevScrollY = getScrollY(); + } + + @Override + public void setScrollX(int value) { + super.setScrollX(value); + prevScrollX = value; + } + + @Override + public void setScrollY(int value) { + super.setScrollY(value); + prevScrollY = value; + } + + @Override + public boolean onCheckIsTextEditor() { + return true; + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(heightMeasureSpec), MeasureSpec.EXACTLY)); + } + }; + webView.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); + WebSettings settings = webView.getSettings(); + settings.setJavaScriptEnabled(true); + settings.setGeolocationEnabled(true); + GeolocationPermissions.getInstance().clearAll(); + + webView.setWebViewClient(new WebViewClient() { + @Override + public boolean shouldOverrideUrlLoading(WebView view, String url) { + Uri uriOrig = Uri.parse(mUrl); + Uri uriNew = Uri.parse(url); + + boolean override; + if (isPageLoaded && (!Objects.equals(uriOrig.getHost(), uriNew.getHost()) || !Objects.equals(uriOrig.getPath(), uriNew.getPath()))) { + override = true; + + if (WHITELISTED_SCHEMES.contains(uriNew.getScheme())) { + new AlertDialog.Builder(context, resourcesProvider) + .setTitle(LocaleController.getString(R.string.OpenUrlTitle)) + .setMessage(LocaleController.formatString(R.string.OpenUrlAlert2, uriNew.toString())) + .setPositiveButton(LocaleController.getString(R.string.Open), (dialog, which) -> { + boolean[] forceBrowser = {false}; + boolean internal = Browser.isInternalUri(uriNew, forceBrowser); + Browser.openUrl(getContext(), uriNew, true, false); + if (internal && delegate != null) { + delegate.onCloseRequested(); + } + }) + .setNegativeButton(LocaleController.getString(R.string.Cancel), null) + .show(); + } + } else { + override = false; + } + + return override; + } + + @Override + public void onPageFinished(WebView view, String url) { + setPageLoaded(url); + } + }); + webView.setWebChromeClient(new WebChromeClient() { + private Dialog lastPermissionsDialog; + + @Override + public boolean onShowFileChooser(WebView webView, ValueCallback filePathCallback, FileChooserParams fileChooserParams) { + Context ctx = getContext(); + if (!(ctx instanceof Activity)) { + return false; + } + Activity activity = (Activity) ctx; + + if (mFilePathCallback != null) { + mFilePathCallback.onReceiveValue(null); + } + + mFilePathCallback = filePathCallback; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + activity.startActivityForResult(fileChooserParams.createIntent(), REQUEST_CODE_WEB_VIEW_FILE); + } else { + Intent intent = new Intent(Intent.ACTION_GET_CONTENT); + intent.addCategory(Intent.CATEGORY_OPENABLE); + intent.setType("*/*"); + activity.startActivityForResult(Intent.createChooser(intent, LocaleController.getString(R.string.BotWebViewFileChooserTitle)), REQUEST_CODE_WEB_VIEW_FILE); + } + + return true; + } + + @Override + public void onProgressChanged(WebView view, int newProgress) { + if (webViewProgressListener != null) { + webViewProgressListener.accept(newProgress / 100f); + } + } + + @Override + public void onGeolocationPermissionsShowPrompt(String origin, GeolocationPermissions.Callback callback) { + if (parentActivity == null) { + callback.invoke(origin, false, false); + return; + } + lastPermissionsDialog = AlertsCreator.createWebViewPermissionsRequestDialog(parentActivity, resourcesProvider, new String[] {Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION}, R.raw.permission_request_location, LocaleController.formatString(R.string.BotWebViewRequestGeolocationPermission, UserObject.getUserName(botUser)), LocaleController.formatString(R.string.BotWebViewRequestGeolocationPermissionWithHint, UserObject.getUserName(botUser)), allow -> { + if (lastPermissionsDialog != null) { + lastPermissionsDialog = null; + + if (allow) { + runWithPermissions(new String[] {Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION}, allowSystem -> { + callback.invoke(origin, allowSystem, false); + if (allowSystem) { + hasUserPermissions = true; + } + }); + } else { + callback.invoke(origin, false, false); + } + } + }); + lastPermissionsDialog.show(); + } + + @Override + public void onGeolocationPermissionsHidePrompt() { + if (lastPermissionsDialog != null){ + lastPermissionsDialog.dismiss(); + lastPermissionsDialog = null; + } + } + + @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) + @Override + public void onPermissionRequest(PermissionRequest request) { + if (lastPermissionsDialog != null){ + lastPermissionsDialog.dismiss(); + lastPermissionsDialog = null; + } + + String[] resources = request.getResources(); + if (resources.length == 1) { + String resource = resources[0]; + + if (parentActivity == null) { + request.deny(); + return; + } + + switch (resource) { + case PermissionRequest.RESOURCE_AUDIO_CAPTURE: { + lastPermissionsDialog = AlertsCreator.createWebViewPermissionsRequestDialog(parentActivity, resourcesProvider, new String[] {Manifest.permission.RECORD_AUDIO}, R.raw.permission_request_microphone, LocaleController.formatString(R.string.BotWebViewRequestMicrophonePermission, UserObject.getUserName(botUser)), LocaleController.formatString(R.string.BotWebViewRequestMicrophonePermissionWithHint, UserObject.getUserName(botUser)), allow -> { + if (lastPermissionsDialog != null) { + lastPermissionsDialog = null; + + if (allow) { + runWithPermissions(new String[] {Manifest.permission.RECORD_AUDIO}, allowSystem -> { + if (allowSystem) { + request.grant(new String[] {resource}); + hasUserPermissions = true; + } else { + request.deny(); + } + }); + } else { + request.deny(); + } + } + }); + lastPermissionsDialog.show(); + break; + } + case PermissionRequest.RESOURCE_VIDEO_CAPTURE: { + lastPermissionsDialog = AlertsCreator.createWebViewPermissionsRequestDialog(parentActivity, resourcesProvider, new String[] {Manifest.permission.CAMERA}, R.raw.permission_request_camera, LocaleController.formatString(R.string.BotWebViewRequestCameraPermission, UserObject.getUserName(botUser)), LocaleController.formatString(R.string.BotWebViewRequestCameraPermissionWithHint, UserObject.getUserName(botUser)), allow -> { + if (lastPermissionsDialog != null) { + lastPermissionsDialog = null; + + if (allow) { + runWithPermissions(new String[] {Manifest.permission.CAMERA}, allowSystem -> { + if (allowSystem) { + request.grant(new String[] {resource}); + hasUserPermissions = true; + } else { + request.deny(); + } + }); + } else { + request.deny(); + } + } + }); + lastPermissionsDialog.show(); + break; + } + } + } + } + + @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) + @Override + public void onPermissionRequestCanceled(PermissionRequest request) { + if (lastPermissionsDialog != null){ + lastPermissionsDialog.dismiss(); + lastPermissionsDialog = null; + } + } + }); + webView.setAlpha(0f); + addView(webView); + + // We can't use javascript interface because of minSDK 16, it can be exploited because of reflection access + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { + webView.addJavascriptInterface(new WebViewProxy(), "TelegramWebviewProxy"); + } + } + + private void setPageLoaded(String url) { + if (isPageLoaded) { + return; + } + AnimatorSet set = new AnimatorSet(); + set.playTogether( + ObjectAnimator.ofFloat(webView, View.ALPHA, 1f), + ObjectAnimator.ofFloat(flickerView, View.ALPHA, 0f) + ); + set.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + flickerView.setVisibility(GONE); + } + }); + set.start(); + mUrl = url; + isPageLoaded = true; + } + + public boolean hasUserPermissions() { + return hasUserPermissions; + } + + public void setBotUser(TLRPC.User botUser) { + this.botUser = botUser; + } + + private void runWithPermissions(String[] permissions, Consumer callback) { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) { + callback.accept(true); + } else { + if (checkPermissions(permissions)) { + callback.accept(true); + } else { + onPermissionsRequestResultCallback = ()-> callback.accept(checkPermissions(permissions)); + + if (parentActivity != null) { + parentActivity.requestPermissions(permissions, REQUEST_CODE_WEB_PERMISSION); + } + } + } + } + + public void setParentActivity(Activity parentActivity) { + this.parentActivity = parentActivity; + } + + @RequiresApi(api = Build.VERSION_CODES.M) + private boolean checkPermissions(String[] permissions) { + for (String perm : permissions) { + if (getContext().checkSelfPermission(perm) != PackageManager.PERMISSION_GRANTED) { + return false; + } + } + return true; + } + + public void restoreButtonData() { + if (buttonData != null) { + onEventReceived("web_app_setup_main_button", buttonData); + } + } + + public void onMainButtonPressed() { + evaluateJs("window.Telegram.WebView.receiveEvent('main_button_pressed', null);"); + } + + public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { + if (requestCode == REQUEST_CODE_WEB_PERMISSION) { + if (onPermissionsRequestResultCallback != null) { + onPermissionsRequestResultCallback.run(); + onPermissionsRequestResultCallback = null; + } + } + } + + public void onActivityResult(int requestCode, int resultCode, Intent data) { + if (requestCode == REQUEST_CODE_WEB_VIEW_FILE && mFilePathCallback != null) { + Uri[] results = null; + + if (resultCode == Activity.RESULT_OK) { + if (data != null && data.getDataString() != null) { + results = new Uri[] {Uri.parse(data.getDataString())}; + } + } + + mFilePathCallback.onReceiveValue(results); + mFilePathCallback = null; + } + } + + public void setViewPortOffset(int viewPortOffset) { + this.viewPortOffset = viewPortOffset; + invalidateViewPortHeight(true); + } + + @Override + protected void onSizeChanged(int w, int h, int oldw, int oldh) { + super.onSizeChanged(w, h, oldw, oldh); + invalidateViewPortHeight(true); + } + + public void invalidateViewPortHeight() { + invalidateViewPortHeight(false); + } + + public void invalidateViewPortHeight(boolean isStable) { + invalidateViewPortHeight(isStable, false); + } + + public void invalidateViewPortHeight(boolean isStable, boolean force) { + if (!isPageLoaded && !force) { + return; + } + + if (getParent() instanceof ChatAttachAlertBotWebViewLayout.WebViewSwipeContainer) { + ChatAttachAlertBotWebViewLayout.WebViewSwipeContainer swipeContainer = (ChatAttachAlertBotWebViewLayout.WebViewSwipeContainer) getParent(); + + if (isStable) { + lastExpanded = swipeContainer.getSwipeOffsetY() == -swipeContainer.getOffsetY() + swipeContainer.getTopActionBarOffsetY(); + } + + int viewPortHeight = (int) (swipeContainer.getMeasuredHeight() - swipeContainer.getOffsetY() - swipeContainer.getSwipeOffsetY() + swipeContainer.getTopActionBarOffsetY() + viewPortOffset); + try { + JSONObject data = new JSONObject(); + data.put("height", viewPortHeight / AndroidUtilities.density); + data.put("is_state_stable", isStable); + data.put("is_expanded", lastExpanded); + evaluateJs("window.Telegram.WebView.receiveEvent('viewport_changed', " + data + ");"); + } catch (JSONException e) { + e.printStackTrace(); + } + } + } + + @Override + protected boolean drawChild(Canvas canvas, View child, long drawingTime) { + if (child == flickerView) { + if (isFlickeringCenter) { + canvas.save(); + View parent = (View) BotWebViewContainer.this.getParent(); + canvas.translate(0, (ActionBar.getCurrentActionBarHeight() - parent.getTranslationY()) / 2f); + } + boolean draw = super.drawChild(canvas, child, drawingTime); + if (isFlickeringCenter) { + canvas.restore(); + } + + AndroidUtilities.rectTmp.set(0, 0, getWidth(), getHeight()); + flickerDrawable.draw(canvas, AndroidUtilities.rectTmp, 0); + invalidate(); + return draw; + } + return super.drawChild(canvas, child, drawingTime); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + + flickerDrawable.setParentWidth(BotWebViewContainer.this.getMeasuredWidth()); + } + + public void setWebViewProgressListener(Consumer webViewProgressListener) { + this.webViewProgressListener = webViewProgressListener; + } + + public WebView getWebView() { + return webView; + } + + public void loadFlicker(int currentAccount, long botId) { + TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(botId); + if (user.username != null && Objects.equals(user.username, DURGER_KING_USERNAME)) { + flickerView.setVisibility(VISIBLE); + flickerView.setAlpha(1f); + flickerView.setImageDrawable(SvgHelper.getDrawable(R.raw.durgerking_placeholder, Theme.getColor(Theme.key_windowBackgroundGray))); + setupFlickerParams(false); + return; + } + + TLRPC.TL_attachMenuBot cachedBot = null; + for (TLRPC.TL_attachMenuBot bot : MediaDataController.getInstance(currentAccount).getAttachMenuBots().bots) { + if (bot.bot_id == botId) { + cachedBot = bot; + break; + } + } + + if (cachedBot != null) { + boolean center = false; + TLRPC.TL_attachMenuBotIcon botIcon = MediaDataController.getPlaceholderStaticAttachMenuBotIcon(cachedBot); + if (botIcon == null) { + botIcon = MediaDataController.getStaticAttachMenuBotIcon(cachedBot); + center = true; + } + if (botIcon != null) { + flickerView.setVisibility(VISIBLE); + flickerView.setAlpha(1f); + flickerView.setImage(ImageLocation.getForDocument(botIcon.icon), null, (Drawable) null, cachedBot); + setupFlickerParams(center); + } + } else { + TLRPC.TL_messages_getAttachMenuBot req = new TLRPC.TL_messages_getAttachMenuBot(); + req.bot = MessagesController.getInstance(currentAccount).getInputUser(botId); + ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> AndroidUtilities.runOnUIThread(() -> { + if (response instanceof TLRPC.TL_attachMenuBotsBot) { + TLRPC.TL_attachMenuBot bot = ((TLRPC.TL_attachMenuBotsBot) response).bot; + + boolean center = false; + TLRPC.TL_attachMenuBotIcon botIcon = MediaDataController.getPlaceholderStaticAttachMenuBotIcon(bot); + if (botIcon == null) { + botIcon = MediaDataController.getStaticAttachMenuBotIcon(bot); + center = true; + } + if (botIcon != null) { + flickerView.setVisibility(VISIBLE); + flickerView.setAlpha(1f); + flickerView.setImage(ImageLocation.getForDocument(botIcon.icon), null, (Drawable) null, bot); + setupFlickerParams(center); + } + } + })); + } + } + + private void setupFlickerParams(boolean center) { + isFlickeringCenter = center; + FrameLayout.LayoutParams params = (LayoutParams) flickerView.getLayoutParams(); + params.gravity = center ? Gravity.CENTER : Gravity.TOP; + if (center) { + params.width = params.height = AndroidUtilities.dp(64); + } else { + params.width = LayoutParams.MATCH_PARENT; + params.height = LayoutParams.WRAP_CONTENT; + } + + flickerView.requestLayout(); + } + + public void loadUrl(String url) { + isPageLoaded = false; + hasUserPermissions = false; + mUrl = url; + webView.loadUrl(url); + } + + @Override + protected void onAttachedToWindow() { + super.onAttachedToWindow(); + + NotificationCenter.getGlobalInstance().addObserver(this, NotificationCenter.didSetNewTheme); + NotificationCenter.getGlobalInstance().addObserver(this, NotificationCenter.onActivityResultReceived); + NotificationCenter.getGlobalInstance().addObserver(this, NotificationCenter.onRequestPermissionResultReceived); + } + + @Override + protected void onDetachedFromWindow() { + super.onDetachedFromWindow(); + + NotificationCenter.getGlobalInstance().removeObserver(this, NotificationCenter.didSetNewTheme); + NotificationCenter.getGlobalInstance().removeObserver(this, NotificationCenter.onActivityResultReceived); + NotificationCenter.getGlobalInstance().removeObserver(this, NotificationCenter.onRequestPermissionResultReceived); + } + + public void destroyWebView() { + webView.destroy(); + } + + @SuppressWarnings("deprecation") + public void evaluateJs(String script) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { + webView.evaluateJavascript(script, value -> {}); + } else { + try { + webView.loadUrl("javascript:" + URLEncoder.encode(script, "UTF-8")); + } catch (UnsupportedEncodingException e) { + webView.loadUrl("javascript:" + URLEncoder.encode(script)); + } + } + } + + @Override + public void didReceivedNotification(int id, int account, Object... args) { + if (id == NotificationCenter.didSetNewTheme) { + evaluateJs("window.Telegram.WebView.receiveEvent('theme_changed', {theme_params: " + buildThemeParams() + "});"); + } else if (id == NotificationCenter.onActivityResultReceived) { + onActivityResult((int) args[0], (int) args[1], (Intent) args[2]); + } else if (id == NotificationCenter.onRequestPermissionResultReceived) { + onRequestPermissionsResult((int) args[0], (String[]) args[1], (int[]) args[2]); + } + } + + public void setWebViewScrollListener(WebViewScrollListener webViewScrollListener) { + this.webViewScrollListener = webViewScrollListener; + } + + public void setDelegate(Delegate delegate) { + this.delegate = delegate; + } + + private void onEventReceived(String eventType, String eventData) { + switch (eventType) { + case "web_app_close": { + delegate.onCloseRequested(); + break; + } + case "web_app_data_send": { + delegate.onSendWebViewData(eventData); + break; + } + case "web_app_expand": { + delegate.onWebAppExpand(); + break; + } + case "web_app_request_viewport": { + boolean hasSwipeInProgress = getParent() instanceof ChatAttachAlertBotWebViewLayout.WebViewSwipeContainer && ((ChatAttachAlertBotWebViewLayout.WebViewSwipeContainer) getParent()).isSwipeInProgress(); + invalidateViewPortHeight(!hasSwipeInProgress, true); + break; + } + case "web_app_ready": { + setPageLoaded(webView.getUrl()); + break; + } + case "web_app_setup_main_button": { + try { + JSONObject info = new JSONObject(eventData); + boolean isActive = info.optBoolean("is_active", false); + String text = info.optString("text", lastButtonText).trim(); + boolean isVisible = info.optBoolean("is_visible", false) && !TextUtils.isEmpty(text); + int color = info.has("color") ? Color.parseColor(info.optString("color")) : lastButtonColor; + int textColor = info.has("text_color") ? Color.parseColor(info.optString("text_color")) : lastButtonTextColor; + boolean isProgressVisible = info.optBoolean("is_progress_visible", false) && isVisible; + + lastButtonColor = color; + lastButtonTextColor = textColor; + lastButtonText = text; + buttonData = eventData; + + delegate.onSetupMainButton(isVisible, isActive, text, color, textColor, isProgressVisible); + } catch (JSONException | IllegalArgumentException e) { + FileLog.e(e); + } + break; + } + } + } + + private String buildThemeParams() { + try { + JSONObject object = new JSONObject(); + object.put("bg_color", formatColor(Theme.key_windowBackgroundWhite)); + object.put("text_color", formatColor(Theme.key_windowBackgroundWhiteBlackText)); + object.put("hint_color", formatColor(Theme.key_windowBackgroundWhiteHintText)); + object.put("link_color", formatColor(Theme.key_windowBackgroundWhiteLinkText)); + object.put("button_color", formatColor(Theme.key_featuredStickers_addButton)); + object.put("button_text_color", formatColor(Theme.key_featuredStickers_buttonText)); + return object.toString(); + } catch (Exception e) { + FileLog.e(e); + return "{}"; + } + } + + private String formatColor(String colorKey) { + Integer color = resourcesProvider != null ? resourcesProvider.getColor(colorKey) : Theme.getColor(colorKey); + if (color == null) { + color = Theme.getColor(colorKey); + } + return "#" + hexFixed(Color.red(color)) + hexFixed(Color.green(color)) + hexFixed(Color.blue(color)); + } + + private String hexFixed(int h) { + String hex = Integer.toHexString(h); + if (hex.length() < 2) { + hex = "0" + hex; + } + return hex; + } + + private class WebViewProxy { + @JavascriptInterface + public void postEvent(String eventType, String eventData) { + AndroidUtilities.runOnUIThread(() -> onEventReceived(eventType, eventData)); + } + } + + public interface WebViewScrollListener { + /** + * Called when WebView scrolls + * + * @param webView WebView that scrolled + * @param dx Delta X + * @param dy Delta Y + */ + void onWebViewScrolled(WebView webView, int dx, int dy); + } + + public interface Delegate { + /** + * Called when WebView requests to close itself + */ + void onCloseRequested(); + + /** + * Called when WebView requests to send custom data + * + * @param data Custom data to send + */ + void onSendWebViewData(String data); + + /** + * Called when WebView requests to expand viewport + */ + void onWebAppExpand(); + + /** + * Setups main button + */ + void onSetupMainButton(boolean isVisible, boolean isActive, String text, int color, int textColor, boolean isProgressVisible); + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/BotWebViewMenuContainer.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/BotWebViewMenuContainer.java new file mode 100644 index 000000000..5f90713d3 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/BotWebViewMenuContainer.java @@ -0,0 +1,657 @@ +package org.telegram.ui.Components; + +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.Paint; +import android.os.Build; +import android.text.Editable; +import android.view.Gravity; +import android.view.MotionEvent; +import android.view.View; +import android.widget.FrameLayout; + +import androidx.annotation.NonNull; +import androidx.core.graphics.ColorUtils; +import androidx.dynamicanimation.animation.SpringAnimation; +import androidx.dynamicanimation.animation.SpringForce; +import androidx.recyclerview.widget.ChatListItemAnimator; + +import org.json.JSONObject; +import org.telegram.messenger.AndroidUtilities; +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.Utilities; +import org.telegram.tgnet.ConnectionsManager; +import org.telegram.tgnet.TLRPC; +import org.telegram.ui.ActionBar.ActionBar; +import org.telegram.ui.ActionBar.ActionBarMenu; +import org.telegram.ui.ActionBar.ActionBarMenuItem; +import org.telegram.ui.ActionBar.Theme; +import org.telegram.ui.ChatActivity; + +import java.util.Objects; + +public class BotWebViewMenuContainer extends FrameLayout implements NotificationCenter.NotificationCenterDelegate { + private final static int POLL_PERIOD = 60000; + + private final static SimpleFloatPropertyCompat ACTION_BAR_TRANSITION_PROGRESS_VALUE = new SimpleFloatPropertyCompat("actionBarTransitionProgress", obj -> obj.actionBarTransitionProgress, (obj, value) -> { + obj.actionBarTransitionProgress = value; + obj.invalidate(); + + int subtitleColor = ColorUtils.blendARGB(obj.getColor(Theme.key_actionBarDefaultSubtitle), obj.getColor(Theme.key_windowBackgroundWhiteGrayText), value); + ChatActivity chatActivity = obj.parentEnterView.getParentFragment(); + ActionBar actionBar = chatActivity.getActionBar(); + actionBar.setBackgroundColor(ColorUtils.blendARGB(obj.getColor(Theme.key_actionBarDefault), obj.getColor(Theme.key_windowBackgroundWhite), value)); + actionBar.setItemsColor(ColorUtils.blendARGB(obj.getColor(Theme.key_actionBarDefaultIcon), obj.getColor(Theme.key_windowBackgroundWhiteBlackText), value), false); + actionBar.setItemsBackgroundColor(ColorUtils.blendARGB(obj.getColor(Theme.key_actionBarDefaultSelector), obj.getColor(Theme.key_actionBarWhiteSelector), value), false); + actionBar.setSubtitleColor(subtitleColor); + + ChatAvatarContainer chatAvatarContainer = chatActivity.getAvatarContainer(); + chatAvatarContainer.getTitleTextView().setTextColor(ColorUtils.blendARGB(obj.getColor(Theme.key_actionBarDefaultTitle), obj.getColor(Theme.key_windowBackgroundWhiteBlackText), value)); + chatAvatarContainer.getSubtitleTextView().setTextColor(subtitleColor); + chatAvatarContainer.setOverrideSubtitleColor(value == 0 ? null : subtitleColor); + + obj.updateLightStatusBar(); + }).setMultiplier(100f); + + private float actionBarTransitionProgress; + private SpringAnimation springAnimation; + private ChatAttachAlertBotWebViewLayout.WebViewSwipeContainer swipeContainer; + private ChatAttachAlertBotWebViewLayout.WebProgressView progressView; + private boolean ignoreLayout; + private BotWebViewContainer webViewContainer; + private BotWebViewContainer.Delegate webViewDelegate; + private ValueAnimator webViewScrollAnimator; + private boolean ignoreMeasure; + + private Paint dimPaint = new Paint(); + private Paint backgroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + private Paint linePaint = new Paint(); + + private ChatActivityEnterView parentEnterView; + private boolean botWebViewButtonWasVisible; + private SpringAnimation botWebViewButtonAnimator; + + private long lastSwipeTime; + + private int currentAccount; + private long botId; + private String botUrl; + + private boolean isLoaded; + private boolean dismissed; + + private Boolean wasLightStatusBar; + private long queryId; + + private ActionBarMenuItem botMenuItem; + private ActionBar.ActionBarMenuOnItemClick actionBarOnItemClick; + + private Editable savedEditText; + private MessageObject savedReplyMessageObject; + private MessageObject savedEditMessageObject; + + private Runnable pollRunnable = () -> { + if (!dismissed) { + TLRPC.TL_messages_prolongWebView prolongWebView = new TLRPC.TL_messages_prolongWebView(); + prolongWebView.bot = MessagesController.getInstance(currentAccount).getInputUser(botId); + prolongWebView.peer = MessagesController.getInstance(currentAccount).getInputPeer(botId); + prolongWebView.query_id = queryId; + + ConnectionsManager.getInstance(currentAccount).sendRequest(prolongWebView, (response, error) -> AndroidUtilities.runOnUIThread(() -> { + if (dismissed) { + return; + } + if (error != null) { + dismiss(); + } else { + AndroidUtilities.runOnUIThread(this.pollRunnable, POLL_PERIOD); + } + })); + } + }; + + public BotWebViewMenuContainer(@NonNull Context context, ChatActivityEnterView parentEnterView) { + super(context); + + this.parentEnterView = parentEnterView; + ChatActivity chatActivity = parentEnterView.getParentFragment(); + ActionBar actionBar = chatActivity.getActionBar(); + ActionBarMenu menu = actionBar.createMenu(); + botMenuItem = menu.addItem(1000, R.drawable.ic_ab_other); + botMenuItem.setVisibility(GONE); + + botMenuItem.addSubItem(R.id.menu_reload_page, R.drawable.msg_retry, LocaleController.getString(R.string.BotWebViewReloadPage)); + actionBarOnItemClick = actionBar.getActionBarMenuOnItemClick(); + + webViewContainer = new BotWebViewContainer(context, parentEnterView.getParentFragment().getResourceProvider(), getColor(Theme.key_windowBackgroundWhite)); + webViewContainer.setViewPortOffset(-AndroidUtilities.dp(5)); + webViewContainer.setDelegate(webViewDelegate = new BotWebViewContainer.Delegate() { + private boolean sentWebViewData; + + @Override + public void onCloseRequested() { + dismiss(); + } + + @Override + public void onSendWebViewData(String data) { + if (sentWebViewData) { + return; + } + sentWebViewData = true; + + TLRPC.TL_messages_sendWebViewData sendWebViewData = new TLRPC.TL_messages_sendWebViewData(); + sendWebViewData.bot = MessagesController.getInstance(currentAccount).getInputUser(botId); + sendWebViewData.random_id = Utilities.random.nextLong(); + sendWebViewData.button_text = "Menu"; + sendWebViewData.data = data; + ConnectionsManager.getInstance(currentAccount).sendRequest(sendWebViewData, (response, error) -> AndroidUtilities.runOnUIThread(()-> dismiss())); + } + + @Override + public void onWebAppExpand() { + if (System.currentTimeMillis() - lastSwipeTime <= 1000 || swipeContainer.isSwipeInProgress()) { + return; + } + swipeContainer.stickTo(-swipeContainer.getOffsetY() + swipeContainer.getTopActionBarOffsetY()); + } + + @Override + public void onSetupMainButton(boolean isVisible, boolean isActive, String text, int color, int textColor, boolean isProgressVisible) { + ChatActivityBotWebViewButton botWebViewButton = parentEnterView.getBotWebViewButton(); + botWebViewButton.setupButtonParams(isActive, text, color, textColor, isProgressVisible); + botWebViewButton.setOnClickListener(v -> webViewContainer.onMainButtonPressed()); + if (isVisible != botWebViewButtonWasVisible) { + animateBotButton(isVisible); + } + } + }); + + linePaint.setStyle(Paint.Style.FILL_AND_STROKE); + linePaint.setStrokeWidth(AndroidUtilities.dp(4)); + linePaint.setStrokeCap(Paint.Cap.ROUND); + + dimPaint.setColor(0x40000000); + backgroundPaint.setColor(getColor(Theme.key_windowBackgroundWhite)); + + swipeContainer = new ChatAttachAlertBotWebViewLayout.WebViewSwipeContainer(context) { + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + int availableHeight = MeasureSpec.getSize(heightMeasureSpec); + + int padding; + if (!AndroidUtilities.isTablet() && AndroidUtilities.displaySize.x > AndroidUtilities.displaySize.y) { + padding = (int) (availableHeight / 3.5f); + } else { + padding = (availableHeight / 5 * 2); + } + if (padding < 0) { + padding = 0; + } + + if (getOffsetY() != padding) { + ignoreLayout = true; + setOffsetY(padding); + ignoreLayout = false; + } + + if (AndroidUtilities.isTablet() && !AndroidUtilities.isInMultiwindow && !AndroidUtilities.isSmallTablet()) { + widthMeasureSpec = MeasureSpec.makeMeasureSpec((int) (Math.min(AndroidUtilities.displaySize.x, AndroidUtilities.displaySize.y) * 0.8f), MeasureSpec.EXACTLY); + } + super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(heightMeasureSpec) - ActionBar.getCurrentActionBarHeight() - AndroidUtilities.statusBarHeight + AndroidUtilities.dp(24), MeasureSpec.EXACTLY)); + } + + @Override + public void requestLayout() { + if (ignoreLayout) { + return; + } + super.requestLayout(); + } + }; + swipeContainer.setWebView(webViewContainer.getWebView()); + swipeContainer.setScrollListener(() -> { + if (swipeContainer.getSwipeOffsetY() > 0) { + dimPaint.setAlpha((int) (0x40 * (1f - Math.min(swipeContainer.getSwipeOffsetY(), swipeContainer.getHeight()) / (float)swipeContainer.getHeight()))); + } else { + dimPaint.setAlpha(0x40); + } + invalidate(); + webViewContainer.invalidateViewPortHeight(); + + if (springAnimation != null) { + float progress = (1f - Math.min(swipeContainer.getTopActionBarOffsetY(), swipeContainer.getTranslationY() - swipeContainer.getTopActionBarOffsetY()) / swipeContainer.getTopActionBarOffsetY()); + float newPos = (progress > 0.5f ? 1 : 0) * 100f; + if (springAnimation.getSpring().getFinalPosition() != newPos) { + springAnimation.getSpring().setFinalPosition(newPos); + springAnimation.start(); + } + } + lastSwipeTime = System.currentTimeMillis(); + }); + swipeContainer.setScrollEndListener(()-> webViewContainer.invalidateViewPortHeight(true)); + swipeContainer.addView(webViewContainer); + swipeContainer.setDelegate(this::dismiss); + swipeContainer.setTopActionBarOffsetY(ActionBar.getCurrentActionBarHeight() + AndroidUtilities.statusBarHeight - AndroidUtilities.dp(24)); + swipeContainer.setSwipeOffsetAnimationDisallowed(true); + addView(swipeContainer, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.TOP, 0, 24, 0, 0)); + + addView(progressView = new ChatAttachAlertBotWebViewLayout.WebProgressView(context, parentEnterView.getParentFragment().getResourceProvider()), LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.BOTTOM, 0, 0, 0, 5)); + webViewContainer.setWebViewProgressListener(progress -> { + progressView.setLoadProgressAnimated(progress); + if (progress == 1f) { + ValueAnimator animator = ValueAnimator.ofFloat(1, 0).setDuration(200); + animator.setInterpolator(CubicBezierInterpolator.DEFAULT); + animator.addUpdateListener(animation -> progressView.setAlpha((Float) animation.getAnimatedValue())); + animator.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + progressView.setVisibility(GONE); + } + }); + animator.start(); + } + }); + + setWillNotDraw(false); + } + + private void animateBotButton(boolean isVisible) { + ChatActivityBotWebViewButton botWebViewButton = parentEnterView.getBotWebViewButton(); + if (botWebViewButtonAnimator != null) { + botWebViewButtonAnimator.cancel(); + botWebViewButtonAnimator = null; + } + + botWebViewButton.setProgress(isVisible ? 0f : 1f); + if (isVisible) { + botWebViewButton.setVisibility(VISIBLE); + } + + botWebViewButtonAnimator = new SpringAnimation(botWebViewButton, ChatActivityBotWebViewButton.PROGRESS_PROPERTY) + .setSpring(new SpringForce((isVisible ? 1f : 0f) * ChatActivityBotWebViewButton.PROGRESS_PROPERTY.getMultiplier()) + .setStiffness(isVisible ? 600f : 750f) + .setDampingRatio(SpringForce.DAMPING_RATIO_NO_BOUNCY) + ) + .addUpdateListener((animation, value, velocity) -> { + float v = value / ChatActivityBotWebViewButton.PROGRESS_PROPERTY.getMultiplier(); + parentEnterView.setBotWebViewButtonOffsetX(AndroidUtilities.dp(64) * v); + parentEnterView.setComposeShadowAlpha(1f - v); + }) + .addEndListener((animation, canceled, value, velocity) -> { + if (!isVisible) { + botWebViewButton.setVisibility(GONE); + } + if (botWebViewButtonAnimator == animation) { + botWebViewButtonAnimator = null; + } + }); + botWebViewButtonAnimator.start(); + botWebViewButtonWasVisible = isVisible; + } + + @Override + public void onAttachedToWindow() { + super.onAttachedToWindow(); + + if (springAnimation == null) { + springAnimation = new SpringAnimation(this, ACTION_BAR_TRANSITION_PROGRESS_VALUE) + .setSpring(new SpringForce() + .setStiffness(1200f) + .setDampingRatio(SpringForce.DAMPING_RATIO_NO_BOUNCY) + ) + .addEndListener((animation, canceled, value, velocity) -> { + ChatActivity chatActivity = parentEnterView.getParentFragment(); + ChatAvatarContainer chatAvatarContainer = chatActivity.getAvatarContainer(); + chatAvatarContainer.setClickable(value == 0); + chatAvatarContainer.getAvatarImageView().setClickable(value == 0); + + ActionBar actionBar = chatActivity.getActionBar(); + if (value == 100) { + chatActivity.showHeaderItem(false); + botMenuItem.setVisibility(VISIBLE); + actionBar.setActionBarMenuOnItemClick(new ActionBar.ActionBarMenuOnItemClick() { + @Override + public void onItemClick(int id) { + if (id == -1) { + dismiss(); + } else if (id == R.id.menu_reload_page) { + webViewContainer.getWebView().animate().cancel(); + webViewContainer.getWebView().animate().alpha(0).start(); + + isLoaded = false; + loadWebView(); + } + } + }); + } else { + chatActivity.showHeaderItem(true); + botMenuItem.setVisibility(GONE); + actionBar.setActionBarMenuOnItemClick(actionBarOnItemClick); + } + }); + } + NotificationCenter.getInstance(currentAccount).addObserver(this, NotificationCenter.webViewResultSent); + } + + @Override + public void onDetachedFromWindow() { + super.onDetachedFromWindow(); + + if (springAnimation != null) { + springAnimation.cancel(); + springAnimation = null; + } + NotificationCenter.getInstance(currentAccount).removeObserver(this, NotificationCenter.webViewResultSent); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + if (ignoreMeasure) { + setMeasuredDimension(getMeasuredWidth(), getMeasuredHeight()); + } else { + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + } + } + + public void onPanTransitionStart(boolean keyboardVisible, int contentHeight) { + if (!keyboardVisible) { + return; + } + + int oldh = contentHeight + parentEnterView.getSizeNotifierLayout().measureKeyboardHeight(); + setMeasuredDimension(getMeasuredWidth(), contentHeight); + ignoreMeasure = true; + + if (webViewScrollAnimator != null) { + webViewScrollAnimator.cancel(); + webViewScrollAnimator = null; + } + + int fromY = webViewContainer.getWebView().getScrollY(); + int toY = fromY + (oldh - contentHeight); + webViewScrollAnimator = ValueAnimator.ofInt(fromY, toY).setDuration(250); + webViewScrollAnimator.setInterpolator(ChatListItemAnimator.DEFAULT_INTERPOLATOR); + webViewScrollAnimator.addUpdateListener(animation -> { + int val = (int) animation.getAnimatedValue(); + webViewContainer.getWebView().setScrollY(val); + }); + webViewScrollAnimator.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + webViewContainer.getWebView().setScrollY(toY); + if (animation == webViewScrollAnimator) { + webViewScrollAnimator = null; + } + } + }); + webViewScrollAnimator.start(); + } + + public void onPanTransitionEnd() { + ignoreMeasure = false; + requestLayout(); + } + + private void updateLightStatusBar() { + int color = Theme.getColor(Theme.key_windowBackgroundWhite, null, true); + boolean lightStatusBar = ColorUtils.calculateLuminance(color) >= 0.9 && actionBarTransitionProgress >= 0.85f; + + if (wasLightStatusBar != null && wasLightStatusBar == lightStatusBar) { + return; + } + wasLightStatusBar = lightStatusBar; + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + int flags = getSystemUiVisibility(); + if (lightStatusBar) { + flags |= View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR; + } else { + flags &= ~View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR; + } + setSystemUiVisibility(flags); + } + } + + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + + AndroidUtilities.rectTmp.set(0, 0, getWidth(), getHeight()); + canvas.drawRect(AndroidUtilities.rectTmp, dimPaint); + + float radius = AndroidUtilities.dp(16) * (1f - actionBarTransitionProgress); + AndroidUtilities.rectTmp.set(0, AndroidUtilities.lerp(swipeContainer.getTranslationY(), 0, actionBarTransitionProgress), getWidth(), getHeight() + radius); + canvas.drawRoundRect(AndroidUtilities.rectTmp, radius, radius, backgroundPaint); + } + + @SuppressLint("ClickableViewAccessibility") + @Override + public boolean onTouchEvent(MotionEvent event) { + if (event.getAction() == MotionEvent.ACTION_DOWN && event.getY() <= AndroidUtilities.lerp(swipeContainer.getTranslationY(), 0, actionBarTransitionProgress)) { + dismiss(); + return true; + } + return super.onTouchEvent(event); + } + + @Override + public void draw(Canvas canvas) { + super.draw(canvas); + + linePaint.setColor(Theme.getColor(Theme.key_dialogGrayLine)); + linePaint.setAlpha((int) (linePaint.getAlpha() * (1f - Math.min(0.5f, actionBarTransitionProgress) / 0.5f))); + + canvas.save(); + float scale = 1f - actionBarTransitionProgress; + float y = AndroidUtilities.lerp(swipeContainer.getTranslationY(), AndroidUtilities.statusBarHeight + ActionBar.getCurrentActionBarHeight() / 2f, actionBarTransitionProgress) + AndroidUtilities.dp(12); + canvas.scale(scale, scale, getWidth() / 2f, y); + canvas.drawLine(getWidth() / 2f - AndroidUtilities.dp(16), y, getWidth() / 2f + AndroidUtilities.dp(16), y, linePaint); + canvas.restore(); + } + + /** + * Shows menu for the bot + */ + public void show(int currentAccount, long botId, String botUrl) { + dismissed = false; + if (this.currentAccount != currentAccount || this.botId != botId || !Objects.equals(this.botUrl, botUrl)) { + isLoaded = false; + } + this.currentAccount = currentAccount; + this.botId = botId; + this.botUrl = botUrl; + + savedEditText = parentEnterView.getEditField().getText(); + parentEnterView.getEditField().setText(null); + savedReplyMessageObject = parentEnterView.getReplyingMessageObject(); + savedEditMessageObject = parentEnterView.getEditingMessageObject(); + ChatActivity chatActivity = parentEnterView.getParentFragment(); + if (chatActivity != null) { + chatActivity.hideFieldPanel(true); + } + + if (!isLoaded) { + loadWebView(); + } + + setVisibility(VISIBLE); + setAlpha(0f); + addOnLayoutChangeListener(new View.OnLayoutChangeListener() { + @Override + public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) { + v.removeOnLayoutChangeListener(this); + + swipeContainer.setSwipeOffsetY(swipeContainer.getHeight()); + setAlpha(1f); + + new SpringAnimation(swipeContainer, ChatAttachAlertBotWebViewLayout.WebViewSwipeContainer.SWIPE_OFFSET_Y, 0) + .setSpring(new SpringForce(0) + .setDampingRatio(SpringForce.DAMPING_RATIO_LOW_BOUNCY) + .setStiffness(500.0f) + ) + .addEndListener((animation, canceled, value, velocity) -> webViewContainer.restoreButtonData()) + .start(); + } + }); + } + + private void loadWebView() { + progressView.setLoadProgress(0); + progressView.setAlpha(1f); + progressView.setVisibility(VISIBLE); + + webViewContainer.setBotUser(MessagesController.getInstance(currentAccount).getUser(botId)); + webViewContainer.loadFlicker(currentAccount, botId); + + TLRPC.TL_messages_requestWebView req = new TLRPC.TL_messages_requestWebView(); + req.bot = MessagesController.getInstance(currentAccount).getInputUser(botId); + req.peer = MessagesController.getInstance(currentAccount).getInputPeer(botId); + + req.url = botUrl; + req.flags |= 2; + + try { + JSONObject jsonObject = new JSONObject(); + jsonObject.put("bg_color", getColor(Theme.key_windowBackgroundWhite)); + jsonObject.put("text_color", getColor(Theme.key_windowBackgroundWhiteBlackText)); + jsonObject.put("hint_color", getColor(Theme.key_windowBackgroundWhiteHintText)); + jsonObject.put("link_color", getColor(Theme.key_windowBackgroundWhiteLinkText)); + jsonObject.put("button_color", getColor(Theme.key_featuredStickers_addButton)); + jsonObject.put("button_text_color", getColor(Theme.key_featuredStickers_buttonText)); + + req.theme_params = new TLRPC.TL_dataJSON(); + req.theme_params.data = jsonObject.toString(); + req.flags |= 4; + } catch (Exception e) { + FileLog.e(e); + } + req.from_bot_menu = true; + + ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> AndroidUtilities.runOnUIThread(() -> { + if (response instanceof TLRPC.TL_webViewResultUrl) { + isLoaded = true; + + TLRPC.TL_webViewResultUrl resultUrl = (TLRPC.TL_webViewResultUrl) response; + queryId = resultUrl.query_id; + webViewContainer.loadUrl(resultUrl.url); + + AndroidUtilities.runOnUIThread(pollRunnable, POLL_PERIOD); + } + })); + } + + private int getColor(String key) { + Integer color; + Theme.ResourcesProvider resourcesProvider = parentEnterView.getParentFragment().getResourceProvider(); + if (resourcesProvider != null) { + color = resourcesProvider.getColor(key); + } else { + color = Theme.getColor(key); + } + return color != null ? color : Theme.getColor(key); + } + + /** + * Dismisses menu + */ + public void dismiss() { + dismiss(null); + } + + /** + * Dismisses menu + */ + public void dismiss(Runnable callback) { + if (dismissed) { + return; + } + dismissed = true; + swipeContainer.stickTo(swipeContainer.getHeight() + parentEnterView.getSizeNotifierLayout().measureKeyboardHeight(), ()->{ + onDismiss(); + if (callback != null) { + callback.run(); + } + }); + } + + /** + * Called when menu is fully dismissed + */ + public void onDismiss() { + setVisibility(GONE); + + webViewContainer.destroyWebView(); + swipeContainer.removeView(webViewContainer); + + webViewContainer = new BotWebViewContainer(getContext(), parentEnterView.getParentFragment().getResourceProvider(), getColor(Theme.key_windowBackgroundWhite)); + webViewContainer.setViewPortOffset(-AndroidUtilities.dp(5)); + webViewContainer.setDelegate(webViewDelegate); + webViewContainer.setWebViewProgressListener(progress -> { + progressView.setLoadProgressAnimated(progress); + if (progress == 1f) { + ValueAnimator animator = ValueAnimator.ofFloat(1, 0).setDuration(200); + animator.setInterpolator(CubicBezierInterpolator.DEFAULT); + animator.addUpdateListener(animation -> progressView.setAlpha((Float) animation.getAnimatedValue())); + animator.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + progressView.setVisibility(GONE); + } + }); + animator.start(); + } + }); + swipeContainer.addView(webViewContainer); + swipeContainer.setWebView(webViewContainer.getWebView()); + isLoaded = false; + + AndroidUtilities.cancelRunOnUIThread(pollRunnable); + boolean delayRestoreText = botWebViewButtonWasVisible; + if (botWebViewButtonWasVisible) { + botWebViewButtonWasVisible = false; + animateBotButton(false); + } + + AndroidUtilities.runOnUIThread(()->{ + if (savedEditText != null) { + parentEnterView.getEditField().setText(savedEditText); + savedEditText = null; + } + if (savedReplyMessageObject != null) { + ChatActivity chatActivity = parentEnterView.getParentFragment(); + if (chatActivity != null) { + chatActivity.showFieldPanelForReply(savedReplyMessageObject); + } + savedReplyMessageObject = null; + } + if (savedEditMessageObject != null) { + ChatActivity chatActivity = parentEnterView.getParentFragment(); + if (chatActivity != null) { + chatActivity.showFieldPanelForEdit(true, savedEditMessageObject); + } + savedEditMessageObject = null; + } + }, delayRestoreText ? 200 : 0); + } + + @Override + public void didReceivedNotification(int id, int account, Object... args) { + if (id == NotificationCenter.webViewResultSent) { + long queryId = (long) args[0]; + + if (this.queryId == queryId) { + dismiss(); + } + } + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/BotWebViewSheet.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/BotWebViewSheet.java new file mode 100644 index 000000000..a0dcc7ba2 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/BotWebViewSheet.java @@ -0,0 +1,639 @@ +package org.telegram.ui.Components; + +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.animation.ValueAnimator; +import android.annotation.SuppressLint; +import android.app.Activity; +import android.app.Dialog; +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.graphics.drawable.Drawable; +import android.os.Build; +import android.os.Bundle; +import android.util.TypedValue; +import android.view.Gravity; +import android.view.MotionEvent; +import android.view.View; +import android.view.ViewGroup; +import android.view.Window; +import android.view.WindowManager; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.core.content.ContextCompat; +import androidx.core.graphics.ColorUtils; +import androidx.dynamicanimation.animation.SpringAnimation; +import androidx.dynamicanimation.animation.SpringForce; + +import org.json.JSONObject; +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.FileLog; +import org.telegram.messenger.LocaleController; +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.TLRPC; +import org.telegram.ui.ActionBar.ActionBar; +import org.telegram.ui.ActionBar.ActionBarMenu; +import org.telegram.ui.ActionBar.ActionBarMenuItem; +import org.telegram.ui.ActionBar.Theme; +import org.telegram.ui.ChatActivity; +import org.telegram.ui.LaunchActivity; + +public class BotWebViewSheet extends Dialog implements NotificationCenter.NotificationCenterDelegate { + private final static int POLL_PERIOD = 60000; + + private final static SimpleFloatPropertyCompat ACTION_BAR_TRANSITION_PROGRESS_VALUE = new SimpleFloatPropertyCompat("actionBarTransitionProgress", obj -> obj.actionBarTransitionProgress, (obj, value) -> { + obj.actionBarTransitionProgress = value; + obj.frameLayout.invalidate(); + + obj.actionBar.setAlpha(value); + + obj.updateLightStatusBar(); + }).setMultiplier(100f); + private float actionBarTransitionProgress = 0f; + private SpringAnimation springAnimation; + + private Boolean wasLightStatusBar; + + private SizeNotifierFrameLayout frameLayout; + + private long lastSwipeTime; + + private ChatAttachAlertBotWebViewLayout.WebViewSwipeContainer swipeContainer; + private BotWebViewContainer webViewContainer; + private ChatAttachAlertBotWebViewLayout.WebProgressView progressView; + private Theme.ResourcesProvider resourcesProvider; + private boolean ignoreLayout; + + private int currentAccount; + private long botId; + private long peerId; + private long queryId; + private int replyToMsgId; + private boolean silent; + private String buttonText; + + private Paint linePaint = new Paint(Paint.ANTI_ALIAS_FLAG); + private Paint dimPaint = new Paint(); + private Paint backgroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + + private ActionBar actionBar; + private Drawable actionBarShadow; + + private boolean dismissed; + + private Activity parentActivity; + + private boolean mainButtonWasVisible, mainButtonProgressWasVisible; + private TextView mainButton; + private RadialProgressView radialProgressView; + + private VerticalPositionAutoAnimator mainButtonAutoAnimator, radialProgressAutoAnimator; + + private Runnable pollRunnable = () -> { + if (!dismissed) { + TLRPC.TL_messages_prolongWebView prolongWebView = new TLRPC.TL_messages_prolongWebView(); + prolongWebView.bot = MessagesController.getInstance(currentAccount).getInputUser(botId); + prolongWebView.peer = MessagesController.getInstance(currentAccount).getInputPeer(peerId); + prolongWebView.query_id = queryId; + prolongWebView.silent = silent; + if (replyToMsgId != 0) { + prolongWebView.reply_to_msg_id = replyToMsgId; + prolongWebView.flags |= 1; + } + ConnectionsManager.getInstance(currentAccount).sendRequest(prolongWebView, (response, error) -> AndroidUtilities.runOnUIThread(() -> { + if (dismissed) { + return; + } + if (error != null) { + dismiss(); + } else { + AndroidUtilities.runOnUIThread(this.pollRunnable, POLL_PERIOD); + } + })); + } + }; + + public BotWebViewSheet(@NonNull Context context, Theme.ResourcesProvider resourcesProvider) { + super(context, R.style.TransparentDialog); + this.resourcesProvider = resourcesProvider; + + swipeContainer = new ChatAttachAlertBotWebViewLayout.WebViewSwipeContainer(context) { + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + int availableHeight = MeasureSpec.getSize(heightMeasureSpec); + + int padding; + if (!AndroidUtilities.isTablet() && AndroidUtilities.displaySize.x > AndroidUtilities.displaySize.y) { + padding = (int) (availableHeight / 3.5f); + } else { + padding = (availableHeight / 5 * 2); + } + if (padding < 0) { + padding = 0; + } + + if (getOffsetY() != padding && !dismissed) { + ignoreLayout = true; + setOffsetY(padding); + ignoreLayout = false; + } + + if (AndroidUtilities.isTablet() && !AndroidUtilities.isInMultiwindow && !AndroidUtilities.isSmallTablet()) { + widthMeasureSpec = MeasureSpec.makeMeasureSpec((int) (Math.min(AndroidUtilities.displaySize.x, AndroidUtilities.displaySize.y) * 0.8f), MeasureSpec.EXACTLY); + } + super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(heightMeasureSpec) - ActionBar.getCurrentActionBarHeight() - AndroidUtilities.statusBarHeight + AndroidUtilities.dp(24) - (mainButtonWasVisible ? mainButton.getLayoutParams().height : 0), MeasureSpec.EXACTLY)); + } + + @Override + public void requestLayout() { + if (ignoreLayout) { + return; + } + super.requestLayout(); + } + }; + webViewContainer = new BotWebViewContainer(context, resourcesProvider, getColor(Theme.key_windowBackgroundWhite)); + + webViewContainer.getWebView().setVerticalScrollBarEnabled(false); + webViewContainer.setDelegate(new BotWebViewContainer.Delegate() { + private boolean sentWebViewData; + + @Override + public void onCloseRequested() { + dismiss(); + } + + @Override + public void onSendWebViewData(String data) { + if (sentWebViewData) { + return; + } + sentWebViewData = true; + + TLRPC.TL_messages_sendWebViewData sendWebViewData = new TLRPC.TL_messages_sendWebViewData(); + sendWebViewData.bot = MessagesController.getInstance(currentAccount).getInputUser(botId); + sendWebViewData.random_id = Utilities.random.nextLong(); + sendWebViewData.button_text = buttonText; + sendWebViewData.data = data; + ConnectionsManager.getInstance(currentAccount).sendRequest(sendWebViewData, (response, error) -> AndroidUtilities.runOnUIThread(()-> dismiss())); + } + + @Override + public void onWebAppExpand() { + if (System.currentTimeMillis() - lastSwipeTime <= 1000 || swipeContainer.isSwipeInProgress()) { + return; + } + swipeContainer.stickTo(-swipeContainer.getOffsetY() + swipeContainer.getTopActionBarOffsetY()); + } + + @Override + public void onSetupMainButton(boolean isVisible, boolean isActive, String text, int color, int textColor, boolean isProgressVisible) { + mainButton.setClickable(isActive); + mainButton.setText(text); + mainButton.setTextColor(textColor); + mainButton.setBackground(Theme.createSelectorWithBackgroundDrawable(color, Theme.getColor(Theme.key_listSelector))); + if (isVisible != mainButtonWasVisible) { + mainButtonWasVisible = isVisible; + mainButton.animate().cancel(); + if (isVisible) { + mainButton.setAlpha(0f); + mainButton.setVisibility(View.VISIBLE); + } + mainButton.animate().alpha(isVisible ? 1f : 0f).setDuration(150).setListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + if (!isVisible) { + mainButton.setVisibility(View.GONE); + } + swipeContainer.requestLayout(); + } + }).start(); + } + radialProgressView.setProgressColor(textColor); + if (isProgressVisible != mainButtonProgressWasVisible) { + mainButtonProgressWasVisible = isProgressVisible; + radialProgressView.animate().cancel(); + if (isProgressVisible) { + radialProgressView.setAlpha(0f); + radialProgressView.setVisibility(View.VISIBLE); + } + radialProgressView.animate().alpha(isProgressVisible ? 1f : 0f) + .scaleX(isProgressVisible ? 1f : 0.1f) + .scaleY(isProgressVisible ? 1f : 0.1f) + .setDuration(250) + .setListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + if (!isProgressVisible) { + radialProgressView.setVisibility(View.GONE); + } + } + }).start(); + } + } + }); + + linePaint.setStyle(Paint.Style.FILL_AND_STROKE); + linePaint.setStrokeWidth(AndroidUtilities.dp(4)); + linePaint.setStrokeCap(Paint.Cap.ROUND); + + backgroundPaint.setColor(getColor(Theme.key_windowBackgroundWhite)); + dimPaint.setColor(0x40000000); + frameLayout = new SizeNotifierFrameLayout(context) { + { + setWillNotDraw(false); + } + + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + + AndroidUtilities.rectTmp.set(0, 0, getWidth(), getHeight()); + canvas.drawRect(AndroidUtilities.rectTmp, dimPaint); + + float radius = AndroidUtilities.dp(16) * (1f - actionBarTransitionProgress); + AndroidUtilities.rectTmp.set(0, AndroidUtilities.lerp(swipeContainer.getTranslationY(), 0, actionBarTransitionProgress), getWidth(), getHeight() + radius); + canvas.drawRoundRect(AndroidUtilities.rectTmp, radius, radius, backgroundPaint); + } + + @Override + public void draw(Canvas canvas) { + super.draw(canvas); + + linePaint.setColor(Theme.getColor(Theme.key_dialogGrayLine)); + linePaint.setAlpha((int) (linePaint.getAlpha() * (1f - Math.min(0.5f, actionBarTransitionProgress) / 0.5f))); + + canvas.save(); + float scale = 1f - actionBarTransitionProgress; + float y = AndroidUtilities.lerp(swipeContainer.getTranslationY(), AndroidUtilities.statusBarHeight + ActionBar.getCurrentActionBarHeight() / 2f, actionBarTransitionProgress) + AndroidUtilities.dp(12); + canvas.scale(scale, scale, getWidth() / 2f, y); + canvas.drawLine(getWidth() / 2f - AndroidUtilities.dp(16), y, getWidth() / 2f + AndroidUtilities.dp(16), y, linePaint); + canvas.restore(); + + actionBarShadow.setAlpha((int) (actionBar.getAlpha() * 0xFF)); + y = actionBar.getY() + actionBar.getTranslationY() + actionBar.getHeight(); + actionBarShadow.setBounds(0, (int)y, getWidth(), (int)(y + actionBarShadow.getIntrinsicHeight())); + actionBarShadow.draw(canvas); + } + + @SuppressLint("ClickableViewAccessibility") + @Override + public boolean onTouchEvent(MotionEvent event) { + if (event.getAction() == MotionEvent.ACTION_DOWN && event.getY() < AndroidUtilities.lerp(swipeContainer.getTranslationY(), 0, actionBarTransitionProgress)) { + dismiss(); + return true; + } + return super.onTouchEvent(event); + } + }; + frameLayout.setDelegate((keyboardHeight, isWidthGreater) -> { + if (keyboardHeight > AndroidUtilities.dp(20)) { + swipeContainer.stickTo(-swipeContainer.getOffsetY() + swipeContainer.getTopActionBarOffsetY()); + } + }); + frameLayout.addView(swipeContainer, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.TOP, 0, 24, 0, 0)); + + mainButton = new TextView(context); + mainButton.setVisibility(View.GONE); + mainButton.setAlpha(0f); + mainButton.setSingleLine(); + mainButton.setGravity(Gravity.CENTER); + mainButton.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); + int padding = AndroidUtilities.dp(16); + mainButton.setPadding(padding, 0, padding, 0); + mainButton.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); + mainButton.setOnClickListener(v -> webViewContainer.onMainButtonPressed()); + frameLayout.addView(mainButton, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 48, Gravity.BOTTOM)); + mainButtonAutoAnimator = VerticalPositionAutoAnimator.attach(mainButton); + + radialProgressView = new RadialProgressView(context); + radialProgressView.setSize(AndroidUtilities.dp(18)); + radialProgressView.setAlpha(0f); + radialProgressView.setScaleX(0.1f); + radialProgressView.setScaleY(0.1f); + radialProgressView.setVisibility(View.GONE); + frameLayout.addView(radialProgressView, LayoutHelper.createFrame(28, 28, Gravity.BOTTOM | Gravity.RIGHT, 0, 0, 10, 10)); + radialProgressAutoAnimator = VerticalPositionAutoAnimator.attach(radialProgressView); + + actionBarShadow = ContextCompat.getDrawable(getContext(), R.drawable.header_shadow).mutate(); + + actionBar = new ActionBar(context, resourcesProvider); + actionBar.setBackgroundColor(Color.TRANSPARENT); + actionBar.setTitleColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlackText)); + actionBar.setItemsColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlackText), false); + actionBar.setItemsBackgroundColor(Theme.getColor(Theme.key_actionBarWhiteSelector), false); + actionBar.setBackButtonImage(R.drawable.ic_ab_back); + actionBar.setActionBarMenuOnItemClick(new ActionBar.ActionBarMenuOnItemClick() { + @Override + public void onItemClick(int id) { + if (id == -1) { + dismiss(); + } + } + }); + actionBar.setAlpha(0f); + frameLayout.addView(actionBar, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.TOP)); + + frameLayout.addView(progressView = new ChatAttachAlertBotWebViewLayout.WebProgressView(context, resourcesProvider), LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.BOTTOM, 0, 0, 0, 0)); + webViewContainer.setWebViewProgressListener(progress -> { + progressView.setLoadProgressAnimated(progress); + if (progress == 1f) { + ValueAnimator animator = ValueAnimator.ofFloat(1, 0).setDuration(200); + animator.setInterpolator(CubicBezierInterpolator.DEFAULT); + animator.addUpdateListener(animation -> progressView.setAlpha((Float) animation.getAnimatedValue())); + animator.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + progressView.setVisibility(View.GONE); + } + }); + animator.start(); + } + }); + + swipeContainer.addView(webViewContainer, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); + swipeContainer.setWebView(webViewContainer.getWebView()); + swipeContainer.setScrollListener(()->{ + if (swipeContainer.getSwipeOffsetY() > 0) { + dimPaint.setAlpha((int) (0x40 * (1f - swipeContainer.getSwipeOffsetY() / (float)swipeContainer.getHeight()))); + } else { + dimPaint.setAlpha(0x40); + } + frameLayout.invalidate(); + webViewContainer.invalidateViewPortHeight(); + + if (springAnimation != null) { + float progress = (1f - Math.min(swipeContainer.getTopActionBarOffsetY(), swipeContainer.getTranslationY() - swipeContainer.getTopActionBarOffsetY()) / swipeContainer.getTopActionBarOffsetY()); + float newPos = (progress > 0.5f ? 1 : 0) * 100f; + if (springAnimation.getSpring().getFinalPosition() != newPos) { + springAnimation.getSpring().setFinalPosition(newPos); + springAnimation.start(); + } + } + float offsetY = Math.max(0, swipeContainer.getSwipeOffsetY()); + mainButtonAutoAnimator.setOffsetY(offsetY); + radialProgressAutoAnimator.setOffsetY(offsetY); + lastSwipeTime = System.currentTimeMillis(); + }); + swipeContainer.setScrollEndListener(()-> webViewContainer.invalidateViewPortHeight(true)); + swipeContainer.setDelegate(this::dismiss); + swipeContainer.setTopActionBarOffsetY(ActionBar.getCurrentActionBarHeight() + AndroidUtilities.statusBarHeight - AndroidUtilities.dp(24)); + + setContentView(frameLayout, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); + } + + public void setParentActivity(Activity parentActivity) { + this.parentActivity = parentActivity; + } + + private void updateLightStatusBar() { + int color = Theme.getColor(Theme.key_windowBackgroundWhite, null, true); + boolean lightStatusBar = ColorUtils.calculateLuminance(color) >= 0.9 && actionBarTransitionProgress >= 0.85f; + + if (wasLightStatusBar != null && wasLightStatusBar == lightStatusBar) { + return; + } + wasLightStatusBar = lightStatusBar; + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + int flags = frameLayout.getSystemUiVisibility(); + if (lightStatusBar) { + flags |= View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR; + } else { + flags &= ~View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR; + } + frameLayout.setSystemUiVisibility(flags); + } + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + Window window = getWindow(); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { + window.addFlags(WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN | WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS); + } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + window.addFlags(WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN | WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS); + } + window.setWindowAnimations(R.style.DialogNoAnimation); + + WindowManager.LayoutParams params = window.getAttributes(); + params.width = ViewGroup.LayoutParams.MATCH_PARENT; + params.gravity = Gravity.TOP | Gravity.LEFT; + params.dimAmount = 0; + params.flags &= ~WindowManager.LayoutParams.FLAG_DIM_BEHIND; + params.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE; + params.height = ViewGroup.LayoutParams.MATCH_PARENT; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { + params.layoutInDisplayCutoutMode = WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES; + } + window.setAttributes(params); + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + window.setStatusBarColor(Color.TRANSPARENT); + } + + frameLayout.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + frameLayout.setOnApplyWindowInsetsListener((v, insets) -> { + v.setPadding(0, 0, 0, insets.getSystemWindowInsetBottom()); + return insets; + }); + } + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + int color = Theme.getColor(Theme.key_windowBackgroundWhite, null, true); + AndroidUtilities.setLightNavigationBar(window, ColorUtils.calculateLuminance(color) >= 0.9); + } + } + + @Override + public void onAttachedToWindow() { + super.onAttachedToWindow(); + + if (springAnimation == null) { + springAnimation = new SpringAnimation(this, ACTION_BAR_TRANSITION_PROGRESS_VALUE) + .setSpring(new SpringForce() + .setStiffness(1200f) + .setDampingRatio(SpringForce.DAMPING_RATIO_NO_BOUNCY) + ); + } + } + + @Override + public void onDetachedFromWindow() { + super.onDetachedFromWindow(); + + if (springAnimation != null) { + springAnimation.cancel(); + springAnimation = null; + } + } + + public void requestWebView(int currentAccount, long peerId, long botId, String buttonText, String buttonUrl, boolean simple, int replyToMsgId, boolean silent) { + this.currentAccount = currentAccount; + this.peerId = peerId; + this.botId = botId; + this.replyToMsgId = replyToMsgId; + this.silent = silent; + this.buttonText = buttonText; + + actionBar.setTitle(UserObject.getUserName(MessagesController.getInstance(currentAccount).getUser(botId))); + ActionBarMenu menu = actionBar.createMenu(); + menu.removeAllViews(); + + ActionBarMenuItem otherItem = menu.addItem(0, R.drawable.ic_ab_other); + otherItem.addSubItem(R.id.menu_open_bot, R.drawable.msg_bot, LocaleController.getString(R.string.BotWebViewOpenBot)); + otherItem.addSubItem(R.id.menu_reload_page, R.drawable.msg_retry, LocaleController.getString(R.string.BotWebViewReloadPage)); + actionBar.setActionBarMenuOnItemClick(new ActionBar.ActionBarMenuOnItemClick() { + @Override + public void onItemClick(int id) { + if (id == -1) { + dismiss(); + } else if (id == R.id.menu_open_bot) { + Bundle bundle = new Bundle(); + bundle.putLong("user_id", botId); + if (parentActivity instanceof LaunchActivity) { + ((LaunchActivity) parentActivity).presentFragment(new ChatActivity(bundle)); + } + dismiss(); + } else if (id == R.id.menu_reload_page) { + webViewContainer.getWebView().animate().cancel(); + webViewContainer.getWebView().animate().alpha(0).start(); + requestWebView(currentAccount, peerId, botId, buttonText, buttonUrl, simple, replyToMsgId, silent); + } + } + }); + + boolean hasThemeParams = true; + String themeParams = null; + try { + JSONObject jsonObject = new JSONObject(); + jsonObject.put("bg_color", getColor(Theme.key_windowBackgroundWhite)); + jsonObject.put("text_color", getColor(Theme.key_windowBackgroundWhiteBlackText)); + jsonObject.put("hint_color", getColor(Theme.key_windowBackgroundWhiteHintText)); + jsonObject.put("link_color", getColor(Theme.key_windowBackgroundWhiteLinkText)); + jsonObject.put("button_color", getColor(Theme.key_featuredStickers_addButton)); + jsonObject.put("button_text_color", getColor(Theme.key_featuredStickers_buttonText)); + themeParams = jsonObject.toString(); + } catch (Exception e) { + FileLog.e(e); + hasThemeParams = false; + } + + webViewContainer.setBotUser(MessagesController.getInstance(currentAccount).getUser(botId)); + webViewContainer.loadFlicker(currentAccount, botId); + if (simple) { + TLRPC.TL_messages_requestSimpleWebView req = new TLRPC.TL_messages_requestSimpleWebView(); + req.bot = MessagesController.getInstance(currentAccount).getInputUser(botId); + if (hasThemeParams) { + req.theme_params = new TLRPC.TL_dataJSON(); + req.theme_params.data = themeParams; + req.flags |= 1; + } + req.url = buttonUrl; + + ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> AndroidUtilities.runOnUIThread(()->{ + if (response instanceof TLRPC.TL_simpleWebViewResultUrl) { + TLRPC.TL_simpleWebViewResultUrl resultUrl = (TLRPC.TL_simpleWebViewResultUrl) response; + webViewContainer.loadUrl(resultUrl.url); + } + })); + } else { + TLRPC.TL_messages_requestWebView req = new TLRPC.TL_messages_requestWebView(); + req.peer = MessagesController.getInstance(currentAccount).getInputPeer(peerId); + req.bot = MessagesController.getInstance(currentAccount).getInputUser(botId); + if (buttonUrl != null) { + req.url = buttonUrl; + req.flags |= 2; + } + + if (replyToMsgId != 0) { + req.reply_to_msg_id = replyToMsgId; + req.flags |= 1; + } + + if (hasThemeParams) { + req.theme_params = new TLRPC.TL_dataJSON(); + req.theme_params.data = themeParams; + req.flags |= 4; + } + + ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> AndroidUtilities.runOnUIThread(() -> { + if (response instanceof TLRPC.TL_webViewResultUrl) { + TLRPC.TL_webViewResultUrl resultUrl = (TLRPC.TL_webViewResultUrl) response; + queryId = resultUrl.query_id; + webViewContainer.loadUrl(resultUrl.url); + + AndroidUtilities.runOnUIThread(pollRunnable, POLL_PERIOD); + } + })); + NotificationCenter.getInstance(currentAccount).addObserver(this, NotificationCenter.webViewResultSent); + } + } + + private int getColor(String key) { + Integer color; + if (resourcesProvider != null) { + color = resourcesProvider.getColor(key); + } else { + color = Theme.getColor(key); + } + return color != null ? color : Theme.getColor(key); + } + + @Override + public void show() { + frameLayout.setAlpha(0f); + frameLayout.addOnLayoutChangeListener(new View.OnLayoutChangeListener() { + @Override + public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) { + v.removeOnLayoutChangeListener(this); + + swipeContainer.setSwipeOffsetY(swipeContainer.getHeight()); + frameLayout.setAlpha(1f); + + new SpringAnimation(swipeContainer, ChatAttachAlertBotWebViewLayout.WebViewSwipeContainer.SWIPE_OFFSET_Y, 0) + .setSpring(new SpringForce(0) + .setDampingRatio(SpringForce.DAMPING_RATIO_LOW_BOUNCY) + .setStiffness(500.0f) + ).start(); + } + }); + super.show(); + } + + @Override + public void dismiss() { + if (dismissed) { + return; + } + dismissed = true; + AndroidUtilities.cancelRunOnUIThread(pollRunnable); + + webViewContainer.destroyWebView(); + NotificationCenter.getInstance(currentAccount).removeObserver(this, NotificationCenter.webViewResultSent); + + swipeContainer.stickTo(swipeContainer.getHeight() + frameLayout.measureKeyboardHeight(), super::dismiss); + } + + @Override + public void didReceivedNotification(int id, int account, Object... args) { + if (id == NotificationCenter.webViewResultSent) { + long queryId = (long) args[0]; + + if (this.queryId == queryId) { + dismiss(); + } + } + } +} 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 d6e5ae053..ea80522df 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Bulletin.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Bulletin.java @@ -62,6 +62,7 @@ public class Bulletin { public static final int TYPE_ERROR = 1; public static final int TYPE_BIO_CHANGED = 2; public static final int TYPE_NAME_CHANGED = 3; + public static final int TYPE_ERROR_SUBTITLE = 4; public int tag; @@ -1004,6 +1005,7 @@ public class Bulletin { addView(imageView, LayoutHelper.createFrameRelatively(56, 48, Gravity.START | Gravity.CENTER_VERTICAL)); final int undoInfoColor = getThemedColor(Theme.key_undo_infoColor); + final int undoLinkColor = getThemedColor(Theme.key_voipgroup_overlayBlue1); final LinearLayout linearLayout = new LinearLayout(context); linearLayout.setOrientation(LinearLayout.VERTICAL); @@ -1018,6 +1020,7 @@ public class Bulletin { subtitleTextView = new TextView(context); subtitleTextView.setTextColor(undoInfoColor); + subtitleTextView.setLinkTextColor(undoLinkColor); subtitleTextView.setTypeface(Typeface.SANS_SERIF); subtitleTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 13); linearLayout.addView(subtitleTextView); 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 1ad7d82c0..f61597ab3 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/BulletinFactory.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/BulletinFactory.java @@ -1,7 +1,6 @@ package org.telegram.ui.Components; import android.content.Context; -import android.os.Build; import android.widget.FrameLayout; import androidx.annotation.CheckResult; @@ -128,6 +127,14 @@ public final class BulletinFactory { return create(layout, Bulletin.DURATION_SHORT); } + public Bulletin createSimpleBulletin(int iconRawId, CharSequence text, CharSequence subtext) { + final Bulletin.TwoLineLottieLayout layout = new Bulletin.TwoLineLottieLayout(getContext(), resourcesProvider); + layout.setAnimation(iconRawId, 36, 36); + layout.titleTextView.setText(text); + layout.subtitleTextView.setText(subtext); + return create(layout, Bulletin.DURATION_SHORT); + } + @CheckResult public Bulletin createDownloadBulletin(FileType fileType) { return createDownloadBulletin(fileType, resourcesProvider); @@ -184,6 +191,14 @@ public final class BulletinFactory { return create(layout, Bulletin.DURATION_SHORT); } + public Bulletin createErrorBulletinSubtitle(CharSequence errorMessage, CharSequence errorDescription, Theme.ResourcesProvider resourcesProvider) { + Bulletin.TwoLineLottieLayout layout = new Bulletin.TwoLineLottieLayout(getContext(), resourcesProvider); + layout.setAnimation(R.raw.chats_infotip); + layout.titleTextView.setText(errorMessage); + layout.subtitleTextView.setText(errorDescription); + return create(layout, Bulletin.DURATION_SHORT); + } + @CheckResult public Bulletin createCopyLinkBulletin() { return createCopyLinkBulletin(false, resourcesProvider); @@ -191,7 +206,7 @@ public final class BulletinFactory { @CheckResult public Bulletin createCopyBulletin(String message) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { + if (!AndroidUtilities.shouldShowClipboardToast()) { return new Bulletin.EmptyBulletin(); } final Bulletin.LottieLayout layout = new Bulletin.LottieLayout(getContext(), null); @@ -202,7 +217,7 @@ public final class BulletinFactory { @CheckResult public Bulletin createCopyLinkBulletin(boolean isPrivate, Theme.ResourcesProvider resourcesProvider) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { + if (!AndroidUtilities.shouldShowClipboardToast()) { return new Bulletin.EmptyBulletin(); } if (isPrivate) { @@ -235,17 +250,23 @@ public final class BulletinFactory { @CheckResult public static Bulletin createMuteBulletin(BaseFragment fragment, int setting) { - return createMuteBulletin(fragment, setting, null); + return createMuteBulletin(fragment, setting, 0, null); } @CheckResult - public static Bulletin createMuteBulletin(BaseFragment fragment, int setting, Theme.ResourcesProvider resourcesProvider) { + public static Bulletin createMuteBulletin(BaseFragment fragment, int setting, int timeInSeconds, Theme.ResourcesProvider resourcesProvider) { final Bulletin.LottieLayout layout = new Bulletin.LottieLayout(fragment.getParentActivity(), resourcesProvider); final String text; final boolean mute; + boolean muteFor = false; switch (setting) { + case NotificationsController.SETTING_MUTE_CUSTOM: + text = LocaleController.formatString("NotificationsMutedForHint", R.string.NotificationsMutedForHint, LocaleController.formatTTLString(timeInSeconds)); + mute = true; + muteFor = true; + break; case NotificationsController.SETTING_MUTE_HOUR: text = LocaleController.formatString("NotificationsMutedForHint", R.string.NotificationsMutedForHint, LocaleController.formatPluralString("Hours", 1)); mute = true; @@ -270,7 +291,9 @@ public final class BulletinFactory { throw new IllegalArgumentException(); } - if (mute) { + if (muteFor) { + layout.setAnimation(R.raw.mute_for); + } else if (mute) { layout.setAnimation(R.raw.ic_mute, "Body Main", "Body Top", "Line", "Curve Big", "Curve Small"); } else { layout.setAnimation(R.raw.ic_unmute, "BODY", "Wibe Big", "Wibe Big 3", "Wibe Small"); @@ -282,7 +305,7 @@ public final class BulletinFactory { @CheckResult public static Bulletin createMuteBulletin(BaseFragment fragment, boolean muted, Theme.ResourcesProvider resourcesProvider) { - return createMuteBulletin(fragment, muted ? NotificationsController.SETTING_MUTE_FOREVER : NotificationsController.SETTING_MUTE_UNMUTE, resourcesProvider); + return createMuteBulletin(fragment, muted ? NotificationsController.SETTING_MUTE_FOREVER : NotificationsController.SETTING_MUTE_UNMUTE, 0, resourcesProvider); } @CheckResult @@ -336,6 +359,14 @@ public final class BulletinFactory { return Bulletin.make(fragment, layout, Bulletin.DURATION_SHORT); } + @CheckResult + public static Bulletin createAddedAsAdminBulletin(BaseFragment fragment, String userFirstName) { + final Bulletin.LottieLayout layout = new Bulletin.LottieLayout(fragment.getParentActivity(), null); + layout.setAnimation(R.raw.ic_admin, "Shield"); + layout.textView.setText(AndroidUtilities.replaceTags(LocaleController.formatString("UserAddedAsAdminHint", R.string.UserAddedAsAdminHint, userFirstName))); + return Bulletin.make(fragment, layout, Bulletin.DURATION_SHORT); + } + @CheckResult public static Bulletin createRemoveFromChatBulletin(BaseFragment fragment, TLRPC.User user, String chatName) { final Bulletin.LottieLayout layout = new Bulletin.LottieLayout(fragment.getParentActivity(), null); @@ -395,5 +426,35 @@ public final class BulletinFactory { } return Bulletin.make(fragment, layout, pinned ? Bulletin.DURATION_SHORT : 5000); } + + @CheckResult + public static Bulletin createSoundEnabledBulletin(BaseFragment fragment, int setting, Theme.ResourcesProvider resourcesProvider) { + final Bulletin.LottieLayout layout = new Bulletin.LottieLayout(fragment.getParentActivity(), resourcesProvider); + + final String text; + final boolean soundOn; + + switch (setting) { + case NotificationsController.SETTING_SOUND_ON: + text = LocaleController.getString("SoundOnHint", R.string.SoundOnHint); + soundOn = true; + break; + case NotificationsController.SETTING_SOUND_OFF: + text = LocaleController.getString("SoundOffHint", R.string.SoundOffHint); + soundOn = false; + break; + default: + throw new IllegalArgumentException(); + } + + if (soundOn) { + layout.setAnimation(R.raw.sound_on); + } else { + layout.setAnimation(R.raw.sound_off); + } + + layout.textView.setText(text); + return Bulletin.make(fragment, layout, Bulletin.DURATION_SHORT); + } //endregion } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatActivityBotWebViewButton.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatActivityBotWebViewButton.java new file mode 100644 index 000000000..234e51027 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatActivityBotWebViewButton.java @@ -0,0 +1,135 @@ +package org.telegram.ui.Components; + +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Path; +import android.util.TypedValue; +import android.view.Gravity; +import android.view.View; +import android.widget.FrameLayout; +import android.widget.TextView; + +import androidx.core.graphics.ColorUtils; + +import org.telegram.messenger.AndroidUtilities; +import org.telegram.ui.ActionBar.Theme; + +public class ChatActivityBotWebViewButton extends FrameLayout { + public final static SimpleFloatPropertyCompat PROGRESS_PROPERTY = new SimpleFloatPropertyCompat<>("progress", obj -> obj.progress, ChatActivityBotWebViewButton::setProgress) + .setMultiplier(100f); + + private Path path = new Path(); + private float progress; + private int buttonColor = Theme.getColor(Theme.key_featuredStickers_addButton); + private int backgroundColor; + private int menuButtonWidth; + + private TextView textView; + private RadialProgressView progressView; + private View rippleView; + + private boolean progressWasVisible; + private BotCommandsMenuView menuButton; + + public ChatActivityBotWebViewButton(Context context) { + super(context); + + textView = new TextView(context); + textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); + textView.setSingleLine(); + textView.setAlpha(0f); + textView.setGravity(Gravity.CENTER); + textView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); + addView(textView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.LEFT, 0, 0, 0, 4)); + + progressView = new RadialProgressView(context); + progressView.setSize(AndroidUtilities.dp(18)); + progressView.setAlpha(0f); + progressView.setScaleX(0); + progressView.setScaleY(0); + addView(progressView, LayoutHelper.createFrame(28, 28, Gravity.RIGHT | Gravity.CENTER_VERTICAL, 0, 0, 12, 4)); + + rippleView = new View(context); + rippleView.setBackground(Theme.createSelectorDrawable(Theme.getColor(Theme.key_listSelector), 2)); + addView(rippleView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.LEFT, 0, -4, 0, 0)); + + setWillNotDraw(false); + } + + public void setBotMenuButton(BotCommandsMenuView menuButton) { + this.menuButton = menuButton; + invalidate(); + } + + public void setupButtonParams(boolean isActive, String text, int color, int textColor, boolean isProgressVisible) { + setClickable(isActive); + rippleView.setVisibility(isActive ? VISIBLE : GONE); + textView.setText(text); + textView.setTextColor(textColor); + buttonColor = color; + + progressView.setProgressColor(textColor); + if (progressWasVisible != isProgressVisible) { + progressWasVisible = isProgressVisible; + progressView.animate().cancel(); + if (isProgressVisible) { + progressView.setAlpha(0f); + progressView.setVisibility(VISIBLE); + } + progressView.animate().alpha(isProgressVisible ? 1f : 0f) + .scaleX(isProgressVisible ? 1f : 0.1f) + .scaleY(isProgressVisible ? 1f : 0.1f) + .setDuration(250) + .setListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + if (!isProgressVisible) { + progressView.setVisibility(GONE); + } + } + }).start(); + } + } + + public void setProgress(float progress) { + this.progress = progress; + backgroundColor = ColorUtils.blendARGB(Theme.getColor(Theme.key_chat_messagePanelVoiceBackground), buttonColor, progress); + for (int i = 0; i < getChildCount(); i++) { + getChildAt(i).setAlpha(progress); + } + invalidate(); + } + + public void setMeasuredButtonWidth(int width) { + menuButtonWidth = width; + invalidate(); + } + + @Override + public void draw(Canvas canvas) { + canvas.save(); + float offset = Math.max(getWidth() - menuButtonWidth - AndroidUtilities.dp(4), getHeight()) * progress; + float rad = AndroidUtilities.dp(16) + offset; + AndroidUtilities.rectTmp.set(AndroidUtilities.dp(14) - offset, AndroidUtilities.dp(8) - offset, AndroidUtilities.dp(6) + menuButtonWidth + offset, getHeight() - AndroidUtilities.dp(12) + offset); + + path.rewind(); + path.addRoundRect(AndroidUtilities.rectTmp, rad, rad, Path.Direction.CW); + canvas.clipPath(path); + canvas.drawColor(backgroundColor); + + canvas.saveLayerAlpha(AndroidUtilities.rectTmp, (int) ((1f - Math.min(0.5f, progress) / 0.5f) * 0xFF), Canvas.ALL_SAVE_FLAG); + canvas.translate(AndroidUtilities.dp(10), AndroidUtilities.dp(4)); + if (menuButton != null) { + menuButton.setDrawBackgroundDrawable(false); + menuButton.draw(canvas); + menuButton.setDrawBackgroundDrawable(true); + } + canvas.restore(); + + canvas.translate(-AndroidUtilities.dp(8) * (1f - progress), 0); + super.draw(canvas); + canvas.restore(); + } +} 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 356880815..ac087c863 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatActivityEnterView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatActivityEnterView.java @@ -118,6 +118,7 @@ import org.telegram.messenger.NotificationsController; import org.telegram.messenger.R; import org.telegram.messenger.SendMessagesHelper; import org.telegram.messenger.SharedConfig; +import org.telegram.messenger.SharedPrefsHelper; import org.telegram.messenger.UserConfig; import org.telegram.messenger.UserObject; import org.telegram.messenger.Utilities; @@ -272,6 +273,13 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific boolean messageTransitionIsRunning; boolean textTransitionIsRunning; + private BotMenuButtonType botMenuButtonType = BotMenuButtonType.NO_BUTTON; + private String botMenuWebViewTitle; + private String botMenuWebViewUrl; + + private BotWebViewMenuContainer botWebViewMenuContainer; + private ChatActivityBotWebViewButton botWebViewButton; + private BotCommandsMenuView botCommandsMenuButton; public BotCommandsMenuContainer botCommandsMenuContainer; private BotCommandsMenuView.BotCommandsAdapter botCommandsAdapter; @@ -518,6 +526,10 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific private Runnable openKeyboardRunnable = new Runnable() { @Override public void run() { + if (hasBotWebView() && botCommandsMenuIsShowing()) { + return; + } + if (!destroyed && messageEditText != null && waitingForKeyboardOpen && !keyboardVisible && !AndroidUtilities.usingHardwareInput && !AndroidUtilities.isInMultiwindow) { messageEditText.requestFocus(); AndroidUtilities.showKeyboard(messageEditText); @@ -1721,7 +1733,15 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific sendByEnter = preferences.getBoolean("send_by_enter", false); configAnimationsEnabled = preferences.getBoolean("view_animations", true); - textFieldContainer = new FrameLayout(context); + textFieldContainer = new FrameLayout(context) { + @Override + public boolean dispatchTouchEvent(MotionEvent ev) { + if (botWebViewButton.getVisibility() == VISIBLE) { + return botWebViewButton.dispatchTouchEvent(ev); + } + return super.dispatchTouchEvent(ev); + } + }; textFieldContainer.setClipChildren(false); textFieldContainer.setClipToPadding(false); textFieldContainer.setPadding(0, AndroidUtilities.dp(1), 0, 0); @@ -1785,6 +1805,11 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific if (adjustPanLayoutHelper != null && adjustPanLayoutHelper.animationInProgress()) { return; } + if (hasBotWebView() && botCommandsMenuIsShowing()) { + botWebViewMenuContainer.dismiss(view::callOnClick); + return; + } + if (!isPopupShowing() || currentPopupContentType != 0) { showPopup(1, 0); emojiView.onOpen(messageEditText.length() > 0); @@ -2079,6 +2104,7 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific messageEditText.setPadding(0, AndroidUtilities.dp(11), 0, AndroidUtilities.dp(12)); messageEditText.setBackgroundDrawable(null); messageEditText.setTextColor(getThemedColor(Theme.key_chat_messagePanelText)); + messageEditText.setLinkTextColor(getThemedColor(Theme.key_chat_messageLinkOut)); messageEditText.setHintColor(getThemedColor(Theme.key_chat_messagePanelHint)); messageEditText.setHintTextColor(getThemedColor(Theme.key_chat_messagePanelHint)); messageEditText.setCursorColor(getThemedColor(Theme.key_chat_messagePanelCursor)); @@ -2316,6 +2342,21 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific try { performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP, HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING); } catch (Exception ignore) {} + if (hasBotWebView()) { + if (open) { + if (emojiViewVisible || botKeyboardViewVisible) { + AndroidUtilities.runOnUIThread(this::openWebViewMenu, 275); + hidePopup(false); + return; + } + + openWebViewMenu(); + } else { + botWebViewMenuContainer.dismiss(); + } + return; + } + if (open) { botCommandsMenuContainer.show(); } else { @@ -2379,6 +2420,15 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific sizeNotifierLayout.addView(botCommandsMenuContainer, 14, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.BOTTOM)); botCommandsMenuContainer.setVisibility(View.GONE); + botWebViewMenuContainer = new BotWebViewMenuContainer(context, this) { + @Override + public void onDismiss() { + super.onDismiss(); + botCommandsMenuButton.setOpened(false); + } + }; + sizeNotifierLayout.addView(botWebViewMenuContainer, 15, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.BOTTOM)); + botWebViewMenuContainer.setVisibility(GONE); botButton = new ImageView(context); botButton.setImageDrawable(botButtonDrawable = new ReplaceableIconDrawable(context)); @@ -2391,6 +2441,10 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific botButton.setVisibility(GONE); attachLayout.addView(botButton, LayoutHelper.createLinear(48, 48)); botButton.setOnClickListener(v -> { + if (hasBotWebView() && botCommandsMenuIsShowing()) { + botWebViewMenuContainer.dismiss(v::callOnClick); + return; + } if (searchingType != 0) { setSearchingTypeInternal(0, false); emojiView.closeSearch(false); @@ -3366,6 +3420,63 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific setRecordVideoButtonVisible(false, false); checkSendButton(false); checkChannelRights(); + + botWebViewButton = new ChatActivityBotWebViewButton(context); + botWebViewButton.setVisibility(GONE); + botWebViewButton.setBotMenuButton(botCommandsMenuButton); + frameLayout.addView(botWebViewButton, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.BOTTOM)); + } + + private void openWebViewMenu() { + Runnable onRequestWebView = () -> { + AndroidUtilities.hideKeyboard(this); + botWebViewMenuContainer.show(currentAccount, dialog_id, botMenuWebViewUrl); + }; + + if (SharedPrefsHelper.isWebViewConfirmShown(currentAccount, dialog_id)) { + onRequestWebView.run(); + } else { + new AlertDialog.Builder(parentFragment.getParentActivity()) + .setTitle(LocaleController.getString(R.string.BotOpenPageTitle)) + .setMessage(AndroidUtilities.replaceTags(LocaleController.formatString(R.string.BotOpenPageMessage, UserObject.getUserName(MessagesController.getInstance(currentAccount).getUser(dialog_id))))) + .setPositiveButton(LocaleController.getString(R.string.OK), (dialog, which) -> { + onRequestWebView.run(); + SharedPrefsHelper.setWebViewConfirmShown(currentAccount, dialog_id, true); + }) + .setNegativeButton(LocaleController.getString(R.string.Cancel), null) + .setOnDismissListener(dialog -> { + if (!SharedPrefsHelper.isWebViewConfirmShown(currentAccount, dialog_id)) { + botCommandsMenuButton.setOpened(false); + } + }) + .show(); + } + } + + public void setBotWebViewButtonOffsetX(float offset) { + for (ImageView imageView : emojiButton) { + imageView.setTranslationX(offset); + } + messageEditText.setTranslationX(offset); + attachButton.setTranslationX(offset); + audioSendButton.setTranslationX(offset); + videoSendButton.setTranslationX(offset); + if (botButton != null) { + botButton.setTranslationX(offset); + } + } + + public void setComposeShadowAlpha(float alpha) { + composeShadowAlpha = alpha; + invalidate(); + } + + public ChatActivityBotWebViewButton getBotWebViewButton() { + return botWebViewButton; + } + + public ChatActivity getParentFragment() { + return parentFragment; } private void checkBotMenu() { @@ -3434,14 +3545,17 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific public boolean allowBlur = true; Paint backgroundPaint = new Paint(); + private float composeShadowAlpha = 1f; @Override protected void onDraw(Canvas canvas) { int top = animatedTop; + top += Theme.chat_composeShadowDrawable.getIntrinsicHeight() * (1f - composeShadowAlpha); if (topView != null && topView.getVisibility() == View.VISIBLE) { top += (1f - topViewEnterProgress) * topView.getLayoutParams().height; } int bottom = top + Theme.chat_composeShadowDrawable.getIntrinsicHeight(); + Theme.chat_composeShadowDrawable.setAlpha((int) (composeShadowAlpha * 0xFF)); Theme.chat_composeShadowDrawable.setBounds(0, top, getMeasuredWidth(), bottom); Theme.chat_composeShadowDrawable.draw(canvas); if (allowBlur) { @@ -3971,14 +4085,20 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific return topView != null && topView.getVisibility() == VISIBLE; } + public void onAdjustPanTransitionUpdate(float y, float progress, boolean keyboardVisible) { + botWebViewMenuContainer.setTranslationY(y); + } + public void onAdjustPanTransitionEnd() { + botWebViewMenuContainer.onPanTransitionEnd(); if (onKeyboardClosed != null) { onKeyboardClosed.run(); onKeyboardClosed = null; } } - public void onAdjustPanTransitionStart(boolean keyboardVisible) { + public void onAdjustPanTransitionStart(boolean keyboardVisible, int contentHeight) { + botWebViewMenuContainer.onPanTransitionStart(keyboardVisible, contentHeight); if (keyboardVisible && showTopViewRunnable != null) { AndroidUtilities.cancelRunOnUIThread(showTopViewRunnable); showTopViewRunnable.run(); @@ -3988,6 +4108,10 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific AndroidUtilities.cancelRunOnUIThread(setTextFieldRunnable); setTextFieldRunnable.run(); } + + if (keyboardVisible && messageEditText.hasFocus() && hasBotWebView() && botCommandsMenuIsShowing()) { + botWebViewMenuContainer.dismiss(); + } } private void onWindowSizeChanged() { @@ -4135,6 +4259,11 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific AndroidUtilities.cancelRunOnUIThread(hideKeyboardRunnable); hideKeyboardRunnable = null; } + + if (hasBotWebView() && botCommandsMenuIsShowing()) { + return; + } + int visibility = getVisibility(); if (showKeyboardOnResume && parentFragment.isLastFragment()) { showKeyboardOnResume = false; @@ -4243,6 +4372,10 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific return hasRecordVideo; } + public MessageObject getReplyingMessageObject() { + return replyingMessageObject; + } + public void updateFieldHint(boolean animated) { if (replyingMessageObject != null && replyingMessageObject.messageOwner.reply_markup != null && !TextUtils.isEmpty(replyingMessageObject.messageOwner.reply_markup.placeholder)) { messageEditText.setHintText(replyingMessageObject.messageOwner.reply_markup.placeholder, animated); @@ -6749,6 +6882,10 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific } } + private boolean hasBotWebView() { + return botMenuButtonType == BotMenuButtonType.WEB_VIEW; + } + private void updateBotButton(boolean animated) { if (botButton == null) { return; @@ -6756,13 +6893,14 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific if (!parentFragment.openAnimationEnded) { animated = false; } - boolean canShowBotsMenu = hasBotCommands && dialog_id > 0; + boolean hasBotWebView = hasBotWebView(); + boolean canShowBotsMenu = botMenuButtonType != BotMenuButtonType.NO_BUTTON && dialog_id > 0; // if (canShowBotsMenu && ) { // TLRPC.Chat chat = accountInstance.getMessagesController().getChat(-dialog_id); // canShowBotsMenu = chat == null || !chat.megagroup; // } - if (hasBotCommands || botReplyMarkup != null) { + if (hasBotWebView || hasBotCommands || botReplyMarkup != null) { if (botReplyMarkup != null) { if (botButton.getVisibility() != VISIBLE) { botButton.setVisibility(VISIBLE); @@ -6786,7 +6924,9 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific } else { botButton.setVisibility(GONE); } - AndroidUtilities.updateViewVisibilityAnimated(botCommandsMenuButton, canShowBotsMenu && hasBotCommands, 0.5f, animated); + botCommandsMenuButton.setWebView(botMenuButtonType == BotMenuButtonType.WEB_VIEW); + botCommandsMenuButton.setMenuText(botMenuButtonType == BotMenuButtonType.COMMANDS ? LocaleController.getString(R.string.BotsMenuTitle) : botMenuWebViewTitle); + AndroidUtilities.updateViewVisibilityAnimated(botCommandsMenuButton, canShowBotsMenu, 0.5f, animated); if (animated) { beginDelayedTransition(); } @@ -6803,6 +6943,11 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific return false; } + public void updateBotWebView(boolean animated) { + botCommandsMenuButton.setWebView(hasBotWebView()); + updateBotButton(animated); + } + public void setBotsCount(int count, boolean hasCommands, boolean animated) { botCount = count; if (hasBotCommands != hasCommands) { @@ -6900,6 +7045,37 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific } else if (button instanceof TLRPC.TL_keyboardButtonRequestPoll) { parentFragment.openPollCreate((button.flags & 1) != 0 ? button.quiz : null); return false; + } else if (button instanceof TLRPC.TL_keyboardButtonWebView || button instanceof TLRPC.TL_keyboardButtonSimpleWebView) { + long botId = messageObject.messageOwner.via_bot_id != 0 ? messageObject.messageOwner.via_bot_id : messageObject.messageOwner.from_id.user_id; + TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(botId); + Runnable onRequestWebView = new Runnable() { + @Override + public void run() { + if (sizeNotifierLayout.measureKeyboardHeight() > AndroidUtilities.dp(20)) { + AndroidUtilities.hideKeyboard(ChatActivityEnterView.this); + AndroidUtilities.runOnUIThread(this, 150); + return; + } + + 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, replyMessageObject != null ? replyMessageObject.messageOwner.id : 0, false); + webViewSheet.show(); + } + }; + if (SharedPrefsHelper.isWebViewConfirmShown(currentAccount, botId)) { + onRequestWebView.run(); + } else { + new AlertDialog.Builder(parentFragment.getParentActivity()) + .setTitle(LocaleController.getString(R.string.BotOpenPageTitle)) + .setMessage(AndroidUtilities.replaceTags(LocaleController.formatString("BotOpenPageMessage", R.string.BotOpenPageMessage, UserObject.getUserName(user)))) + .setPositiveButton(LocaleController.getString(R.string.OK), (dialog, which) -> { + onRequestWebView.run(); + SharedPrefsHelper.setWebViewConfirmShown(currentAccount, botId, true); + }) + .setNegativeButton(LocaleController.getString(R.string.Cancel), null) + .show(); + } } else if (button instanceof TLRPC.TL_keyboardButtonRequestGeoLocation) { AlertDialog.Builder builder = new AlertDialog.Builder(parentActivity); builder.setTitle(LocaleController.getString("ShareYouLocationTitle", R.string.ShareYouLocationTitle)); @@ -6995,6 +7171,10 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific return view == recordCircle; } + public SizeNotifierFrameLayout getSizeNotifierLayout() { + return sizeNotifierLayout; + } + private void createEmojiView() { if (emojiView != null) { return; @@ -7771,6 +7951,9 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific } private void openKeyboardInternal() { + if (hasBotWebView() && botCommandsMenuIsShowing()) { + return; + } showPopup(AndroidUtilities.usingHardwareInput || AndroidUtilities.isInMultiwindow || parentFragment != null && parentFragment.isInBubbleMode() || isPaused ? 0 : 2, 0); messageEditText.requestFocus(); AndroidUtilities.showKeyboard(messageEditText); @@ -7803,6 +7986,9 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific } public void openKeyboard() { + if (hasBotWebView() && botCommandsMenuIsShowing()) { + return; + } if (!AndroidUtilities.showKeyboard(messageEditText)) { messageEditText.clearFocus(); messageEditText.requestFocus(); @@ -8387,6 +8573,9 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific if ((videoSendButton != null) && isInVideoMode() && recordedAudioPanel != null && recordedAudioPanel.getVisibility() == View.VISIBLE) { return false; } + if (hasBotWebView() && botCommandsMenuButton.isOpened()) { + return false; + } return true; } @@ -8993,6 +9182,19 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific } } super.onMeasure(widthMeasureSpec, heightMeasureSpec); + + if (botWebViewButton != null) { + if (botCommandsMenuButton != null) { + botWebViewButton.setMeasuredButtonWidth(botCommandsMenuButton.getMeasuredWidth()); + } + botWebViewButton.getLayoutParams().height = messageEditText.getMeasuredHeight(); + measureChild(botWebViewButton, widthMeasureSpec, heightMeasureSpec); + } + if (botWebViewMenuContainer != null) { + MarginLayoutParams params = (MarginLayoutParams) botWebViewMenuContainer.getLayoutParams(); + params.bottomMargin = messageEditText.getMeasuredHeight(); + measureChild(botWebViewMenuContainer, widthMeasureSpec, heightMeasureSpec); + } } @Override @@ -9014,6 +9216,23 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific } public void setBotInfo(LongSparseArray botInfo) { + if (botInfo.size() == 1 && botInfo.valueAt(0).user_id == dialog_id) { + TLRPC.BotInfo info = botInfo.valueAt(0); + TLRPC.BotMenuButton menuButton = info.menu_button; + if (menuButton instanceof TLRPC.TL_botMenuButtonCommands || menuButton instanceof TLRPC.TL_botMenuButtonDefault) { + botMenuButtonType = info.commands.isEmpty() ? BotMenuButtonType.NO_BUTTON : BotMenuButtonType.COMMANDS; + } else if (menuButton instanceof TLRPC.TL_botMenuButton) { + TLRPC.TL_botMenuButton webViewButton = (TLRPC.TL_botMenuButton) menuButton; + botMenuWebViewTitle = webViewButton.text; + botMenuWebViewUrl = webViewButton.url; + botMenuButtonType = BotMenuButtonType.WEB_VIEW; + } else { + botMenuButtonType = BotMenuButtonType.NO_BUTTON; + } + } else { + botMenuButtonType = BotMenuButtonType.NO_BUTTON; + } + if (botCommandsAdapter != null) { botCommandsAdapter.setBotInfo(botInfo); } @@ -9025,7 +9244,12 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific public void hideBotCommands() { botCommandsMenuButton.setOpened(false); - botCommandsMenuContainer.dismiss(); + + if (hasBotWebView()) { + botWebViewMenuContainer.dismiss(); + } else { + botCommandsMenuContainer.dismiss(); + } } public void setTextTransitionIsRunning(boolean b) { @@ -9071,4 +9295,10 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific Paint paint = resourcesProvider != null ? resourcesProvider.getPaint(paintKey) : null; return paint != null ? paint : Theme.getThemePaint(paintKey); } + + public enum BotMenuButtonType { + NO_BUTTON, + COMMANDS, + WEB_VIEW + } } 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 7838edba8..006717e92 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlert.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlert.java @@ -35,6 +35,7 @@ import android.text.TextPaint; import android.text.TextUtils; import android.text.TextWatcher; import android.text.style.ImageSpan; +import android.util.LongSparseArray; import android.util.Property; import android.util.TypedValue; import android.view.Gravity; @@ -55,6 +56,7 @@ import android.widget.LinearLayout; import android.widget.TextView; import androidx.annotation.Keep; +import androidx.annotation.NonNull; import androidx.core.graphics.ColorUtils; import androidx.dynamicanimation.animation.DynamicAnimation; import androidx.dynamicanimation.animation.FloatValueHolder; @@ -67,6 +69,8 @@ import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.ChatObject; import org.telegram.messenger.ContactsController; import org.telegram.messenger.Emoji; +import org.telegram.messenger.ImageLocation; +import org.telegram.messenger.ImageReceiver; import org.telegram.messenger.LocaleController; import org.telegram.messenger.MediaController; import org.telegram.messenger.MediaDataController; @@ -78,6 +82,7 @@ import org.telegram.messenger.SendMessagesHelper; import org.telegram.messenger.SharedConfig; import org.telegram.messenger.UserConfig; import org.telegram.messenger.UserObject; +import org.telegram.tgnet.ConnectionsManager; import org.telegram.tgnet.TLRPC; import org.telegram.ui.ActionBar.ActionBar; import org.telegram.ui.ActionBar.ActionBarMenuItem; @@ -97,6 +102,7 @@ import org.telegram.ui.PhotoPickerSearchActivity; import java.util.ArrayList; import java.util.HashMap; +import java.util.Objects; public class ChatAttachAlert extends BottomSheet implements NotificationCenter.NotificationCenterDelegate, BottomSheet.BottomSheetDelegateInterface { @@ -107,9 +113,11 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N private int codepointCount; public boolean canOpenPreview = false; + private boolean isSoundPicker = false; + public void setCanOpenPreview(boolean canOpenPreview) { this.canOpenPreview = canOpenPreview; - selectedArrowImageView.setVisibility(canOpenPreview ? View.VISIBLE : View.GONE); + selectedArrowImageView.setVisibility(canOpenPreview && avatarPicker != 2 ? View.VISIBLE : View.GONE); } public float getClipLayoutBottom() { @@ -117,13 +125,142 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N return frameLayout2.getMeasuredHeight() - alphaOffset; } + public void showBotLayout(long id) { + showBotLayout(id, null); + } + + public void showBotLayout(long id, String startCommand) { + if (botAttachLayouts.get(id) == null || !Objects.equals(startCommand, botAttachLayouts.get(id).getStartCommand()) || botAttachLayouts.get(id).needReload()) { + if (baseFragment instanceof ChatActivity && ((ChatActivity) baseFragment).getCurrentUser() != null) { + ChatAttachAlertBotWebViewLayout webViewLayout = new ChatAttachAlertBotWebViewLayout(this, getContext(), resourcesProvider); + botAttachLayouts.put(id, webViewLayout); + botAttachLayouts.get(id).setDelegate(new BotWebViewContainer.Delegate() { + @Override + public void onCloseRequested() { + if (currentAttachLayout != webViewLayout) { + return; + } + dismiss(); + } + + @Override + public void onSendWebViewData(String data) { + // Empty as it's delegate from attachments menu. Data is only available for buttons + } + + @Override + public void onWebAppExpand() { + if (currentAttachLayout != webViewLayout) { + return; + } + + if (webViewLayout.canExpandByRequest()) { + webViewLayout.scrollToTop(); + } + } + + @Override + public void onSetupMainButton(boolean isVisible, boolean isActive, String text, int color, int textColor, boolean isProgressVisible) { + if (currentAttachLayout != webViewLayout || !webViewLayout.isBotButtonAvailable()) { + return; + } + botMainButtonTextView.setClickable(isActive); + botMainButtonTextView.setText(text); + botMainButtonTextView.setTextColor(textColor); + botMainButtonTextView.setBackground(Theme.createSelectorWithBackgroundDrawable(color, Theme.getColor(Theme.key_listSelector))); + if (botButtonWasVisible != isVisible) { + ValueAnimator animator = ValueAnimator.ofFloat(isVisible ? 0 : 1, isVisible ? 1 : 0).setDuration(250); + animator.addUpdateListener(animation -> { + float value = (float) animation.getAnimatedValue(); + buttonsRecyclerView.setAlpha(1f - value); + botMainButtonTextView.setAlpha(value); + botMainButtonOffsetY = value * AndroidUtilities.dp(36); + shadow.setTranslationY(botMainButtonOffsetY); + buttonsRecyclerView.setTranslationY(botMainButtonOffsetY); + }); + animator.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationStart(Animator animation) { + if (isVisible) { + botMainButtonTextView.setAlpha(0f); + botMainButtonTextView.setVisibility(View.VISIBLE); + } else { + buttonsRecyclerView.setAlpha(0f); + buttonsRecyclerView.setVisibility(View.VISIBLE); + } + } + + @Override + public void onAnimationEnd(Animator animation) { + botButtonWasVisible = isVisible; + if (!isVisible) { + botMainButtonTextView.setVisibility(View.GONE); + } else { + buttonsRecyclerView.setVisibility(View.GONE); + } + + int offsetY = isVisible ? AndroidUtilities.dp(36) : 0; + for (int i = 0; i < botAttachLayouts.size(); i++) { + botAttachLayouts.valueAt(i).setMeasureOffsetY(offsetY); + } + } + }); + animator.start(); + } + botProgressView.setProgressColor(textColor); + if (botButtonProgressWasVisible != isProgressVisible) { + botProgressView.animate().cancel(); + if (isProgressVisible) { + botProgressView.setAlpha(0f); + botProgressView.setVisibility(View.VISIBLE); + } + botProgressView.animate().alpha(isProgressVisible ? 1f : 0f) + .scaleX(isProgressVisible ? 1f : 0.1f) + .scaleY(isProgressVisible ? 1f : 0.1f) + .setDuration(250) + .setListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + botButtonProgressWasVisible = isProgressVisible; + if (!isProgressVisible) { + botProgressView.setVisibility(View.GONE); + } + } + }).start(); + } + } + }); + MessageObject replyingObject = ((ChatActivity) baseFragment).getChatActivityEnterView().getReplyingMessageObject(); + botAttachLayouts.get(id).requestWebView(currentAccount, ((ChatActivity) baseFragment).getCurrentUser().id, id, false, replyingObject != null ? replyingObject.messageOwner.id : 0, startCommand); + } + } + if (botAttachLayouts.get(id) != null) { + botAttachLayouts.get(id).disallowSwipeOffsetAnimation(); + showLayout(botAttachLayouts.get(id), -id); + } + } + public interface ChatAttachViewDelegate { void didPressedButton(int button, boolean arg, boolean notify, int scheduleDate, boolean forceDocument); - View getRevealView(); - void didSelectBot(TLRPC.User user); + void onCameraOpened(); - boolean needEnterComment(); - void doOnIdle(Runnable runnable); + + default View getRevealView() { + return null; + } + + default void didSelectBot(TLRPC.User user) { + + } + + default boolean needEnterComment() { + return false; + } + + default void doOnIdle(Runnable runnable) { + runnable.run(); + } + default void openAvatarsSearch() { } @@ -330,7 +467,13 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N return color != null ? color : Theme.getColor(key); } - boolean shouldHideBottomButtons() { return true; } + boolean shouldHideBottomButtons() { + return true; + } + + public void onPanTransitionStart(boolean keyboardVisible, int contentHeight) {} + + public void onPanTransitionEnd() {} } protected BaseFragment baseFragment; @@ -349,6 +492,7 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N private ChatAttachAlertDocumentLayout documentLayout; private ChatAttachAlertPhotoLayoutPreview photoPreviewLayout; private AttachAlertLayout[] layouts = new AttachAlertLayout[7]; + private LongSparseArray botAttachLayouts = new LongSparseArray<>(); private AttachAlertLayout currentAttachLayout; private AttachAlertLayout nextAttachLayout; @@ -371,7 +515,7 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N private float sendButtonEnabledProgress = 1f; private ValueAnimator sendButtonColorAnimator; - private int selectedId; + private long selectedId; protected float cornerRadius = 1.0f; @@ -401,6 +545,13 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N private LinearLayoutManager buttonsLayoutManager; private ButtonsAdapter buttonsAdapter; + private boolean botButtonProgressWasVisible = false; + private RadialProgressView botProgressView; + + private boolean botButtonWasVisible = false; + private TextView botMainButtonTextView; + private float botMainButtonOffsetY; + protected MessageObject editingMessageObject; private boolean buttonPressed; @@ -536,8 +687,8 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N float scale = imageView.getScaleX() + 0.06f * checkedState; float radius = AndroidUtilities.dp(23) * scale; - float cx = imageView.getLeft() + imageView.getMeasuredWidth() / 2; - float cy = imageView.getTop() + imageView.getMeasuredWidth() / 2; + float cx = imageView.getLeft() + imageView.getMeasuredWidth() / 2f; + float cy = imageView.getTop() + imageView.getMeasuredWidth() / 2f; attachButtonPaint.setColor(getThemedColor(backgroundKey)); attachButtonPaint.setStyle(Paint.Style.STROKE); @@ -557,23 +708,56 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N } private class AttachBotButton extends FrameLayout { - private BackupImageView imageView; private TextView nameTextView; private AvatarDrawable avatarDrawable = new AvatarDrawable(); private TLRPC.User currentUser; + private TLRPC.TL_attachMenuBot attachMenuBot; + + private float checkedState; + private Boolean checked; + private ValueAnimator checkAnimator; + + private int textColor; + private int iconBackgroundColor; + + private View selector; public AttachBotButton(Context context) { super(context); - imageView = new BackupImageView(context); + setWillNotDraw(false); + setFocusable(true); + setFocusableInTouchMode(true); + + imageView = new BackupImageView(context) { + { + imageReceiver = new ImageReceiver(this) { + @Override + protected boolean setImageBitmapByKey(Drawable drawable, String key, int type, boolean memCache, int guid) { + if (drawable instanceof RLottieDrawable) { + ((RLottieDrawable) drawable).setCustomEndFrame(0); + ((RLottieDrawable) drawable).stop(); + ((RLottieDrawable) drawable).setProgress(0, false); + } + return super.setImageBitmapByKey(drawable, key, type, memCache, guid); + } + }; + } + + @Override + public void setScaleX(float scaleX) { + super.setScaleX(scaleX); + AttachBotButton.this.invalidate(); + } + }; imageView.setRoundRadius(AndroidUtilities.dp(25)); addView(imageView, LayoutHelper.createFrame(46, 46, Gravity.TOP | Gravity.CENTER_HORIZONTAL, 0, 9, 0, 0)); - if (Build.VERSION.SDK_INT >= 21) { - View selector = new View(context); - selector.setBackgroundDrawable(Theme.createSelectorDrawable(getThemedColor(Theme.key_dialogButtonSelector), 1, AndroidUtilities.dp(23))); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + selector = new View(context); + selector.setBackground(Theme.createSelectorDrawable(getThemedColor(Theme.key_dialogButtonSelector), 1, AndroidUtilities.dp(23))); addView(selector, LayoutHelper.createFrame(46, 46, Gravity.TOP | Gravity.CENTER_HORIZONTAL, 0, 9, 0, 0)); } @@ -591,6 +775,80 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N super.onMeasure(MeasureSpec.makeMeasureSpec(attachItemSize, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(100), MeasureSpec.EXACTLY)); } + public void setCheckedState(float state) { + checkedState = state; + imageView.setScaleX(1.0f - 0.06f * state); + imageView.setScaleY(1.0f - 0.06f * state); + nameTextView.setTextColor(ColorUtils.blendARGB(getThemedColor(Theme.key_dialogTextGray2), textColor, checkedState)); + invalidate(); + } + + private void updateMargins() { + MarginLayoutParams params = (MarginLayoutParams) nameTextView.getLayoutParams(); + params.topMargin = AndroidUtilities.dp(attachMenuBot != null ? 62 : 60); + params = (MarginLayoutParams) imageView.getLayoutParams(); + params.topMargin = AndroidUtilities.dp(attachMenuBot != null ? 11 : 9); + } + + @Override + protected void onDraw(Canvas canvas) { + if (attachMenuBot != null) { + float imageScale = imageView.getScaleX(); + float scale = imageScale + 0.06f * checkedState; + float radius = AndroidUtilities.dp(23) * scale; + + float cx = imageView.getLeft() + imageView.getMeasuredWidth() / 2f; + float cy = imageView.getTop() + imageView.getMeasuredWidth() / 2f; + + attachButtonPaint.setColor(iconBackgroundColor); + attachButtonPaint.setStyle(Paint.Style.STROKE); + attachButtonPaint.setStrokeWidth(AndroidUtilities.dp(3) * scale); + attachButtonPaint.setAlpha(Math.round(255f * checkedState)); + canvas.drawCircle(cx, cy, radius - 0.5f * attachButtonPaint.getStrokeWidth(), attachButtonPaint); + + attachButtonPaint.setAlpha(255); + attachButtonPaint.setStyle(Paint.Style.FILL); + canvas.drawCircle(cx, cy, radius - AndroidUtilities.dp(5) * checkedState, attachButtonPaint); + } + } + + @Override + protected void onAttachedToWindow() { + super.onAttachedToWindow(); + updateCheckedState(false); + } + + void updateCheckedState(boolean animate) { + boolean newChecked = attachMenuBot != null && -currentUser.id == selectedId; + if (checked != null && checked == newChecked && animate) { + return; + } + checked = newChecked; + if (checkAnimator != null) { + checkAnimator.cancel(); + } + RLottieDrawable drawable = imageView.getImageReceiver().getLottieAnimation(); + if (animate) { + if (checked && drawable != null) { + drawable.setAutoRepeat(0); + drawable.setCustomEndFrame(-1); + drawable.setProgress(0, false); + drawable.start(); + } + + checkAnimator = ValueAnimator.ofFloat(checked ? 0f : 1f, checked ? 1f : 0f); + checkAnimator.addUpdateListener(animation -> setCheckedState((float)animation.getAnimatedValue())); + checkAnimator.setDuration(200); + checkAnimator.start(); + } else { + if (drawable != null) { + drawable.stop(); + drawable.setProgress(0, false); + } + setCheckedState(checked ? 1f : 0f); + } + } + public void setUser(TLRPC.User user) { if (user == null) { return; @@ -600,7 +858,73 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N nameTextView.setText(ContactsController.formatName(user.first_name, user.last_name)); avatarDrawable.setInfo(user); imageView.setForUserOrChat(user, avatarDrawable); - requestLayout(); + imageView.setSize(-1, -1); + imageView.setColorFilter(null); + attachMenuBot = null; + selector.setVisibility(VISIBLE); + updateMargins(); + setCheckedState(0f); + invalidate(); + } + + public void setAttachBot(TLRPC.User user, TLRPC.TL_attachMenuBot bot) { + if (user == null || bot == null) { + return; + } + nameTextView.setTextColor(getThemedColor(Theme.key_dialogTextGray2)); + currentUser = user; + nameTextView.setText(bot.short_name); + avatarDrawable.setInfo(user); + + boolean animated = true; + TLRPC.TL_attachMenuBotIcon icon = MediaDataController.getAnimatedAttachMenuBotIcon(bot); + if (icon == null) { + icon = MediaDataController.getStaticAttachMenuBotIcon(bot); + animated = false; + } + if (icon != null) { + textColor = getThemedColor(Theme.key_chat_attachContactText); + iconBackgroundColor = getThemedColor(Theme.key_chat_attachContactBackground); + + for (TLRPC.TL_attachMenuBotIconColor color : icon.colors) { + switch (color.name) { + case MediaDataController.ATTACH_MENU_BOT_COLOR_LIGHT_ICON: + if (!Theme.getCurrentTheme().isDark()) { + iconBackgroundColor = color.color; + } + break; + case MediaDataController.ATTACH_MENU_BOT_COLOR_LIGHT_TEXT: + if (!Theme.getCurrentTheme().isDark()) { + textColor = color.color; + } + break; + case MediaDataController.ATTACH_MENU_BOT_COLOR_DARK_ICON: + if (Theme.getCurrentTheme().isDark()) { + iconBackgroundColor = color.color; + } + break; + case MediaDataController.ATTACH_MENU_BOT_COLOR_DARK_TEXT: + if (Theme.getCurrentTheme().isDark()) { + textColor = color.color; + } + break; + } + } + textColor = ColorUtils.setAlphaComponent(textColor, 0xFF); + iconBackgroundColor = ColorUtils.setAlphaComponent(iconBackgroundColor, 0xFF); + + TLRPC.Document iconDoc = icon.icon; + imageView.getImageReceiver().setAllowStartLottieAnimation(false); + imageView.setImage(ImageLocation.getForDocument(iconDoc), "32_32", animated ? "tgs" : "svg", null, icon); + } + + imageView.setSize(AndroidUtilities.dp(28), AndroidUtilities.dp(28)); + imageView.setColorFilter(new PorterDuffColorFilter(getThemedColor(Theme.key_chat_attachContactIcon), PorterDuff.Mode.SRC_IN)); + attachMenuBot = bot; + selector.setVisibility(GONE); + updateMargins(); + setCheckedState(0f); + invalidate(); } } @@ -625,6 +949,7 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N useSmoothKeyboard = true; setDelegate(this); NotificationCenter.getInstance(currentAccount).addObserver(this, NotificationCenter.reloadInlineHints); + NotificationCenter.getInstance(currentAccount).addObserver(this, NotificationCenter.attachMenuBotsDidLoad); exclusionRects.add(exclustionRect); sizeNotifierFrameLayout = new SizeNotifierFrameLayout(context) { @@ -646,6 +971,8 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N fromScrollY = -1; } invalidate(); + + currentAttachLayout.onPanTransitionStart(keyboardVisible, contentHeight); } @Override @@ -653,6 +980,7 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N super.onTransitionEnd(); updateLayout(currentAttachLayout, false, 0); previousScrollOffsetY = scrollOffsetY[0]; + currentAttachLayout.onPanTransitionEnd(); } @Override @@ -1206,8 +1534,8 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N buttonsRecyclerView.setTranslationY(AndroidUtilities.dp(44) * alpha); } frameLayout2.setTranslationY(AndroidUtilities.dp(48) * alpha); - shadow.setTranslationY(AndroidUtilities.dp(84) * alpha); - } else if (currentAttachLayout == null || currentAttachLayout.shouldHideBottomButtons()) { + shadow.setTranslationY(AndroidUtilities.dp(84) * alpha + botMainButtonOffsetY); + } else if (currentAttachLayout == null) { float value = alpha == 0.0f ? 1.0f : 0.0f; if (buttonsRecyclerView.getAlpha() != value) { buttonsRecyclerView.setAlpha(value); @@ -1381,6 +1709,7 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N Drawable arrowRight = getContext().getResources().getDrawable(R.drawable.attach_arrow_right).mutate(); arrowRight.setColorFilter(new PorterDuffColorFilter(getThemedColor(Theme.key_dialogTextBlack), PorterDuff.Mode.MULTIPLY)); selectedArrowImageView.setImageDrawable(arrowRight); + selectedArrowImageView.setVisibility(View.GONE); selectedView.addView(selectedArrowImageView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_VERTICAL, 4, 1, 0, 0)); headerView.addView(selectedView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.MATCH_PARENT)); @@ -1511,8 +1840,12 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N } } else if (view instanceof AttachBotButton) { AttachBotButton button = (AttachBotButton) view; - delegate.didSelectBot(button.currentUser); - dismiss(); + if (button.attachMenuBot != null) { + showBotLayout(button.attachMenuBot.bot_id); + } else { + delegate.didSelectBot(button.currentUser); + dismiss(); + } } if (view.getX() + view.getWidth() >= buttonsRecyclerView.getMeasuredWidth() - AndroidUtilities.dp(32)) { @@ -1525,17 +1858,39 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N if (baseFragment == null || button.currentUser == null) { return false; } - AlertDialog.Builder builder = new AlertDialog.Builder(getContext()); - builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); - builder.setMessage(LocaleController.formatString("ChatHintsDelete", R.string.ChatHintsDelete, ContactsController.formatName(button.currentUser.first_name, button.currentUser.last_name))); - builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), (dialogInterface, i) -> MediaDataController.getInstance(currentAccount).removeInline(button.currentUser.id)); - builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); - builder.show(); + onLongClickBotButton(button.attachMenuBot, button.currentUser); return true; } return false; }); + botMainButtonTextView = new TextView(context); + botMainButtonTextView.setVisibility(View.GONE); + botMainButtonTextView.setAlpha(0f); + botMainButtonTextView.setSingleLine(); + botMainButtonTextView.setGravity(Gravity.CENTER); + botMainButtonTextView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); + int padding = AndroidUtilities.dp(16); + botMainButtonTextView.setPadding(padding, 0, padding, 0); + botMainButtonTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); + botMainButtonTextView.setOnClickListener(v -> { + if (selectedId < 0) { + ChatAttachAlertBotWebViewLayout webViewLayout = botAttachLayouts.get(-selectedId); + if (webViewLayout != null) { + webViewLayout.getWebViewContainer().onMainButtonPressed(); + } + } + }); + containerView.addView(botMainButtonTextView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 48, Gravity.BOTTOM | Gravity.LEFT)); + + botProgressView = new RadialProgressView(context); + botProgressView.setSize(AndroidUtilities.dp(18)); + botProgressView.setAlpha(0f); + botProgressView.setScaleX(0.1f); + botProgressView.setScaleY(0.1f); + botProgressView.setVisibility(View.GONE); + containerView.addView(botProgressView, LayoutHelper.createFrame(28, 28, Gravity.BOTTOM | Gravity.RIGHT, 0, 0, 10, 10)); + frameLayout2 = new FrameLayout(context) { private final Paint p = new Paint(); @@ -1567,7 +1922,7 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N } float alphaOffset = (frameLayout2.getMeasuredHeight() - AndroidUtilities.dp(84)) * (1f - getAlpha()); - shadow.setTranslationY(-(frameLayout2.getMeasuredHeight() - AndroidUtilities.dp(84)) + captionEditTextTopOffset + currentPanTranslationY + bottomPannelTranslation + alphaOffset); + shadow.setTranslationY(-(frameLayout2.getMeasuredHeight() - AndroidUtilities.dp(84)) + captionEditTextTopOffset + currentPanTranslationY + bottomPannelTranslation + alphaOffset + botMainButtonOffsetY); int newColor = getThemedColor(forceDarkTheme ? Theme.key_voipgroup_listViewBackground : Theme.key_dialogBackground); if (color != newColor) { @@ -1969,6 +2324,35 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N } } + public void onLongClickBotButton(TLRPC.TL_attachMenuBot attachMenuBot, TLRPC.User currentUser) { + String botName = attachMenuBot != null ? attachMenuBot.short_name : UserObject.getUserName(currentUser); + new AlertDialog.Builder(getContext()) + .setTitle(LocaleController.getString(attachMenuBot != null ? R.string.BotRemoveFromMenuTitle : R.string.AppName)) + .setMessage(AndroidUtilities.replaceTags(attachMenuBot != null ? LocaleController.formatString("BotRemoveFromMenu", R.string.BotRemoveFromMenu, botName) : LocaleController.formatString("ChatHintsDelete", R.string.ChatHintsDelete, botName))) + .setPositiveButton(LocaleController.getString("OK", R.string.OK), (dialogInterface, i) -> { + if (attachMenuBot != null) { + TLRPC.TL_messages_toggleBotInAttachMenu req = new TLRPC.TL_messages_toggleBotInAttachMenu(); + req.bot = MessagesController.getInstance(currentAccount).getInputUser(currentUser); + req.enabled = false; + ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> AndroidUtilities.runOnUIThread(()-> { + MediaDataController.getInstance(currentAccount).loadAttachMenuBots(false, true); + if (currentAttachLayout == botAttachLayouts.get(attachMenuBot.bot_id)) { + showLayout(photoLayout); + } + }), ConnectionsManager.RequestFlagInvokeAfter | ConnectionsManager.RequestFlagFailOnServerErrors); + } else { + MediaDataController.getInstance(currentAccount).removeInline(currentUser.id); + } + }) + .setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null) + .show(); + } + + @Override + protected boolean shouldOverlayCameraViewOverNavBar() { + return currentAttachLayout == photoLayout && photoLayout.cameraExpanded; + } + @Override public void show() { super.show(); @@ -1980,7 +2364,11 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N openTransitionFinished = false; if (Build.VERSION.SDK_INT >= 30) { int color = getThemedColor(Theme.key_windowBackgroundGray); - getWindow().setNavigationBarColor(color); + AndroidUtilities.setNavigationBarColor(getWindow(), color, false, tcolor -> { + navBarColorKey = null; + navBarColor = tcolor; + containerView.invalidate(); + }); AndroidUtilities.setLightNavigationBar(getWindow(), AndroidUtilities.computePerceivedBrightness(color) > 0.721); } } @@ -2029,6 +2417,24 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N } private void showLayout(AttachAlertLayout layout) { + long newId = selectedId; + if (layout == photoLayout) { + newId = 1; + } else if (layout == audioLayout) { + newId = 3; + } else if (layout == documentLayout) { + newId = 4; + } else if (layout == contactsLayout) { + newId = 5; + } else if (layout == locationLayout) { + newId = 6; + } else if (layout == pollLayout) { + newId = 9; + } + showLayout(layout, newId); + } + + private void showLayout(AttachAlertLayout layout, long newId) { if (viewChangeAnimator != null || commentsAnimator != null) { return; } @@ -2036,25 +2442,31 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N currentAttachLayout.scrollToTop(); return; } - if (layout == photoLayout) { - selectedId = 1; - } else if (layout == audioLayout) { - selectedId = 3; - } else if (layout == documentLayout) { - selectedId = 4; - } else if (layout == contactsLayout) { - selectedId = 5; - } else if (layout == locationLayout) { - selectedId = 6; - } else if (layout == pollLayout) { - selectedId = 9; + + botButtonWasVisible = false; + botButtonProgressWasVisible = false; + botMainButtonOffsetY = 0; + botMainButtonTextView.setVisibility(View.GONE); + botProgressView.setAlpha(0f); + botProgressView.setScaleX(0.1f); + botProgressView.setScaleY(0.1f); + botProgressView.setVisibility(View.GONE); + buttonsRecyclerView.setAlpha(1f); + buttonsRecyclerView.setTranslationY(botMainButtonOffsetY); + for (int i = 0; i < botAttachLayouts.size(); i++) { + botAttachLayouts.valueAt(i).setMeasureOffsetY(0); } + + selectedId = newId; int count = buttonsRecyclerView.getChildCount(); for (int a = 0; a < count; a++) { View child = buttonsRecyclerView.getChildAt(a); if (child instanceof AttachButton) { AttachButton attachButton = (AttachButton) child; attachButton.updateCheckedState(true); + } else if (child instanceof AttachBotButton) { + AttachBotButton attachButton = (AttachBotButton) child; + attachButton.updateCheckedState(true); } } int t = currentAttachLayout.getFirstOffset() - AndroidUtilities.dp(11) - scrollOffsetY[0]; @@ -2104,7 +2516,8 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N nextAttachLayout.setTranslationY(AndroidUtilities.dp(78)); animator.playTogether( ObjectAnimator.ofFloat(currentAttachLayout, View.TRANSLATION_Y, AndroidUtilities.dp(78) + t), - ObjectAnimator.ofFloat(currentAttachLayout, ATTACH_ALERT_LAYOUT_TRANSLATION, 0.0f, 1.0f) + ObjectAnimator.ofFloat(currentAttachLayout, ATTACH_ALERT_LAYOUT_TRANSLATION, 0.0f, 1.0f), + ObjectAnimator.ofFloat(actionBar, View.ALPHA, actionBar.getAlpha(), 0f) ); animator.setDuration(180); animator.setStartDelay(20); @@ -2158,10 +2571,12 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N currentAttachLayout.setAlpha(1); ATTACH_ALERT_LAYOUT_TRANSLATION.set(currentAttachLayout, 0.0f); + float fromActionBarAlpha = actionBar.getAlpha(); SpringAnimation springAnimation = new SpringAnimation(new FloatValueHolder(0)); springAnimation.addUpdateListener((animation, value, velocity) -> { float f = value / 500f; ATTACH_ALERT_LAYOUT_TRANSLATION.set(currentAttachLayout, f); + actionBar.setAlpha(AndroidUtilities.lerp(fromActionBarAlpha, 0, f)); mediaPreviewView.setAlpha(nextAttachLayout instanceof ChatAttachAlertPhotoLayoutPreview ? f : 1f - f); }); springAnimation.addEndListener((animation, canceled, value, velocity) -> { @@ -2229,12 +2644,13 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N private void openDocumentsLayout(boolean show) { if (documentLayout == null) { - layouts[4] = documentLayout = new ChatAttachAlertDocumentLayout(this, getContext(), false, resourcesProvider); + int type = isSoundPicker ? ChatAttachAlertDocumentLayout.TYPE_RINGTONE : ChatAttachAlertDocumentLayout.TYPE_DEFAULT; + layouts[4] = documentLayout = new ChatAttachAlertDocumentLayout(this, getContext(), type, resourcesProvider); documentLayout.setDelegate(new ChatAttachAlertDocumentLayout.DocumentSelectActivityDelegate() { @Override public void didSelectFiles(ArrayList files, String caption, ArrayList fmessages, boolean notify, int scheduleDate) { - if (baseFragment instanceof ChatActivity) { - ((ChatActivity) baseFragment).didSelectFiles(files, caption, fmessages, notify, scheduleDate); + if (baseFragment instanceof ChatAttachAlertDocumentLayout.DocumentSelectActivityDelegate) { + ((ChatAttachAlertDocumentLayout.DocumentSelectActivityDelegate) baseFragment).didSelectFiles(files, caption, fmessages, notify, scheduleDate); } else if (baseFragment instanceof PassportActivity) { ((PassportActivity) baseFragment).didSelectFiles(files, caption, notify, scheduleDate); } @@ -2251,8 +2667,8 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N @Override public void startDocumentSelectActivity() { - if (baseFragment instanceof ChatActivity) { - ((ChatActivity) baseFragment).startDocumentSelectActivity(); + if (baseFragment instanceof ChatAttachAlertDocumentLayout.DocumentSelectActivityDelegate) { + ((ChatAttachAlertDocumentLayout.DocumentSelectActivityDelegate) baseFragment).startDocumentSelectActivity(); } else if (baseFragment instanceof PassportActivity) { ((PassportActivity) baseFragment).startDocumentSelectActivity(); } @@ -2270,8 +2686,9 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N documentLayout.setMaxSelectedFiles(currentChat != null && !ChatObject.hasAdminRights(currentChat) && currentChat.slowmode_enabled || editingMessageObject != null ? 1 : -1); } else { documentLayout.setMaxSelectedFiles(maxSelectedPhotos); - documentLayout.setCanSelectOnlyImageFiles(true); + documentLayout.setCanSelectOnlyImageFiles(!isSoundPicker); } + documentLayout.isSoundPicker = isSoundPicker; if (show) { showLayout(documentLayout); } @@ -2290,9 +2707,11 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N } commentTextView.hidePopup(true); if (show) { - frameLayout2.setVisibility(View.VISIBLE); + if (!isSoundPicker) { + frameLayout2.setVisibility(View.VISIBLE); + } writeButtonContainer.setVisibility(View.VISIBLE); - if (!typeButtonsAvailable) { + if (!typeButtonsAvailable && !isSoundPicker) { shadow.setVisibility(View.VISIBLE); } } else if (typeButtonsAvailable) { @@ -2313,12 +2732,10 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N animators.add(ObjectAnimator.ofFloat(shadow, View.TRANSLATION_Y, show ? AndroidUtilities.dp(36) : AndroidUtilities.dp(48 + 36))); animators.add(ObjectAnimator.ofFloat(shadow, View.ALPHA, show ? 1.0f : 0.0f)); } else if (typeButtonsAvailable) { - if (currentAttachLayout == null || currentAttachLayout.shouldHideBottomButtons()) { - animators.add(ObjectAnimator.ofFloat(buttonsRecyclerView, View.TRANSLATION_Y, show ? AndroidUtilities.dp(36) : 0)); - } + animators.add(ObjectAnimator.ofFloat(buttonsRecyclerView, View.TRANSLATION_Y, show ? AndroidUtilities.dp(36) : 0)); animators.add(ObjectAnimator.ofFloat(shadow, View.TRANSLATION_Y, show ? AndroidUtilities.dp(36) : 0)); - } else { - shadow.setTranslationY(AndroidUtilities.dp(36)); + } else if (!isSoundPicker) { + shadow.setTranslationY(AndroidUtilities.dp(36) + botMainButtonOffsetY); animators.add(ObjectAnimator.ofFloat(shadow, View.ALPHA, show ? 1.0f : 0.0f)); } @@ -2330,9 +2747,11 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N public void onAnimationEnd(Animator animation) { if (animation.equals(commentsAnimator)) { if (!show) { - frameLayout2.setVisibility(View.INVISIBLE); + if (!isSoundPicker) { + frameLayout2.setVisibility(View.INVISIBLE); + } writeButtonContainer.setVisibility(View.INVISIBLE); - if (!typeButtonsAvailable) { + if (!typeButtonsAvailable && !isSoundPicker) { shadow.setVisibility(View.INVISIBLE); } } else if (typeButtonsAvailable) { @@ -2362,15 +2781,15 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N selectedCountView.setAlpha(show ? 1.0f : 0.0f); if (actionBar.getTag() != null) { frameLayout2.setTranslationY(show ? 0.0f : AndroidUtilities.dp(48)); - shadow.setTranslationY(show ? AndroidUtilities.dp(36) : AndroidUtilities.dp(48 + 36)); + shadow.setTranslationY((show ? AndroidUtilities.dp(36) : AndroidUtilities.dp(48 + 36)) + botMainButtonOffsetY); shadow.setAlpha(show ? 1.0f : 0.0f); } else if (typeButtonsAvailable) { if (currentAttachLayout == null || currentAttachLayout.shouldHideBottomButtons()) { buttonsRecyclerView.setTranslationY(show ? AndroidUtilities.dp(36) : 0); } - shadow.setTranslationY(show ? AndroidUtilities.dp(36) : 0); + shadow.setTranslationY((show ? AndroidUtilities.dp(36) : 0) + botMainButtonOffsetY); } else { - shadow.setTranslationY(AndroidUtilities.dp(36)); + shadow.setTranslationY(AndroidUtilities.dp(36) + botMainButtonOffsetY); shadow.setAlpha(show ? 1.0f : 0.0f); } if (!show) { @@ -2539,6 +2958,9 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N } protected void makeFocusable(EditTextBoldCursor editText, boolean showKeyboard) { + if (delegate == null) { + return; + } if (!enterCommentEventSent) { boolean keyboardVisible = delegate.needEnterComment(); enterCommentEventSent = true; @@ -2558,7 +2980,7 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N button.textView.setTextColor(ColorUtils.blendARGB(getThemedColor(Theme.key_dialogTextGray2), getThemedColor(button.textKey), button.checkedState)); } else if (view instanceof AttachBotButton) { AttachBotButton button = (AttachBotButton) view; - button.nameTextView.setTextColor(getThemedColor(Theme.key_dialogTextGray2)); + button.nameTextView.setTextColor(ColorUtils.blendARGB(getThemedColor(Theme.key_dialogTextGray2), button.textColor, button.checkedState)); } } @@ -2686,7 +3108,7 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N @Override public void didReceivedNotification(int id, int account, Object... args) { - if (id == NotificationCenter.reloadInlineHints) { + if (id == NotificationCenter.reloadInlineHints || id == NotificationCenter.attachMenuBotsDidLoad) { if (buttonsAdapter != null) { buttonsAdapter.notifyDataSetChanged(); } @@ -2767,7 +3189,7 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N if (needMoreItem) { selectedMenuItem.setVisibility(View.VISIBLE); } - } else if (typeButtonsAvailable) { + } else if (typeButtonsAvailable && frameLayout2.getTag() == null) { buttonsRecyclerView.setVisibility(View.VISIBLE); } if (animated) { @@ -2961,6 +3383,21 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N if (baseFragment == null) { return; } + + botButtonWasVisible = false; + botButtonProgressWasVisible = false; + botMainButtonOffsetY = 0; + botMainButtonTextView.setVisibility(View.GONE); + botProgressView.setAlpha(0f); + botProgressView.setScaleX(0.1f); + botProgressView.setScaleY(0.1f); + botProgressView.setVisibility(View.GONE); + buttonsRecyclerView.setAlpha(1f); + buttonsRecyclerView.setTranslationY(0); + for (int i = 0; i < botAttachLayouts.size(); i++) { + botAttachLayouts.valueAt(i).setMeasureOffsetY(0); + } + if (baseFragment instanceof ChatActivity && avatarPicker != 2) { TLRPC.Chat chat = ((ChatActivity) baseFragment).getCurrentChat(); TLRPC.User user = ((ChatActivity) baseFragment).getCurrentUser(); @@ -2978,7 +3415,11 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N enterCommentEventSent = false; setFocusable(false); ChatAttachAlert.AttachAlertLayout layoutToSet; - if (editingMessageObject != null && (editingMessageObject.isMusic() || (editingMessageObject.isDocument() && !editingMessageObject.isGif()))) { + if (isSoundPicker) { + openDocumentsLayout(false); + layoutToSet = documentLayout; + selectedId = 4; + } else if (editingMessageObject != null && (editingMessageObject.isMusic() || (editingMessageObject.isDocument() && !editingMessageObject.isGif()))) { if (editingMessageObject.isMusic()) { openAudioLayout(false); layoutToSet = audioLayout; @@ -3034,6 +3475,7 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N } } NotificationCenter.getInstance(currentAccount).removeObserver(this, NotificationCenter.reloadInlineHints); + NotificationCenter.getInstance(currentAccount).removeObserver(this, NotificationCenter.attachMenuBotsDidLoad); baseFragment = null; if (commentTextView != null) { commentTextView.onDestroy(); @@ -3077,7 +3519,7 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N avatarSearch = search; if (avatarPicker != 0) { typeButtonsAvailable = false; - if (currentAttachLayout == null || currentAttachLayout.shouldHideBottomButtons()) { + if (currentAttachLayout == null) { buttonsRecyclerView.setVisibility(View.GONE); shadow.setVisibility(View.GONE); } @@ -3091,6 +3533,13 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N } } + public void setSoundPicker() { + isSoundPicker = true; + buttonsRecyclerView.setVisibility(View.GONE); + shadow.setVisibility(View.GONE); + selectedTextView.setText(LocaleController.getString("ChoosePhotoOrVideo", R.string.ChoosePhotoOrVideo)); + } + public void setMaxSelectedPhotos(int value, boolean order) { if (editingMessageObject != null) { return; @@ -3108,9 +3557,14 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N } private class ButtonsAdapter extends RecyclerListView.SelectionAdapter { + private final static int VIEW_TYPE_BUTTON = 0, VIEW_TYPE_BOT_BUTTON = 1; private Context mContext; private int galleryButton; + + private int attachBotsStartRow; + private int attachBotsEndRow; + private int documentButton; private int musicButton; private int pollButton; @@ -3122,14 +3576,15 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N mContext = context; } + @NonNull @Override - public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { + public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { View view; switch (viewType) { - case 0: + case VIEW_TYPE_BUTTON: view = new AttachButton(mContext); break; - case 1: + case VIEW_TYPE_BOT_BUTTON: default: view = new AttachBotButton(mContext); break; @@ -3140,7 +3595,7 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N @Override public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { switch (holder.getItemViewType()) { - case 0: + case VIEW_TYPE_BUTTON: AttachButton attachButton = (AttachButton) holder.itemView; if (position == galleryButton) { attachButton.setTextAndIcon(1, LocaleController.getString("ChatGallery", R.string.ChatGallery), Theme.chat_attachButtonDrawables[0], Theme.key_chat_attachGalleryBackground, Theme.key_chat_attachGalleryText); @@ -3162,9 +3617,17 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N attachButton.setTag(5); } break; - case 1: - position -= buttonsCount; + case VIEW_TYPE_BOT_BUTTON: AttachBotButton child = (AttachBotButton) holder.itemView; + if (position >= attachBotsStartRow && position < attachBotsEndRow) { + position -= attachBotsStartRow; + child.setTag(position); + TLRPC.TL_attachMenuBot bot = MediaDataController.getInstance(currentAccount).getAttachMenuBots().bots.get(position); + child.setAttachBot(MessagesController.getInstance(currentAccount).getUser(bot.bot_id), bot); + break; + } + + position -= buttonsCount; child.setTag(position); child.setUser(MessagesController.getInstance(currentAccount).getUser(MediaDataController.getInstance(currentAccount).inlineBots.get(position).peer.user_id)); break; @@ -3199,6 +3662,8 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N pollButton = -1; contactButton = -1; locationButton = -1; + attachBotsStartRow = -1; + attachBotsEndRow = -1; if (!(baseFragment instanceof ChatActivity)) { galleryButton = buttonsCount++; documentButton = buttonsCount++; @@ -3217,6 +3682,13 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N } else { if (mediaEnabled) { galleryButton = buttonsCount++; + + if (baseFragment instanceof ChatActivity && ((ChatActivity) baseFragment).getCurrentUser() != null && !((ChatActivity) baseFragment).isInScheduleMode() && !((ChatActivity) baseFragment).isSecretChat()) { + attachBotsStartRow = buttonsCount; + buttonsCount += MediaDataController.getInstance(currentAccount).getAttachMenuBots().bots.size(); + attachBotsEndRow = buttonsCount; + } + documentButton = buttonsCount++; } locationButton = buttonsCount++; @@ -3243,15 +3715,22 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N @Override public int getItemViewType(int position) { if (position < buttonsCount) { - return 0; + if (position >= attachBotsStartRow && position < attachBotsEndRow) { + return VIEW_TYPE_BOT_BUTTON; + } + return VIEW_TYPE_BUTTON; } - return 1; + return VIEW_TYPE_BOT_BUTTON; } } @Override public void dismissInternal() { - delegate.doOnIdle(this::removeFromRoot); + if (delegate != null) { + delegate.doOnIdle(this::removeFromRoot); + } else { + removeFromRoot(); + } } private void removeFromRoot() { @@ -3323,6 +3802,7 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N if (commentTextView != null) { AndroidUtilities.hideKeyboard(commentTextView.getEditText()); } + botAttachLayouts.clear(); if (!allowPassConfirmationAlert && baseFragment != null && currentAttachLayout.getSelectedItemsCount() > 0) { if (confirmationAlertShown) { return; @@ -3362,6 +3842,11 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N layouts[a].onDismiss(); } } + AndroidUtilities.setNavigationBarColor(getWindow(), ColorUtils.setAlphaComponent(navBarColor, 0), true, tcolor -> { + navBarColorKey = null; + navBarColor = tcolor; + containerView.invalidate(); + }); super.dismiss(); allowPassConfirmationAlert = false; } @@ -3386,4 +3871,8 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N public EditTextEmoji getCommentTextView() { return commentTextView; } + + public ChatAttachAlertDocumentLayout getDocumentLayout() { + return documentLayout; + } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlertBotWebViewLayout.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlertBotWebViewLayout.java new file mode 100644 index 000000000..e90fd7403 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlertBotWebViewLayout.java @@ -0,0 +1,812 @@ +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.Paint; +import android.os.Build; +import android.os.Bundle; +import android.view.GestureDetector; +import android.view.Gravity; +import android.view.MotionEvent; +import android.view.View; +import android.view.ViewConfiguration; +import android.view.WindowManager; +import android.webkit.WebView; +import android.widget.FrameLayout; + +import androidx.annotation.NonNull; +import androidx.core.math.MathUtils; +import androidx.core.view.GestureDetectorCompat; +import androidx.dynamicanimation.animation.SpringAnimation; +import androidx.dynamicanimation.animation.SpringForce; +import androidx.recyclerview.widget.ChatListItemAnimator; + +import org.json.JSONObject; +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.FileLog; +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.UserObject; +import org.telegram.tgnet.ConnectionsManager; +import org.telegram.tgnet.TLRPC; +import org.telegram.ui.ActionBar.ActionBar; +import org.telegram.ui.ActionBar.ActionBarMenu; +import org.telegram.ui.ActionBar.ActionBarMenuItem; +import org.telegram.ui.ActionBar.BaseFragment; +import org.telegram.ui.ActionBar.Theme; +import org.telegram.ui.ChatActivity; + +public class ChatAttachAlertBotWebViewLayout extends ChatAttachAlert.AttachAlertLayout implements NotificationCenter.NotificationCenterDelegate { + private final static int POLL_PERIOD = 60000; + + private BotWebViewContainer webViewContainer; + private ValueAnimator webViewScrollAnimator; + + private boolean ignoreLayout; + + private long botId; + private long peerId; + private long queryId; + private boolean silent; + private int replyToMsgId; + private int currentAccount; + private String startCommand; + + private boolean needReload; + private WebProgressView progressView; + private WebViewSwipeContainer swipeContainer; + private ActionBarMenuItem otherItem; + + private int measureOffsetY; + + private long lastSwipeTime; + + private boolean ignoreMeasure; + private boolean isBotButtonAvailable; + + private boolean destroyed; + private Runnable pollRunnable = () -> { + if (!destroyed) { + TLRPC.TL_messages_prolongWebView prolongWebView = new TLRPC.TL_messages_prolongWebView(); + prolongWebView.bot = MessagesController.getInstance(currentAccount).getInputUser(botId); + prolongWebView.peer = MessagesController.getInstance(currentAccount).getInputPeer(peerId); + prolongWebView.query_id = queryId; + prolongWebView.silent = silent; + if (replyToMsgId != 0) { + prolongWebView.reply_to_msg_id = replyToMsgId; + prolongWebView.flags |= 1; + } + ConnectionsManager.getInstance(currentAccount).sendRequest(prolongWebView, (response, error) -> AndroidUtilities.runOnUIThread(() -> { + if (destroyed) { + return; + } + if (error != null) { + parentAlert.dismiss(); + } else { + AndroidUtilities.runOnUIThread(this.pollRunnable, POLL_PERIOD); + } + })); + } + }; + + public ChatAttachAlertBotWebViewLayout(ChatAttachAlert alert, Context context, Theme.ResourcesProvider resourcesProvider) { + super(alert, context, resourcesProvider); + + ActionBarMenu menu = parentAlert.actionBar.createMenu(); + otherItem = menu.addItem(0, R.drawable.ic_ab_other); + otherItem.addSubItem(R.id.menu_open_bot, R.drawable.msg_bot, LocaleController.getString(R.string.BotWebViewOpenBot)); + otherItem.addSubItem(R.id.menu_reload_page, R.drawable.msg_retry, LocaleController.getString(R.string.BotWebViewReloadPage)); + otherItem.addSubItem(R.id.menu_delete_bot, R.drawable.msg_delete, LocaleController.getString(R.string.BotWebViewDeleteBot)); + parentAlert.actionBar.setActionBarMenuOnItemClick(new ActionBar.ActionBarMenuOnItemClick() { + @Override + public void onItemClick(int id) { + if (id == -1) { + parentAlert.dismiss(); + } else if (id == R.id.menu_open_bot) { + Bundle bundle = new Bundle(); + bundle.putLong("user_id", botId); + parentAlert.baseFragment.presentFragment(new ChatActivity(bundle)); + parentAlert.dismiss(); + } else if (id == R.id.menu_reload_page) { + webViewContainer.getWebView().animate().cancel(); + webViewContainer.getWebView().animate().alpha(0).start(); + requestWebView(currentAccount, peerId, botId, silent, replyToMsgId, startCommand); + } else if (id == R.id.menu_delete_bot) { + for (TLRPC.TL_attachMenuBot bot : MediaDataController.getInstance(currentAccount).getAttachMenuBots().bots) { + if (bot.bot_id == botId) { + parentAlert.onLongClickBotButton(bot, MessagesController.getInstance(currentAccount).getUser(botId)); + break; + } + } + } + } + }); + + webViewContainer = new BotWebViewContainer(context, resourcesProvider, getThemedColor(Theme.key_dialogBackground)) { + @Override + public boolean dispatchTouchEvent(MotionEvent ev) { + if (ev.getAction() == MotionEvent.ACTION_DOWN) { + if (!isBotButtonAvailable) { + isBotButtonAvailable = true; + webViewContainer.restoreButtonData(); + } + } + return super.dispatchTouchEvent(ev); + } + }; + webViewContainer.getWebView().setVerticalScrollBarEnabled(false); + swipeContainer = new WebViewSwipeContainer(context) { + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(heightMeasureSpec) - ActionBar.getCurrentActionBarHeight() - AndroidUtilities.dp(84) + measureOffsetY, MeasureSpec.EXACTLY)); + } + }; + swipeContainer.addView(webViewContainer, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); + swipeContainer.setWebView(webViewContainer.getWebView()); + swipeContainer.setScrollListener(() -> { + parentAlert.updateLayout(this, true, 0); + webViewContainer.invalidateViewPortHeight(); + lastSwipeTime = System.currentTimeMillis(); + }); + swipeContainer.setScrollEndListener(()-> webViewContainer.invalidateViewPortHeight(true)); + swipeContainer.setDelegate(() -> parentAlert.dismiss()); + + addView(swipeContainer, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); + addView(progressView = new WebProgressView(context, resourcesProvider), LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.BOTTOM, 0, 0, 0, 84)); + + webViewContainer.setWebViewProgressListener(progress -> { + progressView.setLoadProgressAnimated(progress); + if (progress == 1f) { + ValueAnimator animator = ValueAnimator.ofFloat(1, 0).setDuration(200); + animator.setInterpolator(CubicBezierInterpolator.DEFAULT); + animator.addUpdateListener(animation -> progressView.setAlpha((Float) animation.getAnimatedValue())); + animator.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + progressView.setVisibility(GONE); + } + }); + animator.start(); + } + }); + } + + public boolean canExpandByRequest() { + return System.currentTimeMillis() - lastSwipeTime > 1000 && !swipeContainer.isSwipeInProgress(); + } + + public void setMeasureOffsetY(int measureOffsetY) { + this.measureOffsetY = measureOffsetY; + swipeContainer.requestLayout(); + } + + public void disallowSwipeOffsetAnimation() { + swipeContainer.setSwipeOffsetAnimationDisallowed(true); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + if (ignoreMeasure) { + setMeasuredDimension(getMeasuredWidth(), getMeasuredHeight()); + } else { + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + } + } + + @Override + public void onPanTransitionStart(boolean keyboardVisible, int contentHeight) { + if (!keyboardVisible) { + return; + } + + int oldh = contentHeight + parentAlert.sizeNotifierFrameLayout.measureKeyboardHeight(); + setMeasuredDimension(getMeasuredWidth(), contentHeight); + ignoreMeasure = true; + + if (webViewScrollAnimator != null) { + webViewScrollAnimator.cancel(); + webViewScrollAnimator = null; + } + + int fromY = webViewContainer.getWebView().getScrollY(); + int toY = fromY + (oldh - contentHeight); + webViewScrollAnimator = ValueAnimator.ofInt(fromY, toY).setDuration(250); + webViewScrollAnimator.setInterpolator(ChatListItemAnimator.DEFAULT_INTERPOLATOR); + webViewScrollAnimator.addUpdateListener(animation -> { + int val = (int) animation.getAnimatedValue(); + webViewContainer.getWebView().setScrollY(val); + }); + webViewScrollAnimator.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + webViewContainer.getWebView().setScrollY(toY); + if (animation == webViewScrollAnimator) { + webViewScrollAnimator = null; + } + } + }); + webViewScrollAnimator.start(); + } + + @Override + public void onPanTransitionEnd() { + ignoreMeasure = false; + requestLayout(); + } + + @Override + void onShow(ChatAttachAlert.AttachAlertLayout previousLayout) { + parentAlert.actionBar.setTitle(UserObject.getUserName(MessagesController.getInstance(currentAccount).getUser(botId))); + swipeContainer.setSwipeOffsetY(0); + webViewContainer.getWebView().scrollTo(0, 0); + if (parentAlert.getBaseFragment() != null) { + webViewContainer.setParentActivity(parentAlert.getBaseFragment().getParentActivity()); + } + otherItem.setVisibility(VISIBLE); + } + + @Override + void onShown() { + requestEnableKeyboard(); + + swipeContainer.setSwipeOffsetAnimationDisallowed(false); + AndroidUtilities.runOnUIThread(() -> webViewContainer.restoreButtonData()); + } + + private void requestEnableKeyboard() { + BaseFragment fragment = parentAlert.getBaseFragment(); + if (fragment instanceof ChatActivity && ((ChatActivity) fragment).contentView.measureKeyboardHeight() > AndroidUtilities.dp(20)) { + AndroidUtilities.hideKeyboard(parentAlert.baseFragment.getFragmentView()); + AndroidUtilities.runOnUIThread(this::requestEnableKeyboard, 150); + return; + } + + setFocusable(true); + parentAlert.setFocusable(true); + parentAlert.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE | WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE); + } + + @Override + void onHidden() { + super.onHidden(); + + parentAlert.setFocusable(false); + parentAlert.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING); + } + + @Override + int getCurrentItemTop() { + return (int) (swipeContainer.getSwipeOffsetY() + swipeContainer.getOffsetY()); + } + + @Override + public void setTranslationY(float translationY) { + super.setTranslationY(translationY); + parentAlert.getSheetContainer().invalidate(); + } + + public String getStartCommand() { + return startCommand; + } + + public void requestWebView(int currentAccount, long peerId, long botId, boolean silent, int replyToMsgId) { + requestWebView(currentAccount, peerId, botId, silent, replyToMsgId, null); + } + + public void requestWebView(int currentAccount, long peerId, long botId, boolean silent, int replyToMsgId, String startCommand) { + this.currentAccount = currentAccount; + this.peerId = peerId; + this.botId = botId; + this.silent = silent; + this.replyToMsgId = replyToMsgId; + this.startCommand = startCommand; + + webViewContainer.setBotUser(MessagesController.getInstance(currentAccount).getUser(botId)); + webViewContainer.loadFlicker(currentAccount, botId); + + TLRPC.TL_messages_requestWebView req = new TLRPC.TL_messages_requestWebView(); + req.peer = MessagesController.getInstance(currentAccount).getInputPeer(peerId); + req.bot = MessagesController.getInstance(currentAccount).getInputUser(botId); + req.silent = silent; + if (startCommand != null) { + req.start_param = startCommand; + req.flags |= 8; + } + + if (replyToMsgId != 0) { + req.reply_to_msg_id = replyToMsgId; + req.flags |= 1; + } + + try { + JSONObject jsonObject = new JSONObject(); + jsonObject.put("bg_color", getThemedColor(Theme.key_dialogBackground)); + jsonObject.put("text_color", getThemedColor(Theme.key_windowBackgroundWhiteBlackText)); + jsonObject.put("hint_color", getThemedColor(Theme.key_windowBackgroundWhiteHintText)); + jsonObject.put("link_color", getThemedColor(Theme.key_windowBackgroundWhiteLinkText)); + jsonObject.put("button_color", getThemedColor(Theme.key_featuredStickers_addButton)); + jsonObject.put("button_text_color", getThemedColor(Theme.key_featuredStickers_buttonText)); + + req.theme_params = new TLRPC.TL_dataJSON(); + req.theme_params.data = jsonObject.toString(); + req.flags |= 4; + } catch (Exception e) { + FileLog.e(e); + } + + ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> AndroidUtilities.runOnUIThread(() -> { + if (response instanceof TLRPC.TL_webViewResultUrl) { + TLRPC.TL_webViewResultUrl resultUrl = (TLRPC.TL_webViewResultUrl) response; + queryId = resultUrl.query_id; + webViewContainer.loadUrl(resultUrl.url); + + AndroidUtilities.runOnUIThread(pollRunnable); + } + })); + + NotificationCenter.getInstance(currentAccount).addObserver(this, NotificationCenter.webViewResultSent); + } + + @Override + void onDestroy() { + NotificationCenter.getInstance(currentAccount).removeObserver(this, NotificationCenter.webViewResultSent); + + ActionBarMenu menu = parentAlert.actionBar.createMenu(); + otherItem.removeAllSubItems(); + menu.removeView(otherItem); + + webViewContainer.destroyWebView(); + destroyed = true; + + AndroidUtilities.cancelRunOnUIThread(pollRunnable); + } + + @Override + void onHide() { + super.onHide(); + otherItem.setVisibility(GONE); + isBotButtonAvailable = false; + + if (webViewContainer.hasUserPermissions()) { + webViewContainer.destroyWebView(); + needReload = true; + } + } + + public boolean needReload() { + if (needReload) { + needReload = false; + return true; + } + return false; + } + + @Override + int getListTopPadding() { + return (int) swipeContainer.getOffsetY(); + } + + @Override + int getFirstOffset() { + return getListTopPadding() + AndroidUtilities.dp(56); + } + + @Override + void onPreMeasure(int availableWidth, int availableHeight) { + int padding; + if (!AndroidUtilities.isTablet() && AndroidUtilities.displaySize.x > AndroidUtilities.displaySize.y) { + padding = (int) (availableHeight / 3.5f); + } else { + padding = (availableHeight / 5 * 2); + } + parentAlert.setAllowNestedScroll(true); + + if (padding < 0) { + padding = 0; + } + if (swipeContainer.getOffsetY() != padding) { + ignoreLayout = true; + swipeContainer.setOffsetY(padding); + ignoreLayout = false; + } + } + + @Override + int getButtonsHideOffset() { + return AndroidUtilities.dp(56); + } + + @Override + public void requestLayout() { + if (ignoreLayout) { + return; + } + super.requestLayout(); + } + + @Override + void scrollToTop() { + swipeContainer.stickTo(-swipeContainer.getOffsetY() + swipeContainer.getTopActionBarOffsetY()); + } + + @Override + boolean shouldHideBottomButtons() { + return false; + } + + @Override + int needsActionBar() { + return 1; + } + + public BotWebViewContainer getWebViewContainer() { + return webViewContainer; + } + + public void setDelegate(BotWebViewContainer.Delegate delegate) { + webViewContainer.setDelegate(delegate); + } + + public boolean isBotButtonAvailable() { + return isBotButtonAvailable; + } + + @Override + public void didReceivedNotification(int id, int account, Object... args) { + if (id == NotificationCenter.webViewResultSent) { + long queryId = (long) args[0]; + + if (this.queryId == queryId) { + webViewContainer.destroyWebView(); + needReload = true; + parentAlert.dismiss(); + } + } + } + + public static class WebViewSwipeContainer extends FrameLayout { + public final static SimpleFloatPropertyCompat SWIPE_OFFSET_Y = new SimpleFloatPropertyCompat<>("swipeOffsetY", WebViewSwipeContainer::getSwipeOffsetY, WebViewSwipeContainer::setSwipeOffsetY); + + private GestureDetectorCompat gestureDetector; + private boolean isScrolling; + private boolean isSwipeDisallowed; + + private float topActionBarOffsetY = ActionBar.getCurrentActionBarHeight(); + private float offsetY = -1; + private float swipeOffsetY; + private boolean isSwipeOffsetAnimationDisallowed; + + private boolean flingInProgress; + + private WebView webView; + + private Runnable scrollListener; + private Runnable scrollEndListener; + private Delegate delegate; + + private SpringAnimation scrollAnimator; + + public WebViewSwipeContainer(@NonNull Context context) { + super(context); + + int touchSlop = ViewConfiguration.get(context).getScaledTouchSlop(); + gestureDetector = new GestureDetectorCompat(context, new GestureDetector.SimpleOnGestureListener() { + @Override + public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { + if (isSwipeDisallowed) { + return false; + } + if (velocityY >= 700 && webView.getScrollY() == 0) { + flingInProgress = true; + + if (swipeOffsetY >= AndroidUtilities.dp(64)) { + if (delegate != null) { + delegate.onDismiss(); + } + } else { + stickTo(0); + } + return true; + } else if (velocityY <= -700 && swipeOffsetY > -offsetY + topActionBarOffsetY) { + flingInProgress = true; + stickTo(-offsetY + topActionBarOffsetY); + return true; + } + return true; + } + + @Override + public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { + if (!isScrolling && !isSwipeDisallowed) { + if (Math.abs(distanceY) >= touchSlop && Math.abs(distanceY) * 1.5f >= Math.abs(distanceX) && (swipeOffsetY != -offsetY + topActionBarOffsetY || distanceY < 0 && webView.getScrollY() == 0)) { + isScrolling = true; + + MotionEvent ev = MotionEvent.obtain(0, 0, MotionEvent.ACTION_CANCEL, 0, 0, 0); + for (int i = 0; i < getChildCount(); i++) { + getChildAt(i).dispatchTouchEvent(ev); + } + ev.recycle(); + + return true; + } else if (webView.canScrollHorizontally(distanceX >= 0 ? 1 : -1)) { + isSwipeDisallowed = true; + } + } + if (isScrolling) { + if (distanceY < 0) { + if (swipeOffsetY > -offsetY + topActionBarOffsetY) { + swipeOffsetY -= distanceY; + } else { + float newWebScrollY = webView.getScrollY() + distanceY; + webView.setScrollY((int) MathUtils.clamp(newWebScrollY, 0, Math.max(webView.getContentHeight(), webView.getHeight()) - topActionBarOffsetY)); + + if (newWebScrollY < 0) { + swipeOffsetY -= newWebScrollY; + } + } + } else { + swipeOffsetY = swipeOffsetY - distanceY; + + if (swipeOffsetY < -offsetY + topActionBarOffsetY) { + float newWebScrollY = webView.getScrollY() - (swipeOffsetY + offsetY - topActionBarOffsetY); + webView.setScrollY((int) MathUtils.clamp(newWebScrollY, 0, Math.max(webView.getContentHeight(), webView.getHeight()) - topActionBarOffsetY)); + } + } + + swipeOffsetY = MathUtils.clamp(swipeOffsetY, -offsetY + topActionBarOffsetY, getHeight() - offsetY + topActionBarOffsetY); + invalidateTranslation(); + return true; + } + + return true; + } + }); + } + + @Override + public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) { + super.requestDisallowInterceptTouchEvent(disallowIntercept); + + if (disallowIntercept) { + isSwipeDisallowed = true; + isScrolling = false; + } + } + + public void setSwipeOffsetAnimationDisallowed(boolean swipeOffsetAnimationDisallowed) { + isSwipeOffsetAnimationDisallowed = swipeOffsetAnimationDisallowed; + } + + public void setScrollListener(Runnable scrollListener) { + this.scrollListener = scrollListener; + } + + public void setScrollEndListener(Runnable scrollEndListener) { + this.scrollEndListener = scrollEndListener; + } + + public void setWebView(WebView webView) { + this.webView = webView; + } + + public void setTopActionBarOffsetY(float topActionBarOffsetY) { + this.topActionBarOffsetY = topActionBarOffsetY; + invalidateTranslation(); + } + + public void setSwipeOffsetY(float swipeOffsetY) { + this.swipeOffsetY = swipeOffsetY; + invalidateTranslation(); + } + + public void setOffsetY(float offsetY) { + float wasOffsetY = this.offsetY; + boolean wasOnTop = swipeOffsetY == -wasOffsetY + topActionBarOffsetY; + if (wasOffsetY != -1 && !isSwipeOffsetAnimationDisallowed) { + ValueAnimator animator = ValueAnimator.ofFloat(wasOffsetY, offsetY).setDuration(200); + animator.setInterpolator(CubicBezierInterpolator.DEFAULT); + animator.addUpdateListener(animation -> { + this.offsetY = (float) animation.getAnimatedValue(); + if (wasOnTop) { + swipeOffsetY = -this.offsetY + topActionBarOffsetY; + } else { + swipeOffsetY = MathUtils.clamp(swipeOffsetY, -this.offsetY + topActionBarOffsetY, getHeight() - this.offsetY + topActionBarOffsetY); + } + invalidateTranslation(); + }); + animator.start(); + } else { + this.offsetY = offsetY; + if (wasOnTop) { + this.swipeOffsetY = -this.offsetY + topActionBarOffsetY; + } + invalidateTranslation(); + } + } + + private void invalidateTranslation() { + setTranslationY(Math.max(topActionBarOffsetY, offsetY + swipeOffsetY)); + if (scrollListener != null) { + scrollListener.run(); + } + } + + public float getTopActionBarOffsetY() { + return topActionBarOffsetY; + } + + public float getOffsetY() { + return offsetY; + } + + public float getSwipeOffsetY() { + return swipeOffsetY; + } + + public void setDelegate(Delegate delegate) { + this.delegate = delegate; + } + + @Override + public boolean dispatchTouchEvent(MotionEvent ev) { + if (isScrolling && ev.getActionIndex() != 0) { + return false; + } + + MotionEvent rawEvent = MotionEvent.obtain(ev); + int index = ev.getActionIndex(); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { + rawEvent.setLocation(ev.getRawX(index), ev.getRawY(index)); + } else { + float offsetX = ev.getRawX() - ev.getX(), offsetY = ev.getRawY() - ev.getY(); + rawEvent.setLocation(ev.getX(index) + offsetX, ev.getY(index) + offsetY); + } + boolean detector = gestureDetector.onTouchEvent(rawEvent); + rawEvent.recycle(); + + if (ev.getAction() == MotionEvent.ACTION_UP || ev.getAction() == MotionEvent.ACTION_CANCEL) { + isSwipeDisallowed = false; + isScrolling = false; + + if (flingInProgress) { + flingInProgress = false; + } else { + if (swipeOffsetY <= -AndroidUtilities.dp(64)) { + stickTo(-offsetY + topActionBarOffsetY); + } else if (swipeOffsetY > -AndroidUtilities.dp(64) && swipeOffsetY <= AndroidUtilities.dp(64)) { + stickTo(0); + } else { + if (delegate != null) { + delegate.onDismiss(); + } + } + } + } + + boolean superTouch = super.dispatchTouchEvent(ev); + if (!superTouch && !detector && ev.getAction() == MotionEvent.ACTION_DOWN) { + return true; + } + return superTouch || detector; + } + + public void stickTo(float offset) { + stickTo(offset, null); + } + + public void stickTo(float offset, Runnable callback) { + if (swipeOffsetY == offset) { + if (callback != null) { + callback.run(); + } + if (scrollEndListener != null) { + scrollEndListener.run(); + } + return; + } + + if (scrollAnimator != null) { + scrollAnimator.cancel(); + } + scrollAnimator = new SpringAnimation(this, SWIPE_OFFSET_Y, offset) + .setSpring(new SpringForce(offset) + .setStiffness(1400) + .setDampingRatio(SpringForce.DAMPING_RATIO_NO_BOUNCY)) + .addEndListener((animation, canceled, value, velocity) -> { + if (animation == scrollAnimator) { + scrollAnimator = null; + + if (callback != null) { + callback.run(); + } + + if (scrollEndListener != null) { + scrollEndListener.run(); + } + } + }); + scrollAnimator.start(); + } + + public boolean isSwipeInProgress() { + return isScrolling; + } + + public interface Delegate { + /** + * Called to dismiss parent layout + */ + void onDismiss(); + } + } + + public final static class WebProgressView extends View { + private final SimpleFloatPropertyCompat LOAD_PROGRESS_PROPERTY = new SimpleFloatPropertyCompat<>("loadProgress", obj -> obj.loadProgress, WebProgressView::setLoadProgress).setMultiplier(100f); + + private Paint bluePaint = new Paint(Paint.ANTI_ALIAS_FLAG); + private float loadProgress; + private SpringAnimation springAnimation; + private Theme.ResourcesProvider resourcesProvider; + + public WebProgressView(Context context, Theme.ResourcesProvider resourcesProvider) { + super(context); + this.resourcesProvider = resourcesProvider; + + bluePaint.setColor(getThemedColor(Theme.key_featuredStickers_addButton)); + bluePaint.setStyle(Paint.Style.STROKE); + bluePaint.setStrokeWidth(AndroidUtilities.dp(2)); + bluePaint.setStrokeCap(Paint.Cap.ROUND); + } + + protected int getThemedColor(String key) { + Integer color = resourcesProvider != null ? resourcesProvider.getColor(key) : null; + return color != null ? color : Theme.getColor(key); + } + + @Override + protected void onAttachedToWindow() { + super.onAttachedToWindow(); + + springAnimation = new SpringAnimation(this, LOAD_PROGRESS_PROPERTY) + .setSpring(new SpringForce() + .setStiffness(400f) + .setDampingRatio(SpringForce.DAMPING_RATIO_NO_BOUNCY)); + } + + @Override + protected void onDetachedFromWindow() { + super.onDetachedFromWindow(); + + springAnimation.cancel(); + springAnimation = null; + } + + public void setLoadProgressAnimated(float loadProgress) { + if (springAnimation == null) { + setLoadProgress(loadProgress); + return; + } + springAnimation.getSpring().setFinalPosition(loadProgress * 100f); + springAnimation.start(); + } + + public void setLoadProgress(float loadProgress) { + this.loadProgress = loadProgress; + invalidate(); + } + + @Override + public void draw(Canvas canvas) { + super.draw(canvas); + + float y = getHeight() - bluePaint.getStrokeWidth() / 2f; + canvas.drawLine(0, y, getWidth() * loadProgress, y, bluePaint); + } + } +} 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 b1882d7fd..f763975e5 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlertContactsLayout.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlertContactsLayout.java @@ -396,7 +396,7 @@ public class ChatAttachAlertContactsLayout extends ChatAttachAlert.AttachAlertLa PhonebookShareAlert phonebookShareAlert = new PhonebookShareAlert(parentAlert.baseFragment, contact, null, null, null, firstName, lastName, resourcesProvider); phonebookShareAlert.setDelegate((user, notify, scheduleDate) -> { - parentAlert.dismiss(); + parentAlert.dismiss(true); delegate.didSelectContact(user, notify, scheduleDate); }); phonebookShareAlert.show(); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlertDocumentLayout.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlertDocumentLayout.java index 8863b9603..78568a44e 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlertDocumentLayout.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlertDocumentLayout.java @@ -17,17 +17,22 @@ import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; +import android.database.Cursor; import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; +import android.media.MediaMetadataRetriever; +import android.net.Uri; import android.os.Build; import android.os.Environment; import android.os.StatFs; +import android.provider.MediaStore; import android.text.TextUtils; import android.util.SparseArray; import android.view.Gravity; import android.view.View; import android.view.ViewGroup; import android.view.ViewTreeObserver; +import android.webkit.MimeTypeMap; import android.widget.EditText; import android.widget.FrameLayout; @@ -44,11 +49,13 @@ import org.telegram.messenger.FileLog; 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.SendMessagesHelper; import org.telegram.messenger.SharedConfig; import org.telegram.messenger.UserConfig; import org.telegram.messenger.Utilities; +import org.telegram.messenger.ringtone.RingtoneDataStore; import org.telegram.tgnet.TLObject; import org.telegram.tgnet.TLRPC; import org.telegram.ui.ActionBar.ActionBar; @@ -81,14 +88,24 @@ public class ChatAttachAlertDocumentLayout extends ChatAttachAlert.AttachAlertLa public interface DocumentSelectActivityDelegate { void didSelectFiles(ArrayList files, String caption, ArrayList fmessages, boolean notify, int scheduleDate); - void didSelectPhotos(ArrayList photos, boolean notify, int scheduleDate); + default void didSelectPhotos(ArrayList photos, boolean notify, int scheduleDate) { - void startDocumentSelectActivity(); + } + + default void startDocumentSelectActivity() { + + } default void startMusicSelectActivity() { } } + public final static int TYPE_DEFAULT = 0; + public final static int TYPE_MUSIC = 1; + public final static int TYPE_RINGTONE = 2; + + private int type; + private RecyclerListView listView; private ListAdapter listAdapter; private SearchAdapter searchAdapter; @@ -129,6 +146,7 @@ public class ChatAttachAlertDocumentLayout extends ChatAttachAlert.AttachAlertLa private final static int search_button = 0; private final static int sort_button = 6; + public boolean isSoundPicker; private static class ListItem { public int icon; @@ -168,9 +186,10 @@ public class ChatAttachAlertDocumentLayout extends ChatAttachAlert.AttachAlertLa } }; - public ChatAttachAlertDocumentLayout(ChatAttachAlert alert, Context context, boolean music, Theme.ResourcesProvider resourcesProvider) { + public ChatAttachAlertDocumentLayout(ChatAttachAlert alert, Context context, int type, Theme.ResourcesProvider resourcesProvider) { super(alert, context, resourcesProvider); - allowMusic = music; + allowMusic = type == TYPE_MUSIC; + isSoundPicker = type == TYPE_RINGTONE; sortByName = SharedConfig.sortFilesByName; loadRecentFiles(); @@ -371,7 +390,7 @@ public class ChatAttachAlertDocumentLayout extends ChatAttachAlert.AttachAlertLa }); fragment.setMaxSelectedPhotos(maxSelectedFiles, false); parentAlert.baseFragment.presentFragment(fragment); - parentAlert.dismiss(); + parentAlert.dismiss(true); } else if (item.icon == R.drawable.files_music) { if (delegate != null) { delegate.startMusicSelectActivity(); @@ -565,7 +584,7 @@ public class ChatAttachAlertDocumentLayout extends ChatAttachAlert.AttachAlertLa ArrayList files = new ArrayList<>(selectedFilesOrder); delegate.didSelectFiles(files, parentAlert.commentTextView.getText().toString(), fmessages, notify, scheduleDate); - parentAlert.dismiss(); + parentAlert.dismiss(true); } private boolean onItemClick(View view, Object object) { @@ -597,6 +616,9 @@ public class ChatAttachAlertDocumentLayout extends ChatAttachAlert.AttachAlertLa showErrorBox(LocaleController.formatString("PassportUploadMaxReached", R.string.PassportUploadMaxReached, LocaleController.formatPluralString("Files", maxSelectedFiles))); return false; } + if (isSoundPicker && !isRingtone(item.file)) { + return false; + } if (item.file.length() == 0) { return false; } @@ -628,12 +650,45 @@ public class ChatAttachAlertDocumentLayout extends ChatAttachAlert.AttachAlertLa return true; } + public boolean isRingtone(File file) { + String mimeType = null; + String extension = FileLoader.getFileExtension(file); + if (extension != null) { + mimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension); + } + if (file.length() == 0 || mimeType == null || !RingtoneDataStore.ringtoneSupportedMimeType.contains(mimeType)) { + BulletinFactory.of(parentAlert.getContainer(), null).createErrorBulletinSubtitle(LocaleController.formatString("InvalidFormatError", R.string.InvalidFormatError), LocaleController.formatString("ErrorInvalidRingtone", R.string.ErrorRingtoneInvalidFormat), null).show(); + return false; + } + if (file.length() > MessagesController.getInstance(UserConfig.selectedAccount).ringtoneSizeMax) { + BulletinFactory.of(parentAlert.getContainer(), null).createErrorBulletinSubtitle(LocaleController.formatString("TooLargeError", R.string.TooLargeError), LocaleController.formatString("ErrorRingtoneSizeTooBig", R.string.ErrorRingtoneSizeTooBig, (MessagesController.getInstance(UserConfig.selectedAccount).ringtoneSizeMax / 1024)), null).show(); + return false; + } + + int millSecond; + try { + MediaMetadataRetriever mmr = new MediaMetadataRetriever(); + mmr.setDataSource(ApplicationLoader.applicationContext, Uri.fromFile(file)); + String durationStr = mmr.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION); + millSecond = Integer.parseInt(durationStr); + } catch (Exception e) { + millSecond = Integer.MAX_VALUE; + } + + if (millSecond > MessagesController.getInstance(UserConfig.selectedAccount).ringtoneDurationMax * 1000) { + BulletinFactory.of(parentAlert.getContainer(), null).createErrorBulletinSubtitle(LocaleController.formatString("TooLongError", R.string.TooLongError), LocaleController.formatString("ErrorRingtoneDurationTooLong", R.string.ErrorRingtoneDurationTooLong, MessagesController.getInstance(UserConfig.selectedAccount).ringtoneDurationMax), null).show(); + return false; + } + + return true; + } + public void setMaxSelectedFiles(int value) { maxSelectedFiles = value; } public void setCanSelectOnlyImageFiles(boolean value) { - canSelectOnlyImageFiles = true; + canSelectOnlyImageFiles = value; } private void sendSelectedPhotos(HashMap photos, ArrayList order, boolean notify, int scheduleDate) { @@ -667,33 +722,75 @@ public class ChatAttachAlertDocumentLayout extends ChatAttachAlert.AttachAlertLa public void loadRecentFiles() { try { - File[] files = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).listFiles(); - if (files != null) { - for (int a = 0; a < files.length; a++) { - File file = files[a]; - if (file.isDirectory()) { - continue; + if (isSoundPicker) { + String[] projection = { + MediaStore.Audio.Media._ID, + MediaStore.Audio.Media.DATA, + MediaStore.Audio.Media.DURATION, + MediaStore.Audio.Media.SIZE, + MediaStore.Audio.Media.MIME_TYPE + }; + try (Cursor cursor = ApplicationLoader.applicationContext.getContentResolver().query(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, projection, MediaStore.Audio.Media.IS_MUSIC + " != 0", null, MediaStore.Audio.Media.DATE_ADDED + " DESC")) { + while (cursor.moveToNext()) { + File file = new File(cursor.getString(1)); + long duration = cursor.getLong(2); + long fileSize = cursor.getLong(3); + String mimeType = cursor.getString(4); + + if (duration > MessagesController.getInstance(UserConfig.selectedAccount).ringtoneDurationMax * 1000 || fileSize > MessagesController.getInstance(UserConfig.selectedAccount).ringtoneSizeMax || (!TextUtils.isEmpty(mimeType) && !("audio/mpeg".equals(mimeType) || !"audio/mpeg4".equals(mimeType)))) { + continue; + } + + ListItem item = new ListItem(); + item.title = file.getName(); + item.file = file; + String fname = file.getName(); + String[] sp = fname.split("\\."); + item.ext = sp.length > 1 ? sp[sp.length - 1] : "?"; + item.subtitle = AndroidUtilities.formatFileSize(file.length()); + fname = fname.toLowerCase(); + if (fname.endsWith(".jpg") || fname.endsWith(".png") || fname.endsWith(".gif") || fname.endsWith(".jpeg")) { + item.thumb = file.getAbsolutePath(); + } + recentItems.add(item); } - ListItem item = new ListItem(); - item.title = file.getName(); - item.file = file; - String fname = file.getName(); - String[] sp = fname.split("\\."); - item.ext = sp.length > 1 ? sp[sp.length - 1] : "?"; - item.subtitle = AndroidUtilities.formatFileSize(file.length()); - fname = fname.toLowerCase(); - if (fname.endsWith(".jpg") || fname.endsWith(".png") || fname.endsWith(".gif") || fname.endsWith(".jpeg")) { - item.thumb = file.getAbsolutePath(); - } - recentItems.add(item); + } catch (Exception e) { + FileLog.e(e); } + } else { + checkDirectory(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS)); + sortRecentItems(); } - sortRecentItems(); } catch (Exception e) { FileLog.e(e); } } + private void checkDirectory(File rootDir) { + File[] files = rootDir.listFiles(); + if (files != null) { + for (int a = 0; a < files.length; a++) { + File file = files[a]; + if (file.isDirectory() && file.getName().equals("Telegram")) { + checkDirectory(file); + continue; + } + ListItem item = new ListItem(); + item.title = file.getName(); + item.file = file; + String fname = file.getName(); + String[] sp = fname.split("\\."); + item.ext = sp.length > 1 ? sp[sp.length - 1] : "?"; + item.subtitle = AndroidUtilities.formatFileSize(file.length()); + fname = fname.toLowerCase(); + if (fname.endsWith(".jpg") || fname.endsWith(".png") || fname.endsWith(".gif") || fname.endsWith(".jpeg")) { + item.thumb = file.getAbsolutePath(); + } + recentItems.add(item); + } + } + } + private void sortRecentItems() { Collections.sort(recentItems, (o1, o2) -> { if (sortByName) { @@ -1049,12 +1146,14 @@ public class ChatAttachAlertDocumentLayout extends ChatAttachAlert.AttachAlertLa FileLog.e(e); } - fs = new ListItem(); - fs.title = LocaleController.getString("Gallery", R.string.Gallery); - fs.subtitle = LocaleController.getString("GalleryInfo", R.string.GalleryInfo); - fs.icon = R.drawable.files_gallery; - fs.file = null; - items.add(fs); + if (!isSoundPicker) { + fs = new ListItem(); + fs.title = LocaleController.getString("Gallery", R.string.Gallery); + fs.subtitle = LocaleController.getString("GalleryInfo", R.string.GalleryInfo); + fs.icon = R.drawable.files_gallery; + fs.file = null; + items.add(fs); + } if (allowMusic) { fs = new ListItem(); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlertLocationLayout.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlertLocationLayout.java index aa8029b12..56476a43b 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlertLocationLayout.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlertLocationLayout.java @@ -265,11 +265,11 @@ public class ChatAttachAlertLocationLayout extends ChatAttachAlert.AttachAlertLa if (chatActivity.isInScheduleMode()) { AlertsCreator.createScheduleDatePickerDialog(getParentActivity(), chatActivity.getDialogId(), (notify, scheduleDate) -> { delegate.didSelectLocation(location.venue, locationType, notify, scheduleDate); - parentAlert.dismiss(); + parentAlert.dismiss(true); }, resourcesProvider); } else { delegate.didSelectLocation(location.venue, locationType, true, 0); - parentAlert.dismiss(); + parentAlert.dismiss(true); } }); @@ -759,11 +759,11 @@ public class ChatAttachAlertLocationLayout extends ChatAttachAlert.AttachAlertLa if (chatActivity.isInScheduleMode()) { AlertsCreator.createScheduleDatePickerDialog(getParentActivity(), chatActivity.getDialogId(), (notify, scheduleDate) -> { delegate.didSelectLocation(location, locationType, notify, scheduleDate); - parentAlert.dismiss(); + parentAlert.dismiss(true); }, resourcesProvider); } else { delegate.didSelectLocation(location, locationType, true, 0); - parentAlert.dismiss(); + parentAlert.dismiss(true); } } } else if (locationDenied) { @@ -772,7 +772,7 @@ public class ChatAttachAlertLocationLayout extends ChatAttachAlert.AttachAlertLa } else if (position == 2 && locationType == LOCATION_TYPE_SEND_WITH_LIVE) { if (getLocationController().isSharingLocation(dialogId)) { getLocationController().removeSharingLocation(dialogId); - parentAlert.dismiss(); + parentAlert.dismiss(true); } else { if (myLocation == null && locationDenied) { AlertsCreator.createLocationRequiredDialog(getParentActivity(), true).show(); @@ -786,11 +786,11 @@ public class ChatAttachAlertLocationLayout extends ChatAttachAlert.AttachAlertLa if (chatActivity.isInScheduleMode()) { AlertsCreator.createScheduleDatePickerDialog(getParentActivity(), chatActivity.getDialogId(), (notify, scheduleDate) -> { delegate.didSelectLocation((TLRPC.TL_messageMediaVenue) object, locationType, notify, scheduleDate); - parentAlert.dismiss(); + parentAlert.dismiss(true); }, resourcesProvider); } else { delegate.didSelectLocation((TLRPC.TL_messageMediaVenue) object, locationType, true, 0); - parentAlert.dismiss(); + parentAlert.dismiss(true); } } else if (object instanceof LiveLocation) { LiveLocation liveLocation = (LiveLocation) object; @@ -932,11 +932,11 @@ public class ChatAttachAlertLocationLayout extends ChatAttachAlert.AttachAlertLa if (chatActivity.isInScheduleMode()) { AlertsCreator.createScheduleDatePickerDialog(getParentActivity(), chatActivity.getDialogId(), (notify, scheduleDate) -> { delegate.didSelectLocation(object, locationType, notify, scheduleDate); - parentAlert.dismiss(); + parentAlert.dismiss(true); }, resourcesProvider); } else { delegate.didSelectLocation(object, locationType, true, 0); - parentAlert.dismiss(); + parentAlert.dismiss(true); } } }); @@ -1170,7 +1170,7 @@ public class ChatAttachAlertLocationLayout extends ChatAttachAlert.AttachAlertLa location.geo._long = AndroidUtilities.fixLocationCoord(myLocation.getLongitude()); location.period = param; delegate.didSelectLocation(location, locationType, true, 0); - parentAlert.dismiss(); + parentAlert.dismiss(true); }, resourcesProvider).show(); } 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 0c44f0e23..3e99d0c39 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlertPhotoLayout.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlertPhotoLayout.java @@ -34,6 +34,7 @@ import android.os.Build; import android.provider.MediaStore; import android.provider.Settings; import android.text.TextUtils; +import android.util.Log; import android.util.TypedValue; import android.view.Gravity; import android.view.KeyEvent; @@ -831,14 +832,6 @@ public class ChatAttachAlertPhotoLayout extends ChatAttachAlert.AttachAlertLayou flashModeButton[a].layout(cx3 - flashModeButton[a].getMeasuredWidth() / 2, cy3 - flashModeButton[a].getMeasuredHeight() / 2, cx3 + flashModeButton[a].getMeasuredWidth() / 2, cy3 + flashModeButton[a].getMeasuredHeight() / 2); } } - - @Override - public void setAlpha(float alpha) { - super.setAlpha(alpha); - if (parentAlert != null) { - parentAlert.setOverlayNavBarColor(ColorUtils.setAlphaComponent(Color.BLACK, (int) (alpha * 255))); - } - } }; cameraPanel.setVisibility(View.GONE); cameraPanel.setAlpha(0.0f); @@ -1472,7 +1465,7 @@ public class ChatAttachAlertPhotoLayout extends ChatAttachAlert.AttachAlertLayou selectedPhotos.clear(); adapter.notifyDataSetChanged(); cameraAttachAdapter.notifyDataSetChanged(); - parentAlert.dismiss(); + parentAlert.dismiss(true); } @Override @@ -1688,9 +1681,6 @@ public class ChatAttachAlertPhotoLayout extends ChatAttachAlert.AttachAlertLayou cameraView.setFpsLimit(-1); AndroidUtilities.hideKeyboard(this); AndroidUtilities.setLightNavigationBar(parentAlert.getWindow(), false); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - parentAlert.getWindow().setNavigationBarColor(0xff000000); - } if (animated) { setCameraOpenProgress(0); cameraAnimationInProgress = true; @@ -1793,9 +1783,6 @@ public class ChatAttachAlertPhotoLayout extends ChatAttachAlert.AttachAlertLayou cameraView.setFocusable(true); cameraView.setFpsLimit(30); if (Build.VERSION.SDK_INT >= 21) { - Path path = new Path(); - float[] radii = new float[8]; - cameraView.setOutlineProvider(new ViewOutlineProvider() { @Override public void getOutline(View view, Outline outline) { @@ -2085,6 +2072,7 @@ public class ChatAttachAlertPhotoLayout extends ChatAttachAlert.AttachAlertLayou AndroidUtilities.cancelRunOnUIThread(zoomControlHideRunnable); zoomControlHideRunnable = null; } + AndroidUtilities.setLightNavigationBar(parentAlert.getWindow(), AndroidUtilities.computePerceivedBrightness(getThemedColor(Theme.key_windowBackgroundGray)) > 0.721); if (animated) { additionCloseCameraY = cameraView.getTranslationY(); @@ -2186,7 +2174,7 @@ public class ChatAttachAlertPhotoLayout extends ChatAttachAlert.AttachAlertLayou float startHeight = animateCameraValues[2]; boolean isPortrait = AndroidUtilities.displaySize.x < AndroidUtilities.displaySize.y; float endWidth = parentAlert.getContainer().getWidth() - parentAlert.getLeftInset() - parentAlert.getRightInset(); - float endHeight = parentAlert.getContainer().getHeight() - parentAlert.getBottomInset(); + float endHeight = parentAlert.getContainer().getHeight(); float fromX = cameraViewLocation[0]; float fromY = cameraViewLocation[1]; @@ -2252,6 +2240,7 @@ public class ChatAttachAlertPhotoLayout extends ChatAttachAlert.AttachAlertLayou cameraIcon.setAlpha(0.0f); } + Log.i("caapl", "cameraViewH=" + cameraViewH + " (endHeight=" + endHeight + ") value=" + value); if (layoutParams.width != cameraViewW || layoutParams.height != cameraViewH) { layoutParams.width = cameraViewW; layoutParams.height = cameraViewH; @@ -2429,9 +2418,11 @@ public class ChatAttachAlertPhotoLayout extends ChatAttachAlert.AttachAlertLayou return selectedPhotosOrder; } - public void updateSelected(HashMap selectedPhotos, ArrayList photosOrder, boolean updateLayout) { - this.selectedPhotos = selectedPhotos; - this.selectedPhotosOrder = photosOrder; + public void updateSelected(HashMap newSelectedPhotos, ArrayList newPhotosOrder, boolean updateLayout) { + selectedPhotos.clear(); + selectedPhotos.putAll(newSelectedPhotos); + selectedPhotosOrder.clear(); + selectedPhotosOrder.addAll(newPhotosOrder); if (updateLayout) { updatePhotosCounter(false); updateCheckedPhotoIndices(); @@ -2543,7 +2534,7 @@ public class ChatAttachAlertPhotoLayout extends ChatAttachAlert.AttachAlertLayou parentAlert.baseFragment.startActivityForResult(photoPickerIntent, 1); } } - parentAlert.dismiss(); + parentAlert.dismiss(true); } catch (Exception e) { FileLog.e(e); } @@ -3081,7 +3072,7 @@ public class ChatAttachAlertPhotoLayout extends ChatAttachAlert.AttachAlertLayou return true; } else if (view == cameraView) { if (cameraOpened && !cameraAnimationInProgress) { - cameraView.measure(View.MeasureSpec.makeMeasureSpec(width, View.MeasureSpec.EXACTLY), View.MeasureSpec.makeMeasureSpec(height, View.MeasureSpec.EXACTLY)); + cameraView.measure(View.MeasureSpec.makeMeasureSpec(width, View.MeasureSpec.EXACTLY), View.MeasureSpec.makeMeasureSpec(height + parentAlert.getBottomInset(), View.MeasureSpec.EXACTLY)); return true; } } else if (view == cameraPanel) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlertPhotoLayoutPreview.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlertPhotoLayoutPreview.java index 6a931f79e..e44307268 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlertPhotoLayoutPreview.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlertPhotoLayoutPreview.java @@ -369,7 +369,8 @@ public class ChatAttachAlertPhotoLayoutPreview extends ChatAttachAlert.AttachAle MessageObject.GroupedMessagePosition position = new MessageObject.GroupedMessagePosition(); position.last = a == count - 1; - int w = photo.width, h = photo.height; + int w = photo.cropState != null ? photo.cropState.width : photo.width, + h = photo.cropState != null ? photo.cropState.height : photo.height; boolean rotate; if (photoRotate.containsKey(photo)) { rotate = photoRotate.get(photo); @@ -868,7 +869,7 @@ public class ChatAttachAlertPhotoLayoutPreview extends ChatAttachAlert.AttachAle paddingTop = Math.max(0, paddingTop); canvas.save(); canvas.clipRect(0, paddingTop, getWidth(), getHeight()); - chatBackgroundDrawable.setBounds(0, paddingTop, getWidth(), AndroidUtilities.displaySize.y); + chatBackgroundDrawable.setBounds(0, paddingTop, getWidth(), paddingTop + AndroidUtilities.displaySize.y); chatBackgroundDrawable.draw(canvas); restore = true; } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlertPollLayout.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlertPollLayout.java index 0336bc03e..756ff9073 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlertPollLayout.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlertPollLayout.java @@ -433,11 +433,11 @@ public class ChatAttachAlertPollLayout extends ChatAttachAlert.AttachAlertLayout if (chatActivity.isInScheduleMode()) { AlertsCreator.createScheduleDatePickerDialog(chatActivity.getParentActivity(), chatActivity.getDialogId(), (notify, scheduleDate) -> { delegate.sendPoll(poll, params, notify, scheduleDate); - parentAlert.dismiss(); + parentAlert.dismiss(true); }); } else { delegate.sendPoll(poll, params, true, 0); - parentAlert.dismiss(); + parentAlert.dismiss(true); } } } 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 9a2b8804a..6eb972fc0 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAvatarContainer.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAvatarContainer.java @@ -40,6 +40,7 @@ import org.telegram.messenger.UserObject; import org.telegram.tgnet.ConnectionsManager; import org.telegram.tgnet.TLRPC; import org.telegram.ui.ActionBar.ActionBar; +import org.telegram.ui.ActionBar.ActionBarPopupWindow; import org.telegram.ui.ActionBar.SimpleTextView; import org.telegram.ui.ActionBar.Theme; import org.telegram.ui.ChatActivity; @@ -70,6 +71,7 @@ public class ChatAvatarContainer extends FrameLayout implements NotificationCent private int currentConnectionState; private CharSequence lastSubtitle; private String lastSubtitleColorKey; + private Integer overrideSubtitleColor; private SharedMediaLayout.SharedMediaPreloader sharedMediaPreloader; private Theme.ResourcesProvider resourcesProvider; @@ -134,7 +136,7 @@ public class ChatAvatarContainer extends FrameLayout implements NotificationCent timeItem.setScaleY(0.0f); timeItem.setScaleX(0.0f); timeItem.setVisibility(GONE); - timeItem.setImageDrawable(timerDrawable = new TimerDrawable(context)); + timeItem.setImageDrawable(timerDrawable = new TimerDrawable(context, resourcesProvider)); addView(timeItem); secretChatTimer = needTime; @@ -170,6 +172,10 @@ public class ChatAvatarContainer extends FrameLayout implements NotificationCent } } + public void setOverrideSubtitleColor(Integer overrideSubtitleColor) { + this.overrideSubtitleColor = overrideSubtitleColor; + } + public boolean openSetTimer() { if (parentFragment.getParentActivity() == null) { return false; @@ -181,19 +187,60 @@ public class ChatAvatarContainer extends FrameLayout implements NotificationCent } return false; } - ClearHistoryAlert alert = new ClearHistoryAlert(parentFragment.getParentActivity(), parentFragment.getCurrentUser(), parentFragment.getCurrentChat(), false, null); - alert.setDelegate(new ClearHistoryAlert.ClearHistoryAlertDelegate() { + TLRPC.ChatFull chatInfo = parentFragment.getCurrentChatInfo(); + TLRPC.UserFull userInfo = parentFragment.getCurrentUserInfo(); + int ttl = 0; + if (userInfo != null) { + ttl = userInfo.ttl_period; + } else if (chatInfo != null) { + ttl = chatInfo.ttl_period; + } + + ActionBarPopupWindow[] scrimPopupWindow = new ActionBarPopupWindow[1]; + AutoDeletePopupWrapper autoDeletePopupWrapper = new AutoDeletePopupWrapper(getContext(), null, new AutoDeletePopupWrapper.Callback() { @Override - public void onAutoDeleteHistory(int ttl, int action) { - parentFragment.getMessagesController().setDialogHistoryTTL(parentFragment.getDialogId(), ttl); + public void dismiss() { + if (scrimPopupWindow[0] != null) { + scrimPopupWindow[0].dismiss(); + } + } + + @Override + public void setAutoDeleteHistory(int time, int action) { + if (parentFragment == null) { + return; + } + parentFragment.getMessagesController().setDialogHistoryTTL(parentFragment.getDialogId(), time); TLRPC.ChatFull chatInfo = parentFragment.getCurrentChatInfo(); TLRPC.UserFull userInfo = parentFragment.getCurrentUserInfo(); if (userInfo != null || chatInfo != null) { parentFragment.getUndoView().showWithAction(parentFragment.getDialogId(), action, parentFragment.getCurrentUser(), userInfo != null ? userInfo.ttl_period : chatInfo.ttl_period, null, null); } + } - }); - parentFragment.showDialog(alert); + }, true, resourcesProvider); + autoDeletePopupWrapper.updateItems(ttl); + + scrimPopupWindow[0] = new ActionBarPopupWindow(autoDeletePopupWrapper.windowLayout, LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT) { + @Override + public void dismiss() { + super.dismiss(); + if (parentFragment != null) { + parentFragment.dimBehindView(false); + } + } + }; + scrimPopupWindow[0].setPauseNotifications(true); + scrimPopupWindow[0].setDismissAnimationDuration(220); + scrimPopupWindow[0].setOutsideTouchable(true); + scrimPopupWindow[0].setClippingEnabled(true); + scrimPopupWindow[0].setAnimationStyle(R.style.PopupContextAnimation); + scrimPopupWindow[0].setFocusable(true); + autoDeletePopupWrapper.windowLayout.measure(View.MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(1000), View.MeasureSpec.AT_MOST), View.MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(1000), View.MeasureSpec.AT_MOST)); + scrimPopupWindow[0].setInputMethodMode(ActionBarPopupWindow.INPUT_METHOD_NOT_NEEDED); + scrimPopupWindow[0].getContentView().setFocusableInTouchMode(true); + scrimPopupWindow[0].showAtLocation(avatarImageView, 0, (int) (avatarImageView.getX() + getX()), (int) avatarImageView.getY()); + parentFragment.dimBehindView(true); return true; } @@ -289,7 +336,7 @@ public class ChatAvatarContainer extends FrameLayout implements NotificationCent } public void showTimeItem(boolean animated) { - if (timeItem == null || timeItem.getTag() != null) { + if (timeItem == null || timeItem.getTag() != null || avatarImageView.getVisibility() != View.VISIBLE) { return; } timeItem.clearAnimation(); @@ -326,14 +373,21 @@ public class ChatAvatarContainer extends FrameLayout implements NotificationCent } } - public void setTime(int value) { + public void setTime(int value, boolean animated) { if (timerDrawable == null) { return; } + boolean show = true; if (value == 0 && !secretChatTimer) { + show = false; return; } - timerDrawable.setTime(value); + if (show) { + showTimeItem(animated); + timerDrawable.setTime(value); + } else { + hideTimeItem(animated); + } } public void setTitleIcons(Drawable leftIcon, Drawable rightIcon) { @@ -601,8 +655,12 @@ public class ChatAvatarContainer extends FrameLayout implements NotificationCent lastSubtitleColorKey = useOnlineColor ? Theme.key_chat_status : Theme.key_actionBarDefaultSubtitle; if (lastSubtitle == null) { subtitleTextView.setText(newSubtitle); - subtitleTextView.setTextColor(getThemedColor(lastSubtitleColorKey)); - subtitleTextView.setTag(lastSubtitleColorKey); + if (overrideSubtitleColor == null) { + subtitleTextView.setTextColor(getThemedColor(lastSubtitleColorKey)); + subtitleTextView.setTag(lastSubtitleColorKey); + } else { + subtitleTextView.setTextColor(overrideSubtitleColor); + } } else { lastSubtitle = newSubtitle; } @@ -742,7 +800,9 @@ public class ChatAvatarContainer extends FrameLayout implements NotificationCent if (lastSubtitle != null) { subtitleTextView.setText(lastSubtitle); lastSubtitle = null; - if (lastSubtitleColorKey != null) { + if (overrideSubtitleColor != null) { + subtitleTextView.setTextColor(overrideSubtitleColor); + } else if (lastSubtitleColorKey != null) { subtitleTextView.setTextColor(getThemedColor(lastSubtitleColorKey)); subtitleTextView.setTag(lastSubtitleColorKey); } @@ -752,8 +812,12 @@ public class ChatAvatarContainer extends FrameLayout implements NotificationCent lastSubtitle = subtitleTextView.getText(); } subtitleTextView.setText(title); - subtitleTextView.setTextColor(getThemedColor(Theme.key_actionBarDefaultSubtitle)); - subtitleTextView.setTag(Theme.key_actionBarDefaultSubtitle); + if (overrideSubtitleColor != null) { + subtitleTextView.setTextColor(overrideSubtitleColor); + } else { + subtitleTextView.setTextColor(getThemedColor(Theme.key_actionBarDefaultSubtitle)); + subtitleTextView.setTag(Theme.key_actionBarDefaultSubtitle); + } } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatNotificationsPopupWrapper.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatNotificationsPopupWrapper.java new file mode 100644 index 000000000..ace816cb2 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatNotificationsPopupWrapper.java @@ -0,0 +1,233 @@ +package org.telegram.ui.Components; + +import android.content.Context; +import android.content.SharedPreferences; +import android.view.View; + +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.LocaleController; +import org.telegram.messenger.MessagesController; +import org.telegram.messenger.R; +import org.telegram.ui.ActionBar.ActionBarMenuItem; +import org.telegram.ui.ActionBar.ActionBarMenuSubItem; +import org.telegram.ui.ActionBar.ActionBarPopupWindow; +import org.telegram.ui.ActionBar.BaseFragment; +import org.telegram.ui.ActionBar.Theme; + +public class ChatNotificationsPopupWrapper { + + View backItem; + ActionBarMenuSubItem soundToggle; + ActionBarMenuSubItem muteUnmuteButton; + ActionBarMenuSubItem muteForLastSelected; + ActionBarMenuSubItem muteForLastSelected2; + public ActionBarPopupWindow.ActionBarPopupWindowLayout windowLayout; + int currentAccount; + ActionBarPopupWindow popupWindow; + Callback callback; + long lastDismissTime; + + private final static String LAST_SELECTED_TIME_KEY_1 = "last_selected_mute_until_time"; + private final static String LAST_SELECTED_TIME_KEY_2 = "last_selected_mute_until_time2"; + private final boolean isProfile; + private int muteForLastSelected2Time; + private int muteForLastSelected1Time; + + public ChatNotificationsPopupWrapper(Context context, int currentAccount, PopupSwipeBackLayout swipeBackLayout, boolean createBackground, boolean isProfile, Callback callback, Theme.ResourcesProvider resourcesProvider) { + this.currentAccount = currentAccount; + this.callback = callback; + this.isProfile = isProfile; + windowLayout = new ActionBarPopupWindow.ActionBarPopupWindowLayout(context, createBackground ? R.drawable.popup_fixed_alert : 0, resourcesProvider); + windowLayout.setFitItems(true); + + if (swipeBackLayout != null) { + backItem = ActionBarMenuItem.addItem(windowLayout, R.drawable.msg_arrow_back, LocaleController.getString("Back", R.string.Back), false, resourcesProvider); + backItem.setOnClickListener(view -> { + swipeBackLayout.closeForeground(); + }); + } + + + soundToggle = ActionBarMenuItem.addItem(windowLayout, R.drawable.msg_tone_on, LocaleController.getString("SoundOn", R.string.SoundOn), false, resourcesProvider); + soundToggle.setOnClickListener(view -> { + dismiss(); + callback.toggleSound(); + }); + + muteForLastSelected = ActionBarMenuItem.addItem(windowLayout, R.drawable.msg_mute_1h, LocaleController.getString("MuteFor1h", R.string.MuteFor1h), false, resourcesProvider); + muteForLastSelected.setOnClickListener(view -> { + dismiss(); + callback.muteFor(muteForLastSelected1Time); + }); + + muteForLastSelected2 = ActionBarMenuItem.addItem(windowLayout, R.drawable.msg_mute_1h, LocaleController.getString("MuteFor1h", R.string.MuteFor1h), false, resourcesProvider); + muteForLastSelected2.setOnClickListener(view -> { + dismiss(); + callback.muteFor(muteForLastSelected2Time); + }); + + ActionBarMenuSubItem item = ActionBarMenuItem.addItem(windowLayout, R.drawable.msg_mute_period, LocaleController.getString("MuteForPopup", R.string.MuteForPopup), false, resourcesProvider); + item.setOnClickListener(view -> { + dismiss(); + AlertsCreator.createMuteForPickerDialog(context, (notify, inMinutes) -> { + AndroidUtilities.runOnUIThread(() -> { + SharedPreferences sharedPreferences = MessagesController.getNotificationsSettings(currentAccount); + int time1 = sharedPreferences.getInt(LAST_SELECTED_TIME_KEY_1, 0); + int time2; + int timeInSeconds = inMinutes * 60; + time2 = time1; + time1 = timeInSeconds; + sharedPreferences.edit() + .putInt(LAST_SELECTED_TIME_KEY_1, time1) + .putInt(LAST_SELECTED_TIME_KEY_2, time2) + .apply(); + callback.muteFor(timeInSeconds); + }, 16); + }); + }); + + item = ActionBarMenuItem.addItem(windowLayout, R.drawable.msg_customize, LocaleController.getString("NotificationsCustomize", R.string.NotificationsCustomize), false, resourcesProvider); + item.setOnClickListener(view -> { + dismiss(); + callback.showCustomize(); + }); + + + muteUnmuteButton = ActionBarMenuItem.addItem(windowLayout, 0, "", false, resourcesProvider); + muteUnmuteButton.setOnClickListener(view -> { + dismiss(); + AndroidUtilities.runOnUIThread(() -> { + callback.toggleMute(); + }); + + }); + } + + private void dismiss() { + if (popupWindow != null) { + popupWindow.dismiss(); + popupWindow.dismiss(); + } + callback.dismiss(); + lastDismissTime = System.currentTimeMillis(); + } + + public void update(long dialogId) { + if (System.currentTimeMillis() - lastDismissTime < 200) { + AndroidUtilities.runOnUIThread(() -> { + update(dialogId); + }); + return; + } + boolean muted = MessagesController.getInstance(currentAccount).isDialogMuted(dialogId); + + int color; + if (muted) { + muteUnmuteButton.setTextAndIcon(LocaleController.getString("UnmuteNotifications", R.string.UnmuteNotifications), R.drawable.msg_unmute); + color = Theme.getColor(Theme.key_wallet_greenText); + soundToggle.setVisibility(View.GONE); + } else { + muteUnmuteButton.setTextAndIcon(LocaleController.getString("MuteNotifications", R.string.MuteNotifications), R.drawable.msg_mute); + color = Theme.getColor(Theme.key_dialogTextRed); + soundToggle.setVisibility(View.VISIBLE); + boolean soundOn = MessagesController.getInstance(currentAccount).isDialogNotificationsSoundEnabled(dialogId); + if (soundOn) { + soundToggle.setTextAndIcon(LocaleController.getString("SoundOff", R.string.SoundOff), R.drawable.msg_tone_off); + } else { + soundToggle.setTextAndIcon(LocaleController.getString("SoundOn", R.string.SoundOn), R.drawable.msg_tone_on); + } + } + + int time1; + int time2; + if (muted) { + time1 = 0; + time2 = 0; + } else { + SharedPreferences sharedPreferences = MessagesController.getNotificationsSettings(currentAccount); + time1 = sharedPreferences.getInt(LAST_SELECTED_TIME_KEY_1, 0); + time2 = sharedPreferences.getInt(LAST_SELECTED_TIME_KEY_2, 0); + } + if (time1 != 0) { + muteForLastSelected1Time = time1; + muteForLastSelected.setVisibility(View.VISIBLE); + muteForLastSelected.getImageView().setImageDrawable(TimerDrawable.getTtlIcon(time1)); + muteForLastSelected.setText(formatMuteForTime(time1)); + } else { + muteForLastSelected.setVisibility(View.GONE); + } + + if (time2 != 0) { + muteForLastSelected2Time = time2; + muteForLastSelected2.setVisibility(View.VISIBLE); + muteForLastSelected2.getImageView().setImageDrawable(TimerDrawable.getTtlIcon(time2)); + muteForLastSelected2.setText(formatMuteForTime(time2)); + } else { + muteForLastSelected2.setVisibility(View.GONE); + } + + + muteUnmuteButton.setColors(color, color); + + } + + private String formatMuteForTime(int time) { + StringBuilder stringBuilder = new StringBuilder(); + int days = time / (60 * 60 * 24); + time -= days * (60 * 60 * 24); + int hours = time / (60 * 60); + + if (days != 0) { + stringBuilder.append(days).append(LocaleController.getString("SecretChatTimerDays", R.string.SecretChatTimerDays)); + } + if (hours != 0) { + if (stringBuilder.length() > 0) { + stringBuilder.append(" "); + } + stringBuilder.append(hours).append(LocaleController.getString("SecretChatTimerHours", R.string.SecretChatTimerHours)); + } + return LocaleController.formatString("MuteForButton", R.string.MuteForButton, stringBuilder.toString()); + } + + public void showAsOptions(BaseFragment parentFragment, View anchorView, float touchedX, float touchedY) { + if (parentFragment == null || parentFragment.getFragmentView() == null) { + return; + } + popupWindow = new ActionBarPopupWindow(windowLayout, LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT); + popupWindow.setPauseNotifications(true); + popupWindow.setDismissAnimationDuration(220); + popupWindow.setOutsideTouchable(true); + popupWindow.setClippingEnabled(true); + popupWindow.setAnimationStyle(R.style.PopupContextAnimation); + popupWindow.setFocusable(true); + windowLayout.measure(View.MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(1000), View.MeasureSpec.AT_MOST), View.MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(1000), View.MeasureSpec.AT_MOST)); + popupWindow.setInputMethodMode(ActionBarPopupWindow.INPUT_METHOD_NOT_NEEDED); + popupWindow.getContentView().setFocusableInTouchMode(true); + + float x = touchedX, y = touchedY; + View view = anchorView; + while (view != parentFragment.getFragmentView()) { + x += view.getX(); + y += view.getY(); + view = (View) view.getParent(); + } + x -= windowLayout.getMeasuredWidth() / 2f; + y -= windowLayout.getMeasuredHeight() / 2f; + popupWindow.showAtLocation(parentFragment.getFragmentView(), 0, (int) x, (int) y); + popupWindow.dimBehind(); + // parentFragment.dimBehindView(true); + } + + public interface Callback { + void dismiss(); + + void toggleSound(); + + void muteFor(int timeInSecond); + + void showCustomize(); + + void toggleMute(); + } + +} 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 1b6a29e96..a6c78aa53 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatThemeBottomSheet.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatThemeBottomSheet.java @@ -65,6 +65,7 @@ import java.util.Objects; public class ChatThemeBottomSheet extends BottomSheet implements NotificationCenter.NotificationCenterDelegate { + private FrameLayout rootLayout; private final Adapter adapter; private final ChatActivity.ThemeDelegate themeDelegate; private final EmojiThemes originalTheme; @@ -100,8 +101,9 @@ public class ChatThemeBottomSheet extends BottomSheet implements NotificationCen setDimBehind(false); setCanDismissWithSwipe(false); setApplyBottomPadding(false); + drawNavigationBar = true; - FrameLayout rootLayout = new FrameLayout(getContext()); + rootLayout = new FrameLayout(getContext()); setCustomView(rootLayout); titleView = new TextView(getContext()); @@ -333,7 +335,7 @@ public class ChatThemeBottomSheet extends BottomSheet implements NotificationCen isAnimationStarted = true; } darkThemeDrawable.setColorFilter(new PorterDuffColorFilter(getThemedColor(Theme.key_featuredStickers_addButton), PorterDuff.Mode.MULTIPLY)); - setOverlayNavBarColor(getThemedColor(Theme.key_dialogBackground)); + setOverlayNavBarColor(getThemedColor(Theme.key_windowBackgroundGray)); if (isLightDarkChangeAnimation) { setItemsAnimationProgress(progress); } @@ -392,7 +394,6 @@ public class ChatThemeBottomSheet extends BottomSheet implements NotificationCen 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); @@ -413,10 +414,16 @@ public class ChatThemeBottomSheet extends BottomSheet implements NotificationCen 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; + AndroidUtilities.setLightNavigationBar(getWindow(), !isDark); + AndroidUtilities.setNavigationBarColor(getWindow(), getThemedColor(Theme.key_windowBackgroundGray)); + } } }); changeDayNightViewAnimator.addListener(new AnimatorListenerAdapter() { @@ -563,8 +570,6 @@ public class ChatThemeBottomSheet extends BottomSheet implements NotificationCen } private void setForceDark(boolean isDark, boolean playAnimation) { - useLightNavBar = isDark; - useLightStatusBar = isDark; if (forceDark == isDark) { return; } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/CircularProgressDrawable.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/CircularProgressDrawable.java new file mode 100644 index 000000000..dce400dc1 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/CircularProgressDrawable.java @@ -0,0 +1,96 @@ +package org.telegram.ui.Components; + +import android.graphics.Canvas; +import android.graphics.ColorFilter; +import android.graphics.Paint; +import android.graphics.PixelFormat; +import android.graphics.Rect; +import android.graphics.RectF; +import android.graphics.drawable.Drawable; +import android.os.SystemClock; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.interpolator.view.animation.FastOutSlowInInterpolator; + +import org.telegram.messenger.AndroidUtilities; + +public class CircularProgressDrawable extends Drawable { + + public CircularProgressDrawable() { + this(0xffffffff); + } + public CircularProgressDrawable(int color) { + setColor(color); + } + + private long start = -1; + private final FastOutSlowInInterpolator interpolator = new FastOutSlowInInterpolator(); + private float segmentFrom, segmentTo; + private void updateSegment() { + final float t = (SystemClock.elapsedRealtime() - start) % 5400f / 667f; + segmentFrom = + t * 187.748148f + 250 * ( + interpolator.getInterpolation(t - 1f) + + interpolator.getInterpolation(t - 3.024f) + + interpolator.getInterpolation(t - 5.048f) + + interpolator.getInterpolation(t - 7.072f) + ) - 20; + segmentTo = + t * 187.748148f + 250 * ( + interpolator.getInterpolation(t) + + interpolator.getInterpolation(t - 2.024f) + + interpolator.getInterpolation(t - 4.048f) + + interpolator.getInterpolation(t - 6.072f) + ); + } + + private final Paint paint = new Paint(); { + paint.setStyle(Paint.Style.STROKE); + } + + private final RectF bounds = new RectF(); + @Override + public void draw(@NonNull Canvas canvas) { + if (start < 0) { + start = SystemClock.elapsedRealtime(); + } + updateSegment(); + canvas.drawArc( + bounds, + segmentFrom, + segmentTo - segmentFrom, + false, + paint + ); + invalidateSelf(); + } + + @Override + public void setBounds(int left, int top, int right, int bottom) { + final float radius = AndroidUtilities.dp(9); + final float thickness = AndroidUtilities.dp(2.25f); + int width = right - left, height = bottom - top; + bounds.set( + left + (width - thickness / 2f) / 2f - radius, + top + (height - thickness / 2f) / 2f - radius, + left + (width + thickness / 2f) / 2f + radius, + top + (height + thickness / 2f) / 2f + radius + ); + super.setBounds(left, top, right, bottom); + paint.setStrokeWidth(thickness); + } + + public void setColor(int color) { + paint.setColor(color); + } + + @Override + public void setAlpha(int i) {} + @Override + public void setColorFilter(@Nullable ColorFilter colorFilter) {} + @Override + public int getOpacity() { + return PixelFormat.TRANSPARENT; + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Crop/CropTransform.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Crop/CropTransform.java index 71c382192..2f5235fff 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Crop/CropTransform.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Crop/CropTransform.java @@ -8,6 +8,8 @@ package org.telegram.ui.Components.Crop; +import androidx.annotation.NonNull; + public class CropTransform { private boolean hasTransform; @@ -24,6 +26,10 @@ public class CropTransform { private float trueCropScale; private float minScale; + public void setViewTransform(boolean set) { + hasTransform = set; + } + public void setViewTransform(boolean set, float px, float py, float rotate, int orientation, float scale, float cs, float ms, float pw, float ph, float cx, float cy, boolean mirrored) { hasTransform = set; cropPx = px; @@ -97,4 +103,23 @@ public class CropTransform { public boolean isMirrored () { return isMirrored; } + + @Override + public CropTransform clone() { + CropTransform cloned = new CropTransform(); + cloned.hasTransform = this.hasTransform; + cloned.cropPx = this.cropPx; + cloned.cropPy = this.cropPy; + cloned.cropAreaX = this.cropAreaX; + cloned.cropAreaY = this.cropAreaY; + cloned.cropScale = this.cropScale; + cloned.cropRotation = this.cropRotation; + cloned.isMirrored = this.isMirrored; + cloned.cropOrientation = this.cropOrientation; + cloned.cropPw = this.cropPw; + cloned.cropPh = this.cropPh; + cloned.trueCropScale = this.trueCropScale; + cloned.minScale = this.minScale; + return cloned; + } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/CrossfadeDrawable.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/CrossfadeDrawable.java index f4929a149..23fe1433b 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/CrossfadeDrawable.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/CrossfadeDrawable.java @@ -6,6 +6,8 @@ import android.graphics.PixelFormat; import android.graphics.Rect; import android.graphics.drawable.Drawable; +import androidx.annotation.NonNull; + public class CrossfadeDrawable extends Drawable { private final Drawable topDrawable; @@ -16,6 +18,35 @@ public class CrossfadeDrawable extends Drawable { public CrossfadeDrawable(Drawable topDrawable, Drawable bottomDrawable) { this.topDrawable = topDrawable; this.bottomDrawable = bottomDrawable; + + if (topDrawable != null) { + topDrawable.setCallback(new Callback() { + @Override + public void invalidateDrawable(@NonNull Drawable drawable) { + if (progress < 1.0f) { + CrossfadeDrawable.this.invalidateSelf(); + } + } + @Override + public void scheduleDrawable(@NonNull Drawable drawable, @NonNull Runnable runnable, long l) {} + @Override + public void unscheduleDrawable(@NonNull Drawable drawable, @NonNull Runnable runnable) {} + }); + } + if (bottomDrawable != null) { + bottomDrawable.setCallback(new Callback() { + @Override + public void invalidateDrawable(@NonNull Drawable drawable) { + if (progress > 0.0f) { + CrossfadeDrawable.this.invalidateSelf(); + } + } + @Override + public void scheduleDrawable(@NonNull Drawable drawable, @NonNull Runnable runnable, long l) {} + @Override + public void unscheduleDrawable(@NonNull Drawable drawable, @NonNull Runnable runnable) {} + }); + } } @Override diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/EmbedBottomSheet.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/EmbedBottomSheet.java index df5289576..4c5b9a6dc 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/EmbedBottomSheet.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/EmbedBottomSheet.java @@ -66,6 +66,7 @@ import org.telegram.ui.PhotoViewer; import java.util.HashMap; import java.util.Locale; +@SuppressLint("WrongConstant") public class EmbedBottomSheet extends BottomSheet { private WebView webView; @@ -76,7 +77,6 @@ public class EmbedBottomSheet extends BottomSheet { private View progressBarBlackBackground; private RadialProgressView progressBar; private Activity parentActivity; - private PipVideoView pipVideoView; private LinearLayout imageButtonsContainer; private TextView copyTextButton; private FrameLayout containerLayout; @@ -204,7 +204,7 @@ public class EmbedBottomSheet extends BottomSheet { private OnShowListener onShowListener = new OnShowListener() { @Override public void onShow(DialogInterface dialog) { - if (pipVideoView != null && videoView.isInline()) { + if (PipVideoOverlay.isVisible() && videoView.isInline()) { videoView.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() { @Override public boolean onPreDraw() { @@ -275,14 +275,14 @@ public class EmbedBottomSheet extends BottomSheet { protected void onDetachedFromWindow() { super.onDetachedFromWindow(); try { - if ((pipVideoView == null || webView.getVisibility() != VISIBLE) && webView.getParent() != null) { + if ((!PipVideoOverlay.isVisible() || webView.getVisibility() != VISIBLE) && webView.getParent() != null) { removeView(webView); webView.stopLoading(); webView.loadUrl("about:blank"); webView.destroy(); } - if (!videoView.isInline() && pipVideoView == null) { + if (!videoView.isInline() && !PipVideoOverlay.isVisible()) { if (instance == EmbedBottomSheet.this) { instance = null; } @@ -340,7 +340,7 @@ public class EmbedBottomSheet extends BottomSheet { @Override public void onShowCustomView(View view, CustomViewCallback callback) { - if (customView != null || pipVideoView != null) { + if (customView != null || PipVideoOverlay.isVisible()) { callback.onCustomViewHidden(); return; } @@ -496,12 +496,12 @@ public class EmbedBottomSheet extends BottomSheet { } setOnShowListener(null); - if (animated) { + if (animated && PipVideoOverlay.IS_TRANSITION_ANIMATION_SUPPORTED) { TextureView textureView = videoView.getTextureView(); View controlsView = videoView.getControlsView(); ImageView textureImageView = videoView.getTextureImageView(); - Rect rect = PipVideoView.getPipRect(aspectRatio); + Rect rect = PipVideoOverlay.getPipRect(true, aspectRatio); float scale = rect.width / textureView.getWidth(); @@ -550,9 +550,9 @@ public class EmbedBottomSheet extends BottomSheet { } } - if (animated) { + if (animated && PipVideoOverlay.IS_TRANSITION_ANIMATION_SUPPORTED) { setOnShowListener(onShowListener); - Rect rect = PipVideoView.getPipRect(aspectRatio); + Rect rect = PipVideoOverlay.getPipRect(false, aspectRatio); TextureView textureView = videoView.getTextureView(); ImageView textureImageView = videoView.getTextureImageView(); @@ -566,8 +566,7 @@ public class EmbedBottomSheet extends BottomSheet { textureView.setTranslationX(rect.x); textureView.setTranslationY(rect.y); } else { - pipVideoView.close(); - pipVideoView = null; + PipVideoOverlay.dismiss(); } setShowWithoutAnimation(true); show(); @@ -580,11 +579,16 @@ public class EmbedBottomSheet extends BottomSheet { } @Override - public TextureView onSwitchInlineMode(View controlsView, boolean inline, float aspectRatio, int rotation, boolean animated) { + public TextureView onSwitchInlineMode(View controlsView, boolean inline, int videoWidth, int videoHeight, int rotation, boolean animated) { if (inline) { controlsView.setTranslationY(0); - pipVideoView = new PipVideoView(false); - return pipVideoView.show(parentActivity, EmbedBottomSheet.this, controlsView, aspectRatio, rotation, null); + + TextureView textureView = new TextureView(parentActivity); + if (PipVideoOverlay.show(false, parentActivity, textureView, videoWidth, videoHeight)) { + PipVideoOverlay.setParentSheet(EmbedBottomSheet.this); + return textureView; + } + return null; } if (animated) { @@ -733,6 +737,12 @@ public class EmbedBottomSheet extends BottomSheet { pipButton.setBackgroundDrawable(Theme.createSelectorDrawable(Theme.getColor(Theme.key_dialogButtonSelector), 0)); imageButtonsContainer.addView(pipButton, LayoutHelper.createFrame(48, 48, Gravity.TOP | Gravity.LEFT, 0, 0, 4, 0)); pipButton.setOnClickListener(v -> { + if (PipVideoOverlay.isVisible()) { + PipVideoOverlay.dismiss(); + AndroidUtilities.runOnUIThread(v::callOnClick, 300); + return; + } + boolean inAppOnly = isYouTube && "inapp".equals(MessagesController.getInstance(currentAccount).youtubePipType); if (!inAppOnly && !checkInlinePermissions()) { return; @@ -741,12 +751,14 @@ public class EmbedBottomSheet extends BottomSheet { return; } boolean animated = false; - pipVideoView = new PipVideoView(inAppOnly); - pipVideoView.show(parentActivity, EmbedBottomSheet.this, null, width != 0 && height != 0 ? width / (float) height : 1.0f, 0, webView); + if (PipVideoOverlay.show(inAppOnly, parentActivity, webView, width, height)) { + PipVideoOverlay.setParentSheet(EmbedBottomSheet.this); + } + if (isYouTube) { runJsCode("hideControls();"); } - if (animated) { + if (animated && PipVideoOverlay.IS_TRANSITION_ANIMATION_SUPPORTED) { animationInProgress = true; View view = videoView.getAspectRatioView(); @@ -1011,9 +1023,6 @@ public class EmbedBottomSheet extends BottomSheet { } } } - if (pipVideoView != null) { - pipVideoView.onConfigurationChanged(); - } } public void destroy() { @@ -1023,10 +1032,7 @@ public class EmbedBottomSheet extends BottomSheet { webView.loadUrl("about:blank"); webView.destroy(); } - if (pipVideoView != null) { - pipVideoView.close(); - pipVideoView = null; - } + PipVideoOverlay.dismiss(); if (videoView != null) { videoView.destroy(); } @@ -1044,7 +1050,7 @@ public class EmbedBottomSheet extends BottomSheet { } public void exitFromPip() { - if (webView == null || pipVideoView == null) { + if (webView == null || !PipVideoOverlay.isVisible()) { return; } if (ApplicationLoader.mainInterfacePaused) { @@ -1064,8 +1070,7 @@ public class EmbedBottomSheet extends BottomSheet { containerLayout.addView(webView, 0, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.TOP | Gravity.LEFT, 0, 0, 0, 48 + 36 + (hasDescription ? 22 : 0))); setShowWithoutAnimation(true); show(); - pipVideoView.close(); - pipVideoView = null; + PipVideoOverlay.dismiss(true); } public static EmbedBottomSheet getInstance() { @@ -1135,8 +1140,7 @@ public class EmbedBottomSheet extends BottomSheet { waitingForDraw--; if (waitingForDraw == 0) { videoView.updateTextureImageView(); - pipVideoView.close(); - pipVideoView = null; + PipVideoOverlay.dismiss(); } else { container.invalidate(); } 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 fb091dc0f..60a46803d 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/EmojiView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/EmojiView.java @@ -448,9 +448,15 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific @Override public void setEnabled(boolean enabled) { super.setEnabled(enabled); - stickersSearchField.searchEditText.setEnabled(enabled); - gifSearchField.searchEditText.setEnabled(enabled); - emojiSearchField.searchEditText.setEnabled(enabled); + if (stickersSearchField != null) { + stickersSearchField.searchEditText.setEnabled(enabled); + } + if (gifSearchField != null) { + gifSearchField.searchEditText.setEnabled(enabled); + } + if (emojiSearchField != null) { + emojiSearchField.searchEditText.setEnabled(enabled); + } } private class SearchField extends FrameLayout { 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 e534cc65b..635856964 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/FilterTabsView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/FilterTabsView.java @@ -855,7 +855,8 @@ public class FilterTabsView extends FrameLayout { }; itemAnimator.setDelayAnimations(false); listView.setItemAnimator(itemAnimator); - listView.setSelectorType(7); + listView.setSelectorType(8); + listView.setSelectorRadius(6); listView.setSelectorDrawableColor(Theme.getColor(selectorColorKey)); listView.setLayoutManager(layoutManager = new LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/ForwardingPreviewView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/ForwardingPreviewView.java index de2c40e00..3fc21b44c 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ForwardingPreviewView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ForwardingPreviewView.java @@ -47,6 +47,12 @@ import java.util.ArrayList; public class ForwardingPreviewView extends FrameLayout { + TLRPC.Peer sendAsPeer; + public void setSendAsPeer(TLRPC.Peer defPeer) { + sendAsPeer = defPeer; + updateMessages(); + } + public interface ResourcesDelegate extends Theme.ResourcesProvider { Drawable getWallpaperDrawable(); @@ -108,7 +114,7 @@ public class ForwardingPreviewView extends FrameLayout { private final ResourcesDelegate resourcesProvider; @SuppressLint("ClickableViewAccessibility") - public ForwardingPreviewView(@NonNull Context context, ForwardingMessagesParams params, TLRPC.User user, TLRPC.Chat chat, int currentAccount, ResourcesDelegate resourcesProvider) { + public ForwardingPreviewView(@NonNull Context context, ForwardingMessagesParams params, TLRPC.User user, TLRPC.Chat chat, int currentAccount, ResourcesDelegate resourcesProvider) { super(context); this.currentAccount = currentAccount; currentUser = user; @@ -168,7 +174,7 @@ public class ForwardingPreviewView extends FrameLayout { if ((cell.getCurrentPosition() != null && cell.getCurrentPosition().last) || cell.getTransitionParams().animateBackgroundBoundsInner) { cell.drawTime(canvas, 1f, true); } - if ((cell.getCurrentPosition() != null && cell.getCurrentPosition().last) || cell.getCurrentPosition() == null) { + if (cell.getCurrentPosition() == null || (cell.getCurrentPosition().last || cell.getCurrentMessagesGroup().isDocuments)) { cell.drawCaptionLayout(canvas, false, 1f); } cell.getTransitionParams().recordDrawingStatePreview(); @@ -779,10 +785,13 @@ public class ForwardingPreviewView extends FrameLayout { for (int i = 0; i < forwardingMessagesParams.previewMessages.size(); i++) { MessageObject messageObject = forwardingMessagesParams.previewMessages.get(i); messageObject.forceUpdate = true; + messageObject.sendAsPeer = sendAsPeer; if (!forwardingMessagesParams.hideForwardSendersName) { messageObject.messageOwner.flags |= TLRPC.MESSAGE_FLAG_FWD; + messageObject.hideSendersName = false; } else { messageObject.messageOwner.flags &= ~TLRPC.MESSAGE_FLAG_FWD; + messageObject.hideSendersName = true; } if (forwardingMessagesParams.hideCaption) { messageObject.caption = null; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/FragmentContextView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/FragmentContextView.java index 520343a92..d3a1a275d 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/FragmentContextView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/FragmentContextView.java @@ -389,9 +389,12 @@ public class FragmentContextView extends FrameLayout implements NotificationCent public void draw(Canvas canvas) { super.draw(canvas); - AndroidUtilities.rectTmp.set(0, 0, getWidth(), getHeight()); - joinButtonFlicker.draw(canvas, AndroidUtilities.rectTmp, AndroidUtilities.dp(4)); - invalidate(); + final int halfOutlineWidth = AndroidUtilities.dp(1); + AndroidUtilities.rectTmp.set(halfOutlineWidth, halfOutlineWidth, getWidth() - halfOutlineWidth, getHeight() - halfOutlineWidth); + joinButtonFlicker.draw(canvas, AndroidUtilities.rectTmp, AndroidUtilities.dp(16)); + if (joinButtonFlicker.getProgress() < 1f && !joinButtonFlicker.repeatEnabled) { + invalidate(); + } } @Override @@ -403,7 +406,7 @@ public class FragmentContextView extends FrameLayout implements NotificationCent }; joinButton.setText(LocaleController.getString("VoipChatJoin", R.string.VoipChatJoin)); joinButton.setTextColor(getThemedColor(Theme.key_featuredStickers_buttonText)); - joinButton.setBackground(Theme.createSimpleSelectorRoundRectDrawable(AndroidUtilities.dp(4), getThemedColor(Theme.key_featuredStickers_addButton), getThemedColor(Theme.key_featuredStickers_addButtonPressed))); + joinButton.setBackground(Theme.createSimpleSelectorRoundRectDrawable(AndroidUtilities.dp(16), getThemedColor(Theme.key_featuredStickers_addButton), getThemedColor(Theme.key_featuredStickers_addButtonPressed))); joinButton.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); joinButton.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); joinButton.setGravity(Gravity.CENTER); @@ -1999,7 +2002,10 @@ public class FragmentContextView extends FrameLayout implements NotificationCent private void startJoinFlickerAnimation() { if (joinButtonFlicker.getProgress() > 1) { - AndroidUtilities.runOnUIThread(()-> joinButtonFlicker.setProgress(0), 150); + AndroidUtilities.runOnUIThread(() -> { + joinButtonFlicker.setProgress(0); + joinButton.invalidate(); + }, 150); } } 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 13ceb10ea..f4af0f052 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/InstantCameraView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/InstantCameraView.java @@ -29,6 +29,7 @@ import android.graphics.PorterDuff; import android.graphics.PorterDuffXfermode; import android.graphics.RectF; import android.graphics.SurfaceTexture; +import android.graphics.drawable.AnimatedVectorDrawable; import android.media.AudioFormat; import android.media.AudioRecord; import android.media.MediaCodec; @@ -58,6 +59,7 @@ import android.view.animation.DecelerateInterpolator; import android.widget.FrameLayout; import android.widget.ImageView; +import androidx.core.content.ContextCompat; import androidx.core.graphics.ColorUtils; import com.google.android.exoplayer2.ExoPlayer; @@ -118,6 +120,7 @@ public class InstantCameraView extends FrameLayout implements NotificationCenter private Paint paint; private RectF rect; private ImageView switchCameraButton; + AnimatedVectorDrawable switchCameraDrawable = null; private ImageView muteImageView; private float progress; private CameraInfo selectedCamera; @@ -204,6 +207,7 @@ public class InstantCameraView extends FrameLayout implements NotificationCenter private FloatBuffer textureBuffer; private float scaleX; private float scaleY; + private boolean flipAnimationInProgress; private View parentView; public boolean opened; @@ -305,7 +309,7 @@ public class InstantCameraView extends FrameLayout implements NotificationCenter cameraContainer.setLayerType(View.LAYER_TYPE_HARDWARE, null); } - addView(cameraContainer, new FrameLayout.LayoutParams(AndroidUtilities.roundPlayingMessageSize, AndroidUtilities.roundPlayingMessageSize, Gravity.CENTER)); + addView(cameraContainer, new LayoutParams(AndroidUtilities.roundPlayingMessageSize, AndroidUtilities.roundPlayingMessageSize, Gravity.CENTER)); switchCameraButton = new ImageView(context); switchCameraButton.setScaleType(ImageView.ScaleType.CENTER); @@ -316,15 +320,42 @@ public class InstantCameraView extends FrameLayout implements NotificationCenter return; } switchCamera(); - ObjectAnimator animator = ObjectAnimator.ofFloat(switchCameraButton, View.SCALE_X, 0.0f).setDuration(100); - animator.addListener(new AnimatorListenerAdapter() { + if (switchCameraDrawable != null) { + switchCameraDrawable.start(); + } + flipAnimationInProgress = true; + ValueAnimator valueAnimator = ValueAnimator.ofFloat(0, 1f); + valueAnimator.setDuration(300); + valueAnimator.setInterpolator(CubicBezierInterpolator.DEFAULT); + valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override - public void onAnimationEnd(Animator animator) { - switchCameraButton.setImageResource(isFrontface ? R.drawable.camera_revert1 : R.drawable.camera_revert2); - ObjectAnimator.ofFloat(switchCameraButton, View.SCALE_X, 1.0f).setDuration(100).start(); + public void onAnimationUpdate(ValueAnimator valueAnimator) { + float p = (float) valueAnimator.getAnimatedValue(); + if (p < 0.5f) { + p = (1f - p / 0.5f); + } else { + p = (p - 0.5f) / 0.5f; + } + float scaleDown = 0.9f + 0.1f * p; + cameraContainer.setScaleX(p * scaleDown); + cameraContainer.setScaleY(scaleDown); + textureOverlayView.setScaleX(p * scaleDown); + textureOverlayView.setScaleY(scaleDown); } }); - animator.start(); + valueAnimator.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + super.onAnimationEnd(animation); + cameraContainer.setScaleX(1f); + cameraContainer.setScaleY(1f); + textureOverlayView.setScaleY(1f); + textureOverlayView.setScaleX(1f); + flipAnimationInProgress = false; + invalidate(); + } + }); + valueAnimator.start(); }); muteImageView = new ImageView(context); @@ -353,10 +384,10 @@ public class InstantCameraView extends FrameLayout implements NotificationCenter } } }; - addView(textureOverlayView, new FrameLayout.LayoutParams(AndroidUtilities.roundPlayingMessageSize, AndroidUtilities.roundPlayingMessageSize, Gravity.CENTER)); + addView(textureOverlayView, new LayoutParams(AndroidUtilities.roundPlayingMessageSize, AndroidUtilities.roundPlayingMessageSize, Gravity.CENTER)); setVisibility(INVISIBLE); - blurBehindDrawable = new BlurBehindDrawable(parentView, this, 0, null); + blurBehindDrawable = new BlurBehindDrawable(parentView, this, 0, resourcesProvider); } @Override @@ -463,7 +494,9 @@ public class InstantCameraView extends FrameLayout implements NotificationCenter if (progress != 0) { canvas.save(); - canvas.scale(cameraContainer.getScaleX(), cameraContainer.getScaleY(), rect.centerX(), rect.centerY()); + if (!flipAnimationInProgress) { + canvas.scale(cameraContainer.getScaleX(), cameraContainer.getScaleY(), rect.centerX(), rect.centerY()); + } canvas.drawArc(rect, -90, 360 * progress, false, paint); canvas.restore(); } @@ -521,7 +554,15 @@ public class InstantCameraView extends FrameLayout implements NotificationCenter return; } - switchCameraButton.setImageResource(R.drawable.camera_revert1); + + + if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) { + switchCameraDrawable = (AnimatedVectorDrawable) ContextCompat.getDrawable(getContext(), R.drawable.avd_flip); + switchCameraButton.setImageDrawable(switchCameraDrawable); + } else { + switchCameraButton.setImageResource(R.drawable.vd_flip); + } + textureOverlayView.setAlpha(1.0f); textureOverlayView.invalidate(); if (lastBitmap == null) { @@ -1958,7 +1999,7 @@ public class InstantCameraView extends FrameLayout implements NotificationCenter } private void createKeyframeThumb() { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && SharedConfig.getDevicePerformanceClass() != SharedConfig.PERFORMANCE_CLASS_LOW && frameCount % 33 == 0) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && SharedConfig.getDevicePerformanceClass() == SharedConfig.PERFORMANCE_CLASS_HIGH && frameCount % 33 == 0) { GenerateKeyframeThumbTask task = new GenerateKeyframeThumbTask(); generateKeyframeThumbsQueue.postRunnable(task); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/LinkPath.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/LinkPath.java index 6110e7e95..7bb73610b 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/LinkPath.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/LinkPath.java @@ -29,9 +29,18 @@ public class LinkPath extends Path { private int baselineShift; private int lineHeight; - private static final int radius = AndroidUtilities.dp(4); - private static final int halfRadius = radius >> 1; - public static final CornerPathEffect roundedEffect = new CornerPathEffect(radius); + public static int getRadius() { + return AndroidUtilities.dp(4); + } + + private static CornerPathEffect roundedEffect; + private static int roundedEffectRadius; + public static CornerPathEffect getRoundedEffect() { + if (roundedEffect == null || roundedEffectRadius != getRadius()) { + roundedEffect = new CornerPathEffect(roundedEffectRadius = getRadius()); + } + return roundedEffect; + } public LinkPath() { super(); @@ -108,7 +117,7 @@ public class LinkPath extends Path { y += baselineShift; } if (useRoundRect) { - super.addRect(left - halfRadius, y, right + halfRadius, y2, dir); + super.addRect(left - getRadius() / 2f, y, right + getRadius() / 2f, y2, dir); } else { super.addRect(left, y, right, y2, dir); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/LinkSpanDrawable.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/LinkSpanDrawable.java new file mode 100644 index 000000000..8ea4a6375 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/LinkSpanDrawable.java @@ -0,0 +1,364 @@ +package org.telegram.ui.Components; + +import android.graphics.Canvas; +import android.graphics.CornerPathEffect; +import android.graphics.Paint; +import android.graphics.Path; +import android.graphics.Rect; +import android.graphics.Region; +import android.os.Build; +import android.os.SystemClock; +import android.text.style.CharacterStyle; +import android.util.Log; +import android.util.Pair; +import android.view.View; +import android.view.ViewConfiguration; + +import org.telegram.messenger.AndroidUtilities; +import org.telegram.ui.ActionBar.Theme; +import org.telegram.ui.ArticleViewer; + +import java.util.ArrayList; + +public class LinkSpanDrawable { + + private int cornerRadius; + private int color; + private Paint mSelectionPaint, mRipplePaint; + private int mSelectionAlpha, mRippleAlpha; + + private static final ArrayList pathCache = new ArrayList<>(); + private final ArrayList mPathes = new ArrayList<>(); + private int mPathesCount = 0; + + private final S mSpan; + private final Theme.ResourcesProvider mResourcesProvider; + private final float mTouchX; + private final float mTouchY; + private final Path circlePath = new Path(); + + private Rect mBounds; + private float mMaxRadius; + private long mStart = -1; + private long mReleaseStart = -1; + private final long mDuration; + private final long mLongPressDuration; + private final boolean mSupportsLongPress; + private static final long mReleaseDelay = 75; + private static final long mReleaseDuration = 100; + + private final float selectionAlpha = 0.2f; + private final float rippleAlpha = 0.8f; + + public LinkSpanDrawable(S span, Theme.ResourcesProvider resourcesProvider, float touchX, float touchY) { + this(span, resourcesProvider, touchX, touchY, true); + } + + public LinkSpanDrawable(S span, Theme.ResourcesProvider resourcesProvider, float touchX, float touchY, boolean supportsLongPress) { + mSpan = span; + mResourcesProvider = resourcesProvider; + setColor(getThemedColor(Theme.key_chat_linkSelectBackground)); + mTouchX = touchX; + mTouchY = touchY; + final long tapTimeout = ViewConfiguration.getTapTimeout(); + mLongPressDuration = ViewConfiguration.getLongPressTimeout(); + mDuration = (long) Math.min(tapTimeout * 1.8f, mLongPressDuration * 0.8f); + mSupportsLongPress = false; + } + + public void setColor(int color) { + this.color = color; + if (mSelectionPaint != null) { + mSelectionPaint.setColor(color); + mSelectionAlpha = mSelectionPaint.getAlpha(); + } + if (mRipplePaint != null) { + mRipplePaint.setColor(color); + mRippleAlpha = mRipplePaint.getAlpha(); + } + } + + public void release() { + mReleaseStart = Math.max(mStart + mDuration, SystemClock.elapsedRealtime()); + } + + public LinkPath obtainNewPath() { + LinkPath linkPath; + if (!pathCache.isEmpty()) { + linkPath = pathCache.remove(0); + } else { + linkPath = new LinkPath(true); + } + linkPath.reset(); + mPathes.add(linkPath); + mPathesCount = mPathes.size(); + return linkPath; + } + + public void reset() { + if (mPathes.isEmpty()) { + return; + } + pathCache.addAll(mPathes); + mPathes.clear(); + mPathesCount = 0; + } + + public S getSpan() { + return mSpan; + } + + public boolean draw(Canvas canvas) { + boolean cornerRadiusUpdate = cornerRadius != AndroidUtilities.dp(4); + if (mSelectionPaint == null || cornerRadiusUpdate) { + mSelectionPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + mSelectionPaint.setStyle(Paint.Style.FILL_AND_STROKE); + mSelectionPaint.setColor(color); + mSelectionAlpha = mSelectionPaint.getAlpha(); + mSelectionPaint.setPathEffect(new CornerPathEffect(cornerRadius = AndroidUtilities.dp(4))); + } + if (mRipplePaint == null || cornerRadiusUpdate) { + mRipplePaint = new Paint(Paint.ANTI_ALIAS_FLAG); + mRipplePaint.setStyle(Paint.Style.FILL_AND_STROKE); + mRipplePaint.setColor(color); + mRippleAlpha = mRipplePaint.getAlpha(); + mRipplePaint.setPathEffect(new CornerPathEffect(cornerRadius = AndroidUtilities.dp(4))); + } + if (mBounds == null && mPathesCount > 0) { + mPathes.get(0).computeBounds(AndroidUtilities.rectTmp, false); + mBounds = new Rect( + (int) AndroidUtilities.rectTmp.left, + (int) AndroidUtilities.rectTmp.top, + (int) AndroidUtilities.rectTmp.right, + (int) AndroidUtilities.rectTmp.bottom + ); + for (int i = 1; i < mPathesCount; ++i) { + mPathes.get(i).computeBounds(AndroidUtilities.rectTmp, false); + mBounds.left = Math.min(mBounds.left, (int) AndroidUtilities.rectTmp.left); + mBounds.top = Math.min(mBounds.top, (int) AndroidUtilities.rectTmp.top); + mBounds.right = Math.max(mBounds.right, (int) AndroidUtilities.rectTmp.right); + mBounds.bottom = Math.max(mBounds.bottom, (int) AndroidUtilities.rectTmp.bottom); + } + mMaxRadius = (float) Math.sqrt( + Math.max( + Math.max( + Math.pow(mBounds.left - mTouchX, 2) + Math.pow(mBounds.top - mTouchY, 2), + Math.pow(mBounds.right - mTouchX, 2) + Math.pow(mBounds.top - mTouchY, 2) + ), + Math.max( + Math.pow(mBounds.left - mTouchX, 2) + Math.pow(mBounds.bottom - mTouchY, 2), + Math.pow(mBounds.right - mTouchX, 2) + Math.pow(mBounds.bottom - mTouchY, 2) + ) + ) + ); + } + + final long now = SystemClock.elapsedRealtime(); + if (mStart < 0) { + mStart = now; + } + float pressT = CubicBezierInterpolator.DEFAULT.getInterpolation(Math.min(1, (now - mStart) / (float) mDuration)), + releaseT = mReleaseStart < 0 ? 0 : Math.min(1, Math.max(0, (now - mReleaseDelay - mReleaseStart) / (float) mReleaseDuration)); + float longPress; + if (mSupportsLongPress) { + longPress = Math.max(0, (now - mStart - mDuration * 2) / (float) (mLongPressDuration - mDuration * 2)); + if (longPress > 1f) { + longPress = 1f - ((now - mStart - mLongPressDuration) / (float) mDuration); + } else { + longPress *= .5f; + } + longPress *= (1f - releaseT); + } else { + longPress = 1f; + } + + mSelectionPaint.setAlpha((int) (mSelectionAlpha * selectionAlpha * Math.min(1, pressT * 5f) * (1f - releaseT))); + mSelectionPaint.setStrokeWidth(Math.min(1, 1f - longPress) * AndroidUtilities.dp(5)); + for (int i = 0; i < mPathesCount; ++i) { + canvas.drawPath(mPathes.get(i), mSelectionPaint); + } + + mRipplePaint.setAlpha((int) (mRippleAlpha * rippleAlpha * (1f - releaseT))); + mRipplePaint.setStrokeWidth(Math.min(1, 1f - longPress) * AndroidUtilities.dp(5)); + if (pressT < 1f) { + float r = pressT * mMaxRadius; + canvas.save(); + circlePath.reset(); + circlePath.addCircle(mTouchX, mTouchY, r, Path.Direction.CW); + canvas.clipPath(circlePath); + for (int i = 0; i < mPathesCount; ++i) { + canvas.drawPath(mPathes.get(i), mRipplePaint); + } + canvas.restore(); + } else { + for (int i = 0; i < mPathesCount; ++i) { + canvas.drawPath(mPathes.get(i), mRipplePaint); + } + } + + return pressT < 1f || mReleaseStart >= 0 || (mSupportsLongPress && now - mStart < mLongPressDuration + mDuration); + } + + private int getThemedColor(String key) { + Integer color = mResourcesProvider != null ? mResourcesProvider.getColor(key) : null; + return color != null ? color : Theme.getColor(key); + } + + public static class LinkCollector { + + private View mParent; + + public LinkCollector() {} + public LinkCollector(View parentView) { + mParent = parentView; + } + + private ArrayList> mLinks = new ArrayList<>(); + private int mLinksCount = 0; + + public void addLink(LinkSpanDrawable link) { + addLink(link, null); + } + + public void addLink(LinkSpanDrawable link, Object obj) { + mLinks.add(new Pair<>(link, obj)); + mLinksCount++; + invalidate(obj); + } + + public void removeLink(LinkSpanDrawable link) { + removeLink(link, true); + } + + public void removeLink(LinkSpanDrawable link, boolean animated) { + if (link == null) { + return; + } + Pair pair = null; + for (int i = 0; i < mLinksCount; ++i) { + if (mLinks.get(i).first == link) { + pair = mLinks.get(i); + break; + } + } + if (pair == null) { + return; + } + if (animated) { + if (link.mReleaseStart < 0) { + link.release(); + invalidate(pair.second); + final long now = SystemClock.elapsedRealtime(); + AndroidUtilities.runOnUIThread( + () -> removeLink(link, false), + Math.max(0, (link.mReleaseStart - now) + mReleaseDelay + mReleaseDuration) + ); + } + } else { + mLinks.remove(pair); + link.reset(); + mLinksCount = mLinks.size(); + invalidate(pair.second); + } + } + + private void removeLink(int index, boolean animated) { + if (index < 0 || index >= mLinksCount) { + return; + } + if (animated) { + Pair pair = mLinks.get(index); + LinkSpanDrawable link = pair.first; + if (link.mReleaseStart < 0) { + link.release(); + invalidate(pair.second); + final long now = SystemClock.elapsedRealtime(); + AndroidUtilities.runOnUIThread( + () -> removeLink(link, false), + Math.max(0, (link.mReleaseStart - now) + mReleaseDelay + mReleaseDuration) + ); + } + } else { + Pair pair = mLinks.remove(index); + LinkSpanDrawable link = pair.first; + link.reset(); + mLinksCount = mLinks.size(); + invalidate(pair.second); + } + } + + public void clear() { + clear(true); + } + + public void clear(boolean animated) { + if (animated) { + for (int i = 0; i < mLinksCount; ++i) { + removeLink(i, true); + } + } else if (mLinksCount > 0) { + for (int i = 0; i < mLinksCount; ++i) { + mLinks.get(i).first.reset(); + invalidate(mLinks.get(i).second, false); + } + mLinks.clear(); + mLinksCount = 0; + invalidate(); + } + } + + public void removeLinks(Object obj) { + removeLinks(obj, true); + } + + public void removeLinks(Object obj, boolean animated) { + for (int i = 0; i < mLinksCount; ++i) { + if (mLinks.get(i).second == obj) { + removeLink(i, animated); + } + } + } + + public boolean draw(Canvas canvas) { + boolean invalidate = false; + for (int i = 0; i < mLinksCount; ++i) { + invalidate = mLinks.get(i).first.draw(canvas) || invalidate; + } + return invalidate; + } + + public boolean draw(Canvas canvas, Object obj) { + boolean invalidate = false; + for (int i = 0; i < mLinksCount; ++i) { + if (mLinks.get(i).second == obj) { + invalidate = mLinks.get(i).first.draw(canvas) || invalidate; + } + } + invalidate(obj, false); + return invalidate; + } + + public boolean isEmpty() { + return mLinksCount <= 0; + } + + private void invalidate() { + invalidate(null, true); + } + private void invalidate(Object obj) { + invalidate(obj, true); + } + private void invalidate(Object obj, boolean tryParent) { + if (obj instanceof View) { + ((View) obj).invalidate(); + } else if (obj instanceof ArticleViewer.DrawingText) { + ArticleViewer.DrawingText text = (ArticleViewer.DrawingText) obj; + if (text.latestParentView != null) { + text.latestParentView.invalidate(); + } + } else if (tryParent && mParent != null) { + mParent.invalidate(); + } + } + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/NumberPicker.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/NumberPicker.java index ed1fe3cf6..29f8077be 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/NumberPicker.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/NumberPicker.java @@ -39,12 +39,14 @@ import android.widget.LinearLayout; import android.widget.TextView; import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.Utilities; import org.telegram.ui.ActionBar.Theme; import java.util.Locale; public class NumberPicker extends LinearLayout { + public static final int DEFAULT_SIZE_PER_COUNT = 42; private int SELECTOR_WHEEL_ITEM_COUNT = 3; private static final long DEFAULT_LONG_PRESS_UPDATE_INTERVAL = 300; private int SELECTOR_MIDDLE_ITEM_INDEX = SELECTOR_WHEEL_ITEM_COUNT / 2; @@ -265,8 +267,8 @@ public class NumberPicker extends LinearLayout { if (changed) { initializeSelectorWheel(); initializeFadingEdges(); - mTopSelectionDividerTop = (getHeight() - mSelectionDividersDistance) / 2 - mSelectionDividerHeight; - mBottomSelectionDividerBottom = mTopSelectionDividerTop + 2 * mSelectionDividerHeight + mSelectionDividersDistance; + mTopSelectionDividerTop = (getHeight() - mTextSize - mSelectorTextGapHeight) / 2; + mBottomSelectionDividerBottom = (getHeight() + mTextSize + mSelectorTextGapHeight) / 2; } } @@ -517,7 +519,6 @@ public class NumberPicker extends LinearLayout { while (mCurrentScrollOffset - mInitialScrollOffset > mSelectorTextGapHeight) { mCurrentScrollOffset -= mSelectorElementHeight; decrementSelectorIndices(selectorIndices); - setValueInternal(selectorIndices[SELECTOR_MIDDLE_ITEM_INDEX], true); if (!mWrapSelectorWheel && selectorIndices[SELECTOR_MIDDLE_ITEM_INDEX] <= mMinValue && mCurrentScrollOffset > mInitialScrollOffset) { mCurrentScrollOffset = mInitialScrollOffset; } @@ -525,11 +526,11 @@ public class NumberPicker extends LinearLayout { while (mCurrentScrollOffset - mInitialScrollOffset < -mSelectorTextGapHeight) { mCurrentScrollOffset += mSelectorElementHeight; incrementSelectorIndices(selectorIndices); - setValueInternal(selectorIndices[SELECTOR_MIDDLE_ITEM_INDEX], true); if (!mWrapSelectorWheel && selectorIndices[SELECTOR_MIDDLE_ITEM_INDEX] >= mMaxValue && mCurrentScrollOffset < mInitialScrollOffset) { mCurrentScrollOffset = mInitialScrollOffset; } } + setValueInternal(selectorIndices[SELECTOR_MIDDLE_ITEM_INDEX], true); } @Override @@ -712,6 +713,7 @@ public class NumberPicker extends LinearLayout { removeAllCallbacks(); } + private final static CubicBezierInterpolator interpolator = new CubicBezierInterpolator(0, 0.5f, 0.5f, 1f); @Override protected void onDraw(Canvas canvas) { float x = (getRight() - getLeft()) / 2 + textOffset; @@ -728,7 +730,40 @@ public class NumberPicker extends LinearLayout { // IME he may see a dimmed version of the old value intermixed // with the new one. if (scrollSelectorValue != null && (i != SELECTOR_MIDDLE_ITEM_INDEX || mInputText.getVisibility() != VISIBLE)) { - canvas.drawText(scrollSelectorValue, x, y, mSelectorWheelPaint); + if (SELECTOR_WHEEL_ITEM_COUNT > 3) { + float p; + float cY = getMeasuredHeight() / 2f; + float r = getMeasuredHeight() * 0.5f; + float localY = y - mSelectorWheelPaint.getTextSize() / 2f; + boolean top = true; + if (localY < cY) { + p = localY / r; + } else { + p = (getMeasuredHeight() - localY) / r; + top = false; + } + p = interpolator.getInterpolation(Utilities.clamp(p, 1f, 0)); + float yOffset = (1f - p) * mSelectorWheelPaint.getTextSize(); + if (!top) { + yOffset = -yOffset; + } + int oldAlpha = -1; + + canvas.save(); + canvas.translate(0, yOffset); + canvas.scale(0.8f + p * 0.2f, p, x, localY); + if (p < 0.1f) { + oldAlpha = mSelectorWheelPaint.getAlpha(); + mSelectorWheelPaint.setAlpha((int) (oldAlpha * p / 0.1f)); + } + canvas.drawText(scrollSelectorValue, x, y, mSelectorWheelPaint); + canvas.restore(); + if (oldAlpha != -1) { + mSelectorWheelPaint.setAlpha(oldAlpha); + } + } else { + canvas.drawText(scrollSelectorValue, x, y, mSelectorWheelPaint); + } } y += mSelectorElementHeight; } @@ -846,7 +881,7 @@ public class NumberPicker extends LinearLayout { initializeSelectorWheelIndices(); int[] selectorIndices = mSelectorIndices; int totalTextHeight = selectorIndices.length * mTextSize; - float totalTextGapHeight = (getBottom() - getTop()) - totalTextHeight; + float totalTextGapHeight = (getBottom() - getTop() + mTextSize) - totalTextHeight; float textGapCount = selectorIndices.length; mSelectorTextGapHeight = (int) (totalTextGapHeight / textGapCount + 0.5f); mSelectorElementHeight = mTextSize + mSelectorTextGapHeight; 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 26f5df890..6c77ffa27 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 @@ -12,6 +12,7 @@ import org.telegram.messenger.FileLoader; import org.telegram.messenger.ImageLocation; import org.telegram.messenger.ImageReceiver; import org.telegram.tgnet.TLRPC; +import org.telegram.ui.Components.AnimatedFileDrawable; import org.telegram.ui.Components.LayoutHelper; import org.telegram.ui.Components.Point; import org.telegram.ui.Components.RLottieDrawable; @@ -144,11 +145,16 @@ public class StickerView extends EntityView { } public long getDuration() { - RLottieDrawable drawable = centerImage.getLottieAnimation(); - if (drawable == null) { - return 0; + RLottieDrawable rLottieDrawable = centerImage.getLottieAnimation(); + if (rLottieDrawable != null) { + return rLottieDrawable.getDuration(); } - return drawable.getDuration(); + AnimatedFileDrawable animatedFileDrawable = centerImage.getAnimation(); + if (animatedFileDrawable != null) { + return animatedFileDrawable.getDurationMs(); + } + return 0; + } @Override diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/PhotoPaintView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/PhotoPaintView.java index 511d65ed5..aec222dbd 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/PhotoPaintView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/PhotoPaintView.java @@ -485,8 +485,10 @@ public class PhotoPaintView extends FrameLayout implements EntityView.EntityView lcm = BigInteger.ONE; if (bitmap != null && entitiesView.entitiesCount() > 0) { Canvas canvas = null; + Canvas thumbCanvas = null; int count = entitiesView.getChildCount(); for (int i = 0; i < count; i++) { + boolean skipDrawToBitmap = false; View v = entitiesView.getChildAt(i); if (!(v instanceof EntityView)) { continue; @@ -517,13 +519,20 @@ public class PhotoPaintView extends FrameLayout implements EntityView.EntityView mediaEntity.parentObject = stickerView.getParentObject(); TLRPC.Document document = stickerView.getSticker(); mediaEntity.text = FileLoader.getPathToAttach(document, true).getAbsolutePath(); - if (MessageObject.isAnimatedStickerDocument(document, true)) { - mediaEntity.subType |= 1; - long duration = stickerView.getDuration(); + if (MessageObject.isAnimatedStickerDocument(document, true) || MessageObject.isVideoStickerDocument(document)) { + boolean isAnimatedSticker = MessageObject.isAnimatedStickerDocument(document, true); + mediaEntity.subType |= isAnimatedSticker ? 1 : 4; + long duration; + if (isAnimatedSticker) { + duration = stickerView.getDuration(); + } else { + duration = 5000; + } if (duration != 0) { BigInteger x = BigInteger.valueOf(duration); lcm = lcm.multiply(x).divide(lcm.gcd(x)); } + skipDrawToBitmap = true; } if (stickerView.isMirrored()) { mediaEntity.subType |= 2; @@ -552,33 +561,37 @@ public class PhotoPaintView extends FrameLayout implements EntityView.EntityView if (thumbBitmap[0] == null) { thumbBitmap[0] = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), bitmap.getConfig()); - canvas = new Canvas(thumbBitmap[0]); - canvas.drawBitmap(bitmap, 0, 0, null); + thumbCanvas = new Canvas(thumbBitmap[0]); + thumbCanvas.drawBitmap(bitmap, 0, 0, null); } } - if (canvas == null) { - canvas = new Canvas(bitmap); - } - canvas.save(); - canvas.translate(position.x, position.y); - canvas.scale(v.getScaleX(), v.getScaleY()); - canvas.rotate(v.getRotation()); - canvas.translate(-entity.getWidth() / 2, -entity.getHeight() / 2); - if (v instanceof TextPaintView) { - Bitmap b = Bitmaps.createBitmap(v.getWidth(), v.getHeight(), Bitmap.Config.ARGB_8888); - Canvas c = new Canvas(b); - v.draw(c); - canvas.drawBitmap(b, null, new Rect(0, 0, b.getWidth(), b.getHeight()), null); - try { - c.setBitmap(null); - } catch (Exception e) { - FileLog.e(e); + canvas = new Canvas(bitmap); + for (int k = 0; k < 2; k++) { + Canvas currentCanvas = k == 0 ? canvas : thumbCanvas; + if (currentCanvas == null || (k == 0 && skipDrawToBitmap)) { + continue; } - b.recycle(); - } else { - v.draw(canvas); + currentCanvas.save(); + currentCanvas.translate(position.x, position.y); + currentCanvas.scale(v.getScaleX(), v.getScaleY()); + currentCanvas.rotate(v.getRotation()); + currentCanvas.translate(-entity.getWidth() / 2, -entity.getHeight() / 2); + if (v instanceof TextPaintView) { + Bitmap b = Bitmaps.createBitmap(v.getWidth(), v.getHeight(), Bitmap.Config.ARGB_8888); + Canvas c = new Canvas(b); + v.draw(c); + currentCanvas.drawBitmap(b, null, new Rect(0, 0, b.getWidth(), b.getHeight()), null); + try { + c.setBitmap(null); + } catch (Exception e) { + FileLog.e(e); + } + b.recycle(); + } else { + v.draw(currentCanvas); + } + currentCanvas.restore(); } - canvas.restore(); } } return bitmap; 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 42862fab7..708ec63a7 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/PhotoViewerCaptionEnterView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/PhotoViewerCaptionEnterView.java @@ -69,6 +69,7 @@ public class PhotoViewerCaptionEnterView extends FrameLayout implements Notifica void onWindowSizeChanged(int size); void onEmojiViewCloseStart(); void onEmojiViewCloseEnd(); + void onEmojiViewOpen(); } private EditTextCaption messageEditText; @@ -645,6 +646,7 @@ public class PhotoViewerCaptionEnterView extends FrameLayout implements Notifica } emojiView.setVisibility(VISIBLE); + delegate.onEmojiViewOpen(); if (keyboardHeight <= 0) { keyboardHeight = MessagesController.getGlobalEmojiSettings().getInt("kbd_height", AndroidUtilities.dp(200)); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/PhotoViewerWebView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/PhotoViewerWebView.java index a51a781e0..9e6fb69f6 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/PhotoViewerWebView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/PhotoViewerWebView.java @@ -36,7 +36,6 @@ import java.util.Locale; public class PhotoViewerWebView extends FrameLayout { private int currentAccount = UserConfig.selectedAccount; - private PipVideoView pipVideoView; private WebView webView; private View progressBarBlackBackground; @@ -253,18 +252,24 @@ public class PhotoViewerWebView extends FrameLayout { return progressBar.getVisibility() != View.VISIBLE; } - public PipVideoView openInPip() { + public boolean openInPip() { boolean inAppOnly = isYouTube && "inapp".equals(MessagesController.getInstance(currentAccount).youtubePipType); if (!inAppOnly && !checkInlinePermissions()) { - return null; + return false; } if (progressBar.getVisibility() == View.VISIBLE) { - return null; + return false; } - boolean animated = false; - pipVideoView = new PipVideoView(inAppOnly); - pipVideoView.show((Activity) getContext(), PhotoViewer.getInstance(), currentWebpage.embed_width != 0 && currentWebpage.embed_height != 0 ? currentWebpage.embed_width / (float) currentWebpage.embed_height : 1.0f, 0, webView); - return pipVideoView; + if (PipVideoOverlay.isVisible()) { + PipVideoOverlay.dismiss(); + AndroidUtilities.runOnUIThread(this::openInPip, 300); + return true; + } + + if (PipVideoOverlay.show(inAppOnly, (Activity) getContext(), webView, currentWebpage.embed_width, currentWebpage.embed_height)) { + PipVideoOverlay.setPhotoViewer(PhotoViewer.getInstance()); + } + return true; } public void setPlaybackSpeed(float speed) { @@ -349,7 +354,7 @@ public class PhotoViewerWebView extends FrameLayout { } public void exitFromPip() { - if (webView == null || pipVideoView == null) { + if (webView == null) { return; } if (ApplicationLoader.mainInterfacePaused) { @@ -364,8 +369,7 @@ public class PhotoViewerWebView extends FrameLayout { parent.removeView(webView); } addView(webView, 0, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.TOP | Gravity.LEFT)); - pipVideoView.close(); - pipVideoView = null; + PipVideoOverlay.dismiss(); } public void release() { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/PipVideoOverlay.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/PipVideoOverlay.java new file mode 100644 index 000000000..95396a278 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/PipVideoOverlay.java @@ -0,0 +1,941 @@ +package org.telegram.ui.Components; + +import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE; + +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.animation.AnimatorSet; +import android.animation.ObjectAnimator; +import android.animation.ValueAnimator; +import android.annotation.SuppressLint; +import android.app.Activity; +import android.app.ActivityManager; +import android.content.Context; +import android.content.Intent; +import android.content.SharedPreferences; +import android.content.res.Configuration; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Outline; +import android.graphics.Paint; +import android.graphics.Path; +import android.graphics.PixelFormat; +import android.graphics.PorterDuff; +import android.os.Build; +import android.view.GestureDetector; +import android.view.Gravity; +import android.view.MotionEvent; +import android.view.ScaleGestureDetector; +import android.view.View; +import android.view.ViewConfiguration; +import android.view.ViewGroup; +import android.view.ViewOutlineProvider; +import android.view.WindowManager; +import android.webkit.WebView; +import android.widget.FrameLayout; +import android.widget.ImageView; + +import androidx.core.math.MathUtils; +import androidx.core.view.GestureDetectorCompat; +import androidx.dynamicanimation.animation.DynamicAnimation; +import androidx.dynamicanimation.animation.FloatPropertyCompat; +import androidx.dynamicanimation.animation.SpringAnimation; +import androidx.dynamicanimation.animation.SpringForce; + +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.ApplicationLoader; +import org.telegram.messenger.R; +import org.telegram.ui.ActionBar.Theme; +import org.telegram.ui.LaunchActivity; +import org.telegram.ui.PhotoViewer; + +import java.util.ArrayList; +import java.util.List; + +public class PipVideoOverlay { + public final static boolean IS_TRANSITION_ANIMATION_SUPPORTED = true; + public final static float ROUNDED_CORNERS_DP = 10; + + private final static float SIDE_PADDING_DP = 16; + private final static FloatPropertyCompat PIP_X_PROPERTY = new SimpleFloatPropertyCompat<>("pipX", obj -> obj.pipX, (obj, value) -> { + obj.windowLayoutParams.x = (int) (obj.pipX = value); + try { + obj.windowManager.updateViewLayout(obj.contentView, obj.windowLayoutParams); + } catch (IllegalArgumentException e) { + obj.pipXSpring.cancel(); + } + }), PIP_Y_PROPERTY = new SimpleFloatPropertyCompat<>("pipY", obj -> obj.pipY, (obj, value) -> { + obj.windowLayoutParams.y = (int) (obj.pipY = value); + + try { + obj.windowManager.updateViewLayout(obj.contentView, obj.windowLayoutParams); + } catch (IllegalArgumentException e) { + obj.pipYSpring.cancel(); + } + }); + + @SuppressLint("StaticFieldLeak") + private static PipVideoOverlay instance = new PipVideoOverlay(); + + private float minScaleFactor = 0.75f, maxScaleFactor = 1.4f; + + private WindowManager windowManager; + private WindowManager.LayoutParams windowLayoutParams; + private ViewGroup contentView; + private FrameLayout contentFrameLayout; + private View innerView; + private FrameLayout controlsView; + + private ScaleGestureDetector scaleGestureDetector; + private GestureDetectorCompat gestureDetector; + private boolean isScrolling; + private boolean isScrollDisallowed; + private View consumingChild; + private boolean isShowingControls; + private ValueAnimator controlsAnimator; + + private PipConfig pipConfig; + private int pipWidth, pipHeight; + private float scaleFactor = 1f; + private float pipX, pipY; + private SpringAnimation pipXSpring, pipYSpring; + private Float aspectRatio; + + private boolean isVisible; + + private boolean postedDismissControls; + private Runnable dismissControlsCallback = () -> { + toggleControls(isShowingControls = false); + postedDismissControls = false; + }; + + private int mVideoWidth, mVideoHeight; + private EmbedBottomSheet parentSheet; + private PhotoViewer photoViewer; + private ImageView playPauseButton; + private boolean isVideoCompleted; + private float videoProgress, bufferProgress; + private VideoProgressView videoProgressView; + private boolean isDismissing; + private boolean onSideToDismiss; + private Runnable progressRunnable = () -> { + if (photoViewer == null) { + return; + } + VideoPlayer videoPlayer = photoViewer.getVideoPlayer(); + if (videoPlayer == null) { + return; + } + videoProgress = videoPlayer.getCurrentPosition() / (float) videoPlayer.getDuration(); + if (photoViewer == null) { + bufferProgress = videoPlayer.getBufferedPosition() / (float) videoPlayer.getDuration(); + } + videoProgressView.invalidate(); + + AndroidUtilities.runOnUIThread(this.progressRunnable, 500); + }; + + private PipConfig getPipConfig() { + if (pipConfig == null) { + pipConfig = new PipConfig(AndroidUtilities.displaySize.x, AndroidUtilities.displaySize.y); + } + return pipConfig; + } + + public static boolean isVisible() { + return instance.isVisible; + } + + private int getSuggestedWidth() { + return getSuggestedWidth(getRatio()); + } + + private static int getSuggestedWidth(float ratio) { + if (ratio >= 1) { + return (int) (Math.min(AndroidUtilities.displaySize.x, AndroidUtilities.displaySize.y) * 0.35f); + } + return (int) (Math.min(AndroidUtilities.displaySize.x, AndroidUtilities.displaySize.y) * 0.6f); + } + + private int getSuggestedHeight() { + return getSuggestedHeight(getRatio()); + } + + private static int getSuggestedHeight(float ratio) { + return (int) (getSuggestedWidth(ratio) * ratio); + } + + private float getRatio() { + if (aspectRatio == null) { + aspectRatio = mVideoHeight / (float) mVideoWidth; + + maxScaleFactor = (Math.min(AndroidUtilities.displaySize.x, AndroidUtilities.displaySize.y) - AndroidUtilities.dp(SIDE_PADDING_DP * 2)) / (float) getSuggestedWidth(); + } + return aspectRatio; + } + + private void toggleControls(boolean show) { + controlsAnimator = ValueAnimator.ofFloat(show ? 0 : 1, show ? 1 : 0f).setDuration(200); + controlsAnimator.setInterpolator(CubicBezierInterpolator.DEFAULT); + controlsAnimator.addUpdateListener(animation -> { + float value = (float) animation.getAnimatedValue(); + controlsView.setAlpha(value); + }); + controlsAnimator.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + controlsAnimator = null; + } + }); + controlsAnimator.start(); + } + + public static void dimissAndDestroy() { + if (instance.parentSheet != null) { + instance.parentSheet.destroy(); + } else if (instance.photoViewer != null) { + instance.photoViewer.destroyPhotoViewer(); + } + dismiss(); + } + + public static void dismiss() { + dismiss(false); + } + + public static void dismiss(boolean animate) { + instance.dismissInternal(animate); + } + + private void dismissInternal(boolean animate) { + if (isDismissing) { + return; + } + isDismissing = true; + + if (controlsAnimator != null) { + controlsAnimator.cancel(); + } + + if (postedDismissControls) { + AndroidUtilities.cancelRunOnUIThread(dismissControlsCallback); + postedDismissControls = false; + } + + if (pipXSpring != null) { + pipXSpring.cancel(); + pipYSpring.cancel(); + } + + // Animate is a flag for PhotoViewer transition, not ours + if (animate) { + AndroidUtilities.runOnUIThread(this::onDismissedInternal, 100); + } else { + AnimatorSet set = new AnimatorSet(); + set.setDuration(250); + set.setInterpolator(CubicBezierInterpolator.DEFAULT); + set.playTogether( + ObjectAnimator.ofFloat(contentView, View.ALPHA, 0f), + ObjectAnimator.ofFloat(contentView, View.SCALE_X, 0.1f), + ObjectAnimator.ofFloat(contentView, View.SCALE_Y, 0.1f) + ); + set.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + onDismissedInternal(); + } + }); + set.start(); + } + } + + private void onDismissedInternal() { + try { + if (controlsView.getParent() != null) { + windowManager.removeViewImmediate(contentView); + } + } catch (IllegalArgumentException ignored) {} + + videoProgressView = null; + innerView = null; + photoViewer = null; + parentSheet = null; + consumingChild = null; + isScrolling = false; + isVisible = false; + isDismissing = false; + } + + public static void updatePlayButton() { + instance.updatePlayButtonInternal(); + } + + private void updatePlayButtonInternal() { + if (photoViewer == null) { + return; + } + VideoPlayer videoPlayer = photoViewer.getVideoPlayer(); + if (videoPlayer == null || playPauseButton == null) { + return; + } + AndroidUtilities.cancelRunOnUIThread(progressRunnable); + if (!videoPlayer.isPlaying()) { + if (isVideoCompleted) { + playPauseButton.setImageResource(R.drawable.pip_replay_large); + } else { + playPauseButton.setImageResource(R.drawable.pip_play_large); + } + } else { + playPauseButton.setImageResource(R.drawable.pip_pause_large); + AndroidUtilities.runOnUIThread(progressRunnable, 500); + } + } + + public static void onVideoCompleted() { + instance.onVideoCompletedInternal(); + } + + private void onVideoCompletedInternal() { + if (!isVisible || videoProgressView == null) { + return; + } + isVideoCompleted = true; + videoProgress = 0f; + bufferProgress = 0f; + if (videoProgressView != null) { + videoProgressView.invalidate(); + } + + updatePlayButtonInternal(); + AndroidUtilities.cancelRunOnUIThread(progressRunnable); + if (!isShowingControls) { + toggleControls(true); + AndroidUtilities.cancelRunOnUIThread(dismissControlsCallback); + } + } + + public static void setBufferedProgress(float progress) { + instance.bufferProgress = progress; + if (instance.videoProgressView != null) { + instance.videoProgressView.invalidate(); + } + } + + public static void setParentSheet(EmbedBottomSheet parentSheet) { + instance.parentSheet = parentSheet; + } + + public static void setPhotoViewer(PhotoViewer photoViewer) { + instance.photoViewer = photoViewer; + instance.updatePlayButtonInternal(); + } + + public static Rect getPipRect(boolean inAnimation, float aspectRatio) { + Rect rect = new Rect(); + float ratio = 1f / aspectRatio; + if (!instance.isVisible || inAnimation) { + float savedPipX = instance.getPipConfig().getPipX(), savedPipY = instance.getPipConfig().getPipY(); + float scaleFactor = instance.getPipConfig().getScaleFactor(); + + rect.width = getSuggestedWidth(ratio) * scaleFactor; + rect.height = getSuggestedHeight(ratio) * scaleFactor; + if (savedPipX != -1) { + rect.x = savedPipX + rect.width / 2f >= AndroidUtilities.displaySize.x / 2f ? AndroidUtilities.displaySize.x - rect.width - AndroidUtilities.dp(SIDE_PADDING_DP) : AndroidUtilities.dp(SIDE_PADDING_DP); + } else { + rect.x = AndroidUtilities.displaySize.x - rect.width - AndroidUtilities.dp(SIDE_PADDING_DP); + } + if (savedPipY != -1) { + rect.y = MathUtils.clamp(savedPipY, AndroidUtilities.dp(SIDE_PADDING_DP), AndroidUtilities.displaySize.y - AndroidUtilities.dp(SIDE_PADDING_DP) - rect.height) + AndroidUtilities.statusBarHeight; + } else { + rect.y = AndroidUtilities.dp(SIDE_PADDING_DP) + AndroidUtilities.statusBarHeight; + } + return rect; + } + + rect.x = instance.pipX; + rect.y = instance.pipY + AndroidUtilities.statusBarHeight; + rect.width = instance.pipWidth; + rect.height = instance.pipHeight; + return rect; + } + + public static boolean show(boolean inAppOnly, Activity activity, View pipContentView, int videoWidth, int videoHeight) { + return show(inAppOnly, activity, pipContentView, videoWidth, videoHeight, false); + } + + public static boolean show(boolean inAppOnly, Activity activity, View pipContentView, int videoWidth, int videoHeight, boolean animate) { + return instance.showInternal(inAppOnly, activity, pipContentView, videoWidth, videoHeight, animate); + } + + private boolean showInternal(boolean inAppOnly, Activity activity, View pipContentView, int videoWidth, int videoHeight, boolean animate) { + if (isVisible) { + return false; + } + isVisible = true; + + mVideoWidth = videoWidth; + mVideoHeight = videoHeight; + aspectRatio = null; + + float savedPipX = getPipConfig().getPipX(), savedPipY = getPipConfig().getPipY(); + scaleFactor = getPipConfig().getScaleFactor(); + + pipWidth = (int) (getSuggestedWidth() * scaleFactor); + pipHeight = (int) (getSuggestedHeight() * scaleFactor); + isShowingControls = false; + + float stiffness = 650f; + pipXSpring = new SpringAnimation(this, PIP_X_PROPERTY) + .setSpring(new SpringForce() + .setDampingRatio(SpringForce.DAMPING_RATIO_LOW_BOUNCY) + .setStiffness(stiffness)) + .addEndListener((animation, canceled, value, velocity) -> getPipConfig().setPipX(value)); + pipYSpring = new SpringAnimation(this, PIP_Y_PROPERTY) + .setSpring(new SpringForce() + .setDampingRatio(SpringForce.DAMPING_RATIO_LOW_BOUNCY) + .setStiffness(stiffness)) + .addEndListener((animation, canceled, value, velocity) -> getPipConfig().setPipY(value)); + + Context context = ApplicationLoader.applicationContext; + int touchSlop = ViewConfiguration.get(context).getScaledTouchSlop(); + scaleGestureDetector = new ScaleGestureDetector(context, new ScaleGestureDetector.OnScaleGestureListener() { + @Override + public boolean onScale(ScaleGestureDetector detector) { + scaleFactor = MathUtils.clamp(scaleFactor * detector.getScaleFactor(), minScaleFactor, maxScaleFactor); + pipWidth = (int) (getSuggestedWidth() * scaleFactor); + pipHeight = (int) (getSuggestedHeight() * scaleFactor); + AndroidUtilities.runOnUIThread(()->{ + contentView.invalidate(); + contentFrameLayout.requestLayout(); + }); + + float finalX = detector.getFocusX() >= AndroidUtilities.displaySize.x / 2f ? AndroidUtilities.displaySize.x - pipWidth - AndroidUtilities.dp(SIDE_PADDING_DP) : AndroidUtilities.dp(SIDE_PADDING_DP); + if (!pipXSpring.isRunning()) { + pipXSpring.setStartValue(pipX) + .getSpring() + .setFinalPosition(finalX); + } else { + pipXSpring.getSpring().setFinalPosition(finalX); + } + pipXSpring.start(); + + float finalY = MathUtils.clamp(detector.getFocusY() - pipHeight / 2f, AndroidUtilities.dp(SIDE_PADDING_DP), AndroidUtilities.displaySize.y - pipHeight - AndroidUtilities.dp(SIDE_PADDING_DP)); + if (!pipYSpring.isRunning()) { + pipYSpring.setStartValue(pipY) + .getSpring() + .setFinalPosition(finalY); + } else { + pipYSpring.getSpring().setFinalPosition(finalY); + } + pipYSpring.start(); + + return true; + } + + @Override + public boolean onScaleBegin(ScaleGestureDetector detector) { + if (isScrolling) { + isScrolling = false; + } + isScrollDisallowed = true; + windowLayoutParams.width = (int) (getSuggestedWidth() * maxScaleFactor); + windowLayoutParams.height = (int) (getSuggestedHeight() * maxScaleFactor); + windowManager.updateViewLayout(contentView, windowLayoutParams); + + return true; + } + + @Override + public void onScaleEnd(ScaleGestureDetector detector) { + if (pipXSpring.isRunning() || pipYSpring.isRunning()) { + List springs = new ArrayList<>(); + DynamicAnimation.OnAnimationEndListener endListener = new DynamicAnimation.OnAnimationEndListener() { + @Override + public void onAnimationEnd(DynamicAnimation animation, boolean canceled, float value, float velocity) { + animation.removeEndListener(this); + + springs.add((SpringAnimation) animation); + if (springs.size() == 2) { + updateLayout(); + } + } + }; + if (!pipXSpring.isRunning()) { + springs.add(pipXSpring); + } else { + pipXSpring.addEndListener(endListener); + } + if (!pipYSpring.isRunning()) { + springs.add(pipYSpring); + } else { + pipYSpring.addEndListener(endListener); + } + return; + } + updateLayout(); + } + + private void updateLayout() { + pipWidth = windowLayoutParams.width = (int) (getSuggestedWidth() * scaleFactor); + pipHeight = windowLayoutParams.height = (int) (getSuggestedHeight() * scaleFactor); + try { + windowManager.updateViewLayout(contentView, windowLayoutParams); + } catch (IllegalArgumentException ignored) {} + } + }); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { + scaleGestureDetector.setQuickScaleEnabled(false); + } + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + scaleGestureDetector.setStylusScaleEnabled(false); + } + gestureDetector = new GestureDetectorCompat(context, new GestureDetector.SimpleOnGestureListener() { + private float startPipX, startPipY; + + @Override + public boolean onDown(MotionEvent e) { + if (isShowingControls) { + for (int i = 1; i < contentFrameLayout.getChildCount(); i++) { + View child = contentFrameLayout.getChildAt(i); + boolean consumed = child.dispatchTouchEvent(e); + if (consumed) { + consumingChild = child; + return true; + } + } + } + startPipX = pipX; + startPipY = pipY; + return true; + } + + @Override + public boolean onSingleTapUp(MotionEvent e) { + if (controlsAnimator != null) { + return true; + } + + if (postedDismissControls) { + AndroidUtilities.cancelRunOnUIThread(dismissControlsCallback); + postedDismissControls = false; + } + + isShowingControls = !isShowingControls; + toggleControls(isShowingControls); + + if (isShowingControls && !postedDismissControls) { + AndroidUtilities.runOnUIThread(dismissControlsCallback, 2500); + postedDismissControls = true; + } + + return true; + } + + @Override + public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { + if (isScrolling && !isScrollDisallowed) { + pipXSpring.setStartVelocity(velocityX) + .setStartValue(pipX) + .getSpring() + .setFinalPosition(pipX + pipWidth / 2f + velocityX / 7f >= AndroidUtilities.displaySize.x / 2f ? AndroidUtilities.displaySize.x - pipWidth - AndroidUtilities.dp(SIDE_PADDING_DP) : AndroidUtilities.dp(SIDE_PADDING_DP)); + pipXSpring.start(); + + pipYSpring.setStartVelocity(velocityX) + .setStartValue(pipY) + .getSpring() + .setFinalPosition(MathUtils.clamp(pipY + velocityY / 10f, AndroidUtilities.dp(SIDE_PADDING_DP), AndroidUtilities.displaySize.y - pipHeight - AndroidUtilities.dp(SIDE_PADDING_DP))); + pipYSpring.start(); + return true; + } + return false; + } + + @Override + public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { + if (!isScrolling && controlsAnimator == null && !isScrollDisallowed) { + if (Math.abs(distanceX) >= touchSlop || Math.abs(distanceY) >= touchSlop) { + isScrolling = true; + + pipXSpring.cancel(); + pipYSpring.cancel(); + } + } + if (isScrolling) { + float wasPipX = pipX; + float newPipX = startPipX + e2.getRawX() - e1.getRawX(); + pipY = startPipY + e2.getRawY() - e1.getRawY(); + if (newPipX <= -pipWidth * 0.25f || newPipX >= AndroidUtilities.displaySize.x - pipWidth * 0.75f) { + if (!onSideToDismiss) { + pipXSpring.setStartValue(wasPipX) + .getSpring() + .setFinalPosition(newPipX + pipWidth / 2f >= AndroidUtilities.displaySize.x / 2f ? AndroidUtilities.displaySize.x - AndroidUtilities.dp(SIDE_PADDING_DP) : AndroidUtilities.dp(SIDE_PADDING_DP) - pipWidth); + pipXSpring.start(); + } + onSideToDismiss = true; + } else if (onSideToDismiss) { + if (onSideToDismiss) { + pipXSpring.addEndListener((animation, canceled, value, velocity) -> { + if (!canceled) { + pipXSpring.getSpring().setFinalPosition(newPipX + pipWidth / 2f >= AndroidUtilities.displaySize.x / 2f ? AndroidUtilities.displaySize.x - pipWidth - AndroidUtilities.dp(SIDE_PADDING_DP) : AndroidUtilities.dp(SIDE_PADDING_DP)); + } + }); + + pipXSpring.setStartValue(wasPipX) + .getSpring() + .setFinalPosition(newPipX); + pipXSpring.start(); + } + onSideToDismiss = false; + } else { + if (pipXSpring.isRunning()) { + pipXSpring.getSpring().setFinalPosition(newPipX); + } else { + windowLayoutParams.x = (int) (pipX = newPipX); + getPipConfig().setPipX(newPipX); + } + windowLayoutParams.y = (int) pipY; + getPipConfig().setPipY(pipY); + windowManager.updateViewLayout(contentView, windowLayoutParams); + } + } + return true; + } + }); + contentFrameLayout = new FrameLayout(context) { + private Path path = new Path(); + + @Override + public boolean dispatchTouchEvent(MotionEvent ev) { + int action = ev.getAction(); + if (consumingChild != null) { + MotionEvent newEvent = MotionEvent.obtain(ev); + newEvent.offsetLocation(consumingChild.getX(), consumingChild.getY()); + boolean consumed = consumingChild.dispatchTouchEvent(ev); + newEvent.recycle(); + + if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) { + consumingChild = null; + } + + if (consumed) { + return true; + } + } + MotionEvent temp = MotionEvent.obtain(ev); + temp.offsetLocation(ev.getRawX() - ev.getX(), ev.getRawY() - ev.getY()); + boolean scaleDetector = scaleGestureDetector.onTouchEvent(temp); + temp.recycle(); + boolean detector = !scaleGestureDetector.isInProgress() && gestureDetector.onTouchEvent(ev); + if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) { + isScrolling = false; + isScrollDisallowed = false; + + if (onSideToDismiss) { + onSideToDismiss = false; + + dimissAndDestroy(); + } else { + if (!pipXSpring.isRunning()) { + pipXSpring.setStartValue(pipX) + .getSpring() + .setFinalPosition(pipX + pipWidth / 2f >= AndroidUtilities.displaySize.x / 2f ? AndroidUtilities.displaySize.x - pipWidth - AndroidUtilities.dp(SIDE_PADDING_DP) : AndroidUtilities.dp(SIDE_PADDING_DP)); + pipXSpring.start(); + } + + if (!pipYSpring.isRunning()) { + pipYSpring.setStartValue(pipY) + .getSpring() + .setFinalPosition(MathUtils.clamp(pipY, AndroidUtilities.dp(SIDE_PADDING_DP), AndroidUtilities.displaySize.y - pipHeight - AndroidUtilities.dp(SIDE_PADDING_DP))); + pipYSpring.start(); + } + } + } + return scaleDetector || detector; + } + + @Override + protected void onConfigurationChanged(Configuration newConfig) { + AndroidUtilities.checkDisplaySize(getContext(), newConfig); + pipConfig = null; + + if (pipWidth != getSuggestedWidth() * scaleFactor || pipHeight != getSuggestedHeight() * scaleFactor) { + windowLayoutParams.width = pipWidth = (int) (getSuggestedWidth() * scaleFactor); + windowLayoutParams.height = pipHeight = (int) (getSuggestedHeight() * scaleFactor); + windowManager.updateViewLayout(contentView, windowLayoutParams); + + pipXSpring.setStartValue(pipX) + .getSpring() + .setFinalPosition(pipX + (getSuggestedWidth() * scaleFactor) / 2f >= AndroidUtilities.displaySize.x / 2f ? AndroidUtilities.displaySize.x - (getSuggestedWidth() * scaleFactor) - AndroidUtilities.dp(SIDE_PADDING_DP) : AndroidUtilities.dp(SIDE_PADDING_DP)); + pipXSpring.start(); + + pipYSpring.setStartValue(pipY) + .getSpring() + .setFinalPosition(MathUtils.clamp(pipY, AndroidUtilities.dp(SIDE_PADDING_DP), AndroidUtilities.displaySize.y - (getSuggestedHeight() * scaleFactor) - AndroidUtilities.dp(SIDE_PADDING_DP))); + pipYSpring.start(); + } + } + + @Override + public void draw(Canvas canvas) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + super.draw(canvas); + } else { + canvas.save(); + canvas.clipPath(path); + super.draw(canvas); + canvas.restore(); + } + } + + @Override + protected void onSizeChanged(int w, int h, int oldw, int oldh) { + super.onSizeChanged(w, h, oldw, oldh); + + path.rewind(); + AndroidUtilities.rectTmp.set(0, 0, w, h); + path.addRoundRect(AndroidUtilities.rectTmp, AndroidUtilities.dp(ROUNDED_CORNERS_DP), AndroidUtilities.dp(ROUNDED_CORNERS_DP), Path.Direction.CW); + } + }; + contentView = new ViewGroup(context) { + @Override + protected void onLayout(boolean changed, int l, int t, int r, int b) { + contentFrameLayout.layout(0, 0, pipWidth, pipHeight); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.getSize(heightMeasureSpec)); + contentFrameLayout.measure(MeasureSpec.makeMeasureSpec(pipWidth, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(pipHeight, MeasureSpec.EXACTLY)); + } + + @Override + public void draw(Canvas canvas) { + canvas.save(); + canvas.scale(pipWidth / (float)contentFrameLayout.getWidth(), pipHeight / (float)contentFrameLayout.getHeight()); + super.draw(canvas); + canvas.restore(); + } + }; + contentView.addView(contentFrameLayout, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + contentFrameLayout.setOutlineProvider(new ViewOutlineProvider() { + @Override + public void getOutline(View view, Outline outline) { + outline.setRoundRect(0, 0, view.getMeasuredWidth(), view.getMeasuredHeight(), AndroidUtilities.dp(ROUNDED_CORNERS_DP)); + } + }); + contentFrameLayout.setClipToOutline(true); + } + contentFrameLayout.setBackgroundColor(Theme.getColor(Theme.key_voipgroup_actionBar)); + + innerView = pipContentView; + if (innerView.getParent() != null) { + ((ViewGroup)innerView.getParent()).removeView(innerView); + } + contentFrameLayout.addView(innerView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); + + controlsView = new FrameLayout(context); + controlsView.setAlpha(0f); + View scrim = new View(context); + scrim.setBackgroundColor(0x4C000000); + controlsView.addView(scrim, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); + + int padding = AndroidUtilities.dp(8); + int margin = 4; + int buttonSize = 38; + + ImageView closeButton = new ImageView(context); + closeButton.setImageResource(R.drawable.pip_video_close); + closeButton.setColorFilter(Theme.getColor(Theme.key_voipgroup_actionBarItems), PorterDuff.Mode.MULTIPLY); + closeButton.setBackground(Theme.createSelectorDrawable(Theme.getColor(Theme.key_listSelector))); + closeButton.setPadding(padding, padding, padding, padding); + closeButton.setOnClickListener(v -> dimissAndDestroy()); + controlsView.addView(closeButton, LayoutHelper.createFrame(buttonSize, buttonSize, Gravity.RIGHT, 0, margin, margin, 0)); + + ImageView expandButton = new ImageView(context); + expandButton.setImageResource(R.drawable.pip_video_expand); + expandButton.setColorFilter(Theme.getColor(Theme.key_voipgroup_actionBarItems), PorterDuff.Mode.MULTIPLY); + expandButton.setBackground(Theme.createSelectorDrawable(Theme.getColor(Theme.key_listSelector))); + expandButton.setPadding(padding, padding, padding, padding); + expandButton.setOnClickListener(v -> { + boolean isResumedByActivityManager = true; + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + ActivityManager activityManager = (ActivityManager) v.getContext().getSystemService(Context.ACTIVITY_SERVICE); + List appProcessInfos = activityManager.getRunningAppProcesses(); + if (!appProcessInfos.isEmpty()) { + isResumedByActivityManager = appProcessInfos.get(0).importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND; + } + } + + if (!inAppOnly && (!isResumedByActivityManager || !LaunchActivity.isResumed)) { + LaunchActivity.onResumeStaticCallback = v::callOnClick; + + Context ctx = ApplicationLoader.applicationContext; + Intent intent = new Intent(ctx, LaunchActivity.class); + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + ctx.startActivity(intent); + } else { + if (parentSheet != null) { + parentSheet.exitFromPip(); + } else if (photoViewer != null) { + photoViewer.exitFromPip(); + } + } + }); + controlsView.addView(expandButton, LayoutHelper.createFrame(buttonSize, buttonSize, Gravity.RIGHT, 0, margin, buttonSize + margin + 6, 0)); + + playPauseButton = new ImageView(context); + playPauseButton.setColorFilter(Theme.getColor(Theme.key_voipgroup_actionBarItems), PorterDuff.Mode.MULTIPLY); + playPauseButton.setBackground(Theme.createSelectorDrawable(Theme.getColor(Theme.key_listSelector))); + playPauseButton.setOnClickListener(v -> { + if (photoViewer == null) { + return; + } + VideoPlayer videoPlayer = photoViewer.getVideoPlayer(); + if (videoPlayer == null) { + return; + } + if (videoPlayer.isPlaying()) { + videoPlayer.pause(); + } else { + videoPlayer.play(); + } + updatePlayButton(); + }); + playPauseButton.setVisibility(innerView instanceof WebView ? View.GONE : View.VISIBLE); + controlsView.addView(playPauseButton, LayoutHelper.createFrame(buttonSize, buttonSize, Gravity.CENTER)); + + videoProgressView = new VideoProgressView(context); + controlsView.addView(videoProgressView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); + + contentFrameLayout.addView(controlsView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); + + windowManager = (WindowManager) (inAppOnly ? activity : ApplicationLoader.applicationContext).getSystemService(Context.WINDOW_SERVICE); + + windowLayoutParams = createWindowLayoutParams(inAppOnly); + windowLayoutParams.width = pipWidth; + windowLayoutParams.height = pipHeight; + if (savedPipX != -1) { + windowLayoutParams.x = (int) (pipX = savedPipX + pipWidth / 2f >= AndroidUtilities.displaySize.x / 2f ? AndroidUtilities.displaySize.x - pipWidth - AndroidUtilities.dp(SIDE_PADDING_DP) : AndroidUtilities.dp(SIDE_PADDING_DP)); + } else { + windowLayoutParams.x = (int) (pipX = AndroidUtilities.displaySize.x - pipWidth - AndroidUtilities.dp(SIDE_PADDING_DP)); + } + if (savedPipY != -1) { + windowLayoutParams.y = (int) (pipY = MathUtils.clamp(savedPipY, AndroidUtilities.dp(SIDE_PADDING_DP), AndroidUtilities.displaySize.y - AndroidUtilities.dp(SIDE_PADDING_DP) - pipHeight)); + } else { + windowLayoutParams.y = (int) (pipY = AndroidUtilities.dp(SIDE_PADDING_DP)); + } + windowLayoutParams.dimAmount = 0f; + windowLayoutParams.flags = FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS; + + // Animate is a flag for PhotoViewer transition, not ours + if (animate) { + windowManager.addView(contentView, windowLayoutParams); + } else { + contentView.setAlpha(0f); + contentView.setScaleX(0.1f); + contentView.setScaleY(0.1f); + windowManager.addView(contentView, windowLayoutParams); + + AnimatorSet set = new AnimatorSet(); + set.setDuration(250); + set.setInterpolator(CubicBezierInterpolator.DEFAULT); + set.playTogether( + ObjectAnimator.ofFloat(contentView, View.ALPHA, 1f), + ObjectAnimator.ofFloat(contentView, View.SCALE_X, 1f), + ObjectAnimator.ofFloat(contentView, View.SCALE_Y, 1f) + ); + set.start(); + } + return true; + } + + @SuppressLint("WrongConstant") + private WindowManager.LayoutParams createWindowLayoutParams(boolean inAppOnly) { + WindowManager.LayoutParams windowLayoutParams = new WindowManager.LayoutParams(); + windowLayoutParams.gravity = Gravity.TOP | Gravity.LEFT; + windowLayoutParams.format = PixelFormat.TRANSLUCENT; + + if (!inAppOnly && AndroidUtilities.checkInlinePermissions(ApplicationLoader.applicationContext)) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + windowLayoutParams.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY; + } else { + windowLayoutParams.type = WindowManager.LayoutParams.TYPE_SYSTEM_ALERT; + } + } else { + windowLayoutParams.type = WindowManager.LayoutParams.LAST_APPLICATION_WINDOW; + } + + windowLayoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS; + + return windowLayoutParams; + } + + private final class VideoProgressView extends View { + private Paint progressPaint = new Paint(), bufferPaint = new Paint(); + + public VideoProgressView(Context context) { + super(context); + + progressPaint.setColor(Color.WHITE); + progressPaint.setStyle(Paint.Style.STROKE); + progressPaint.setStrokeCap(Paint.Cap.ROUND); + progressPaint.setStrokeWidth(AndroidUtilities.dp(2)); + bufferPaint.setColor(progressPaint.getColor()); + bufferPaint.setAlpha((int) (progressPaint.getAlpha() * 0.3f)); + bufferPaint.setStyle(Paint.Style.STROKE); + bufferPaint.setStrokeCap(Paint.Cap.ROUND); + bufferPaint.setStrokeWidth(AndroidUtilities.dp(2)); + } + + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + + int width = getWidth(); + + int progressSidePadding = AndroidUtilities.dp(10); + + int progressLeft = progressSidePadding; + int progressRight = progressLeft + (int) ((width - progressLeft - progressSidePadding) * videoProgress); + float y = getHeight() - AndroidUtilities.dp(8); + if (bufferProgress != 0) { + canvas.drawLine(progressLeft, y, progressLeft + (width - progressLeft - progressSidePadding) * bufferProgress, y, bufferPaint); + } + canvas.drawLine(progressLeft, y, progressRight, y, progressPaint); + } + } + + private final static class PipConfig { + private SharedPreferences mPrefs; + + private PipConfig(int width, int height) { + mPrefs = ApplicationLoader.applicationContext.getSharedPreferences("pip_layout_" + width + "_" + height, Context.MODE_PRIVATE); + } + + private void setPipX(float x) { + mPrefs.edit().putFloat("x", x).apply(); + } + + private void setPipY(float y) { + mPrefs.edit().putFloat("y", y).apply(); + } + + private void setScaleFactor(float scaleFactor) { + mPrefs.edit().putFloat("scale_factor", scaleFactor).apply(); + } + + private float getScaleFactor() { + return mPrefs.getFloat("scale_factor", 1f); + } + + private float getPipX() { + return mPrefs.getFloat("x", -1); + } + + private float getPipY() { + return mPrefs.getFloat("y", -1); + } + } +} \ No newline at end of file diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/PopupSwipeBackLayout.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/PopupSwipeBackLayout.java index 96b6c14ac..00ff98ead 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/PopupSwipeBackLayout.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/PopupSwipeBackLayout.java @@ -33,7 +33,7 @@ public class PopupSwipeBackLayout extends FrameLayout { private final static int DURATION = 300; SparseIntArray overrideHeightIndex = new SparseIntArray(); - private float transitionProgress; + public float transitionProgress; private float toProgress = -1; private GestureDetectorCompat detector; private boolean isProcessingSwipe; @@ -140,10 +140,7 @@ public class PopupSwipeBackLayout extends FrameLayout { return b; } - /** - * Invalidates transformations - */ - private void invalidateTransforms() { + public void invalidateTransforms() { if (!onSwipeBackProgressListeners.isEmpty()) { for (int i = 0; i < onSwipeBackProgressListeners.size(); i++) { @@ -151,28 +148,28 @@ public class PopupSwipeBackLayout extends FrameLayout { } } - View bg = getChildAt(0); - View fg = null; + View backgroundView = getChildAt(0); + View foregroundView = null; if (currentForegroundIndex >= 0 && currentForegroundIndex < getChildCount()) { - fg = getChildAt(currentForegroundIndex); + foregroundView = getChildAt(currentForegroundIndex); } - bg.setTranslationX(-transitionProgress * getWidth() * 0.5f); + backgroundView.setTranslationX(-transitionProgress * getWidth() * 0.5f); float bSc = 0.95f + (1f - transitionProgress) * 0.05f; - bg.setScaleX(bSc); - bg.setScaleY(bSc); - if (fg != null) { - fg.setTranslationX((1f - transitionProgress) * getWidth()); + backgroundView.setScaleX(bSc); + backgroundView.setScaleY(bSc); + if (foregroundView != null) { + foregroundView.setTranslationX((1f - transitionProgress) * getWidth()); } invalidateVisibility(); - float fW = bg.getMeasuredWidth(), fH = bg.getMeasuredHeight(); + float fW = backgroundView.getMeasuredWidth(), fH = backgroundView.getMeasuredHeight(); float tW = 0; float tH = 0; - if (fg != null) { - tW = fg.getMeasuredWidth(); - tH = overrideForegroundHeight != 0 ? overrideForegroundHeight : fg.getMeasuredHeight(); + if (foregroundView != null) { + tW = foregroundView.getMeasuredWidth(); + tH = overrideForegroundHeight != 0 ? overrideForegroundHeight : foregroundView.getMeasuredHeight(); } - if (bg.getMeasuredWidth() == 0 || bg.getMeasuredHeight() == 0) { + if (backgroundView.getMeasuredWidth() == 0 || backgroundView.getMeasuredHeight() == 0) { return; } @@ -181,8 +178,10 @@ public class PopupSwipeBackLayout extends FrameLayout { float h = fH + (tH - fH) * transitionProgress; w += p.getPaddingLeft() + p.getPaddingRight(); h += p.getPaddingTop() + p.getPaddingBottom(); + p.updateAnimation = false; p.setBackScaleX(w / p.getMeasuredWidth()); p.setBackScaleY(h / p.getMeasuredHeight()); + p.updateAnimation = true; for (int i = 0; i < getChildCount(); i++) { View ch = getChildAt(i); @@ -304,12 +303,20 @@ public class PopupSwipeBackLayout extends FrameLayout { animateToState(1, 0); } - /** - * Closes foreground view - */ public void closeForeground() { + closeForeground(true); + } + + public void closeForeground(boolean animated) { if (isAnimationInProgress) return; - animateToState(0, 0); + if (!animated) { + currentForegroundIndex = -1; + transitionProgress = 0; + invalidateTransforms(); + return; + } else { + animateToState(0, 0); + } } @Override 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 799bed639..90ec9dd18 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ReactedUsersListView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ReactedUsersListView.java @@ -35,6 +35,7 @@ import org.telegram.ui.ActionBar.Theme; import java.util.ArrayList; import java.util.Collections; +import java.util.Comparator; import java.util.List; public class ReactedUsersListView extends FrameLayout { @@ -190,7 +191,7 @@ public class ReactedUsersListView extends FrameLayout { } if (onlySeenNow) { - Collections.sort(userReactions, (o1, o2) -> Integer.compare(o1.reaction != null ? 1 : 0, o2.reaction != null ? 1 : 0)); + Collections.sort(userReactions, Comparator.comparingInt(o -> o.reaction != null ? 0 : 1)); } if (onlySeenNow) { 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 f1136a8df..65e95d52c 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ReactionsContainerLayout.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ReactionsContainerLayout.java @@ -110,6 +110,7 @@ public class ReactionsContainerLayout extends FrameLayout implements Notificatio private float pressedViewScale; private float otherViewsScale; private boolean clicked; + long lastReactionSentTime; public ReactionsContainerLayout(@NonNull Context context, int currentAccount, Theme.ResourcesProvider resourcesProvider) { super(context); @@ -299,7 +300,7 @@ public class ReactionsContainerLayout extends FrameLayout implements Notificatio canvas.scale(sc, sc, pivotX, getHeight() / 2f); } - if (transitionProgress != 0) { + if (transitionProgress != 0 && getAlpha() == 1f) { int delay = 0; for (int i = 0; i < recyclerListView.getChildCount(); i++) { ReactionHolderView view = (ReactionHolderView) recyclerListView.getChildAt(i); @@ -352,6 +353,7 @@ public class ReactionsContainerLayout extends FrameLayout implements Notificatio canvas.restore(); } + private void checkPressedProgress(Canvas canvas, ReactionHolderView view) { if (view.currentReaction.reaction.equals(pressedReaction)) { view.setPivotX(view.getMeasuredWidth() >> 1); @@ -372,16 +374,19 @@ public class ReactionsContainerLayout extends FrameLayout implements Notificatio } if (pressedProgress == 1f) { clicked = true; - delegate.onReactionClicked(view, view.currentReaction, true); + if (System.currentTimeMillis() - lastReactionSentTime > 300) { + lastReactionSentTime = System.currentTimeMillis(); + delegate.onReactionClicked(view, view.currentReaction, true); + } } } canvas.save(); float x = recyclerListView.getX() + view.getX(); float additionalWidth = (view.getMeasuredWidth() * view.getScaleX() - view.getMeasuredWidth()) / 2f; - if (x - additionalWidth < 0) { + if (x - additionalWidth < 0 && view.getTranslationX() >= 0) { view.setTranslationX(-(x - additionalWidth)); - } else if (x + view.getMeasuredWidth() + additionalWidth > getMeasuredWidth()) { + } else if (x + view.getMeasuredWidth() + additionalWidth > getMeasuredWidth() && view.getTranslationX() <= 0) { view.setTranslationX(getMeasuredWidth() - x - view.getMeasuredWidth() - additionalWidth); } else { view.setTranslationX(0); @@ -653,7 +658,11 @@ public class ReactionsContainerLayout extends FrameLayout implements Notificatio if (cancelByMove || event.getAction() == MotionEvent.ACTION_UP || event.getAction() == MotionEvent.ACTION_CANCEL) { if (event.getAction() == MotionEvent.ACTION_UP && pressed && (pressedReaction == null || pressedProgress > 0.8f) && delegate != null) { clicked = true; - delegate.onReactionClicked(this, currentReaction, pressedProgress > 0.8f); + if (System.currentTimeMillis() - lastReactionSentTime > 300) { + lastReactionSentTime = System.currentTimeMillis(); + delegate.onReactionClicked(this, currentReaction, pressedProgress > 0.8f); + } + } if (!clicked) { cancelPressed(); @@ -723,4 +732,15 @@ public class ReactionsContainerLayout extends FrameLayout implements Notificatio } } + @Override + public void setAlpha(float alpha) { + if (getAlpha() != alpha && alpha == 0) { + lastVisibleViews.clear(); + for (int i = 0; i < recyclerListView.getChildCount(); i++) { + ReactionHolderView view = (ReactionHolderView) recyclerListView.getChildAt(i); + view.resetAnimation(); + } + } + super.setAlpha(alpha); + } } \ No newline at end of file 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 8d4c3aaf3..6c0ca8d2b 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/RecyclerListView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/RecyclerListView.java @@ -1243,13 +1243,20 @@ public class RecyclerListView extends RecyclerView { interceptedByChild = false; } + private boolean resetSelectorOnChanged = true; + public void setResetSelectorOnChanged(boolean value) { + resetSelectorOnChanged = value; + } + private AdapterDataObserver observer = new AdapterDataObserver() { @Override public void onChanged() { checkIfEmpty(true); - currentFirst = -1; - if (removeHighlighSelectionRunnable == null) { - selectorRect.setEmpty(); + if (resetSelectorOnChanged) { + currentFirst = -1; + if (removeHighlighSelectionRunnable == null) { + selectorRect.setEmpty(); + } } invalidate(); } @@ -1418,7 +1425,9 @@ public class RecyclerListView extends RecyclerView { if (selectorDrawable != null) { selectorDrawable.setCallback(null); } - if (topBottomSelectorRadius > 0) { + if (selectorType == 8) { + selectorDrawable = Theme.createRadSelectorDrawable(color, selectorRadius, 0); + } else if (topBottomSelectorRadius > 0) { selectorDrawable = Theme.createRadSelectorDrawable(color, topBottomSelectorRadius, topBottomSelectorRadius); } else if (selectorRadius > 0) { selectorDrawable = Theme.createSimpleSelectorRoundRectDrawable(selectorRadius, 0, color, 0xff000000); @@ -1972,7 +1981,9 @@ public class RecyclerListView extends RecyclerView { if (position != NO_POSITION) { selectorPosition = position; } - if (topBottomSelectorRadius > 0 && getAdapter() != null) { + if (selectorType == 8) { + Theme.setMaskDrawableRad(selectorDrawable, selectorRadius, 0); + } else if (topBottomSelectorRadius > 0 && getAdapter() != null) { Theme.setMaskDrawableRad(selectorDrawable, position == 0 ? topBottomSelectorRadius : 0, position == getAdapter().getItemCount() - 2 ? topBottomSelectorRadius : 0); } selectorRect.set(sel.getLeft(), sel.getTop(), sel.getRight(), sel.getBottom() - bottomPadding); 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 caa892aa4..d761f4626 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/SearchViewPager.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/SearchViewPager.java @@ -6,6 +6,7 @@ import android.content.Context; import android.content.DialogInterface; import android.os.Bundle; import android.text.SpannableStringBuilder; +import android.text.TextUtils; import android.view.View; import android.widget.FrameLayout; import android.widget.TextView; @@ -185,12 +186,15 @@ public class SearchViewPager extends ViewPagerFixed implements FilteredSearchVie } public void onTextChanged(String text) { - lastSearchString = text; View view = getCurrentView(); boolean reset = false; if (!attached) { reset = true; } + if (TextUtils.isEmpty(lastSearchString)) { + reset = true; + } + lastSearchString = text; search(view, getCurrentPosition(), text, reset); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/SenderSelectPopup.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/SenderSelectPopup.java index a335d834d..36292bae2 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/SenderSelectPopup.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/SenderSelectPopup.java @@ -12,6 +12,7 @@ import android.view.Gravity; import android.view.KeyEvent; import android.view.View; import android.view.ViewGroup; +import android.view.WindowManager; import android.widget.FrameLayout; import android.widget.LinearLayout; import android.widget.TextView; @@ -65,6 +66,7 @@ public class SenderSelectPopup extends ActionBarPopupWindow { private boolean clicked; protected List springAnimations = new ArrayList<>(); + private boolean dismissed; public SenderSelectPopup(Context context, ChatActivity parentFragment, MessagesController messagesController, TLRPC.ChatFull chatFull, TLRPC.TL_channels_sendAsPeers sendAsPeers, OnSelectCallback selectCallback) { super(context); @@ -76,6 +78,9 @@ public class SenderSelectPopup extends ActionBarPopupWindow { scrimPopupContainerLayout.setLayoutParams(LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT)); setContentView(scrimPopupContainerLayout); + setWidth(WindowManager.LayoutParams.WRAP_CONTENT); + setHeight(WindowManager.LayoutParams.WRAP_CONTENT); + setBackgroundDrawable(null); Drawable shadowDrawable = ContextCompat.getDrawable(context, R.drawable.popup_fixed_alert).mutate(); @@ -198,6 +203,15 @@ public class SenderSelectPopup extends ActionBarPopupWindow { scrimPopupContainerLayout.addView(recyclerContainer); } + @Override + public void dismiss() { + if (dismissed) { + return; + } + dismissed = true; + super.dismiss(); + } + public void startShowAnimation() { for (SpringAnimation springAnimation : springAnimations) { springAnimation.cancel(); 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 63b7cbc78..2f001df6e 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/SharedMediaLayout.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/SharedMediaLayout.java @@ -3973,10 +3973,12 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter if (child instanceof SharedDocumentCell) { SharedDocumentCell cell = (SharedDocumentCell) child; messageId = cell.getMessage().getId(); + offset = cell.getTop(); } if (child instanceof SharedAudioCell) { SharedAudioCell cell = (SharedAudioCell) child; messageId = cell.getMessage().getId(); + offset = cell.getTop(); } if (messageId != 0) { break; @@ -5118,8 +5120,9 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter public void getPositionForScrollProgress(RecyclerListView listView, float progress, int[] position) { int viewHeight = listView.getChildAt(0).getMeasuredHeight(); int totalHeight = (int) getTotalItemsCount() * viewHeight; - position[0] = (int) ((progress * (totalHeight - listView.getMeasuredHeight())) / viewHeight); - position[1] = (int) (progress * (totalHeight - listView.getMeasuredHeight())) % viewHeight; + int listViewHeight = listView.getMeasuredHeight() - listView.getPaddingTop(); + position[0] = (int) ((progress * (totalHeight - listViewHeight)) / viewHeight); + position[1] = (int) (progress * (totalHeight - listViewHeight)) % viewHeight; } @Override @@ -5402,8 +5405,9 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter public void getPositionForScrollProgress(RecyclerListView listView, float progress, int[] position) { int viewHeight = listView.getChildAt(0).getMeasuredHeight(); int totalHeight = (int) (Math.ceil(getTotalItemsCount() / (float) mediaColumnsCount) * viewHeight); - position[0] = (int) ((progress * (totalHeight - listView.getMeasuredHeight())) / viewHeight) * mediaColumnsCount; - position[1] = (int) (progress * (totalHeight - listView.getMeasuredHeight())) % viewHeight; + int listHeight = listView.getMeasuredHeight() - listView.getPaddingTop(); + position[0] = (int) ((progress * (totalHeight -listHeight)) / viewHeight) * mediaColumnsCount; + position[1] = (int) (progress * (totalHeight - listHeight)) % viewHeight; } @Override @@ -5456,8 +5460,10 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter if (firstPosition < 0) { return 0; } - float scrollY = (firstPosition / parentCount) * cellHeight - firstChild.getTop(); - return scrollY / (((float) cellCount) * cellHeight - listView.getMeasuredHeight()); + float childTop = firstChild.getTop() - listView.getPaddingTop(); + float listH = listView.getMeasuredHeight() - listView.getPaddingTop(); + float scrollY = (firstPosition / parentCount) * cellHeight - childTop; + return scrollY / (((float) cellCount) * cellHeight - listH); } public boolean fastScrollIsVisible(RecyclerListView listView) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/SimpleFloatPropertyCompat.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/SimpleFloatPropertyCompat.java index 27d6881b7..91c869e00 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/SimpleFloatPropertyCompat.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/SimpleFloatPropertyCompat.java @@ -18,6 +18,10 @@ public class SimpleFloatPropertyCompat extends FloatPropertyCompat { return this; } + public float getMultiplier() { + return multiplier; + } + @Override public float getValue(T object) { return getter.get(object) * multiplier; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/SizeNotifierFrameLayoutPhoto.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/SizeNotifierFrameLayoutPhoto.java index b859725a8..3434c3d4f 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/SizeNotifierFrameLayoutPhoto.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/SizeNotifierFrameLayoutPhoto.java @@ -50,6 +50,10 @@ public class SizeNotifierFrameLayoutPhoto extends FrameLayout { } public int getKeyboardHeight() { + return keyboardHeight; + } + + public int measureKeyboardHeight() { View rootView = getRootView(); getWindowVisibleDisplayFrame(rect); if (withoutWindow) { @@ -66,7 +70,7 @@ public class SizeNotifierFrameLayoutPhoto extends FrameLayout { public void notifyHeightChanged() { if (delegate != null) { - keyboardHeight = getKeyboardHeight(); + keyboardHeight = measureKeyboardHeight(); final boolean isWidthGreater = AndroidUtilities.displaySize.x > AndroidUtilities.displaySize.y; post(() -> { if (delegate != null) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/TableLayout.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/TableLayout.java index abaec1605..0bd7b37f4 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/TableLayout.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/TableLayout.java @@ -192,7 +192,7 @@ public class TableLayout extends View { } } - public void draw(Canvas canvas) { + public void draw(Canvas canvas, View view) { if (cell == null) { return; } @@ -249,7 +249,7 @@ public class TableLayout extends View { if (selectionIndex >= 0) { textSelectionHelper.draw(canvas, (TextSelectionHelper.ArticleSelectableView) getParent().getParent(), selectionIndex); } - textLayout.draw(canvas); + textLayout.draw(canvas, view); canvas.restore(); } if (drawLines) { @@ -705,7 +705,7 @@ public class TableLayout extends View { protected void onDraw(Canvas canvas) { for (int i = 0, N = getChildCount(); i < N; i++) { Child c = getChildAt(i); - c.draw(canvas); + c.draw(canvas, this); } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/TimerDrawable.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/TimerDrawable.java index 75d7b95cb..e2f95ab66 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/TimerDrawable.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/TimerDrawable.java @@ -13,12 +13,17 @@ import android.graphics.Canvas; import android.graphics.ColorFilter; import android.graphics.Paint; import android.graphics.PixelFormat; +import android.graphics.PorterDuff; +import android.graphics.PorterDuffColorFilter; import android.graphics.drawable.Drawable; import android.text.Layout; import android.text.StaticLayout; import android.text.TextPaint; +import androidx.core.content.ContextCompat; + import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.ApplicationLoader; import org.telegram.messenger.FileLog; import org.telegram.messenger.LocaleController; import org.telegram.messenger.R; @@ -32,64 +37,94 @@ public class TimerDrawable extends Drawable { private StaticLayout timeLayout; private float timeWidth = 0; private int timeHeight = 0; - private int time = 0; + private int time = -1; + private Drawable currentTtlIcon; + private int iconColor; + private int currentTtlIconId; + Context context; + Theme.ResourcesProvider resourcesProvider; + private boolean overrideColor; + private boolean isStaticIcon; - public TimerDrawable(Context context) { - timePaint.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); - timePaint.setTextSize(AndroidUtilities.dp(11)); + public TimerDrawable(Context context, Theme.ResourcesProvider resourcesProvider) { + this.context = context; + this.resourcesProvider = resourcesProvider; + timePaint.setTypeface(AndroidUtilities.getTypeface("fonts/rcondensedbold.ttf")); linePaint.setStrokeWidth(AndroidUtilities.dp(1)); linePaint.setStyle(Paint.Style.STROKE); } public void setTime(int value) { - time = value; + if (time != value) { + time = value; - String timeString; - if (time >= 1 && time < 60) { - timeString = "" + value; - if (timeString.length() < 2) { - timeString += LocaleController.getString("SecretChatTimerSeconds", R.string.SecretChatTimerSeconds); + currentTtlIcon = ContextCompat.getDrawable(context, time == 0 ? R.drawable.msg_mini_autodelete : R.drawable.msg_mini_autodelete_empty).mutate(); + currentTtlIcon.setColorFilter(currentColorFilter); + invalidateSelf(); + + String timeString; + if (time >= 1 && time < 60) { + timeString = "" + value; + if (timeString.length() < 2) { + timeString += LocaleController.getString("SecretChatTimerSeconds", R.string.SecretChatTimerSeconds); + } + } else if (time >= 60 && time < 60 * 60) { + timeString = "" + value / 60; + if (timeString.length() < 2) { + timeString += LocaleController.getString("SecretChatTimerMinutes", R.string.SecretChatTimerMinutes); + } + } else if (time >= 60 * 60 && time < 60 * 60 * 24) { + timeString = "" + value / 60 / 60; + if (timeString.length() < 2) { + timeString += LocaleController.getString("SecretChatTimerHours", R.string.SecretChatTimerHours); + } + } else if (time >= 60 * 60 * 24 && time < 60 * 60 * 24 * 7) { + timeString = "" + value / 60 / 60 / 24; + if (timeString.length() < 2) { + timeString += LocaleController.getString("SecretChatTimerDays", R.string.SecretChatTimerDays); + } + } else if (time < 60 * 60 * 24 * 31) { + timeString = "" + value / 60 / 60 / 24 / 7; + if (timeString.length() < 2) { + timeString += LocaleController.getString("SecretChatTimerWeeks", R.string.SecretChatTimerWeeks); + } else if (timeString.length() > 2) { + timeString = "c"; + } + } else { + timeString = "" + value / 60 / 60 / 24 / 30; + if (timeString.length() < 2) { + timeString += LocaleController.getString("SecretChatTimerMonths", R.string.SecretChatTimerMonths); + } } - } else if (time >= 60 && time < 60 * 60) { - timeString = "" + value / 60; - if (timeString.length() < 2) { - timeString += LocaleController.getString("SecretChatTimerMinutes", R.string.SecretChatTimerMinutes); + + timePaint.setTextSize(AndroidUtilities.dp(11)); + timeWidth = timePaint.measureText(timeString); + if (timeWidth > AndroidUtilities.dp(13)) { + timePaint.setTextSize(AndroidUtilities.dp(9)); + timeWidth = timePaint.measureText(timeString); } - } else if (time >= 60 * 60 && time < 60 * 60 * 24) { - timeString = "" + value / 60 / 60; - if (timeString.length() < 2) { - timeString += LocaleController.getString("SecretChatTimerHours", R.string.SecretChatTimerHours); + if (timeWidth > AndroidUtilities.dp(13)) { + timePaint.setTextSize(AndroidUtilities.dp(6)); + timeWidth = timePaint.measureText(timeString); } - } else if (time >= 60 * 60 * 24 && time < 60 * 60 * 24 * 7) { - timeString = "" + value / 60 / 60 / 24; - if (timeString.length() < 2) { - timeString += LocaleController.getString("SecretChatTimerDays", R.string.SecretChatTimerDays); - } - } else if (time >= 30 * 60 * 60 * 24 && time <= 60 * 60 * 24 * 31) { - timeString = "" + value / 60 / 60 / 24 / 30; - if (timeString.length() < 2) { - timeString += LocaleController.getString("SecretChatTimerMonths", R.string.SecretChatTimerMonths); - } - } else { - timeString = "" + value / 60 / 60 / 24 / 7; - if (timeString.length() < 2) { - timeString += LocaleController.getString("SecretChatTimerWeeks", R.string.SecretChatTimerWeeks); - } else if (timeString.length() > 2) { - timeString = "c"; + try { + timeLayout = new StaticLayout(timeString, timePaint, (int) Math.ceil(timeWidth), Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); + timeHeight = timeLayout.getHeight(); + } catch (Exception e) { + timeLayout = null; + FileLog.e(e); } + + invalidateSelf(); } + } - timeWidth = timePaint.measureText(timeString); - try { - timeLayout = new StaticLayout(timeString, timePaint, (int)Math.ceil(timeWidth), Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); - timeHeight = timeLayout.getHeight(); - } catch (Exception e) { - timeLayout = null; - FileLog.e(e); - } - - invalidateSelf(); + public static TimerDrawable getTtlIcon(int ttl) { + TimerDrawable timerDrawable = new TimerDrawable(ApplicationLoader.applicationContext, null); + timerDrawable.setTime(ttl); + timerDrawable.isStaticIcon = true; + return timerDrawable; } @Override @@ -97,32 +132,38 @@ public class TimerDrawable extends Drawable { int width = getIntrinsicWidth(); int height = getIntrinsicHeight(); - - if (time == 0) { - paint.setColor(Theme.getColor(Theme.key_chat_secretTimerBackground)); - linePaint.setColor(Theme.getColor(Theme.key_chat_secretTimerText)); - - canvas.drawCircle(AndroidUtilities.dpf2(9), AndroidUtilities.dpf2(9), AndroidUtilities.dpf2(7.5f), paint); - canvas.drawCircle(AndroidUtilities.dpf2(9), AndroidUtilities.dpf2(9), AndroidUtilities.dpf2(8), linePaint); - - paint.setColor(Theme.getColor(Theme.key_chat_secretTimerText)); - canvas.drawLine(AndroidUtilities.dp(9), AndroidUtilities.dp(9), AndroidUtilities.dp(13), AndroidUtilities.dp(9), linePaint); - canvas.drawLine(AndroidUtilities.dp(9), AndroidUtilities.dp(5), AndroidUtilities.dp(9), AndroidUtilities.dp(9.5f), linePaint); - - canvas.drawRect(AndroidUtilities.dpf2(7), AndroidUtilities.dpf2(0), AndroidUtilities.dpf2(11), AndroidUtilities.dpf2(1.5f), paint); + if (!isStaticIcon) { + if (!overrideColor) { + paint.setColor(Theme.getColor(Theme.key_actionBarDefault, resourcesProvider)); + } + timePaint.setColor(Theme.getColor(Theme.key_actionBarDefaultTitle, resourcesProvider)); } else { - paint.setColor(Theme.getColor(Theme.key_chat_secretTimerBackground)); - timePaint.setColor(Theme.getColor(Theme.key_chat_secretTimerText)); - canvas.drawCircle(AndroidUtilities.dp(9.5f), AndroidUtilities.dp(9.5f), AndroidUtilities.dp(9.5f), paint); + timePaint.setColor(Theme.getColor(Theme.key_actionBarDefaultSubmenuItemIcon, resourcesProvider)); } - if (time != 0 && timeLayout != null) { - int xOffxet = 0; - if (AndroidUtilities.density == 3) { - xOffxet = -1; + if (currentTtlIcon != null) { + if (!isStaticIcon) { + canvas.drawCircle(getBounds().centerX(), getBounds().centerY(), getBounds().width() / 2f, paint); + int iconColor = Theme.getColor(Theme.key_actionBarDefaultTitle, resourcesProvider); + if (this.iconColor != iconColor) { + this.iconColor = iconColor; + currentTtlIcon.setColorFilter(new PorterDuffColorFilter(iconColor, PorterDuff.Mode.MULTIPLY)); + } + } + AndroidUtilities.rectTmp2.set(getBounds()); + AndroidUtilities.rectTmp2.inset(AndroidUtilities.dp(1f), AndroidUtilities.dp(1f)); + currentTtlIcon.setBounds(AndroidUtilities.rectTmp2); + currentTtlIcon.draw(canvas); + } + if (time != 0) { + if (timeLayout != null) { + int xOffxet = 0; + if (AndroidUtilities.density == 3) { + xOffxet = -1; + } + canvas.translate((int) (width / 2 - Math.ceil(timeWidth / 2)) + xOffxet, (height - timeHeight) / 2); + timeLayout.draw(canvas); } - canvas.translate((int)(width / 2 - Math.ceil(timeWidth / 2)) + xOffxet, (height - timeHeight) / 2); - timeLayout.draw(canvas); } } @@ -131,9 +172,13 @@ public class TimerDrawable extends Drawable { } + ColorFilter currentColorFilter; @Override public void setColorFilter(ColorFilter cf) { - + currentColorFilter = cf; + if (isStaticIcon) { + currentTtlIcon.setColorFilter(cf); + } } @Override @@ -143,11 +188,16 @@ public class TimerDrawable extends Drawable { @Override public int getIntrinsicWidth() { - return AndroidUtilities.dp(19); + return AndroidUtilities.dp(23); } @Override public int getIntrinsicHeight() { - return AndroidUtilities.dp(19); + return AndroidUtilities.dp(23); + } + + public void setBackgroundColor(int currentActionBarColor) { + overrideColor = true; + paint.setColor(currentActionBarColor); } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/TranslateAlert.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/TranslateAlert.java index f67036850..3be2543f9 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/TranslateAlert.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/TranslateAlert.java @@ -459,32 +459,12 @@ public class TranslateAlert extends Dialog { protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, MOST_SPEC); } - private Paint pressedLinkPaint = null; - private Path pressedLinkPath = new Path() { - private RectF rectF = new RectF(); - @Override - public void addRect(float left, float top, float right, float bottom, @NonNull Direction dir) { - rectF.set(left - LoadingTextView2.paddingHorizontal / 2, top - LoadingTextView2.paddingVertical, right + LoadingTextView2.paddingHorizontal / 2, bottom + LoadingTextView2.paddingVertical); - addRoundRect(rectF, dp(4), dp(4), Direction.CW); - } - }; @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); canvas.translate(getPaddingLeft(), getPaddingTop()); - if (pressedLink != null) { - try { - Layout layout = getLayout(); - int start = allTexts.getSpanStart(pressedLink); - int end = allTexts.getSpanEnd(pressedLink); - layout.getSelectionPath(start, end, pressedLinkPath); - - if (pressedLinkPaint == null) { - pressedLinkPaint = new Paint(); - pressedLinkPaint.setColor(Theme.getColor(Theme.key_chat_linkSelectBackground)); - } - canvas.drawPath(pressedLinkPath, pressedLinkPaint); - } catch (Exception e) { } + if (links != null && links.draw(canvas)) { + invalidate(); } } @Override @@ -502,10 +482,12 @@ public class TranslateAlert extends Dialog { BulletinFactory.of(bulletinContainer, null).createCopyBulletin(LocaleController.getString("TextCopied", R.string.TextCopied)).show(); clearFocus(); return true; - } else + } else { return super.onTextContextMenuItem(id); + } } }; + links = new LinkSpanDrawable.LinkCollector(allTextsView); allTextsView.setTextColor(0x00000000); allTextsView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16); allTextsView.setTextIsSelectable(!noforwards); @@ -621,7 +603,9 @@ public class TranslateAlert extends Dialog { private boolean fromTranslateMoreView = false; private float fromScrollViewY = 0; private Spannable allTexts = null; - private ClickableSpan pressedLink; + private LinkSpanDrawable pressedLink; + private LinkSpanDrawable.LinkCollector links; + @Override public boolean dispatchTouchEvent(@NonNull MotionEvent event) { try { @@ -647,20 +631,31 @@ public class TranslateAlert extends Dialog { if (textRect.contains((int) x, (int) y) && !maybeScrolling) { Layout allTextsLayout = allTextsView.getLayout(); int tx = (int) (x - allTextsView.getLeft() - container.getLeft()), - ty = (int) (y - allTextsView.getTop() - container.getTop() - scrollView.getTop() + scrollView.getScrollY()); + ty = (int) (y - allTextsView.getTop() - container.getTop() - scrollView.getTop() + scrollView.getScrollY()); final int line = allTextsLayout.getLineForVertical(ty); final int off = allTextsLayout.getOffsetForHorizontal(line, tx); final float left = allTextsLayout.getLineLeft(line); - if (allTexts != null && allTexts instanceof Spannable && left <= tx && left + allTextsLayout.getLineWidth(line) >= tx) { - ClickableSpan[] links = allTexts.getSpans(off, off, ClickableSpan.class); - if (links != null && links.length >= 1) { - if (event.getAction() == MotionEvent.ACTION_UP && pressedLink == links[0]) { - pressedLink.onClick(allTextsView); + if (allTexts instanceof Spannable && left <= tx && left + allTextsLayout.getLineWidth(line) >= tx) { + ClickableSpan[] linkSpans = allTexts.getSpans(off, off, ClickableSpan.class); + if (linkSpans != null && linkSpans.length >= 1) { + if (event.getAction() == MotionEvent.ACTION_UP && pressedLink.getSpan() == linkSpans[0]) { + ((ClickableSpan) pressedLink.getSpan()).onClick(allTextsView); + if (links != null) { + links.removeLink(pressedLink); + } pressedLink = null; allTextsView.setTextIsSelectable(!noforwards); } else if (event.getAction() == MotionEvent.ACTION_DOWN) { - pressedLink = links[0]; + pressedLink = new LinkSpanDrawable(linkSpans[0], fragment.getResourceProvider(), tx, ty, false); + if (links != null) { + links.addLink(pressedLink); + } + LinkPath path = pressedLink.obtainNewPath(); + int start = allTexts.getSpanStart(pressedLink.getSpan()); + int end = allTexts.getSpanEnd(pressedLink.getSpan()); + path.setCurrentLayout(allTextsLayout, start, 0); + allTextsLayout.getSelectionPath(start, end, path); } allTextsView.invalidate(); return true; @@ -668,7 +663,9 @@ public class TranslateAlert extends Dialog { } } if (pressedLink != null) { - allTextsView.invalidate(); + if (links != null) { + links.clear(); + } pressedLink = null; } } catch (Exception e2) { @@ -904,6 +901,7 @@ public class TranslateAlert extends Dialog { if (n == -1) n = maxBlockStr.lastIndexOf("\n\n"); if (n == -1) n = maxBlockStr.lastIndexOf("\n"); if (n == -1) n = maxBlockStr.lastIndexOf(". "); + if (n == -1) n = Math.min(maxBlockStr.length(), maxBlockSize); blocks.add(full.subSequence(0, n + 1)); full = full.subSequence(n + 1, full.length()); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/URLSpanNoUnderline.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/URLSpanNoUnderline.java index d891fb588..0bd1c0d0a 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/URLSpanNoUnderline.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/URLSpanNoUnderline.java @@ -18,6 +18,7 @@ import org.telegram.tgnet.TLObject; public class URLSpanNoUnderline extends URLSpan { + private boolean forceNoUnderline = false; private TextStyleSpan.TextStyleRun style; private TLObject object; @@ -25,6 +26,11 @@ public class URLSpanNoUnderline extends URLSpan { this(url, null); } + public URLSpanNoUnderline(String url, boolean forceNoUnderline) { + this(url, null); + this.forceNoUnderline = forceNoUnderline; + } + public URLSpanNoUnderline(String url, TextStyleSpan.TextStyleRun run) { super(url != null ? url.replace('\u202E', ' ') : url); style = run; @@ -49,7 +55,7 @@ public class URLSpanNoUnderline extends URLSpan { if (style != null) { style.applyStyle(p); } - p.setUnderlineText(l == c); + p.setUnderlineText(l == c && !forceNoUnderline); } public void setObject(TLObject spanObject) { 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 f339afbee..a7872f174 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/UndoView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/UndoView.java @@ -176,6 +176,7 @@ public class UndoView extends FrameLayout { public final static int ACTION_CLEAR_DATES = 81; public final static int ACTION_PREVIEW_MEDIA_DESELECTED = 82; + public static int ACTION_RINGTONE_ADDED = 83; private CharSequence infoText; private int hideAnimationType = 1; @@ -327,17 +328,18 @@ public class UndoView extends FrameLayout { currentAction == ACTION_REPORT_SENT || currentAction == ACTION_VOIP_USER_CHANGED || currentAction == ACTION_VOIP_CAN_NOW_SPEAK || currentAction == ACTION_VOIP_RECORDING_STARTED || currentAction == ACTION_VOIP_RECORDING_FINISHED || currentAction == ACTION_VOIP_SOUND_MUTED || currentAction == ACTION_VOIP_SOUND_UNMUTED || currentAction == ACTION_PAYMENT_SUCCESS || currentAction == ACTION_VOIP_USER_JOINED || currentAction == ACTION_PIN_DIALOGS || currentAction == ACTION_UNPIN_DIALOGS || currentAction == ACTION_VOIP_VIDEO_RECORDING_STARTED || - currentAction == ACTION_VOIP_VIDEO_RECORDING_FINISHED; + currentAction == ACTION_VOIP_VIDEO_RECORDING_FINISHED || currentAction == ACTION_RINGTONE_ADDED; } private boolean hasSubInfo() { return currentAction == ACTION_QR_SESSION_ACCEPTED || currentAction == ACTION_PROXIMITY_SET || currentAction == ACTION_ARCHIVE_HIDDEN || currentAction == ACTION_ARCHIVE_HINT || currentAction == ACTION_ARCHIVE_FEW_HINT || currentAction == ACTION_QUIZ_CORRECT || currentAction == ACTION_QUIZ_INCORRECT || - currentAction == ACTION_REPORT_SENT || currentAction == ACTION_ARCHIVE_PINNED && MessagesController.getInstance(currentAccount).dialogFilters.isEmpty(); + currentAction == ACTION_REPORT_SENT || currentAction == ACTION_ARCHIVE_PINNED && MessagesController.getInstance(currentAccount).dialogFilters.isEmpty() || currentAction == ACTION_RINGTONE_ADDED; } public boolean isMultilineSubInfo() { - return currentAction == ACTION_THEME_CHANGED || currentAction == ACTION_FILTERS_AVAILABLE || currentAction == ACTION_PROXIMITY_SET || currentAction == ACTION_REPORT_SENT; + return currentAction == ACTION_THEME_CHANGED || currentAction == ACTION_FILTERS_AVAILABLE || currentAction == ACTION_PROXIMITY_SET || currentAction == ACTION_REPORT_SENT + || currentAction == ACTION_RINGTONE_ADDED; } public void setAdditionalTranslationY(float value) { @@ -436,7 +438,7 @@ public class UndoView extends FrameLayout { } public void showWithAction(ArrayList dialogIds, int action, Object infoObject, Object infoObject2, Runnable actionRunnable, Runnable cancelRunnable) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S && currentAction == ACTION_MESSAGE_COPIED || currentAction == ACTION_USERNAME_COPIED || currentAction == ACTION_HASHTAG_COPIED || currentAction == ACTION_TEXT_COPIED || currentAction == ACTION_LINK_COPIED || currentAction == ACTION_PHONE_COPIED || currentAction == ACTION_EMAIL_COPIED || currentAction == ACTION_VOIP_LINK_COPIED) { + if (!AndroidUtilities.shouldShowClipboardToast() && currentAction == ACTION_MESSAGE_COPIED || currentAction == ACTION_USERNAME_COPIED || currentAction == ACTION_HASHTAG_COPIED || currentAction == ACTION_TEXT_COPIED || currentAction == ACTION_LINK_COPIED || currentAction == ACTION_PHONE_COPIED || currentAction == ACTION_EMAIL_COPIED || currentAction == ACTION_VOIP_LINK_COPIED) { return; } if (currentActionRunnable != null) { @@ -475,7 +477,7 @@ public class UndoView extends FrameLayout { boolean infoOnly = false; boolean reversedPlay = false; int reversedPlayEndFrame = 0; - if (actionRunnable == null && cancelRunnable == null) { + if ((actionRunnable == null && cancelRunnable == null) || action == ACTION_RINGTONE_ADDED) { setOnClickListener(view -> hide(false, 1)); setOnTouchListener(null); } else { @@ -487,12 +489,19 @@ public class UndoView extends FrameLayout { if (isTooltipAction()) { CharSequence infoText; - String subInfoText; + CharSequence subInfoText; int icon; int size = 36; boolean iconIsDrawable = false; - if (action == ACTION_REPORT_SENT) { + if (action == ACTION_RINGTONE_ADDED) { + subinfoTextView.setSingleLine(false); + infoText = LocaleController.getString("SoundAdded", R.string.SoundAdded); + subInfoText = AndroidUtilities.replaceSingleTag(LocaleController.getString("SoundAddedSubtitle", R.string.SoundAddedSubtitle), actionRunnable); + currentActionRunnable = null; + icon = R.raw.sound_download; + timeLeft = 4000; + } else if (action == ACTION_REPORT_SENT) { subinfoTextView.setSingleLine(false); infoText = LocaleController.getString("ReportChatSent", R.string.ReportChatSent); subInfoText = LocaleController.formatString("ReportSentInfo", R.string.ReportSentInfo); @@ -906,19 +915,8 @@ public class UndoView extends FrameLayout { } else if (action == ACTION_AUTO_DELETE_ON) { TLRPC.User user = (TLRPC.User) infoObject; int ttl = (Integer) infoObject2; - String time; subinfoTextView.setSingleLine(false); - if (ttl >= 30 * 24 * 60 * 60) { - time = LocaleController.formatPluralString("Months", ttl / (30 * 24 * 60 * 60)); - } else if (ttl > 24 * 60 * 60) { - time = LocaleController.formatPluralString("Days", ttl / (24 * 60 * 60)); - } else if (ttl >= 60 * 60) { - time = LocaleController.formatPluralString("Hours", ttl / (60 * 60)); - } else if (ttl >= 60) { - time = LocaleController.formatPluralString("Minutes", ttl / 60); - } else { - time = LocaleController.formatPluralString("Seconds", ttl); - } + String time = LocaleController.formatTTLString(ttl); infoTextView.setText(LocaleController.formatString("AutoDeleteHintOnText", R.string.AutoDeleteHintOnText, time)); leftImageView.setAnimation(R.raw.fire_on, 36, 36); layoutParams.topMargin = AndroidUtilities.dp(9); @@ -961,7 +959,7 @@ public class UndoView extends FrameLayout { timeLeft = 3000; infoTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 15); } else if (currentAction == ACTION_MESSAGE_COPIED || currentAction == ACTION_USERNAME_COPIED || currentAction == ACTION_HASHTAG_COPIED || currentAction == ACTION_TEXT_COPIED || currentAction == ACTION_LINK_COPIED || currentAction == ACTION_PHONE_COPIED || currentAction == ACTION_EMAIL_COPIED) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { + if (!AndroidUtilities.shouldShowClipboardToast()) { return; } int iconRawId = R.raw.copy; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/WebPlayerView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/WebPlayerView.java index 0c94a4d01..8649537da 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/WebPlayerView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/WebPlayerView.java @@ -70,7 +70,6 @@ import java.net.URLConnection; import java.net.URLDecoder; import java.net.URLEncoder; import java.net.UnknownHostException; -import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.HashMap; import java.util.Locale; @@ -84,7 +83,7 @@ public class WebPlayerView extends ViewGroup implements VideoPlayer.VideoPlayerD public interface WebPlayerViewDelegate { void onInitFailed(); TextureView onSwitchToFullscreen(View controlsView, boolean fullscreen, float aspectRatio, int rotation, boolean byButton); - TextureView onSwitchInlineMode(View controlsView, boolean inline, float aspectRatio, int rotation, boolean animated); + TextureView onSwitchInlineMode(View controlsView, boolean inline, int width, int height, int rotation, boolean animated); void onInlineSurfaceTextureReady(); void prepareToSwitchInlineMode(boolean inline, Runnable switchInlineModeRunnable, float aspectRatio, boolean animated); void onSharePressed(); @@ -156,6 +155,8 @@ public class WebPlayerView extends ViewGroup implements VideoPlayer.VideoPlayerD private ControlsView controlsView; + private int videoWidth, videoHeight; + private Runnable progressRunnable = new Runnable() { @Override public void run() { @@ -552,7 +553,7 @@ public class WebPlayerView extends ViewGroup implements VideoPlayer.VideoPlayerD if (result == null) { result = new StringBuilder(); } - result.append(new String(data, 0, read, StandardCharsets.UTF_8)); + result.append(new String(data, 0, read, "UTF-8")); } else if (read == -1) { done = true; break; @@ -799,7 +800,7 @@ public class WebPlayerView extends ViewGroup implements VideoPlayer.VideoPlayerD } else { try { String javascript = ""; - byte[] data = javascript.getBytes(StandardCharsets.UTF_8); + byte[] data = javascript.getBytes("UTF-8"); final String base64 = Base64.encodeToString(data, Base64.DEFAULT); webView.loadUrl("data:text/html;charset=utf-8;base64," + base64); } catch (Exception e) { @@ -1094,7 +1095,7 @@ public class WebPlayerView extends ViewGroup implements VideoPlayer.VideoPlayerD source.setCharAt(a, c == lower ? Character.toUpperCase(c) : lower); } try { - return new String(Base64.decode(source.toString(), Base64.DEFAULT), StandardCharsets.UTF_8); + return new String(Base64.decode(source.toString(), Base64.DEFAULT), "UTF-8"); } catch (Exception ignore) { return null; } @@ -1230,7 +1231,7 @@ public class WebPlayerView extends ViewGroup implements VideoPlayer.VideoPlayerD if (viewGroup != null) { viewGroup.removeView(controlsView); } - changedTextureView = delegate.onSwitchInlineMode(controlsView, isInline, aspectRatioFrameLayout.getAspectRatio(), aspectRatioFrameLayout.getVideoRotation(), allowInlineAnimation); + changedTextureView = delegate.onSwitchInlineMode(controlsView, isInline, videoWidth, videoHeight, aspectRatioFrameLayout.getVideoRotation(), allowInlineAnimation); changedTextureView.setVisibility(INVISIBLE); ViewGroup parent = (ViewGroup) textureView.getParent(); if (parent != null) { @@ -1775,6 +1776,8 @@ public class WebPlayerView extends ViewGroup implements VideoPlayer.VideoPlayerD width = height; height = temp; } + videoWidth = (int) (width * pixelWidthHeightRatio); + videoHeight = height; float ratio = height == 0 ? 1 : (width * pixelWidthHeightRatio) / height; aspectRatioFrameLayout.setAspectRatio(ratio, unappliedRotationDegrees); if (inFullscreen) { @@ -1819,7 +1822,7 @@ public class WebPlayerView extends ViewGroup implements VideoPlayer.VideoPlayerD } } switchingInlineMode = false; - delegate.onSwitchInlineMode(controlsView, false, aspectRatioFrameLayout.getAspectRatio(), aspectRatioFrameLayout.getVideoRotation(), allowInlineAnimation); + delegate.onSwitchInlineMode(controlsView, false, videoWidth, videoHeight, aspectRatioFrameLayout.getVideoRotation(), allowInlineAnimation); waitingForFirstTextureUpload = 0; } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/voip/CellFlickerDrawable.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/voip/CellFlickerDrawable.java index 4cd465788..7fca1f3fe 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/voip/CellFlickerDrawable.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/voip/CellFlickerDrawable.java @@ -14,11 +14,11 @@ import org.telegram.messenger.AndroidUtilities; public class CellFlickerDrawable { - private final Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG); - private final Shader gradientShader; + private Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG); + private Shader gradientShader; - private final Paint paintOutline = new Paint(Paint.ANTI_ALIAS_FLAG); - private final Shader gradientShader2; + private Paint paintOutline = new Paint(Paint.ANTI_ALIAS_FLAG); + private Shader gradientShader2; int size; int parentWidth; @@ -45,6 +45,17 @@ public class CellFlickerDrawable { paintOutline.setStrokeWidth(AndroidUtilities.dp(2)); } + public void setColors(int color) { + setColors(color, 64, 204); + } + + public void setColors(int color, int alpha1, int alpha2) { + gradientShader = new LinearGradient(0, 0, size, 0, new int[]{Color.TRANSPARENT, ColorUtils.setAlphaComponent(color, alpha1), Color.TRANSPARENT}, null, Shader.TileMode.CLAMP); + gradientShader2 = new LinearGradient(0, 0, size, 0, new int[]{Color.TRANSPARENT, ColorUtils.setAlphaComponent(color, alpha2), Color.TRANSPARENT}, null, Shader.TileMode.CLAMP); + paint.setShader(gradientShader); + paintOutline.setShader(gradientShader2); + } + public float getProgress() { return progress; } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/voip/RTMPStreamPipOverlay.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/voip/RTMPStreamPipOverlay.java index a582c92d1..5ef37d138 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/voip/RTMPStreamPipOverlay.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/voip/RTMPStreamPipOverlay.java @@ -86,8 +86,6 @@ public class RTMPStreamPipOverlay implements NotificationCenter.NotificationCent private VoIPTextureView textureView; private FrameLayout controlsView; - private int textureWidth, textureHeight; - private CellFlickerDrawable cellFlickerDrawable = new CellFlickerDrawable(); private BackupImageView avatarImageView; private View flickerView; @@ -527,16 +525,11 @@ public class RTMPStreamPipOverlay implements NotificationCenter.NotificationCent AndroidUtilities.runOnUIThread(()-> bindTextureView()); } - @SuppressWarnings("SuspiciousNameCombination") @Override public void onFrameResolutionChanged(int videoWidth, int videoHeight, int rotation) { if ((rotation / 90) % 2 == 0) { - textureWidth = videoWidth; - textureHeight = videoHeight; aspectRatio = (float) videoHeight / videoWidth; } else { - textureWidth = videoHeight; - textureHeight = videoWidth; aspectRatio = (float) videoWidth / videoHeight; } AndroidUtilities.runOnUIThread(()-> bindTextureView()); 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 7557e1610..245164214 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 @@ -725,7 +725,11 @@ public class VoIPHelper { } } } - return new File(logsDir, callId + ".log").getAbsolutePath(); + if (stats) { + return new File(logsDir, callId + "_stats.log").getAbsolutePath(); + } else { + return new File(logsDir, callId + ".log").getAbsolutePath(); + } } public static void showGroupCallAlert(BaseFragment fragment, TLRPC.Chat currentChat, TLRPC.InputPeer peer, boolean recreate, AccountInstance accountInstance) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/DialogsActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/DialogsActivity.java index bd2b43e96..d208f9e81 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/DialogsActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/DialogsActivity.java @@ -114,6 +114,7 @@ import org.telegram.ui.ActionBar.ActionBarMenu; import org.telegram.ui.ActionBar.ActionBarMenuItem; import org.telegram.ui.ActionBar.ActionBarMenuSubItem; import org.telegram.ui.ActionBar.ActionBarPopupWindow; +import org.telegram.ui.ActionBar.AdjustPanLayoutHelper; import org.telegram.ui.ActionBar.AlertDialog; import org.telegram.ui.ActionBar.BackDrawable; import org.telegram.ui.ActionBar.BaseFragment; @@ -135,6 +136,7 @@ import org.telegram.ui.Cells.DrawerProfileCell; import org.telegram.ui.Cells.DrawerUserCell; import org.telegram.ui.Cells.GraySectionCell; import org.telegram.ui.Cells.HashtagSearchCell; +import org.telegram.ui.Cells.HeaderCell; import org.telegram.ui.Cells.HintDialogCell; import org.telegram.ui.Cells.LoadingCell; import org.telegram.ui.Cells.ProfileSearchCell; @@ -300,6 +302,7 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. private RecyclerView sideMenu; private ChatActivityEnterView commentView; + private View commentViewBg; private ImageView[] writeButton; private FrameLayout writeButtonContainer; private View selectedCountView; @@ -358,6 +361,7 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. private boolean afterSignup; private boolean showSetPasswordConfirm; private int otherwiseReloginDays; + private boolean closeFragment; private FrameLayout updateLayout; private AnimatorSet updateLayoutAnimator; @@ -777,6 +781,13 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. } else { h = heightSize - inputFieldHeight + AndroidUtilities.dp(2) - (onlySelect ? 0 : actionBar.getMeasuredHeight()) - topPadding; } + int paddingBottom = 0; + if (keyboardSize > AndroidUtilities.dp(20)) { + h += (paddingBottom = inputFieldHeight + keyboardSize); + } + if (((ViewPage) child).listView != null) { + ((ViewPage) child).listView.setPadding(0, 0, 0, paddingBottom); + } if (filtersTabAnimator != null && filterTabsView != null && filterTabsView.getVisibility() == VISIBLE) { h += filterTabsMoveFrom; @@ -811,10 +822,39 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. } } + private int previousHeight = -1; + private AnimatorSet keyboardAnimator; + @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { final int count = getChildCount(); + int layoutHeight = b - t; + if (previousHeight != -1 && commentView != null) { + if (Math.abs(previousHeight - layoutHeight) > AndroidUtilities.dp(20)) { + if (keyboardAnimator != null) { + keyboardAnimator.cancel(); + } + keyboardAnimator = new AnimatorSet(); + ArrayList animators = new ArrayList<>(); + animators.add(ObjectAnimator.ofFloat(commentView, TRANSLATION_Y, previousHeight - layoutHeight, 0)); + if (commentViewBg != null) { + animators.add(ObjectAnimator.ofFloat(commentViewBg, TRANSLATION_Y, previousHeight - layoutHeight, 0)); + } + if (writeButtonContainer != null) { + animators.add(ObjectAnimator.ofFloat(writeButtonContainer, TRANSLATION_Y, previousHeight - layoutHeight, 0)); + } + if (selectedCountView != null) { + animators.add(ObjectAnimator.ofFloat(selectedCountView, TRANSLATION_Y, previousHeight - layoutHeight, 0)); + } + keyboardAnimator.playTogether(animators); + keyboardAnimator.setDuration(AdjustPanLayoutHelper.keyboardDuration); + keyboardAnimator.setInterpolator(AdjustPanLayoutHelper.keyboardInterpolator); + keyboardAnimator.start(); + } + } + previousHeight = layoutHeight; + int paddingBottom; Object tag = commentView != null ? commentView.getTag() : null; int keyboardSize = measureKeyboardHeight(); @@ -1536,6 +1576,14 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. } return super.onInterceptTouchEvent(e); } + + @Override + protected boolean allowSelectChildAtPosition(View child) { + if (child instanceof HeaderCell && !child.isClickable()) { + return false; + } + return true; + } } private class SwipeController extends ItemTouchHelper.Callback { @@ -1840,6 +1888,7 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. hasInvoice = arguments.getBoolean("hasInvoice", false); showSetPasswordConfirm = arguments.getBoolean("showSetPasswordConfirm", showSetPasswordConfirm); otherwiseReloginDays = arguments.getInt("otherwiseRelogin"); + closeFragment = arguments.getBoolean("closeFragment", true); } if (initialDialogsType == 0) { @@ -1916,6 +1965,7 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. accountInstance.getMediaDataController().loadRecents(MediaDataController.TYPE_GREETINGS, false, true, false); accountInstance.getMediaDataController().checkFeaturedStickers(); accountInstance.getMediaDataController().checkReactions(); + accountInstance.getMediaDataController().checkMenuBots(); AndroidUtilities.runOnUIThread(() -> accountInstance.getDownloadController().loadDownloadingFiles(), 200); for (String emoji : messagesController.diceEmojies) { accountInstance.getMediaDataController().loadStickersByEmojiOrName(emoji, true, true); @@ -2062,6 +2112,9 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. if (proxyItem != null && proxyItemVisible) { proxyItem.setVisibility(View.GONE); } + if (downloadsItem != null && downloadsItemVisible) { + downloadsItem.setVisibility(View.GONE); + } if (viewPages[0] != null) { if (searchString != null) { viewPages[0].listView.hide(); @@ -2089,6 +2142,9 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. if (proxyItem != null && proxyItemVisible) { proxyItem.setVisibility(View.VISIBLE); } + if (downloadsItem != null && downloadsItemVisible) { + downloadsItem.setVisibility(View.VISIBLE); + } if (searchString != null) { finishFragment(); return false; @@ -2493,7 +2549,7 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. } } }; - tabView.setBackground(Theme.createRoundRectDrawable(AndroidUtilities.dp(6), Theme.getColor(Theme.key_actionBarDefault))); + tabView.setBackground(Theme.createRoundRectDrawable(AndroidUtilities.dp(6), 0, Theme.getColor(Theme.key_actionBarDefault))); scrimPopupWindow.setDismissAnimationDuration(220); scrimPopupWindow.setOutsideTouchable(true); scrimPopupWindow.setClippingEnabled(true); @@ -2856,7 +2912,9 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. ArrayList arrayList = new ArrayList<>(); arrayList.add(-chatId); DialogsActivityDelegate dialogsActivityDelegate = delegate; - removeSelfFromStack(); + if (closeFragment) { + removeSelfFromStack(); + } dialogsActivityDelegate.didSelectDialogs(DialogsActivity.this, arrayList, null, true); } @@ -3317,6 +3375,9 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. commentView.setVisibility(View.GONE); commentView.getSendButton().setAlpha(0); contentView.addView(commentView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.LEFT | Gravity.BOTTOM)); + commentViewBg = new View(getParentActivity()); + commentViewBg.setBackgroundColor(getThemedColor(Theme.key_chat_messagePanelBackground)); + contentView.addView(commentViewBg, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 1600, Gravity.BOTTOM | Gravity.FILL_HORIZONTAL, 0, 0, 0, -1600)); commentView.setDelegate(new ChatActivityEnterView.ChatActivityEnterViewDelegate() { @Override public void onMessageSend(CharSequence message, boolean notify, int scheduleDate) { @@ -5217,6 +5278,7 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. } addOrRemoveSelectedDialog(dialog.id, view); updateSelectedCount(); + return true; } else { if (dialog instanceof TLRPC.TL_dialogFolder) { view.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS, HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING); @@ -5257,7 +5319,6 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. showOrUpdateActionMode(dialog.id, view); return true; } - return false; } private boolean showChatPreview(DialogCell cell) { @@ -6469,7 +6530,8 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. } private boolean isNextButton = false; - + private AnimatorSet commentViewAnimator; + private void updateSelectedCount() { if (commentView != null) { if (selectedDialogs.isEmpty()) { @@ -6481,9 +6543,13 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. if (commentView.getTag() != null) { commentView.hidePopup(false); commentView.closeKeyboard(); - AnimatorSet animatorSet = new AnimatorSet(); - animatorSet.playTogether( - ObjectAnimator.ofFloat(commentView, View.TRANSLATION_Y, 0, commentView.getMeasuredHeight()), + if (commentViewAnimator != null) { + commentViewAnimator.cancel(); + } + commentViewAnimator = new AnimatorSet(); + commentView.setTranslationY(0); + commentViewAnimator.playTogether( + ObjectAnimator.ofFloat(commentView, View.TRANSLATION_Y, commentView.getMeasuredHeight()), ObjectAnimator.ofFloat(writeButtonContainer, View.SCALE_X, .2f), ObjectAnimator.ofFloat(writeButtonContainer, View.SCALE_Y, .2f), ObjectAnimator.ofFloat(writeButtonContainer, View.ALPHA, 0), @@ -6491,16 +6557,16 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. ObjectAnimator.ofFloat(selectedCountView, View.SCALE_Y, 0.2f), ObjectAnimator.ofFloat(selectedCountView, View.ALPHA, 0.0f) ); - animatorSet.setDuration(180); - animatorSet.setInterpolator(new DecelerateInterpolator()); - animatorSet.addListener(new AnimatorListenerAdapter() { + commentViewAnimator.setDuration(180); + commentViewAnimator.setInterpolator(new DecelerateInterpolator()); + commentViewAnimator.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { commentView.setVisibility(View.GONE); writeButtonContainer.setVisibility(View.GONE); } }); - animatorSet.start(); + commentViewAnimator.start(); commentView.setTag(null); fragmentView.requestLayout(); } @@ -6508,11 +6574,14 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. selectedCountView.invalidate(); if (commentView.getTag() == null) { commentView.setFieldText(""); + if (commentViewAnimator != null) { + commentViewAnimator.cancel(); + } commentView.setVisibility(View.VISIBLE); writeButtonContainer.setVisibility(View.VISIBLE); - AnimatorSet animatorSet = new AnimatorSet(); - animatorSet.playTogether( - ObjectAnimator.ofFloat(commentView, View.TRANSLATION_Y, commentView.getMeasuredHeight(), 0), + commentViewAnimator = new AnimatorSet(); + commentViewAnimator.playTogether( + ObjectAnimator.ofFloat(commentView, View.TRANSLATION_Y, commentView.getMeasuredHeight(),0), ObjectAnimator.ofFloat(writeButtonContainer, View.SCALE_X, 1f), ObjectAnimator.ofFloat(writeButtonContainer, View.SCALE_Y, 1f), ObjectAnimator.ofFloat(writeButtonContainer, View.ALPHA, 1f), @@ -6520,16 +6589,16 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. ObjectAnimator.ofFloat(selectedCountView, View.SCALE_Y, 1f), ObjectAnimator.ofFloat(selectedCountView, View.ALPHA, 1f) ); - animatorSet.setDuration(180); - animatorSet.setInterpolator(new DecelerateInterpolator()); - animatorSet.addListener(new AnimatorListenerAdapter() { + commentViewAnimator.setDuration(180); + commentViewAnimator.setInterpolator(new DecelerateInterpolator()); + commentViewAnimator.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { commentView.setTag(2); commentView.requestLayout(); } }); - animatorSet.start(); + commentViewAnimator.start(); commentView.setTag(1); } actionBar.setTitle(LocaleController.formatPluralString("Recipient", selectedDialogs.size())); @@ -6538,7 +6607,7 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. hideFloatingButton(selectedDialogs.isEmpty()); } - isNextButton = shouldShowNextButton(this, selectedDialogs, commentView.getFieldText(), false); + isNextButton = shouldShowNextButton(this, selectedDialogs, commentView != null ? commentView.getFieldText() : "", false); AndroidUtilities.updateViewVisibilityAnimated(writeButton[0], !isNextButton, 0.5f, true); AndroidUtilities.updateViewVisibilityAnimated(writeButton[1], isNextButton, 0.5f, true); } @@ -7025,7 +7094,20 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. } else if (dialogsType == 1 || dialogsType == 10 || dialogsType == 13) { return messagesController.dialogsServerOnly; } else if (dialogsType == 2) { - return messagesController.dialogsCanAddUsers; + ArrayList dialogs = new ArrayList<>(messagesController.dialogsCanAddUsers.size() + messagesController.dialogsMyChannels.size() + messagesController.dialogsMyGroups.size() + 2); + if (messagesController.dialogsMyChannels.size() > 0) { + dialogs.add(null); + dialogs.addAll(messagesController.dialogsMyChannels); + } + if (messagesController.dialogsMyGroups.size() > 0) { + dialogs.add(null); + dialogs.addAll(messagesController.dialogsMyGroups); + } + if (messagesController.dialogsCanAddUsers.size() > 0) { + dialogs.add(null); + dialogs.addAll(messagesController.dialogsCanAddUsers); + } + return dialogs; } else if (dialogsType == 3) { return messagesController.dialogsForward; } else if (dialogsType == 4 || dialogsType == 12) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/LaunchActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/LaunchActivity.java index acf3daeb8..04fe5a858 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/LaunchActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/LaunchActivity.java @@ -22,7 +22,6 @@ import android.content.res.Configuration; import android.database.Cursor; import android.graphics.Bitmap; import android.graphics.Canvas; -import android.graphics.Color; import android.graphics.LinearGradient; import android.graphics.Matrix; import android.graphics.Paint; @@ -120,6 +119,7 @@ import org.telegram.ui.Cells.DrawerProfileCell; import org.telegram.ui.Cells.DrawerUserCell; import org.telegram.ui.Cells.LanguageCell; import org.telegram.ui.Components.AlertsCreator; +import org.telegram.ui.Components.AttachBotIntroTopView; import org.telegram.ui.Components.AudioPlayerAlert; import org.telegram.ui.Components.BlockingUpdateView; import org.telegram.ui.Components.Bulletin; @@ -167,6 +167,8 @@ import java.util.Set; import java.util.regex.Pattern; public class LaunchActivity extends BasePermissionsActivity implements ActionBarLayout.ActionBarLayoutDelegate, NotificationCenter.NotificationCenterDelegate, DialogsActivity.DialogsActivityDelegate { + public static boolean isResumed; + public static Runnable onResumeStaticCallback; private static final String EXTRA_ACTION_TOKEN = "actions.fulfillment.extra.ACTION_TOKEN"; @@ -248,21 +250,6 @@ public class LaunchActivity extends BasePermissionsActivity implements ActionBar @Override protected void onCreate(Bundle savedInstanceState) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { - getSplashScreen().setOnExitAnimationListener(splashScreenView -> { - ObjectAnimator animator = ObjectAnimator.ofFloat(splashScreenView, View.ALPHA, 1f, 0f); - animator.setInterpolator(CubicBezierInterpolator.DEFAULT); - animator.setDuration(150L); - animator.addListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator animation) { - splashScreenView.remove(); - } - }); - animator.start(); - }); - } - ApplicationLoader.postInitApplication(); AndroidUtilities.checkDisplaySize(this, getResources().getConfiguration()); currentAccount = UserConfig.selectedAccount; @@ -519,7 +506,7 @@ public class LaunchActivity extends BasePermissionsActivity implements ActionBar sideMenu.setBackgroundColor(Theme.getColor(Theme.key_chats_menuBackground)); sideMenu.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false)); sideMenu.setAllowItemsInteractionDuringAnimation(false); - sideMenu.setAdapter(drawerLayoutAdapter = new DrawerLayoutAdapter(this, itemAnimator)); + sideMenu.setAdapter(drawerLayoutAdapter = new DrawerLayoutAdapter(this, itemAnimator, drawerLayoutContainer)); sideMenuContainer.addView(sideMenu, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); drawerLayoutContainer.setDrawerLayout(sideMenuContainer); FrameLayout.LayoutParams layoutParams = (FrameLayout.LayoutParams) sideMenuContainer.getLayoutParams(); @@ -1604,6 +1591,7 @@ public class LaunchActivity extends BasePermissionsActivity implements ActionBar String unsupportedUrl = null; String botUser = null; String botChat = null; + String botChatAdminParams = null; String message = null; String phone = null; String game = null; @@ -1620,6 +1608,8 @@ public class LaunchActivity extends BasePermissionsActivity implements ActionBar Integer commentId = null; int videoTimestamp = -1; boolean hasUrl = false; + String setAsAttachBot = null; + String attachMenuBotToOpen = null; final String scheme = data.getScheme(); if (scheme != null) { switch (scheme) { @@ -1789,9 +1779,12 @@ public class LaunchActivity extends BasePermissionsActivity implements ActionBar } botUser = data.getQueryParameter("start"); botChat = data.getQueryParameter("startgroup"); + botChatAdminParams = data.getQueryParameter("admin"); game = data.getQueryParameter("game"); voicechat = data.getQueryParameter("voicechat"); livestream = data.getQueryParameter("livestream"); + setAsAttachBot = data.getQueryParameter("startattach"); + attachMenuBotToOpen = data.getQueryParameter("attach"); threadId = Utilities.parseInt(data.getQueryParameter("thread")); if (threadId == 0) { threadId = null; @@ -1827,9 +1820,12 @@ public class LaunchActivity extends BasePermissionsActivity implements ActionBar } else { botUser = data.getQueryParameter("start"); botChat = data.getQueryParameter("startgroup"); + botChatAdminParams = data.getQueryParameter("admin"); game = data.getQueryParameter("game"); voicechat = data.getQueryParameter("voicechat"); livestream = data.getQueryParameter("livestream"); + setAsAttachBot = data.getQueryParameter("startattach"); + attachMenuBotToOpen = data.getQueryParameter("attach"); messageId = Utilities.parseInt(data.getQueryParameter("post")); if (messageId == 0) { messageId = null; @@ -2154,7 +2150,7 @@ public class LaunchActivity extends BasePermissionsActivity implements ActionBar if (message != null && message.startsWith("@")) { message = " " + message; } - runLinkRequest(intentAccount[0], username, group, sticker, botUser, botChat, message, hasUrl, messageId, channelId, threadId, commentId, game, auth, lang, unsupportedUrl, code, login, wallPaper, theme, voicechat, livestream, 0, videoTimestamp); + runLinkRequest(intentAccount[0], username, group, sticker, botUser, botChat, botChatAdminParams, message, hasUrl, messageId, channelId, threadId, commentId, game, auth, lang, unsupportedUrl, code, login, wallPaper, theme, voicechat, livestream, 0, videoTimestamp, setAsAttachBot, attachMenuBotToOpen); } else { try (Cursor cursor = getContentResolver().query(intent.getData(), null, null, null, null)) { if (cursor != null) { @@ -2831,6 +2827,7 @@ public class LaunchActivity extends BasePermissionsActivity implements ActionBar final String sticker, final String botUser, final String botChat, + final String botChatAdminParams, final String message, final boolean hasUrl, final Integer messageId, @@ -2848,13 +2845,15 @@ public class LaunchActivity extends BasePermissionsActivity implements ActionBar final String voicechat, final String livestream, final int state, - final int videoTimestamp) { + final int videoTimestamp, + final String setAsAttachBot, + final String attachMenuBotToOpen) { if (state == 0 && UserConfig.getActivatedAccountsCount() >= 2 && auth != null) { AlertsCreator.createAccountSelectDialog(this, account -> { if (account != intentAccount) { switchToAccount(account, true); } - runLinkRequest(account, username, group, sticker, botUser, botChat, message, hasUrl, messageId, channelId, threadId, commentId, game, auth, lang, unsupportedUrl, code, loginToken, wallPaper, theme, voicechat, livestream, 1, videoTimestamp); + runLinkRequest(account, username, group, sticker, botUser, botChat, botChatAdminParams, message, hasUrl, messageId, channelId, threadId, commentId, game, auth, lang, unsupportedUrl, code, loginToken, wallPaper, theme, voicechat, livestream, 1, videoTimestamp, setAsAttachBot, attachMenuBotToOpen); }).show(); return; } else if (code != null) { @@ -2894,12 +2893,63 @@ public class LaunchActivity extends BasePermissionsActivity implements ActionBar requestId[0] = ConnectionsManager.getInstance(intentAccount).sendRequest(req, (response, error) -> AndroidUtilities.runOnUIThread(() -> { if (!LaunchActivity.this.isFinishing()) { boolean hideProgressDialog = true; - final TLRPC.TL_contacts_resolvedPeer res = (TLRPC.TL_contacts_resolvedPeer) response; + TLRPC.TL_contacts_resolvedPeer res = (TLRPC.TL_contacts_resolvedPeer) response; if (error == null && actionBarLayout != null && (game == null && voicechat == null || game != null && !res.users.isEmpty() || voicechat != null && !res.chats.isEmpty() || livestream != null && !res.chats.isEmpty())) { MessagesController.getInstance(intentAccount).putUsers(res.users, false); MessagesController.getInstance(intentAccount).putChats(res.chats, false); MessagesStorage.getInstance(intentAccount).putUsersAndChats(res.users, res.chats, false, true); - if (messageId != null && (commentId != null || threadId != null) && !res.chats.isEmpty()) { + if (setAsAttachBot != null && attachMenuBotToOpen == null) { + TLRPC.User user = MessagesController.getInstance(intentAccount).getUser(res.peer.user_id); + if (user != null && user.bot) { + if (user.bot_attach_menu) { + TLRPC.TL_messages_getAttachMenuBot getAttachMenuBot = new TLRPC.TL_messages_getAttachMenuBot(); + getAttachMenuBot.bot = MessagesController.getInstance(intentAccount).getInputUser(res.peer.user_id); + ConnectionsManager.getInstance(intentAccount).sendRequest(getAttachMenuBot, (response1, error1) -> AndroidUtilities.runOnUIThread(()->{ + if (response1 instanceof TLRPC.TL_attachMenuBotsBot) { + TLRPC.TL_attachMenuBotsBot attachMenuBotsBot = (TLRPC.TL_attachMenuBotsBot) response1; + MessagesController.getInstance(intentAccount).putUsers(attachMenuBotsBot.users, false); + TLRPC.TL_attachMenuBot attachMenuBot = attachMenuBotsBot.bot; + BaseFragment lastFragment = mainFragmentsStack.get(mainFragmentsStack.size() - 1); + if (!attachMenuBot.inactive) { + if (lastFragment instanceof ChatActivity) { + ((ChatActivity) lastFragment).openAttachBotLayout(user.id, setAsAttachBot); + } else { + BulletinFactory.of(lastFragment).createErrorBulletin(LocaleController.getString(R.string.BotAlreadyAddedToAttachMenu)).show(); + } + } else { + AttachBotIntroTopView introTopView = new AttachBotIntroTopView(LaunchActivity.this); + introTopView.setColor(Theme.getColor(Theme.key_chat_attachContactIcon)); + introTopView.setBackgroundColor(Theme.getColor(Theme.key_dialogTopBackground)); + introTopView.setAttachBot(attachMenuBot); + new AlertDialog.Builder(LaunchActivity.this) + .setTopView(introTopView) + .setMessage(AndroidUtilities.replaceTags(LocaleController.formatString("BotRequestAttachPermission", R.string.BotRequestAttachPermission, UserObject.getUserName(user)))) + .setPositiveButton(LocaleController.getString(R.string.BotAddToMenu), (dialog, which) -> { + TLRPC.TL_messages_toggleBotInAttachMenu botRequest = new TLRPC.TL_messages_toggleBotInAttachMenu(); + botRequest.bot = MessagesController.getInstance(intentAccount).getInputUser(res.peer.user_id); + botRequest.enabled = true; + ConnectionsManager.getInstance(intentAccount).sendRequest(botRequest, (response2, error2) -> AndroidUtilities.runOnUIThread(() -> { + if (error2 == null) { + MediaDataController.getInstance(intentAccount).loadAttachMenuBots(false, true); + + if (lastFragment instanceof ChatActivity) { + ((ChatActivity) lastFragment).openAttachBotLayout(user.id, setAsAttachBot); + } + } + }), ConnectionsManager.RequestFlagInvokeAfter | ConnectionsManager.RequestFlagFailOnServerErrors); + }) + .setNegativeButton(LocaleController.getString(R.string.Cancel), null) + .show(); + } + } + })); + } else { + BulletinFactory.of(mainFragmentsStack.get(mainFragmentsStack.size() - 1)).createErrorBulletin(LocaleController.getString(R.string.BotCantAddToAttachMenu)).show(); + } + } else { + BulletinFactory.of(mainFragmentsStack.get(mainFragmentsStack.size() - 1)).createErrorBulletin(LocaleController.getString(R.string.BotSetAttachLinkNotBot)).show(); + } + } else if (messageId != null && (commentId != null || threadId != null) && !res.chats.isEmpty()) { requestId[0] = runCommentRequest(intentAccount, progressDialog, messageId, commentId, threadId, res.chats.get(0)); if (requestId[0] != 0) { hideProgressDialog = false; @@ -2973,17 +3023,107 @@ public class LaunchActivity extends BasePermissionsActivity implements ActionBar Bundle args = new Bundle(); args.putBoolean("onlySelect", true); args.putInt("dialogsType", 2); - args.putString("addToGroupAlertString", LocaleController.formatString("AddToTheGroupAlertText", R.string.AddToTheGroupAlertText, UserObject.getUserName(user), "%1$s")); + args.putBoolean("resetDelegate", false); + args.putBoolean("closeFragment", false); +// args.putString("addToGroupAlertString", LocaleController.formatString("AddToTheGroupAlertText", R.string.AddToTheGroupAlertText, UserObject.getUserName(user), "%1$s")); DialogsActivity fragment = new DialogsActivity(args); fragment.setDelegate((fragment12, dids, message1, param) -> { long did = dids.get(0); - Bundle args12 = new Bundle(); - args12.putBoolean("scrollToTopOnResume", true); - args12.putLong("chat_id", -did); - if (mainFragmentsStack.isEmpty() || MessagesController.getInstance(intentAccount).checkCanOpenChat(args12, mainFragmentsStack.get(mainFragmentsStack.size() - 1))) { - NotificationCenter.getInstance(intentAccount).postNotificationName(NotificationCenter.closeChats); - MessagesController.getInstance(intentAccount).addUserToChat(-did, user, 0, botChat, null, null); - actionBarLayout.presentFragment(new ChatActivity(args12), true, false, true, false); + + TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(-did); + if (chat != null && (chat.creator || chat.admin_rights != null && chat.admin_rights.add_admins)) { + MessagesController.getInstance(intentAccount).checkIsInChat(chat, user, (isInChatAlready, currentRights, currentRank) -> AndroidUtilities.runOnUIThread(() -> { + TLRPC.TL_chatAdminRights requestingRights = null; + if (botChatAdminParams != null) { + String[] adminParams = botChatAdminParams.split("\\+"); + requestingRights = new TLRPC.TL_chatAdminRights(); + final int count = adminParams.length; + for (int i = 0; i < count; ++i) { + String adminParam = adminParams[i]; + switch (adminParam) { + case "change_info": + requestingRights.change_info = true; + break; + case "post_messages": + requestingRights.post_messages = true; + break; + case "edit_messages": + requestingRights.edit_messages = true; + break; + case "add_admins": + requestingRights.add_admins = true; + break; + case "delete_messages": + requestingRights.delete_messages = true; + break; + case "ban_users": + requestingRights.ban_users = true; + break; + case "invite_users": + requestingRights.invite_users = true; + break; + case "pin_messages": + requestingRights.pin_messages = true; + break; + case "manage_call": + requestingRights.manage_call = true; + break; + case "anonymous": + requestingRights.anonymous = true; + break; + } + } + } + TLRPC.TL_chatAdminRights editRights = null; + if (requestingRights != null || currentRights != null) { + if (requestingRights == null) { + editRights = currentRights; + } else if (currentRights == null) { + editRights = requestingRights; + } else { + editRights = currentRights; + editRights.change_info = requestingRights.change_info || editRights.change_info; + editRights.post_messages = requestingRights.post_messages || editRights.post_messages; + editRights.edit_messages = requestingRights.edit_messages || editRights.edit_messages; + editRights.add_admins = requestingRights.add_admins || editRights.add_admins; + editRights.delete_messages = requestingRights.delete_messages || editRights.delete_messages; + editRights.ban_users = requestingRights.ban_users || editRights.ban_users; + editRights.invite_users = requestingRights.invite_users || editRights.invite_users; + editRights.pin_messages = requestingRights.pin_messages || editRights.pin_messages; + editRights.manage_call = requestingRights.manage_call || editRights.manage_call; + editRights.anonymous = requestingRights.anonymous || editRights.anonymous; + } + } + ChatRightsEditActivity editRightsActivity = new ChatRightsEditActivity(user.id, -did, editRights, null, null, currentRank, ChatRightsEditActivity.TYPE_ADD_BOT, true, !isInChatAlready, null); + editRightsActivity.setDelegate(new ChatRightsEditActivity.ChatRightsEditActivityDelegate() { + @Override + public void didSetRights(int rights, TLRPC.TL_chatAdminRights rightsAdmin, TLRPC.TL_chatBannedRights rightsBanned, String rank) { + fragment.removeSelfFromStack(); + NotificationCenter.getInstance(intentAccount).postNotificationName(NotificationCenter.closeChats); + } + + @Override + public void didChangeOwner(TLRPC.User user) {} + }); + actionBarLayout.presentFragment(editRightsActivity, false); + })); + } else { + AlertDialog.Builder builder = new AlertDialog.Builder(this); + builder.setTitle(LocaleController.getString("AddBot", R.string.AddBot)); + String chatName = chat == null ? "" : chat.title; + builder.setMessage(AndroidUtilities.replaceTags(LocaleController.formatString("AddMembersAlertNamesText", R.string.AddMembersAlertNamesText, UserObject.getUserName(user), chatName))); + builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); + builder.setPositiveButton(LocaleController.getString("AddBot", R.string.AddBot), (di, i) -> { + Bundle args12 = new Bundle(); + args12.putBoolean("scrollToTopOnResume", true); + args12.putLong("chat_id", -did); + + ChatActivity chatActivity = new ChatActivity(args12); + NotificationCenter.getInstance(intentAccount).postNotificationName(NotificationCenter.closeChats); + MessagesController.getInstance(intentAccount).addUserToChat(-did, user, 0, TextUtils.isEmpty(botChat) ? null : botChat, chatActivity, null); + actionBarLayout.presentFragment(chatActivity, true, false, true, false); + }); + builder.show(); } }); presentFragment(fragment); @@ -3014,6 +3154,12 @@ public class LaunchActivity extends BasePermissionsActivity implements ActionBar if (videoTimestamp >= 0) { args.putInt("video_timestamp", videoTimestamp); } + if (attachMenuBotToOpen != null) { + args.putString("attach_bot", attachMenuBotToOpen); + } + if (setAsAttachBot != null) { + args.putString("attach_bot_start_command", setAsAttachBot); + } BaseFragment lastFragment = !mainFragmentsStack.isEmpty() && voicechat == null ? mainFragmentsStack.get(mainFragmentsStack.size() - 1) : null; if (lastFragment == null || MessagesController.getInstance(intentAccount).checkCanOpenChat(args, lastFragment)) { if (isBot && lastFragment instanceof ChatActivity && ((ChatActivity) lastFragment).getDialogId() == dialog_id) { @@ -3028,20 +3174,35 @@ public class LaunchActivity extends BasePermissionsActivity implements ActionBar FileLog.e(e); } if (!LaunchActivity.this.isFinishing()) { - ChatActivity fragment = new ChatActivity(args); - actionBarLayout.presentFragment(fragment); + BaseFragment voipLastFragment; + if (livestream == null || !(lastFragment instanceof ChatActivity) || ((ChatActivity) lastFragment).getDialogId() != dialog_id) { + ChatActivity fragment = new ChatActivity(args); + actionBarLayout.presentFragment(fragment); + voipLastFragment = fragment; + } else { + voipLastFragment = lastFragment; + } AndroidUtilities.runOnUIThread(()->{ if (livestream != null) { AccountInstance accountInstance = AccountInstance.getInstance(currentAccount); ChatObject.Call cachedCall = accountInstance.getMessagesController().getGroupCall(-dialog_id, false); if (cachedCall != null) { - VoIPHelper.startCall(accountInstance.getMessagesController().getChat(-dialog_id), accountInstance.getMessagesController().getInputPeer(dialog_id), null, false, cachedCall == null || !cachedCall.call.rtmp_stream, LaunchActivity.this, fragment, accountInstance); + VoIPHelper.startCall(accountInstance.getMessagesController().getChat(-dialog_id), accountInstance.getMessagesController().getInputPeer(dialog_id), null, false, cachedCall == null || !cachedCall.call.rtmp_stream, LaunchActivity.this, voipLastFragment, accountInstance); } else { - accountInstance.getMessagesController().getGroupCall(-dialog_id, true, () -> AndroidUtilities.runOnUIThread(() -> { - ChatObject.Call call = accountInstance.getMessagesController().getGroupCall(-dialog_id, false); - VoIPHelper.startCall(accountInstance.getMessagesController().getChat(-dialog_id), accountInstance.getMessagesController().getInputPeer(dialog_id), null, false, call == null || !call.call.rtmp_stream, LaunchActivity.this, fragment, accountInstance); - })); + TLRPC.ChatFull chatFull = accountInstance.getMessagesController().getChatFull(-dialog_id); + if (chatFull != null) { + if (chatFull.call == null) { + if (voipLastFragment.getParentActivity() != null) { + BulletinFactory.of(voipLastFragment).createSimpleBulletin(R.raw.linkbroken, LocaleController.getString("InviteExpired", R.string.InviteExpired)).show(); + } + } else { + accountInstance.getMessagesController().getGroupCall(-dialog_id, true, () -> AndroidUtilities.runOnUIThread(() -> { + ChatObject.Call call = accountInstance.getMessagesController().getGroupCall(-dialog_id, false); + VoIPHelper.startCall(accountInstance.getMessagesController().getChat(-dialog_id), accountInstance.getMessagesController().getInputPeer(dialog_id), null, false, call == null || !call.call.rtmp_stream, LaunchActivity.this, voipLastFragment, accountInstance); + })); + } + } } } }, 150); @@ -4208,6 +4369,7 @@ public class LaunchActivity extends BasePermissionsActivity implements ActionBar fragment.onActivityResultFragment(requestCode, resultCode, data); } } + NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.onActivityResultReceived, requestCode, resultCode, data); } } @@ -4232,11 +4394,13 @@ public class LaunchActivity extends BasePermissionsActivity implements ActionBar } VoIPFragment.onRequestPermissionsResult(requestCode, permissions, grantResults); + NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.onRequestPermissionResultReceived, requestCode, permissions, grantResults); } @Override protected void onPause() { super.onPause(); + isResumed = false; NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.stopAllHeavyOperations, 4096); ApplicationLoader.mainInterfacePaused = true; int account = currentAccount; @@ -4346,6 +4510,11 @@ public class LaunchActivity extends BasePermissionsActivity implements ActionBar @Override protected void onResume() { super.onResume(); + isResumed = true; + if (onResumeStaticCallback != null) { + onResumeStaticCallback.run(); + onResumeStaticCallback = null; + } if (Theme.selectedAutoNightType == Theme.AUTO_NIGHT_TYPE_SYSTEM) { Theme.checkAutoNightThemeConditions(); } @@ -4848,6 +5017,12 @@ public class LaunchActivity extends BasePermissionsActivity implements ActionBar } else { BulletinFactory.of(container, null).createErrorBulletin((String) args[1]).show(); } + } if (type == Bulletin.TYPE_ERROR_SUBTITLE) { + if (fragment != null) { + BulletinFactory.of(fragment).createErrorBulletinSubtitle((String) args[1], (String) args[2], fragment.getResourceProvider()).show(); + } else { + BulletinFactory.of(container, null).createErrorBulletinSubtitle((String) args[1], (String) args[2], null).show(); + } } } } else if (id == NotificationCenter.groupCallUpdated) { @@ -5470,7 +5645,12 @@ public class LaunchActivity extends BasePermissionsActivity implements ActionBar } } } - return super.dispatchKeyEvent(event); + try { + super.dispatchKeyEvent(event); + } catch (Exception e) { + FileLog.e(e); + } + return false; } @Override diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ManageLinksActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ManageLinksActivity.java index 1b7bc509e..72524c5fe 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ManageLinksActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ManageLinksActivity.java @@ -51,9 +51,9 @@ 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.CreationTextCell; import org.telegram.ui.Cells.HeaderCell; import org.telegram.ui.Cells.ManageChatTextCell; import org.telegram.ui.Cells.ManageChatUserCell; @@ -68,9 +68,9 @@ import org.telegram.ui.Components.FlickerLoadingView; import org.telegram.ui.Components.InviteLinkBottomSheet; import org.telegram.ui.Components.LayoutHelper; import org.telegram.ui.Components.LinkActionView; +import org.telegram.ui.Components.RecyclerItemsEnterAnimator; import org.telegram.ui.Components.RecyclerListView; import org.telegram.ui.Components.TimerParticles; -import org.telegram.ui.Components.RecyclerItemsEnterAnimator; import java.util.ArrayList; import java.util.HashMap; @@ -764,7 +764,7 @@ public class ManageLinksActivity extends BaseFragment { view.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); break; case 3: - view = new TextCell(mContext); + view = new CreationTextCell(mContext); view.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); break; case 4: @@ -851,7 +851,7 @@ public class ManageLinksActivity extends BaseFragment { } break; case 3: - TextCell textCell = (TextCell) holder.itemView; + CreationTextCell textCell = (CreationTextCell) holder.itemView; Drawable drawable1 = mContext.getResources().getDrawable(R.drawable.poll_add_circle); Drawable drawable2 = mContext.getResources().getDrawable(R.drawable.poll_add_plus); drawable1.setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_switchTrackChecked), PorterDuff.Mode.MULTIPLY)); @@ -973,71 +973,6 @@ public class ManageLinksActivity extends BaseFragment { } } - public static class TextCell extends FrameLayout { - - private SimpleTextView textView; - private ImageView imageView; - boolean divider; - - public TextCell(Context context) { - super(context); - - textView = new SimpleTextView(context); - textView.setTextSize(16); - textView.setGravity(LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT); - textView.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlueText2)); - textView.setTag(Theme.key_windowBackgroundWhiteBlueText2); - addView(textView); - - imageView = new ImageView(context); - imageView.setScaleType(ImageView.ScaleType.CENTER); - addView(imageView); - setWillNotDraw(false); - } - - @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - int width = MeasureSpec.getSize(widthMeasureSpec); - int height = AndroidUtilities.dp(48); - - textView.measure(MeasureSpec.makeMeasureSpec(width - AndroidUtilities.dp(71 + 23), MeasureSpec.AT_MOST), MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(20), MeasureSpec.EXACTLY)); - imageView.measure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.AT_MOST), MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(50), MeasureSpec.EXACTLY)); - setMeasuredDimension(width, AndroidUtilities.dp(50)); - } - - @Override - protected void onLayout(boolean changed, int left, int top, int right, int bottom) { - int height = bottom - top; - int width = right - left; - - int viewLeft; - int viewTop = (height - textView.getTextHeight()) / 2; - if (LocaleController.isRTL) { - viewLeft = getMeasuredWidth() - textView.getMeasuredWidth() - AndroidUtilities.dp(imageView.getVisibility() == VISIBLE ? 70 : 25); - } else { - viewLeft = AndroidUtilities.dp(imageView.getVisibility() == VISIBLE ? 70 : 25); - } - textView.layout(viewLeft, viewTop, viewLeft + textView.getMeasuredWidth(), viewTop + textView.getMeasuredHeight()); - - viewLeft = !LocaleController.isRTL ? (AndroidUtilities.dp(70) - imageView.getMeasuredWidth()) / 2 : width - imageView.getMeasuredWidth() - AndroidUtilities.dp(25); - imageView.layout(viewLeft, 0, viewLeft + imageView.getMeasuredWidth(), imageView.getMeasuredHeight()); - } - - @Override - protected void onDraw(Canvas canvas) { - super.onDraw(canvas); - if (divider) { - canvas.drawLine(AndroidUtilities.dp(70), getMeasuredHeight() - 1, getMeasuredWidth() + AndroidUtilities.dp(23), getMeasuredHeight(), Theme.dividerPaint); - } - } - - public void setTextAndIcon(String text, Drawable icon, boolean divider) { - textView.setText(text); - imageView.setImageDrawable(icon); - this.divider = divider; - } - } - private class LinkCell extends FrameLayout { private final static int LINK_STATE_BLUE = 0; @@ -1693,7 +1628,7 @@ public class ManageLinksActivity extends BaseFragment { } }; - themeDescriptions.add(new ThemeDescription(listView, ThemeDescription.FLAG_CELLBACKGROUNDCOLOR, new Class[]{HeaderCell.class, TextCell.class, LinkActionView.class, LinkCell.class}, null, null, null, Theme.key_windowBackgroundWhite)); + themeDescriptions.add(new ThemeDescription(listView, ThemeDescription.FLAG_CELLBACKGROUNDCOLOR, new Class[]{HeaderCell.class, CreationTextCell.class, LinkActionView.class, LinkCell.class}, null, null, null, Theme.key_windowBackgroundWhite)); themeDescriptions.add(new ThemeDescription(fragmentView, ThemeDescription.FLAG_BACKGROUND | ThemeDescription.FLAG_CHECKTAG, null, null, null, null, Theme.key_windowBackgroundGray)); themeDescriptions.add(new ThemeDescription(fragmentView, ThemeDescription.FLAG_BACKGROUND | ThemeDescription.FLAG_CHECKTAG, null, null, null, null, Theme.key_windowBackgroundWhite)); @@ -1729,9 +1664,9 @@ public class ManageLinksActivity extends BaseFragment { themeDescriptions.add(new ThemeDescription(listView, ThemeDescription.FLAG_CHECKTAG, new Class[]{ManageChatTextCell.class}, new String[]{"imageView"}, null, null, null, Theme.key_windowBackgroundWhiteBlueButton)); themeDescriptions.add(new ThemeDescription(listView, ThemeDescription.FLAG_CHECKTAG, new Class[]{ManageChatTextCell.class}, new String[]{"textView"}, null, null, null, Theme.key_windowBackgroundWhiteBlueIcon)); - themeDescriptions.add(new ThemeDescription(listView, 0, new Class[]{TextCell.class}, new String[]{"textView"}, null, null, null, Theme.key_windowBackgroundWhiteBlueText2)); - themeDescriptions.add(new ThemeDescription(listView, ThemeDescription.FLAG_BACKGROUNDFILTER, new Class[]{TextCell.class}, new String[]{"imageView"}, null, null, null, Theme.key_switchTrackChecked)); - themeDescriptions.add(new ThemeDescription(listView, 0, new Class[]{TextCell.class}, new String[]{"imageView"}, null, null, null, Theme.key_checkboxCheck)); + themeDescriptions.add(new ThemeDescription(listView, 0, new Class[]{CreationTextCell.class}, new String[]{"textView"}, null, null, null, Theme.key_windowBackgroundWhiteBlueText2)); + themeDescriptions.add(new ThemeDescription(listView, ThemeDescription.FLAG_BACKGROUNDFILTER, new Class[]{CreationTextCell.class}, new String[]{"imageView"}, null, null, null, Theme.key_switchTrackChecked)); + themeDescriptions.add(new ThemeDescription(listView, 0, new Class[]{CreationTextCell.class}, new String[]{"imageView"}, null, null, null, Theme.key_checkboxCheck)); themeDescriptions.add(new ThemeDescription(listView, 0, new Class[]{HeaderCell.class}, new String[]{"textView"}, null, null, null, Theme.key_windowBackgroundWhiteBlueHeader)); themeDescriptions.add(new ThemeDescription(listView, 0, new Class[]{LinkCell.class}, new String[]{"titleView"}, null, null, null, Theme.key_windowBackgroundWhiteBlackText)); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/NotificationsCustomSettingsActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/NotificationsCustomSettingsActivity.java index de1eaf95d..d9f09fe2c 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/NotificationsCustomSettingsActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/NotificationsCustomSettingsActivity.java @@ -30,6 +30,9 @@ import android.widget.EditText; import android.widget.FrameLayout; import android.widget.TextView; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; + import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.ChatObject; import org.telegram.messenger.ContactsController; @@ -68,10 +71,7 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.Map; -import androidx.recyclerview.widget.LinearLayoutManager; -import androidx.recyclerview.widget.RecyclerView; - -public class NotificationsCustomSettingsActivity extends BaseFragment { +public class NotificationsCustomSettingsActivity extends BaseFragment implements NotificationCenter.NotificationCenterDelegate { private RecyclerListView listView; private ListAdapter adapter; @@ -435,39 +435,42 @@ public class NotificationsCustomSettingsActivity extends BaseFragment { return; } try { - SharedPreferences preferences = getNotificationsSettings(); - Intent tmpIntent = new Intent(RingtoneManager.ACTION_RINGTONE_PICKER); - tmpIntent.putExtra(RingtoneManager.EXTRA_RINGTONE_TYPE, RingtoneManager.TYPE_NOTIFICATION); - tmpIntent.putExtra(RingtoneManager.EXTRA_RINGTONE_SHOW_DEFAULT, true); - tmpIntent.putExtra(RingtoneManager.EXTRA_RINGTONE_SHOW_SILENT, true); - tmpIntent.putExtra(RingtoneManager.EXTRA_RINGTONE_DEFAULT_URI, RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION)); - Uri currentSound = null; - - String defaultPath = null; - Uri defaultUri = Settings.System.DEFAULT_NOTIFICATION_URI; - if (defaultUri != null) { - defaultPath = defaultUri.getPath(); - } - - String path; - if (currentType == NotificationsController.TYPE_PRIVATE) { - path = preferences.getString("GlobalSoundPath", defaultPath); - } else if (currentType == NotificationsController.TYPE_GROUP) { - path = preferences.getString("GroupSoundPath", defaultPath); - } else { - path = preferences.getString("ChannelSoundPath", defaultPath); - } - - if (path != null && !path.equals("NoSound")) { - if (path.equals(defaultPath)) { - currentSound = defaultUri; - } else { - currentSound = Uri.parse(path); - } - } - - tmpIntent.putExtra(RingtoneManager.EXTRA_RINGTONE_EXISTING_URI, currentSound); - startActivityForResult(tmpIntent, position); + Bundle bundle = new Bundle(); + bundle.putInt("type", currentType); + presentFragment(new NotificationsSoundActivity(bundle)); +// SharedPreferences preferences = getNotificationsSettings(); +// Intent tmpIntent = new Intent(RingtoneManager.ACTION_RINGTONE_PICKER); +// tmpIntent.putExtra(RingtoneManager.EXTRA_RINGTONE_TYPE, RingtoneManager.TYPE_NOTIFICATION); +// tmpIntent.putExtra(RingtoneManager.EXTRA_RINGTONE_SHOW_DEFAULT, true); +// tmpIntent.putExtra(RingtoneManager.EXTRA_RINGTONE_SHOW_SILENT, true); +// tmpIntent.putExtra(RingtoneManager.EXTRA_RINGTONE_DEFAULT_URI, RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION)); +// Uri currentSound = null; +// +// String defaultPath = null; +// Uri defaultUri = Settings.System.DEFAULT_NOTIFICATION_URI; +// if (defaultUri != null) { +// defaultPath = defaultUri.getPath(); +// } +// +// String path; +// if (currentType == NotificationsController.TYPE_PRIVATE) { +// path = preferences.getString("GlobalSoundPath", defaultPath); +// } else if (currentType == NotificationsController.TYPE_GROUP) { +// path = preferences.getString("GroupSoundPath", defaultPath); +// } else { +// path = preferences.getString("ChannelSoundPath", defaultPath); +// } +// +// if (path != null && !path.equals("NoSound")) { +// if (path.equals(defaultPath)) { +// currentSound = defaultUri; +// } else { +// currentSound = Uri.parse(path); +// } +// } +// +// tmpIntent.putExtra(RingtoneManager.EXTRA_RINGTONE_EXISTING_URI, currentSound); +// startActivityForResult(tmpIntent, position); } catch (Exception e) { FileLog.e(e); } @@ -863,6 +866,22 @@ public class NotificationsCustomSettingsActivity extends BaseFragment { if (adapter != null) { adapter.notifyDataSetChanged(); } + getNotificationCenter().addObserver(this, NotificationCenter.notificationsSettingsUpdated); + } + + @Override + public void onPause() { + super.onPause(); + getNotificationCenter().removeObserver(this, NotificationCenter.notificationsSettingsUpdated); + } + + @Override + public void didReceivedNotification(int id, int account, Object... args) { + if (id == NotificationCenter.notificationsSettingsUpdated) { + if (adapter != null) { + adapter.notifyDataSetChanged(); + } + } } private class SearchAdapter extends RecyclerListView.SelectionAdapter { @@ -1215,15 +1234,24 @@ public class NotificationsCustomSettingsActivity extends BaseFragment { SharedPreferences preferences = getNotificationsSettings(); if (position == messageSoundRow) { String value; + long documentId; if (currentType == NotificationsController.TYPE_PRIVATE) { value = preferences.getString("GlobalSound", LocaleController.getString("SoundDefault", R.string.SoundDefault)); + documentId = preferences.getLong("GlobalSoundDocId", 0); } else if (currentType == NotificationsController.TYPE_GROUP) { value = preferences.getString("GroupSound", LocaleController.getString("SoundDefault", R.string.SoundDefault)); + documentId = preferences.getLong("GroupSoundDocId", 0); } else { value = preferences.getString("ChannelSound", LocaleController.getString("SoundDefault", R.string.SoundDefault)); + documentId = preferences.getLong("ChannelDocId", 0); } - if (value.equals("NoSound")) { + if (documentId != 0) { + TLRPC.Document document = getMediaDataController().ringtoneDataStore.getDocument(documentId); + value = NotificationsSoundActivity.trimTitle(document, document.file_name_fixed); + } else if (value.equals("NoSound")) { value = LocaleController.getString("NoSound", R.string.NoSound); + } else if (value.equals("Default")) { + value = LocaleController.getString("SoundDefault", R.string.SoundDefault); } textCell.setTextAndValue(LocaleController.getString("Sound", R.string.Sound), value, true); } else if (position == messageVibrateRow) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/NotificationsSettingsActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/NotificationsSettingsActivity.java index 80d4df5bf..86d61b3d6 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/NotificationsSettingsActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/NotificationsSettingsActivity.java @@ -26,23 +26,28 @@ import android.widget.FrameLayout; import android.widget.TextView; import android.widget.Toast; +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.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.NotificationsController; import org.telegram.messenger.NotificationCenter; -import org.telegram.messenger.ApplicationLoader; +import org.telegram.messenger.NotificationsController; +import org.telegram.messenger.R; import org.telegram.messenger.SharedConfig; import org.telegram.messenger.UserConfig; import org.telegram.messenger.Utilities; import org.telegram.tgnet.ConnectionsManager; import org.telegram.tgnet.TLRPC; -import org.telegram.messenger.FileLog; -import org.telegram.messenger.MessagesController; -import org.telegram.messenger.R; +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.ActionBar.ThemeDescription; import org.telegram.ui.Cells.HeaderCell; @@ -50,8 +55,6 @@ import org.telegram.ui.Cells.NotificationsCheckCell; import org.telegram.ui.Cells.ShadowSectionCell; import org.telegram.ui.Cells.TextCheckCell; import org.telegram.ui.Cells.TextDetailSettingsCell; -import org.telegram.ui.ActionBar.ActionBar; -import org.telegram.ui.ActionBar.BaseFragment; import org.telegram.ui.Cells.TextInfoPrivacyCell; import org.telegram.ui.Cells.TextSettingsCell; import org.telegram.ui.Components.AlertsCreator; @@ -61,9 +64,6 @@ import org.telegram.ui.Components.RecyclerListView; import java.util.ArrayList; import java.util.Map; -import androidx.recyclerview.widget.LinearLayoutManager; -import androidx.recyclerview.widget.RecyclerView; - public class NotificationsSettingsActivity extends BaseFragment implements NotificationCenter.NotificationCenterDelegate { public static class NotificationException { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/NotificationsSoundActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/NotificationsSoundActivity.java new file mode 100644 index 000000000..4678b8d6e --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/NotificationsSoundActivity.java @@ -0,0 +1,956 @@ +package org.telegram.ui; + +import android.app.NotificationManager; +import android.content.ClipData; +import android.content.Context; +import android.content.DialogInterface; +import android.content.Intent; +import android.content.SharedPreferences; +import android.database.Cursor; +import android.graphics.Canvas; +import android.graphics.PorterDuff; +import android.graphics.PorterDuffColorFilter; +import android.graphics.drawable.Drawable; +import android.media.AudioManager; +import android.media.Ringtone; +import android.media.RingtoneManager; +import android.net.Uri; +import android.os.Build; +import android.os.Bundle; +import android.text.TextUtils; +import android.util.SparseArray; +import android.util.TypedValue; +import android.view.Gravity; +import android.view.HapticFeedbackConstants; +import android.view.View; +import android.view.ViewGroup; +import android.view.accessibility.AccessibilityNodeInfo; +import android.widget.FrameLayout; +import android.widget.TextView; + +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.ApplicationLoader; +import org.telegram.messenger.ContactsController; +import org.telegram.messenger.FileLoader; +import org.telegram.messenger.FileLog; +import org.telegram.messenger.LocaleController; +import org.telegram.messenger.MessageObject; +import org.telegram.messenger.NotificationCenter; +import org.telegram.messenger.NotificationsController; +import org.telegram.messenger.R; +import org.telegram.messenger.ringtone.RingtoneDataStore; +import org.telegram.messenger.ringtone.RingtoneUploader; +import org.telegram.tgnet.TLRPC; +import org.telegram.ui.ActionBar.ActionBar; +import org.telegram.ui.ActionBar.ActionBarMenu; +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.Cells.CreationTextCell; +import org.telegram.ui.Cells.HeaderCell; +import org.telegram.ui.Cells.ShadowSectionCell; +import org.telegram.ui.Components.ChatAttachAlert; +import org.telegram.ui.Components.ChatAttachAlertDocumentLayout; +import org.telegram.ui.Components.ChatAvatarContainer; +import org.telegram.ui.Components.CheckBox2; +import org.telegram.ui.Components.CombinedDrawable; +import org.telegram.ui.Components.LayoutHelper; +import org.telegram.ui.Components.NumberTextView; +import org.telegram.ui.Components.RadioButton; +import org.telegram.ui.Components.RecyclerListView; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; + +public class NotificationsSoundActivity extends BaseFragment implements ChatAttachAlertDocumentLayout.DocumentSelectActivityDelegate, NotificationCenter.NotificationCenterDelegate { + + ArrayList serverTones = new ArrayList<>(); + ArrayList systemTones = new ArrayList<>(); + ArrayList uploadingTones = new ArrayList<>(); + + NumberTextView selectedTonesCountTextView; + RecyclerListView listView; + Adapter adapter; + + int rowCount; + int serverTonesHeaderRow; + int serverTonesStartRow; + int serverTonesEndRow; + + int uploadRow; + + int dividerRow; + int dividerRow2; + + int systemTonesHeaderRow; + int systemTonesStartRow; + int systemTonesEndRow; + + private int stableIds = 100; + + Tone selectedTone; + boolean selectedToneChanged; + + SparseArray selectedTones = new SparseArray<>(); + private final static int deleteId = 1; + private final static int shareId = 2; + + ChatAvatarContainer avatarContainer; + long dialogId; + int currentType = -1; + + + private Tone startSelectedTone; + ChatAttachAlert chatAttachAlert; + Ringtone lastPlayedRingtone; + + private final int tonesStreamType = AudioManager.STREAM_ALARM; + + public NotificationsSoundActivity(Bundle args) { + super(args); + } + + @Override + public boolean onFragmentCreate() { + if (getArguments() != null) { + dialogId = getArguments().getLong("dialog_id", 0); + currentType = getArguments().getInt("type", -1); + } + String prefPath; + String prefDocId; + if (dialogId != 0) { + prefDocId = "sound_document_id_" + dialogId; + prefPath = "sound_path_" + dialogId; + } else { + if (currentType == NotificationsController.TYPE_PRIVATE) { + prefPath = "GlobalSoundPath"; + prefDocId = "GlobalSoundDocId"; + } else if (currentType == NotificationsController.TYPE_GROUP) { + prefPath = "GroupSoundPath"; + prefDocId = "GroupSoundDocId"; + } else if (currentType == NotificationsController.TYPE_CHANNEL) { + prefPath = "ChannelSoundPath"; + prefDocId = "ChannelSoundDocId"; + } else { + throw new RuntimeException("Unsupported type"); + } + } + + SharedPreferences preferences = getNotificationsSettings(); + long documentId = preferences.getLong(prefDocId, 0); + String localUri = preferences.getString(prefPath, "NoSound"); + + startSelectedTone = new Tone(); + if (documentId != 0) { + startSelectedTone.document = new TLRPC.TL_document(); + startSelectedTone.document.id = documentId; + } else { + startSelectedTone.uri = localUri; + } + return super.onFragmentCreate(); + } + + @Override + public View createView(final Context context) { + actionBar.setBackButtonDrawable(new BackDrawable(false)); + actionBar.setAllowOverlayTitle(false); + actionBar.setActionBarMenuOnItemClick(new ActionBar.ActionBarMenuOnItemClick() { + @Override + public void onItemClick(int id) { + if (id == -1) { + if (actionBar.isActionModeShowed()) { + hideActionMode(); + } else { + finishFragment(); + } + } else if (id == deleteId) { + AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); + builder.setTitle(LocaleController.formatPluralString("DeleteTones", selectedTones.size())); + builder.setMessage(AndroidUtilities.replaceTags(LocaleController.formatPluralString("DeleteTonesMessage", selectedTones.size()))); + builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), (dialog, which) -> { + dialog.dismiss(); + }); + builder.setPositiveButton(LocaleController.getString("Delete", R.string.Delete), (dialog, which) -> { + deleteSelectedMessages(); + dialog.dismiss(); + }); + AlertDialog dialog = builder.show(); + TextView button = (TextView) dialog.getButton(DialogInterface.BUTTON_POSITIVE); + if (button != null) { + button.setTextColor(Theme.getColor(Theme.key_dialogTextRed2)); + } + } else if (id == shareId) { + if (selectedTones.size() == 1) { + Intent intent = new Intent(context, LaunchActivity.class); + intent.setAction(Intent.ACTION_SEND); + + Uri uri = selectedTones.valueAt(0).getUriForShare(currentAccount); + if (uri != null) { + intent.putExtra(Intent.EXTRA_STREAM, uri); + context.startActivity(intent); + } + } else { + Intent intent = new Intent(context, LaunchActivity.class); + intent.setAction(Intent.ACTION_SEND_MULTIPLE); + + ArrayList uries = new ArrayList<>(); + for(int i = 0; i < selectedTones.size(); i++) { + Uri uri = selectedTones.valueAt(i).getUriForShare(currentAccount); + if (uri != null) { + uries.add(uri); + } + + } + if (!uries.isEmpty()) { + intent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, uries); + context.startActivity(intent); + } + } + + hideActionMode(); + updateRows(); + adapter.notifyDataSetChanged(); + } + } + + private void deleteSelectedMessages() { + ArrayList documentsToRemove = new ArrayList<>(); + for (int i = 0; i < selectedTones.size(); i++) { + Tone tone = selectedTones.valueAt(i); + if (tone.document != null) { + documentsToRemove.add(tone.document); + getMediaDataController().ringtoneDataStore.remove(tone.document); + } + if (tone.uri != null) { + RingtoneUploader ringtoneUploader = getMediaDataController().ringtoneUploaderHashMap.get(tone.uri); + if (ringtoneUploader != null) { + ringtoneUploader.cancel(); + } + } + if (tone == selectedTone) { + startSelectedTone = null; + selectedTone = systemTones.get(0); + selectedToneChanged = true; + } + serverTones.remove(tone); + uploadingTones.remove(tone); + } + getMediaDataController().ringtoneDataStore.saveTones(); + + for (int i = 0; i < documentsToRemove.size(); i++) { + TLRPC.Document document = documentsToRemove.get(i); + TLRPC.TL_account_saveRingtone req = new TLRPC.TL_account_saveRingtone(); + req.id = new TLRPC.TL_inputDocument(); + req.id.id = document.id; + req.id.access_hash = document.access_hash; + req.id.file_reference = document.file_reference; + if (req.id.file_reference == null) { + req.id.file_reference = new byte[0]; + } + req.unsave = true; + getConnectionsManager().sendRequest(req, (response, error) -> { + + }); + } + hideActionMode(); + updateRows(); + adapter.notifyDataSetChanged(); + } + }); + + if (dialogId == 0) { + if (currentType == NotificationsController.TYPE_PRIVATE) { + actionBar.setTitle(LocaleController.getString("NotificationsSoundPrivate", R.string.NotificationsSoundPrivate)); + } else if (currentType == NotificationsController.TYPE_GROUP) { + actionBar.setTitle(LocaleController.getString("NotificationsSoundGroup", R.string.NotificationsSoundGroup)); + } else if (currentType == NotificationsController.TYPE_CHANNEL) { + actionBar.setTitle(LocaleController.getString("NotificationsSoundChannels", R.string.NotificationsSoundChannels)); + } + } else { + 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)); + if (dialogId < 0) { + TLRPC.Chat chatLocal = getMessagesController().getChat(-dialogId); + avatarContainer.setChatAvatar(chatLocal); + avatarContainer.setTitle(chatLocal.title); + } else { + TLRPC.User user = getMessagesController().getUser(dialogId); + avatarContainer.setUserAvatar(user); + avatarContainer.setTitle(ContactsController.formatName(user.first_name, user.last_name)); + } + avatarContainer.setSubtitle(LocaleController.getString("NotificationsSound", R.string.NotificationsSound)); + } + + final ActionBarMenu actionMode = actionBar.createActionMode(); + + selectedTonesCountTextView = new NumberTextView(actionMode.getContext()); + selectedTonesCountTextView.setTextSize(18); + selectedTonesCountTextView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); + selectedTonesCountTextView.setTextColor(Theme.getColor(Theme.key_actionBarActionModeDefaultIcon)); + actionMode.addView(selectedTonesCountTextView, LayoutHelper.createLinear(0, LayoutHelper.MATCH_PARENT, 1.0f, 72, 0, 0, 0)); + selectedTonesCountTextView.setOnTouchListener((v, event) -> true); + + actionMode.addItemWithWidth(shareId, R.drawable.msg_forward, AndroidUtilities.dp(54), LocaleController.getString("ShareFile", R.string.ShareFile)); + actionMode.addItemWithWidth(deleteId, R.drawable.msg_delete, AndroidUtilities.dp(54), LocaleController.getString("Delete", R.string.Delete)); + + fragmentView = new FrameLayout(context); + FrameLayout frameLayout = (FrameLayout) fragmentView; + frameLayout.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundGray)); + + listView = new RecyclerListView(context); + frameLayout.addView(listView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); + adapter = new Adapter(); + adapter.setHasStableIds(true); + listView.setAdapter(adapter); + ((DefaultItemAnimator) listView.getItemAnimator()).setSupportsChangeAnimations(false); + ((DefaultItemAnimator) listView.getItemAnimator()).setDelayAnimations(false); + listView.setLayoutManager(new LinearLayoutManager(context)); + listView.setOnItemClickListener((view, position) -> { + if (position == uploadRow) { + chatAttachAlert = new ChatAttachAlert(context, NotificationsSoundActivity.this, false, false); + chatAttachAlert.setSoundPicker(); + chatAttachAlert.init(); + chatAttachAlert.show(); + } + if (view instanceof ToneCell) { + ToneCell cell = (ToneCell) view; + if (actionBar.isActionModeShowed()) { + checkSelection(cell.tone); + return; + } + if (lastPlayedRingtone != null) { + lastPlayedRingtone.stop(); + } + if (cell.tone.isSystemDefault) { + Ringtone r = RingtoneManager.getRingtone(context.getApplicationContext(), RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION)); + r.setStreamType(tonesStreamType); + lastPlayedRingtone = r; + r.play(); + } else if (cell.tone.uri != null && !cell.tone.fromServer) { + Ringtone r = RingtoneManager.getRingtone(context.getApplicationContext(), Uri.parse(cell.tone.uri)); + r.setStreamType(tonesStreamType); + lastPlayedRingtone = r; + r.play(); + } else if (cell.tone.fromServer) { + File file = null; + if (!TextUtils.isEmpty(cell.tone.uri)) { + File localUriFile = new File(cell.tone.uri); + if (localUriFile.exists()) { + file = localUriFile; + } + } + if (file == null) { + file = FileLoader.getPathToAttach(cell.tone.document); + } + if (file != null && file.exists()) { + Ringtone r = RingtoneManager.getRingtone(context.getApplicationContext(), Uri.parse(file.toString())); + r.setStreamType(tonesStreamType); + lastPlayedRingtone = r; + r.play(); + } else { + getFileLoader().loadFile(cell.tone.document, null, 2, 0); + } + } + startSelectedTone = null; + selectedTone = cell.tone; + selectedToneChanged = true; + adapter.notifyItemRangeChanged(0, adapter.getItemCount()); + checkDisabledBySystem(); + } + + }); + + listView.setOnItemLongClickListener((view, position) -> { + if (view instanceof ToneCell) { + ToneCell cell = (ToneCell) view; + checkSelection(cell.tone); + cell.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS); + } + return false; + }); + + loadTones(); + updateRows(); + return fragmentView; + } + + private void hideActionMode() { + selectedTones.clear(); + adapter.notifyItemRangeChanged(0, adapter.getItemCount()); + updateActionMode(); + } + + private void checkSelection(Tone tone) { + boolean changed = false; + if (selectedTones.get(tone.stableId) != null) { + selectedTones.remove(tone.stableId); + changed = true; + } else if (tone.fromServer) { + selectedTones.put(tone.stableId, tone); + changed = true; + } + if (changed) { + updateActionMode(); + adapter.notifyItemRangeChanged(0, adapter.getItemCount()); + } + } + + private void updateActionMode() { + if (selectedTones.size() > 0) { + selectedTonesCountTextView.setNumber(selectedTones.size(), actionBar.isActionModeShowed()); + actionBar.showActionMode(); + } else { + actionBar.hideActionMode(); + } + } + + private void loadTones() { + getMediaDataController().ringtoneDataStore.loadUserRingtones(); + for (int i = 0; i < getMediaDataController().ringtoneDataStore.userRingtones.size(); i++) { + RingtoneDataStore.CachedTone cachedTone = getMediaDataController().ringtoneDataStore.userRingtones.get(i); + Tone tone = new Tone(); + tone.stableId = stableIds++; + tone.fromServer = true; + tone.localId = cachedTone.localId; + tone.title = cachedTone.document.file_name_fixed; + tone.document = cachedTone.document; + trimTitle(tone); + + tone.uri = cachedTone.localUri; + + if (startSelectedTone != null && startSelectedTone.document != null && cachedTone.document != null && startSelectedTone.document.id == cachedTone.document.id) { + startSelectedTone = null; + selectedTone = tone; + } + + serverTones.add(tone); + } + + RingtoneManager manager = new RingtoneManager(ApplicationLoader.applicationContext); + manager.setType(RingtoneManager.TYPE_NOTIFICATION); + Cursor cursor = manager.getCursor(); + + systemTones.clear(); + + + Tone noSoundTone = new Tone(); + noSoundTone.stableId = stableIds++; + noSoundTone.title = LocaleController.getString("NoSound", R.string.NoSound); + noSoundTone.isSystemNoSound = true; + systemTones.add(noSoundTone); + + + Tone defaultTone = new Tone(); + defaultTone.stableId = stableIds++; + defaultTone.title = LocaleController.getString("DefaultRingtone", R.string.DefaultRingtone); + defaultTone.isSystemDefault = true; + systemTones.add(defaultTone); + + if (startSelectedTone != null && startSelectedTone.document == null && startSelectedTone.uri.equals("NoSound")) { + startSelectedTone = null; + selectedTone = noSoundTone; + } + + if (startSelectedTone != null && startSelectedTone.document == null && startSelectedTone.uri.equals("Default")) { + startSelectedTone = null; + selectedTone = defaultTone; + } + + while (cursor.moveToNext()) { + String notificationTitle = cursor.getString(RingtoneManager.TITLE_COLUMN_INDEX); + String notificationUri = cursor.getString(RingtoneManager.URI_COLUMN_INDEX) + "/" + cursor.getString(RingtoneManager.ID_COLUMN_INDEX); + + Tone tone = new Tone(); + tone.stableId = stableIds++; + tone.title = notificationTitle; + tone.uri = notificationUri; + + if (startSelectedTone != null && startSelectedTone.document == null && startSelectedTone.uri.equals(notificationUri)) { + startSelectedTone = null; + selectedTone = tone; + } + + systemTones.add(tone); + } + if (getMediaDataController().ringtoneDataStore.isLoaded() && selectedTone == null) { + selectedTone = defaultTone; + selectedToneChanged = true; + } + updateRows(); + } + + private void updateRows() { + serverTonesHeaderRow = -1; + serverTonesStartRow = -1; + serverTonesEndRow = -1; + uploadRow = -1; + dividerRow = -1; + systemTonesHeaderRow = -1; + systemTonesStartRow = -1; + systemTonesEndRow = -1; + + rowCount = 0; + + serverTonesHeaderRow = rowCount++; + if (!serverTones.isEmpty()) { + serverTonesStartRow = rowCount; + rowCount += serverTones.size(); + serverTonesEndRow = rowCount; + } + uploadRow = rowCount++; + dividerRow = rowCount++; + + if (!systemTones.isEmpty()) { + systemTonesHeaderRow = rowCount++; + systemTonesStartRow = rowCount; + rowCount += systemTones.size(); + systemTonesEndRow = rowCount; + } + dividerRow2 = rowCount++; + } + + @Override + public void didSelectFiles(ArrayList files, String caption, ArrayList fmessages, boolean notify, int scheduleDate) { + for (int i = 0; i < files.size(); i++) { + getMediaDataController().uploadRingtone(files.get(i)); + } + getNotificationCenter().postNotificationName(NotificationCenter.onUserRingtonesUpdated); + } + + private class Adapter extends RecyclerListView.SelectionAdapter { + + @Override + public long getItemId(int position) { + Tone tone = getTone(position); + if (tone != null) { + return tone.stableId; + } + if (position == serverTonesHeaderRow) { + return 1; + } else if (position == systemTonesHeaderRow) { + return 2; + } else if (position == uploadRow) { + return 3; + } else if (position == dividerRow) { + return 4; + } else if (position == dividerRow2) { + return 5; + } else { + throw new RuntimeException(); + } + } + + private Tone getTone(int position) { + if (position >= systemTonesStartRow && position < systemTonesEndRow) { + return systemTones.get(position - systemTonesStartRow); + } + if (position >= serverTonesStartRow && position < serverTonesEndRow) { + return serverTones.get(position - serverTonesStartRow); + } + return null; + } + + @NonNull + @Override + public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { + View view; + Context context = parent.getContext(); + switch (viewType) { + case 0: + view = new ToneCell(context); + view.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); + break; + default: + case 1: + view = new HeaderCell(context); + view.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); + break; + case 2: + CreationTextCell creationTextCell = new CreationTextCell(context); + creationTextCell.startPadding = 61; + view = creationTextCell; + view.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); + break; + case 3: + view = new ShadowSectionCell(context); + break; + } + view.setLayoutParams(new RecyclerView.LayoutParams(RecyclerView.LayoutParams.MATCH_PARENT, RecyclerView.LayoutParams.WRAP_CONTENT)); + return new RecyclerListView.Holder(view); + } + + @Override + public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) { + switch (holder.getItemViewType()) { + case 0: + ToneCell toneCell = (ToneCell) holder.itemView; + Tone tone = null; + if (position >= systemTonesStartRow && position < systemTonesEndRow) { + tone = systemTones.get(position - systemTonesStartRow); + } + if (position >= serverTonesStartRow && position < serverTonesEndRow) { + tone = serverTones.get(position - serverTonesStartRow); + } + + if (tone != null) { + boolean animated = toneCell.tone == tone; + boolean checked = tone == selectedTone; + boolean selected = selectedTones.get(tone.stableId) != null; + toneCell.tone = tone; + toneCell.textView.setText(tone.title); + toneCell.needDivider = position != systemTonesEndRow - 1; + toneCell.radioButton.setChecked(checked, animated); + toneCell.checkBox.setChecked(selected, animated); + } + break; + case 1: + HeaderCell headerCell = (HeaderCell) holder.itemView; + if (position == serverTonesHeaderRow) { + headerCell.setText(LocaleController.getString("TelegramTones", R.string.TelegramTones)); + } else if (position == systemTonesHeaderRow) { + headerCell.setText(LocaleController.getString("SystemTones", R.string.SystemTones)); + } + break; + case 2: + CreationTextCell textCell = (CreationTextCell) holder.itemView; + Drawable drawable1 = textCell.getContext().getResources().getDrawable(R.drawable.poll_add_circle); + Drawable drawable2 = textCell.getContext().getResources().getDrawable(R.drawable.poll_add_plus); + drawable1.setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_switchTrackChecked), PorterDuff.Mode.MULTIPLY)); + drawable2.setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_checkboxCheck), PorterDuff.Mode.MULTIPLY)); + CombinedDrawable combinedDrawable = new CombinedDrawable(drawable1, drawable2); + textCell.setTextAndIcon(LocaleController.getString("UploadSound", R.string.UploadSound), combinedDrawable, false); + break; + } + } + + @Override + public int getItemViewType(int position) { + if (position >= systemTonesStartRow && position < systemTonesEndRow) { + return 0; + } else if (position == serverTonesHeaderRow || position == systemTonesHeaderRow) { + return 1; + } else if (position == uploadRow) { + return 2; + } else if (position == dividerRow || position == dividerRow2) { + return 3; + } + + return super.getItemViewType(position); + } + + @Override + public int getItemCount() { + return rowCount; + } + + @Override + public boolean isEnabled(RecyclerView.ViewHolder holder) { + return holder.getItemViewType() == 0 || holder.getItemViewType() == 2; + } + } + + private static class ToneCell extends FrameLayout { + private TextView textView; + public TextView valueTextView; + private RadioButton radioButton; + private CheckBox2 checkBox; + private boolean needDivider; + + Tone tone; + + public ToneCell(Context context) { + super(context); + + radioButton = new RadioButton(context); + radioButton.setSize(AndroidUtilities.dp(20)); + radioButton.setColor(Theme.getColor(Theme.key_radioBackground), Theme.getColor(Theme.key_radioBackgroundChecked)); + addView(radioButton, LayoutHelper.createFrame(22, 22, (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.CENTER_VERTICAL, (LocaleController.isRTL ? 0 : 20), 0, (LocaleController.isRTL ? 20 : 0), 0)); + + + checkBox = new CheckBox2(context, 24); + checkBox.setColor(null, Theme.key_windowBackgroundWhite, Theme.key_checkboxCheck); + checkBox.setDrawUnchecked(false); + checkBox.setDrawBackgroundAsArc(3); + addView(checkBox, LayoutHelper.createFrame(26, 26, (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.CENTER_VERTICAL, (LocaleController.isRTL ? 0 : 18), 0, (LocaleController.isRTL ? 18 : 0), 0)); + checkBox.setChecked(true, false); + + textView = new TextView(context); + textView.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlackText)); + textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16); + textView.setLines(1); + textView.setMaxLines(1); + textView.setSingleLine(true); + textView.setEllipsize(TextUtils.TruncateAt.END); + textView.setGravity((LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.CENTER_VERTICAL); + + addView(textView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.CENTER_VERTICAL, (LocaleController.isRTL ? 23 : 61), 0, (LocaleController.isRTL ? 61 : 23), 0)); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.EXACTLY), View.MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(50), MeasureSpec.EXACTLY)); + } + + @Override + protected void onDraw(Canvas canvas) { + if (needDivider) { + canvas.drawLine(AndroidUtilities.dp(LocaleController.isRTL ? 0 : 60), getHeight() - 1, getMeasuredWidth() - AndroidUtilities.dp(LocaleController.isRTL ? 60 : 0), getHeight() - 1, Theme.dividerPaint); + } + } + + @Override + public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) { + super.onInitializeAccessibilityNodeInfo(info); + info.setClassName("android.widget.RadioButton"); + info.setCheckable(true); + info.setChecked(radioButton.isChecked()); + } + } + + @Override + public void onResume() { + super.onResume(); + getNotificationCenter().addObserver(this, NotificationCenter.onUserRingtonesUpdated); + } + + @Override + public void onPause() { + super.onPause(); + getNotificationCenter().removeObserver(this, NotificationCenter.onUserRingtonesUpdated); + } + + @Override + public void didReceivedNotification(int id, int account, Object... args) { + if (id == NotificationCenter.onUserRingtonesUpdated) { + HashMap currentTones = new HashMap<>(); + for (int i = 0; i < serverTones.size(); i++) { + currentTones.put(serverTones.get(i).localId, serverTones.get(i)); + } + serverTones.clear(); + for (int i = 0; i < getMediaDataController().ringtoneDataStore.userRingtones.size(); i++) { + RingtoneDataStore.CachedTone cachedTone = getMediaDataController().ringtoneDataStore.userRingtones.get(i); + Tone tone = new Tone(); + Tone currentTone = currentTones.get(cachedTone.localId); + if (currentTone != null) { + if (currentTone == selectedTone) { + selectedTone = tone; + } + tone.stableId = currentTone.stableId; + } else { + tone.stableId = stableIds++; + } + tone.fromServer = true; + tone.localId = cachedTone.localId; + if (cachedTone.document != null) { + tone.title = cachedTone.document.file_name_fixed; + } else { + tone.title = new File(cachedTone.localUri).getName(); + } + tone.document = cachedTone.document; + trimTitle(tone); + tone.uri = cachedTone.localUri; + + if (startSelectedTone != null && startSelectedTone.document != null && cachedTone.document != null && startSelectedTone.document.id == cachedTone.document.id) { + startSelectedTone = null; + selectedTone = tone; + } + + serverTones.add(tone); + } + updateRows(); + adapter.notifyDataSetChanged(); + + if (getMediaDataController().ringtoneDataStore.isLoaded() && selectedTone == null && systemTones.size() > 0) { + startSelectedTone = null; + selectedTone = systemTones.get(0); + } + } + } + + private void trimTitle(Tone tone) { + tone.title = trimTitle(tone.document, tone.title); + } + + public static String trimTitle(TLRPC.Document document, String title) { + if (title != null) { + int idx = title.lastIndexOf('.'); + if (idx != -1) { + title = title.substring(0, idx); + } + } + if (TextUtils.isEmpty(title) && document != null) { + title = LocaleController.formatString("SoundNameEmpty", R.string.SoundNameEmpty, LocaleController.formatDateChat(document.date, true)); + } + return title; + } + + @Override + public void onFragmentDestroy() { + super.onFragmentDestroy(); + if (selectedTone != null && selectedToneChanged) { + SharedPreferences preferences = getNotificationsSettings(); + SharedPreferences.Editor editor = preferences.edit(); + + String prefName; + String prefPath; + String prefDocId; + + if (dialogId != 0) { + prefName = "sound_" + dialogId; + prefPath = "sound_path_" + dialogId; + prefDocId = "sound_document_id_" + dialogId; + editor.putBoolean("sound_enabled_" + dialogId, true); + } else { + if (currentType == NotificationsController.TYPE_PRIVATE) { + prefName = "GlobalSound"; + prefPath = "GlobalSoundPath"; + prefDocId = "GlobalSoundDocId"; + } else if (currentType == NotificationsController.TYPE_GROUP) { + prefName = "GroupSound"; + prefPath = "GroupSoundPath"; + prefDocId = "GroupSoundDocId"; + } else if (currentType == NotificationsController.TYPE_CHANNEL) { + prefName = "ChannelSound"; + prefPath = "ChannelSoundPath"; + prefDocId = "ChannelSoundDocId"; + } else { + throw new RuntimeException("Unsupported type"); + } + } + + if (selectedTone.fromServer && selectedTone.document != null) { + editor.putLong(prefDocId, selectedTone.document.id); + editor.putString(prefName, selectedTone.title); + editor.putString(prefPath, "NoSound"); + } else if (selectedTone.uri != null) { + editor.putString(prefName, selectedTone.title); + editor.putString(prefPath, selectedTone.uri); + editor.remove(prefDocId); + } else if (selectedTone.isSystemDefault) { + editor.putString(prefName, "Default"); + editor.putString(prefPath, "Default"); + editor.remove(prefDocId); + } else { + editor.putString(prefName, "NoSound"); + editor.putString(prefPath, "NoSound"); + editor.remove(prefDocId); + } + + editor.apply(); + if (dialogId != 0) { + getNotificationsController().updateServerNotificationsSettings(dialogId); + } else { + getNotificationsController().updateServerNotificationsSettings(currentType); + getNotificationCenter().postNotificationName(NotificationCenter.notificationsSettingsUpdated); + } + } + } + + public void startDocumentSelectActivity() { + try { + Intent photoPickerIntent = new Intent(Intent.ACTION_GET_CONTENT); + if (Build.VERSION.SDK_INT >= 18) { + photoPickerIntent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true); + } + photoPickerIntent.setType("audio/mpeg"); + startActivityForResult(photoPickerIntent, 21); + } catch (Exception e) { + FileLog.e(e); + } + } + + @Override + public void onActivityResultFragment(int requestCode, int resultCode, Intent data) { + if (requestCode == 21) { + if (data == null) { + return; + } + + if (chatAttachAlert != null) { + boolean apply = false; + if (data.getData() != null) { + String path = AndroidUtilities.getPath(data.getData()); + if (path != null) { + File file = new File(path); + if (chatAttachAlert.getDocumentLayout().isRingtone(file)) { + apply = true; + getMediaDataController().uploadRingtone(path); + getNotificationCenter().postNotificationName(NotificationCenter.onUserRingtonesUpdated); + } + } + } else if (data.getClipData() != null) { + ClipData clipData = data.getClipData(); + for (int i = 0; i < clipData.getItemCount(); i++) { + String path = clipData.getItemAt(i).getUri().toString(); + if (chatAttachAlert.getDocumentLayout().isRingtone(new File(path))) { + apply = true; + getMediaDataController().uploadRingtone(path); + getNotificationCenter().postNotificationName(NotificationCenter.onUserRingtonesUpdated); + } + } + } + if (apply) { + chatAttachAlert.dismiss(); + } + } + } + } + + private static class Tone { + public boolean fromServer; + boolean isSystemDefault; + boolean isSystemNoSound; + int stableId; + int localId; + TLRPC.Document document; + String title; + String uri; + + public Uri getUriForShare(int currentAccount) { + if (! TextUtils.isEmpty(uri)) { + return Uri.fromFile(new File(uri)); + } + if (document != null) { + String fileName = document.file_name_fixed; + String ext = FileLoader.getDocumentExtension(document); + if (ext != null) { + ext = ext.toLowerCase(); + if (!fileName.endsWith(ext)) { + fileName += "." + ext; + } + File file = new File(AndroidUtilities.getCacheDir(), fileName); + if (!file.exists()) { + try { + AndroidUtilities.copyFile(FileLoader.getPathToAttach(document), file); + } catch (IOException e) { + e.printStackTrace(); + } + } + return Uri.fromFile(file); + } + } + + return null; + } + } + + private void checkDisabledBySystem() { + NotificationManager manager = (NotificationManager) ApplicationLoader.applicationContext.getSystemService(Context.NOTIFICATION_SERVICE); + boolean notificationsEnabled = true; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + notificationsEnabled = manager.areNotificationsEnabled(); + } +// if (!notificationsEnabled) { +// BulletinFactory.of(this).createErrorBulletin(LocaleController.getString()).show(); +// } + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/PassportActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/PassportActivity.java index 6997a3a0b..0f8f6bfdb 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/PassportActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/PassportActivity.java @@ -6861,30 +6861,11 @@ public class PassportActivity extends BaseFragment implements NotificationCenter processSelectedAttach(button); } - @Override - public View getRevealView() { - return null; - } - - @Override - public void didSelectBot(TLRPC.User user) { - - } - @Override public void onCameraOpened() { AndroidUtilities.hideKeyboard(fragmentView.findFocus()); } - @Override - public boolean needEnterComment() { - return false; - } - - @Override - public void doOnIdle(Runnable runnable) { - runnable.run(); - } }); } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/PaymentFormActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/PaymentFormActivity.java index 69d6b545e..f348b4d8e 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/PaymentFormActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/PaymentFormActivity.java @@ -1223,6 +1223,7 @@ public class PaymentFormActivity extends BaseFragment implements NotificationCen public final String[] PREFIXES_14 = {"300", "301", "302", "303", "304", "305", "309", "36", "38", "39"}; public final String[] PREFIXES_16 = { "2221", "2222", "2223", "2224", "2225", "2226", "2227", "2228", "2229", + "2200", "2201", "2202", "2203", "2204", "223", "224", "225", "226", "227", "228", "229", "23", "24", "25", "26", "270", "271", "2720", diff --git a/TMessagesProj/src/main/java/org/telegram/ui/PeopleNearbyActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/PeopleNearbyActivity.java index 04bba9e58..1d7a50805 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/PeopleNearbyActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/PeopleNearbyActivity.java @@ -28,6 +28,12 @@ import android.widget.FrameLayout; import android.widget.ImageView; import android.widget.TextView; +import androidx.core.graphics.ColorUtils; +import androidx.recyclerview.widget.DefaultItemAnimator; +import androidx.recyclerview.widget.DiffUtil; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; + import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.BuildVars; import org.telegram.messenger.ChatObject; @@ -58,11 +64,6 @@ import org.telegram.ui.Components.UndoView; import java.util.ArrayList; -import androidx.recyclerview.widget.DefaultItemAnimator; -import androidx.recyclerview.widget.DiffUtil; -import androidx.recyclerview.widget.LinearLayoutManager; -import androidx.recyclerview.widget.RecyclerView; - public class PeopleNearbyActivity extends BaseFragment implements NotificationCenter.NotificationCenterDelegate, LocationController.LocationFetchCallback { private ListAdapter listViewAdapter; @@ -314,9 +315,6 @@ public class PeopleNearbyActivity extends BaseFragment implements NotificationCe actionBar.setOccupyStatusBar(Build.VERSION.SDK_INT >= 21 && !AndroidUtilities.isTablet()); actionBar.setTitle(LocaleController.getString("PeopleNearby", R.string.PeopleNearby)); actionBar.getTitleTextView().setAlpha(0.0f); - if (!AndroidUtilities.isTablet()) { - actionBar.showActionModeTop(); - } actionBar.setActionBarMenuOnItemClick(new ActionBar.ActionBarMenuOnItemClick() { @Override public void onItemClick(int id) { @@ -1053,6 +1051,12 @@ public class PeopleNearbyActivity extends BaseFragment implements NotificationCe } } + @Override + public boolean isLightStatusBar() { + int color = Theme.getColor(Theme.key_windowBackgroundWhite, null, true); + return ColorUtils.calculateLuminance(color) > 0.7f; + } + @Override public ArrayList getThemeDescriptions() { ArrayList themeDescriptions = new ArrayList<>(); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/PhotoViewer.java b/TMessagesProj/src/main/java/org/telegram/ui/PhotoViewer.java index 9e59065f8..a5a8eaa60 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/PhotoViewer.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/PhotoViewer.java @@ -29,6 +29,7 @@ import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Matrix; +import android.graphics.Outline; import android.graphics.Paint; import android.graphics.PixelFormat; import android.graphics.PorterDuff; @@ -48,28 +49,7 @@ import android.os.Bundle; import android.os.SystemClock; import android.os.Vibrator; import android.provider.Settings; -import androidx.annotation.Keep; -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.collection.ArrayMap; -import androidx.core.content.ContextCompat; -import androidx.core.content.FileProvider; -import androidx.core.graphics.ColorUtils; -import androidx.core.graphics.Insets; -import androidx.core.view.ViewCompat; -import androidx.core.view.WindowInsetsCompat; -import androidx.core.widget.NestedScrollView; -import androidx.dynamicanimation.animation.DynamicAnimation; -import androidx.dynamicanimation.animation.SpringAnimation; -import androidx.dynamicanimation.animation.SpringForce; -import androidx.exifinterface.media.ExifInterface; -import androidx.recyclerview.widget.DefaultItemAnimator; -import androidx.recyclerview.widget.LinearLayoutManager; -import androidx.recyclerview.widget.LinearSmoothScrollerEnd; -import androidx.recyclerview.widget.RecyclerView; - import android.text.Layout; -import android.text.Selection; import android.text.Spannable; import android.text.SpannableString; import android.text.SpannableStringBuilder; @@ -77,8 +57,6 @@ import android.text.Spanned; import android.text.StaticLayout; import android.text.TextPaint; import android.text.TextUtils; -import android.text.method.LinkMovementMethod; -import android.text.method.Touch; import android.text.style.ClickableSpan; import android.text.style.URLSpan; import android.transition.ChangeBounds; @@ -88,7 +66,6 @@ import android.transition.TransitionManager; import android.transition.TransitionSet; import android.transition.TransitionValues; import android.util.FloatProperty; -import android.util.Log; import android.util.Property; import android.util.Range; import android.util.SparseArray; @@ -107,7 +84,7 @@ import android.view.VelocityTracker; import android.view.View; import android.view.ViewConfiguration; import android.view.ViewGroup; -import android.view.ViewPropertyAnimator; +import android.view.ViewOutlineProvider; import android.view.ViewTreeObserver; import android.view.WindowInsets; import android.view.WindowManager; @@ -125,6 +102,24 @@ import android.widget.Scroller; import android.widget.TextView; import android.widget.Toast; +import androidx.annotation.Keep; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.collection.ArrayMap; +import androidx.core.content.ContextCompat; +import androidx.core.content.FileProvider; +import androidx.core.graphics.ColorUtils; +import androidx.core.view.ViewCompat; +import androidx.core.widget.NestedScrollView; +import androidx.dynamicanimation.animation.DynamicAnimation; +import androidx.dynamicanimation.animation.SpringAnimation; +import androidx.dynamicanimation.animation.SpringForce; +import androidx.exifinterface.media.ExifInterface; +import androidx.recyclerview.widget.DefaultItemAnimator; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.LinearSmoothScrollerEnd; +import androidx.recyclerview.widget.RecyclerView; + import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.ExoPlayer; import com.google.android.exoplayer2.analytics.AnalyticsListener; @@ -134,6 +129,7 @@ import com.google.android.gms.vision.face.Face; import com.google.android.gms.vision.face.FaceDetector; import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.ApplicationLoader; import org.telegram.messenger.Bitmaps; import org.telegram.messenger.BringAppForegroundService; import org.telegram.messenger.BuildConfig; @@ -142,33 +138,36 @@ import org.telegram.messenger.ChatObject; import org.telegram.messenger.ContactsController; import org.telegram.messenger.DialogObject; import org.telegram.messenger.DownloadController; -import org.telegram.messenger.MediaDataController; 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.LocaleController; +import org.telegram.messenger.MediaController; +import org.telegram.messenger.MediaDataController; +import org.telegram.messenger.MessageObject; +import org.telegram.messenger.MessagesController; import org.telegram.messenger.MessagesStorage; +import org.telegram.messenger.NotificationCenter; +import org.telegram.messenger.R; import org.telegram.messenger.SecureDocument; 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.VideoEditedInfo; import org.telegram.messenger.WebFile; -import org.telegram.messenger.ApplicationLoader; -import org.telegram.messenger.FileLoader; -import org.telegram.messenger.FileLog; -import org.telegram.messenger.LocaleController; -import org.telegram.messenger.MediaController; -import org.telegram.messenger.MessagesController; -import org.telegram.messenger.NotificationCenter; -import org.telegram.messenger.R; import org.telegram.messenger.browser.Browser; import org.telegram.messenger.video.VideoPlayerRewinder; import org.telegram.tgnet.ConnectionsManager; import org.telegram.tgnet.TLObject; import org.telegram.tgnet.TLRPC; -import org.telegram.messenger.UserConfig; -import org.telegram.messenger.MessageObject; -import org.telegram.messenger.Utilities; +import org.telegram.ui.ActionBar.ActionBar; +import org.telegram.ui.ActionBar.ActionBarMenu; +import org.telegram.ui.ActionBar.ActionBarMenuItem; import org.telegram.ui.ActionBar.ActionBarMenuSubItem; import org.telegram.ui.ActionBar.ActionBarPopupWindow; import org.telegram.ui.ActionBar.AdjustPanLayoutHelper; @@ -178,9 +177,6 @@ import org.telegram.ui.ActionBar.BottomSheet; import org.telegram.ui.ActionBar.SimpleTextView; import org.telegram.ui.ActionBar.Theme; import org.telegram.ui.Adapters.MentionsAdapter; -import org.telegram.ui.ActionBar.ActionBar; -import org.telegram.ui.ActionBar.ActionBarMenu; -import org.telegram.ui.ActionBar.ActionBarMenuItem; import org.telegram.ui.Cells.CheckBoxCell; import org.telegram.ui.Cells.PhotoPickerPhotoCell; import org.telegram.ui.Components.AlertsCreator; @@ -192,7 +188,6 @@ import org.telegram.ui.Components.BulletinFactory; import org.telegram.ui.Components.ChatAttachAlert; import org.telegram.ui.Components.CheckBox; import org.telegram.ui.Components.ClippingImageView; -import org.telegram.messenger.ImageReceiver; import org.telegram.ui.Components.CombinedDrawable; import org.telegram.ui.Components.Crop.CropTransform; import org.telegram.ui.Components.Crop.CropView; @@ -204,6 +199,8 @@ import org.telegram.ui.Components.GestureDetector2; import org.telegram.ui.Components.GroupedPhotosListView; import org.telegram.ui.Components.HideViewAfterAnimation; import org.telegram.ui.Components.LayoutHelper; +import org.telegram.ui.Components.LinkPath; +import org.telegram.ui.Components.LinkSpanDrawable; import org.telegram.ui.Components.MediaActivity; import org.telegram.ui.Components.NumberPicker; import org.telegram.ui.Components.OtherDocumentPlaceholderDrawable; @@ -214,7 +211,7 @@ import org.telegram.ui.Components.PhotoPaintView; import org.telegram.ui.Components.PhotoViewerCaptionEnterView; import org.telegram.ui.Components.PhotoViewerWebView; import org.telegram.ui.Components.PickerBottomLayoutViewer; -import org.telegram.ui.Components.PipVideoView; +import org.telegram.ui.Components.PipVideoOverlay; import org.telegram.ui.Components.PlayPauseDrawable; import org.telegram.ui.Components.RLottieDrawable; import org.telegram.ui.Components.RadialProgressView; @@ -250,6 +247,7 @@ import java.util.List; import java.util.Locale; import java.util.Map; +@SuppressLint("WrongConstant") @SuppressWarnings("unchecked") public class PhotoViewer implements NotificationCenter.NotificationCenterDelegate, GestureDetector2.OnGestureListener, GestureDetector2.OnDoubleTapListener { @@ -288,6 +286,14 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat private static final int PROGRESS_PAUSE = 4; private static Drawable[] progressDrawables; + private static final int EDIT_MODE_NONE = 0; + private static final int EDIT_MODE_CROP = 1; + private static final int EDIT_MODE_FILTER = 2; + private static final int EDIT_MODE_PAINT = 3; + + private int videoWidth, videoHeight; + private float inlineOutAnimationProgress; + private WindowManager.LayoutParams windowLayoutParams; private FrameLayoutDrawer containerView; private PhotoViewerWebView photoViewerWebView; @@ -359,6 +365,10 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat private AnimatorSet currentListViewAnimation; private PhotoCropView photoCropView; private CropTransform cropTransform = new CropTransform(); + private CropTransform leftCropTransform = new CropTransform(); + private CropTransform rightCropTransform = new CropTransform(); + private MediaController.CropState leftCropState; + private MediaController.CropState rightCropState; private PhotoFilterView photoFilterView; private PhotoPaintView photoPaintView; private AlertDialog visibleDialog; @@ -465,7 +475,6 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat private VideoSeekPreviewImage videoPreviewFrame; private AnimatorSet videoPreviewFrameAnimation; private boolean needShowOnReady; - private PipVideoView pipVideoView; private int waitingForDraw; private TextureView changedTextureView; private ImageView textureImageView; @@ -571,6 +580,8 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat public void setCaption(CharSequence caption) { hasCaptionForAllMedia = true; captionForAllMedia = caption; + setCurrentCaption(null, caption, false); + updateCaptionTextForCurrentPhoto(null); } private static class SavedVideoPosition { @@ -584,194 +595,130 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat } } - private class CaptionLinkMovementMethod extends LinkMovementMethod { - ClickableSpan selectedLink; - TextView selectedWidget; - Runnable longPressRunnable = new Runnable() { - @Override - public void run() { - if (selectedWidget != null && selectedLink instanceof URLSpan) { - onLongClick((URLSpan) selectedLink); - selectedLink = null; - } - } - }; - - @Override - public boolean onTouchEvent(@NonNull TextView widget, @NonNull Spannable buffer, @NonNull MotionEvent event) { - try { - if (!imagesArrLocals.isEmpty()) { - return false; - } - int action = event.getAction(); - boolean result = false; - - if (action == MotionEvent.ACTION_CANCEL) { - AndroidUtilities.cancelRunOnUIThread(longPressRunnable); - selectedLink = null; - } - if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_DOWN) { - int x = (int) event.getX(); - int y = (int) event.getY(); - - x -= widget.getTotalPaddingLeft(); - y -= widget.getTotalPaddingTop(); - - x += widget.getScrollX(); - y += widget.getScrollY(); - - Layout layout = widget.getLayout(); - int line = layout.getLineForVertical(y); - int off = layout.getOffsetForHorizontal(line, x); - - ClickableSpan[] links = buffer.getSpans(off, off, ClickableSpan.class); - - if (links.length != 0) { - ClickableSpan link = links[0]; - if (action == MotionEvent.ACTION_UP) { - if (selectedLink != link) { - selectedLink = null; - return false; - } - onClick(link, widget); - AndroidUtilities.cancelRunOnUIThread(longPressRunnable); - selectedLink = null; - } else { // action == MotionEvent.ACTION_DOWN - Selection.setSelection(buffer, buffer.getSpanStart(link), buffer.getSpanEnd(link)); - AndroidUtilities.runOnUIThread(longPressRunnable, ViewConfiguration.getLongPressTimeout()); - selectedLink = link; - selectedWidget = widget; - } - result = true; + private void onLinkClick(ClickableSpan link, TextView widget) { + if (widget != null && link instanceof URLSpan) { + String url = ((URLSpan) link).getURL(); + if (url.startsWith("video")) { + if (videoPlayer != null && currentMessageObject != null) { + int seconds = Utilities.parseInt(url); + if (videoPlayer.getDuration() == C.TIME_UNSET) { + seekToProgressPending = seconds / (float) currentMessageObject.getDuration(); } else { - Selection.removeSelection(buffer); - AndroidUtilities.cancelRunOnUIThread(longPressRunnable); - selectedLink = null; + videoPlayer.seekTo(seconds * 1000L); + videoPlayerSeekbar.setProgress(seconds * 1000L / (float) videoPlayer.getDuration(), true); + videoPlayerSeekbarView.invalidate(); } } - - return result || Touch.onTouchEvent(widget, buffer, event); - } catch (Exception e) { - FileLog.e(e); - } - return false; - } - - private void onClick(ClickableSpan link, TextView widget) { - if (widget != null && link instanceof URLSpan) { - String url = ((URLSpan) link).getURL(); - if (url.startsWith("video")) { - if (videoPlayer != null && currentMessageObject != null) { - int seconds = Utilities.parseInt(url); - if (videoPlayer.getDuration() == C.TIME_UNSET) { - seekToProgressPending = seconds / (float) currentMessageObject.getDuration(); - } else { - videoPlayer.seekTo(seconds * 1000L); - videoPlayerSeekbar.setProgress(seconds * 1000L / (float) videoPlayer.getDuration(), true); - videoPlayerSeekbarView.invalidate(); - } - } - } else if (url.startsWith("#")) { - if (parentActivity instanceof LaunchActivity) { - DialogsActivity fragment = new DialogsActivity(null); - fragment.setSearchString(url); - ((LaunchActivity) parentActivity).presentFragment(fragment, false, true); - closePhoto(false, false); - } - } else if (parentChatActivity != null && (link instanceof URLSpanReplacement || AndroidUtilities.shouldShowUrlInAlert(url))) { - AlertsCreator.showOpenUrlAlert(parentChatActivity, url, true, true); - } else { - link.onClick(widget); + } else if (url.startsWith("#")) { + if (parentActivity instanceof LaunchActivity) { + DialogsActivity fragment = new DialogsActivity(null); + fragment.setSearchString(url); + ((LaunchActivity) parentActivity).presentFragment(fragment, false, true); + closePhoto(false, false); } + } else if (parentChatActivity != null && (link instanceof URLSpanReplacement || AndroidUtilities.shouldShowUrlInAlert(url))) { + AlertsCreator.showOpenUrlAlert(parentChatActivity, url, true, true); } else { link.onClick(widget); } + } else { + link.onClick(widget); } + } - private void onLongClick(URLSpan link) { - int timestamp = -1; - BottomSheet.Builder builder = new BottomSheet.Builder(parentActivity, false, resourcesProvider); - if (link.getURL().startsWith("video?")) { - try { - String timestampStr = link.getURL().substring(link.getURL().indexOf('?') + 1); - timestamp = Integer.parseInt(timestampStr); - } catch (Throwable ignore) { + private void onLinkLongPress(URLSpan link, TextView widget, Runnable onDismiss) { + int timestamp = -1; + BottomSheet.Builder builder = new BottomSheet.Builder(parentActivity, false, resourcesProvider); + if (link.getURL().startsWith("video?")) { + try { + String timestampStr = link.getURL().substring(link.getURL().indexOf('?') + 1); + timestamp = Integer.parseInt(timestampStr); + } catch (Throwable ignore) { - } } - if (timestamp >= 0) { - builder.setTitle(AndroidUtilities.formatDuration(timestamp, false)); - } else { - builder.setTitle(link.getURL()); - } - final int finalTimestamp = timestamp; - builder.setItems(new CharSequence[]{LocaleController.getString("Open", R.string.Open), LocaleController.getString("Copy", R.string.Copy)}, (dialog, which) -> { - if (which == 0) { - onClick(link, selectedWidget); - } else if (which == 1) { - String url1 = link.getURL(); - boolean tel = false; - if (url1.startsWith("mailto:")) { - url1 = url1.substring(7); - } else if (url1.startsWith("tel:")) { - url1 = url1.substring(4); - tel = true; - } else if (finalTimestamp >= 0) { - if (currentMessageObject != null && !currentMessageObject.scheduled) { - MessageObject messageObject1 = currentMessageObject; - boolean isMedia = currentMessageObject.isVideo() || currentMessageObject.isRoundVideo() || currentMessageObject.isVoice() || currentMessageObject.isMusic(); - if (!isMedia && currentMessageObject.replyMessageObject != null) { - messageObject1 = currentMessageObject.replyMessageObject; - } - long dialogId = messageObject1.getDialogId(); - int messageId = messageObject1.getId(); + } + if (timestamp >= 0) { + builder.setTitle(AndroidUtilities.formatDuration(timestamp, false)); + } else { + builder.setTitle(link.getURL()); + } + final int finalTimestamp = timestamp; + builder.setItems(new CharSequence[]{LocaleController.getString("Open", R.string.Open), LocaleController.getString("Copy", R.string.Copy)}, (dialog, which) -> { + if (which == 0) { + onLinkClick(link, widget); + } else if (which == 1) { + String url1 = link.getURL(); + boolean tel = false; + if (url1.startsWith("mailto:")) { + url1 = url1.substring(7); + } else if (url1.startsWith("tel:")) { + url1 = url1.substring(4); + tel = true; + } else if (finalTimestamp >= 0) { + if (currentMessageObject != null && !currentMessageObject.scheduled) { + MessageObject messageObject1 = currentMessageObject; + boolean isMedia = currentMessageObject.isVideo() || currentMessageObject.isRoundVideo() || currentMessageObject.isVoice() || currentMessageObject.isMusic(); + if (!isMedia && currentMessageObject.replyMessageObject != null) { + messageObject1 = currentMessageObject.replyMessageObject; + } + long dialogId = messageObject1.getDialogId(); + int messageId = messageObject1.getId(); - if (messageObject1.messageOwner.fwd_from != null) { - if (messageObject1.messageOwner.fwd_from.saved_from_peer != null) { - dialogId = MessageObject.getPeerId(messageObject1.messageOwner.fwd_from.saved_from_peer); - messageId = messageObject1.messageOwner.fwd_from.saved_from_msg_id; - } else if (messageObject1.messageOwner.fwd_from.from_id != null) { - dialogId = MessageObject.getPeerId(messageObject1.messageOwner.fwd_from.from_id); - messageId = messageObject1.messageOwner.fwd_from.channel_post; - } + if (messageObject1.messageOwner.fwd_from != null) { + if (messageObject1.messageOwner.fwd_from.saved_from_peer != null) { + dialogId = MessageObject.getPeerId(messageObject1.messageOwner.fwd_from.saved_from_peer); + messageId = messageObject1.messageOwner.fwd_from.saved_from_msg_id; + } else if (messageObject1.messageOwner.fwd_from.from_id != null) { + dialogId = MessageObject.getPeerId(messageObject1.messageOwner.fwd_from.from_id); + messageId = messageObject1.messageOwner.fwd_from.channel_post; } + } - if (DialogObject.isChatDialog(dialogId)) { - TLRPC.Chat currentChat = MessagesController.getInstance(currentAccount).getChat(-dialogId); - if (currentChat != null && currentChat.username != null) { - url1 = "https://t.me/" + currentChat.username + "/" + messageId + "?t=" + finalTimestamp; - } - } else { - TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(dialogId); - if (user != null && user.username != null) { - url1 = "https://t.me/" + user.username + "/" + messageId + "?t=" + finalTimestamp; - } + if (DialogObject.isChatDialog(dialogId)) { + TLRPC.Chat currentChat = MessagesController.getInstance(currentAccount).getChat(-dialogId); + if (currentChat != null && currentChat.username != null) { + url1 = "https://t.me/" + currentChat.username + "/" + messageId + "?t=" + finalTimestamp; + } + } else { + TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(dialogId); + if (user != null && user.username != null) { + url1 = "https://t.me/" + user.username + "/" + messageId + "?t=" + finalTimestamp; } } } - AndroidUtilities.addToClipboard(url1); - String bulletinMessage; - if (tel) { - bulletinMessage = LocaleController.getString("PhoneCopied", R.string.PhoneCopied); - } else if (url1.startsWith("#")) { - bulletinMessage = LocaleController.getString("HashtagCopied", R.string.HashtagCopied); - } else if (url1.startsWith("@")) { - bulletinMessage = LocaleController.getString("UsernameCopied", R.string.UsernameCopied); - } else { - bulletinMessage = LocaleController.getString("LinkCopied", R.string.LinkCopied); - } - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.S) { - BulletinFactory.of(containerView, resourcesProvider).createSimpleBulletin(R.raw.voip_invite, bulletinMessage).show(); - } } - }); - BottomSheet bottomSheet = builder.create(); - bottomSheet.show(); - bottomSheet.setItemColor(0,0xffffffff, 0xffffffff); - bottomSheet.setItemColor(1,0xffffffff, 0xffffffff); - bottomSheet.setBackgroundColor(0xff1C2229); - bottomSheet.setTitleColor(0xff8A8A8A); - } + AndroidUtilities.addToClipboard(url1); + String bulletinMessage; + if (tel) { + bulletinMessage = LocaleController.getString("PhoneCopied", R.string.PhoneCopied); + } else if (url1.startsWith("#")) { + bulletinMessage = LocaleController.getString("HashtagCopied", R.string.HashtagCopied); + } else if (url1.startsWith("@")) { + bulletinMessage = LocaleController.getString("UsernameCopied", R.string.UsernameCopied); + } else { + bulletinMessage = LocaleController.getString("LinkCopied", R.string.LinkCopied); + } + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.S) { + BulletinFactory.of(containerView, resourcesProvider).createSimpleBulletin(R.raw.voip_invite, bulletinMessage).show(); + } + } + }); + builder.setOnPreDismissListener(di -> onDismiss.run()); + BottomSheet bottomSheet = builder.create(); + bottomSheet.scrollNavBar = true; + bottomSheet.show(); + try { + containerView.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS, HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING); + } catch (Exception ignore) {} + bottomSheet.setItemColor(0,0xffffffff, 0xffffffff); + bottomSheet.setItemColor(1,0xffffffff, 0xffffffff); + bottomSheet.setBackgroundColor(0xff1C2229); + bottomSheet.setTitleColor(0xff8A8A8A); + bottomSheet.setCalcMandatoryInsets(true); + bottomSheet.setOverlayNavBarColor(0xff1C2229); + AndroidUtilities.setNavigationBarColor(bottomSheet.getWindow(), 0xff1C2229, false); + AndroidUtilities.setLightNavigationBar(bottomSheet.getWindow(), false); + bottomSheet.scrollNavBar = true; } private void cancelFlashAnimations() { @@ -805,13 +752,13 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat if (shownControlsByEnd && !actionBarWasShownBeforeByEnd) { progress = 0; } - if (!inPreview && (currentEditMode != 0 || videoTimelineView.getVisibility() == View.VISIBLE)) { + if (!inPreview && (currentEditMode != EDIT_MODE_NONE || videoTimelineView.getVisibility() == View.VISIBLE)) { if (progress >= videoTimelineView.getRightProgress()) { videoTimelineView.setProgress(videoTimelineView.getLeftProgress()); videoPlayer.seekTo((int) (videoTimelineView.getLeftProgress() * videoPlayer.getDuration())); manuallyPaused = false; cancelVideoPlayRunnable(); - if (muteVideo || sendPhotoType == SELECT_TYPE_AVATAR || currentEditMode != 0 || switchingToMode > 0) { + if (muteVideo || sendPhotoType == SELECT_TYPE_AVATAR || currentEditMode != EDIT_MODE_NONE || switchingToMode > 0) { videoPlayer.play(); } else { videoPlayer.pause(); @@ -866,9 +813,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat } if (bufferedProgress != -1) { videoPlayerSeekbar.setBufferedProgress(bufferedProgress); - if (pipVideoView != null) { - pipVideoView.setBufferedProgress(bufferedProgress); - } + PipVideoOverlay.setBufferedProgress(bufferedProgress); } } videoPlayerSeekbarView.invalidate(); @@ -911,6 +856,12 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat private Runnable switchToInlineRunnable = new Runnable() { @Override public void run() { + if (PipVideoOverlay.isVisible()) { + PipVideoOverlay.dismiss(); + AndroidUtilities.runOnUIThread(this, 250); + return; + } + switchingInlineMode = false; if (currentBitmap != null) { currentBitmap.recycle(); @@ -940,8 +891,10 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat isInline = true; - pipVideoView = new PipVideoView(false); - changedTextureView = pipVideoView.show(parentActivity, PhotoViewer.this, aspectRatioFrameLayout.getAspectRatio(), aspectRatioFrameLayout.getVideoRotation()); + changedTextureView = new TextureView(parentActivity); + if (PipVideoOverlay.show(false, parentActivity, changedTextureView, videoWidth, videoHeight, true)) { + PipVideoOverlay.setPhotoViewer(PhotoViewer.this); + } changedTextureView.setVisibility(View.INVISIBLE); aspectRatioFrameLayout.removeView(videoTextureView); } @@ -984,11 +937,22 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat public boolean onPreDraw() { changedTextureView.getViewTreeObserver().removeOnPreDrawListener(this); if (textureImageView != null) { - textureImageView.setVisibility(View.INVISIBLE); - textureImageView.setImageDrawable(null); - if (currentBitmap != null) { - currentBitmap.recycle(); - currentBitmap = null; + if (isInline) { + AndroidUtilities.runOnUIThread(()-> { + textureImageView.setVisibility(View.INVISIBLE); + textureImageView.setImageDrawable(null); + if (currentBitmap != null) { + currentBitmap.recycle(); + currentBitmap = null; + } + }, 300); + } else { + textureImageView.setVisibility(View.INVISIBLE); + textureImageView.setImageDrawable(null); + if (currentBitmap != null) { + currentBitmap.recycle(); + currentBitmap = null; + } } } AndroidUtilities.runOnUIThread(() -> { @@ -1094,11 +1058,16 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat private int currentImageHasFace; private String currentImageFaceKey; private PaintingOverlay paintingOverlay; + private PaintingOverlay leftPaintingOverlay; + private PaintingOverlay rightPaintingOverlay; private ImageReceiver leftImage = new ImageReceiver(); private ImageReceiver centerImage = new ImageReceiver(); + private ImageReceiver rightImage = new ImageReceiver(); + private boolean leftImageIsVideo; + private boolean centerImageIsVideo; + private boolean rightImageIsVideo; private Paint videoFrameBitmapPaint = new Paint(); private Bitmap videoFrameBitmap = null; - private ImageReceiver rightImage = new ImageReceiver(); private int currentIndex; private int switchingToIndex; private MessageObject currentMessageObject; @@ -1991,7 +1960,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat @Override protected void onPanTranslationUpdate(float y, float progress, boolean keyboardVisible) { currentPanTranslationY = y; - if (currentEditMode != 3) { + if (currentEditMode != EDIT_MODE_PAINT) { actionBar.setTranslationY(y); } if (miniProgressView != null) { @@ -2029,7 +1998,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat pickerViewSendButton.setTranslationY(y); } - if (currentEditMode == 3) { + if (currentEditMode == EDIT_MODE_PAINT) { if (captionEditText != null) { captionEditText.setTranslationY(y); } @@ -2065,7 +2034,8 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat @Override protected void onTransitionStart(boolean keyboardVisible, int contentHeight) { - windowView.setClipChildren(false); + navigationBar.setVisibility(View.INVISIBLE); + animateNavBarColorTo(0xff000000); if (captionEditText.getTag() != null && keyboardVisible) { if (isCurrentVideo) { CharSequence title = muteVideo ? LocaleController.getString("GifCaption", R.string.GifCaption) : LocaleController.getString("VideoCaption", R.string.VideoCaption); @@ -2093,7 +2063,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat @Override protected void onTransitionEnd() { super.onTransitionEnd(); - windowView.setClipChildren(false); + navigationBar.setVisibility(currentEditMode == EDIT_MODE_NONE || currentEditMode == EDIT_MODE_CROP ? View.VISIBLE : View.INVISIBLE); if (captionEditText.getTag() == null) { captionEditText.setVisibility(View.GONE); } @@ -2109,8 +2079,6 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat public FrameLayoutDrawer(Context context) { super(context, false); setWillNotDraw(false); - setClipChildren(false); - setClipToPadding(false); paint.setColor(0x33000000); } @@ -2233,7 +2201,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat @Override protected void onLayout(boolean changed, int _l, int t, int _r, int _b) { final int count = getChildCount(); - int keyboardHeight = getKeyboardHeight(); + int keyboardHeight = measureKeyboardHeight(); keyboardSize = keyboardHeight; int paddingBottom = keyboardHeight <= AndroidUtilities.dp(20) && !AndroidUtilities.isInMultiwindow ? captionEditText.getEmojiPadding() : 0; @@ -2348,9 +2316,28 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat } @Override + protected void dispatchDraw(Canvas canvas) { + canvas.save(); + canvas.clipRect(0, 0, getWidth(), getHeight()); + super.dispatchDraw(canvas); + canvas.restore(); + } + protected boolean drawChild(Canvas canvas, View child, long drawingTime) { + if (child != navigationBar) { + canvas.save(); + canvas.clipRect(0, 0, getWidth(), getHeight()); + } + boolean result = this.drawChildInternal(canvas, child, drawingTime); + if (child != navigationBar) { + canvas.restore(); + } + return result; + } + + protected boolean drawChildInternal(Canvas canvas, View child, long drawingTime) { if (child == mentionListView || child == captionEditText) { - if (currentEditMode != 0 && currentPanTranslationY == 0) { + if (currentEditMode != EDIT_MODE_NONE && currentPanTranslationY == 0) { return false; } else if (AndroidUtilities.isInMultiwindow || AndroidUtilities.usingHardwareInput) { if (!captionEditText.isPopupShowing() && captionEditText.getEmojiPadding() == 0 && captionEditText.getTag() == null) { @@ -2368,7 +2355,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat canvas.restore(); return r; } - } else if (child == cameraItem || child == muteItem || child == pickerView || child == videoTimelineView || child == pickerViewSendButton || child == captionLimitView || child == captionTextViewSwitcher || muteItem.getVisibility() == VISIBLE && child == bottomLayout || child == navigationBar) { + } else if (child == cameraItem || child == muteItem || child == pickerView || child == videoTimelineView || child == pickerViewSendButton || child == captionLimitView || child == captionTextViewSwitcher || muteItem.getVisibility() == VISIBLE && child == bottomLayout) { if (captionEditText.isPopupAnimating()) { child.setTranslationY(captionEditText.getEmojiPadding()); bottomTouchEnabled = false; @@ -3124,9 +3111,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat } if (bufferedProgress != -1) { videoPlayerSeekbar.setBufferedProgress(bufferedProgress); - if (pipVideoView != null) { - pipVideoView.setBufferedProgress(bufferedProgress); - } + PipVideoOverlay.setBufferedProgress(bufferedProgress); videoPlayerSeekbarView.invalidate(); } checkBufferedProgress(loadProgress); @@ -3676,6 +3661,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat ViewGroup.LayoutParams layoutParams = animatingImageView.getLayoutParams(); animatingImageView.measure(MeasureSpec.makeMeasureSpec(layoutParams.width, MeasureSpec.AT_MOST), MeasureSpec.makeMeasureSpec(layoutParams.height, MeasureSpec.AT_MOST)); containerView.measure(MeasureSpec.makeMeasureSpec(widthSize, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(heightSize, MeasureSpec.EXACTLY)); + navigationBar.measure(MeasureSpec.makeMeasureSpec(widthSize, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(navigationBarHeight, MeasureSpec.EXACTLY)); } @SuppressWarnings("DrawAllocation") @@ -3683,6 +3669,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat protected void onLayout(boolean changed, int left, int top, int right, int bottom) { animatingImageView.layout(getPaddingLeft(), 0, getPaddingLeft() + animatingImageView.getMeasuredWidth(), animatingImageView.getMeasuredHeight()); containerView.layout(getPaddingLeft(), 0, getPaddingLeft() + containerView.getMeasuredWidth(), containerView.getMeasuredHeight()); + navigationBar.layout(getPaddingLeft(), containerView.getMeasuredHeight(), navigationBar.getMeasuredWidth(), containerView.getMeasuredHeight() + navigationBar.getMeasuredHeight()); wasLayout = true; if (changed) { if (!dontResetZoomOnFirstLayout) { @@ -3721,12 +3708,18 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat @Override protected void onAttachedToWindow() { super.onAttachedToWindow(); + centerImage.onAttachedToWindow(); + leftImage.onAttachedToWindow(); + rightImage.onAttachedToWindow(); attachedToWindow = true; } @Override protected void onDetachedFromWindow() { super.onDetachedFromWindow(); + centerImage.onDetachedFromWindow(); + leftImage.onDetachedFromWindow(); + rightImage.onDetachedFromWindow(); attachedToWindow = false; wasLayout = false; } @@ -3780,11 +3773,10 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat containerView = new FrameLayoutDrawer(activity); containerView.setFocusable(false); - //TODO uncomment when fix transparent navigation -// containerView.setClipChildren(false); -// containerView.setClipToPadding(false); -// windowView.setClipChildren(false); -// windowView.setClipToPadding(false); + containerView.setClipChildren(true); + containerView.setClipToPadding(true); + windowView.setClipChildren(false); + windowView.setClipToPadding(false); windowView.addView(containerView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.TOP | Gravity.LEFT)); if (Build.VERSION.SDK_INT >= 21) { @@ -3811,7 +3803,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat navigationBarHeight = insets.getSystemWindowInsetBottom(); ViewGroup.MarginLayoutParams navigationBarLayoutParams = (ViewGroup.MarginLayoutParams) navigationBar.getLayoutParams(); navigationBarLayoutParams.height = navigationBarHeight; - navigationBarLayoutParams.bottomMargin = -navigationBarHeight; + navigationBarLayoutParams.bottomMargin = -navigationBarHeight / 2; navigationBar.setLayoutParams(navigationBarLayoutParams); } containerView.setPadding(insets.getSystemWindowInsetLeft(), 0, insets.getSystemWindowInsetRight(), 0); @@ -4259,8 +4251,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat return; } if (isEmbedVideo) { - pipVideoView = photoViewerWebView.openInPip(); - if (pipVideoView != null) { + if (photoViewerWebView.openInPip()) { if (PipInstance != null) { PipInstance.destroyPhotoViewer(); } @@ -4540,7 +4531,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat navigationBar = new View(activityContext); navigationBar.setBackgroundColor(0x7f000000); - containerView.addView(navigationBar, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, navigationBarHeight / AndroidUtilities.density, Gravity.BOTTOM | Gravity.FILL_HORIZONTAL, 0, 0, 0, -navigationBarHeight / AndroidUtilities.density)); + windowView.addView(navigationBar, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, navigationBarHeight / AndroidUtilities.density, Gravity.BOTTOM | Gravity.FILL_HORIZONTAL)); pressedDrawable[0] = new GradientDrawable(GradientDrawable.Orientation.LEFT_RIGHT, new int[] {0x32000000, 0}); pressedDrawable[0].setShape(GradientDrawable.RECTANGLE); @@ -4654,9 +4645,8 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat }); } - final LinkMovementMethod captionLinkMovementMethod = new CaptionLinkMovementMethod(); captionTextViewSwitcher = new CaptionTextViewSwitcher(containerView.getContext()); - captionTextViewSwitcher.setFactory(() -> createCaptionTextView(captionLinkMovementMethod)); + captionTextViewSwitcher.setFactory(() -> createCaptionTextView()); captionTextViewSwitcher.setVisibility(View.INVISIBLE); setCaptionHwLayerEnabled(true); @@ -5322,7 +5312,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat return; } } - switchToEditMode(1); + switchToEditMode(EDIT_MODE_CROP); }); cropItem.setContentDescription(LocaleController.getString("CropImage", R.string.CropImage)); @@ -5382,7 +5372,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat return; } } - switchToEditMode(3); + switchToEditMode(EDIT_MODE_PAINT); }); paintItem.setContentDescription(LocaleController.getString("AccDescrPhotoEditor", R.string.AccDescrPhotoEditor)); @@ -5443,7 +5433,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat return; } } - switchToEditMode(2); + switchToEditMode(EDIT_MODE_FILTER); }); tuneItem.setContentDescription(LocaleController.getString("AccDescrPhotoAdjust", R.string.AccDescrPhotoAdjust)); @@ -5522,6 +5512,9 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat titleView.setOnTouchListener((v12, event) -> true); final BottomSheet bottomSheet = builder.create(); + bottomSheet.setCalcMandatoryInsets(true); + bottomSheet.setOverlayNavBarColor(0xff000000); + bottomSheet.scrollNavBar = true; final NumberPicker numberPicker = new NumberPicker(parentActivity, resourcesProvider); numberPicker.setMinValue(0); numberPicker.setMaxValue(28); @@ -5628,6 +5621,8 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat textView.setOnClickListener(v14 -> bottomSheet.dismiss()); bottomSheet.show(); bottomSheet.setBackgroundColor(0xff000000); + AndroidUtilities.setNavigationBarColor(bottomSheet.getWindow(), 0xff000000, false); + AndroidUtilities.setLightNavigationBar(bottomSheet.getWindow(), false); }); editorDoneLayout = new PickerBottomLayoutViewer(activityContext); @@ -5637,14 +5632,14 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat containerView.addView(editorDoneLayout, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 48, Gravity.LEFT | Gravity.BOTTOM)); editorDoneLayout.cancelButton.setOnClickListener(view -> { cropTransform.setViewTransform(previousHasTransform, previousCropPx, previousCropPy, previousCropRotation, previousCropOrientation, previousCropScale, 1.0f, 1.0f, previousCropPw, previousCropPh, 0, 0, previousCropMirrored); - switchToEditMode(0); + switchToEditMode(EDIT_MODE_NONE); }); editorDoneLayout.doneButton.setOnClickListener(view -> { - if (currentEditMode == 1 && !photoCropView.isReady()) { + if (currentEditMode == EDIT_MODE_CROP && !photoCropView.isReady()) { return; } applyCurrentEditMode(); - switchToEditMode(0); + switchToEditMode(EDIT_MODE_NONE); }); resetButton = new TextView(activityContext); @@ -5665,7 +5660,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat ImageReceiver.ImageReceiverDelegate imageReceiverDelegate = (imageReceiver, set, thumb, memCache) -> { if (imageReceiver == centerImage && set && !thumb) { - if (!isCurrentVideo && (currentEditMode == 1 || sendPhotoType == SELECT_TYPE_AVATAR) && photoCropView != null) { + if (!isCurrentVideo && (currentEditMode == EDIT_MODE_CROP || sendPhotoType == SELECT_TYPE_AVATAR) && photoCropView != null) { Bitmap bitmap = imageReceiver.getBitmap(); if (bitmap != null) { photoCropView.setBitmap(bitmap, imageReceiver.getOrientation(), sendPhotoType != SELECT_TYPE_AVATAR, true, paintingOverlay, cropTransform, null, null); @@ -5847,8 +5842,16 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat } } + @Override + public void onEmojiViewOpen() { + navigationBar.setVisibility(View.INVISIBLE); + animateNavBarColorTo(getThemedColor(Theme.key_chat_emojiPanelBackground), false); + } + @Override public void onEmojiViewCloseStart() { + navigationBar.setVisibility(currentEditMode == EDIT_MODE_NONE || currentEditMode == EDIT_MODE_CROP ? View.VISIBLE : View.INVISIBLE); + animateNavBarColorTo(0xff000000); setOffset(captionEditText.getEmojiPadding()); if (captionEditText.getTag() != null) { if (isCurrentVideo) { @@ -6055,6 +6058,40 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat } } + private ValueAnimator navBarAnimator; + private void animateNavBarColorTo(int color) { + animateNavBarColorTo(color, true); + } + private void animateNavBarColorTo(int color, boolean animated) { + if (navBarAnimator != null) { + navBarAnimator.cancel(); + } + int fromColor = blackPaint.getColor(), + toColor = color; + AndroidUtilities.setLightNavigationBar(windowView, AndroidUtilities.computePerceivedBrightness(toColor) >= 0.721); + if (animated) { + navBarAnimator = ValueAnimator.ofFloat(0, 1); + navBarAnimator.addUpdateListener(a -> { + blackPaint.setColor(ColorUtils.blendARGB(fromColor, toColor, (float) a.getAnimatedValue())); + windowView.invalidate(); + }); + navBarAnimator.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + blackPaint.setColor(toColor); + windowView.invalidate(); + } + }); + navBarAnimator.setInterpolator(CubicBezierInterpolator.DEFAULT); + navBarAnimator.setDuration(200); + navBarAnimator.start(); + } else { + navBarAnimator = null; + blackPaint.setColor(toColor); + windowView.invalidate(); + } + } + private void showScheduleDatePickerDialog() { if (parentChatActivity == null) { return; @@ -6177,33 +6214,69 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat }).start(); } - private TextView createCaptionTextView(LinkMovementMethod linkMovementMethod) { + private TextView createCaptionTextView() { TextView textView = new SpoilersTextView(activityContext) { - private boolean handleClicks; + private LinkSpanDrawable pressedLink; + private LinkSpanDrawable.LinkCollector links = new LinkSpanDrawable.LinkCollector(this); @Override public boolean onTouchEvent(MotionEvent event) { - if (event.getActionMasked() == MotionEvent.ACTION_DOWN) { - handleClicks = needCaptionLayout; + + boolean linkResult = false; + if (event.getAction() == MotionEvent.ACTION_DOWN || pressedLink != null && event.getAction() == MotionEvent.ACTION_UP) { + int x = (int) (event.getX() - getPaddingLeft()); + int y = (int) (event.getY() - getPaddingTop()); + final int line = getLayout().getLineForVertical(y); + final int off = getLayout().getOffsetForHorizontal(line, x); + final float left = getLayout().getLineLeft(line); + + ClickableSpan touchLink = null; + if (left <= x && left + getLayout().getLineWidth(line) >= x && y >= 0 && y <= getLayout().getHeight()) { + Spannable buffer = new SpannableString(getText()); + ClickableSpan[] link = buffer.getSpans(off, off, ClickableSpan.class); + if (link.length != 0) { + touchLink = link[0]; + if (event.getAction() == MotionEvent.ACTION_DOWN) { + linkResult = true; + links.clear(); + pressedLink = new LinkSpanDrawable<>(link[0], null, event.getX(), event.getY()); + pressedLink.setColor(0x6662a9e3); + links.addLink(pressedLink); + int start = buffer.getSpanStart(pressedLink.getSpan()); + int end = buffer.getSpanEnd(pressedLink.getSpan()); + LinkPath path = pressedLink.obtainNewPath(); + path.setCurrentLayout(getLayout(), start, getPaddingTop()); + getLayout().getSelectionPath(start, end, path); + + final LinkSpanDrawable savedPressedLink = pressedLink; + postDelayed(() -> { + if (savedPressedLink == pressedLink && pressedLink != null && pressedLink.getSpan() instanceof URLSpan) { + onLinkLongPress((URLSpan) pressedLink.getSpan(), this, () -> links.clear()); + pressedLink = null; + } + }, ViewConfiguration.getLongPressTimeout()); + } + } + } + if (event.getAction() == MotionEvent.ACTION_UP) { + links.clear(); + if (pressedLink != null && pressedLink.getSpan() == touchLink) { + onLinkClick(pressedLink.getSpan(), this); + } + pressedLink = null; + linkResult = true; + } + } else if (event.getAction() == MotionEvent.ACTION_CANCEL) { + links.clear(); + pressedLink = null; + linkResult = true; } - boolean b = super.onTouchEvent(event); + + boolean b = linkResult || super.onTouchEvent(event); return bottomTouchEnabled && b; } - @Override - public void scrollTo(int x, int y) { - if (getParent().getParent() == pickerView) { - super.scrollTo(x, y); - handleClicks = false; - } - } - - @Override - public boolean performClick() { - return handleClicks && super.performClick(); - } - @Override public void setPressed(boolean pressed) { final boolean needsRefresh = pressed != isPressed(); @@ -6212,15 +6285,30 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat invalidate(); } } + + @Override + protected void onDraw(Canvas canvas) { + canvas.save(); + canvas.translate(getPaddingLeft(), 0); + if (links.draw(canvas)) { + invalidate(); + } + canvas.restore(); + super.onDraw(canvas); + } }; - textView.setMovementMethod(linkMovementMethod); ViewHelper.setPadding(textView, 16, 8, 16, 8); - textView.setLinkTextColor(0xff76c2f1); + textView.setLinkTextColor(0xff79c4fc); textView.setTextColor(0xffffffff); textView.setHighlightColor(0x33ffffff); textView.setGravity(Gravity.CENTER_VERTICAL | LayoutHelper.getAbsoluteGravityStart()); textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16); - textView.setOnClickListener((v) -> openCaptionEnter()); + textView.setOnClickListener((v) -> { + if (!needCaptionLayout) { + return; + } + openCaptionEnter(); + }); return textView; } @@ -6299,9 +6387,9 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat currentPlaceObject.imageReceiver.startAnimation(); } } - if (Build.VERSION.SDK_INT >= 21) { + if (Build.VERSION.SDK_INT >= 21 && PipVideoOverlay.IS_TRANSITION_ANIMATION_SUPPORTED) { pipAnimationInProgress = true; - org.telegram.ui.Components.Rect rect = PipVideoView.getPipRect(aspectRatioFrameLayout.getAspectRatio()); + org.telegram.ui.Components.Rect rect = PipVideoOverlay.getPipRect(true, aspectRatioFrameLayout.getAspectRatio()); float scale = rect.width / videoTextureView.getWidth(); @@ -6334,20 +6422,38 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat } else { interpolator = null; } + ViewOutlineProvider outlineProvider = new ViewOutlineProvider() { + @Override + public void getOutline(View view, Outline outline) { + outline.setRoundRect(0, 0, view.getMeasuredWidth(), view.getMeasuredHeight(), (float) valueAnimator.getAnimatedValue() * AndroidUtilities.dp(PipVideoOverlay.ROUNDED_CORNERS_DP) * (1f / scale)); + } + }; + videoTextureView.setOutlineProvider(outlineProvider); + videoTextureView.setClipToOutline(true); + textureImageView.setOutlineProvider(outlineProvider); + textureImageView.setClipToOutline(true); + if (firstFrameView != null) { + firstFrameView.setOutlineProvider(outlineProvider); + firstFrameView.setClipToOutline(true); + } + valueAnimator.addUpdateListener(animation -> { float xValue = (float) animation.getAnimatedValue(); float yValue = interpolator == null ? xValue : interpolator.getInterpolation(xValue); textureImageView.setTranslationX(fromX * (1f - xValue) + toX * xValue); textureImageView.setTranslationY(fromY2 * (1f - yValue) + toY * yValue); + textureImageView.invalidateOutline(); videoTextureView.setTranslationX(fromX * (1f - xValue) + (toX2) * xValue); videoTextureView.setTranslationY(fromY * (1f - yValue) + (toY2) * yValue); + videoTextureView.invalidateOutline(); if (firstFrameView != null) { firstFrameView.setTranslationX(videoTextureView.getTranslationX()); firstFrameView.setTranslationY(videoTextureView.getTranslationY()); firstFrameView.setScaleX(videoTextureView.getScaleX()); firstFrameView.setScaleY(videoTextureView.getScaleY()); + firstFrameView.invalidateOutline(); } }); @@ -6372,6 +6478,13 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat public void onAnimationEnd(Animator animation) { pipAnimationInProgress = false; switchToInlineRunnable.run(); + AndroidUtilities.runOnUIThread(()->{ + videoTextureView.setOutlineProvider(null); + textureImageView.setOutlineProvider(null); + if (firstFrameView != null) { + firstFrameView.setOutlineProvider(null); + } + }, 100); } }); animatorSet.start(); @@ -6415,6 +6528,9 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat isInline = false; if (photoViewerWebView == null && videoTextureView != null) { + if (videoTextureView.getParent() != null) { + ((ViewGroup) videoTextureView.getParent()).removeView(videoTextureView); + } videoTextureView.setVisibility(View.INVISIBLE); aspectRatioFrameLayout.addView(videoTextureView); } @@ -6428,9 +6544,9 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat } if (photoViewerWebView == null) { - if (Build.VERSION.SDK_INT >= 21 && videoTextureView != null) { + if (Build.VERSION.SDK_INT >= 21 && videoTextureView != null && PipVideoOverlay.IS_TRANSITION_ANIMATION_SUPPORTED) { pipAnimationInProgress = true; - org.telegram.ui.Components.Rect rect = PipVideoView.getPipRect(aspectRatioFrameLayout.getAspectRatio()); + org.telegram.ui.Components.Rect rect = PipVideoOverlay.getPipRect(false, aspectRatioFrameLayout.getAspectRatio()); float scale = rect.width / textureImageView.getLayoutParams().width; textureImageView.setScaleX(scale); @@ -6447,9 +6563,24 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat firstFrameView.setTranslationX(videoTextureView.getTranslationX()); firstFrameView.setTranslationY(videoTextureView.getTranslationY()); } + + inlineOutAnimationProgress = 0f; + ViewOutlineProvider outlineProvider = new ViewOutlineProvider() { + @Override + public void getOutline(View view, Outline outline) { + outline.setRoundRect(0, 0, view.getMeasuredWidth(), view.getMeasuredHeight(), (1f - inlineOutAnimationProgress) * AndroidUtilities.dp(PipVideoOverlay.ROUNDED_CORNERS_DP) * (1f / scale)); + } + }; + videoTextureView.setOutlineProvider(outlineProvider); + videoTextureView.setClipToOutline(true); + textureImageView.setOutlineProvider(outlineProvider); + textureImageView.setClipToOutline(true); + if (firstFrameView != null) { + firstFrameView.setOutlineProvider(outlineProvider); + firstFrameView.setClipToOutline(true); + } } else { - pipVideoView.close(); - pipVideoView = null; + PipVideoOverlay.dismiss(true); } } @@ -6622,7 +6753,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat } private void openCaptionEnter() { - if (imageMoveAnimation != null || changeModeAnimation != null || currentEditMode != 0 || sendPhotoType == SELECT_TYPE_AVATAR || sendPhotoType == SELECT_TYPE_WALLPAPER || sendPhotoType == SELECT_TYPE_QR) { + if (imageMoveAnimation != null || changeModeAnimation != null || currentEditMode != EDIT_MODE_NONE || sendPhotoType == SELECT_TYPE_AVATAR || sendPhotoType == SELECT_TYPE_WALLPAPER || sendPhotoType == SELECT_TYPE_QR) { return; } if (!windowView.isFocusable()) { @@ -7084,7 +7215,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat AndroidUtilities.runOnUIThread(updateProgressRunnable); } } else if (isPlaying || playbackState == ExoPlayer.STATE_ENDED) { - if (currentEditMode != 3) { + if (currentEditMode != EDIT_MODE_PAINT) { photoProgressViews[0].setIndexedAlpha(1, 1f, playbackState == ExoPlayer.STATE_ENDED); photoProgressViews[0].setBackgroundState(PROGRESS_PLAY, false, photoProgressViews[0].animAlphas[1] > 0f); } @@ -7094,14 +7225,14 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat if (isCurrentVideo) { if (!videoTimelineView.isDragging()) { videoTimelineView.setProgress(videoTimelineView.getLeftProgress()); - if (!inPreview && (currentEditMode != 0 || videoTimelineView.getVisibility() == View.VISIBLE)) { + if (!inPreview && (currentEditMode != EDIT_MODE_NONE || videoTimelineView.getVisibility() == View.VISIBLE)) { videoPlayer.seekTo((int) (videoTimelineView.getLeftProgress() * videoPlayer.getDuration())); } else { videoPlayer.seekTo(0); } manuallyPaused = false; cancelVideoPlayRunnable(); - if (sendPhotoType != SELECT_TYPE_AVATAR && currentEditMode == 0 && switchingToMode <= 0) { + if (sendPhotoType != SELECT_TYPE_AVATAR && currentEditMode == EDIT_MODE_NONE && switchingToMode <= 0) { videoPlayer.pause(); } else { videoPlayer.play(); @@ -7122,14 +7253,10 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat toggleActionBar(true, true); } } - if (pipVideoView != null) { - pipVideoView.onVideoCompleted(); - } + PipVideoOverlay.onVideoCompleted(); } } - if (pipVideoView != null) { - pipVideoView.updatePlayButton(); - } + PipVideoOverlay.updatePlayButton(); updateVideoPlayerTime(); } @@ -7227,7 +7354,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat @Override public void pause() { super.pause(); - if (currentEditMode == 0) { + if (currentEditMode == EDIT_MODE_NONE) { playOrStopAnimatedStickers(false); } } @@ -7286,6 +7413,9 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat width = height; height = temp; } + videoWidth = (int) (width * pixelWidthHeightRatio); + videoHeight = (int) (height * pixelWidthHeightRatio); + aspectRatioFrameLayout.setAspectRatio(height == 0 ? 1 : (width * pixelWidthHeightRatio) / height, unappliedRotationDegrees); if (videoTextureView instanceof VideoEditTextureView) { ((VideoEditTextureView) videoTextureView).setVideoSize((int) (width * pixelWidthHeightRatio), height); @@ -7346,8 +7476,12 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat aspectRatioFrameLayout.getLocationInWindow(pipPosition); //pipPosition[0] -= getLeftInset(); pipPosition[1] -= containerView.getTranslationY(); - textureImageView.setTranslationX(textureImageView.getTranslationX() + getLeftInset()); - videoTextureView.setTranslationX(videoTextureView.getTranslationX() + getLeftInset() - aspectRatioFrameLayout.getX()); + if (textureImageView != null) { + textureImageView.setTranslationX(textureImageView.getTranslationX() + getLeftInset()); + } + if (videoTextureView != null) { + videoTextureView.setTranslationX(videoTextureView.getTranslationX() + getLeftInset() - aspectRatioFrameLayout.getX()); + } if (firstFrameView != null) { firstFrameView.setTranslationX(videoTextureView.getTranslationX()); } @@ -7369,6 +7503,24 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat animators.add(ObjectAnimator.ofFloat(firstFrameView, View.TRANSLATION_X, pipPosition[0] - aspectRatioFrameLayout.getX())); animators.add(ObjectAnimator.ofFloat(firstFrameView, View.TRANSLATION_Y, pipPosition[1] - aspectRatioFrameLayout.getY())); } + + org.telegram.ui.Components.Rect pipRect = PipVideoOverlay.getPipRect(false, aspectRatioFrameLayout.getAspectRatio()); + float scale = pipRect.width / videoTextureView.getWidth(); + ValueAnimator valueAnimator = ValueAnimator.ofFloat(0, 1); + valueAnimator.addUpdateListener(animation -> { + inlineOutAnimationProgress = (float) animation.getAnimatedValue(); + if (videoTextureView != null) { + videoTextureView.invalidateOutline(); + } + if (textureImageView != null) { + textureImageView.invalidateOutline(); + } + if (firstFrameView != null) { + firstFrameView.invalidateOutline(); + } + }); + animators.add(valueAnimator); + animatorSet.playTogether(animators); final DecelerateInterpolator interpolator = new DecelerateInterpolator(); animatorSet.setInterpolator(interpolator); @@ -7377,6 +7529,15 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat @Override public void onAnimationEnd(Animator animation) { pipAnimationInProgress = false; + if (videoTextureView != null) { + videoTextureView.setOutlineProvider(null); + } + if (textureImageView != null) { + textureImageView.setOutlineProvider(null); + } + if (firstFrameView != null) { + firstFrameView.setOutlineProvider(null); + } } }); animatorSet.start(); @@ -7863,7 +8024,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat if (editState.mediaEntities != null) { for (int a = 0, N = editState.mediaEntities.size(); a < N; a++) { VideoEditedInfo.MediaEntity entity = editState.mediaEntities.get(a); - if (entity.type == 0 && (entity.subType & 1) != 0) { + if (entity.type == 0 && ((entity.subType & 1) != 0 || (entity.subType & 4) != 0)) { count++; if (single) { break; @@ -7931,7 +8092,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat int[] orientation = null; boolean hasChanged = false; MediaController.MediaEditState entry = (MediaController.MediaEditState) imagesArrLocals.get(currentIndex); - if (currentEditMode == 1 || currentEditMode == 0 && sendPhotoType == SELECT_TYPE_AVATAR) { + if (currentEditMode == EDIT_MODE_CROP || currentEditMode == EDIT_MODE_NONE && sendPhotoType == SELECT_TYPE_AVATAR) { photoCropView.makeCrop(entry); if (entry.cropState == null) { return; @@ -7951,10 +8112,10 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat bitmap = centerImage.getBitmap(); orientation = new int[]{centerImage.getOrientation()}; } - } else if (currentEditMode == 2) { + } else if (currentEditMode == EDIT_MODE_FILTER) { bitmap = photoFilterView.getBitmap(); savedFilterState = photoFilterView.getSavedFilterState(); - } else if (currentEditMode == 3) { + } else if (currentEditMode == EDIT_MODE_PAINT) { if (Build.VERSION.SDK_INT >= 18 && (sendPhotoType == 0 || sendPhotoType == SELECT_TYPE_AVATAR || sendPhotoType == 2)) { entities = new ArrayList<>(); } @@ -7975,7 +8136,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat entry.imagePath = null; } - if (currentEditMode == 1 || currentEditMode == 0 && sendPhotoType == SELECT_TYPE_AVATAR) { + if (currentEditMode == EDIT_MODE_CROP || currentEditMode == EDIT_MODE_NONE && sendPhotoType == SELECT_TYPE_AVATAR) { editState.cropState = entry.cropState; editState.croppedPaintPath = entry.croppedPaintPath; editState.croppedMediaEntities = entry.croppedMediaEntities; @@ -8010,11 +8171,11 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat TLRPC.PhotoSize size = ImageLoader.scaleAndSaveImage(croppedBitmap, thumbSize, thumbSize, 70, false, 101, 101); entry.thumbPath = FileLoader.getPathToAttach(size, true).toString(); } - if (currentEditMode == 0 && isCurrentVideo) { + if (currentEditMode == EDIT_MODE_NONE && isCurrentVideo) { bitmap.recycle(); bitmap = croppedBitmap; } - } else if (currentEditMode == 2) { + } else if (currentEditMode == EDIT_MODE_FILTER) { if (entry.filterPath != null) { new File(entry.filterPath).delete(); } @@ -8064,7 +8225,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat if (entry.cropState != null) { b.recycle(); } - } else if (currentEditMode == 3) { + } else if (currentEditMode == EDIT_MODE_PAINT) { if (entry.paintPath != null) { new File(entry.paintPath).delete(); if (!entry.paintPath.equals(entry.fullPaintPath)) { @@ -8190,13 +8351,13 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat if (savedFilterState != null) { entry.savedFilterState = editState.savedFilterState = savedFilterState; } - if (currentEditMode == 1) { + if (currentEditMode == EDIT_MODE_CROP) { entry.isCropped = true; cropItem.setColorFilter(new PorterDuffColorFilter(getThemedColor(Theme.key_dialogFloatingButton), PorterDuff.Mode.MULTIPLY)); - } else if (currentEditMode == 2) { + } else if (currentEditMode == EDIT_MODE_FILTER) { entry.isFiltered = true; tuneItem.setColorFilter(new PorterDuffColorFilter(getThemedColor(Theme.key_dialogFloatingButton), PorterDuff.Mode.MULTIPLY)); - } else if (currentEditMode == 3) { + } else if (currentEditMode == EDIT_MODE_PAINT) { if (hasChanged) { entry.isPainted = true; paintItem.setColorFilter(new PorterDuffColorFilter(getThemedColor(Theme.key_dialogFloatingButton), PorterDuff.Mode.MULTIPLY)); @@ -8209,7 +8370,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat setPhotoChecked(); } } - if (currentEditMode == 1) { + if (currentEditMode == EDIT_MODE_CROP) { float scaleX = photoCropView.getRectSizeX() / (float) getContainerViewWidth(); float scaleY = photoCropView.getRectSizeY() / (float) getContainerViewHeight(); scale = Math.max(scaleX, scaleY); @@ -8224,9 +8385,9 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat ignoreDidSetImage = true; boolean setImage; if (isCurrentVideo) { - setImage = currentEditMode == 1 || currentEditMode == 0 && sendPhotoType == SELECT_TYPE_AVATAR; + setImage = currentEditMode == EDIT_MODE_CROP || currentEditMode == EDIT_MODE_NONE && sendPhotoType == SELECT_TYPE_AVATAR; } else { - setImage = currentEditMode == 2; + setImage = currentEditMode == EDIT_MODE_FILTER; } if (setImage) { centerImage.setImageBitmap(bitmap); @@ -8391,8 +8552,11 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat if (currentEditMode == mode || (isCurrentVideo && photoProgressViews[0].backgroundState != 3) && !isCurrentVideo && (centerImage.getBitmap() == null || photoProgressViews[0].backgroundState != -1) || changeModeAnimation != null || imageMoveAnimation != null || captionEditText.getTag() != null) { return; } + windowView.setClipChildren(mode != EDIT_MODE_NONE && mode != EDIT_MODE_CROP); + navigationBar.setBackgroundColor(mode == EDIT_MODE_CROP ? 0xcc000000 : 0x7f000000); + navigationBar.setVisibility(mode == EDIT_MODE_NONE || mode == EDIT_MODE_CROP ? View.VISIBLE : View.INVISIBLE); switchingToMode = mode; - if (mode == 0) { // no edit mode + if (mode == EDIT_MODE_NONE) { Bitmap bitmap = centerImage.getBitmap(); if (bitmap != null) { int bitmapWidth = centerImage.getBitmapWidth(); @@ -8400,7 +8564,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat float newScale; float oldScale; - if (currentEditMode == 3) { + if (currentEditMode == EDIT_MODE_PAINT) { if (sendPhotoType != SELECT_TYPE_AVATAR) { if (cropTransform.getOrientation() == 90 || cropTransform.getOrientation() == 270) { int temp = bitmapWidth; @@ -8421,7 +8585,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat newScale = Math.min(getContainerViewWidth(0) / (float) bitmapWidth, getContainerViewHeight(0) / (float) bitmapHeight); oldScale = Math.min(getContainerViewWidth() / (float) bitmapWidth, getContainerViewHeight() / (float) bitmapHeight); } else { - if (currentEditMode != 1 && editState.cropState != null && (editState.cropState.transformRotation == 90 || editState.cropState.transformRotation == 270)) { + if (currentEditMode != EDIT_MODE_CROP && editState.cropState != null && (editState.cropState.transformRotation == 90 || editState.cropState.transformRotation == 270)) { float scaleToFitX = getContainerViewWidth() / (float) bitmapHeight; if (scaleToFitX * bitmapWidth > getContainerViewHeight()) { scaleToFitX = getContainerViewHeight() / (float) bitmapWidth; @@ -8462,17 +8626,17 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat animateToX = 0; translationX = getLeftInset() / 2 - getRightInset() / 2; if (sendPhotoType == SELECT_TYPE_AVATAR) { - if (currentEditMode == 2) { + if (currentEditMode == EDIT_MODE_FILTER) { animateToY = AndroidUtilities.dp(36); - } else if (currentEditMode == 3) { + } else if (currentEditMode == EDIT_MODE_PAINT) { animateToY = -AndroidUtilities.dp(12); } } else { - if (currentEditMode == 1) { + if (currentEditMode == EDIT_MODE_CROP) { animateToY = AndroidUtilities.dp(24 + 32); - } else if (currentEditMode == 2) { + } else if (currentEditMode == EDIT_MODE_FILTER) { animateToY = AndroidUtilities.dp(93); - } else if (currentEditMode == 3) { + } else if (currentEditMode == EDIT_MODE_PAINT) { animateToY = AndroidUtilities.dp(44); } if (isStatusBarVisible()) { @@ -8486,17 +8650,17 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat imageMoveAnimation = new AnimatorSet(); ArrayList animators = new ArrayList<>(4); - if (currentEditMode == 1) { + if (currentEditMode == EDIT_MODE_CROP) { animators.add(ObjectAnimator.ofFloat(editorDoneLayout, View.TRANSLATION_Y, AndroidUtilities.dp(48))); animators.add(ObjectAnimator.ofFloat(PhotoViewer.this, AnimationProperties.PHOTO_VIEWER_ANIMATION_VALUE, 0, 1)); animators.add(ObjectAnimator.ofFloat(photoCropView, View.ALPHA, 0)); - } else if (currentEditMode == 2) { + } else if (currentEditMode == EDIT_MODE_FILTER) { photoFilterView.shutdown(); animators.add(ObjectAnimator.ofFloat(photoFilterView.getToolsView(), View.TRANSLATION_Y, AndroidUtilities.dp(186))); animators.add(ObjectAnimator.ofFloat(photoFilterView.getCurveControl(), View.ALPHA, 0.0f)); animators.add(ObjectAnimator.ofFloat(photoFilterView.getBlurControl(), View.ALPHA, 0.0f)); animators.add(ObjectAnimator.ofFloat(PhotoViewer.this, AnimationProperties.PHOTO_VIEWER_ANIMATION_VALUE, 0, 1)); - } else if (currentEditMode == 3) { + } else if (currentEditMode == EDIT_MODE_PAINT) { paintingOverlay.showAll(); containerView.invalidate(); photoPaintView.shutdown(); @@ -8509,19 +8673,19 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat imageMoveAnimation.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { - if (currentEditMode == 1) { + if (currentEditMode == EDIT_MODE_CROP) { photoCropView.onDisappear(); photoCropView.onHide(); editorDoneLayout.setVisibility(View.GONE); photoCropView.setVisibility(View.GONE); - } else if (currentEditMode == 2) { + } else if (currentEditMode == EDIT_MODE_FILTER) { try { containerView.removeView(photoFilterView); } catch (Exception e) { FileLog.e(e); } photoFilterView = null; - } else if (currentEditMode == 3) { + } else if (currentEditMode == EDIT_MODE_PAINT) { try { containerView.removeView(photoPaintView); } catch (Exception e) { @@ -8576,6 +8740,10 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat muteItem.setVisibility(View.VISIBLE); arrayList.add(ObjectAnimator.ofFloat(muteItem, View.ALPHA, 1)); } + if (navigationBar != null) { + navigationBar.setVisibility(View.VISIBLE); + arrayList.add(ObjectAnimator.ofFloat(navigationBar, View.ALPHA, 1)); + } animatorSet.playTogether(arrayList); animatorSet.setDuration(200); animatorSet.addListener(new AnimatorListenerAdapter() { @@ -8597,7 +8765,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat } }); imageMoveAnimation.start(); - } else if (mode == 1) { // crop + } else if (mode == EDIT_MODE_CROP) { startVideoPlayer(); createCropView(); previousHasTransform = cropTransform.hasViewTransform(); @@ -8635,6 +8803,9 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat if (muteItem.getTag() != null) { arrayList.add(ObjectAnimator.ofFloat(muteItem, View.ALPHA, 1, 0)); } + if (navigationBar != null) { + arrayList.add(ObjectAnimator.ofFloat(navigationBar, View.ALPHA, 1)); + } changeModeAnimation.playTogether(arrayList); changeModeAnimation.setDuration(200); changeModeAnimation.addListener(new AnimatorListenerAdapter() { @@ -8730,7 +8901,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat } }); changeModeAnimation.start(); - } else if (mode == 2) { // filter + } else if (mode == EDIT_MODE_FILTER) { startVideoPlayer(); if (photoFilterView == null) { MediaController.SavedFilterState state = null; @@ -8770,7 +8941,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat containerView.addView(photoFilterView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); photoFilterView.getDoneTextView().setOnClickListener(v -> { applyCurrentEditMode(); - switchToEditMode(0); + switchToEditMode(EDIT_MODE_NONE); }); photoFilterView.getCancelTextView().setOnClickListener(v -> { if (photoFilterView.hasChanges()) { @@ -8784,7 +8955,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); showAlertDialog(builder); } else { - switchToEditMode(0); + switchToEditMode(EDIT_MODE_NONE); } }); photoFilterView.getToolsView().setTranslationY(AndroidUtilities.dp(186)); @@ -8894,7 +9065,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat } }); changeModeAnimation.start(); - } else if (mode == 3) { + } else if (mode == EDIT_MODE_PAINT) { startVideoPlayer(); createPaintView(); @@ -8995,7 +9166,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat photoPaintView.getDoneTextView().setOnClickListener(v -> { savedState = null; applyCurrentEditMode(); - switchToEditMode(0); + switchToEditMode(EDIT_MODE_NONE); }); photoPaintView.getCancelTextView().setOnClickListener(v -> closePaintMode()); photoPaintView.getColorPicker().setTranslationY(AndroidUtilities.dp(126)); @@ -9004,7 +9175,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat } private void closePaintMode() { - photoPaintView.maybeShowDismissalAlert(PhotoViewer.this, parentActivity, () -> switchToEditMode(0)); + photoPaintView.maybeShowDismissalAlert(PhotoViewer.this, parentActivity, () -> switchToEditMode(EDIT_MODE_NONE)); } private void switchToPaintMode() { @@ -9064,6 +9235,8 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat zoomAnimation = true; } + windowView.setClipChildren(true); + navigationBar.setVisibility(View.INVISIBLE); imageMoveAnimation = new AnimatorSet(); imageMoveAnimation.playTogether( ObjectAnimator.ofFloat(PhotoViewer.this, AnimationProperties.PHOTO_VIEWER_ANIMATION_VALUE, 0, 1), @@ -9082,7 +9255,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat photoPaintView.init(); paintingOverlay.hideEntities(); imageMoveAnimation = null; - currentEditMode = 3; + currentEditMode = EDIT_MODE_PAINT; switchingToMode = -1; animateToScale = 1; animateToX = 0; @@ -9290,11 +9463,6 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat } if (navigationBar != null) { arrayList.add(ObjectAnimator.ofFloat(navigationBar, View.ALPHA, show ? 1.0f : 0.0f)); - if (params.enableTranslationAnimation) { - arrayList.add(ObjectAnimator.ofFloat(navigationBar, View.TRANSLATION_Y, show ? 0 : offsetY)); - } else { - navigationBar.setTranslationY(0); - } } if (videoPlayerControlVisible) { arrayList.add(ObjectAnimator.ofFloat(videoPlayerControlFrameLayout, VPC_PROGRESS, show ? 1.0f : 0.0f)); @@ -9366,7 +9534,6 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat bottomLayout.setAlpha(show ? 1.0f : 0.0f); bottomLayout.setTranslationY(show ? 0 : offsetY); navigationBar.setAlpha(show ? 1.0f : 0.0f); - navigationBar.setTranslationY(show ? 0 : offsetY); groupedPhotosListView.setAlpha(show ? 1.0f : 0.0f); groupedPhotosListView.setTranslationY(show ? 0 : offsetY); if (!needCaptionLayout && captionScrollView != null) { @@ -9735,7 +9902,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat canEditAvatar = false; totalImagesCount = 0; totalImagesCountMerge = 0; - currentEditMode = 0; + currentEditMode = EDIT_MODE_NONE; isFirstLoading = true; needSearchImageInArr = false; loadingMoreImages = false; @@ -10075,6 +10242,10 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat pickerViewSendButton.setVisibility(View.VISIBLE); pickerViewSendButton.setTranslationY(0); pickerViewSendButton.setAlpha(1.0f); + if (navigationBar != null) { + navigationBar.setVisibility(View.VISIBLE); + navigationBar.setAlpha(1.0f); + } bottomLayout.setVisibility(View.GONE); bottomLayout.setTag(null); containerView.setTag(null); @@ -10142,9 +10313,9 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat private void setImages() { if (animationInProgress == 0) { - setIndexToImage(centerImage, currentIndex); - setIndexToImage(rightImage, currentIndex + 1); - setIndexToImage(leftImage, currentIndex - 1); + setIndexToImage(centerImage, currentIndex, null, paintingOverlay); + setIndexToImage(rightImage, currentIndex + 1, rightCropTransform, rightPaintingOverlay); + setIndexToImage(leftImage, currentIndex - 1, leftCropTransform, leftPaintingOverlay); } } @@ -10788,6 +10959,11 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat boolean isVideo = false; boolean sameImage = false; Uri videoPath = null; + + CropTransform prevCropTransform = cropTransform.clone(); + MediaController.CropState prevCropState = editState == null || editState.cropState == null ? null : editState.cropState.clone(); + boolean prevIsVideo = centerImageIsVideo; + editState.reset(); if (!imagesArr.isEmpty()) { @@ -11015,6 +11191,8 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat editState.reset(); } + centerImageIsVideo = isVideo; + if (prevIndex == -1) { setImages(); @@ -11029,6 +11207,10 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat centerImage = leftImage; leftImage = temp; + rightImageIsVideo = prevIsVideo; + rightCropTransform = prevCropTransform; + rightCropState = prevCropState; + PhotoProgressView tempProgress = photoProgressViews[0]; photoProgressViews[0] = photoProgressViews[2]; photoProgressViews[2] = tempProgress; @@ -11038,7 +11220,8 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat fullscreenButton[2] = tmp; fullscreenButton[0].setTranslationY(tmp.getTranslationY()); - setIndexToImage(leftImage, currentIndex - 1); + leftCropState = null; + setIndexToImage(leftImage, currentIndex - 1, leftCropTransform, leftPaintingOverlay); updateAccessibilityOverlayVisibility(); checkProgress(1, true, false); @@ -11049,6 +11232,10 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat centerImage = rightImage; rightImage = temp; + leftImageIsVideo = prevIsVideo; + leftCropTransform = prevCropTransform; + leftCropState = prevCropState; + PhotoProgressView tempProgress = photoProgressViews[0]; photoProgressViews[0] = photoProgressViews[1]; photoProgressViews[1] = tempProgress; @@ -11058,7 +11245,8 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat fullscreenButton[1] = tmp; fullscreenButton[0].setTranslationY(tmp.getTranslationY()); - setIndexToImage(rightImage, currentIndex + 1); + rightCropState = null; + setIndexToImage(rightImage, currentIndex + 1, rightCropTransform, rightPaintingOverlay); updateAccessibilityOverlayVisibility(); checkProgress(1, true, false); @@ -11481,7 +11669,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat return captionEditText != null ? captionEditText.getSelectionLength() : 0; } - private void setIndexToImage(ImageReceiver imageReceiver, int index) { + private void setIndexToImage(ImageReceiver imageReceiver, int index, CropTransform cropTransform, PaintingOverlay paintingOverlay) { imageReceiver.setOrientation(0, false); if (!secureDocuments.isEmpty()) { if (index >= 0 && index < secureDocuments.size()) { @@ -11515,12 +11703,14 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat ImageLocation videoThumb = null; TLRPC.PhotoSize photo = null; TLObject photoObject = null; + MediaController.CropState cropState = null; int imageSize = 0; String filter = null; boolean isVideo = false; int cacheType = 0; if (object instanceof MediaController.PhotoEntry) { MediaController.PhotoEntry photoEntry = (MediaController.PhotoEntry) object; + cropState = photoEntry.cropState; isVideo = photoEntry.isVideo; if (photoEntry.isVideo) { if (photoEntry.thumbPath != null) { @@ -11596,6 +11786,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat path = photoEntry.imageUrl; imageSize = photoEntry.size; } + cropState = photoEntry.cropState; filter = "d"; } if (document != null) { @@ -11616,6 +11807,22 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat } else { imageReceiver.setImage(path, filter, placeHolder != null ? new BitmapDrawable(placeHolder.bitmap) : (isVideo && parentActivity != null ? parentActivity.getResources().getDrawable(R.drawable.nophotos) : null), null, imageSize); } + + if (cropTransform != null) { + if (cropState != null) { + cropTransform.setViewTransform(true, cropState.cropPx, cropState.cropPy, cropState.cropRotate, cropState.transformRotation, cropState.cropScale, 1.0f, 1.0f, cropState.cropPw, cropState.cropPh, 0, 0, cropState.mirrored); + } else { + cropTransform.setViewTransform(false); + } + } + + if (imageReceiver == leftImage) { + leftCropState = cropState; + leftImageIsVideo = isVideo; + } else if (imageReceiver == rightImage) { + rightCropState = cropState; + rightImageIsVideo = isVideo; + } } else { imageReceiver.setImageBitmap((Bitmap) null); } @@ -11755,7 +11962,9 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat parentObject = null; } if (videoThumb != null) { - imageReceiver.setImage(imageLocation, null, videoThumb, null, placeHolder == null ? ImageLocation.getForObject(thumbLocation, photoObject) : null, "b", placeHolder != null ? new BitmapDrawable(placeHolder.bitmap) : null, size[0], null, parentObject, cacheOnly ? 1 : 0); + String filter = sharedMediaType == MediaDataController.MEDIA_GIF ? ImageLoader.AUTOPLAY_FILTER : null; + imageReceiver.setImage(imageLocation, filter, videoThumb, null, placeHolder == null ? ImageLocation.getForObject(thumbLocation, photoObject) : null, "b", placeHolder != null ? new BitmapDrawable(placeHolder.bitmap) : null, size[0], null, parentObject, cacheOnly ? 1 : 0); + imageReceiver.setAllowStartAnimation(true); } else { String filter; if (avatarsDialogId != 0) { @@ -12231,6 +12440,9 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat } } + windowView.setClipChildren(false); + navigationBar.setVisibility(View.VISIBLE); + seekToProgressPending2 = 0; skipFirstBufferingProgress = false; playerInjected = false; @@ -12402,6 +12614,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat } backgroundDrawable.setAlpha(0); containerView.setAlpha(0); + navigationBar.setAlpha(0); animationEndRunnable = () -> { animationEndRunnable = null; @@ -12450,6 +12663,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat } animators.add(ObjectAnimator.ofInt(backgroundDrawable, AnimationProperties.COLOR_DRAWABLE_ALPHA, 0, 255)); animators.add(ObjectAnimator.ofFloat(containerView, View.ALPHA, 0.0f, 1.0f)); + animators.add(ObjectAnimator.ofFloat(navigationBar, View.ALPHA, 0.0f, 1.0f)); if (sendPhotoType == SELECT_TYPE_AVATAR) { animators.add(ObjectAnimator.ofFloat(photoCropView, View.ALPHA, 0, 1.0f)); } @@ -12551,11 +12765,11 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat animationInProgress = 4; containerView.invalidate(); AnimatorSet animatorSet = new AnimatorSet(); - ObjectAnimator alphaAnimator = ObjectAnimator.ofFloat(containerView, View.ALPHA, 0f, 1f).setDuration(220); ObjectAnimator a2 = ObjectAnimator.ofFloat(pickerView, View.TRANSLATION_Y, pickerView.getTranslationY(), 0f).setDuration(220); a2.setInterpolator(CubicBezierInterpolator.DEFAULT); animatorSet.playTogether( - alphaAnimator, + ObjectAnimator.ofFloat(containerView, View.ALPHA, 0f, 1f).setDuration(220), + ObjectAnimator.ofFloat(navigationBar, View.ALPHA, 0f, 1f).setDuration(220), a2 ); animatorSet.addListener(new AnimatorListenerAdapter() { @@ -12652,15 +12866,15 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat } public void closePhoto(boolean animated, boolean fromEditMode) { - if (!fromEditMode && currentEditMode != 0) { - if (currentEditMode == 3 && photoPaintView != null) { + if (!fromEditMode && currentEditMode != EDIT_MODE_NONE) { + if (currentEditMode == EDIT_MODE_PAINT && photoPaintView != null) { closePaintMode(); return; } - if (currentEditMode == 1) { + if (currentEditMode == EDIT_MODE_CROP) { cropTransform.setViewTransform(previousHasTransform, previousCropPx, previousCropPy, previousCropRotation, previousCropOrientation, previousCropScale, 1.0f, 1.0f, previousCropPw, previousCropPh, 0, 0, previousCropMirrored); } - switchToEditMode(0); + switchToEditMode(EDIT_MODE_NONE); return; } if (qualityChooseView != null && qualityChooseView.getTag() != null) { @@ -12680,21 +12894,28 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat AndroidUtilities.cancelRunOnUIThread(updateContainerFlagsRunnable); updateContainerFlags(true); } - if (currentEditMode != 0) { - if (currentEditMode == 2) { + if (currentEditMode != EDIT_MODE_NONE) { + if (currentEditMode == EDIT_MODE_FILTER) { photoFilterView.shutdown(); containerView.removeView(photoFilterView); photoFilterView = null; - } else if (currentEditMode == 1) { + } else if (currentEditMode == EDIT_MODE_CROP) { editorDoneLayout.setVisibility(View.GONE); photoCropView.setVisibility(View.GONE); - } else if (currentEditMode == 3) { + } else if (currentEditMode == EDIT_MODE_PAINT) { photoPaintView.shutdown(); containerView.removeView(photoPaintView); photoPaintView = null; savedState = null; } - currentEditMode = 0; + currentEditMode = EDIT_MODE_NONE; + } + + if (navigationBar != null) { + navigationBar.setVisibility(View.VISIBLE); + } + if (windowView != null) { + windowView.setClipChildren(false); } if (parentActivity == null || !isInline && !isVisible || checkAnimation() || placeProvider == null) { @@ -12906,6 +13127,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat } animators.add(ObjectAnimator.ofInt(backgroundDrawable, AnimationProperties.COLOR_DRAWABLE_ALPHA, 0)); animators.add(ObjectAnimator.ofFloat(containerView, View.ALPHA, 0.0f)); + animators.add(ObjectAnimator.ofFloat(navigationBar, View.ALPHA, 0.0f)); if (sendPhotoType == SELECT_TYPE_AVATAR) { animators.add(ObjectAnimator.ofFloat(photoCropView, View.ALPHA, 0.0f)); } @@ -12916,7 +13138,8 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat ObjectAnimator.ofInt(backgroundDrawable, AnimationProperties.COLOR_DRAWABLE_ALPHA, 0), ObjectAnimator.ofFloat(animatingImageView, View.ALPHA, 0.0f), ObjectAnimator.ofFloat(animatingImageView, View.TRANSLATION_Y, translationY >= 0 ? h : -h), - ObjectAnimator.ofFloat(containerView, View.ALPHA, 0.0f) + ObjectAnimator.ofFloat(containerView, View.ALPHA, 0.0f), + ObjectAnimator.ofFloat(navigationBar, View.ALPHA, 0.0f) ); } @@ -12952,7 +13175,8 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat ObjectAnimator.ofFloat(containerView, View.SCALE_X, 0.9f), ObjectAnimator.ofFloat(containerView, View.SCALE_Y, 0.9f), ObjectAnimator.ofInt(backgroundDrawable, AnimationProperties.COLOR_DRAWABLE_ALPHA, 0), - ObjectAnimator.ofFloat(containerView, View.ALPHA, 0.0f) + ObjectAnimator.ofFloat(containerView, View.ALPHA, 0.0f), + ObjectAnimator.ofFloat(navigationBar, View.ALPHA, 0.0f) ); animationInProgress = 2; animationEndRunnable = () -> { @@ -13035,9 +13259,8 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat if (parentActivity == null || windowView == null) { return; } - if (pipVideoView != null) { - pipVideoView.close(); - pipVideoView = null; + if (PipVideoOverlay.isVisible()) { + PipVideoOverlay.dismiss(); } removeObservers(); releasePlayer(false); @@ -13169,11 +13392,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat } } - public void onConfigurationChanged(Configuration newConfig) { - if (pipVideoView != null) { - pipVideoView.onConfigurationChanged(); - } - } + public void onConfigurationChanged(Configuration newConfig) {} public void onPause() { if (currentAnimation != null) { @@ -13193,7 +13412,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat } private void updateMinMax(float scale) { - if (currentEditMode == 3 && aspectRatioFrameLayout != null && aspectRatioFrameLayout.getVisibility() == View.VISIBLE && textureUploaded) { + if (aspectRatioFrameLayout != null && aspectRatioFrameLayout.getVisibility() == View.VISIBLE && textureUploaded) { scale *= Math.min(getContainerViewWidth() / (float) videoTextureView.getMeasuredWidth(), getContainerViewHeight() / (float) videoTextureView.getMeasuredHeight()); } float w = centerImage.getImageWidth(); @@ -13220,20 +13439,20 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat } private int getAdditionX() { - if (currentEditMode == 1 || currentEditMode == 0 && sendPhotoType == SELECT_TYPE_AVATAR) { + if (currentEditMode == EDIT_MODE_CROP || currentEditMode == EDIT_MODE_NONE && sendPhotoType == SELECT_TYPE_AVATAR) { return AndroidUtilities.dp(16); - } else if (currentEditMode != 0 && currentEditMode != 3) { + } else if (currentEditMode != EDIT_MODE_NONE && currentEditMode != EDIT_MODE_PAINT) { return AndroidUtilities.dp(14); } return 0; } private int getAdditionY() { - if (currentEditMode == 1 || currentEditMode == 0 && sendPhotoType == SELECT_TYPE_AVATAR) { + if (currentEditMode == EDIT_MODE_CROP || currentEditMode == EDIT_MODE_NONE && sendPhotoType == SELECT_TYPE_AVATAR) { return AndroidUtilities.dp(16) + (isStatusBarVisible() ? AndroidUtilities.statusBarHeight : 0); - } else if (currentEditMode == 3) { + } else if (currentEditMode == EDIT_MODE_PAINT) { return AndroidUtilities.dp(8) + (isStatusBarVisible() ? AndroidUtilities.statusBarHeight : 0); - } else if (currentEditMode != 0) { + } else if (currentEditMode != EDIT_MODE_NONE) { return AndroidUtilities.dp(14) + (isStatusBarVisible() ? AndroidUtilities.statusBarHeight : 0); } return 0; @@ -13285,7 +13504,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat Runnable longPressRunnable = this::onLongPress; private boolean onTouchEvent(MotionEvent ev) { - if (currentEditMode == 3 && animationStartTime != 0 && (ev.getActionMasked() == MotionEvent.ACTION_DOWN || ev.getActionMasked() == MotionEvent.ACTION_POINTER_DOWN)) { + if (currentEditMode == EDIT_MODE_PAINT && animationStartTime != 0 && (ev.getActionMasked() == MotionEvent.ACTION_DOWN || ev.getActionMasked() == MotionEvent.ACTION_POINTER_DOWN)) { if (ev.getPointerCount() >= 2) { cancelMoveZoomAnimation(); } else { @@ -13304,10 +13523,10 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat return true; } - if (currentEditMode == 2) { + if (currentEditMode == EDIT_MODE_FILTER) { photoFilterView.onTouch(ev); return true; - } else if (currentEditMode == 1 || currentEditMode != 3 && sendPhotoType == SELECT_TYPE_AVATAR) { + } else if (currentEditMode == EDIT_MODE_CROP || currentEditMode != EDIT_MODE_PAINT && sendPhotoType == SELECT_TYPE_AVATAR) { return true; } @@ -13318,7 +13537,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat return true; } - if (currentEditMode == 0 && sendPhotoType != SELECT_TYPE_AVATAR && ev.getPointerCount() == 1 && gestureDetector.onTouchEvent(ev)) { + if (currentEditMode == EDIT_MODE_NONE && sendPhotoType != SELECT_TYPE_AVATAR && ev.getPointerCount() == 1 && gestureDetector.onTouchEvent(ev)) { if (doubleTap) { doubleTap = false; moving = false; @@ -13353,7 +13572,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat pinchStartY = translationY; zooming = true; moving = false; - if (currentEditMode == 3) { + if (currentEditMode == EDIT_MODE_PAINT) { moveStartX = pinchCenterX; moveStartY = pinchCenterY; draggingDown = false; @@ -13364,7 +13583,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat velocityTracker.clear(); } } else if (ev.getPointerCount() == 1) { - if (currentEditMode == 3) { + if (currentEditMode == EDIT_MODE_PAINT) { if (paintViewTouched == 0) { photoPaintView.getHitRect(hitRect); if (hitRect.contains((int) ev.getX(), (int) ev.getY())) { @@ -13396,7 +13615,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat if (canZoom && ev.getPointerCount() == 2 && !draggingDown && zooming && !changingPage) { discardTap = true; - if (currentEditMode == 3) { + if (currentEditMode == EDIT_MODE_PAINT) { float newPinchCenterX = (ev.getX(0) + ev.getX(1)) / 2.0f; float newPinchCenterY = (ev.getY(0) + ev.getY(1)) / 2.0f; float moveDx = moveStartX - newPinchCenterX; @@ -13440,7 +13659,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat return true; } } - if (placeProvider.canScrollAway() && currentEditMode == 0 && sendPhotoType != SELECT_TYPE_AVATAR && canDragDown && !draggingDown && scale == 1 && dy >= AndroidUtilities.dp(30) && dy / 2 > dx) { + if (placeProvider.canScrollAway() && currentEditMode == EDIT_MODE_NONE && sendPhotoType != SELECT_TYPE_AVATAR && canDragDown && !draggingDown && scale == 1 && dy >= AndroidUtilities.dp(30) && dy / 2 > dx) { draggingDown = true; hidePressedDrawables(); moving = false; @@ -13459,7 +13678,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat } else if (!invalidCoords && animationStartTime == 0) { float moveDx = moveStartX - ev.getX(); float moveDy = moveStartY - ev.getY(); - if (moving || currentEditMode != 0 || scale == 1 && Math.abs(moveDy) + AndroidUtilities.dp(12) < Math.abs(moveDx) || scale != 1) { + if (moving || currentEditMode != EDIT_MODE_NONE || scale == 1 && Math.abs(moveDy) + AndroidUtilities.dp(12) < Math.abs(moveDx) || scale != 1) { if (!moving) { moveDx = 0; moveDy = 0; @@ -13471,10 +13690,10 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat moveStartX = ev.getX(); moveStartY = ev.getY(); updateMinMax(scale); - if (translationX < minX && (currentEditMode != 0 || !rightImage.hasImageSet()) || translationX > maxX && (currentEditMode != 0 || !leftImage.hasImageSet())) { + if (translationX < minX && (currentEditMode != EDIT_MODE_NONE || !rightImage.hasImageSet()) || translationX > maxX && (currentEditMode != EDIT_MODE_NONE || !leftImage.hasImageSet())) { moveDx /= 3.0f; } - if (maxY == 0 && minY == 0 && currentEditMode == 0 && sendPhotoType != SELECT_TYPE_AVATAR) { + if (maxY == 0 && minY == 0 && currentEditMode == EDIT_MODE_NONE && sendPhotoType != SELECT_TYPE_AVATAR) { if (translationY - moveDy < minY) { translationY = minY; moveDy = 0; @@ -13489,7 +13708,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat } translationX -= moveDx; - if (scale != 1 || currentEditMode != 0) { + if (scale != 1 || currentEditMode != EDIT_MODE_NONE) { translationY -= moveDy; } containerView.invalidate(); @@ -13535,7 +13754,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat animateTo(3.0f, atx, aty, true); } else { checkMinMax(true); - if (currentEditMode == 3) { + if (currentEditMode == EDIT_MODE_PAINT) { float moveToX = translationX; float moveToY = translationY; updateMinMax(scale); @@ -13581,7 +13800,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat velocity = velocityTracker.getXVelocity(); } - if (currentEditMode == 0 && sendPhotoType != SELECT_TYPE_AVATAR) { + if (currentEditMode == EDIT_MODE_NONE && sendPhotoType != SELECT_TYPE_AVATAR) { if ((translationX < minX - getContainerViewWidth() / 3 || velocity < -AndroidUtilities.dp(650)) && rightImage.hasImageSet()) { goToNext(); return true; @@ -13869,7 +14088,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat int containerWidth = getContainerViewWidth(); int containerHeight = getContainerViewHeight(); if (animationInProgress != 2 && animationInProgress != 4 && !pipAnimationInProgress && !isInline) { - if (currentEditMode == 0 && sendPhotoType != SELECT_TYPE_AVATAR && scale == 1 && aty != -1 && !zoomAnimation) { + if (currentEditMode == EDIT_MODE_NONE && sendPhotoType != SELECT_TYPE_AVATAR && scale == 1 && aty != -1 && !zoomAnimation) { float maxValue = containerWidth / 4.0f; backgroundDrawable.setAlpha((int) Math.max(127, 255 * (1.0f - (Math.min(Math.abs(aty), maxValue) / maxValue)))); } else { @@ -13880,7 +14099,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat } sideImage = null; - if (currentEditMode == 0 && sendPhotoType != SELECT_TYPE_AVATAR) { + if (currentEditMode == EDIT_MODE_NONE && sendPhotoType != SELECT_TYPE_AVATAR) { if (scale >= 1.0f && !zoomAnimation && !zooming) { if (currentTranslationX > maxX + AndroidUtilities.dp(5)) { sideImage = leftImage; @@ -13922,6 +14141,9 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat canvas.scale(1.0f - scaleDiff, 1.0f - scaleDiff); int bitmapWidth = sideImage.getBitmapWidth(); int bitmapHeight = sideImage.getBitmapHeight(); + if (!rightImageIsVideo && rightCropTransform.hasViewTransform()) { + applyCrop(canvas, containerWidth, containerHeight, bitmapWidth, bitmapHeight, currentScale, rightCropTransform, rightCropState); + } float scaleX = containerWidth / (float) bitmapWidth; float scaleY = containerHeight / (float) bitmapHeight; @@ -13958,7 +14180,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat float translateX = currentTranslationX; float scaleDiff = 0; float alpha = 1; - if (!zoomAnimation && translateX > maxX && currentEditMode == 0 && sendPhotoType != SELECT_TYPE_AVATAR) { + if (!zoomAnimation && translateX > maxX && currentEditMode == EDIT_MODE_NONE && sendPhotoType != SELECT_TYPE_AVATAR) { alpha = Math.min(1.0f, (translateX - maxX) / containerWidth); scaleDiff = alpha * 0.3f; alpha = 1.0f - alpha; @@ -13968,9 +14190,9 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat if (centerImage.hasBitmapImage() || drawTextureView && textureUploaded) { canvas.save(); canvas.translate(containerWidth / 2 + getAdditionX(), containerHeight / 2 + getAdditionY()); - canvas.translate(translateX, currentTranslationY + (currentEditMode != 3 ? currentPanTranslationY : currentPanTranslationY / 2)); + canvas.translate(translateX, currentTranslationY + (currentEditMode != EDIT_MODE_PAINT ? currentPanTranslationY : currentPanTranslationY / 2)); canvas.scale(currentScale - scaleDiff, currentScale - scaleDiff); - if (currentEditMode == 3 && keyboardSize > AndroidUtilities.dp(20)) { + if (currentEditMode == EDIT_MODE_PAINT && keyboardSize > AndroidUtilities.dp(20)) { int trueH = getContainerViewHeight(true, 0); int h = getContainerViewHeight(false, 0); if (trueH != h) { @@ -13994,7 +14216,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat int width = centerImage.getBitmapWidth(); int height = centerImage.getBitmapHeight(); float scale; - if (isCurrentVideo && currentEditMode == 0 && sendPhotoType == SELECT_TYPE_AVATAR) { + if (isCurrentVideo && currentEditMode == EDIT_MODE_NONE && sendPhotoType == SELECT_TYPE_AVATAR) { scale = getCropFillScale(false); } else { scale = Math.min(containerWidth / (float) width, containerHeight / (float) height); @@ -14027,12 +14249,12 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat boolean applyCrop; float scaleToFitX = 1.0f; if (!imagesArrLocals.isEmpty()) { - if (currentEditMode == 3 || switchingToMode == 3) { + if (currentEditMode == EDIT_MODE_PAINT || switchingToMode == 3) { applyCrop = true; } else if (sendPhotoType == SELECT_TYPE_AVATAR) { - applyCrop = (switchingToMode == 0 || currentEditMode != 3 && currentEditMode != 2); + applyCrop = (switchingToMode == 0 || currentEditMode != EDIT_MODE_PAINT && currentEditMode != EDIT_MODE_FILTER); } else { - applyCrop = imageMoveAnimation != null && switchingToMode != -1 || currentEditMode == 0 || currentEditMode == 1 || switchingToMode != -1; + applyCrop = imageMoveAnimation != null && switchingToMode != -1 || currentEditMode == EDIT_MODE_NONE || currentEditMode == EDIT_MODE_CROP || switchingToMode != -1; } } else { applyCrop = false; @@ -14145,7 +14367,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat } } } - if (currentEditMode == 3) { + if (currentEditMode == EDIT_MODE_PAINT) { float add = containerView.adjustPanLayoutHelper.animationInProgress() ? keyboardSize / 2f + currentPanTranslationY / 2 : 0; photoPaintView.setTransform(currentScale, currentTranslationX, currentTranslationY + add, bitmapWidth * scaleToFitX, bitmapHeight * scaleToFitX); } @@ -14153,7 +14375,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat if (drawCenterImage) { boolean mirror = false; if (!imagesArrLocals.isEmpty()) { - if (currentEditMode == 1 || sendPhotoType == SELECT_TYPE_AVATAR) { + if (currentEditMode == EDIT_MODE_CROP || sendPhotoType == SELECT_TYPE_AVATAR) { mirror = cropTransform.isMirrored(); } else { mirror = editState.cropState != null && editState.cropState.mirrored; @@ -14196,7 +14418,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat } paintingOverlay.setAlpha(alpha); } - if (paintingOverlay.getVisibility() == View.VISIBLE && (isCurrentVideo || currentEditMode != 2 || switchingToMode != -1)) { + if (paintingOverlay.getVisibility() == View.VISIBLE && (isCurrentVideo || currentEditMode != EDIT_MODE_FILTER || switchingToMode != -1)) { canvas.clipRect(0, 0, paintingOverlay.getMeasuredWidth(), paintingOverlay.getMeasuredHeight()); paintingOverlay.draw(canvas); } @@ -14275,7 +14497,9 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat canvas.translate(-(containerWidth * (scale + 1) + AndroidUtilities.dp(30)) / 2 + currentTranslationX, 0); int bitmapWidth = sideImage.getBitmapWidth(); int bitmapHeight = sideImage.getBitmapHeight(); - + if (!leftImageIsVideo && leftCropTransform.hasViewTransform()) { + applyCrop(canvas, containerWidth, containerHeight, bitmapWidth, bitmapHeight, currentScale, leftCropTransform, leftCropState); + } float scaleX = containerWidth / (float) bitmapWidth; float scaleY = containerHeight / (float) bitmapHeight; float scale = Math.min(scaleX, scaleY); @@ -14328,10 +14552,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat textureImageView.setImageDrawable(null); } } - if (pipVideoView != null) { - pipVideoView.close(); - pipVideoView = null; - } + PipVideoOverlay.dismiss(true); } else { containerView.invalidate(); } @@ -14348,6 +14569,102 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat } } + private int[] tempInt = new int[2]; + + private int[] applyCrop(Canvas canvas, int containerWidth, int containerHeight, int bitmapWidth, int bitmapHeight, float currentScale, CropTransform cropTransform, MediaController.CropState cropState) { + int originalWidth = bitmapWidth; + int originalHeight = bitmapHeight; + float scale = Math.min(containerWidth / (float) originalWidth, containerHeight / (float) originalHeight); + int rotatedWidth = originalWidth; + int rotatedHeight = originalHeight; + int orientation = cropTransform.getOrientation(); + if (orientation == 90 || orientation == 270) { + int temp = bitmapWidth; + bitmapWidth = bitmapHeight; + bitmapHeight = temp; + + temp = rotatedWidth; + rotatedWidth = rotatedHeight; + rotatedHeight = temp; + } + float cropAnimationValue; + if (sendPhotoType != SELECT_TYPE_AVATAR && (currentEditMode == EDIT_MODE_PAINT || switchingToMode == EDIT_MODE_PAINT)) { + cropAnimationValue = 1.0f; + } else if (imageMoveAnimation != null && switchingToMode != -1) { + if (currentEditMode == 1 || switchingToMode == 1 || (currentEditMode == EDIT_MODE_FILTER || currentEditMode == EDIT_MODE_PAINT) && switchingToMode == -1) { + cropAnimationValue = 1.0f; + } else if (switchingToMode == 0) { + cropAnimationValue = animationValue; + } else { + cropAnimationValue = 1.0f - animationValue; + } + } else { + cropAnimationValue = currentEditMode == EDIT_MODE_FILTER || currentEditMode == EDIT_MODE_PAINT ? 0.0f : 1.0f; + } + float cropPw = cropTransform.getCropPw(); + float cropPh = cropTransform.getCropPh(); + bitmapWidth *= cropPw + (1.0f - cropPw) * (1.0f - cropAnimationValue); + bitmapHeight *= cropPh + (1.0f - cropPh) * (1.0f - cropAnimationValue); + float scaleToFitX = containerWidth / (float) bitmapWidth; + if (scaleToFitX * bitmapHeight > containerHeight) { + scaleToFitX = containerHeight / (float) bitmapHeight; + } + if (sendPhotoType != SELECT_TYPE_AVATAR && (currentEditMode != EDIT_MODE_CROP || switchingToMode == EDIT_MODE_NONE) && cropState != null) { + float startW = bitmapWidth * scaleToFitX; + float startH = bitmapHeight * scaleToFitX; + float originalScaleToFitX = containerWidth / (float) originalWidth; + if (originalScaleToFitX * originalHeight > containerHeight) { + originalScaleToFitX = containerHeight / (float) originalHeight; + } + float finalW = originalWidth * originalScaleToFitX / currentScale; + float finalH = originalHeight * originalScaleToFitX / currentScale; + + float w = startW + (finalW - startW) * (1.0f - cropAnimationValue); + float h = startH + (finalH - startH) * (1.0f - cropAnimationValue); + + canvas.clipRect(-w / 2, -h / 2, w / 2, h / 2); + } + if (sendPhotoType == SELECT_TYPE_AVATAR || cropTransform.hasViewTransform()) { + float cropScale; + if (currentEditMode == EDIT_MODE_CROP || sendPhotoType == SELECT_TYPE_AVATAR) { + float trueScale = 1.0f + (cropTransform.getTrueCropScale() - 1.0f) * (1.0f - cropAnimationValue); + cropScale = cropTransform.getScale() / trueScale; + float scaleToFit = containerWidth / (float) rotatedWidth; + if (scaleToFit * rotatedHeight > containerHeight) { + scaleToFit = containerHeight / (float) rotatedHeight; + } + cropScale *= scaleToFit / scale; + if (sendPhotoType == SELECT_TYPE_AVATAR) { + if (currentEditMode == 3 || switchingToMode == 3) { + cropScale /= 1.0f + (cropTransform.getMinScale() - 1.0f) * (1.0f - cropAnimationValue); + } else if (switchingToMode == 0) { + cropScale /= cropTransform.getMinScale(); + } + } + } else { + cropScale = cropState != null ? cropState.cropScale : 1.0f; + float trueScale = 1.0f + (cropScale - 1.0f) * (1.0f - cropAnimationValue); + cropScale *= scaleToFitX / scale / trueScale; + } + + canvas.translate(cropTransform.getCropAreaX() * cropAnimationValue, cropTransform.getCropAreaY() * cropAnimationValue); + canvas.scale(cropScale, cropScale); + canvas.translate(cropTransform.getCropPx() * rotatedWidth * scale * cropAnimationValue, cropTransform.getCropPy() * rotatedHeight * scale * cropAnimationValue); + float rotation = (cropTransform.getRotation() + orientation); + if (rotation > 180) { + rotation -= 360; + } + if (sendPhotoType == SELECT_TYPE_AVATAR && (currentEditMode == 3 || switchingToMode == 3)) { + canvas.rotate(rotation); + } else { + canvas.rotate(rotation * cropAnimationValue); + } + } + tempInt[0] = bitmapWidth; + tempInt[1] = bitmapHeight; + return tempInt; + } + private void onActionClick(boolean download) { if (currentMessageObject == null && currentBotInlineResult == null && pageBlocksAdapter == null || currentFileNames[0] == null) { return; @@ -14736,11 +15053,6 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat private boolean enableSwipeToPiP() { return false; -// if (!BuildVars.DEBUG_PRIVATE_VERSION) { -// return false; -// } -// boolean permissionsEnabled = Build.VERSION.SDK_INT < 23 || Settings.canDrawOverlays(parentActivity); -// return pipAvailable && textureUploaded && videoPlayer != null && videoPlayer.getRepeatCount() == 0 && permissionsEnabled && !(changingTextureView || switchingInlineMode || isInline); } @Override diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ProfileActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ProfileActivity.java index 62c6f7bdb..cb150e18a 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ProfileActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ProfileActivity.java @@ -59,6 +59,7 @@ import android.view.WindowManager; import android.view.accessibility.AccessibilityNodeInfo; import android.view.animation.AccelerateInterpolator; import android.view.animation.DecelerateInterpolator; +import android.webkit.WebStorage; import android.widget.EditText; import android.widget.FrameLayout; import android.widget.ImageView; @@ -117,6 +118,7 @@ import org.telegram.tgnet.TLRPC; import org.telegram.ui.ActionBar.ActionBar; import org.telegram.ui.ActionBar.ActionBarMenu; import org.telegram.ui.ActionBar.ActionBarMenuItem; +import org.telegram.ui.ActionBar.ActionBarMenuSubItem; import org.telegram.ui.ActionBar.ActionBarPopupWindow; import org.telegram.ui.ActionBar.AlertDialog; import org.telegram.ui.ActionBar.BackDrawable; @@ -140,11 +142,13 @@ import org.telegram.ui.Components.AlertsCreator; import org.telegram.ui.Components.AnimatedFileDrawable; import org.telegram.ui.Components.AnimationProperties; 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.BulletinFactory; import org.telegram.ui.Components.ChatAvatarContainer; +import org.telegram.ui.Components.ChatNotificationsPopupWrapper; import org.telegram.ui.Components.CombinedDrawable; import org.telegram.ui.Components.CrossfadeDrawable; import org.telegram.ui.Components.CubicBezierInterpolator; @@ -226,6 +230,7 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. private AvatarDrawable avatarDrawable; private ImageUpdater imageUpdater; private int avatarColor; + TimerDrawable autoDeleteItemDrawable; private View scrimView = null; private Paint scrimPaint = new Paint(Paint.ANTI_ALIAS_FLAG) { @@ -260,7 +265,10 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. private ActionBarMenuItem editItem; private ActionBarMenuItem otherItem; private ActionBarMenuItem searchItem; + private ImageView ttlIconView; private ActionBarMenuItem qrItem; + private ActionBarMenuSubItem autoDeleteItem; + AutoDeletePopupWrapper autoDeletePopupWrapper; protected float headerShadowAlpha = 1.0f; private TopView topView; private long userId; @@ -289,6 +297,7 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. private int playProfileAnimation; private boolean needTimerImage; private boolean allowProfileAnimation = true; + private boolean disableProfileAnimation = false; private float extraHeight; private float initialAnimationExtraHeight; private float animationProgress; @@ -416,6 +425,8 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. private int infoSectionRow; private int sendMessageRow; private int reportRow; + private int addToGroupButtonRow; + private int addToGroupInfoRow; private int settingsTimerRow; private int settingsKeyRow; @@ -1664,22 +1675,54 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. Bundle args = new Bundle(); args.putBoolean("onlySelect", true); args.putInt("dialogsType", 2); - args.putString("addToGroupAlertString", LocaleController.formatString("AddToTheGroupAlertText", R.string.AddToTheGroupAlertText, UserObject.getUserName(user), "%1$s")); + args.putBoolean("resetDelegate", false); + args.putBoolean("closeFragment", false); +// args.putString("addToGroupAlertString", LocaleController.formatString("AddToTheGroupAlertText", R.string.AddToTheGroupAlertText, UserObject.getUserName(user), "%1$s")); DialogsActivity fragment = new DialogsActivity(args); fragment.setDelegate((fragment1, dids, message, param) -> { long did = dids.get(0); - Bundle args1 = new Bundle(); - args1.putBoolean("scrollToTopOnResume", true); - args1.putLong("chat_id", -did); - if (!getMessagesController().checkCanOpenChat(args1, fragment1)) { - return; - } - getNotificationCenter().removeObserver(ProfileActivity.this, NotificationCenter.closeChats); - getNotificationCenter().postNotificationName(NotificationCenter.closeChats); - getMessagesController().addUserToChat(-did, user, 0, null, ProfileActivity.this, null); - presentFragment(new ChatActivity(args1), true); - removeSelfFromStack(); + TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(-did); + if (chat != null && (chat.creator || chat.admin_rights != null && chat.admin_rights.add_admins)) { + getMessagesController().checkIsInChat(chat, user, (isInChatAlready, rightsAdmin, currentRank) -> AndroidUtilities.runOnUIThread(() -> { + ChatRightsEditActivity editRightsActivity = new ChatRightsEditActivity(userId, -did, rightsAdmin, null, null, currentRank, ChatRightsEditActivity.TYPE_ADD_BOT, true, !isInChatAlready, null); + editRightsActivity.setDelegate(new ChatRightsEditActivity.ChatRightsEditActivityDelegate() { + @Override + public void didSetRights(int rights, TLRPC.TL_chatAdminRights rightsAdmin, TLRPC.TL_chatBannedRights rightsBanned, String rank) { + disableProfileAnimation = true; + fragment.removeSelfFromStack(); + getNotificationCenter().removeObserver(ProfileActivity.this, NotificationCenter.closeChats); + getNotificationCenter().postNotificationName(NotificationCenter.closeChats); + } + + @Override + public void didChangeOwner(TLRPC.User user) {} + }); + presentFragment(editRightsActivity); + })); + } else { + AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); + builder.setTitle(LocaleController.getString("AddBot", R.string.AddBot)); + String chatName = chat == null ? "" : chat.title; + builder.setMessage(AndroidUtilities.replaceTags(LocaleController.formatString("AddMembersAlertNamesText", R.string.AddMembersAlertNamesText, UserObject.getUserName(user), chatName))); + builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); + builder.setPositiveButton(LocaleController.getString("AddBot", R.string.AddBot), (di, i) -> { + disableProfileAnimation = true; + + Bundle args1 = new Bundle(); + args1.putBoolean("scrollToTopOnResume", true); + args1.putLong("chat_id", -did); + if (!getMessagesController().checkCanOpenChat(args1, fragment1)) { + return; + } + ChatActivity chatActivity = new ChatActivity(args1); + getNotificationCenter().removeObserver(ProfileActivity.this, NotificationCenter.closeChats); + getNotificationCenter().postNotificationName(NotificationCenter.closeChats); + getMessagesController().addUserToChat(-did, user, 0, null, chatActivity, true, null, null); + presentFragment(chatActivity, true); + }); + showDialog(builder.create()); + } }); presentFragment(fragment); } else if (id == share) { @@ -2388,6 +2431,10 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. editItem = menu.addItem(edit_channel, R.drawable.group_edit_profile); editItem.setContentDescription(LocaleController.getString("Edit", R.string.Edit)); otherItem = menu.addItem(10, R.drawable.ic_ab_other); + ttlIconView = new ImageView(context); + AndroidUtilities.updateViewVisibilityAnimated(ttlIconView, false, 0.8f, false); + ttlIconView.setImageResource(R.drawable.msg_mini_autodelete_timer); + otherItem.addView(ttlIconView, LayoutHelper.createFrame(12, 12, Gravity.CENTER_VERTICAL | Gravity.LEFT, 8, 2, 0, 0)); otherItem.setContentDescription(LocaleController.getString("AccDescrMoreOptions", R.string.AccDescrMoreOptions)); int scrollTo; @@ -2512,7 +2559,9 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. @Override protected void onAllAnimationsDone() { super.onAllAnimationsDone(); - getNotificationCenter().onAnimationFinish(animationIndex); + AndroidUtilities.runOnUIThread(() -> { + getNotificationCenter().onAnimationFinish(animationIndex); + }); } @Override @@ -2603,6 +2652,7 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. if (getParentActivity() == null) { return; } + listView.stopScroll(); if (position == settingsKeyRow) { Bundle args = new Bundle(); args.putInt("chat_id", DialogObject.getEncryptedChatId(dialogId)); @@ -2661,12 +2711,65 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. } return; } - AlertsCreator.showCustomNotificationsDialog(ProfileActivity.this, did, -1, null, currentAccount, param -> listAdapter.notifyItemChanged(notificationsRow)); + ChatNotificationsPopupWrapper chatNotificationsPopupWrapper = new ChatNotificationsPopupWrapper(context, currentAccount, null, true, true, new ChatNotificationsPopupWrapper.Callback() { + @Override + public void dismiss() { + + } + + @Override + public void toggleSound() { + SharedPreferences preferences = MessagesController.getNotificationsSettings(currentAccount); + boolean enabled = !preferences.getBoolean("sound_enabled_" + did, true); + preferences.edit().putBoolean("sound_enabled_" + did, enabled).apply(); + if (BulletinFactory.canShowBulletin(ProfileActivity.this)) { + BulletinFactory.createSoundEnabledBulletin(ProfileActivity.this, enabled ? NotificationsController.SETTING_SOUND_ON : NotificationsController.SETTING_SOUND_OFF, getResourceProvider()).show(); + } + } + + @Override + public void muteFor(int timeInSeconds) { + getNotificationsController().muteUntil(did, timeInSeconds); + if (BulletinFactory.canShowBulletin(ProfileActivity.this)) { + BulletinFactory.createMuteBulletin(ProfileActivity.this, NotificationsController.SETTING_MUTE_CUSTOM, timeInSeconds, getResourceProvider()).show(); + } + if (notificationsRow >= 0) { + listAdapter.notifyItemChanged(notificationsRow); + } + } + + @Override + public void showCustomize() { + if (did != 0) { + Bundle args = new Bundle(); + args.putLong("dialog_id", did); + presentFragment(new ProfileNotificationsActivity(args)); + } + } + + @Override + public void toggleMute() { + boolean muted = getMessagesController().isDialogMuted(did); + getNotificationsController().muteDialog(did, !muted); + BulletinFactory.createMuteBulletin(ProfileActivity.this, getMessagesController().isDialogMuted(dialogId), null).show(); + if (notificationsRow >= 0) { + listAdapter.notifyItemChanged(notificationsRow); + } + } + }, getResourceProvider()); + chatNotificationsPopupWrapper.update(did); + chatNotificationsPopupWrapper.showAsOptions(ProfileActivity.this, view, x, y); } else if (position == unblockRow) { getMessagesController().unblockPeer(userId); if (BulletinFactory.canShowBulletin(ProfileActivity.this)) { BulletinFactory.createBanBulletin(ProfileActivity.this, false).show(); } + } else if (position == addToGroupButtonRow) { + try { + actionBar.getActionBarMenuOnItemClick().onItemClick(invite_to_group); + } catch (Exception e) { + FileLog.e(e); + } } else if (position == sendMessageRow) { onWriteButtonClick(); } else if (position == reportRow) { @@ -2815,7 +2918,8 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. Build.VERSION.SDK_INT >= 21 ? (SharedConfig.noStatusBar ? "Show status bar background" : "Hide status bar background") : null, BuildVars.DEBUG_PRIVATE_VERSION ? "Clean app update" : null, BuildVars.DEBUG_PRIVATE_VERSION ? "Reset suggestions" : null, - BuildVars.DEBUG_PRIVATE_VERSION ? LocaleController.getString(SharedConfig.forceRtmpStream ? R.string.DebugMenuDisableForceRtmpStreamFlag : R.string.DebugMenuEnableForceRtmpStreamFlag) : null + BuildVars.DEBUG_PRIVATE_VERSION ? LocaleController.getString(SharedConfig.forceRtmpStream ? R.string.DebugMenuDisableForceRtmpStreamFlag : R.string.DebugMenuEnableForceRtmpStreamFlag) : null, + BuildVars.DEBUG_PRIVATE_VERSION ? LocaleController.getString(R.string.DebugMenuClearWebViewCache) : null }; builder.setItems(items, (dialog, which) -> { if (which == 0) { @@ -2888,6 +2992,10 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. getNotificationCenter().postNotificationName(NotificationCenter.newSuggestionsAvailable); } else if (which == 17) { SharedConfig.toggleForceRTMPStream(); + } else if (which == 18) { + ApplicationLoader.applicationContext.deleteDatabase("webview.db"); + ApplicationLoader.applicationContext.deleteDatabase("webviewCache.db"); + WebStorage.getInstance().deleteAllData(); } }); builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); @@ -3021,7 +3129,7 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. frameLayout.addView(frameLayout1, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 51, Gravity.LEFT | Gravity.BOTTOM)); frameLayout1.setOnClickListener(v -> { - ChatRightsEditActivity fragment = new ChatRightsEditActivity(userId, banFromGroup, null, chat.default_banned_rights, currentChannelParticipant != null ? currentChannelParticipant.banned_rights : null, "", ChatRightsEditActivity.TYPE_BANNED, true, false); + ChatRightsEditActivity fragment = new ChatRightsEditActivity(userId, banFromGroup, null, chat.default_banned_rights, currentChannelParticipant != null ? currentChannelParticipant.banned_rights : null, "", ChatRightsEditActivity.TYPE_BANNED, true, false, null); fragment.setDelegate(new ChatRightsEditActivity.ChatRightsEditActivityDelegate() { @Override public void didSetRights(int rights, TLRPC.TL_chatAdminRights rightsAdmin, TLRPC.TL_chatBannedRights rightsBanned, String rank) { @@ -3155,9 +3263,8 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. timeItem.setPadding(AndroidUtilities.dp(10), AndroidUtilities.dp(10), AndroidUtilities.dp(5), AndroidUtilities.dp(5)); timeItem.setScaleType(ImageView.ScaleType.CENTER); timeItem.setAlpha(0.0f); - timeItem.setImageDrawable(timerDrawable = new TimerDrawable(context)); + timeItem.setImageDrawable(timerDrawable = new TimerDrawable(context, null)); frameLayout.addView(timeItem, LayoutHelper.createFrame(34, 34, Gravity.TOP | Gravity.LEFT)); - updateTimeItem(); showAvatarProgress(false, false); @@ -3498,9 +3605,25 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. scrimPaint.setAlpha(0); actionBarBackgroundPaint.setColor(Theme.getColor(Theme.key_listSelector)); contentView.blurBehindViews.add(sharedMediaLayout); + updateTtlIcon(); return fragmentView; } + private void updateTtlIcon() { + if (ttlIconView == null) { + return; + } + boolean visible = false; + if (currentEncryptedChat == null) { + if (userInfo != null && userInfo.ttl_period > 0) { + visible = true; + } else if (chatInfo != null && ChatObject.canUserDoAdminAction(currentChat, ChatObject.ACTION_DELETE_MESSAGES) && chatInfo.ttl_period > 0) { + visible = true; + } + } + AndroidUtilities.updateViewVisibilityAnimated(ttlIconView, visible, 0.8f, fragmentOpened); + } + public long getDialogId() { if (dialogId != 0) { return dialogId; @@ -3760,7 +3883,7 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. private void openRightsEdit(int action, TLRPC.User user, TLRPC.ChatParticipant participant, TLRPC.TL_chatAdminRights adminRights, TLRPC.TL_chatBannedRights bannedRights, String rank, boolean editingAdmin) { boolean[] needShowBulletin = new boolean[1]; - ChatRightsEditActivity fragment = new ChatRightsEditActivity(user.id, chatId, adminRights, currentChat.default_banned_rights, bannedRights, rank, action, true, false) { + ChatRightsEditActivity fragment = new ChatRightsEditActivity(user.id, chatId, adminRights, currentChat.default_banned_rights, bannedRights, rank, action, true, false, null) { @Override protected void onTransitionAnimationEnd(boolean isOpen, boolean backward) { if (!isOpen && backward && needShowBulletin[0] && BulletinFactory.canShowBulletin(ProfileActivity.this)) { @@ -4663,7 +4786,7 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. } } - if (isPulledDown || overlaysView.animator != null && overlaysView.animator.isRunning()) { + if (isPulledDown || (overlaysView != null && overlaysView.animator != null && overlaysView.animator.isRunning())) { final ViewGroup.LayoutParams overlaysLp = overlaysView.getLayoutParams(); overlaysLp.width = listView.getMeasuredWidth(); overlaysLp.height = (int) (extraHeight + newTop); @@ -4864,7 +4987,6 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. if (currentEncryptedChat != null && chat.id == currentEncryptedChat.id) { currentEncryptedChat = chat; updateListAnimated(false); - updateTimeItem(); } } else if (id == NotificationCenter.blockedUsersDidLoad) { boolean oldValue = userBlocked; @@ -4915,7 +5037,8 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. if (currentChat.megagroup && (loadChannelParticipants || !byChannelUsers)) { getChannelParticipants(true); } - updateTimeItem(); + updateAutoDeleteItem(); + updateTtlIcon(); } } else if (id == NotificationCenter.closeChats) { removeSelfFromStack(); @@ -4947,7 +5070,8 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. needLayout(true); } } - updateTimeItem(); + updateAutoDeleteItem(); + updateTtlIcon(); } } else if (id == NotificationCenter.didReceiveNewMessages) { boolean scheduled = (Boolean) args[2]; @@ -4985,6 +5109,18 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. } } + private void updateAutoDeleteItem() { + if (autoDeleteItem == null || autoDeletePopupWrapper == null) { + return; + } + int ttl = 0; + if (userInfo != null || chatInfo != null) { + ttl = userInfo != null ? userInfo.ttl_period : chatInfo.ttl_period; + } + autoDeleteItemDrawable.setTime(ttl); + autoDeletePopupWrapper.updateItems(ttl); + } + private void updateTimeItem() { if (timerDrawable == null) { return; @@ -5207,10 +5343,12 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. } int actionBarColor = actionBarAnimationColorFrom != 0 ? actionBarAnimationColorFrom : Theme.getColor(Theme.key_actionBarDefault); + int actionBarColor2 = actionBarColor; if (SharedConfig.chatBlurEnabled()) { actionBarColor = ColorUtils.setAlphaComponent(actionBarColor, 0); } topView.setBackgroundColor(ColorUtils.blendARGB(actionBarColor, color, progress)); + timerDrawable.setBackgroundColor(ColorUtils.blendARGB(actionBarColor2, color, progress)); color = AvatarDrawable.getIconColorForId(userId != 0 || ChatObject.isChannel(chatId, currentAccount) && !currentChat.megagroup ? 5 : chatId); int iconColor = Theme.getColor(Theme.key_actionBarDefaultIcon); @@ -5261,7 +5399,7 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. @Override protected AnimatorSet onCustomTransitionAnimation(final boolean isOpen, final Runnable callback) { - if (playProfileAnimation != 0 && allowProfileAnimation && !isPulledDown) { + if (playProfileAnimation != 0 && allowProfileAnimation && !isPulledDown && !disableProfileAnimation) { if (timeItem != null) { timeItem.setAlpha(1.0f); } @@ -5271,6 +5409,9 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. previousTransitionFragment = (ChatActivity) fragment; } } + if (previousTransitionFragment != null) { + updateTimeItem(); + } final AnimatorSet animatorSet = new AnimatorSet(); animatorSet.setDuration(playProfileAnimation == 2 ? 250 : 180); listView.setLayerType(View.LAYER_TYPE_HARDWARE, null); @@ -5346,6 +5487,10 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. editItem.setAlpha(0.0f); animators.add(ObjectAnimator.ofFloat(editItem, View.ALPHA, 1.0f)); } + if (ttlIconView.getTag() != null) { + ttlIconView.setAlpha(0f); + animators.add(ObjectAnimator.ofFloat(ttlIconView, View.ALPHA, 1.0f)); + } boolean onlineTextCrosafade = false; BaseFragment previousFragment = parentLayout.fragmentsStack.size() > 1 ? parentLayout.fragmentsStack.get(parentLayout.fragmentsStack.size() - 2) : null; @@ -5380,6 +5525,7 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. animators.add(ObjectAnimator.ofFloat(nameTextView[a], View.ALPHA, a == 0 ? 1.0f : 0.0f)); } if (timeItem.getTag() != null) { + timeItem.setAlpha(0f); animators.add(ObjectAnimator.ofFloat(timeItem, View.ALPHA, 0.0f, 1.0f)); animators.add(ObjectAnimator.ofFloat(timeItem, View.SCALE_X, 0.0f, 1.0f)); animators.add(ObjectAnimator.ofFloat(timeItem, View.SCALE_Y, 0.0f, 1.0f)); @@ -5400,6 +5546,9 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. editItem.setAlpha(1.0f); animators.add(ObjectAnimator.ofFloat(editItem, View.ALPHA, 0.0f)); } + if (ttlIconView != null) { + animators.add(ObjectAnimator.ofFloat(ttlIconView, View.ALPHA, ttlIconView.getAlpha(), 0.0f)); + } boolean crossfadeOnlineText = false; BaseFragment previousFragment = parentLayout.fragmentsStack.size() > 1 ? parentLayout.fragmentsStack.get(parentLayout.fragmentsStack.size() - 2) : null; @@ -5645,6 +5794,8 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. infoSectionRow = -1; secretSettingsSectionRow = -1; bottomPaddingRow = -1; + addToGroupButtonRow = -1; + addToGroupInfoRow = -1; membersHeaderRow = -1; membersStartRow = -1; @@ -5765,6 +5916,11 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. } } + if (user != null && isBot && !user.bot_nochats) { // TODO(dkaraush): and had invite button sent + addToGroupButtonRow = rowCount++; + addToGroupInfoRow = rowCount++; + } + if (hasMedia || userInfo != null && userInfo.common_chats_count != 0) { sharedMediaRow = rowCount++; } else if (lastSectionRow == -1 && needSendMessage) { @@ -6194,7 +6350,7 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. if (actionBar == null || otherItem == null) { return; } - ActionBarMenu menu = actionBar.createMenu(); + Context context = actionBar.getContext(); otherItem.removeAllSubItems(); animatingItem = null; @@ -6222,6 +6378,9 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. otherItem.addSubItem(block_contact, R.drawable.msg_block, LocaleController.getString("Unblock", R.string.Unblock)); } } else { + if (currentEncryptedChat == null) { + createAutoDeleteItem(context); + } if (isBot) { if (!user.bot_nochats) { otherItem.addSubItem(invite_to_group, R.drawable.msg_addbot, LocaleController.getString("BotInvite", R.string.BotInvite)); @@ -6240,6 +6399,10 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. } } } else { + if (currentEncryptedChat == null) { + createAutoDeleteItem(context); + } + if (!TextUtils.isEmpty(user.phone)) { otherItem.addSubItem(share_contact, R.drawable.msg_share, LocaleController.getString("ShareContact", R.string.ShareContact)); } @@ -6255,6 +6418,9 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. } else if (chatId != 0) { TLRPC.Chat chat = getMessagesController().getChat(chatId); hasVoiceChatItem = false; + if (ChatObject.canUserDoAdminAction(chat, ChatObject.ACTION_DELETE_MESSAGES)) { + createAutoDeleteItem(context); + } if (ChatObject.isChannel(chat)) { if (ChatObject.hasAdminRights(chat) || chat.megagroup && ChatObject.canChangeChatInfo(chat)) { editItemVisible = true; @@ -6396,6 +6562,37 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. } } + private void createAutoDeleteItem(Context context) { + autoDeletePopupWrapper = new AutoDeletePopupWrapper(context, otherItem.getPopupLayout().getSwipeBack(), new AutoDeletePopupWrapper.Callback() { + + @Override + public void dismiss() { + otherItem.toggleSubMenu(); + } + + @Override + public void setAutoDeleteHistory(int time, int action) { + ProfileActivity.this.setAutoDeleteHistory(time, action); + } + }, false, getResourceProvider()); + int ttl = 0; + if (userInfo != null || chatInfo != null) { + ttl = userInfo != null ? userInfo.ttl_period : chatInfo.ttl_period; + } + autoDeleteItemDrawable = TimerDrawable.getTtlIcon(ttl); + autoDeleteItem = otherItem.addSwipeBackItem(0, autoDeleteItemDrawable, LocaleController.getString("AutoDeletePopupTitle", R.string.AutoDeletePopupTitle), autoDeletePopupWrapper.windowLayout); + otherItem.addColoredGap(); + updateAutoDeleteItem(); + } + + private void setAutoDeleteHistory(int time, int action) { + long did = getDialogId(); + getMessagesController().setDialogHistoryTTL(did, time); + if (userInfo != null || chatInfo != null) { + undoView.showWithAction(did, action, getMessagesController().getUser(did), userInfo != null ? userInfo.ttl_period : chatInfo.ttl_period, null, null); + } + } + @Override protected void onDialogDismiss(Dialog dialog) { if (listView != null) { @@ -6942,7 +7139,8 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. VIEW_TYPE_BOTTOM_PADDING = 12, VIEW_TYPE_SHARED_MEDIA = 13, VIEW_TYPE_VERSION = 14, - VIEW_TYPE_SUGGESTION = 15; + VIEW_TYPE_SUGGESTION = 15, + VIEW_TYPE_ADDTOGROUP_INFO = 17; private Context mContext; @@ -7073,6 +7271,10 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. view = sharedMediaLayout; break; } + case VIEW_TYPE_ADDTOGROUP_INFO: { + view = new TextInfoPrivacyCell(mContext); + break; + } case VIEW_TYPE_VERSION: default: { TextInfoPrivacyCell cell = new TextInfoPrivacyCell(mContext, 10); @@ -7188,7 +7390,7 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. TextDetailCell detailCell = (TextDetailCell) holder.itemView; if (position == usernameRow) { Drawable drawable = ContextCompat.getDrawable(detailCell.getContext(), R.drawable.msg_qr_mini); - drawable.setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_switch2TrackChecked), PorterDuff.Mode.SRC_IN)); + drawable.setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_switch2TrackChecked), PorterDuff.Mode.MULTIPLY)); detailCell.setImage(drawable); } else { detailCell.setImage(null); @@ -7371,6 +7573,9 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. textCell.getImageView().setPadding(0, 0, 0, AndroidUtilities.dp(8)); textCell.setImageLeft(12); setAvatarCell = textCell; + } else if (position == addToGroupButtonRow) { + textCell.setTextAndIcon(LocaleController.getString("AddToGroupOrChannel", R.string.AddToGroupOrChannel), R.drawable.groups_create, false); // TODO(dkaraush): text! icon! + textCell.setColors(Theme.key_windowBackgroundWhiteBlueIcon, Theme.key_windowBackgroundWhiteBlueButton); } break; case VIEW_TYPE_NOTIFICATIONS_CHECK: @@ -7429,6 +7634,7 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. if (val == null) { val = LocaleController.getString("NotificationsOff", R.string.NotificationsOff); } + checkCell.setAnimationsEnabled(fragmentOpened); checkCell.setTextAndValueAndCheck(LocaleController.getString("Notifications", R.string.Notifications), val, enabled, false); } break; @@ -7490,6 +7696,11 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. SettingsSuggestionCell suggestionCell = (SettingsSuggestionCell) holder.itemView; suggestionCell.setType(position == passwordSuggestionRow ? SettingsSuggestionCell.TYPE_PASSWORD : SettingsSuggestionCell.TYPE_PHONE); break; + case VIEW_TYPE_ADDTOGROUP_INFO: + TextInfoPrivacyCell addToGroupInfo = (TextInfoPrivacyCell) holder.itemView; + addToGroupInfo.setBackground(Theme.getThemedDrawable(mContext, R.drawable.greydivider, Theme.key_windowBackgroundGrayShadow)); + addToGroupInfo.setText("This bot is able to manage a group or channel."); // TODO(dkaraush): text! + break; } } @@ -7509,7 +7720,7 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. position == versionRow || position == dataRow || position == chatRow || position == questionRow || position == devicesRow || position == filtersRow || position == faqRow || position == policyRow || position == sendLogsRow || position == sendLastLogsRow || - position == clearLogsRow || position == switchBackendRow || position == setAvatarRow; + position == clearLogsRow || position == switchBackendRow || position == setAvatarRow || position == addToGroupButtonRow; } if (holder.itemView instanceof UserCell) { UserCell userCell = (UserCell) holder.itemView; @@ -7549,7 +7760,7 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. position == languageRow || position == dataRow || position == chatRow || position == questionRow || position == devicesRow || position == filtersRow || position == faqRow || position == policyRow || position == sendLogsRow || position == sendLastLogsRow || - position == clearLogsRow || position == switchBackendRow || position == setAvatarRow) { + position == clearLogsRow || position == switchBackendRow || position == setAvatarRow || position == addToGroupButtonRow) { return VIEW_TYPE_TEXT; } else if (position == notificationsDividerRow) { return VIEW_TYPE_DIVIDER; @@ -7572,6 +7783,8 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. return VIEW_TYPE_VERSION; } else if (position == passwordSuggestionRow || position == phoneSuggestionRow) { return VIEW_TYPE_SUGGESTION; + } else if (position == addToGroupInfoRow) { + return VIEW_TYPE_ADDTOGROUP_INFO; } return 0; } @@ -8554,6 +8767,8 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. put(++pointer, membersSectionRow, sparseIntArray); put(++pointer, sharedMediaRow, sparseIntArray); put(++pointer, unblockRow, sparseIntArray); + put(++pointer, addToGroupButtonRow, sparseIntArray); + put(++pointer, addToGroupInfoRow, sparseIntArray); put(++pointer, joinRow, sparseIntArray); put(++pointer, lastSectionRow, sparseIntArray); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ProfileNotificationsActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ProfileNotificationsActivity.java index 18a65e899..887bd0671 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ProfileNotificationsActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ProfileNotificationsActivity.java @@ -21,28 +21,30 @@ import android.net.Uri; import android.os.Build; import android.os.Bundle; import android.provider.Settings; -import android.text.TextUtils; -import android.util.TypedValue; import android.view.Gravity; import android.view.View; import android.view.ViewGroup; import android.widget.FrameLayout; -import android.widget.TextView; + +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; import org.telegram.messenger.AndroidUtilities; -import org.telegram.messenger.ChatObject; -import org.telegram.messenger.DialogObject; -import org.telegram.messenger.MessagesController; import org.telegram.messenger.ApplicationLoader; +import org.telegram.messenger.ChatObject; +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.NotificationsController; import org.telegram.messenger.R; import org.telegram.tgnet.TLObject; import org.telegram.tgnet.TLRPC; -import org.telegram.ui.ActionBar.AlertDialog; +import org.telegram.ui.ActionBar.ActionBar; +import org.telegram.ui.ActionBar.BaseFragment; import org.telegram.ui.ActionBar.Theme; import org.telegram.ui.ActionBar.ThemeDescription; import org.telegram.ui.Cells.HeaderCell; @@ -51,20 +53,16 @@ import org.telegram.ui.Cells.ShadowSectionCell; import org.telegram.ui.Cells.TextCheckBoxCell; import org.telegram.ui.Cells.TextCheckCell; import org.telegram.ui.Cells.TextColorCell; -import org.telegram.ui.ActionBar.ActionBar; -import org.telegram.ui.ActionBar.BaseFragment; import org.telegram.ui.Cells.TextInfoPrivacyCell; import org.telegram.ui.Cells.TextSettingsCell; import org.telegram.ui.Cells.UserCell2; import org.telegram.ui.Components.AlertsCreator; +import org.telegram.ui.Components.ChatAvatarContainer; import org.telegram.ui.Components.LayoutHelper; import org.telegram.ui.Components.RecyclerListView; import java.util.ArrayList; -import androidx.recyclerview.widget.LinearLayoutManager; -import androidx.recyclerview.widget.RecyclerView; - public class ProfileNotificationsActivity extends BaseFragment implements NotificationCenter.NotificationCenterDelegate { private RecyclerListView listView; @@ -80,6 +78,8 @@ public class ProfileNotificationsActivity extends BaseFragment implements Notifi private ProfileNotificationsActivityDelegate delegate; + ChatAvatarContainer avatarContainer; + private int customRow; private int customInfoRow; private int generalRow; @@ -222,7 +222,6 @@ public class ProfileNotificationsActivity extends BaseFragment implements Notifi @Override public View createView(final Context context) { actionBar.setBackButtonImage(R.drawable.ic_ab_back); - actionBar.setAllowOverlayTitle(true); actionBar.setActionBarMenuOnItemClick(new ActionBar.ActionBarMenuOnItemClick() { @Override public void onItemClick(int id) { @@ -270,11 +269,29 @@ public class ProfileNotificationsActivity extends BaseFragment implements Notifi finishFragment(); } }); + + 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)); + actionBar.setAllowOverlayTitle(false); + if (dialogId < 0) { + TLRPC.Chat chatLocal = getMessagesController().getChat(-dialogId); + avatarContainer.setChatAvatar(chatLocal); + avatarContainer.setTitle(chatLocal.title); + } else { + TLRPC.User user = getMessagesController().getUser(dialogId); + if (user != null) { + avatarContainer.setUserAvatar(user); + avatarContainer.setTitle(ContactsController.formatName(user.first_name, user.last_name)); + } + } + if (addingException) { - actionBar.setTitle(LocaleController.getString("NotificationsNewException", R.string.NotificationsNewException)); + avatarContainer.setSubtitle(LocaleController.getString("NotificationsNewException", R.string.NotificationsNewException)); actionBar.createMenu().addItem(done_button, LocaleController.getString("Done", R.string.Done).toUpperCase()); } else { - actionBar.setTitle(LocaleController.getString("CustomNotifications", R.string.CustomNotifications)); + avatarContainer.setSubtitle(LocaleController.getString("CustomNotifications", R.string.CustomNotifications)); } fragmentView = new FrameLayout(context); @@ -295,48 +312,28 @@ public class ProfileNotificationsActivity extends BaseFragment implements Notifi listView.setOnItemClickListener(new RecyclerListView.OnItemClickListener() { @Override public void onItemClick(View view, int position) { - if (position == customRow && view instanceof TextCheckBoxCell) { + if (position == customRow && view instanceof TextCheckCell) { SharedPreferences preferences = MessagesController.getNotificationsSettings(currentAccount); customEnabled = !customEnabled; notificationsEnabled = customEnabled; - preferences.edit().putBoolean("custom_" + dialogId, customEnabled).commit(); - TextCheckBoxCell cell = (TextCheckBoxCell) view; + preferences.edit().putBoolean("custom_" + dialogId, customEnabled).apply(); + TextCheckCell cell = (TextCheckCell) view; cell.setChecked(customEnabled); + int clr = Theme.getColor(customEnabled ? Theme.key_windowBackgroundChecked : Theme.key_windowBackgroundUnchecked); + if (customEnabled) { + cell.setBackgroundColorAnimated(customEnabled, clr); + } else { + cell.setBackgroundColorAnimatedReverse(clr); + } checkRowsEnabled(); } else if (customEnabled) { if (!view.isEnabled()) { return; } if (position == soundRow) { - try { - Intent tmpIntent = new Intent(RingtoneManager.ACTION_RINGTONE_PICKER); - tmpIntent.putExtra(RingtoneManager.EXTRA_RINGTONE_TYPE, RingtoneManager.TYPE_NOTIFICATION); - tmpIntent.putExtra(RingtoneManager.EXTRA_RINGTONE_SHOW_DEFAULT, true); - tmpIntent.putExtra(RingtoneManager.EXTRA_RINGTONE_SHOW_SILENT, true); - tmpIntent.putExtra(RingtoneManager.EXTRA_RINGTONE_DEFAULT_URI, RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION)); - SharedPreferences preferences = MessagesController.getNotificationsSettings(currentAccount); - Uri currentSound = null; - - String defaultPath = null; - Uri defaultUri = Settings.System.DEFAULT_NOTIFICATION_URI; - if (defaultUri != null) { - defaultPath = defaultUri.getPath(); - } - - String path = preferences.getString("sound_path_" + dialogId, defaultPath); - if (path != null && !path.equals("NoSound")) { - if (path.equals(defaultPath)) { - currentSound = defaultUri; - } else { - currentSound = Uri.parse(path); - } - } - - tmpIntent.putExtra(RingtoneManager.EXTRA_RINGTONE_EXISTING_URI, currentSound); - startActivityForResult(tmpIntent, 12); - } catch (Exception e) { - FileLog.e(e); - } + Bundle bundle = new Bundle(); + bundle.putLong("dialog_id", dialogId); + presentFragment(new NotificationsSoundActivity(bundle)); } else if (position == ringtoneRow) { try { Intent tmpIntent = new Intent(RingtoneManager.ACTION_RINGTONE_PICKER); @@ -406,77 +403,15 @@ public class ProfileNotificationsActivity extends BaseFragment implements Notifi if (notifyMaxCount == 0) { notifyMaxCount = 2; } - final int selected = (notifyDelay / 60 - 1) * 10 + notifyMaxCount - 1; - - RecyclerListView list = new RecyclerListView(getParentActivity()); - list.setLayoutManager(new LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false)); - list.setClipToPadding(true); - list.setAdapter(new RecyclerListView.SelectionAdapter() { - @Override - public int getItemCount() { - return 100; - } - - @Override - public boolean isEnabled(RecyclerView.ViewHolder holder) { - return true; - } - - @Override - public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { - TextView textView = new TextView(context1) { - @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - super.onMeasure(MeasureSpec.makeMeasureSpec(widthMeasureSpec, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(48), MeasureSpec.EXACTLY)); - } - }; - textView.setGravity(Gravity.CENTER); - textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 18); - textView.setSingleLine(true); - textView.setEllipsize(TextUtils.TruncateAt.END); - textView.setLayoutParams(new RecyclerView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)); - return new RecyclerListView.Holder(textView); - } - - @Override - public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { - TextView textView = (TextView) holder.itemView; - textView.setTextColor(Theme.getColor(position == selected ? Theme.key_dialogTextGray : Theme.key_dialogTextBlack)); - int notifyMaxCount = position % 10; - int notifyDelay = position / 10; - String times = LocaleController.formatPluralString("Times", notifyMaxCount + 1); - String minutes = LocaleController.formatPluralString("Minutes", notifyDelay + 1); - textView.setText(LocaleController.formatString("SmartNotificationsDetail", R.string.SmartNotificationsDetail, times, minutes)); - } - }); - list.setPadding(0, AndroidUtilities.dp(12), 0, AndroidUtilities.dp(8)); - list.setOnItemClickListener((view1, position1) -> { - if (position1 < 0 || position1 >= 100) { - return; - } - int notifyMaxCount1 = position1 % 10 + 1; - int notifyDelay1 = position1 / 10 + 1; - SharedPreferences preferences1 = MessagesController.getNotificationsSettings(currentAccount); - preferences1.edit().putInt("smart_max_count_" + dialogId, notifyMaxCount1).commit(); - preferences1.edit().putInt("smart_delay_" + dialogId, notifyDelay1 * 60).commit(); + AlertsCreator.createSoundFrequencyPickerDialog(getParentActivity(), notifyMaxCount, notifyDelay, (time, minute) -> { + MessagesController.getNotificationsSettings(currentAccount).edit() + .putInt("smart_max_count_" + dialogId, time) + .putInt("smart_delay_" + dialogId, minute) + .apply(); if (adapter != null) { adapter.notifyItemChanged(smartRow); } - dismissCurrentDialog(); }); - AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); - builder.setTitle(LocaleController.getString("SmartNotificationsAlert", R.string.SmartNotificationsAlert)); - builder.setView(list); - builder.setPositiveButton(LocaleController.getString("Cancel", R.string.Cancel), null); - builder.setNegativeButton(LocaleController.getString("SmartNotificationsDisabled", R.string.SmartNotificationsDisabled), (dialog, which) -> { - SharedPreferences preferences12 = MessagesController.getNotificationsSettings(currentAccount); - preferences12.edit().putInt("smart_max_count_" + dialogId, 0).commit(); - if (adapter != null) { - adapter.notifyItemChanged(smartRow); - } - dismissCurrentDialog(); - }); - showDialog(builder.create()); } else if (position == colorRow) { if (getParentActivity() == null) { return; @@ -699,8 +634,11 @@ public class ProfileNotificationsActivity extends BaseFragment implements Notifi view.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); break; case 5: - view = new TextCheckBoxCell(context); - view.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); + TextCheckCell checkBoxCell = new TextCheckCell(context); + checkBoxCell.setHeight(56); + checkBoxCell.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); + checkBoxCell.setColors(Theme.key_windowBackgroundCheckText, Theme.key_switchTrackBlue, Theme.key_switchTrackBlueChecked, Theme.key_switchTrackBlueThumb, Theme.key_switchTrackBlueThumbChecked); + view = checkBoxCell; break; case 6: view = new UserCell2(context, 4, 0); @@ -740,8 +678,14 @@ public class ProfileNotificationsActivity extends BaseFragment implements Notifi SharedPreferences preferences = MessagesController.getNotificationsSettings(currentAccount); if (position == soundRow) { String value = preferences.getString("sound_" + dialogId, LocaleController.getString("SoundDefault", R.string.SoundDefault)); - if (value.equals("NoSound")) { + long documentId = preferences.getLong("sound_document_id_" + dialogId, 0); + if (documentId != 0) { + TLRPC.Document document = getMediaDataController().ringtoneDataStore.getDocument(documentId); + value = NotificationsSoundActivity.trimTitle(document, document.file_name_fixed); + } else if (value.equals("NoSound")) { value = LocaleController.getString("NoSound", R.string.NoSound); + } else if (value.equals("Default")) { + value = LocaleController.getString("SoundDefault", R.string.SoundDefault); } textCell.setTextAndValue(LocaleController.getString("Sound", R.string.Sound), value, true); } else if (position == ringtoneRow) { @@ -865,8 +809,8 @@ public class ProfileNotificationsActivity extends BaseFragment implements Notifi break; } case 5: { - TextCheckBoxCell cell = (TextCheckBoxCell) holder.itemView; - SharedPreferences preferences = MessagesController.getNotificationsSettings(currentAccount); + TextCheckCell cell = (TextCheckCell) holder.itemView; + cell.setBackgroundColor(Theme.getColor(customEnabled && notificationsEnabled ? Theme.key_windowBackgroundChecked : Theme.key_windowBackgroundUnchecked)); cell.setTextAndCheck(LocaleController.getString("NotificationsEnableCustom", R.string.NotificationsEnableCustom), customEnabled && notificationsEnabled, false); break; } @@ -1017,12 +961,6 @@ public class ProfileNotificationsActivity extends BaseFragment implements Notifi themeDescriptions.add(new ThemeDescription(null, 0, null, null, null, cellDelegate, Theme.key_avatar_backgroundBlue)); themeDescriptions.add(new ThemeDescription(null, 0, null, null, null, cellDelegate, Theme.key_avatar_backgroundPink)); - themeDescriptions.add(new ThemeDescription(listView, 0, new Class[]{TextCheckBoxCell.class}, new String[]{"textView"}, null, null, null, Theme.key_windowBackgroundWhiteBlackText)); - themeDescriptions.add(new ThemeDescription(listView, 0, new Class[]{TextCheckBoxCell.class}, null, null, null, Theme.key_checkboxSquareUnchecked)); - themeDescriptions.add(new ThemeDescription(listView, 0, new Class[]{TextCheckBoxCell.class}, null, null, null, Theme.key_checkboxSquareDisabled)); - themeDescriptions.add(new ThemeDescription(listView, 0, new Class[]{TextCheckBoxCell.class}, null, null, null, Theme.key_checkboxSquareBackground)); - themeDescriptions.add(new ThemeDescription(listView, 0, new Class[]{TextCheckBoxCell.class}, null, null, null, Theme.key_checkboxSquareCheck)); - return themeDescriptions; } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/SecretMediaViewer.java b/TMessagesProj/src/main/java/org/telegram/ui/SecretMediaViewer.java index 357b85b30..03b6032d9 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/SecretMediaViewer.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/SecretMediaViewer.java @@ -19,6 +19,7 @@ import android.content.Context; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Paint; +import android.graphics.Path; import android.graphics.PixelFormat; import android.graphics.RectF; import android.graphics.SurfaceTexture; @@ -54,6 +55,7 @@ import org.telegram.messenger.NotificationCenter; import org.telegram.messenger.FileLoader; import org.telegram.messenger.FileLog; import org.telegram.messenger.R; +import org.telegram.messenger.SharedConfig; import org.telegram.messenger.UserConfig; import org.telegram.tgnet.ConnectionsManager; import org.telegram.tgnet.TLRPC; @@ -269,6 +271,8 @@ public class SecretMediaViewer implements NotificationCenter.NotificationCenterD private float dragY; private float clipTop; private float clipBottom; + private float clipTopOrigin; + private float clipBottomOrigin; private float clipHorizontal; private float translationX; private float translationY; @@ -279,7 +283,11 @@ public class SecretMediaViewer implements NotificationCenter.NotificationCenterD private float animateToScale; private float animateToClipTop; private float animateToClipBottom; + private float animateToClipTopOrigin; + private float animateToClipBottomOrigin; private float animateToClipHorizontal; + private int[] animateFromRadius; + private boolean animateToRadius; private float animationValue; private int currentRotation; private long animationStartTime; @@ -723,6 +731,14 @@ public class SecretMediaViewer implements NotificationCenter.NotificationCenterD int viewHeight = AndroidUtilities.displaySize.y + (Build.VERSION.SDK_INT >= 21 ? AndroidUtilities.statusBarHeight : 0); scale = Math.max(width / viewWidth, height / viewHeight); + if (object.radius != null) { + animateFromRadius = new int[object.radius.length]; + for (int i = 0; i < object.radius.length; ++i) { + animateFromRadius[i] = object.radius[i]; + } + } else { + animateFromRadius = null; + } translationX = object.viewX + drawRegion.left + width / 2 - viewWidth / 2; translationY = object.viewY + drawRegion.top + height / 2 - viewHeight / 2; clipHorizontal = Math.abs(drawRegion.left - object.imageReceiver.getImageX()); @@ -730,24 +746,25 @@ public class SecretMediaViewer implements NotificationCenter.NotificationCenterD int[] coords2 = new int[2]; object.parentView.getLocationInWindow(coords2); clipTop = coords2[1] - (Build.VERSION.SDK_INT >= 21 ? 0 : AndroidUtilities.statusBarHeight) - (object.viewY + drawRegion.top) + object.clipTopAddition; - if (clipTop < 0) { - clipTop = 0; - } + clipTop = Math.max(0, Math.max(clipTop, clipVertical)); clipBottom = (object.viewY + drawRegion.top + (int) height) - (coords2[1] + object.parentView.getHeight() - (Build.VERSION.SDK_INT >= 21 ? 0 : AndroidUtilities.statusBarHeight)) + object.clipBottomAddition; - if (clipBottom < 0) { - clipBottom = 0; - } - clipTop = Math.max(clipTop, clipVertical); - clipBottom = Math.max(clipBottom, clipVertical); + clipBottom = Math.max(0, Math.max(clipBottom, clipVertical)); + clipTopOrigin = 0;//coords2[1] - (Build.VERSION.SDK_INT >= 21 ? 0 : AndroidUtilities.statusBarHeight) - (object.viewY + drawRegion.top) + object.clipTopAddition; + clipTopOrigin = Math.max(0, Math.max(clipTopOrigin, clipVertical)); + clipBottomOrigin = 0;//(object.viewY + drawRegion.top + (int) height) - (coords2[1] + object.parentView.getHeight() - (Build.VERSION.SDK_INT >= 21 ? 0 : AndroidUtilities.statusBarHeight)) + object.clipBottomAddition; + clipBottomOrigin = Math.max(0, Math.max(clipBottomOrigin, clipVertical)); animationStartTime = System.currentTimeMillis(); animateToX = 0; animateToY = 0; animateToClipBottom = 0; + animateToClipBottomOrigin = 0; animateToClipHorizontal = 0; animateToClipTop = 0; + animateToClipTopOrigin = 0; animateToScale = 1.0f; + animateToRadius = true; zoomAnimation = true; NotificationCenter.getInstance(currentAccount).addObserver(this, NotificationCenter.messagesDeleted); @@ -939,6 +956,9 @@ public class SecretMediaViewer implements NotificationCenter.NotificationCenterD } + private float[] currentRadii; + private Path roundRectPath = new Path(); + private void onDraw(Canvas canvas) { if (!isPhotoVisible) { return; @@ -949,6 +969,8 @@ public class SecretMediaViewer implements NotificationCenter.NotificationCenterD float currentScale; float currentClipTop; float currentClipBottom; + float currentClipTopOrigin; + float currentClipBottomOrigin; float currentClipHorizontal; float aty = -1; @@ -972,6 +994,8 @@ public class SecretMediaViewer implements NotificationCenter.NotificationCenterD currentTranslationX = translationX + (animateToX - translationX) * av; currentClipTop = clipTop + (animateToClipTop - clipTop) * av; currentClipBottom = clipBottom + (animateToClipBottom - clipBottom) * av; + currentClipTopOrigin = clipTopOrigin + (animateToClipTopOrigin - clipTopOrigin) * av; + currentClipBottomOrigin = clipBottomOrigin + (animateToClipBottomOrigin - clipBottomOrigin) * av; currentClipHorizontal = clipHorizontal + (animateToClipHorizontal - clipHorizontal) * av; } else { currentScale = scale + (animateToScale - scale) * animationValue; @@ -979,8 +1003,11 @@ public class SecretMediaViewer implements NotificationCenter.NotificationCenterD currentTranslationX = translationX + (animateToX - translationX) * animationValue; currentClipTop = clipTop + (animateToClipTop - clipTop) * animationValue; currentClipBottom = clipBottom + (animateToClipBottom - clipBottom) * animationValue; + currentClipTopOrigin = clipTopOrigin + (animateToClipTopOrigin - clipTopOrigin) * animationValue; + currentClipBottomOrigin = clipBottomOrigin + (animateToClipBottomOrigin - clipBottomOrigin) * animationValue; currentClipHorizontal = clipHorizontal + (animateToClipHorizontal - clipHorizontal) * animationValue; } + if (animateToScale == 1 && scale == 1 && translationX == 0) { aty = currentTranslationY; } @@ -992,6 +1019,8 @@ public class SecretMediaViewer implements NotificationCenter.NotificationCenterD translationY = animateToY; clipBottom = animateToClipBottom; clipTop = animateToClipTop; + clipTopOrigin = animateToClipTopOrigin; + clipBottomOrigin = animateToClipBottomOrigin; clipHorizontal = animateToClipHorizontal; scale = animateToScale; animationStartTime = 0; @@ -1015,12 +1044,29 @@ public class SecretMediaViewer implements NotificationCenter.NotificationCenterD currentTranslationX = translationX; currentClipTop = clipTop; currentClipBottom = clipBottom; + currentClipTopOrigin = clipTopOrigin; + currentClipBottomOrigin = clipBottomOrigin; currentClipHorizontal = clipHorizontal; if (!moving) { aty = translationY; } } + boolean zeroRadius = true; + if (animateFromRadius != null) { + if (currentRadii == null) { + currentRadii = new float[8]; + } + float t = animateToRadius ? animationValue : 1f - animationValue; + zeroRadius = true; + for (int i = 0; i < 8; i += 2) { + currentRadii[i] = currentRadii[i + 1] = AndroidUtilities.lerp((float) animateFromRadius[i / 2] * 2, 0, t); + if (currentRadii[i] > 0) { + zeroRadius = false; + } + } + } + float translateX = currentTranslationX; float scaleDiff = 0; float alpha = 1; @@ -1061,6 +1107,12 @@ public class SecretMediaViewer implements NotificationCenter.NotificationCenterD int height = (int) (bitmapHeight * scale); canvas.clipRect(-width / 2 + currentClipHorizontal / sc, -height / 2 + currentClipTop / sc, width / 2 - currentClipHorizontal / sc, height / 2 - currentClipBottom / sc); + if (!zeroRadius) { + roundRectPath.reset(); + AndroidUtilities.rectTmp.set(-width / 2 + currentClipHorizontal / sc, -height / 2 + currentClipTopOrigin / sc, width / 2 - currentClipHorizontal / sc, height / 2 - currentClipBottomOrigin / sc); + roundRectPath.addRoundRect(AndroidUtilities.rectTmp, currentRadii, Path.Direction.CW); + canvas.clipPath(roundRectPath); + } if (!drawTextureView || !textureUploaded || !videoCrossfadeStarted || videoCrossfadeAlpha != 1.0f) { centerImage.setAlpha(alpha); @@ -1181,21 +1233,22 @@ public class SecretMediaViewer implements NotificationCenter.NotificationCenterD int[] coords2 = new int[2]; object.parentView.getLocationInWindow(coords2); animateToClipTop = coords2[1] - (Build.VERSION.SDK_INT >= 21 ? 0 : AndroidUtilities.statusBarHeight) - (object.viewY + drawRegion.top) + object.clipTopAddition; - if (animateToClipTop < 0) { - animateToClipTop = 0; - } + animateToClipTop = Math.max(0, Math.max(animateToClipTop, clipVertical)); animateToClipBottom = (object.viewY + drawRegion.top + (int) height) - (coords2[1] + object.parentView.getHeight() - (Build.VERSION.SDK_INT >= 21 ? 0 : AndroidUtilities.statusBarHeight)) + object.clipBottomAddition; - if (animateToClipBottom < 0) { - animateToClipBottom = 0; - } + animateToClipBottom = Math.max(0, Math.max(animateToClipBottom, clipVertical)); + + animateToClipTopOrigin = 0; // coords2[1] - (Build.VERSION.SDK_INT >= 21 ? 0 : AndroidUtilities.statusBarHeight) - (object.viewY + drawRegion.top) + object.clipTopAddition; + animateToClipTopOrigin = Math.max(0, Math.max(animateToClipTopOrigin, clipVertical)); + animateToClipBottomOrigin = 0; // (object.viewY + drawRegion.top + (int) height) - (coords2[1] + object.parentView.getHeight() - (Build.VERSION.SDK_INT >= 21 ? 0 : AndroidUtilities.statusBarHeight)) + object.clipBottomAddition; + animateToClipBottomOrigin = Math.max(0, Math.max(animateToClipBottomOrigin, clipVertical)); + animationStartTime = System.currentTimeMillis(); - animateToClipBottom = Math.max(animateToClipBottom, clipVertical); - animateToClipTop = Math.max(animateToClipTop, clipVertical); zoomAnimation = true; } else { int h = (AndroidUtilities.displaySize.y + (Build.VERSION.SDK_INT >= 21 ? AndroidUtilities.statusBarHeight : 0)); animateToY = translationY >= 0 ? h : -h; } + animateToRadius = false; if (isVideo) { videoCrossfadeStarted = false; textureUploaded = false; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/StatisticActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/StatisticActivity.java index cbbd2c235..4dfd602a1 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/StatisticActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/StatisticActivity.java @@ -2654,7 +2654,7 @@ public class StatisticActivity extends BaseFragment implements NotificationCente builder.setItems(items.toArray(new CharSequence[actions.size()]), AndroidUtilities.toIntArray(icons), (dialogInterface, i) -> { if (actions.get(i) == 0) { boolean[] needShowBulletin = new boolean[1]; - ChatRightsEditActivity newFragment = new ChatRightsEditActivity(user.id, chat.id, finalCurrentParticipant.channelParticipant.admin_rights, null, finalCurrentParticipant.channelParticipant.banned_rights, finalCurrentParticipant.channelParticipant.rank, ChatRightsEditActivity.TYPE_ADMIN, true, finalIsAdmin) { + ChatRightsEditActivity newFragment = new ChatRightsEditActivity(user.id, chat.id, finalCurrentParticipant.channelParticipant.admin_rights, null, finalCurrentParticipant.channelParticipant.banned_rights, finalCurrentParticipant.channelParticipant.rank, ChatRightsEditActivity.TYPE_ADMIN, true, finalIsAdmin, null) { @Override protected void onTransitionAnimationEnd(boolean isOpen, boolean backward) { if (!isOpen && backward && needShowBulletin[0] && BulletinFactory.canShowBulletin(fragment)) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ThemeActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ThemeActivity.java index bbe074968..2e23d8cc4 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ThemeActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ThemeActivity.java @@ -75,6 +75,7 @@ import org.telegram.ui.Cells.ChatListCell; import org.telegram.ui.Cells.ChatMessageCell; import org.telegram.ui.Cells.HeaderCell; import org.telegram.ui.Cells.NotificationsCheckCell; +import org.telegram.ui.Cells.RadioButtonCell; import org.telegram.ui.Cells.ShadowSectionCell; import org.telegram.ui.Cells.TextCell; import org.telegram.ui.Cells.TextCheckCell; @@ -134,6 +135,9 @@ public class ThemeActivity extends BaseFragment implements NotificationCenter.No private int raiseToSpeakRow; private int sendByEnterRow; private int saveToGalleryRow; + private int saveToGalleryOption1Row; + private int saveToGalleryOption2Row; + private int saveToGallerySectionRow; private int distanceRow; private int enableAnimationsRow; private int settings2Row; @@ -508,6 +512,9 @@ public class ThemeActivity extends BaseFragment implements NotificationCenter.No raiseToSpeakRow = -1; sendByEnterRow = -1; saveToGalleryRow = -1; + saveToGalleryOption1Row = -1; + saveToGalleryOption2Row = -1; + saveToGallerySectionRow = -1; distanceRow = -1; settings2Row = -1; stickersRow = -1; @@ -1991,6 +1998,9 @@ public class ThemeActivity extends BaseFragment implements NotificationCenter.No case 18: view = new TextSettingsCell(mContext); break; + case 19: + view = new RadioButtonCell(mContext); + break; } return new RecyclerListView.Holder(view); } @@ -2055,7 +2065,7 @@ public class ThemeActivity extends BaseFragment implements NotificationCenter.No break; } case 3: { - if (position == stickersSection2Row || position == nightTypeInfoRow && themeInfoRow == -1 || position == themeInfoRow && nightTypeInfoRow != -1) { + if (position == stickersSection2Row || position == nightTypeInfoRow && themeInfoRow == -1 || position == themeInfoRow && nightTypeInfoRow != -1 || position == saveToGallerySectionRow) { holder.itemView.setBackgroundDrawable(Theme.getThemedDrawable(mContext, R.drawable.greydivider_bottom, Theme.key_windowBackgroundGrayShadow)); } else { holder.itemView.setBackgroundDrawable(Theme.getThemedDrawable(mContext, R.drawable.greydivider, Theme.key_windowBackgroundGrayShadow)); @@ -2204,6 +2214,16 @@ public class ThemeActivity extends BaseFragment implements NotificationCenter.No } break; } + case 19:{ + RadioButtonCell radioCell = (RadioButtonCell) holder.itemView; + if (position == saveToGalleryOption1Row) { + radioCell.setTextAndValue("save media only from peer chats", "",true, false); + } else { + radioCell.setTextAndValue("save media from all chats", "",true, false); + } + + break; + } } } @@ -2228,7 +2248,7 @@ public class ThemeActivity extends BaseFragment implements NotificationCenter.No return 2; } else if (position == themeInfoRow || position == nightTypeInfoRow || position == scheduleFromToInfoRow || position == stickersSection2Row || position == settings2Row || position == newThemeInfoRow || - position == chatListInfoRow || position == bubbleRadiusInfoRow || position == swipeGestureInfoRow) { + position == chatListInfoRow || position == bubbleRadiusInfoRow || position == swipeGestureInfoRow || position == saveToGallerySectionRow) { return 3; } else if (position == nightDisabledRow || position == nightScheduledRow || position == nightAutomaticRow || position == nightSystemDefaultRow) { return 4; @@ -2264,6 +2284,8 @@ public class ThemeActivity extends BaseFragment implements NotificationCenter.No return 17; } else if (position == reactionsDoubleTapRow) { return 18; + } else if (position == saveToGalleryOption1Row || position == saveToGalleryOption2Row) { + return 19; } return 1; } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ThemePreviewActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ThemePreviewActivity.java index a292ba0bf..5cdd2fe4a 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ThemePreviewActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ThemePreviewActivity.java @@ -1547,39 +1547,39 @@ public class ThemePreviewActivity extends BaseFragment implements DownloadContro messagesPlayAnimationImageView.setScaleType(ImageView.ScaleType.CENTER); messagesPlayAnimationImageView.setImageResource(R.drawable.bg_rotate_large); messagesPlayAnimationView.addView(messagesPlayAnimationImageView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER)); + + for (int a = 0; a < 2; a++) { + final int num = a; + messagesCheckBoxView[a] = new WallpaperCheckBoxView(context, a == 0, backgroundImage); + 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); + 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); + } else { + layoutParams.rightMargin = width / 2 + AndroidUtilities.dp(10); + } + messagesButtonsContainer.addView(messagesCheckBoxView[a], layoutParams); + WallpaperCheckBoxView view = messagesCheckBoxView[a]; + messagesCheckBoxView[a].setOnClickListener(v -> { + if (messagesButtonsContainer.getAlpha() != 1.0f) { + return; + } + if (num == 0) { + view.setChecked(!view.isChecked(), true); + accent.myMessagesAnimated = view.isChecked(); + Theme.refreshThemeColors(true, true); + listView2.invalidateViews(); + } + }); + } } - - for (int a = 0; a < 2; a++) { - final int num = a; - messagesCheckBoxView[a] = new WallpaperCheckBoxView(context, a == 0, backgroundImage); - 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); - 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); - } else { - layoutParams.rightMargin = width / 2 + AndroidUtilities.dp(10); - } - messagesButtonsContainer.addView(messagesCheckBoxView[a], layoutParams); - WallpaperCheckBoxView view = messagesCheckBoxView[a]; - messagesCheckBoxView[a].setOnClickListener(v -> { - if (messagesButtonsContainer.getAlpha() != 1.0f) { - return; - } - if (num == 0) { - view.setChecked(!view.isChecked(), true); - accent.myMessagesAnimated = view.isChecked(); - Theme.refreshThemeColors(true, true); - listView2.invalidateViews(); - } - }); - } } if (screenType == SCREEN_TYPE_ACCENT_COLOR || currentWallpaper instanceof WallpapersListActivity.ColorWallpaper) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/TwoStepVerificationActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/TwoStepVerificationActivity.java index 93eea235a..a1d36292c 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/TwoStepVerificationActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/TwoStepVerificationActivity.java @@ -39,6 +39,7 @@ import android.widget.LinearLayout; import android.widget.ScrollView; import android.widget.TextView; +import androidx.core.graphics.ColorUtils; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; @@ -199,9 +200,6 @@ public class TwoStepVerificationActivity extends BaseFragment implements Notific actionBar.setItemsColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlackText), false); actionBar.setItemsBackgroundColor(Theme.getColor(Theme.key_actionBarWhiteSelector), false); actionBar.setCastShadows(false); - if (!AndroidUtilities.isTablet()) { - actionBar.showActionModeTop(); - } } actionBar.setActionBarMenuOnItemClick(new ActionBar.ActionBarMenuOnItemClick() { @Override @@ -1297,4 +1295,10 @@ public class TwoStepVerificationActivity extends BaseFragment implements Notific super.finishFragment(); } } + + @Override + public boolean isLightStatusBar() { + int color = Theme.getColor(Theme.key_windowBackgroundWhite, null, true); + return ColorUtils.calculateLuminance(color) > 0.7f; + } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/TwoStepVerificationSetupActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/TwoStepVerificationSetupActivity.java index ece4f9d3b..e1084b358 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/TwoStepVerificationSetupActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/TwoStepVerificationSetupActivity.java @@ -51,6 +51,8 @@ import android.widget.ScrollView; import android.widget.TextView; import android.widget.Toast; +import androidx.core.graphics.ColorUtils; + import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.FileLog; import org.telegram.messenger.LocaleController; @@ -252,9 +254,6 @@ public class TwoStepVerificationSetupActivity extends BaseFragment { actionBar.setItemsBackgroundColor(Theme.getColor(Theme.key_actionBarWhiteSelector), false); actionBar.setCastShadows(false); actionBar.setAddToContainer(false); - if (!AndroidUtilities.isTablet()) { - actionBar.showActionModeTop(); - } actionBar.setActionBarMenuOnItemClick(new ActionBar.ActionBarMenuOnItemClick() { @Override public void onItemClick(int id) { @@ -2186,4 +2185,10 @@ public class TwoStepVerificationSetupActivity extends BaseFragment { super.finishFragment(); } } + + @Override + public boolean isLightStatusBar() { + int color = Theme.getColor(Theme.key_windowBackgroundWhite, null, true); + return ColorUtils.calculateLuminance(color) > 0.7f; + } } diff --git a/TMessagesProj/src/main/res/drawable-hdpi/bot_invite.png b/TMessagesProj/src/main/res/drawable-hdpi/bot_invite.png new file mode 100644 index 000000000..73e5707c1 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/bot_invite.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/bot_webview.png b/TMessagesProj/src/main/res/drawable-hdpi/bot_webview.png new file mode 100644 index 000000000..475d08f2e Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/bot_webview.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_autodelete.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_autodelete.png new file mode 100644 index 000000000..33cb8df2c Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/msg_autodelete.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_autodelete_1d.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_autodelete_1d.png new file mode 100644 index 000000000..26d3a207c Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/msg_autodelete_1d.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_autodelete_1h.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_autodelete_1h.png new file mode 100644 index 000000000..1ed05a6da Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/msg_autodelete_1h.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_autodelete_1m.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_autodelete_1m.png new file mode 100644 index 000000000..c087d2a9f Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/msg_autodelete_1m.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_autodelete_1w.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_autodelete_1w.png new file mode 100644 index 000000000..9559485ec Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/msg_autodelete_1w.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_bot.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_bot.png new file mode 100644 index 000000000..32fb81e8d Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/msg_bot.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_customize.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_customize.png new file mode 100644 index 000000000..dfd2793fc Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/msg_customize.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_delete.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_delete.png index 04653df98..3b4e1f337 100644 Binary files a/TMessagesProj/src/main/res/drawable-hdpi/msg_delete.png and b/TMessagesProj/src/main/res/drawable-hdpi/msg_delete.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_delete_auto.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_delete_auto.png index dcef48c58..6e4f315bf 100644 Binary files a/TMessagesProj/src/main/res/drawable-hdpi/msg_delete_auto.png and b/TMessagesProj/src/main/res/drawable-hdpi/msg_delete_auto.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_disable.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_disable.png new file mode 100644 index 000000000..772be0874 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/msg_disable.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_mini_autodelete.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_mini_autodelete.png new file mode 100644 index 000000000..4628a69ed Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/msg_mini_autodelete.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_mini_autodelete_empty.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_mini_autodelete_empty.png new file mode 100644 index 000000000..77a8d4ac0 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/msg_mini_autodelete_empty.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_mini_autodelete_timer.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_mini_autodelete_timer.png new file mode 100644 index 000000000..3615aa74b Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/msg_mini_autodelete_timer.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_mute.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_mute.png index 9a6e3b2b3..b1d086283 100644 Binary files a/TMessagesProj/src/main/res/drawable-hdpi/msg_mute.png and b/TMessagesProj/src/main/res/drawable-hdpi/msg_mute.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_mute_1h.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_mute_1h.png new file mode 100644 index 000000000..4d95025d8 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/msg_mute_1h.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_mute_8h.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_mute_8h.png new file mode 100644 index 000000000..6cb976d4e Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/msg_mute_8h.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_mute_period.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_mute_period.png new file mode 100644 index 000000000..be0de9ad1 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/msg_mute_period.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_silent.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_silent.png new file mode 100644 index 000000000..7f5a2f869 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/msg_silent.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_tone_add.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_tone_add.png new file mode 100644 index 000000000..59b6dc57d Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/msg_tone_add.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_tone_off.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_tone_off.png new file mode 100644 index 000000000..ef1be3615 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/msg_tone_off.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_tone_on.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_tone_on.png new file mode 100644 index 000000000..0deae5a62 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/msg_tone_on.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_unmute.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_unmute.png index 56a75943f..952ab798b 100644 Binary files a/TMessagesProj/src/main/res/drawable-hdpi/msg_unmute.png and b/TMessagesProj/src/main/res/drawable-hdpi/msg_unmute.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_videocall.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_videocall.png index c6d203879..0faa29a9c 100644 Binary files a/TMessagesProj/src/main/res/drawable-hdpi/msg_videocall.png and b/TMessagesProj/src/main/res/drawable-hdpi/msg_videocall.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/pip_pause_large.png b/TMessagesProj/src/main/res/drawable-hdpi/pip_pause_large.png new file mode 100644 index 000000000..c24fc3c6b Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/pip_pause_large.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/pip_play_large.png b/TMessagesProj/src/main/res/drawable-hdpi/pip_play_large.png new file mode 100644 index 000000000..b256919d7 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/pip_play_large.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/pip_replay_large.png b/TMessagesProj/src/main/res/drawable-hdpi/pip_replay_large.png new file mode 100644 index 000000000..a09d4d71d Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/pip_replay_large.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/bot_invite.png b/TMessagesProj/src/main/res/drawable-mdpi/bot_invite.png new file mode 100644 index 000000000..e5655fb05 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/bot_invite.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/bot_webview.png b/TMessagesProj/src/main/res/drawable-mdpi/bot_webview.png new file mode 100644 index 000000000..c5de9be14 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/bot_webview.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_autodelete.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_autodelete.png new file mode 100644 index 000000000..d77fe2491 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/msg_autodelete.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_autodelete_1d.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_autodelete_1d.png new file mode 100644 index 000000000..5ae1da8c7 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/msg_autodelete_1d.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_autodelete_1h.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_autodelete_1h.png new file mode 100644 index 000000000..48e44a2f8 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/msg_autodelete_1h.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_autodelete_1m.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_autodelete_1m.png new file mode 100644 index 000000000..e9f49e51f Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/msg_autodelete_1m.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_autodelete_1w.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_autodelete_1w.png new file mode 100644 index 000000000..3447cc773 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/msg_autodelete_1w.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_bot.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_bot.png new file mode 100644 index 000000000..a76e39048 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/msg_bot.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_customize.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_customize.png new file mode 100644 index 000000000..744313cd2 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/msg_customize.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_delete.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_delete.png index 0a846fb25..3b557e128 100644 Binary files a/TMessagesProj/src/main/res/drawable-mdpi/msg_delete.png and b/TMessagesProj/src/main/res/drawable-mdpi/msg_delete.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_delete_auto.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_delete_auto.png index aa789fd4e..d95af7c86 100644 Binary files a/TMessagesProj/src/main/res/drawable-mdpi/msg_delete_auto.png and b/TMessagesProj/src/main/res/drawable-mdpi/msg_delete_auto.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_disable.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_disable.png new file mode 100644 index 000000000..079b57fb8 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/msg_disable.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_mini_autodelete.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_mini_autodelete.png new file mode 100644 index 000000000..431ba8872 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/msg_mini_autodelete.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_mini_autodelete_empty.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_mini_autodelete_empty.png new file mode 100644 index 000000000..4df725ebe Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/msg_mini_autodelete_empty.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_mini_autodelete_timer.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_mini_autodelete_timer.png new file mode 100644 index 000000000..7e177ecf1 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/msg_mini_autodelete_timer.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_mute.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_mute.png index 4dc2917ba..250a9a7ee 100644 Binary files a/TMessagesProj/src/main/res/drawable-mdpi/msg_mute.png and b/TMessagesProj/src/main/res/drawable-mdpi/msg_mute.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_mute_1h.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_mute_1h.png new file mode 100644 index 000000000..0fa0e550f Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/msg_mute_1h.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_mute_8h.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_mute_8h.png new file mode 100644 index 000000000..9306016bd Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/msg_mute_8h.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_mute_period.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_mute_period.png new file mode 100644 index 000000000..ae1b570ca Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/msg_mute_period.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_silent.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_silent.png new file mode 100644 index 000000000..6b37956a9 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/msg_silent.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_tone_add.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_tone_add.png new file mode 100644 index 000000000..e3d24a24f Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/msg_tone_add.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_tone_off.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_tone_off.png new file mode 100644 index 000000000..1c346dc7f Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/msg_tone_off.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_tone_on.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_tone_on.png new file mode 100644 index 000000000..b3e5d9b27 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/msg_tone_on.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_unmute.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_unmute.png index 2e201bbd9..3e8644ac2 100644 Binary files a/TMessagesProj/src/main/res/drawable-mdpi/msg_unmute.png and b/TMessagesProj/src/main/res/drawable-mdpi/msg_unmute.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_videocall.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_videocall.png index 45dd2cfc1..8e005ed8f 100644 Binary files a/TMessagesProj/src/main/res/drawable-mdpi/msg_videocall.png and b/TMessagesProj/src/main/res/drawable-mdpi/msg_videocall.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/pip_pause_large.png b/TMessagesProj/src/main/res/drawable-mdpi/pip_pause_large.png new file mode 100644 index 000000000..b8691206d Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/pip_pause_large.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/pip_play_large.png b/TMessagesProj/src/main/res/drawable-mdpi/pip_play_large.png new file mode 100644 index 000000000..2f91aa10a Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/pip_play_large.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/pip_replay_large.png b/TMessagesProj/src/main/res/drawable-mdpi/pip_replay_large.png new file mode 100644 index 000000000..e66c7b44e Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/pip_replay_large.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/bot_invite.png b/TMessagesProj/src/main/res/drawable-xhdpi/bot_invite.png new file mode 100644 index 000000000..dfadd0449 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/bot_invite.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/bot_webview.png b/TMessagesProj/src/main/res/drawable-xhdpi/bot_webview.png new file mode 100644 index 000000000..f2ce51240 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/bot_webview.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_autodelete.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_autodelete.png new file mode 100644 index 000000000..5eba29d6c Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/msg_autodelete.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_autodelete_1d.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_autodelete_1d.png new file mode 100644 index 000000000..04f068450 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/msg_autodelete_1d.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_autodelete_1h.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_autodelete_1h.png new file mode 100644 index 000000000..f4ba3e583 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/msg_autodelete_1h.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_autodelete_1m.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_autodelete_1m.png new file mode 100644 index 000000000..f5c36154c Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/msg_autodelete_1m.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_autodelete_1w.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_autodelete_1w.png new file mode 100644 index 000000000..58edfe6bf Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/msg_autodelete_1w.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_bot.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_bot.png new file mode 100644 index 000000000..43c4a5a0e Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/msg_bot.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_customize.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_customize.png new file mode 100644 index 000000000..d9522439c Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/msg_customize.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_delete.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_delete.png index 93ac3b001..c61ad723e 100644 Binary files a/TMessagesProj/src/main/res/drawable-xhdpi/msg_delete.png and b/TMessagesProj/src/main/res/drawable-xhdpi/msg_delete.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_delete_auto.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_delete_auto.png index 9fd64ec28..3981f14aa 100644 Binary files a/TMessagesProj/src/main/res/drawable-xhdpi/msg_delete_auto.png and b/TMessagesProj/src/main/res/drawable-xhdpi/msg_delete_auto.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_disable.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_disable.png new file mode 100644 index 000000000..eac4873c4 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/msg_disable.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_mini_autodelete.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_mini_autodelete.png new file mode 100644 index 000000000..89e34b142 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/msg_mini_autodelete.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_mini_autodelete_empty.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_mini_autodelete_empty.png new file mode 100644 index 000000000..c3ff18c5f Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/msg_mini_autodelete_empty.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_mini_autodelete_timer.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_mini_autodelete_timer.png new file mode 100644 index 000000000..084570304 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/msg_mini_autodelete_timer.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_mute.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_mute.png index 7fb830bc7..d959f1e24 100644 Binary files a/TMessagesProj/src/main/res/drawable-xhdpi/msg_mute.png and b/TMessagesProj/src/main/res/drawable-xhdpi/msg_mute.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_mute_1h.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_mute_1h.png new file mode 100644 index 000000000..8a360a628 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/msg_mute_1h.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_mute_8h.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_mute_8h.png new file mode 100644 index 000000000..34131e408 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/msg_mute_8h.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_mute_period.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_mute_period.png new file mode 100644 index 000000000..61e5f32b2 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/msg_mute_period.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_silent.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_silent.png new file mode 100644 index 000000000..fa9801652 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/msg_silent.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_tone_add.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_tone_add.png new file mode 100644 index 000000000..9b480b167 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/msg_tone_add.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_tone_off.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_tone_off.png new file mode 100644 index 000000000..6efdc2dd8 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/msg_tone_off.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_tone_on.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_tone_on.png new file mode 100644 index 000000000..97be3b6d5 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/msg_tone_on.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_unmute.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_unmute.png index 037d3bf97..29ee3be36 100644 Binary files a/TMessagesProj/src/main/res/drawable-xhdpi/msg_unmute.png and b/TMessagesProj/src/main/res/drawable-xhdpi/msg_unmute.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_videocall.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_videocall.png index c79c49e3a..53877643c 100644 Binary files a/TMessagesProj/src/main/res/drawable-xhdpi/msg_videocall.png and b/TMessagesProj/src/main/res/drawable-xhdpi/msg_videocall.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/pip_pause_large.png b/TMessagesProj/src/main/res/drawable-xhdpi/pip_pause_large.png new file mode 100644 index 000000000..364b71a7c Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/pip_pause_large.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/pip_play_large.png b/TMessagesProj/src/main/res/drawable-xhdpi/pip_play_large.png new file mode 100644 index 000000000..37b561d45 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/pip_play_large.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/pip_replay_large.png b/TMessagesProj/src/main/res/drawable-xhdpi/pip_replay_large.png new file mode 100644 index 000000000..65207aa6a Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/pip_replay_large.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/bot_invite.png b/TMessagesProj/src/main/res/drawable-xxhdpi/bot_invite.png new file mode 100644 index 000000000..536943329 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/bot_invite.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/bot_webview.png b/TMessagesProj/src/main/res/drawable-xxhdpi/bot_webview.png new file mode 100644 index 000000000..e771235b6 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/bot_webview.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_autodelete.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_autodelete.png new file mode 100644 index 000000000..d26b6a3e0 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_autodelete.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_autodelete_1d.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_autodelete_1d.png new file mode 100644 index 000000000..3ce1023fc Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_autodelete_1d.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_autodelete_1h.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_autodelete_1h.png new file mode 100644 index 000000000..7b8facd34 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_autodelete_1h.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_autodelete_1m.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_autodelete_1m.png new file mode 100644 index 000000000..04d53f0af Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_autodelete_1m.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_autodelete_1w.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_autodelete_1w.png new file mode 100644 index 000000000..3249b9e95 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_autodelete_1w.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_bot.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_bot.png new file mode 100644 index 000000000..134ae6aaf Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_bot.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_customize.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_customize.png new file mode 100644 index 000000000..73bb1b9c0 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_customize.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_delete.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_delete.png index 800cd12af..4b87ebc01 100644 Binary files a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_delete.png and b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_delete.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_delete_auto.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_delete_auto.png index 9112817b1..cee6d944e 100644 Binary files a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_delete_auto.png and b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_delete_auto.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_disable.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_disable.png new file mode 100644 index 000000000..6e86c0889 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_disable.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_mini_autodelete.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_mini_autodelete.png new file mode 100644 index 000000000..d00bf8cb5 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_mini_autodelete.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_mini_autodelete_empty.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_mini_autodelete_empty.png new file mode 100644 index 000000000..062f5666a Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_mini_autodelete_empty.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_mini_autodelete_timer.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_mini_autodelete_timer.png new file mode 100644 index 000000000..b80d87b5c Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_mini_autodelete_timer.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_mute.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_mute.png index e089f9ab4..a02e81b8d 100644 Binary files a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_mute.png and b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_mute.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_mute_1h.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_mute_1h.png new file mode 100644 index 000000000..8c41b8955 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_mute_1h.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_mute_8h.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_mute_8h.png new file mode 100644 index 000000000..c802a2b7f Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_mute_8h.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_mute_period.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_mute_period.png new file mode 100644 index 000000000..3f04018f4 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_mute_period.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_silent.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_silent.png new file mode 100644 index 000000000..a48c93c7a Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_silent.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_tone_add.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_tone_add.png new file mode 100644 index 000000000..56d9d307f Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_tone_add.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_tone_off.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_tone_off.png new file mode 100644 index 000000000..0e7a5173c Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_tone_off.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_tone_on.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_tone_on.png new file mode 100644 index 000000000..f8d0bed82 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_tone_on.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_unmute.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_unmute.png index 4c7f5c7b8..bfab737e7 100644 Binary files a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_unmute.png and b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_unmute.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_videocall.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_videocall.png index 838720c4f..97da5f1a6 100644 Binary files a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_videocall.png and b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_videocall.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/pip_pause_large.png b/TMessagesProj/src/main/res/drawable-xxhdpi/pip_pause_large.png new file mode 100644 index 000000000..7b0535cb4 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/pip_pause_large.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/pip_play_large.png b/TMessagesProj/src/main/res/drawable-xxhdpi/pip_play_large.png new file mode 100644 index 000000000..9703a5326 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/pip_play_large.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/pip_replay_large.png b/TMessagesProj/src/main/res/drawable-xxhdpi/pip_replay_large.png new file mode 100644 index 000000000..c2e3fc35b Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/pip_replay_large.png differ diff --git a/TMessagesProj/src/main/res/drawable/avd_flip.xml b/TMessagesProj/src/main/res/drawable/avd_flip.xml new file mode 100644 index 000000000..f39b83996 --- /dev/null +++ b/TMessagesProj/src/main/res/drawable/avd_flip.xml @@ -0,0 +1,136 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/TMessagesProj/src/main/res/drawable/tg_splash_320.xml b/TMessagesProj/src/main/res/drawable/tg_splash_320.xml new file mode 100644 index 000000000..e46e5f6f9 --- /dev/null +++ b/TMessagesProj/src/main/res/drawable/tg_splash_320.xml @@ -0,0 +1,110 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/TMessagesProj/src/main/res/drawable/vd_flip.xml b/TMessagesProj/src/main/res/drawable/vd_flip.xml new file mode 100644 index 000000000..3eae5f050 --- /dev/null +++ b/TMessagesProj/src/main/res/drawable/vd_flip.xml @@ -0,0 +1,53 @@ + + + + + + + + + + + diff --git a/TMessagesProj/src/main/res/raw/bot_webview_cross_to_sheet.json b/TMessagesProj/src/main/res/raw/bot_webview_cross_to_sheet.json new file mode 100644 index 000000000..194f3f756 --- /dev/null +++ b/TMessagesProj/src/main/res/raw/bot_webview_cross_to_sheet.json @@ -0,0 +1 @@ +{"v":"4.8.0","meta":{"g":"LottieFiles AE 1.1.0","a":"","k":"","d":"","tc":""},"fr":60,"ip":0,"op":22,"w":400,"h":400,"nm":"Icon Cross - Sheet","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Rectangle","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":16,"s":[0]},{"t":17,"s":[100]}],"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":1,"s":[-90]},{"t":19,"s":[0]}],"ix":10},"p":{"a":0,"k":[199.889,94.444,0],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"t":1,"s":[100,100,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":8,"s":[85,85,100]},{"t":19,"s":[87.8,87.8,100]}],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":1},"o":{"x":0.167,"y":0},"t":17,"s":[{"i":[[0,0],[0,0],[0,0],[5.563,0.602],[0,0],[0.17,-6.48],[0,0]],"o":[[0,0],[0,0],[-4.027,-4.787],[0,0],[-6.51,0],[0,0],[0,0]],"v":[[-137.063,-35.692],[101.551,-27.99],[108.363,7.164],[98.561,-2.186],[-115.918,-9.099],[-136.756,-0.822],[-143.844,25.663]],"c":true}]},{"i":{"x":0.833,"y":1},"o":{"x":0.333,"y":0},"t":18,"s":[{"i":[[0,0],[0,0],[0,0],[2.977,-0.397],[0,0],[7.855,-5.16],[0,0]],"o":[[0,0],[0,0],[-1.653,-9.205],[0,0],[-6.51,0],[0,0],[0,0]],"v":[[-131.237,-31.981],[120.492,-29.916],[120.483,30.641],[114.172,20.784],[-124.47,25.867],[-132.442,28.233],[-134.389,37.125]],"c":true}]},{"t":19,"s":[{"i":[[0,0],[0,0],[0,0],[6.73,0],[0,0],[0.17,-6.48],[0,0]],"o":[[0,0],[0,0],[-0.32,-6.72],[0,0],[-6.51,0],[0,0],[0,0]],"v":[[-128.5,-39],[128.5,-39],[128.5,39],[115.91,27],[-116.52,27],[-128.5,38.68],[-128.5,39]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.592156862745,0.592156862745,0.592156862745,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":"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":[111.111,111.111],"ix":3},"r":{"a":0,"k":-0.075,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":23,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"Path 7","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":1,"s":[0]},{"t":19,"s":[180]}],"ix":10},"p":{"a":0,"k":[200,200,0],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"t":1,"s":[100,100,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":8,"s":[85,85,100]},{"t":19,"s":[90,90,100]}],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0},"t":1,"s":[{"i":[[94.07,-96.65],[-14.5,14.885],[0,0],[-13.93,14.3],[0,0],[-13.85,13.69]],"o":[[17.57,-17.9],[0,0],[15.65,-16.01],[0,0],[9.88,-8.65],[0,0]],"v":[[-95.87,97.1],[-58.85,59.365],[-16.1,16.01],[21.13,-21.95],[67.97,-67.85],[98.45,-97.84]],"c":false}]},{"i":{"x":0.833,"y":1},"o":{"x":0.167,"y":0.167},"t":12,"s":[{"i":[[94.254,-96.761],[-14.134,15.233],[0,0],[-14.292,13.939],[0,0],[-13.501,12.621]],"o":[[16.414,-17.448],[0,0],[15.255,-16.329],[0,0],[10.344,-8.432],[0,0]],"v":[[-95.768,98.258],[-60.973,60.165],[-19.301,13.308],[18.281,-25.004],[68.572,-69.746],[99.574,-97.67]],"c":false}]},{"t":19,"s":[{"i":[[101.36,-101.05],[0,28.67],[0,0],[-28.27,0],[0,0],[0,-28.67]],"o":[[-28.27,0],[0,0],[0,-28.67],[0,0],[28.27,0],[0,0]],"v":[[-91.82,143],[-143,91.09],[-143,-91.09],[-91.82,-143],[91.82,-143],[143,-91.09]],"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":36,"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":[111.111,111.111],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Path","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":1,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":14,"s":[22]},{"t":19,"s":[0]}],"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":1,"s":[100]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":14,"s":[78]},{"t":19,"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":23,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"Path","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":1,"s":[-90]},{"t":19,"s":[0]}],"ix":10},"p":{"a":0,"k":[200,200,0],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"t":1,"s":[100,100,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":8,"s":[85,85,100]},{"t":19,"s":[90,90,100]}],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0},"t":1,"s":[{"i":[[94.07,-96.65],[-14.5,14.885],[0,0],[-13.93,14.3],[0,0],[-13.85,13.69]],"o":[[17.57,-17.9],[0,0],[15.65,-16.01],[0,0],[9.88,-8.65],[0,0]],"v":[[-95.87,97.1],[-58.85,59.365],[-16.1,16.01],[21.13,-21.95],[67.97,-67.85],[98.45,-97.84]],"c":false}]},{"i":{"x":0.833,"y":1},"o":{"x":0.167,"y":0.167},"t":12,"s":[{"i":[[94.254,-96.761],[-14.134,15.233],[0,0],[-14.292,13.939],[0,0],[-13.501,12.621]],"o":[[16.414,-17.448],[0,0],[15.255,-16.329],[0,0],[10.344,-8.432],[0,0]],"v":[[-95.768,98.258],[-60.973,60.165],[-19.301,13.308],[18.281,-25.004],[68.572,-69.746],[99.574,-97.67]],"c":false}]},{"t":19,"s":[{"i":[[101.36,-101.05],[0,28.67],[0,0],[-28.27,0],[0,0],[0,-28.67]],"o":[[-28.27,0],[0,0],[0,-28.67],[0,0],[28.27,0],[0,0]],"v":[[-91.82,143],[-143,91.09],[-143,-91.09],[-91.82,-143],[91.82,-143],[143,-91.09]],"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":36,"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":[111.111,111.111],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Path","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":1,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":14,"s":[22]},{"t":19,"s":[0]}],"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":1,"s":[100]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":14,"s":[78]},{"t":19,"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":23,"st":0,"bm":0}],"markers":[]} \ No newline at end of file diff --git a/TMessagesProj/src/main/res/raw/bot_webview_sheet_to_cross.json b/TMessagesProj/src/main/res/raw/bot_webview_sheet_to_cross.json new file mode 100644 index 000000000..f7b3df250 --- /dev/null +++ b/TMessagesProj/src/main/res/raw/bot_webview_sheet_to_cross.json @@ -0,0 +1 @@ +{"v":"4.8.0","meta":{"g":"LottieFiles AE 1.1.0","a":"","k":"","d":"","tc":""},"fr":60,"ip":0,"op":22,"w":400,"h":400,"nm":"Icon Sheet - Cross","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Rectangle","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":3,"s":[100]},{"t":4,"s":[0]}],"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":1,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":2,"s":[-0.737]},{"t":20,"s":[-90]}],"ix":10},"p":{"a":0,"k":[199.889,94.444,0],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":1,"s":[90,90,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":12,"s":[85,85,100]},{"t":19,"s":[100,100,100]}],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":1,"s":[{"i":[[0,0],[0,0],[0,0],[6.73,0],[0,0],[0.17,-6.48],[0,0]],"o":[[0,0],[0,0],[-0.32,-6.72],[0,0],[-6.51,0],[0,0],[0,0]],"v":[[-128.5,-39],[128.5,-39],[128.5,39],[115.91,27],[-116.52,27],[-128.5,38.68],[-128.5,39]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":2,"s":[{"i":[[0,0],[0,0],[0,0],[6.73,0],[0,0],[0.17,-6.48],[0,0]],"o":[[0,0],[0,0],[-3.868,-6.262],[0,0],[-6.51,0],[0,0],[0,0]],"v":[[-117.276,-35.38],[109.015,-34.936],[128.983,11.495],[120.865,12.05],[-116.52,27],[-126.06,31.653],[-128.5,39]],"c":true}]},{"t":3,"s":[{"i":[[0,0],[0,0],[0,0],[6.73,0],[0,0],[0.17,-6.48],[0,0]],"o":[[0,0],[0,0],[-3.868,-6.262],[0,0],[-6.51,0],[0,0],[0,0]],"v":[[-102.392,-18.806],[87.683,-27.969],[106.014,-6.856],[93.212,-8.892],[-75.63,-10.574],[-97.414,3.029],[-107.412,16.44]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.592156862745,0.592156862745,0.592156862745,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":"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":[111.111,111.111],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":22,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"Path 7","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.262],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":1,"s":[180]},{"t":20,"s":[0]}],"ix":10},"p":{"a":0,"k":[200,200,0],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":1,"s":[90,90,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":12,"s":[85,85,100]},{"t":19,"s":[100,100,100]}],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.333,"y":0},"t":1,"s":[{"i":[[101.36,-101.05],[0,28.67],[0,0],[-28.27,0],[0,0],[0,-28.67]],"o":[[-28.27,0],[0,0],[0,-28.67],[0,0],[28.27,0],[0,0]],"v":[[-91.82,143],[-143,91.09],[-143,-91.09],[-91.82,-143],[91.82,-143],[143,-91.09]],"c":false}]},{"i":{"x":0,"y":1},"o":{"x":0.167,"y":0.167},"t":6,"s":[{"i":[[94.254,-96.761],[-14.134,15.233],[0,0],[-14.292,13.939],[0,0],[-13.501,12.621]],"o":[[16.414,-17.448],[0,0],[15.255,-16.329],[0,0],[10.344,-8.432],[0,0]],"v":[[-95.768,98.258],[-60.973,60.165],[-19.301,13.308],[18.281,-25.004],[68.572,-69.746],[99.574,-97.67]],"c":false}]},{"t":13,"s":[{"i":[[94.07,-96.65],[-14.5,14.885],[0,0],[-13.93,14.3],[0,0],[-13.85,13.69]],"o":[[17.57,-17.9],[0,0],[15.65,-16.01],[0,0],[9.88,-8.65],[0,0]],"v":[[-95.87,97.1],[-58.85,59.365],[-16.1,16.01],[21.13,-21.95],[67.97,-67.85],[98.45,-97.84]],"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":36,"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":[111.111,111.111],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Path","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.667],"y":[0.915]},"o":{"x":[0.333],"y":[0]},"t":1,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0.509]},"t":2,"s":[12]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":7,"s":[22]},{"t":19,"s":[0]}],"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":1,"s":[100]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":7,"s":[78]},{"t":19,"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":22,"st":0,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"Path","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.262],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":1,"s":[0]},{"t":20,"s":[-90]}],"ix":10},"p":{"a":0,"k":[200,200,0],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":1,"s":[90,90,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":12,"s":[85,85,100]},{"t":19,"s":[100,100,100]}],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.333,"y":0},"t":1,"s":[{"i":[[101.36,-101.05],[0,28.67],[0,0],[-28.27,0],[0,0],[0,-28.67]],"o":[[-28.27,0],[0,0],[0,-28.67],[0,0],[28.27,0],[0,0]],"v":[[-91.82,143],[-143,91.09],[-143,-91.09],[-91.82,-143],[91.82,-143],[143,-91.09]],"c":false}]},{"i":{"x":0,"y":1},"o":{"x":0.167,"y":0.167},"t":6,"s":[{"i":[[94.254,-96.761],[-14.134,15.233],[0,0],[-14.292,13.939],[0,0],[-13.501,12.621]],"o":[[16.414,-17.448],[0,0],[15.255,-16.329],[0,0],[10.344,-8.432],[0,0]],"v":[[-95.768,98.258],[-60.973,60.165],[-19.301,13.308],[18.281,-25.004],[68.572,-69.746],[99.574,-97.67]],"c":false}]},{"t":13,"s":[{"i":[[94.07,-96.65],[-14.5,14.885],[0,0],[-13.93,14.3],[0,0],[-13.85,13.69]],"o":[[17.57,-17.9],[0,0],[15.65,-16.01],[0,0],[9.88,-8.65],[0,0]],"v":[[-95.87,97.1],[-58.85,59.365],[-16.1,16.01],[21.13,-21.95],[67.97,-67.85],[98.45,-97.84]],"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":36,"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":[111.111,111.111],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Path","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":1,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":7,"s":[22]},{"t":19,"s":[0]}],"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":1,"s":[100]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":7,"s":[78]},{"t":19,"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":22,"st":0,"bm":0}],"markers":[]} \ No newline at end of file diff --git a/TMessagesProj/src/main/res/raw/durgerking_placeholder.svg b/TMessagesProj/src/main/res/raw/durgerking_placeholder.svg new file mode 100644 index 000000000..3ab775b1c --- /dev/null +++ b/TMessagesProj/src/main/res/raw/durgerking_placeholder.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/TMessagesProj/src/main/res/raw/mute_for.json b/TMessagesProj/src/main/res/raw/mute_for.json new file mode 100644 index 000000000..1ec4f52fd --- /dev/null +++ b/TMessagesProj/src/main/res/raw/mute_for.json @@ -0,0 +1 @@ +{"v":"4.8.0","meta":{"g":"LottieFiles AE ","a":"","k":"","d":"","tc":""},"fr":60,"ip":0,"op":61,"w":512,"h":512,"nm":"Mute for","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":3,"nm":"NULL ALL","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.05,"y":0},"t":0,"s":[256,404,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.6,"y":1},"o":{"x":0.3,"y":0},"t":12,"s":[256,218,0],"to":[0,0,0],"ti":[0,0,0]},{"t":24,"s":[256,256,0]}],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.2,0.2,0.2],"y":[1,1,1]},"o":{"x":[0.05,0.05,0.05],"y":[0,0,0]},"t":0,"s":[0,0,100]},{"i":{"x":[0.7,0.7,0.7],"y":[1,1,1]},"o":{"x":[0.3,0.3,0.3],"y":[0,0,0]},"t":16,"s":[103,103,100]},{"i":{"x":[0.7,0.7,0.7],"y":[1,1,1]},"o":{"x":[0.3,0.3,0.3],"y":[0,0,0]},"t":29,"s":[96,96,100]},{"i":{"x":[0.7,0.7,0.7],"y":[1,1,1]},"o":{"x":[0.3,0.3,0.3],"y":[0,0,0]},"t":40,"s":[102,102,100]},{"i":{"x":[0.4,0.4,0.4],"y":[1,1,1]},"o":{"x":[0.3,0.3,0.3],"y":[0,0,0]},"t":51,"s":[99,99,100]},{"t":60,"s":[100,100,100]}],"ix":6}},"ao":0,"ip":1,"op":180,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"Z","parent":3,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":28,"s":[100]},{"t":35,"s":[0]}],"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":[-18.201,18.449,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":26,"s":[128.01,-129.801,0],"to":[0,0,0],"ti":[0,0,0]},{"t":35,"s":[166.212,-157.57,0]}],"ix":2},"a":{"a":0,"k":[135.35,-152.7,0],"ix":1},"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":0,"s":[137,137,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":[100,100,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":26,"s":[85,85,100]},{"t":35,"s":[40,40,100]}],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,-9.2],[1.8,-2.7],[0,0],[0,0],[0,-9.3],[7.5,0],[0,0],[2.9,2.3],[-4.9,7.2],[0,0],[0,0],[0,7.6],[-7,0.5]],"o":[[9.2,0],[0,3.3],[0,0],[0,0],[7.1,0],[0,9],[0,0],[-3.7,0],[-7,-5.4],[0,0],[0,0],[-7.1,0],[0,-7.6],[0,0]],"v":[[158.6,-205],[175.3,-188.3],[172.5,-179.1],[132.7,-127.3],[165.2,-127.3],[178.6,-114.1],[166.1,-100.4],[112.1,-100.4],[101.9,-103.9],[98.2,-126.4],[137.9,-178.1],[105.5,-178.1],[92.1,-191.5],[104.6,-204.9]],"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":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":26,"op":180,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"Body","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.514],"y":[0]},"t":0,"s":[15]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":13,"s":[-10]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":26,"s":[7]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":37,"s":[-3]},{"i":{"x":[0.4],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":48,"s":[1]},{"t":60,"s":[0]}],"ix":10},"p":{"a":0,"k":[-21.031,-93.65,0],"ix":2},"a":{"a":0,"k":[-21.031,-93.65,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.4,"y":1},"o":{"x":0.2,"y":0},"t":34,"s":[{"i":[[0,0],[0.012,-0.589],[0.466,-0.029],[0,0],[0.183,0.136],[-0.348,0.53],[0,0],[0,0],[0,0.613],[-0.466,0.029],[0,0],[0,-0.666],[0.124,-0.189],[0,0]],"o":[[0.466,0.029],[-0.012,0.583],[0,0],[-0.23,-0.018],[-0.519,-0.383],[0,0],[0,0],[-0.466,-0.029],[0,-0.607],[0,0],[0.666,0],[0,0.23],[0,0],[0,0]],"v":[[-60.566,62.774],[-59.7,63.699],[-60.566,64.625],[-64.797,64.625],[-65.428,64.395],[-65.723,62.768],[-62.169,57.941],[-65.328,57.941],[-66.194,57.016],[-65.328,56.091],[-60.896,56.091],[-59.688,57.299],[-59.876,57.941],[-63.442,62.78]],"c":true}]},{"t":60,"s":[{"i":[[0,0],[0.2,-10],[7.9,-0.5],[0,0],[3.1,2.3],[-5.9,9],[0,0],[0,0],[0,10.4],[-7.9,0.5],[0,0],[0,-11.3],[2.1,-3.2],[0,0]],"o":[[7.9,0.5],[-0.2,9.9],[0,0],[-3.9,-0.3],[-8.8,-6.5],[0,0],[0,0],[-7.9,-0.5],[0,-10.3],[0,0],[11.3,0],[0,3.9],[0,0],[0,0]],"v":[[20.9,58.7],[35.6,74.4],[20.9,90.1],[-50.9,90.1],[-61.6,86.2],[-66.6,58.6],[-6.3,-23.3],[-59.9,-23.3],[-74.6,-39],[-59.9,-54.7],[15.3,-54.7],[35.8,-34.2],[32.6,-23.3],[-27.9,58.8]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[-19.4,17.7],"ix":2},"a":{"a":0,"k":[-19.4,17.7],"ix":1},"s":{"a":1,"k":[{"t":20,"s":[0,0],"h":1},{"t":34,"s":[100,100],"h":1}],"ix":3},"r":{"a":0,"k":0,"ix":6},"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":1,"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.6,"y":1},"o":{"x":0.167,"y":0.167},"t":14,"s":[{"i":[[0,0],[0.034,-1.69],[1.335,-0.084],[0,0],[0.525,0.388],[-0.997,1.521],[0,0],[0,0],[0,1.757],[-1.335,0.084],[0,0],[0,-1.909],[0.355,-0.541],[0,0]],"o":[[1.335,0.084],[-0.034,1.673],[0,0],[-0.659,-0.051],[-1.487,-1.098],[0,0],[0,0],[-1.335,-0.084],[0,-1.74],[0,0],[1.909,0],[0,0.659],[0,0],[0,0]],"v":[[-12.59,24.628],[-10.107,27.281],[-12.59,29.934],[-24.723,29.934],[-26.531,29.275],[-27.376,24.611],[-17.187,10.772],[-26.244,10.772],[-28.728,8.119],[-26.244,5.466],[-13.537,5.466],[-10.073,8.93],[-10.613,10.772],[-20.836,24.645]],"c":true}]},{"i":{"x":0.4,"y":1},"o":{"x":0.167,"y":0.167},"t":33,"s":[{"i":[[0,0],[0.2,-10],[7.9,-0.5],[0,0],[3.1,2.3],[-5.9,9],[0,0],[0,0],[0,10.4],[-7.9,0.5],[0,0],[0,-11.3],[2.1,-3.2],[0,0]],"o":[[7.9,0.5],[-0.2,9.9],[0,0],[-3.9,-0.3],[-8.8,-6.5],[0,0],[0,0],[-7.9,-0.5],[0,-10.3],[0,0],[11.3,0],[0,3.9],[0,0],[0,0]],"v":[[20.9,58.7],[35.6,74.4],[20.9,90.1],[-50.9,90.1],[-61.6,86.2],[-66.6,58.6],[-6.3,-23.3],[-59.9,-23.3],[-74.6,-39],[-59.9,-54.7],[15.3,-54.7],[35.8,-34.2],[32.6,-23.3],[-27.9,58.8]],"c":true}]},{"t":60,"s":[{"i":[[0,0],[0.15,-6.923],[8.798,0.25],[0,0],[2.302,1.588],[-4.375,6.231],[0,0],[0,0],[0.107,8.63],[-5.857,0.346],[0,0],[0,-7.823],[1.557,-2.215],[0,0]],"o":[[5.857,0.346],[-0.148,6.854],[0,0],[-2.892,-0.208],[-6.525,-4.5],[0,0],[0,0],[-5.857,-0.346],[-0.116,-9.391],[0,0],[8.378,0],[0,2.7],[0,0],[0,0]],"v":[[16.202,42.011],[26.602,54.13],[14.702,67.5],[-40.784,67],[-48.718,64.3],[-52.675,43.191],[-12.215,-9.511],[-45.207,-10.011],[-57.607,-22.88],[-45.957,-36],[9.8,-35.75],[25.25,-19.557],[22.877,-12.011],[-17.231,41.58]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":13,"s":[-66.124,69.677],"to":[0,0],"ti":[0,0]},{"i":{"x":0.6,"y":1},"o":{"x":0.167,"y":0.167},"t":26,"s":[-1.656,3.622],"to":[0,0],"ti":[0,0]},{"t":60,"s":[131.6,-150.3]}],"ix":2},"a":{"a":0,"k":[-19.4,17.7],"ix":1},"s":{"a":1,"k":[{"t":1,"s":[0,0],"h":1},{"t":14,"s":[100,100],"h":1}],"ix":3},"r":{"a":0,"k":0,"ix":6},"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":1,"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.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":0,"s":[{"i":[[0,0],[0.2,-10],[7.9,-0.5],[0,0],[3.1,2.3],[-5.9,9],[0,0],[0,0],[0,10.4],[-7.9,0.5],[0,0],[0,-11.3],[2.1,-3.2],[0,0]],"o":[[7.9,0.5],[-0.2,9.9],[0,0],[-3.9,-0.3],[-8.8,-6.5],[0,0],[0,0],[-7.9,-0.5],[0,-10.3],[0,0],[11.3,0],[0,3.9],[0,0],[0,0]],"v":[[20.9,58.7],[35.6,74.4],[20.9,90.1],[-50.9,90.1],[-61.6,86.2],[-66.6,58.6],[-6.3,-23.3],[-59.9,-23.3],[-74.6,-39],[-59.9,-54.7],[15.3,-54.7],[35.8,-34.2],[32.6,-23.3],[-27.9,58.8]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":16,"s":[{"i":[[0,0],[0.148,-7.096],[5.801,-0.355],[0,0],[2.28,1.627],[-4.333,6.386],[0,0],[0,0],[0,7.38],[-5.801,0.355],[0,0],[0,-8.018],[1.542,-2.271],[0,0]],"o":[[5.801,0.355],[-0.147,7.025],[0,0],[-2.864,-0.213],[-6.462,-4.612],[0,0],[0,0],[-5.801,-0.355],[0,-7.309],[0,0],[8.298,0],[0,2.767],[0,0],[0,0]],"v":[[9.195,44.886],[19.437,57.181],[9,69.117],[-45.657,69.952],[-53.515,67.185],[-57.116,45.08],[-15.421,-10.242],[-52.369,-9.827],[-63.183,-22.112],[-52.176,-34.172],[3.034,-34.859],[18.1,-19.626],[15.75,-11.891],[-26.291,45.294]],"c":true}]},{"t":25,"s":[{"i":[[0,0],[0.125,-5.911],[6.158,0.167],[0,0],[1.924,1.355],[-3.657,5.32],[0,0],[0,0],[0,6.147],[-4.897,0.296],[0,0],[0,-6.679],[1.302,-1.892],[0,0]],"o":[[4.897,0.296],[-0.124,5.852],[0,0],[-2.418,-0.177],[-5.455,-3.842],[0,0],[0,0],[-4.897,-0.296],[0,-6.088],[0,0],[7.005,0],[0,2.305],[0,0],[0,0]],"v":[[4.126,39.89],[13.642,51.059],[4.008,62.091],[-44.717,61.966],[-51.35,59.661],[-54.367,40.413],[-20.426,-3.835],[-49.379,-3.843],[-58.889,-14.427],[-49.961,-25.495],[-0.549,-25.64],[12.327,-12.359],[10.344,-5.916],[-24.855,40.148]],"c":true}]}],"ix":2},"nm":"Path 3","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":0,"s":[-19.4,17.7],"to":[0,0],"ti":[0,0]},{"t":26,"s":[131.763,-130.207]}],"ix":2},"a":{"a":0,"k":[-19.4,17.7],"ix":1},"s":{"a":1,"k":[{"t":17,"s":[100,100],"h":1},{"t":26,"s":[0,0],"h":1}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":1,"cix":2,"bm":0,"ix":3,"mn":"ADBE Vector Group","hd":false},{"ind":3,"ty":"sh","ix":4,"ks":{"a":0,"k":{"i":[[12.7,12.4],[0,0],[0,2.5],[0,0],[57.3,13.9],[0,0],[15.9,0],[0,-14.1],[0,0],[0,-60],[0,0],[1.7,-1.9],[0,0],[-18,0],[0,0]],"o":[[0,0],[-1.5,-2],[0,0],[-1,-60],[0,0],[0,-14.5],[-14.8,0],[0,0],[-56.3,15.2],[0,0],[-0.2,2.5],[0,0],[-11.8,12.7],[0,0],[17.8,-0.7]],"v":[[130.1,110.1],[105.8,82.8],[103.5,75.9],[103.5,-8.2],[4.7,-128.3],[4.7,-141.5],[-22.1,-167.7],[-48.3,-141.5],[-48.3,-128.4],[-143.6,-5.9],[-143.6,76.9],[-146.5,83.6],[-170.8,110.8],[-151.8,144.4],[112.6,144.4]],"c":true},"ix":2},"nm":"Path 2","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":"Group 1","np":5,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":1,"op":180,"st":0,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"Bottom","parent":3,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.7,"y":1},"o":{"x":0.514,"y":0},"t":2,"s":[-58.416,164.067,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.7,"y":1},"o":{"x":0.3,"y":0},"t":16,"s":[9.925,165.08,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.7,"y":1},"o":{"x":0.3,"y":0},"t":29,"s":[-38.506,164.725,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.7,"y":1},"o":{"x":0.3,"y":0},"t":40,"s":[-6.869,164.433,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.4,"y":1},"o":{"x":0.3,"y":0},"t":51,"s":[-26.011,164.7,0],"to":[0,0,0],"ti":[0,0,0]},{"t":60,"s":[-20.011,164.7,0]}],"ix":2},"a":{"a":0,"k":[-20.011,164.7,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[22.7,-0.3],[-0.8,19.1]],"o":[[0,20.2],[-21.7,0.2],[0,0]],"v":[[21.2,164.7],[-20,202.8],[-61.2,164.7]],"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":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":1,"op":180,"st":0,"bm":0}],"markers":[]} \ No newline at end of file diff --git a/TMessagesProj/src/main/res/raw/sound_download.json b/TMessagesProj/src/main/res/raw/sound_download.json new file mode 100644 index 000000000..d323a10f4 --- /dev/null +++ b/TMessagesProj/src/main/res/raw/sound_download.json @@ -0,0 +1 @@ +{"v":"4.8.0","meta":{"g":"LottieFiles AE ","a":"","k":"","d":"","tc":""},"fr":60,"ip":0,"op":66,"w":512,"h":512,"nm":"Sound Download 2","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":3,"nm":"NULL ALL","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.764],"y":[1]},"o":{"x":[0.683],"y":[0]},"t":4,"s":[-5]},{"i":{"x":[0.44],"y":[1]},"o":{"x":[0.4],"y":[0]},"t":15,"s":[2]},{"i":{"x":[0.6],"y":[1]},"o":{"x":[0.576],"y":[0]},"t":23,"s":[-1]},{"i":{"x":[0.517],"y":[1]},"o":{"x":[0.4],"y":[0]},"t":32,"s":[2]},{"i":{"x":[0.6],"y":[1]},"o":{"x":[0.545],"y":[0]},"t":39,"s":[-1]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":47,"s":[2]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":56,"s":[-1]},{"t":65,"s":[0]}],"ix":10},"p":{"a":1,"k":[{"i":{"x":0.59,"y":1},"o":{"x":0.236,"y":0},"t":0,"s":[256,416,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.7,"y":1},"o":{"x":0.4,"y":0},"t":11,"s":[262,232,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.6,"y":1},"o":{"x":0.3,"y":0},"t":19,"s":[256,284,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.7,"y":1},"o":{"x":0.4,"y":0},"t":28,"s":[256,256,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.6,"y":1},"o":{"x":0.3,"y":0},"t":34,"s":[256,284,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.7,"y":1},"o":{"x":0.3,"y":0},"t":43,"s":[256,236,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.7,"y":1},"o":{"x":0.3,"y":0},"t":52,"s":[256,300,0],"to":[0,0,0],"ti":[0,0,0]},{"t":63,"s":[256,256,0]}],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.5,0.5,0.5],"y":[1,1,1]},"o":{"x":[0.2,0.2,0.2],"y":[0,0,0]},"t":0,"s":[60,10,100]},{"i":{"x":[0.7,0.7,0.7],"y":[1,1,1]},"o":{"x":[0.4,0.4,0.4],"y":[0,0,0]},"t":11,"s":[90,110,100]},{"i":{"x":[0.6,0.6,0.6],"y":[1,1,1]},"o":{"x":[0.3,0.3,0.3],"y":[0,0,0]},"t":19,"s":[105,95,100]},{"i":{"x":[0.7,0.7,0.7],"y":[1,1,1]},"o":{"x":[0.4,0.4,0.4],"y":[0,0,0]},"t":28,"s":[95,105,100]},{"i":{"x":[0.6,0.6,0.6],"y":[1,1,1]},"o":{"x":[0.3,0.3,0.3],"y":[0,0,0]},"t":34,"s":[105,95,100]},{"i":{"x":[0.7,0.7,0.7],"y":[1,1,1]},"o":{"x":[0.3,0.3,0.3],"y":[0,0,0]},"t":43,"s":[95,105,100]},{"i":{"x":[0.7,0.7,0.7],"y":[1,1,1]},"o":{"x":[0.3,0.3,0.3],"y":[0,0,0]},"t":52,"s":[105,95,100]},{"t":63,"s":[100,100,100]}],"ix":6}},"ao":0,"ip":1,"op":179,"st":-1,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"Arrow 3","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.8,"y":1},"o":{"x":0.7,"y":0},"t":36,"s":[395,27.333,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.6,"y":1},"o":{"x":0.2,"y":0},"t":51,"s":[395,219.333,0],"to":[0,0,0],"ti":[0,0,0]},{"t":62,"s":[395,141.333,0]}],"ix":2},"a":{"a":0,"k":[139,-114.667,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":36,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[117,-105.5],[139.054,-69],[161,-105.5]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":51,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[62,-80],[139.188,-36.333],[216,-80]],"c":false}]},{"t":62,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[70.667,-86.5],[139.167,-36.333],[207.333,-86.5]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":0,"k":100,"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":40,"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":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.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":36,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[139.038,-110],[139.02,-69.849]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":51,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[139.125,-172],[139.071,-37.349]],"c":false}]},{"t":62,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[139.063,-193],[139.063,-37.5]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":0,"k":100,"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":40,"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 2","np":3,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":36,"op":213,"st":33,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"Arrow 2","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.744,"y":0.482},"o":{"x":0.477,"y":0},"t":16,"s":[395,41.333,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.615,"y":0.728},"o":{"x":0.312,"y":0.353},"t":28,"s":[391,145.474,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.581,"y":1},"o":{"x":0.265,"y":0.596},"t":34,"s":[401.815,238.274,0],"to":[0,0,0],"ti":[0,0,0]},{"t":42,"s":[399,277.333,0]}],"ix":2},"a":{"a":0,"k":[139,-114.667,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":16,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[103,-112.817],[139.088,-93],[175,-112.817]],"c":false}]},{"i":{"x":0.39,"y":1},"o":{"x":0.167,"y":0.167},"t":28,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[70.667,-86.5],[139.167,-36.333],[207.333,-86.5]],"c":false}]},{"t":38,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[139,-86.5],[139,-51.833],[139,-86.5]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":0,"k":100,"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":36,"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":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.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":16,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[139.066,-130],[139.033,-93.461]],"c":false}]},{"i":{"x":0.39,"y":1},"o":{"x":0.167,"y":0.167},"t":28,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[139.125,-167],[139.063,-37.5]],"c":false}]},{"t":38,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[139.5,-102],[139,-53]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":0,"k":100,"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":36,"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 2","np":3,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":16,"op":38,"st":-1,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"Arrow 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.746,"y":0.458},"o":{"x":0.463,"y":0},"t":4,"s":[395,105.333,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.489,"y":1},"o":{"x":0.267,"y":0.449},"t":12,"s":[395,167.999,0],"to":[0,0,0],"ti":[0,0,0]},{"t":23,"s":[401,277.333,0]}],"ix":2},"a":{"a":0,"k":[139,-114.667,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":4,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[93.085,-94.664],[139.112,-63],[184.915,-94.664]],"c":false}]},{"i":{"x":0.39,"y":1},"o":{"x":0.167,"y":0.167},"t":12,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[70.667,-86.5],[139.167,-36.333],[207.333,-86.5]],"c":false}]},{"t":20,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[139.25,-103],[139,-51.833],[139.25,-103]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":0,"k":100,"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":36,"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":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.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":4,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[139.084,-137],[139.042,-63.736]],"c":false}]},{"i":{"x":0.39,"y":1},"o":{"x":0.167,"y":0.167},"t":12,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[139.125,-167],[139.063,-37.5]],"c":false}]},{"t":20,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[139.5,-103.5],[139,-53]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":0,"k":100,"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":36,"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 2","np":3,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":3,"op":20,"st":1,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":"R","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[88.174,82.369,0],"ix":2},"a":{"a":0,"k":[88.174,82.369,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.566,"y":1},"o":{"x":0.61,"y":0},"t":0,"s":[{"i":[[-6.917,3.879],[0,-0.716],[39.672,0],[0,30.227],[-39.672,0],[-10.43,-4.012],[0,0],[-6.028,0]],"o":[[0,0],[0,30.227],[-39.672,0],[0,-30.227],[12.077,0],[0,0],[5.313,2.033],[8.494,0]],"v":[[159.904,-49.445],[160.007,103.453],[84.753,158.183],[16.341,103.453],[84.753,48.723],[118.958,55.005],[119.406,-46.501],[136.514,-43.354]],"c":true}]},{"i":{"x":0.4,"y":1},"o":{"x":0.3,"y":0},"t":14,"s":[{"i":[[-6.917,3.879],[0,-0.716],[39.672,0],[0,30.227],[-39.672,0],[-10.43,-4.012],[0,0],[-6.028,0]],"o":[[0,0],[0,30.227],[-39.672,0],[0,-30.227],[12.077,0],[0,0],[5.313,2.033],[8.494,0]],"v":[[162.959,25.276],[160.007,103.453],[84.753,158.183],[16.341,103.453],[84.753,48.723],[118.958,55.005],[122.462,28.22],[139.57,31.366]],"c":true}]},{"i":{"x":0.287,"y":1},"o":{"x":0.451,"y":0},"t":22,"s":[{"i":[[-6.917,3.879],[0,-0.716],[39.672,0],[0,30.227],[-39.672,0],[-10.43,-4.012],[0,0],[-6.028,0]],"o":[[0,0],[0,30.227],[-39.672,0],[0,-30.226],[12.077,0],[0,0],[5.313,2.033],[8.494,0]],"v":[[159.305,-51.745],[160.007,103.453],[84.753,158.183],[16.341,103.453],[84.753,48.723],[118.958,55.005],[118.808,-48.801],[135.916,-45.654]],"c":true}]},{"i":{"x":0.4,"y":1},"o":{"x":0.3,"y":0},"t":34,"s":[{"i":[[-6.917,3.879],[0,-0.716],[39.672,0],[0,30.227],[-39.672,0],[-10.43,-4.012],[0,0],[-6.028,0]],"o":[[0,0],[0,30.227],[-39.672,0],[0,-30.227],[12.077,0],[0,0],[5.313,2.033],[8.494,0]],"v":[[159.027,13.718],[160.007,103.453],[84.753,158.183],[16.341,103.453],[84.753,48.723],[118.958,55.005],[118.529,16.663],[135.637,19.809]],"c":true}]},{"i":{"x":0.8,"y":1},"o":{"x":0.599,"y":0},"t":42,"s":[{"i":[[-6.917,3.879],[0,-0.716],[39.672,0],[0,30.227],[-39.672,0],[-10.43,-4.012],[0,0],[-6.028,0]],"o":[[0,0],[0,30.227],[-39.672,0],[0,-30.226],[12.077,0],[0,0],[5.313,2.033],[8.494,0]],"v":[[159.611,-74.745],[160.007,103.453],[84.753,158.183],[16.341,103.453],[84.753,48.723],[118.958,55.005],[119.114,-71.801],[136.222,-68.654]],"c":true}]},{"i":{"x":0.4,"y":1},"o":{"x":0.2,"y":0},"t":51,"s":[{"i":[[-4.316,1.274],[0,-0.716],[39.672,0],[0,30.227],[-39.672,0],[-3.48,-4.272],[0,0],[-6.028,0]],"o":[[0,0],[0,30.227],[-39.672,0],[0,-30.226],[12.077,0],[0,0],[5.313,2.033],[8.494,0]],"v":[[160.128,43.818],[160.007,103.453],[84.753,158.183],[16.341,103.453],[84.753,48.723],[111.637,55.698],[111.65,43.878],[135.309,47.714]],"c":true}]},{"t":62,"s":[{"i":[[-6.917,3.879],[0,-0.716],[39.672,0],[0,30.227],[-39.672,0],[-10.43,-4.012],[0,0],[-6.028,0]],"o":[[0,0],[0,30.227],[-39.672,0],[0,-30.227],[12.077,0],[0,0],[5.313,2.033],[8.494,0]],"v":[[159.452,6.555],[160.007,103.453],[84.753,158.183],[16.341,103.453],[84.753,48.723],[118.958,55.005],[118.955,9.499],[136.063,12.646]],"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":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":1,"op":181,"st":1,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":"L","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-58.912,2.378,0],"ix":2},"a":{"a":0,"k":[-58.912,2.378,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.82,"y":1},"o":{"x":0.279,"y":0},"t":0,"s":[{"i":[[0,0],[0,0],[0,0],[0.171,-0.721],[0,-0.687],[39.672,0],[0,30.227],[-39.672,0],[-9.268,-3.322],[0,0],[-19.193,4.657]],"o":[[0,0],[0,0],[-0.752,0.152],[0,0],[0,30.227],[-39.672,0],[0,-30.227],[10.92,0],[0,0],[0,-19.896],[0,0]],"v":[[48.175,-182.632],[48.165,-140.754],[-61.03,-115.682],[-62.53,-114.233],[-62.334,137.659],[-134.167,192.389],[-206,137.659],[-134.167,82.929],[-103.628,88.107],[-103.629,-113.786],[-70.799,-155.552]],"c":true}]},{"i":{"x":0.458,"y":1},"o":{"x":0.3,"y":0},"t":14,"s":[{"i":[[0,0],[0,0],[0,0],[0.171,-0.721],[0,-0.687],[39.672,0],[0,30.227],[-39.672,0],[-9.268,-3.322],[0,0],[-19.193,4.657]],"o":[[0,0],[0,0],[-0.752,0.152],[0,0],[0,30.227],[-39.672,0],[0,-30.227],[10.92,0],[0,0],[0,-19.896],[0,0]],"v":[[94.175,-189.632],[94.165,-147.754],[-61.03,-115.682],[-62.53,-114.233],[-62.334,137.659],[-134.167,192.389],[-206,137.659],[-134.167,82.929],[-103.628,88.107],[-103.629,-113.786],[-70.799,-155.552]],"c":true}]},{"i":{"x":0.837,"y":1},"o":{"x":0.66,"y":0},"t":22,"s":[{"i":[[0,0],[0,0],[0,0],[0.171,-0.721],[0,-0.687],[39.672,0],[0,30.227],[-39.672,0],[-9.268,-3.322],[0,0],[-19.193,4.657]],"o":[[0,0],[0,0],[-0.752,0.152],[0,0],[0,30.227],[-39.672,0],[0,-30.227],[10.92,0],[0,0],[0,-19.896],[0,0]],"v":[[62.175,-183.632],[62.165,-141.754],[-61.03,-115.682],[-62.53,-114.233],[-62.334,137.659],[-134.167,192.389],[-206,137.659],[-134.167,82.929],[-103.628,88.107],[-103.629,-113.786],[-70.799,-155.552]],"c":true}]},{"i":{"x":0.82,"y":1},"o":{"x":0.3,"y":0},"t":34,"s":[{"i":[[0,0],[0,0],[0,0],[0.171,-0.721],[0,-0.687],[39.672,0],[0,30.227],[-39.672,0],[-9.268,-3.322],[0,0],[-19.193,4.657]],"o":[[0,0],[0,0],[-0.752,0.152],[0,0],[0,30.227],[-39.672,0],[0,-30.227],[10.92,0],[0,0],[0,-19.896],[0,0]],"v":[[90.175,-190.632],[90.165,-148.754],[-61.03,-115.682],[-62.53,-114.233],[-62.334,137.659],[-134.167,192.389],[-206,137.659],[-134.167,82.929],[-103.628,88.107],[-103.629,-113.786],[-70.799,-155.552]],"c":true}]},{"i":{"x":0.8,"y":1},"o":{"x":0.66,"y":0},"t":42,"s":[{"i":[[0,0],[0,0],[0,0],[0.171,-0.721],[0,-0.687],[39.672,0],[0,30.227],[-39.672,0],[-9.268,-3.322],[0,0],[-19.193,4.657]],"o":[[0,0],[0,0],[-0.752,0.152],[0,0],[0,30.227],[-39.672,0],[0,-30.227],[10.92,0],[0,0],[0,-19.896],[0,0]],"v":[[63.175,-182.632],[63.165,-140.754],[-61.03,-115.682],[-62.53,-114.233],[-62.334,137.659],[-134.167,192.389],[-206,137.659],[-134.167,82.929],[-103.628,88.107],[-103.629,-113.786],[-70.799,-155.552]],"c":true}]},{"i":{"x":0.4,"y":1},"o":{"x":0.2,"y":0},"t":51,"s":[{"i":[[0,0],[0,0],[0,0],[0.171,-0.721],[0,-0.687],[39.672,0],[0,30.227],[-39.672,0],[-9.268,-3.322],[0,0],[-19.193,4.657]],"o":[[0,0],[0,0],[-0.752,0.152],[0,0],[0,30.227],[-39.672,0],[0,-30.227],[10.92,0],[0,0],[0,-19.896],[0,0]],"v":[[88.175,-187.632],[88.165,-145.754],[-61.03,-115.682],[-62.53,-114.233],[-62.334,137.659],[-134.167,192.389],[-206,137.659],[-134.167,82.929],[-103.628,88.107],[-103.629,-113.786],[-70.799,-155.552]],"c":true}]},{"t":62,"s":[{"i":[[0,0],[0,0],[0,0],[0.171,-0.721],[0,-0.687],[39.672,0],[0,30.227],[-39.672,0],[-9.268,-3.322],[0,0],[-19.193,4.657]],"o":[[0,0],[0,0],[-0.752,0.152],[0,0],[0,30.227],[-39.672,0],[0,-30.227],[10.92,0],[0,0],[0,-19.896],[0,0]],"v":[[88.175,-187.632],[88.165,-145.754],[-61.03,-115.682],[-62.53,-114.233],[-62.334,137.659],[-134.167,192.389],[-206,137.659],[-134.167,82.929],[-103.628,88.107],[-103.629,-113.786],[-70.799,-155.552]],"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":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":1,"op":179,"st":-1,"bm":0}],"markers":[]} \ No newline at end of file diff --git a/TMessagesProj/src/main/res/raw/sound_off.json b/TMessagesProj/src/main/res/raw/sound_off.json new file mode 100644 index 000000000..cca176358 --- /dev/null +++ b/TMessagesProj/src/main/res/raw/sound_off.json @@ -0,0 +1 @@ +{"v":"4.8.0","meta":{"g":"LottieFiles AE ","a":"","k":"","d":"","tc":""},"fr":60,"ip":0,"op":61,"w":512,"h":512,"nm":"Sound Off","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":3,"nm":"NULL ALL","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.507],"y":[1.085]},"o":{"x":[0.595],"y":[0]},"t":0,"s":[28]},{"i":{"x":[0.95],"y":[1]},"o":{"x":[0.7],"y":[0.283]},"t":14,"s":[-7]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":30,"s":[10]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":36,"s":[-5]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":41,"s":[5]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":46,"s":[-3]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":52,"s":[1]},{"t":60,"s":[0]}],"ix":10},"p":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.4,"y":0},"t":0,"s":[326,365.957,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.8,"y":1},"o":{"x":0.6,"y":0},"t":20,"s":[247.971,230.719,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.6,"y":1},"o":{"x":0.3,"y":0},"t":32,"s":[283.5,285.957,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.6,"y":1},"o":{"x":0.3,"y":0},"t":44,"s":[276,239.957,0],"to":[0,0,0],"ti":[0,0,0]},{"t":60,"s":[276,255.957,0]}],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.2,0.2,0.2],"y":[1,1,1]},"o":{"x":[0.1,0.1,0.1],"y":[0,0,0]},"t":0,"s":[20,0,100]},{"i":{"x":[0.95,0.95,0.95],"y":[1,1,1]},"o":{"x":[0.8,0.8,0.8],"y":[0,0,0]},"t":18,"s":[90,104,100]},{"i":{"x":[0.7,0.7,0.7],"y":[1,1,1]},"o":{"x":[0.3,0.3,0.3],"y":[0,0,0]},"t":30,"s":[90,75,100]},{"i":{"x":[0.7,0.7,0.7],"y":[1,1,1]},"o":{"x":[0.3,0.3,0.3],"y":[0,0,0]},"t":37,"s":[105,105,100]},{"i":{"x":[0.7,0.7,0.7],"y":[1,1,1]},"o":{"x":[0.3,0.3,0.3],"y":[0,0,0]},"t":42,"s":[97,97,100]},{"t":48,"s":[100,100,100]}],"ix":6}},"ao":0,"ip":1,"op":180,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"Line","parent":4,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[6.25,1.35,0],"ix":2},"a":{"a":0,"k":[6.25,1.35,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.6,"y":1},"o":{"x":0.8,"y":0},"t":19,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-194.619,-190.263],[168.481,158.037]],"c":false}]},{"i":{"x":0.7,"y":1},"o":{"x":0.3,"y":0},"t":32,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-145.787,-140.476],[207.235,196.36]],"c":false}]},{"i":{"x":0.7,"y":1},"o":{"x":0.3,"y":0},"t":37,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-185.469,-181.453],[165.552,155.752]],"c":false}]},{"t":43,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-175.3,-172.8],[187.8,175.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":34,"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},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.6],"y":[1]},"o":{"x":[0.8],"y":[0]},"t":19,"s":[0]},{"t":30,"s":[100]}],"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.6],"y":[1]},"o":{"x":[0.8],"y":[0]},"t":19,"s":[0]},{"t":30,"s":[3]}],"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":21,"op":180,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"Top Top","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[38.282,-48.297,0],"ix":2},"a":{"a":0,"k":[38.282,-48.297,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.1,"y":0},"t":3,"s":[{"i":[[0,0.1],[0.8,0],[0,0],[0,0],[-6.4,1.5],[0,0]],"o":[[-0.2,-0.9],[0,0],[0,0],[-1.266,-33.912],[0,0],[23.1,-4.8]],"v":[[184.317,-78.65],[182.517,-80.15],[-106.368,-35.177],[-147.331,-33.019],[-115.272,-76.324],[174.017,-120.15]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.3,"y":0},"t":18,"s":[{"i":[[0,0.1],[0.8,0],[0,0],[0,0],[-6.4,1.5],[0,0]],"o":[[-0.2,-0.9],[0,0],[0,0],[-1.266,-33.912],[0,0],[23.1,-4.8]],"v":[[120.8,-149.7],[119,-151.2],[-59.396,-113.953],[-100.359,-111.795],[-68.3,-155.1],[110.5,-191.2]],"c":true}]},{"t":19,"s":[{"i":[[0,0.1],[0.8,0],[0,0],[0,0],[-6.4,1.5],[0,0]],"o":[[-0.2,-0.9],[0,0],[0,0],[-1.266,-33.912],[0,0],[23.1,-4.8]],"v":[[120.8,-149.7],[119,-151.2],[-59.396,-113.953],[-100.359,-111.795],[-68.3,-155.1],[110.5,-191.2]],"c":true}],"h":1},{"t":25,"s":[{"i":[[0,0.1],[0.8,0],[0,0],[0,0],[-6.4,1.5],[0,0]],"o":[[-0.2,-0.9],[0,0],[0,0],[4.8,-4],[0,0],[23.1,-4.8]],"v":[[120.8,-149.7],[119,-151.2],[-54.3,-116.3],[-85.3,-146.7],[-68.3,-155.1],[110.5,-191.2]],"c":true}],"h":1}],"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":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":1,"op":180,"st":0,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"Top Bottom","parent":3,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[38.282,-48.297,0],"ix":2},"a":{"a":0,"k":[38.282,-48.297,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.1,"y":0},"t":3,"s":[{"i":[[-4.3,-19.24],[1.331,-8.002],[12.42,-8.541],[5.324,5.994],[0,0],[0,0.083],[0.8,0],[0,0]],"o":[[1.5,6.552],[-0.957,5.754],[-6.18,-7.561],[26.409,-1.342],[0,0],[-0.2,-0.746],[0,0],[28.171,-4.938]],"v":[[219.954,-90.552],[219.845,104.803],[203.836,131.006],[138.861,57.639],[178.453,62.603],[180.6,-78.452],[178.8,-79.696],[169.299,-118.145]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.3,"y":0},"t":18,"s":[{"i":[[-4.3,-23.2],[1.331,-9.649],[12.42,-10.298],[5.324,7.227],[0,0],[0,0.1],[0.8,0],[0,0]],"o":[[1.5,7.9],[-0.957,6.939],[-6.18,-9.117],[26.409,-1.618],[0,0],[-0.2,-0.9],[0,0],[23.1,-4.8]],"v":[[160.9,-157.8],[162.191,105.885],[146.183,137.481],[81.208,49.015],[120.8,55],[120.8,-149.7],[119,-151.2],[110.5,-191.2]],"c":true}]},{"t":19,"s":[{"i":[[-4.3,-23.2],[1.331,-9.649],[12.42,-10.298],[5.324,7.227],[0,0],[0,0.1],[0.8,0],[0,0]],"o":[[1.5,7.9],[-0.957,6.939],[-6.18,-9.117],[26.409,-1.618],[0,0],[-0.2,-0.9],[0,0],[23.1,-4.8]],"v":[[160.9,-157.8],[162.191,105.885],[146.183,137.481],[81.208,49.015],[120.8,55],[120.8,-149.7],[119,-151.2],[110.5,-191.2]],"c":true}],"h":1},{"t":28,"s":[{"i":[[-4.3,-23.2],[0,0],[0,0],[0,0],[0,0],[0,0.1],[0.8,0],[0,0]],"o":[[1.5,7.9],[0,0],[0,0],[0,0],[0,0],[-0.2,-0.9],[0,0],[23.1,-4.8]],"v":[[160.9,-157.8],[161.7,95.5],[160.755,94.564],[121.112,55.309],[120.8,55],[120.8,-149.7],[119,-151.2],[110.5,-191.2]],"c":true}],"h":1}],"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":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":1,"op":180,"st":0,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":"Bottom R","parent":4,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[63.15,116.65,0],"ix":2},"a":{"a":0,"k":[63.15,116.65,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.1,"y":0},"t":3,"s":[{"i":[[-58.795,2.85],[0,0],[7.433,0],[0,26.189]],"o":[[0,0],[-20.002,19.246],[-41.46,0],[0,-8.499]],"v":[[140.985,58.827],[207.76,129.436],[143.556,152.205],[72.886,104.596]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.3,"y":0},"t":18,"s":[{"i":[[-56.158,3.287],[0,0],[7.1,0],[0,30.2]],"o":[[0,0],[-17.583,17.964],[-39.6,0],[0,-9.8]],"v":[[82.619,48.668],[146.381,136.663],[86.7,157.5],[19.2,102.6]],"c":true}]},{"t":19,"s":[{"i":[[-56.158,3.287],[0,0],[7.1,0],[0,30.2]],"o":[[0,0],[-17.583,17.964],[-39.6,0],[0,-9.8]],"v":[[82.619,48.668],[146.381,136.663],[86.7,157.5],[19.2,102.6]],"c":true}],"h":1},{"t":28,"s":[{"i":[[-6,8],[0,0],[7.1,0],[0,30.2]],"o":[[0,0],[-6.5,1.5],[-39.6,0],[0,-9.8]],"v":[[27.7,75.8],[107.1,155.3],[86.7,157.5],[19.2,102.6]],"c":true}],"h":1}],"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":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":1,"op":180,"st":0,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":"Bottom L","parent":4,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-131.6,73.1,0],"ix":2},"a":{"a":0,"k":[-131.6,73.1,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.1,"y":0},"t":3,"s":[{"i":[[0,0],[0,0],[0,-1.484],[39.5,0],[0,24.9],[-39.5,0],[-9.2,-2.721]],"o":[[0,0],[0,0],[0,24.818],[-39.5,0],[0,-24.818],[10.9,0],[0,0]],"v":[[-149.241,-39.902],[-107.881,-40.686],[-110.291,145.989],[-181.891,191.007],[-253.491,145.989],[-181.891,100.97],[-151.491,105.258]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.3,"y":0},"t":18,"s":[{"i":[[0,0],[0,0],[0,-1.8],[39.5,0],[0,30.2],[-39.5,0],[-9.2,-3.3]],"o":[[0,0],[0,0],[0,30.1],[-39.5,0],[0,-30.1],[10.9,0],[0,0]],"v":[[-100.461,-113.925],[-59.1,-114.876],[-60,137],[-131.6,191.599],[-203.2,137],[-131.6,82.4],[-101.2,87.6]],"c":true}]},{"t":19,"s":[{"i":[[0,0],[0,0],[0,-1.8],[39.5,0],[0,30.2],[-39.5,0],[-9.2,-3.3]],"o":[[0,0],[0,0],[0,30.1],[-39.5,0],[0,-30.1],[10.9,0],[0,0]],"v":[[-100.461,-113.925],[-59.1,-114.876],[-60,137],[-131.6,191.599],[-203.2,137],[-131.6,82.4],[-101.2,87.6]],"c":true}],"h":1},{"t":25,"s":[{"i":[[0,0],[0,0],[0,-1.8],[39.5,0],[0,30.2],[-39.5,0],[-9.2,-3.3]],"o":[[0,0],[0,0],[0,30.1],[-39.5,0],[0,-30.1],[10.9,0],[0,0]],"v":[[-101.1,-45.4],[-60.1,-5.9],[-60,137],[-131.6,191.6],[-203.2,137],[-131.6,82.4],[-101.2,87.6]],"c":true}],"h":1}],"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":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":1,"op":180,"st":0,"bm":0}],"markers":[]} \ No newline at end of file diff --git a/TMessagesProj/src/main/res/raw/sound_on.json b/TMessagesProj/src/main/res/raw/sound_on.json new file mode 100644 index 000000000..f5a9ccb5a --- /dev/null +++ b/TMessagesProj/src/main/res/raw/sound_on.json @@ -0,0 +1 @@ +{"v":"4.8.0","meta":{"g":"LottieFiles AE ","a":"","k":"","d":"","tc":""},"fr":60,"ip":0,"op":61,"w":512,"h":512,"nm":"Sound On","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":3,"nm":"NULL ALL","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.3],"y":[0.919]},"o":{"x":[0.433],"y":[0]},"t":0,"s":[-20]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.425],"y":[-0.114]},"t":12,"s":[12]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":26,"s":[-4]},{"i":{"x":[0.6],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":39,"s":[4]},{"t":57,"s":[0]}],"ix":10},"p":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.3,"y":0},"t":0,"s":[196,376,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.71,"y":1},"o":{"x":0.4,"y":0},"t":18,"s":[256,220,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.71,"y":1},"o":{"x":0.29,"y":0},"t":31,"s":[256,276,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.6,"y":1},"o":{"x":0.29,"y":0},"t":44,"s":[256,232,0],"to":[0,0,0],"ti":[0,0,0]},{"t":60,"s":[256,256,0]}],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.3,0.3,0.3],"y":[1,1,1]},"o":{"x":[0.3,0.3,0.3],"y":[0,0,0]},"t":0,"s":[20,0,100]},{"i":{"x":[0.71,0.71,0.71],"y":[1,1,1]},"o":{"x":[0.4,0.4,0.4],"y":[0,0,0]},"t":16,"s":[90,107,100]},{"i":{"x":[0.71,0.71,0.71],"y":[1,1,1]},"o":{"x":[0.29,0.29,0.29],"y":[0,0,0]},"t":29,"s":[105,95,100]},{"i":{"x":[0.6,0.6,0.6],"y":[1,1,1]},"o":{"x":[0.29,0.29,0.29],"y":[0,0,0]},"t":42,"s":[95,105,100]},{"t":58,"s":[100,100,100]}],"ix":6}},"ao":0,"ip":0,"op":180,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"Note ON L","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-0.053,-0.397,0],"ix":2},"a":{"a":0,"k":[-0.053,-0.397,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.4,"y":1},"o":{"x":0.6,"y":0},"t":2,"s":[{"i":[[-4.8,-23.2],[0,0.2],[0.8,0],[0,0],[0.2,-0.7],[0,-0.7],[39.7,0],[0,30.1],[-39.7,0],[-9.2,-3.4],[0,0],[-19.2,4.6],[0,0]],"o":[[0.5,11.8],[-0.425,-2.675],[0,0],[-0.8,0.2],[0,0],[0,30.1],[-39.7,0],[0,-30.1],[10.9,0],[0,0],[0,-19.8],[0,0],[23.3,-4.8]],"v":[[203.232,-154.081],[163.782,-144.356],[161.232,-147.481],[-73.733,-106.013],[-75.233,-104.613],[-74.98,161.798],[-146.78,216.298],[-218.68,161.798],[-146.88,107.298],[-116.38,112.498],[-116.433,-104.113],[-83.633,-145.713],[152.532,-187.481]],"c":true}]},{"i":{"x":0.4,"y":1},"o":{"x":0.6,"y":0},"t":12,"s":[{"i":[[-4.8,-23.2],[0,0.2],[0.8,0],[0,0],[0.2,-0.7],[0,-0.7],[39.7,0],[0,30.1],[-39.7,0],[-9.2,-3.4],[0,0],[-19.2,4.6],[0,0]],"o":[[0.5,11.8],[-0.425,-2.675],[0,0],[-0.8,0.2],[0,0],[0,30.1],[-39.7,0],[0,-30.1],[10.9,0],[0,0],[0,-19.8],[0,0],[23.3,-4.8]],"v":[[183.101,-147.811],[143.651,-138.086],[141.101,-141.211],[-35.959,-125.135],[-37.459,-123.735],[-39.2,55.8],[-111,110.3],[-182.9,55.8],[-111.1,1.3],[-80.6,6.5],[-78.659,-123.235],[-45.859,-164.835],[132.401,-181.211]],"c":true}]},{"i":{"x":0.4,"y":1},"o":{"x":0.6,"y":0},"t":25,"s":[{"i":[[-4.8,-23.2],[0,0.2],[0.8,0],[0,0],[0.2,-0.7],[0,-0.7],[39.7,0],[0,30.1],[-39.7,0],[-9.2,-3.4],[0,0],[-19.2,4.6],[0,0]],"o":[[0.5,11.8],[-0.425,-2.675],[0,0],[-0.8,0.2],[0,0],[0,30.1],[-39.7,0],[0,-30.1],[10.9,0],[0,0],[0,-19.8],[0,0],[23.3,-4.8]],"v":[[181.854,-163.321],[142.404,-153.596],[139.854,-156.721],[-38.353,-110.011],[-39.853,-108.611],[-39.6,157.8],[-111.4,212.3],[-183.3,157.8],[-111.5,103.3],[-81,108.5],[-81.053,-108.111],[-48.253,-149.711],[131.154,-196.721]],"c":true}]},{"i":{"x":0.4,"y":1},"o":{"x":0.6,"y":0},"t":38,"s":[{"i":[[-4.8,-23.2],[0,0.2],[0.8,0],[0,0],[0.2,-0.7],[0,-0.7],[39.7,0],[0,30.1],[-39.7,0],[-9.2,-3.4],[0,0],[-19.2,4.6],[0,0]],"o":[[0.5,11.8],[-0.425,-2.675],[0,0],[-0.8,0.2],[0,0],[0,30.1],[-39.7,0],[0,-30.1],[10.9,0],[0,0],[0,-19.8],[0,0],[23.3,-4.8]],"v":[[183.101,-147.811],[143.651,-138.086],[141.101,-141.211],[-36.108,-128.131],[-37.608,-126.731],[-39.2,55.8],[-111,110.3],[-182.9,55.8],[-111.1,1.3],[-80.6,6.5],[-78.808,-126.231],[-46.008,-167.831],[132.401,-181.211]],"c":true}]},{"t":60,"s":[{"i":[[-4.8,-23.2],[0,0.2],[0.8,0],[0,0],[0.2,-0.7],[0,-0.7],[39.7,0],[0,30.1],[-39.7,0],[-9.2,-3.4],[0,0],[-19.2,4.6],[0,0]],"o":[[0.5,11.8],[-0.425,-2.675],[0,0],[-0.8,0.2],[0,0],[0,30.1],[-39.7,0],[0,-30.1],[10.9,0],[0,0],[0,-19.8],[0,0],[23.3,-4.8]],"v":[[182,-157.8],[142.55,-148.075],[140,-151.2],[-38,-115.5],[-39.5,-114.1],[-39.3,136.8],[-111.1,191.3],[-183,136.8],[-111.2,82.3],[-80.7,87.5],[-80.7,-113.6],[-47.9,-155.2],[131.3,-191.2]],"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":"Path","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":180,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"Note ON R","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-0.053,-0.397,0],"ix":2},"a":{"a":0,"k":[-0.053,-0.397,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.4,"y":1},"o":{"x":0.6,"y":0},"t":2,"s":[{"i":[[-22.75,1.55],[0,-0.7],[39.6,0],[0,30.1],[-39.7,0],[-10.4,-4],[0,0.2]],"o":[[1.3,6.5],[0,30.1],[-39.6,0],[0,-30.1],[12.1,0],[0,0],[-0.2,-0.9]],"v":[[205.461,-155.207],[206.207,78.814],[131.007,133.314],[62.607,78.814],[131.007,24.314],[165.207,30.614],[165.261,-147.107]],"c":true}]},{"i":{"x":0.4,"y":1},"o":{"x":0.6,"y":0},"t":12,"s":[{"i":[[-22.75,1.55],[0,-0.7],[39.6,0],[0,30.1],[-39.7,0],[-10.4,-4],[0,0.2]],"o":[[1.3,6.5],[0,30.1],[-39.6,0],[0,-30.1],[12.1,0],[0,0],[-0.2,-0.9]],"v":[[182.963,-149.059],[185.985,150.495],[110.785,204.995],[42.385,150.495],[110.785,95.995],[144.985,102.295],[142.763,-140.959]],"c":true}]},{"i":{"x":0.4,"y":1},"o":{"x":0.6,"y":0},"t":25,"s":[{"i":[[-22.75,1.55],[0,-0.7],[39.6,0],[0,30.1],[-39.7,0],[-10.4,-4],[0,0.2]],"o":[[1.3,6.5],[0,30.1],[-39.6,0],[0,-30.1],[12.1,0],[0,0],[-0.2,-0.9]],"v":[[181.854,-163.321],[182.6,70.7],[107.4,125.2],[39,70.7],[107.4,16.2],[141.6,22.5],[141.654,-155.221]],"c":true}]},{"i":{"x":0.4,"y":1},"o":{"x":0.6,"y":0},"t":38,"s":[{"i":[[-22.75,1.55],[0,-0.7],[39.6,0],[0,30.1],[-39.7,0],[-10.4,-4],[0,0.2]],"o":[[1.3,6.5],[0,30.1],[-39.6,0],[0,-30.1],[12.1,0],[0,0],[-0.2,-0.9]],"v":[[182.963,-149.059],[185.985,150.495],[110.785,204.995],[42.385,150.495],[110.785,95.995],[144.985,102.295],[142.763,-140.959]],"c":true}]},{"t":60,"s":[{"i":[[-22.75,1.55],[0,-0.7],[39.6,0],[0,30.1],[-39.7,0],[-10.4,-4],[0,0.2]],"o":[[1.3,6.5],[0,30.1],[-39.6,0],[0,-30.1],[12.1,0],[0,0],[-0.2,-0.9]],"v":[[182,-157.8],[182.8,102.7],[107.6,157.2],[39.2,102.7],[107.6,48.2],[141.8,54.5],[141.8,-149.7]],"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":"Path","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":180,"st":0,"bm":0}],"markers":[]} \ No newline at end of file diff --git a/TMessagesProj/src/main/res/raw/utyan_change_number.tgs b/TMessagesProj/src/main/res/raw/utyan_change_number.tgs new file mode 100644 index 000000000..4085c3f95 --- /dev/null +++ b/TMessagesProj/src/main/res/raw/utyan_change_number.tgs @@ -0,0 +1 @@ +{"tgs":1,"v":"5.5.2.2","fr":60,"ip":0,"op":180,"w":512,"h":512,"nm":"_032_SIM_OUT","ddd":0,"assets":[{"id":"comp_0","layers":[{"ddd":0,"ind":1,"ty":3,"nm":"NULL CONTROL","sr":1,"ks":{"o":{"a":0,"k":0},"p":{"a":0,"k":[44.5,44.5,0]},"a":{"a":0,"k":[60,60,0]},"s":{"a":0,"k":[280,280,100]}},"ao":0,"ip":96,"op":276,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"Shape Layer 6","parent":1,"sr":1,"ks":{"p":{"a":0,"k":[60,60,0]},"a":{"a":0,"k":[147.5,-172.5,0]},"s":{"a":0,"k":[20,20,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[147.5,-172.5],[147.5,-106.5]],"c":false}},"nm":"Path 1","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":170.666,"s":[0]},{"t":180.666015625,"s":[100]}]},"e":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.71],"y":[0]},"t":164,"s":[0]},{"t":176.857421875,"s":[100]}]},"o":{"a":0,"k":0},"m":1,"nm":"Trim Paths 1","hd":false},{"ty":"st","c":{"a":0,"k":[0.462745127958,0.752941236309,0.035294117647,1]},"o":{"a":0,"k":100},"w":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":164,"s":[10]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":174,"s":[19]},{"t":184,"s":[10]}]},"lc":2,"lj":2,"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":"Shape 1","bm":0,"hd":false}],"ip":100,"op":280,"st":100,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"Shape Layer 7","parent":1,"sr":1,"ks":{"r":{"a":0,"k":-45},"p":{"a":0,"k":[60,60,0]},"a":{"a":0,"k":[147.5,-172.5,0]},"s":{"a":0,"k":[20,20,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[147.5,-172.5],[147.5,-106.5]],"c":false}},"nm":"Path 1","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":170.666,"s":[0]},{"t":180.666015625,"s":[100]}]},"e":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.71],"y":[0]},"t":164,"s":[0]},{"t":176.857421875,"s":[100]}]},"o":{"a":0,"k":0},"m":1,"nm":"Trim Paths 1","hd":false},{"ty":"st","c":{"a":0,"k":[0.462745127958,0.752941236309,0.035294117647,1]},"o":{"a":0,"k":100},"w":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":164,"s":[10]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":174,"s":[19]},{"t":184,"s":[10]}]},"lc":2,"lj":2,"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":"Shape 1","bm":0,"hd":false}],"ip":100,"op":280,"st":100,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"Shape Layer 9","parent":1,"sr":1,"ks":{"r":{"a":0,"k":-135},"p":{"a":0,"k":[60,60,0]},"a":{"a":0,"k":[147.5,-172.5,0]},"s":{"a":0,"k":[20,20,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[147.5,-172.5],[147.5,-106.5]],"c":false}},"nm":"Path 1","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":170.666,"s":[0]},{"t":180.666015625,"s":[100]}]},"e":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.71],"y":[0]},"t":164,"s":[0]},{"t":176.857421875,"s":[100]}]},"o":{"a":0,"k":0},"m":1,"nm":"Trim Paths 1","hd":false},{"ty":"st","c":{"a":0,"k":[0.462745127958,0.752941236309,0.035294117647,1]},"o":{"a":0,"k":100},"w":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":164,"s":[10]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":174,"s":[19]},{"t":184,"s":[10]}]},"lc":2,"lj":2,"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":"Shape 1","bm":0,"hd":false}],"ip":100,"op":280,"st":100,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":"Shape Layer 8","parent":1,"sr":1,"ks":{"r":{"a":0,"k":-90},"p":{"a":0,"k":[60,60,0]},"a":{"a":0,"k":[147.5,-172.5,0]},"s":{"a":0,"k":[20,20,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[147.5,-172.5],[147.5,-106.5]],"c":false}},"nm":"Path 1","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":170.666,"s":[0]},{"t":180.666015625,"s":[100]}]},"e":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.71],"y":[0]},"t":164,"s":[0]},{"t":176.857421875,"s":[100]}]},"o":{"a":0,"k":0},"m":1,"nm":"Trim Paths 1","hd":false},{"ty":"st","c":{"a":0,"k":[0.462745127958,0.752941236309,0.035294117647,1]},"o":{"a":0,"k":100},"w":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":164,"s":[10]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":174,"s":[19]},{"t":184,"s":[10]}]},"lc":2,"lj":2,"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":"Shape 1","bm":0,"hd":false}],"ip":100,"op":280,"st":100,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":"Shape Layer 10","parent":1,"sr":1,"ks":{"r":{"a":0,"k":-180},"p":{"a":0,"k":[60,60,0]},"a":{"a":0,"k":[147.5,-172.5,0]},"s":{"a":0,"k":[20,20,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[147.5,-172.5],[147.5,-106.5]],"c":false}},"nm":"Path 1","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":170.666,"s":[0]},{"t":180.666015625,"s":[100]}]},"e":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.71],"y":[0]},"t":164,"s":[0]},{"t":176.857421875,"s":[100]}]},"o":{"a":0,"k":0},"m":1,"nm":"Trim Paths 1","hd":false},{"ty":"st","c":{"a":0,"k":[0.462745127958,0.752941236309,0.035294117647,1]},"o":{"a":0,"k":100},"w":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":164,"s":[10]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":174,"s":[19]},{"t":184,"s":[10]}]},"lc":2,"lj":2,"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":"Shape 1","bm":0,"hd":false}],"ip":100,"op":280,"st":100,"bm":0},{"ddd":0,"ind":7,"ty":4,"nm":"Shape Layer 11","parent":1,"sr":1,"ks":{"r":{"a":0,"k":-225},"p":{"a":0,"k":[60,60,0]},"a":{"a":0,"k":[147.5,-172.5,0]},"s":{"a":0,"k":[20,20,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[147.5,-172.5],[147.5,-106.5]],"c":false}},"nm":"Path 1","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":170.666,"s":[0]},{"t":180.666015625,"s":[100]}]},"e":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.71],"y":[0]},"t":164,"s":[0]},{"t":176.857421875,"s":[100]}]},"o":{"a":0,"k":0},"m":1,"nm":"Trim Paths 1","hd":false},{"ty":"st","c":{"a":0,"k":[0.462745127958,0.752941236309,0.035294117647,1]},"o":{"a":0,"k":100},"w":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":164,"s":[10]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":174,"s":[19]},{"t":184,"s":[10]}]},"lc":2,"lj":2,"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":"Shape 1","bm":0,"hd":false}],"ip":100,"op":280,"st":100,"bm":0},{"ddd":0,"ind":8,"ty":4,"nm":"Shape Layer 12","parent":1,"sr":1,"ks":{"r":{"a":0,"k":-270},"p":{"a":0,"k":[60,60,0]},"a":{"a":0,"k":[147.5,-172.5,0]},"s":{"a":0,"k":[20,20,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[147.5,-172.5],[147.5,-106.5]],"c":false}},"nm":"Path 1","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":170.666,"s":[0]},{"t":180.666015625,"s":[100]}]},"e":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.71],"y":[0]},"t":164,"s":[0]},{"t":176.857421875,"s":[100]}]},"o":{"a":0,"k":0},"m":1,"nm":"Trim Paths 1","hd":false},{"ty":"st","c":{"a":0,"k":[0.462745127958,0.752941236309,0.035294117647,1]},"o":{"a":0,"k":100},"w":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":164,"s":[10]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":174,"s":[19]},{"t":184,"s":[10]}]},"lc":2,"lj":2,"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":"Shape 1","bm":0,"hd":false}],"ip":100,"op":280,"st":100,"bm":0},{"ddd":0,"ind":9,"ty":4,"nm":"Shape Layer 13","parent":1,"sr":1,"ks":{"r":{"a":0,"k":-315},"p":{"a":0,"k":[60,60,0]},"a":{"a":0,"k":[147.5,-172.5,0]},"s":{"a":0,"k":[20,20,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[147.5,-172.5],[147.5,-106.5]],"c":false}},"nm":"Path 1","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":170.666,"s":[0]},{"t":180.666015625,"s":[100]}]},"e":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.71],"y":[0]},"t":164,"s":[0]},{"t":176.857421875,"s":[100]}]},"o":{"a":0,"k":0},"m":1,"nm":"Trim Paths 1","hd":false},{"ty":"st","c":{"a":0,"k":[0.462745127958,0.752941236309,0.035294117647,1]},"o":{"a":0,"k":100},"w":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":164,"s":[10]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":174,"s":[19]},{"t":184,"s":[10]}]},"lc":2,"lj":2,"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":"Shape 1","bm":0,"hd":false}],"ip":100,"op":280,"st":100,"bm":0},{"ddd":0,"ind":10,"ty":3,"nm":"NULL CONTROL","parent":20,"sr":1,"ks":{"o":{"a":0,"k":0},"r":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":60,"s":[3]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":90,"s":[5]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":210,"s":[5]},{"t":238,"s":[3]}]},"p":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.65,"y":0},"t":60,"s":[-7.461,49.744,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.967},"o":{"x":0.333,"y":0},"t":78,"s":[-5.807,49.589,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":90,"s":[-18.277,49.366,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0.028},"t":210,"s":[-18.277,49.366,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.35,"y":1},"o":{"x":0.333,"y":0},"t":220,"s":[-5.807,49.589,0],"to":[0,0,0],"ti":[0,0,0]},{"t":238,"s":[-7.461,49.744,0]}]},"a":{"a":0,"k":[60,60,0]},"s":{"a":1,"k":[{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.65,0.65,0.65],"y":[0,0,0]},"t":60,"s":[86.58,86.58,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.967,1.033,1.033]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":78,"s":[90,86.58,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1.333,1.333,1.333]},"o":{"x":[0.167,0.167,0.167],"y":[-0.333,-0.333,-0.333]},"t":90,"s":[64.58,86.58,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.028,-0.028,-0.028]},"t":210,"s":[64.58,86.58,100]},{"i":{"x":[0.35,0.35,0.35],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":220,"s":[90,86.58,100]},{"t":238,"s":[86.58,86.58,100]}]}},"ao":0,"ip":0,"op":304,"st":0,"bm":0},{"ddd":0,"ind":13,"ty":4,"nm":"Layer 18","parent":14,"sr":1,"ks":{"r":{"a":0,"k":-0.192},"p":{"a":0,"k":[-18.16,-3.564,0]},"a":{"a":0,"k":[760.164,23.42,0]},"s":{"a":0,"k":[62.374,62.485,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[13.908,0.342],[-13.908,-0.342]],"c":false}},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":0,"k":[0.717647075653,0.494117647409,0.247058823705,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":6},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"tr","p":{"a":0,"k":[786.371,34.76]},"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 1","bm":0,"hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[13.908,0.342],[-13.908,-0.342]],"c":false}},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":0,"k":[0.717647075653,0.494117647409,0.247058823705,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":6},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"tr","p":{"a":0,"k":[787.706,14.042]},"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":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[13.908,0.342],[-13.908,-0.342]],"c":false}},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":0,"k":[0.717647075653,0.494117647409,0.247058823705,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":6},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"tr","p":{"a":0,"k":[732.524,33.436]},"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 3","bm":0,"hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[13.908,0.342],[-13.908,-0.342]],"c":false}},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":0,"k":[0.717647075653,0.494117647409,0.247058823705,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":6},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"tr","p":{"a":0,"k":[733.859,12.717]},"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 4","bm":0,"hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[5.269,7.676],[-5.342,7.018],[3.511,5.143],[-5.666,6.487]],"o":[[-5.269,-7.676],[5.342,-7.018],[-3.511,-5.143],[5.666,-6.487]],"v":[[-0.71,30.845],[0.661,9.556],[0.778,-9.575],[2.906,-30.845]],"c":false}},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":0,"k":[0.717647075653,0.494117647409,0.247058823705,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":6},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"tr","p":{"a":0,"k":[773.021,23.275]},"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 5","bm":0,"hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[-5.269,-7.676],[5.342,-7.018],[-3.511,-5.143],[5.666,-6.487]],"o":[[5.269,7.676],[-5.342,7.018],[3.511,5.143],[-5.666,6.487]],"v":[[1.008,-30.845],[-0.363,-9.556],[-1.709,11.336],[-2.608,30.845]],"c":false}},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":0,"k":[0.717647075653,0.494117647409,0.247058823705,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":6},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"tr","p":{"a":0,"k":[748.129,22.616]},"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 6","bm":0,"hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[-0.482,7.48],[0,0],[-7.491,-0.184],[0,0],[0.482,-7.48],[0,0],[7.491,0.184],[0,0]],"o":[[0,0],[0.482,-7.48],[0,0],[7.491,0.184],[0,0],[-0.482,7.48],[0,0],[-7.491,-0.184]],"v":[[-42.006,16.78],[-39.714,-18.79],[-25.277,-31.999],[29.314,-30.657],[42.006,-16.78],[39.714,18.79],[25.277,31.999],[-29.314,30.657]],"c":true}},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":0,"k":[0.717647075653,0.494117647409,0.247058823705,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":10},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.933333337307,0.827450990677,0.301960796118,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[760.164,23.42]},"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 7","bm":0,"hd":false}],"ip":0,"op":300,"st":0,"bm":0},{"ddd":0,"ind":14,"ty":4,"nm":"Layer 13","parent":10,"sr":1,"ks":{"r":{"a":0,"k":-4.925},"p":{"a":0,"k":[57.076,-23.931,0]},"s":{"a":1,"k":[{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":90,"s":[103.95,103.95,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":99,"s":[103.95,145.531,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":108,"s":[0,0,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":198,"s":[0,0,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":212,"s":[103.95,145.531,100]},{"t":220,"s":[103.95,103.95,100]}]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[-0.145,1.726],[0,0],[3.605,0.131],[0,0],[0.302,-3.594],[0,0],[-3.605,-0.131],[0,0],[-1.327,1.176],[0,0]],"o":[[0,0],[0.302,-3.594],[0,0],[-3.605,-0.131],[0,0],[-0.302,3.594],[0,0],[1.731,0.063],[0,0],[1.327,-1.176]],"v":[[53.897,11.199],[56.88,-24.257],[50.9,-31.002],[-45.333,-34.509],[-52.408,-28.239],[-56.88,24.903],[-50.9,31.649],[27.592,34.509],[32.368,32.771],[51.597,15.731]],"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 1","bm":0,"hd":false}],"ip":0,"op":300,"st":0,"bm":0},{"ddd":0,"ind":15,"ty":4,"nm":"Layer 17","parent":10,"sr":1,"ks":{"o":{"a":0,"k":30},"r":{"a":0,"k":-4.925},"p":{"a":0,"k":[71.154,-7.093,0]},"s":{"a":1,"k":[{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":90,"s":[103.95,103.95,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":99,"s":[103.95,145.531,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":108,"s":[0,0,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":198,"s":[0,0,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":212,"s":[103.95,145.531,100]},{"t":220,"s":[103.95,103.95,100]}]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[-0.145,1.726],[0,0],[3.605,0.131],[0,0],[0.302,-3.594],[0,0],[-3.605,-0.131],[0,0],[-1.327,1.176],[0,0]],"o":[[0,0],[0.302,-3.594],[0,0],[-3.605,-0.131],[0,0],[-0.302,3.594],[0,0],[1.731,0.063],[0,0],[1.327,-1.176]],"v":[[53.897,11.199],[56.88,-24.257],[50.9,-31.002],[-45.333,-34.509],[-52.408,-28.239],[-56.88,24.903],[-50.9,31.649],[27.592,34.509],[32.368,32.771],[51.597,15.731]],"c":true}},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0,0,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 1","bm":0,"hd":false}],"ip":0,"op":300,"st":0,"bm":0},{"ddd":0,"ind":16,"ty":3,"nm":"ALL","sr":1,"ks":{"o":{"a":0,"k":0},"p":{"a":0,"k":[184.732,461.677,0]},"a":{"a":0,"k":[60,60,0]},"s":{"a":0,"k":[102.688,97.312,100]}},"ao":0,"ip":0,"op":304,"st":0,"bm":0},{"ddd":0,"ind":17,"ty":4,"nm":"wing_bl","parent":18,"sr":1,"ks":{"p":{"a":0,"k":[-8.855,-11.869,0]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":60,"s":[{"i":[[-17.276,5.324],[-17.581,17.49]],"o":[[35.586,-10.373],[9.488,-9.438]],"v":[[-35.127,5.783],[45.001,-36.879]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":80,"s":[{"i":[[-17.276,5.324],[-8.234,24.443]],"o":[[35.586,-10.373],[4.273,-12.683]],"v":[[-35.127,5.783],[31.82,-43.067]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":90,"s":[{"i":[[-17.276,5.324],[-16.274,23.744]],"o":[[35.586,-10.373],[7.566,-11.039]],"v":[[-35.127,5.783],[31.82,-43.067]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":100,"s":[{"i":[[-17.276,5.324],[-24.88,5.04]],"o":[[27.71,-32.456],[13.117,-2.657]],"v":[[-35.127,5.783],[37.564,-28.441]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":112,"s":[{"i":[[-17.276,5.324],[-22.504,0.69]],"o":[[23.282,-27.828],[13.377,-0.41]],"v":[[-35.127,5.783],[37.564,-28.441]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":128,"s":[{"i":[[-17.276,5.324],[-22.504,0.69]],"o":[[23.282,-27.828],[13.377,-0.41]],"v":[[-35.127,5.783],[37.564,-28.441]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":140,"s":[{"i":[[-17.276,5.324],[-22.504,0.69]],"o":[[23.282,-27.828],[13.377,-0.41]],"v":[[-35.127,5.783],[37.564,-28.441]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":152,"s":[{"i":[[-17.276,5.324],[-5.585,25.207]],"o":[[24.367,-10.734],[2.895,-13.066]],"v":[[-15.415,10.058],[36.215,-49.966]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":174,"s":[{"i":[[-17.276,5.324],[5.972,33.072]],"o":[[24.367,-10.734],[-2.378,-13.17]],"v":[[-0.918,31.478],[29.91,-25.042]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":190,"s":[{"i":[[-17.276,5.324],[5.972,33.072]],"o":[[19.202,-5.366],[-2.378,-13.17]],"v":[[-32.362,4.039],[3.355,-46.163]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":206,"s":[{"i":[[-17.276,5.324],[-16.274,23.744]],"o":[[35.586,-10.373],[7.566,-11.039]],"v":[[-12.052,22.789],[54.895,-26.061]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":216,"s":[{"i":[[-17.276,5.324],[-16.274,23.744]],"o":[[24.939,-3.096],[7.566,-11.039]],"v":[[-24.432,4.873],[45.308,-38.48]],"c":false}]},{"t":224,"s":[{"i":[[-17.276,5.324],[-17.581,17.49]],"o":[[35.586,-10.373],[9.488,-9.438]],"v":[[-35.127,5.783],[45.001,-36.879]],"c":false}]}]},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":10},"lc":2,"lj":2,"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":"Group 1","bm":0,"hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":60,"s":[5]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":72,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":84,"s":[5]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":96,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":108,"s":[5]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":120,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":132,"s":[5]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":144,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":156,"s":[5]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":168,"s":[5]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":180,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":192,"s":[5]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":204,"s":[5]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":216,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":228,"s":[5]},{"t":240,"s":[5]}]},"e":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":60,"s":[100]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":72,"s":[95]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":84,"s":[100]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":96,"s":[95]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":108,"s":[100]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":120,"s":[95]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":132,"s":[100]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":144,"s":[95]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":156,"s":[100]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":168,"s":[100]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":180,"s":[95]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":192,"s":[100]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":204,"s":[100]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":216,"s":[95]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":228,"s":[100]},{"t":240,"s":[100]}]},"o":{"a":0,"k":0},"m":1,"nm":"Trim Paths 1","hd":false}],"ip":0,"op":304,"st":0,"bm":0},{"ddd":0,"ind":18,"ty":4,"nm":"wing_l","parent":37,"sr":1,"ks":{"r":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":60,"s":[29.776]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":80,"s":[4.46]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":90,"s":[37.851]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":100,"s":[59.739]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":112,"s":[4.46]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":128,"s":[21.37]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":140,"s":[21.37]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":146,"s":[55.489]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":152,"s":[-44.575]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":174,"s":[196.558]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":190,"s":[4.46]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":203.334,"s":[22.973]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":208,"s":[22.973]},{"t":224,"s":[29.776]}]},"p":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":60,"s":[-30.879,8.023,0],"to":[8.62,5.016,0],"ti":[-4.359,4.747,0]},{"t":80,"s":[-0.69,2.885,0],"h":1},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":90,"s":[-0.69,2.885,0],"to":[-15.117,14.007,0],"ti":[3.965,5.433,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":100,"s":[-60.094,3.912,0],"to":[10.448,10.012,0],"ti":[-2.412,5.004,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0},"t":112,"s":[-0.69,2.885,0],"to":[-18.039,1.676,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":0.667},"o":{"x":0.167,"y":0.167},"t":128,"s":[-40.617,2.885,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0},"t":140,"s":[-40.617,2.885,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0},"t":152,"s":[-75.675,-12.016,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0},"t":174,"s":[-76.445,-11.57,0],"to":[0,0,0],"ti":[-2.412,5.004,0]},{"t":190,"s":[-29.905,2.885,0],"h":1},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":208,"s":[-0.69,2.885,0],"to":[-4.283,6.172,0],"ti":[6.595,3.708,0]},{"t":224,"s":[-30.879,8.023,0]}]},"a":{"a":0,"k":[-31.735,12.164,0]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":60,"s":[{"i":[[0,0],[-4.979,-16.514],[39.864,-41.939]],"o":[[90.592,-20.031],[32.187,51.424],[0,0]],"v":[[-54.963,-24.543],[53.934,-82.266],[-7.564,37.989]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":80,"s":[{"i":[[0,0],[-4.979,-16.514],[63.721,-32.03]],"o":[[96.719,-10.119],[37.874,31.846],[0,0]],"v":[[-54.963,-24.543],[18.075,-103.691],[-7.564,37.989]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":90,"s":[{"i":[[0,0],[-4.979,-16.514],[53.781,-41.332]],"o":[[80.14,-24.918],[37.874,31.846],[0,0]],"v":[[-54.963,-24.543],[42.597,-103.877],[-7.564,37.989]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":100,"s":[{"i":[[0,0],[-4.979,-16.514],[10.322,-50.653]],"o":[[68.489,-50.418],[-13.793,31.74],[0,0]],"v":[[-54.963,-24.543],[56.936,-39.654],[-7.564,37.989]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":112,"s":[{"i":[[0,0],[-4.979,-16.514],[10.322,-50.653]],"o":[[68.489,-50.418],[-13.793,31.74],[0,0]],"v":[[-54.963,-24.543],[56.936,-39.654],[-7.564,37.989]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":128,"s":[{"i":[[0,0],[-4.979,-16.514],[10.322,-50.653]],"o":[[68.489,-50.418],[-13.793,31.74],[0,0]],"v":[[-54.963,-24.543],[56.936,-39.654],[-7.564,37.989]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":140,"s":[{"i":[[0,0],[-4.979,-16.514],[10.322,-50.653]],"o":[[68.489,-50.418],[-13.793,31.74],[0,0]],"v":[[-54.963,-24.543],[56.936,-39.654],[-7.564,37.989]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":152,"s":[{"i":[[0,0],[-32.75,-11.91],[59.265,-50.183]],"o":[[78.567,-33.366],[24.656,17.24],[0,0]],"v":[[-43.586,-9.728],[36.855,-97.669],[-7.564,37.989]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":174,"s":[{"i":[[0,0],[-32.75,-11.91],[70.329,-22.436]],"o":[[66.395,-10.011],[24.656,17.24],[0,0]],"v":[[-54.047,-22.699],[13.364,-72.459],[-7.564,37.989]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":192,"s":[{"i":[[0,0],[-32.75,-11.91],[55.046,-37.171]],"o":[[66.395,-10.011],[24.656,17.24],[0,0]],"v":[[-54.047,-22.699],[-11.282,-96.108],[-7.564,37.989]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":206,"s":[{"i":[[0,0],[-4.979,-16.514],[63.721,-32.03]],"o":[[96.719,-10.119],[37.874,31.846],[0,0]],"v":[[-39.368,-7.715],[52.499,-94.845],[8.031,54.817]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":216,"s":[{"i":[[0,0],[-4.979,-16.514],[63.721,-32.03]],"o":[[96.719,-10.119],[37.874,31.846],[0,0]],"v":[[-54.963,-24.543],[52.499,-94.845],[-7.564,37.989]],"c":false}]},{"t":224,"s":[{"i":[[0,0],[-4.979,-16.514],[39.864,-41.939]],"o":[[90.592,-20.031],[32.187,51.424],[0,0]],"v":[[-54.963,-24.543],[53.934,-82.266],[-7.564,37.989]],"c":false}]}]},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":0,"k":[0.980392158031,0.564705908298,0.086274512112,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":10},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"fl","c":{"a":0,"k":[1,0.835294127464,0.152941182256,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 1","bm":0,"hd":false}],"ip":0,"op":304,"st":0,"bm":0},{"ddd":0,"ind":19,"ty":4,"nm":"Layer 9","parent":20,"sr":1,"ks":{"r":{"a":0,"k":1},"p":{"a":0,"k":[-12.158,109.645,0]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.65,"y":0},"t":60,"s":[{"i":[[-15.991,2],[0,0]],"o":[[0,0],[15.991,2]],"v":[[-28.751,0],[28.751,0]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.333,"y":0},"t":78,"s":[{"i":[[-15.991,2],[0,0]],"o":[[0,0],[15.991,2]],"v":[[-25.504,-0.023],[31.997,-0.023]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":90,"s":[{"i":[[-12.744,2],[0,0]],"o":[[0,0],[12.744,2]],"v":[[-33.734,-0.189],[12.092,-0.189]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0.167},"t":210,"s":[{"i":[[-12.744,2],[0,0]],"o":[[0,0],[12.744,2]],"v":[[-33.734,-0.189],[12.092,-0.189]],"c":false}]},{"i":{"x":0.35,"y":1},"o":{"x":0.333,"y":0},"t":220,"s":[{"i":[[-15.991,2],[0,0]],"o":[[0,0],[15.991,2]],"v":[[-25.504,-0.023],[31.997,-0.023]],"c":false}]},{"t":234,"s":[{"i":[[-15.991,2],[0,0]],"o":[[0,0],[15.991,2]],"v":[[-28.751,0],[28.751,0]],"c":false}]}]},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":6},"lc":2,"lj":2,"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":"Group 1","bm":0,"hd":false}],"ip":0,"op":300,"st":0,"bm":0},{"ddd":0,"ind":20,"ty":4,"nm":"phone","sr":1,"ks":{"r":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":60,"s":[2]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":90,"s":[-2]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":210,"s":[-2]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":222,"s":[2]},{"t":238,"s":[2]}]},"p":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.85,"y":0},"t":60,"s":[376.205,446.188,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":90,"s":[423.908,446.188,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.15,"y":1},"o":{"x":0.333,"y":0},"t":210,"s":[423.908,446.188,0],"to":[0,0,0],"ti":[0,0,0]},{"t":234,"s":[376.205,446.188,0]}]},"a":{"a":0,"k":[-2.564,120.731,0]},"s":{"a":0,"k":[115.5,115.5,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.65,"y":0},"t":60,"s":[{"i":[[15.283,0.013],[0,0],[0.248,-3.693],[0,0],[4.492,0.004],[0,0],[-0.311,4.619],[0,0],[3.592,0.003],[0,0],[1.057,-15.715],[0,0],[-15.283,-0.013],[0,0],[-1.057,15.715],[0,0]],"o":[[0,0],[-3.592,-0.003],[0,0],[-0.311,4.619],[0,0],[-4.492,-0.004],[0,0],[0.248,-3.693],[0,0],[-15.283,-0.013],[0,0],[-1.057,15.715],[0,0],[15.283,0.013],[0,0],[1.057,-15.715]],"v":[[45.404,-120.462],[42.113,-120.465],[35.159,-113.783],[35.159,-113.783],[26.463,-105.426],[-17.142,-105.464],[-24.713,-113.835],[-24.713,-113.835],[-30.767,-120.528],[-34.058,-120.53],[-58.052,-97.473],[-71.291,97.564],[-55.109,120.656],[32.344,120.731],[53.054,97.671],[66.293,-97.366]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.333,"y":0},"t":78,"s":[{"i":[[15.991,0],[0,0],[0.226,-3.694],[0,0],[4.7,0],[0,0],[-0.283,4.62],[0,0],[3.758,0],[0,0],[0.963,-15.718],[0,0],[-15.991,0],[0,0],[-0.963,15.718],[0,0]],"o":[[0,0],[-3.758,0],[0,0],[-0.283,4.62],[0,0],[-4.7,0],[0,0],[0.226,-3.694],[0,0],[-15.991,0],[0,0],[-0.963,15.718],[0,0],[15.991,0],[0,0],[0.963,-15.718]],"v":[[49.017,-120.612],[45.574,-120.612],[38.359,-113.923],[38.359,-113.923],[29.336,-105.558],[-16.287,-105.558],[-24.284,-113.923],[-24.284,-113.923],[-30.679,-120.612],[-34.122,-120.612],[-59.018,-97.531],[-70.974,97.531],[-53.834,120.612],[37.668,120.612],[59.127,97.531],[71.083,-97.531]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":90,"s":[{"i":[[12.455,0.066],[0,0],[0.336,-3.691],[0,0],[3.661,0.019],[0,0],[-0.421,4.616],[0,0],[2.927,0.015],[0,0],[1.432,-15.705],[0,0],[-12.455,-0.066],[0,0],[-1.432,15.705],[0,0]],"o":[[0,0],[-2.927,-0.015],[0,0],[-0.421,4.616],[0,0],[-3.661,-0.019],[0,0],[0.336,-3.691],[0,0],[-12.455,-0.066],[0,0],[-1.432,15.705],[0,0],[12.455,0.066],[0,0],[1.432,-15.705]],"v":[[30.957,-119.864],[28.275,-119.878],[22.366,-113.223],[22.366,-113.223],[14.975,-104.9],[-20.56,-105.087],[-26.426,-113.48],[-26.426,-113.48],[-31.117,-120.191],[-33.799,-120.205],[-54.19,-97.24],[-72.56,97.694],[-60.21,120.832],[11.059,121.206],[28.774,98.227],[47.144,-96.707]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0.167},"t":210,"s":[{"i":[[12.455,0.066],[0,0],[0.336,-3.691],[0,0],[3.661,0.019],[0,0],[-0.421,4.616],[0,0],[2.927,0.015],[0,0],[1.432,-15.705],[0,0],[-12.455,-0.066],[0,0],[-1.432,15.705],[0,0]],"o":[[0,0],[-2.927,-0.015],[0,0],[-0.421,4.616],[0,0],[-3.661,-0.019],[0,0],[0.336,-3.691],[0,0],[-12.455,-0.066],[0,0],[-1.432,15.705],[0,0],[12.455,0.066],[0,0],[1.432,-15.705]],"v":[[30.957,-119.864],[28.275,-119.878],[22.366,-113.223],[22.366,-113.223],[14.975,-104.9],[-20.56,-105.087],[-26.426,-113.48],[-26.426,-113.48],[-31.117,-120.191],[-33.799,-120.205],[-54.19,-97.24],[-72.56,97.694],[-60.21,120.832],[11.059,121.206],[28.774,98.227],[47.144,-96.707]],"c":true}]},{"i":{"x":0.35,"y":1},"o":{"x":0.333,"y":0},"t":220,"s":[{"i":[[15.991,0],[0,0],[0.226,-3.694],[0,0],[4.7,0],[0,0],[-0.283,4.62],[0,0],[3.758,0],[0,0],[0.963,-15.718],[0,0],[-15.991,0],[0,0],[-0.963,15.718],[0,0]],"o":[[0,0],[-3.758,0],[0,0],[-0.283,4.62],[0,0],[-4.7,0],[0,0],[0.226,-3.694],[0,0],[-15.991,0],[0,0],[-0.963,15.718],[0,0],[15.991,0],[0,0],[0.963,-15.718]],"v":[[49.017,-120.612],[45.574,-120.612],[38.359,-113.923],[38.359,-113.923],[29.336,-105.558],[-16.287,-105.558],[-24.284,-113.923],[-24.284,-113.923],[-30.679,-120.612],[-34.122,-120.612],[-59.018,-97.531],[-70.974,97.531],[-53.834,120.612],[37.668,120.612],[59.127,97.531],[71.083,-97.531]],"c":true}]},{"t":234,"s":[{"i":[[15.283,0.013],[0,0],[0.248,-3.693],[0,0],[4.492,0.004],[0,0],[-0.311,4.619],[0,0],[3.592,0.003],[0,0],[1.057,-15.715],[0,0],[-15.283,-0.013],[0,0],[-1.057,15.715],[0,0]],"o":[[0,0],[-3.592,-0.003],[0,0],[-0.311,4.619],[0,0],[-4.492,-0.004],[0,0],[0.248,-3.693],[0,0],[-15.283,-0.013],[0,0],[-1.057,15.715],[0,0],[15.283,0.013],[0,0],[1.057,-15.715]],"v":[[45.404,-120.462],[42.113,-120.465],[35.159,-113.783],[35.159,-113.783],[26.463,-105.426],[-17.142,-105.464],[-24.713,-113.835],[-24.713,-113.835],[-30.767,-120.528],[-34.058,-120.53],[-58.052,-97.473],[-71.291,97.564],[-55.109,120.656],[32.344,120.731],[53.054,97.671],[66.293,-97.366]],"c":true}]}]},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":56,"s":[0.273039604636,0.643120799345,0.868321078431,1]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":90,"s":[0.283864578546,0.876776960784,0.444299675437,1]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":204,"s":[0.283864578546,0.876776960784,0.444299675437,1]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":214,"s":[0.273039604636,0.643120799345,0.868321078431,1]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":236,"s":[0.273039604636,0.643120799345,0.868321078431,1]},{"t":270,"s":[0.283864578546,0.876776960784,0.444299675437,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 1","bm":0,"hd":false}],"ip":0,"op":300,"st":0,"bm":0},{"ddd":0,"ind":21,"ty":4,"nm":"Layer 7","parent":20,"sr":1,"ks":{"p":{"a":0,"k":[0.017,0,0]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.65,"y":0},"t":60,"s":[{"i":[[0,0],[-1.953,28.612],[0,0],[-26.105,0],[0,0],[1.865,-27.295],[0,0],[25.412,0]],"o":[[-26.617,0],[0,0],[1.784,-26.143],[0,0],[27.368,0],[0,0],[-1.905,27.916],[0,0]],"v":[[-54.757,136.924],[-87.506,96.47],[-74.191,-98.593],[-33.172,-137.043],[44.78,-137.043],[82.394,-96.59],[69.078,98.472],[31.452,136.924]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.333,"y":0},"t":78,"s":[{"i":[[0,0],[-1.754,28.612],[0,0],[-26.435,0],[0,0],[1.674,-27.295],[0,0],[25.733,0]],"o":[[-26.954,0],[0,0],[1.602,-26.143],[0,0],[27.714,0],[0,0],[-1.71,27.916],[0,0]],"v":[[-53.851,136.984],[-87.331,96.53],[-75.375,-98.533],[-34.139,-136.984],[49,-136.984],[87.406,-96.531],[75.45,98.532],[37.65,136.984]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":90,"s":[{"i":[[0,0],[-2.751,28.612],[0,0],[-24.785,0],[0,0],[2.625,-27.295],[0,0],[24.127,0]],"o":[[-25.271,0],[0,0],[2.513,-26.143],[0,0],[25.984,0],[0,0],[-2.683,27.916],[0,0]],"v":[[-58.38,136.685],[-88.206,96.231],[-69.453,-98.831],[-29.304,-137.282],[27.909,-137.282],[62.353,-96.829],[43.6,98.234],[6.673,136.685]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0.167},"t":210,"s":[{"i":[[0,0],[-2.751,28.612],[0,0],[-24.785,0],[0,0],[2.625,-27.295],[0,0],[24.127,0]],"o":[[-25.271,0],[0,0],[2.513,-26.143],[0,0],[25.984,0],[0,0],[-2.683,27.916],[0,0]],"v":[[-58.38,136.685],[-88.206,96.231],[-69.453,-98.831],[-29.304,-137.282],[27.909,-137.282],[62.353,-96.829],[43.6,98.234],[6.673,136.685]],"c":true}]},{"i":{"x":0.35,"y":1},"o":{"x":0.333,"y":0},"t":220,"s":[{"i":[[0,0],[-1.754,28.612],[0,0],[-26.435,0],[0,0],[1.674,-27.295],[0,0],[25.733,0]],"o":[[-26.954,0],[0,0],[1.602,-26.143],[0,0],[27.714,0],[0,0],[-1.71,27.916],[0,0]],"v":[[-53.851,136.984],[-87.331,96.53],[-75.375,-98.533],[-34.139,-136.984],[49,-136.984],[87.406,-96.531],[75.45,98.532],[37.65,136.984]],"c":true}]},{"t":234,"s":[{"i":[[0,0],[-1.953,28.612],[0,0],[-26.105,0],[0,0],[1.865,-27.295],[0,0],[25.412,0]],"o":[[-26.617,0],[0,0],[1.784,-26.143],[0,0],[27.368,0],[0,0],[-1.905,27.916],[0,0]],"v":[[-54.757,136.924],[-87.506,96.47],[-74.191,-98.593],[-33.172,-137.043],[44.78,-137.043],[82.394,-96.59],[69.078,98.472],[31.452,136.924]],"c":true}]}]},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.84],"y":[0]},"t":60,"s":[0.552941176471,0.003921568627,0.996078491211,1]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":90,"s":[0.38431372549,0.062745098039,0.647058823529,1]},{"i":{"x":[0.16],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":210,"s":[0.38431372549,0.062745098039,0.647058823529,1]},{"t":234,"s":[0.552941176471,0.003921568627,0.996078491211,1]}]},"o":{"a":0,"k":100},"w":{"a":0,"k":10},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0,0,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 1","bm":0,"hd":false}],"ip":0,"op":300,"st":0,"bm":0},{"ddd":0,"ind":22,"ty":4,"nm":"Layer 19","parent":20,"sr":1,"ks":{"p":{"a":0,"k":[-8.635,-0.302,0]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.65,"y":0},"t":60,"s":[{"i":[[-2.751,28.612],[0,0]],"o":[[0,0],[2.513,-26.143]],"v":[[-77.384,96.343],[-64.476,-98.839]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.333,"y":0},"t":78,"s":[{"i":[[-2.751,28.612],[0,0]],"o":[[0,0],[2.513,-26.143]],"v":[[-77.384,96.343],[-65.774,-98.793]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":90,"s":[{"i":[[-2.751,28.612],[0,0]],"o":[[0,0],[2.513,-26.143]],"v":[[-88.206,96.231],[-69.453,-98.831]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0.167},"t":210,"s":[{"i":[[-2.751,28.612],[0,0]],"o":[[0,0],[2.513,-26.143]],"v":[[-88.206,96.231],[-69.453,-98.831]],"c":false}]},{"i":{"x":0.35,"y":1},"o":{"x":0.333,"y":0},"t":220,"s":[{"i":[[-2.751,28.612],[0,0]],"o":[[0,0],[2.513,-26.143]],"v":[[-77.384,96.343],[-65.774,-98.793]],"c":false}]},{"t":234,"s":[{"i":[[-2.751,28.612],[0,0]],"o":[[0,0],[2.513,-26.143]],"v":[[-77.384,96.343],[-64.476,-98.839]],"c":false}]}]},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.84],"y":[0]},"t":60,"s":[0.38431372549,0.062745098039,0.647058823529,1]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":90,"s":[0.552941176471,0.003921568627,0.996078491211,1]},{"i":{"x":[0.16],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":210,"s":[0.552941176471,0.003921568627,0.996078491211,1]},{"t":234,"s":[0.38431372549,0.062745098039,0.647058823529,1]}]},"o":{"a":0,"k":100},"w":{"a":0,"k":10},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0,0,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 1","bm":0,"hd":false}],"ip":0,"op":300,"st":0,"bm":0},{"ddd":0,"ind":23,"ty":4,"nm":"sim 2","parent":20,"sr":1,"ks":{"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":174,"s":[165.948]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":198,"s":[11.974]},{"t":204,"s":[2.981]}]},"p":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":174,"s":[-314.937,77.506,0],"to":[252.931,98.89,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":190,"s":[-187.083,-41.038,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":1},"o":{"x":0.333,"y":0},"t":196,"s":[-205.254,-41.673,0],"to":[0,0,0],"ti":[-111.831,-17.041,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":204,"s":[-43.298,-2.247,0],"to":[111.831,17.041,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":0.667},"o":{"x":0.167,"y":0.167},"t":214,"s":[6.153,1.95,0],"to":[0,0,0],"ti":[0,0,0]},{"t":228,"s":[6.153,1.95,0]}]},"a":{"a":0,"k":[293.859,350.706,0]},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833,0.833],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":190,"s":[100.016,100,100]},{"i":{"x":[0,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":204,"s":[100.016,100,100]},{"i":{"x":[0,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"t":214,"s":[80.016,99.507,100]},{"t":228,"s":[80.016,99.507,100]}]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":174,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[3.149,0],[-3.071,0]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0},"t":194,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[13.908,0],[-13.908,0]],"c":false}]},{"t":210,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[13.908,0],[-13.908,0]],"c":false}]}]},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":0,"k":[0.588235294118,0.466666696586,0.325490196078,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":6},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"tr","p":{"a":0,"k":[296.227,358.747]},"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 1","bm":0,"hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":174,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[3.149,0],[-3.071,0]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0},"t":194,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[13.908,0],[-13.908,0]],"c":false}]},{"t":210,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[13.908,0],[-13.908,0]],"c":false}]}]},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":0,"k":[0.588235294118,0.466666696586,0.325490196078,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":6},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"tr","p":{"a":0,"k":[296.227,337.996]},"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":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":174,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[44.956,0],[38.737,0]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0},"t":194,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[13.908,0],[-13.908,0]],"c":false}]},{"t":210,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[13.438,0.007],[-14.848,0.013]],"c":false}]}]},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":0,"k":[0.588235294118,0.466666696586,0.325490196078,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":6},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"tr","p":{"a":0,"k":[242.38,358.747]},"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 3","bm":0,"hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":174,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[44.956,0],[38.737,0]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0},"t":194,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[13.908,0],[-13.908,0]],"c":false}]},{"t":210,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[13.908,0],[-13.908,0]],"c":false}]}]},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":0,"k":[0.588235294118,0.466666696586,0.325490196078,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":6},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"tr","p":{"a":0,"k":[242.38,337.996]},"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 4","bm":0,"hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":174,"s":[{"i":[[1.287,7.546],[-1.092,7.15],[0.858,5.057],[-1.172,6.626]],"o":[[-1.287,-7.546],[1.092,-7.15],[-0.858,-5.057],[1.172,-6.626]],"v":[[10.63,30.889],[10.63,9.567],[10.381,-9.567],[10.55,-30.889]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0},"t":194,"s":[{"i":[[5.755,7.546],[-4.883,7.15],[3.836,5.057],[-5.24,6.626]],"o":[[-5.755,-7.546],[4.883,-7.15],[-3.836,-5.057],[5.24,-6.626]],"v":[[0.658,30.889],[0.658,9.567],[-0.456,-9.567],[0.301,-30.889]],"c":false}]},{"t":210,"s":[{"i":[[5.755,7.546],[-4.883,7.15],[3.836,5.057],[-5.24,6.626]],"o":[[-5.755,-7.546],[4.883,-7.15],[-3.836,-5.057],[5.24,-6.626]],"v":[[0.658,30.889],[0.658,9.567],[-0.456,-9.567],[0.301,-30.889]],"c":false}]}]},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":0,"k":[0.588235294118,0.466666696586,0.325490196078,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":6},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"tr","p":{"a":0,"k":[282.776,347.563]},"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 5","bm":0,"hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":174,"s":[{"i":[[-1.287,-7.546],[1.092,-7.15],[-0.858,-5.057],[1.172,-6.626]],"o":[[1.287,7.546],[-1.092,7.15],[0.858,5.057],[-1.172,6.626]],"v":[[30.691,-30.889],[30.691,-9.567],[30.691,11.359],[30.771,30.889]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0},"t":194,"s":[{"i":[[-5.755,-7.546],[4.883,-7.15],[-3.836,-5.057],[5.24,-6.626]],"o":[[5.755,7.546],[-4.883,7.15],[3.836,5.057],[-5.24,6.626]],"v":[[-0.357,-30.889],[-0.357,-9.567],[-0.357,11.359],[0,30.889]],"c":false}]},{"t":210,"s":[{"i":[[-5.755,-7.546],[4.883,-7.15],[-3.836,-5.057],[5.24,-6.626]],"o":[[5.755,7.546],[-4.883,7.15],[3.836,5.057],[-5.24,6.626]],"v":[[-0.357,-30.889],[-0.357,-9.567],[-0.827,11.365],[-1.41,30.909]],"c":false}]}]},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":0,"k":[0.588235294118,0.466666696586,0.325490196078,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":6},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"tr","p":{"a":0,"k":[256.644,347.563]},"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 6","bm":0,"hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":174,"s":[{"i":[[0,7.491],[0,0],[-1.675,0],[0,0],[0,-7.491],[0,0],[1.675,0],[0,0]],"o":[[0,0],[0,-7.491],[0,0],[1.675,0],[0,0],[0,7.491],[0,0],[-1.675,0]],"v":[[11.785,17.813],[11.785,-17.813],[14.818,-31.378],[27.024,-31.378],[30.057,-17.813],[30.057,17.813],[27.024,31.378],[14.818,31.378]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0},"t":194,"s":[{"i":[[0,7.491],[0,0],[-7.491,0],[0,0],[0,-7.491],[0,0],[7.491,0],[0,0]],"o":[[0,0],[0,-7.491],[0,0],[7.491,0],[0,0],[0,7.491],[0,0],[-7.491,0]],"v":[[-40.86,17.813],[-40.86,-17.813],[-27.296,-31.378],[27.296,-31.378],[40.86,-17.813],[40.86,17.813],[27.296,31.378],[-27.296,31.378]],"c":true}]},{"t":210,"s":[{"i":[[0,7.491],[0,0],[-7.491,0],[0,0],[0,-7.491],[0,0],[7.491,0],[0,0]],"o":[[0,0],[0,-7.491],[0,0],[7.491,0],[0,0],[0,7.491],[0,0],[-7.491,0]],"v":[[-42.27,17.833],[-40.86,-17.813],[-27.296,-31.378],[27.296,-31.378],[40.86,-17.813],[40.86,17.813],[27.296,31.378],[-28.706,31.398]],"c":true}]}]},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":0,"k":[0.588235294118,0.466666696586,0.325490196078,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":8},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"gf","o":{"a":0,"k":100},"r":1,"bm":0,"g":{"p":7,"k":{"a":0,"k":[0,0.969,0.882,0.451,0.007,0.984,0.941,0.725,0.015,1,1,1,0.233,1,1,1,0.45,1,1,1,0.46,0.984,0.941,0.725,0.47,0.969,0.882,0.451]}},"s":{"a":1,"k":[{"i":{"x":0.667,"y":0.779},"o":{"x":0.333,"y":0},"t":174,"s":[40.307,-3.438],"to":[0,0],"ti":[0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.233,"y":1},"t":180,"s":[-58.119,-1.804],"to":[0,0],"ti":[0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":190,"s":[-83.342,-4.221],"to":[0,0],"ti":[0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":210,"s":[-83.342,-4.221],"to":[0,0],"ti":[0,0]},{"t":226,"s":[40.307,-3.438]}]},"e":{"a":1,"k":[{"i":{"x":0.667,"y":0.265},"o":{"x":0.333,"y":0},"t":174,"s":[100,0],"to":[0,0],"ti":[0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0.237},"t":180,"s":[135.751,4.033],"to":[0,0],"ti":[0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":190,"s":[-50.395,-2.943],"to":[0,0],"ti":[0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":210,"s":[-50.395,-2.943],"to":[0,0],"ti":[0,0]},{"t":226,"s":[100,0]}]},"t":1,"nm":"gggggd","hd":false},{"ty":"tr","p":{"a":0,"k":[269.332,348.051]},"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 7","bm":0,"hd":false},{"ty":"tr","p":{"a":0,"k":[269.332,348.051]},"a":{"a":0,"k":[269.332,348.051]},"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 1","bm":0,"hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":174,"s":[{"i":[[0,2.578],[0,0],[1.2,0],[0,0],[0,-5.369],[0,0],[-1.2,0],[0,0],[-0.408,1.823],[0,0]],"o":[[0,0],[0,-5.369],[0,0],[-1.2,0],[0,0],[0,5.369],[0,0],[0.576,0],[0,0],[0.408,-1.823]],"v":[[20.073,13.272],[20.073,-39.693],[17.899,-49.415],[-14.145,-49.415],[-16.319,-39.693],[-16.319,39.693],[-14.145,49.415],[11.992,49.415],[13.529,46.567],[19.436,20.146]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0},"t":194,"s":[{"i":[[0,2.578],[0,0],[5.369,0],[0,0],[0,-5.369],[0,0],[-5.369,0],[0,0],[-1.823,1.823],[0,0]],"o":[[0,0],[0,-5.369],[0,0],[-5.369,0],[0,0],[0,5.369],[0,0],[2.578,0],[0,0],[1.823,-1.823]],"v":[[81.38,13.272],[81.38,-39.693],[71.659,-49.415],[-71.659,-49.415],[-81.38,-39.693],[-81.38,39.693],[-71.659,49.415],[45.237,49.415],[52.111,46.567],[78.533,20.146]],"c":true}]},{"t":210,"s":[{"i":[[0,2.578],[0,0],[2.461,0],[0,0],[0,-5.369],[0,0],[-5.369,0],[0,0],[-0.836,1.823],[0,0]],"o":[[0,0],[0,-5.369],[0,0],[-5.369,0],[0,0],[0,5.369],[0,0],[1.182,0],[0,0],[0.836,-1.823]],"v":[[46.763,13.486],[46.763,-39.48],[42.306,-49.201],[-71.659,-49.415],[-81.38,-39.693],[-86.081,39.76],[-76.359,49.482],[30.195,49.629],[33.346,46.781],[45.457,20.36]],"c":true}]}]},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":0,"k":[0,0.360784313725,0.478431372549,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":10},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.298314921061,0.626238116096,1,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[293.859,350.706]},"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}],"ip":174,"op":212,"st":0,"bm":0},{"ddd":0,"ind":24,"ty":4,"nm":"sim","parent":20,"sr":1,"ks":{"r":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.676],"y":[0]},"t":120,"s":[2.981]},{"i":{"x":[0.843],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":130,"s":[-87]},{"i":{"x":[0.28],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":136,"s":[-84.422]},{"i":{"x":[0.28],"y":[1]},"o":{"x":[0.72],"y":[0]},"t":140,"s":[-84.422]},{"i":{"x":[0.525],"y":[1]},"o":{"x":[0.773],"y":[0]},"t":146,"s":[-75.422]},{"t":166,"s":[-444.422]}]},"p":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":90,"s":[6.153,1.95,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":98,"s":[-56.802,-1.745,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":0.667},"o":{"x":0.333,"y":0.333},"t":102,"s":[-43.298,-2.247,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":112,"s":[-43.298,-2.247,0],"to":[0,0,0],"ti":[0,0,0]},{"t":128,"s":[-146.635,-5.011,0],"h":1},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":140,"s":[-146.635,-5.011,0],"to":[0,0,0],"ti":[8.699,-11.94,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.182,"y":0},"t":146,"s":[-162.284,28.159,0],"to":[-3.342,-34.908,0],"ti":[151.73,-82.575,0]},{"t":166,"s":[-335.962,-231.985,0]}]},"a":{"a":0,"k":[293.859,350.706,0]},"s":{"a":1,"k":[{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":90,"s":[80.016,99.507,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":100,"s":[105,99.507,100]},{"i":{"x":[0.28,0.28,0.28],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":104,"s":[100.016,100,100]},{"i":{"x":[0.28,0.28,0.28],"y":[1,1,1]},"o":{"x":[1,1,0.72],"y":[0,0,0]},"t":140,"s":[100.016,99.507,100]},{"i":{"x":[0.88,0.88,0.88],"y":[1,1,1]},"o":{"x":[1,1,0.72],"y":[0,0,0]},"t":148,"s":[100.016,99.507,100]},{"t":166,"s":[0,0,100]}]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0.167},"t":112,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[13.908,0],[-13.908,0]],"c":false}]},{"t":128,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[13.908,0],[-13.908,0]],"c":false}],"h":1},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":148,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[13.908,0],[-13.908,0]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":162,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-2.404,-4.488],[-7.911,-4.488]],"c":false}]},{"t":172,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[13.908,0],[-13.908,0]],"c":false}]}]},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":1,"k":[{"i":{"x":[0.15],"y":[1]},"o":{"x":[0.85],"y":[0]},"t":154,"s":[0.588710171569,0.46798993279,0.326721520517,1]},{"t":158,"s":[0.968627512455,0.882353007793,0.450980424881,1]}]},"o":{"a":0,"k":100},"w":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.333],"y":[0]},"t":146,"s":[6]},{"t":166,"s":[12]}]},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"tr","p":{"a":0,"k":[296.227,358.747]},"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 1","bm":0,"hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0.167},"t":112,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[13.908,0],[-13.908,0]],"c":false}]},{"t":128,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[13.908,0],[-13.908,0]],"c":false}],"h":1},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":148,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[13.908,0],[-13.908,0]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":162,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-2.404,3.839],[-7.911,3.839]],"c":false}]},{"t":172,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[13.908,0],[-13.908,0]],"c":false}]}]},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":1,"k":[{"i":{"x":[0.15],"y":[1]},"o":{"x":[0.85],"y":[0]},"t":154,"s":[0.588710171569,0.46798993279,0.326721520517,1]},{"t":158,"s":[0.968627512455,0.882353007793,0.450980424881,1]}]},"o":{"a":0,"k":100},"w":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.333],"y":[0]},"t":146,"s":[6]},{"t":166,"s":[12]}]},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"tr","p":{"a":0,"k":[296.227,337.996]},"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":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0.167},"t":112,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[13.438,0.007],[-14.848,0.013]],"c":false}]},{"t":128,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[13.908,0],[-13.908,0]],"c":false}],"h":1},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":148,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[13.908,0],[-13.908,0]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":162,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[40.783,-4.488],[35.277,-4.488]],"c":false}]},{"t":172,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[13.908,0],[-13.908,0]],"c":false}]}]},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":1,"k":[{"i":{"x":[0.15],"y":[1]},"o":{"x":[0.85],"y":[0]},"t":154,"s":[0.588710171569,0.46798993279,0.326721520517,1]},{"t":158,"s":[0.968627512455,0.882353007793,0.450980424881,1]}]},"o":{"a":0,"k":100},"w":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.333],"y":[0]},"t":146,"s":[6]},{"t":166,"s":[12]}]},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"tr","p":{"a":0,"k":[242.38,358.747]},"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 3","bm":0,"hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0.167},"t":112,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[13.908,0],[-13.908,0]],"c":false}]},{"t":128,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[13.908,0],[-13.908,0]],"c":false}],"h":1},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":148,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[13.908,0],[-13.908,0]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":162,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[40.783,3.839],[35.277,3.839]],"c":false}]},{"t":172,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[13.908,0],[-13.908,0]],"c":false}]}]},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":1,"k":[{"i":{"x":[0.15],"y":[1]},"o":{"x":[0.85],"y":[0]},"t":154,"s":[0.588710171569,0.46798993279,0.326721520517,1]},{"t":158,"s":[0.968627512455,0.882353007793,0.450980424881,1]}]},"o":{"a":0,"k":100},"w":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.333],"y":[0]},"t":146,"s":[6]},{"t":166,"s":[12]}]},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"tr","p":{"a":0,"k":[242.38,337.996]},"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 4","bm":0,"hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0.167},"t":112,"s":[{"i":[[5.755,7.546],[-4.883,7.15],[3.836,5.057],[-5.24,6.626]],"o":[[-5.755,-7.546],[4.883,-7.15],[-3.836,-5.057],[5.24,-6.626]],"v":[[0.658,30.889],[0.658,9.567],[-0.456,-9.567],[0.301,-30.889]],"c":false}]},{"t":128,"s":[{"i":[[5.755,7.546],[-4.883,7.15],[3.836,5.057],[-5.24,6.626]],"o":[[-5.755,-7.546],[4.883,-7.15],[-3.836,-5.057],[5.24,-6.626]],"v":[[0.658,30.889],[0.658,9.567],[-0.456,-9.567],[0.301,-30.889]],"c":false}],"h":1},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":148,"s":[{"i":[[5.755,7.546],[-4.883,7.15],[3.836,5.057],[-5.24,6.626]],"o":[[-5.755,-7.546],[4.883,-7.15],[-3.836,-5.057],[5.24,-6.626]],"v":[[0.658,30.889],[0.658,9.567],[-0.456,-9.567],[0.301,-30.889]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":162,"s":[{"i":[[1.139,4.518],[-0.967,4.28],[0.759,3.028],[-1.037,3.967]],"o":[[-1.139,-4.518],[0.967,-4.28],[-0.759,-3.028],[1.037,-3.967]],"v":[[5.761,18.493],[5.761,5.728],[5.54,-5.728],[5.69,-18.493]],"c":false}]},{"t":172,"s":[{"i":[[5.755,7.546],[-4.883,7.15],[3.836,5.057],[-5.24,6.626]],"o":[[-5.755,-7.546],[4.883,-7.15],[-3.836,-5.057],[5.24,-6.626]],"v":[[0.658,30.889],[0.658,9.567],[-0.456,-9.567],[0.301,-30.889]],"c":false}]}]},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":1,"k":[{"i":{"x":[0.15],"y":[1]},"o":{"x":[0.85],"y":[0]},"t":154,"s":[0.588710171569,0.46798993279,0.326721520517,1]},{"t":158,"s":[0.968627512455,0.882353007793,0.450980424881,1]}]},"o":{"a":0,"k":100},"w":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.333],"y":[0]},"t":146,"s":[6]},{"t":166,"s":[12]}]},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"tr","p":{"a":0,"k":[282.776,347.563]},"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 5","bm":0,"hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0.167},"t":112,"s":[{"i":[[-5.755,-7.546],[4.883,-7.15],[-3.836,-5.057],[5.24,-6.626]],"o":[[5.755,7.546],[-4.883,7.15],[3.836,5.057],[-5.24,6.626]],"v":[[-0.357,-30.889],[-0.357,-9.567],[-0.827,11.365],[-1.41,30.909]],"c":false}]},{"t":128,"s":[{"i":[[-5.755,-7.546],[4.883,-7.15],[-3.836,-5.057],[5.24,-6.626]],"o":[[5.755,7.546],[-4.883,7.15],[3.836,5.057],[-5.24,6.626]],"v":[[-0.357,-30.889],[-0.357,-9.567],[-0.357,11.359],[0,30.889]],"c":false}],"h":1},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":148,"s":[{"i":[[-5.755,-7.546],[4.883,-7.15],[-3.836,-5.057],[5.24,-6.626]],"o":[[5.755,7.546],[-4.883,7.15],[3.836,5.057],[-5.24,6.626]],"v":[[-0.357,-30.889],[-0.357,-9.567],[-0.357,11.359],[0,30.889]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":162,"s":[{"i":[[-1.139,-4.518],[0.967,-4.28],[-0.759,-3.028],[1.037,-3.967]],"o":[[1.139,4.518],[-0.967,4.28],[0.759,3.028],[-1.037,3.967]],"v":[[26.519,-18.493],[26.519,-5.728],[26.519,6.8],[26.589,18.493]],"c":false}]},{"t":172,"s":[{"i":[[-5.755,-7.546],[4.883,-7.15],[-3.836,-5.057],[5.24,-6.626]],"o":[[5.755,7.546],[-4.883,7.15],[3.836,5.057],[-5.24,6.626]],"v":[[-0.357,-30.889],[-0.357,-9.567],[-0.357,11.359],[0,30.889]],"c":false}]}]},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":1,"k":[{"i":{"x":[0.15],"y":[1]},"o":{"x":[0.85],"y":[0]},"t":154,"s":[0.588710171569,0.46798993279,0.326721520517,1]},{"t":158,"s":[0.968627512455,0.882353007793,0.450980424881,1]}]},"o":{"a":0,"k":100},"w":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.333],"y":[0]},"t":146,"s":[6]},{"t":166,"s":[12]}]},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"tr","p":{"a":0,"k":[256.644,347.563]},"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 6","bm":0,"hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0.167},"t":112,"s":[{"i":[[0,7.491],[0,0],[-7.491,0],[0,0],[0,-7.491],[0,0],[7.491,0],[0,0]],"o":[[0,0],[0,-7.491],[0,0],[7.491,0],[0,0],[0,7.491],[0,0],[-7.491,0]],"v":[[-42.27,17.833],[-40.86,-17.813],[-27.296,-31.378],[27.296,-31.378],[40.86,-17.813],[40.86,17.813],[27.296,31.378],[-28.706,31.398]],"c":true}]},{"t":128,"s":[{"i":[[0,7.491],[0,0],[-7.491,0],[0,0],[0,-7.491],[0,0],[7.491,0],[0,0]],"o":[[0,0],[0,-7.491],[0,0],[7.491,0],[0,0],[0,7.491],[0,0],[-7.491,0]],"v":[[-40.86,17.813],[-40.86,-17.813],[-27.296,-31.378],[27.296,-31.378],[40.86,-17.813],[40.86,17.813],[27.296,31.378],[-27.296,31.378]],"c":true}],"h":1},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":148,"s":[{"i":[[0,7.491],[0,0],[-7.491,0],[0,0],[0,-7.491],[0,0],[7.491,0],[0,0]],"o":[[0,0],[0,-7.491],[0,0],[7.491,0],[0,0],[0,7.491],[0,0],[-7.491,0]],"v":[[-40.86,17.813],[-40.86,-17.813],[-27.296,-31.378],[27.296,-31.378],[40.86,-17.813],[40.86,17.813],[27.296,31.378],[-27.296,31.378]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":162,"s":[{"i":[[0,4.911],[0,0],[-1.624,0],[0,0],[0,-4.911],[0,0],[1.624,0],[0,0]],"o":[[0,0],[0,-4.911],[0,0],[1.624,0],[0,0],[0,4.911],[0,0],[-1.624,0]],"v":[[7.559,11.678],[7.559,-11.678],[10.5,-20.571],[22.334,-20.571],[25.275,-11.678],[25.275,11.678],[22.334,20.571],[10.5,20.571]],"c":true}]},{"t":172,"s":[{"i":[[0,7.491],[0,0],[-7.491,0],[0,0],[0,-7.491],[0,0],[7.491,0],[0,0]],"o":[[0,0],[0,-7.491],[0,0],[7.491,0],[0,0],[0,7.491],[0,0],[-7.491,0]],"v":[[-40.86,17.813],[-40.86,-17.813],[-27.296,-31.378],[27.296,-31.378],[40.86,-17.813],[40.86,17.813],[27.296,31.378],[-27.296,31.378]],"c":true}]}]},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":1,"k":[{"i":{"x":[0.15],"y":[1]},"o":{"x":[0.85],"y":[0]},"t":154,"s":[0.588710171569,0.46798993279,0.326721520517,1]},{"t":158,"s":[0.968627512455,0.882353007793,0.450980424881,1]}]},"o":{"a":0,"k":100},"w":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.333],"y":[0]},"t":146,"s":[8]},{"t":166,"s":[20]}]},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"gf","o":{"a":0,"k":100},"r":1,"bm":0,"g":{"p":7,"k":{"a":0,"k":[0,0.969,0.882,0.451,0.007,0.984,0.941,0.725,0.015,1,1,1,0.233,1,1,1,0.45,1,1,1,0.46,0.984,0.941,0.725,0.47,0.969,0.882,0.451]}},"s":{"a":1,"k":[{"i":{"x":0.667,"y":0.779},"o":{"x":0.333,"y":0},"t":118,"s":[40.307,-3.438],"to":[0,0],"ti":[0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.233,"y":1},"t":124,"s":[-58.119,-1.804],"to":[0,0],"ti":[0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":134,"s":[-83.342,-4.221],"to":[0,0],"ti":[0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":154,"s":[-83.342,-4.221],"to":[0,0],"ti":[0,0]},{"t":170,"s":[40.307,-3.438]}]},"e":{"a":1,"k":[{"i":{"x":0.667,"y":0.265},"o":{"x":0.333,"y":0},"t":118,"s":[100,0],"to":[0,0],"ti":[0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0.237},"t":124,"s":[135.751,4.033],"to":[0,0],"ti":[0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":134,"s":[-50.395,-2.943],"to":[0,0],"ti":[0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":154,"s":[-50.395,-2.943],"to":[0,0],"ti":[0,0]},{"t":170,"s":[100,0]}]},"t":1,"nm":"gggggd","hd":false},{"ty":"tr","p":{"a":0,"k":[269.332,348.051]},"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 7","bm":0,"hd":false},{"ty":"tr","p":{"a":0,"k":[269.332,348.051]},"a":{"a":0,"k":[269.332,348.051]},"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 1","bm":0,"hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0.167},"t":112,"s":[{"i":[[0,2.578],[0,0],[2.461,0],[0,0],[0,-5.369],[0,0],[-5.369,0],[0,0],[-0.836,1.823],[0,0]],"o":[[0,0],[0,-5.369],[0,0],[-5.369,0],[0,0],[0,5.369],[0,0],[1.182,0],[0,0],[0.836,-1.823]],"v":[[46.763,13.486],[46.763,-39.48],[42.306,-49.201],[-71.659,-49.415],[-81.38,-39.693],[-86.081,39.76],[-76.359,49.482],[30.195,49.629],[33.346,46.781],[45.457,20.36]],"c":true}]},{"t":128,"s":[{"i":[[0,2.578],[0,0],[5.369,0],[0,0],[0,-5.369],[0,0],[-5.369,0],[0,0],[-1.823,1.823],[0,0]],"o":[[0,0],[0,-5.369],[0,0],[-5.369,0],[0,0],[0,5.369],[0,0],[2.578,0],[0,0],[1.823,-1.823]],"v":[[81.38,13.272],[81.38,-39.693],[71.659,-49.415],[-71.659,-49.415],[-81.38,-39.693],[-81.38,39.693],[-71.659,49.415],[45.237,49.415],[52.111,46.567],[78.533,20.146]],"c":true}],"h":1},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":148,"s":[{"i":[[0,2.578],[0,0],[5.369,0],[0,0],[0,-5.369],[0,0],[-5.369,0],[0,0],[-1.823,1.823],[0,0]],"o":[[0,0],[0,-5.369],[0,0],[-5.369,0],[0,0],[0,5.369],[0,0],[2.578,0],[0,0],[1.823,-1.823]],"v":[[81.38,13.272],[81.38,-39.693],[71.659,-49.415],[-71.659,-49.415],[-81.38,-39.693],[-81.38,39.693],[-71.659,49.415],[45.237,49.415],[52.111,46.567],[78.533,20.146]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":162,"s":[{"i":[[0,2.578],[0,0],[1.775,0],[0,0],[0,-5.369],[0,0],[-1.775,0],[0,0],[-0.603,1.823],[0,0]],"o":[[0,0],[0,-5.369],[0,0],[-1.775,0],[0,0],[0,5.369],[0,0],[0.853,0],[0,0],[0.603,-1.823]],"v":[[26.909,13.272],[26.909,-39.693],[23.695,-49.415],[-23.695,-49.415],[-26.909,-39.693],[-26.909,39.693],[-23.695,49.415],[14.958,49.415],[17.231,46.567],[25.968,20.146]],"c":true}]},{"t":172,"s":[{"i":[[0,2.578],[0,0],[5.369,0],[0,0],[0,-5.369],[0,0],[-5.369,0],[0,0],[-1.823,1.823],[0,0]],"o":[[0,0],[0,-5.369],[0,0],[-5.369,0],[0,0],[0,5.369],[0,0],[2.578,0],[0,0],[1.823,-1.823]],"v":[[81.38,13.272],[81.38,-39.693],[71.659,-49.415],[-71.659,-49.415],[-81.38,-39.693],[-81.38,39.693],[-71.659,49.415],[45.237,49.415],[52.111,46.567],[78.533,20.146]],"c":true}]}]},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":0,"k":[0.066666666667,0.482352941176,0.121568627451,1]},"o":{"a":0,"k":100},"w":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.333],"y":[0]},"t":146,"s":[10]},{"t":166,"s":[20]}]},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.462745098039,0.752941176471,0.035294117647,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[293.859,350.706]},"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}],"ip":92,"op":300,"st":0,"bm":0},{"ddd":0,"ind":25,"ty":4,"nm":"Shape Layer 15","sr":1,"ks":{"p":{"a":0,"k":[256,256,0]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[-84.812,-40.085],[71,-165.689]],"o":[[44,20.796],[-29.976,69.954]],"v":[[-159,-199.915],[-58,38.689]],"c":false}},"nm":"Path 2","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":150,"s":[100]},{"t":168,"s":[0]}]},"e":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":150,"s":[100]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":158,"s":[100]},{"t":166,"s":[0]}]},"o":{"a":0,"k":0},"m":1,"nm":"Trim Paths 1","hd":false},{"ty":"st","c":{"a":0,"k":[0.462745127958,0.752941236309,0.035294117647,1]},"o":{"a":0,"k":100},"w":{"a":1,"k":[{"i":{"x":[0.654],"y":[0.944]},"o":{"x":[0.298],"y":[0]},"t":150,"s":[5]},{"i":{"x":[0.819],"y":[1.017]},"o":{"x":[0.42],"y":[-0.043]},"t":158,"s":[20]},{"t":163,"s":[5]}]},"lc":2,"lj":2,"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":"Shape 1","bm":0,"hd":false}],"ip":0,"op":300,"st":0,"bm":0},{"ddd":0,"ind":26,"ty":4,"nm":"Shape Layer 14","sr":1,"ks":{"p":{"a":0,"k":[256,256,0]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[-92.352,2.527],[58,-220.43]],"o":[[80,-2.189],[-19.367,73.606]],"v":[[-196,-221.806],[-20,70.43]],"c":false}},"nm":"Path 1","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":148,"s":[100]},{"t":166,"s":[0]}]},"e":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":153,"s":[100]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":159,"s":[54]},{"t":166,"s":[0]}]},"o":{"a":0,"k":0},"m":1,"nm":"Trim Paths 1","hd":false},{"ty":"st","c":{"a":0,"k":[0.462745127958,0.752941236309,0.035294117647,1]},"o":{"a":0,"k":100},"w":{"a":1,"k":[{"i":{"x":[0.654],"y":[0.942]},"o":{"x":[0.298],"y":[0]},"t":153,"s":[5]},{"i":{"x":[0.819],"y":[1.032]},"o":{"x":[0.42],"y":[-0.083]},"t":159,"s":[20]},{"t":166,"s":[5]}]},"lc":2,"lj":2,"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":"Shape 1","bm":0,"hd":false}],"ip":0,"op":300,"st":0,"bm":0},{"ddd":0,"ind":27,"ty":4,"nm":"Layer 6","parent":20,"sr":1,"ks":{"p":{"a":0,"k":[4.03,-0.011,0]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.65,"y":0},"t":60,"s":[{"i":[[0,0],[-1.953,28.612],[0,0],[-26.105,0],[0,0],[1.865,-27.295],[0,0],[25.412,0]],"o":[[-26.617,0],[0,0],[1.784,-26.143],[0,0],[27.368,0],[0,0],[-1.905,27.916],[0,0]],"v":[[-58.633,136.882],[-91.382,96.428],[-78.08,-98.529],[-37.144,-136.985],[49.227,-137.44],[86.841,-96.987],[73.539,97.97],[35.914,136.422]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.333,"y":0},"t":78,"s":[{"i":[[0,0],[-1.754,28.612],[0,0],[-26.435,0],[0,0],[1.674,-27.295],[0,0],[25.733,0]],"o":[[-26.954,0],[0,0],[1.602,-26.143],[0,0],[27.714,0],[0,0],[-1.71,27.916],[0,0]],"v":[[-56.066,136.789],[-89.546,96.335],[-77.605,-98.611],[-36.461,-137.067],[46.658,-137.065],[85.064,-96.612],[73.124,98.334],[35.324,136.786]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":90,"s":[{"i":[[0,0],[-2.751,28.612],[0,0],[-24.785,0],[0,0],[2.625,-27.295],[0,0],[24.127,0]],"o":[[-25.271,0],[0,0],[2.513,-26.143],[0,0],[25.984,0],[0,0],[-2.683,27.916],[0,0]],"v":[[-81.03,136.831],[-110.856,96.377],[-92.111,-98.628],[-52.007,-137.081],[23.599,-136.972],[58.044,-96.519],[39.298,98.485],[2.371,136.937]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0.167},"t":210,"s":[{"i":[[0,0],[-2.751,28.612],[0,0],[-24.785,0],[0,0],[2.625,-27.295],[0,0],[24.127,0]],"o":[[-25.271,0],[0,0],[2.513,-26.143],[0,0],[25.984,0],[0,0],[-2.683,27.916],[0,0]],"v":[[-81.03,136.831],[-110.856,96.377],[-92.111,-98.628],[-52.007,-137.081],[23.599,-136.972],[58.044,-96.519],[39.298,98.485],[2.371,136.937]],"c":true}]},{"i":{"x":0.35,"y":1},"o":{"x":0.333,"y":0},"t":220,"s":[{"i":[[0,0],[-1.754,28.612],[0,0],[-26.435,0],[0,0],[1.674,-27.295],[0,0],[25.733,0]],"o":[[-26.954,0],[0,0],[1.602,-26.143],[0,0],[27.714,0],[0,0],[-1.71,27.916],[0,0]],"v":[[-56.066,136.789],[-89.546,96.335],[-77.605,-98.611],[-36.461,-137.067],[46.658,-137.065],[85.064,-96.612],[73.124,98.334],[35.324,136.786]],"c":true}]},{"t":234,"s":[{"i":[[0,0],[-1.953,28.612],[0,0],[-26.105,0],[0,0],[1.865,-27.295],[0,0],[25.412,0]],"o":[[-26.617,0],[0,0],[1.784,-26.143],[0,0],[27.368,0],[0,0],[-1.905,27.916],[0,0]],"v":[[-58.633,136.882],[-91.382,96.428],[-78.08,-98.529],[-37.144,-136.985],[49.227,-137.44],[86.841,-96.987],[73.539,97.97],[35.914,136.422]],"c":true}]}]},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.84],"y":[0]},"t":60,"s":[0.38431372549,0.062745098039,0.647058823529,1]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":90,"s":[0.552941176471,0.003921568627,0.996078491211,1]},{"i":{"x":[0.16],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":210,"s":[0.552941176471,0.003921568627,0.996078491211,1]},{"t":234,"s":[0.38431372549,0.062745098039,0.647058823529,1]}]},"o":{"a":0,"k":100},"w":{"a":0,"k":10},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"fl","c":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.84],"y":[0]},"t":60,"s":[0.38431372549,0.062745098039,0.647058823529,1]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":90,"s":[0.552941176471,0.003921568627,0.996078491211,1]},{"i":{"x":[0.16],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":210,"s":[0.552941176471,0.003921568627,0.996078491211,1]},{"t":234,"s":[0.38431372549,0.062745098039,0.647058823529,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 1","bm":0,"hd":false}],"ip":0,"op":300,"st":0,"bm":0},{"ddd":0,"ind":28,"ty":4,"nm":"eye 2","parent":32,"sr":1,"ks":{"p":{"a":1,"k":[{"i":{"x":0.667,"y":0.667},"o":{"x":0.333,"y":0.333},"t":60,"s":[138.817,193.029,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":0.667},"o":{"x":0.333,"y":0.333},"t":72,"s":[138.817,193.029,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":112,"s":[138.817,193.029,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":128,"s":[143.686,193.046,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":140,"s":[143.686,193.046,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":0.667},"o":{"x":0.333,"y":0.333},"t":152,"s":[152.299,193.077,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":174,"s":[152.299,193.077,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":192,"s":[138.817,193.029,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":0.667},"o":{"x":0.333,"y":0.333},"t":216,"s":[138.817,193.029,0],"to":[0,0,0],"ti":[0,0,0]},{"t":228,"s":[138.817,193.029,0]}]},"a":{"a":0,"k":[147.88,185.335,0]},"s":{"a":1,"k":[{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":60,"s":[99.787,100,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":72,"s":[99.787,100,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":112,"s":[99.787,100,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":128,"s":[95,100,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":140,"s":[95,100,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":152,"s":[80,100,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":174,"s":[80,100,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":192,"s":[99.787,100,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":216,"s":[99.787,100,100]},{"t":228,"s":[99.787,100,100]}]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":80,"s":[{"i":[[-0.452,-1.863],[3.093,-0.314],[0.452,1.863],[-3.093,0.314]],"o":[[0.452,1.863],[-3.093,0.314],[-0.452,-1.863],[3.093,-0.314]],"v":[[2.407,14.924],[-2.375,18.866],[-8.794,16.062],[-4.012,12.12]],"c":true}]},{"i":{"x":0.833,"y":1},"o":{"x":0.333,"y":0},"t":86,"s":[{"i":[[-0.731,-4.657],[5.005,-0.786],[0.731,4.657],[-5.005,0.786]],"o":[[0.731,4.657],[-5.005,0.786],[-0.731,-4.657],[5.005,-0.786]],"v":[[8.683,1.293],[0.945,11.148],[-9.442,4.139],[-1.704,-5.716]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":170,"s":[{"i":[[-0.731,-4.657],[5.005,-0.786],[0.731,4.657],[-5.005,0.786]],"o":[[0.731,4.657],[-5.005,0.786],[-0.731,-4.657],[5.005,-0.786]],"v":[[8.683,1.293],[0.945,11.148],[-9.442,4.139],[-1.704,-5.716]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":176,"s":[{"i":[[-0.452,-1.863],[3.093,-0.314],[0.452,1.863],[-3.093,0.314]],"o":[[0.452,1.863],[-3.093,0.314],[-0.452,-1.863],[3.093,-0.314]],"v":[[2.407,14.924],[-2.375,18.866],[-8.794,16.062],[-4.012,12.12]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":182,"s":[{"i":[[-0.731,-4.657],[5.005,-0.786],[0.731,4.657],[-5.005,0.786]],"o":[[0.731,4.657],[-5.005,0.786],[-0.731,-4.657],[5.005,-0.786]],"v":[[8.683,1.293],[0.945,11.148],[-9.442,4.139],[-1.704,-5.716]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":188,"s":[{"i":[[-0.452,-1.863],[3.093,-0.314],[0.452,1.863],[-3.093,0.314]],"o":[[0.452,1.863],[-3.093,0.314],[-0.452,-1.863],[3.093,-0.314]],"v":[[2.407,14.924],[-2.375,18.866],[-8.794,16.062],[-4.012,12.12]],"c":true}]},{"i":{"x":0.833,"y":1},"o":{"x":0.333,"y":0},"t":194,"s":[{"i":[[-0.731,-4.657],[5.005,-0.786],[0.731,4.657],[-5.005,0.786]],"o":[[0.731,4.657],[-5.005,0.786],[-0.731,-4.657],[5.005,-0.786]],"v":[[8.683,1.293],[0.945,11.148],[-9.442,4.139],[-1.704,-5.716]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":228,"s":[{"i":[[-0.731,-4.657],[5.005,-0.786],[0.731,4.657],[-5.005,0.786]],"o":[[0.731,4.657],[-5.005,0.786],[-0.731,-4.657],[5.005,-0.786]],"v":[[8.683,1.293],[0.945,11.148],[-9.442,4.139],[-1.704,-5.716]],"c":true}]},{"t":234,"s":[{"i":[[-0.452,-1.863],[3.093,-0.314],[0.452,1.863],[-3.093,0.314]],"o":[[0.452,1.863],[-3.093,0.314],[-0.452,-1.863],[3.093,-0.314]],"v":[[2.407,14.924],[-2.375,18.866],[-8.794,16.062],[-4.012,12.12]],"c":true}]}]},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":1,"k":[{"i":{"x":[0],"y":[1]},"o":{"x":[1],"y":[0]},"t":80,"s":[0,0,0,1]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[1],"y":[0]},"t":86,"s":[1,1,1,1]},{"i":{"x":[0],"y":[1]},"o":{"x":[1],"y":[0]},"t":170,"s":[1,1,1,1]},{"i":{"x":[0],"y":[1]},"o":{"x":[1],"y":[0]},"t":176,"s":[0,0,0,1]},{"i":{"x":[0],"y":[1]},"o":{"x":[1],"y":[0]},"t":182,"s":[1,1,1,1]},{"i":{"x":[0],"y":[1]},"o":{"x":[1],"y":[0]},"t":188,"s":[0,0,0,1]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[1],"y":[0]},"t":194,"s":[1,1,1,1]},{"i":{"x":[0],"y":[1]},"o":{"x":[1],"y":[0]},"t":228,"s":[1,1,1,1]},{"t":234,"s":[0,0,0,1]}]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[149.824,171.565]},"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 1","bm":0,"hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":80,"s":[{"i":[[5.062,-6.391],[20.249,0.534],[6.627,5.855],[-18.219,-0.566]],"o":[[-5.425,6.85],[-17.702,-0.466],[-6.809,-6.015],[20.458,0.636]],"v":[[27.893,12.284],[-0.054,7.019],[-28.57,12.484],[1.562,-4.579]],"c":true}]},{"i":{"x":0.833,"y":1},"o":{"x":0.333,"y":0},"t":86,"s":[{"i":[[5.531,-16.68],[14.69,4.217],[-5.531,16.68],[-14.69,-4.217]],"o":[[-5.531,16.68],[-14.69,-4.217],[5.531,-16.68],[14.69,4.217]],"v":[[26.599,7.636],[-10.015,30.202],[-26.599,-7.636],[10.015,-30.202]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":170,"s":[{"i":[[5.531,-16.68],[14.69,4.217],[-5.531,16.68],[-14.69,-4.217]],"o":[[-5.531,16.68],[-14.69,-4.217],[5.531,-16.68],[14.69,4.217]],"v":[[26.599,7.636],[-10.015,30.202],[-26.599,-7.636],[10.015,-30.202]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":176,"s":[{"i":[[5.062,-6.391],[20.249,0.534],[6.627,5.855],[-18.219,-0.566]],"o":[[-5.425,6.85],[-17.702,-0.466],[-6.809,-6.015],[20.458,0.636]],"v":[[27.893,12.284],[-0.054,7.019],[-28.57,12.484],[1.562,-4.579]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":182,"s":[{"i":[[5.531,-16.68],[14.69,4.217],[-5.531,16.68],[-14.69,-4.217]],"o":[[-5.531,16.68],[-14.69,-4.217],[5.531,-16.68],[14.69,4.217]],"v":[[26.599,7.636],[-10.015,30.202],[-26.599,-7.636],[10.015,-30.202]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":188,"s":[{"i":[[5.062,-6.391],[20.249,0.534],[6.627,5.855],[-18.219,-0.566]],"o":[[-5.425,6.85],[-17.702,-0.466],[-6.809,-6.015],[20.458,0.636]],"v":[[27.893,12.284],[-0.054,7.019],[-28.57,12.484],[1.562,-4.579]],"c":true}]},{"i":{"x":0.833,"y":1},"o":{"x":0.333,"y":0},"t":194,"s":[{"i":[[5.531,-16.68],[14.69,4.217],[-5.531,16.68],[-14.69,-4.217]],"o":[[-5.531,16.68],[-14.69,-4.217],[5.531,-16.68],[14.69,4.217]],"v":[[26.599,7.636],[-10.015,30.202],[-26.599,-7.636],[10.015,-30.202]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":228,"s":[{"i":[[5.531,-16.68],[14.69,4.217],[-5.531,16.68],[-14.69,-4.217]],"o":[[-5.531,16.68],[-14.69,-4.217],[5.531,-16.68],[14.69,4.217]],"v":[[26.599,7.636],[-10.015,30.202],[-26.599,-7.636],[10.015,-30.202]],"c":true}]},{"t":234,"s":[{"i":[[5.062,-6.391],[20.249,0.534],[6.627,5.855],[-18.219,-0.566]],"o":[[-5.425,6.85],[-17.702,-0.466],[-6.809,-6.015],[20.458,0.636]],"v":[[27.893,12.284],[-0.054,7.019],[-28.57,12.484],[1.562,-4.579]],"c":true}]}]},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":0,"k":[0,0,0,1]},"o":{"a":0,"k":100},"w":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":80,"s":[6]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":86,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":170,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":176,"s":[6]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":182,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":188,"s":[6]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":194,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":228,"s":[0]},{"t":234,"s":[6]}]},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0,0,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[147.88,185.335]},"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":[147.88,185.335]},"a":{"a":0,"k":[147.88,185.335]},"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}],"ip":0,"op":304,"st":0,"bm":0},{"ddd":0,"ind":29,"ty":4,"nm":"eye","parent":32,"sr":1,"ks":{"p":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":60,"s":[307.76,193.862,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":0.667},"o":{"x":0.333,"y":0.333},"t":72,"s":[301.917,193.842,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":112,"s":[301.917,193.842,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":128,"s":[306.786,193.859,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":0.667},"o":{"x":0.333,"y":0.333},"t":140,"s":[306.786,193.859,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":0.667},"o":{"x":0.333,"y":0.333},"t":152,"s":[306.786,193.859,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":174,"s":[306.786,193.859,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":192,"s":[301.917,193.842,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":216,"s":[301.917,193.842,0],"to":[0,0,0],"ti":[0,0,0]},{"t":228,"s":[307.76,193.862,0]}]},"a":{"a":0,"k":[293.018,185.074,0]},"s":{"a":1,"k":[{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":60,"s":[115,100,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":72,"s":[105,100,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":112,"s":[105,100,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":128,"s":[115,100,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":140,"s":[115,100,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":152,"s":[120,100,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":174,"s":[120,100,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":192,"s":[105,100,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":216,"s":[105,100,100]},{"t":228,"s":[115,100,100]}]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":80,"s":[{"i":[[0.393,-2.046],[1.834,0.352],[-0.393,2.046],[-1.834,-0.352]],"o":[[-0.393,2.046],[-1.834,-0.352],[0.393,-2.046],[1.834,0.352]],"v":[[7.462,7.436],[3.43,10.502],[0.819,6.161],[4.851,3.094]],"c":true}]},{"i":{"x":0.833,"y":1},"o":{"x":0.333,"y":0},"t":86,"s":[{"i":[[0,-4.505],[4.505,0],[0,4.505],[-4.505,0]],"o":[[0,4.505],[-4.505,0],[0,-4.505],[4.505,0]],"v":[[8.158,0],[0,8.158],[-8.158,0],[0,-8.158]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":170,"s":[{"i":[[0,-4.505],[4.505,0],[0,4.505],[-4.505,0]],"o":[[0,4.505],[-4.505,0],[0,-4.505],[4.505,0]],"v":[[8.158,0],[0,8.158],[-8.158,0],[0,-8.158]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":176,"s":[{"i":[[0.393,-2.046],[1.834,0.352],[-0.393,2.046],[-1.834,-0.352]],"o":[[-0.393,2.046],[-1.834,-0.352],[0.393,-2.046],[1.834,0.352]],"v":[[7.462,7.436],[3.43,10.502],[0.819,6.161],[4.851,3.094]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":182,"s":[{"i":[[0,-4.505],[4.505,0],[0,4.505],[-4.505,0]],"o":[[0,4.505],[-4.505,0],[0,-4.505],[4.505,0]],"v":[[8.158,0],[0,8.158],[-8.158,0],[0,-8.158]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":188,"s":[{"i":[[0.393,-2.046],[1.834,0.352],[-0.393,2.046],[-1.834,-0.352]],"o":[[-0.393,2.046],[-1.834,-0.352],[0.393,-2.046],[1.834,0.352]],"v":[[7.462,7.436],[3.43,10.502],[0.819,6.161],[4.851,3.094]],"c":true}]},{"i":{"x":0.833,"y":1},"o":{"x":0.333,"y":0},"t":194,"s":[{"i":[[0,-4.505],[4.505,0],[0,4.505],[-4.505,0]],"o":[[0,4.505],[-4.505,0],[0,-4.505],[4.505,0]],"v":[[8.158,0],[0,8.158],[-8.158,0],[0,-8.158]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":228,"s":[{"i":[[0,-4.505],[4.505,0],[0,4.505],[-4.505,0]],"o":[[0,4.505],[-4.505,0],[0,-4.505],[4.505,0]],"v":[[8.158,0],[0,8.158],[-8.158,0],[0,-8.158]],"c":true}]},{"t":234,"s":[{"i":[[0.393,-2.046],[1.834,0.352],[-0.393,2.046],[-1.834,-0.352]],"o":[[-0.393,2.046],[-1.834,-0.352],[0.393,-2.046],[1.834,0.352]],"v":[[7.462,7.436],[3.43,10.502],[0.819,6.161],[4.851,3.094]],"c":true}]}]},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":1,"k":[{"i":{"x":[0],"y":[1]},"o":{"x":[1],"y":[0]},"t":80,"s":[0,0,0,1]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[1],"y":[0]},"t":86,"s":[1,1,1,1]},{"i":{"x":[0],"y":[1]},"o":{"x":[1],"y":[0]},"t":170,"s":[1,1,1,1]},{"i":{"x":[0],"y":[1]},"o":{"x":[1],"y":[0]},"t":176,"s":[0,0,0,1]},{"i":{"x":[0],"y":[1]},"o":{"x":[1],"y":[0]},"t":182,"s":[1,1,1,1]},{"i":{"x":[0],"y":[1]},"o":{"x":[1],"y":[0]},"t":188,"s":[0,0,0,1]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[1],"y":[0]},"t":194,"s":[1,1,1,1]},{"i":{"x":[0],"y":[1]},"o":{"x":[1],"y":[0]},"t":228,"s":[1,1,1,1]},{"t":234,"s":[0,0,0,1]}]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[289.869,171.446]},"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 1","bm":0,"hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":80,"s":[{"i":[[-4.028,-4.701],[-16.852,0.144],[-3.874,5.201],[11.871,-2.293]],"o":[[4.332,5.056],[16.513,-0.141],[3.569,-4.791],[-11.871,2.293]],"v":[[-18.384,5.894],[0.65,-1.771],[20.406,5.307],[-1.229,-11.575]],"c":true}]},{"i":{"x":0.833,"y":1},"o":{"x":0.333,"y":0},"t":86,"s":[{"i":[[-4.427,-16.68],[-11.76,4.217],[4.427,16.68],[11.76,-4.217]],"o":[[4.428,16.68],[11.76,-4.217],[-4.428,-16.68],[-11.76,4.217]],"v":[[-21.293,7.636],[8.017,30.202],[21.293,-7.636],[-8.017,-30.202]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":170,"s":[{"i":[[-4.428,-16.68],[-11.76,4.217],[4.428,16.68],[11.76,-4.217]],"o":[[4.428,16.68],[11.76,-4.217],[-4.428,-16.68],[-11.76,4.217]],"v":[[-21.293,7.636],[8.017,30.202],[21.293,-7.636],[-8.017,-30.202]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":176,"s":[{"i":[[-4.028,-4.701],[-16.852,0.144],[-3.874,5.201],[11.871,-2.293]],"o":[[4.332,5.056],[16.513,-0.141],[3.569,-4.791],[-11.871,2.293]],"v":[[-18.384,5.894],[0.65,-1.771],[20.406,5.307],[-1.229,-11.575]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":182,"s":[{"i":[[-4.427,-16.68],[-11.76,4.217],[4.427,16.68],[11.76,-4.217]],"o":[[4.428,16.68],[11.76,-4.217],[-4.428,-16.68],[-11.76,4.217]],"v":[[-21.293,7.636],[8.017,30.202],[21.293,-7.636],[-8.017,-30.202]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":188,"s":[{"i":[[-4.028,-4.701],[-16.852,0.144],[-3.874,5.201],[11.871,-2.293]],"o":[[4.332,5.056],[16.513,-0.141],[3.569,-4.791],[-11.871,2.293]],"v":[[-18.384,5.894],[0.65,-1.771],[20.406,5.307],[-1.229,-11.575]],"c":true}]},{"i":{"x":0.833,"y":1},"o":{"x":0.333,"y":0},"t":194,"s":[{"i":[[-4.427,-16.68],[-11.76,4.217],[4.427,16.68],[11.76,-4.217]],"o":[[4.428,16.68],[11.76,-4.217],[-4.428,-16.68],[-11.76,4.217]],"v":[[-21.293,7.636],[8.017,30.202],[21.293,-7.636],[-8.017,-30.202]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":228,"s":[{"i":[[-4.428,-16.68],[-11.76,4.217],[4.428,16.68],[11.76,-4.217]],"o":[[4.428,16.68],[11.76,-4.217],[-4.428,-16.68],[-11.76,4.217]],"v":[[-21.293,7.636],[8.017,30.202],[21.293,-7.636],[-8.017,-30.202]],"c":true}]},{"t":234,"s":[{"i":[[-4.028,-4.701],[-16.852,0.144],[-3.874,5.201],[11.871,-2.293]],"o":[[4.332,5.056],[16.513,-0.141],[3.569,-4.791],[-11.871,2.293]],"v":[[-18.384,5.894],[0.65,-1.771],[20.406,5.307],[-1.229,-11.575]],"c":true}]}]},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":0,"k":[0,0,0,1]},"o":{"a":0,"k":100},"w":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":80,"s":[6]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":86,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":170,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":176,"s":[6]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":182,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":188,"s":[6]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":194,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":228,"s":[0]},{"t":234,"s":[6]}]},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0,0,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[293.018,185.074]},"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":[293.018,185.074]},"a":{"a":0,"k":[293.018,185.074]},"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 1","bm":0,"hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"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":[149.824,171.565]},"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 1","bm":0,"hd":false},{"ty":"gr","it":[{"ty":"fl","c":{"a":0,"k":[0,0,0,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[147.88,185.335]},"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":[147.88,185.335]},"a":{"a":0,"k":[147.88,185.335]},"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}],"ip":0,"op":304,"st":0,"bm":0},{"ddd":0,"ind":30,"ty":4,"nm":"beak_bl","parent":31,"sr":1,"ks":{"r":{"a":0,"k":-26.335},"p":{"a":0,"k":[211.876,216.495,0]},"a":{"a":0,"k":[35.051,-0.937,0]},"s":{"a":0,"k":[-100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":112,"s":[{"i":[[0,0],[9.529,12.852]],"o":[[-10.575,1.56],[0,0]],"v":[[31.846,-15.21],[-9.151,-31.298]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":128,"s":[{"i":[[0,0],[9.529,12.852]],"o":[[-10.575,1.56],[0,0]],"v":[[31.846,-15.21],[-9.151,-31.298]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":140,"s":[{"i":[[0,0],[9.529,12.852]],"o":[[-10.575,1.56],[0,0]],"v":[[31.846,-15.21],[-9.151,-31.298]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":152,"s":[{"i":[[0,0],[9.529,12.852]],"o":[[-10.575,1.56],[0,0]],"v":[[43.175,-19.787],[2.178,-35.875]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":174,"s":[{"i":[[0,0],[9.529,12.852]],"o":[[-10.575,1.56],[0,0]],"v":[[42.855,-15.249],[1.859,-31.337]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":192,"s":[{"i":[[0,0],[9.529,12.852]],"o":[[-10.575,1.56],[0,0]],"v":[[37.628,-18.009],[-3.368,-34.097]],"c":false}]},{"t":216,"s":[{"i":[[0,0],[9.529,12.852]],"o":[[-10.575,1.56],[0,0]],"v":[[31.846,-15.21],[-9.151,-31.298]],"c":false}]}]},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":0,"k":[1,0.705882352941,0.517647058824,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":8},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"tr","p":{"a":0,"k":[24.706,22.107]},"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 1","bm":0,"hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":60,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":72,"s":[5]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":84,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":96,"s":[5]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":108,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":120,"s":[5]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":132,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":144,"s":[5]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":156,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":168,"s":[5]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":180,"s":[5]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":192,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":204,"s":[5]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":216,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":228,"s":[5]},{"t":240,"s":[0]}]},"e":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":60,"s":[95]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":72,"s":[100]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":84,"s":[95]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":96,"s":[100]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":108,"s":[95]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":120,"s":[100]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":132,"s":[95]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":144,"s":[100]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":156,"s":[95]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":168,"s":[100]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":180,"s":[100]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":192,"s":[95]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":204,"s":[100]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":216,"s":[95]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":228,"s":[100]},{"t":240,"s":[95]}]},"o":{"a":0,"k":0},"m":1,"nm":"Trim Paths 1","hd":false}],"ip":-14,"op":354,"st":10,"bm":0},{"ddd":0,"ind":31,"ty":4,"nm":"mouth","parent":32,"sr":1,"ks":{"p":{"a":0,"k":[237.401,247.552,0]},"a":{"a":0,"k":[237.401,247.552,0]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":112,"s":[{"i":[[33.146,5.228],[-7.617,-0.476],[0,0]],"o":[[0,0],[7.617,0.476],[-36.437,2.698]],"v":[[-67.852,0.563],[-17.759,4.038],[49.944,0.695]],"c":true}]},{"t":128,"s":[{"i":[[33.146,5.228],[-7.617,-0.476],[0,0]],"o":[[0,0],[7.617,0.476],[-36.437,2.698]],"v":[[-67.852,0.563],[-17.759,4.038],[49.944,0.695]],"c":true}]}]},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":0,"k":[0.490196079016,0.035294119269,0.035294119269,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":10},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"tr","p":{"a":0,"k":[237.401,247.552]},"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 1","bm":0,"hd":false},{"ty":"fl","c":{"a":0,"k":[0.490196078431,0.035294117647,0.035294117647,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false}],"ip":0,"op":304,"st":0,"bm":0},{"ddd":0,"ind":32,"ty":4,"nm":"beak","parent":35,"sr":1,"ks":{"r":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":60,"s":[-0.134]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":72,"s":[-0.134]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":116,"s":[-0.134]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":132,"s":[-0.134]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":144,"s":[-0.134]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":156,"s":[6]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":178,"s":[7.771]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":196,"s":[-10]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":206,"s":[-0.134]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":216,"s":[-0.134]},{"t":228,"s":[-0.134]}]},"p":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":60,"s":[6.825,60.141,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":0.667},"o":{"x":0.333,"y":0.333},"t":72,"s":[26.289,70.441,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":112,"s":[26.289,70.441,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":0.667},"o":{"x":0.333,"y":0.333},"t":128,"s":[9.223,89.945,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":140,"s":[9.223,89.945,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":152,"s":[-42.294,11.783,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":174,"s":[-33.624,88.865,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":0.667},"o":{"x":0.333,"y":0.333},"t":192,"s":[26.289,70.441,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":216,"s":[26.289,70.441,0],"to":[0,0,0],"ti":[0,0,0]},{"t":228,"s":[6.825,60.141,0]}]},"a":{"a":0,"k":[227.021,227.06,0]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":112,"s":[{"i":[[12.67,4.843],[26.569,-0.895],[38.329,-5.184],[-1.527,-10.216],[-6.604,-0.924],[-33.038,1.174],[7.149,7.125]],"o":[[-22.616,-8.645],[-20.157,0.679],[-15.975,2.16],[0.912,7.325],[45.699,6.397],[11.541,-0.41],[12.67,-12.213]],"v":[[42.778,2.247],[0.134,-43.954],[-56.562,-0.787],[-76.4,20.973],[-64.732,37.374],[51.997,39.136],[61.526,18.975]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":128,"s":[{"i":[[10.355,4.062],[17.947,0.289],[29.75,-3.088],[-1.467,-9.194],[-6.347,-0.832],[-26.436,1.174],[0.444,17.051]],"o":[[-20.875,-8.189],[-18.096,-0.291],[-15.409,1.6],[0.876,6.592],[43.921,5.757],[9.235,-0.41],[-0.444,-17.051]],"v":[[43.983,2.761],[-2.103,-38.666],[-57.394,3.669],[-76.46,23.253],[-65.246,38.014],[51.361,39.136],[68.329,21.585]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":140,"s":[{"i":[[10.355,4.062],[17.947,0.289],[29.75,-3.088],[-1.467,-9.194],[-6.347,-0.832],[-26.436,1.174],[0.444,17.051]],"o":[[-20.875,-8.189],[-18.096,-0.291],[-15.409,1.6],[0.876,6.592],[43.921,5.757],[9.235,-0.41],[-0.444,-17.051]],"v":[[43.983,2.761],[-2.103,-38.666],[-57.394,3.669],[-76.46,23.253],[-65.246,38.014],[51.361,39.136],[68.329,21.585]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":152,"s":[{"i":[[10.355,4.062],[23.28,2.939],[29.75,-3.088],[-9.177,-8.492],[-6.347,-0.832],[-31.934,6.314],[0.444,17.051]],"o":[[-20.875,-8.189],[-21.351,-2.695],[-15.409,1.6],[-9.719,6.921],[43.921,5.757],[9.068,-1.793],[-0.444,-17.051]],"v":[[36.202,0.164],[2.318,-49.44],[-57.394,3.669],[-65.738,20.722],[-65.246,38.014],[51.361,39.136],[68.329,21.585]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":174,"s":[{"i":[[11.029,1.444],[23.28,2.939],[29.75,-3.088],[-9.177,-8.492],[-6.156,-1.753],[-30.244,12.038],[2.189,10.683]],"o":[[-17.364,-2.273],[-21.351,-2.695],[-15.409,1.6],[-9.719,6.921],[41.809,11.908],[12.417,-4.942],[-3.424,-16.71]],"v":[[42.32,-0.556],[-5.089,-38.611],[-57.394,3.669],[-65.738,20.722],[-65.235,34.931],[64.034,35.18],[77.687,14.942]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":192,"s":[{"i":[[12.67,4.843],[26.569,-0.895],[38.329,-5.184],[-1.527,-10.216],[-6.604,-0.924],[-33.038,1.174],[7.149,7.125]],"o":[[-22.616,-8.645],[-20.157,0.679],[-15.975,2.16],[0.912,7.325],[45.699,6.397],[11.541,-0.41],[12.67,-12.213]],"v":[[42.778,2.247],[0.134,-43.954],[-56.562,-0.787],[-76.4,20.973],[-64.732,37.374],[51.997,39.136],[61.526,18.975]],"c":true}]},{"t":216,"s":[{"i":[[12.67,4.843],[26.569,-0.895],[38.329,-5.184],[-1.527,-10.216],[-6.604,-0.924],[-33.038,1.174],[7.149,7.125]],"o":[[-22.616,-8.645],[-20.157,0.679],[-15.975,2.16],[0.912,7.325],[45.699,6.397],[11.541,-0.41],[12.67,-12.213]],"v":[[42.778,2.247],[0.134,-43.954],[-56.562,-0.787],[-76.4,20.973],[-64.732,37.374],[51.997,39.136],[61.526,18.975]],"c":true}]}]},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":0,"k":[0.811764717102,0.207843139768,0.007843137719,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":10},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"fl","c":{"a":0,"k":[1,0.364705890417,0.121568627656,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[227.021,227.06]},"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}],"ip":0,"op":304,"st":0,"bm":0},{"ddd":0,"ind":33,"ty":4,"nm":"head_bl2","parent":35,"sr":1,"ks":{"p":{"a":0,"k":[121.325,22.259,0]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[0,0],[0,-35.646],[19.005,-18.433]],"o":[[28.147,25.502],[0,28.584],[0,0]],"v":[[-22.887,-83.863],[22.887,12.639],[-7.452,83.863]],"c":false}},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":0,"k":[0.988235294819,0.933333337307,0.129411771894,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":10},"lc":2,"lj":2,"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":"Group 1","bm":0,"hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":60,"s":[5]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":72,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":84,"s":[5]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":96,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":108,"s":[5]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":120,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":132,"s":[5]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":144,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":156,"s":[5]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":168,"s":[5]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":180,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":192,"s":[5]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":204,"s":[5]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":216,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":228,"s":[5]},{"t":240,"s":[5]}]},"e":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":60,"s":[100]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":72,"s":[95]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":84,"s":[100]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":96,"s":[95]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":108,"s":[100]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":120,"s":[95]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":132,"s":[100]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":144,"s":[95]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":156,"s":[100]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":168,"s":[100]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":180,"s":[95]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":192,"s":[100]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":204,"s":[100]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":216,"s":[95]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":228,"s":[100]},{"t":240,"s":[100]}]},"o":{"a":0,"k":0},"m":1,"nm":"Trim Paths 1","hd":false}],"ip":0,"op":304,"st":0,"bm":0},{"ddd":0,"ind":34,"ty":4,"nm":"head_bl1","parent":35,"sr":1,"ks":{"r":{"a":0,"k":-21.149},"p":{"a":0,"k":[-15.163,40.193,0]},"a":{"a":0,"k":[71.641,94.652,0]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":112,"s":[{"i":[[0,0],[-26.697,16.101],[-13.876,3.539]],"o":[[11.529,-27.092],[11.933,-7.196],[0,0]],"v":[[-49.05,41.823],[10.169,-25.495],[49.05,-41.823]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":128,"s":[{"i":[[0,0],[-26.698,17.712],[-13.876,3.893]],"o":[[11.529,-29.805],[11.933,-7.917],[0,0]],"v":[[-49.05,41.823],[10.169,-32.236],[49.05,-50.199]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":140,"s":[{"i":[[0,0],[-26.698,17.712],[-13.876,3.893]],"o":[[11.529,-29.805],[11.933,-7.917],[0,0]],"v":[[-49.05,41.823],[10.169,-32.236],[49.05,-50.199]],"c":false}]},{"t":152,"s":[{"i":[[0,0],[-26.697,16.101],[-13.876,3.539]],"o":[[11.529,-27.092],[11.933,-7.196],[0,0]],"v":[[-49.05,41.823],[10.169,-25.495],[49.05,-41.823]],"c":false}]}]},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":10},"lc":2,"lj":2,"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":"Group 1","bm":0,"hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":60,"s":[5]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":72,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":84,"s":[5]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":96,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":108,"s":[5]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":120,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":132,"s":[5]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":144,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":156,"s":[5]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":168,"s":[5]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":180,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":192,"s":[5]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":204,"s":[5]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":216,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":228,"s":[5]},{"t":240,"s":[5]}]},"e":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":60,"s":[100]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":72,"s":[95]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":84,"s":[100]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":96,"s":[95]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":108,"s":[100]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":120,"s":[95]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":132,"s":[100]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":144,"s":[95]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":156,"s":[100]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":168,"s":[100]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":180,"s":[95]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":192,"s":[100]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":204,"s":[100]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":216,"s":[95]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":228,"s":[100]},{"t":240,"s":[100]}]},"o":{"a":0,"k":0},"m":1,"nm":"Trim Paths 1","hd":false}],"ip":0,"op":304,"st":0,"bm":0},{"ddd":0,"ind":35,"ty":4,"nm":"head","parent":37,"sr":1,"ks":{"r":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":152,"s":[-0.07]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":170,"s":[-11.109]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":190,"s":[7.381]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":208,"s":[-11.109]},{"t":216,"s":[-0.07]}]},"p":{"a":0,"k":[13.86,-52.631,0]},"a":{"a":0,"k":[0,131.046,0]},"s":{"a":1,"k":[{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":142,"s":[100,100,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":152,"s":[102,98,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":162,"s":[98,102,100]},{"t":172,"s":[100,100,100]}]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":112,"s":[{"i":[[0,0],[0,39.247],[93.266,0],[0,-83.375],[-28.671,-23.75]],"o":[[29.034,-23.938],[0,-83.375],[-93.265,0],[0,39.353],[0,0]],"v":[[122.976,131.046],[168.871,34.404],[0,-131.046],[-168.871,34.404],[-123.254,130.814]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":128,"s":[{"i":[[0,0],[0,41.488],[93.266,0],[0,-88.135],[-28.671,-25.106]],"o":[[29.034,-25.304],[0,-88.135],[-93.265,0],[0,41.6],[0,0]],"v":[[122.976,131.046],[168.871,28.886],[0,-146.008],[-168.871,28.886],[-123.254,130.801]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":140,"s":[{"i":[[0,0],[0,41.488],[93.266,0],[0,-88.135],[-28.671,-25.106]],"o":[[29.034,-25.304],[0,-88.135],[-93.265,0],[0,41.6],[0,0]],"v":[[122.976,131.046],[168.871,28.886],[0,-146.008],[-168.871,28.886],[-123.254,130.801]],"c":false}]},{"i":{"x":0.833,"y":1},"o":{"x":0.333,"y":0},"t":152,"s":[{"i":[[0,0],[0,39.247],[93.266,0],[0,-83.375],[-28.671,-23.75]],"o":[[29.034,-23.938],[0,-83.375],[-93.265,0],[0,39.353],[0,0]],"v":[[122.976,131.046],[168.871,34.404],[0,-131.046],[-168.871,34.404],[-123.254,130.814]],"c":false}]},{"i":{"x":0.833,"y":1},"o":{"x":0.333,"y":0},"t":154,"s":[{"i":[[0,0],[0,39.247],[93.266,0],[0,-83.375],[-28.671,-23.75]],"o":[[29.034,-23.938],[0,-83.375],[-93.265,0],[0,39.353],[0,0]],"v":[[122.976,131.046],[168.871,34.404],[0,-131.046],[-168.871,34.404],[-123.254,130.814]],"c":false}]},{"i":{"x":0.833,"y":1},"o":{"x":0.333,"y":0},"t":170,"s":[{"i":[[0,0],[-3.003,39.132],[92.992,7.135],[6.379,-83.131],[-26.77,-25.874]],"o":[[30.78,-21.646],[6.379,-83.131],[-92.991,-7.135],[-3.011,39.238],[0,0]],"v":[[112.472,139.977],[165.625,47.129],[9.907,-130.755],[-171.126,21.29],[-133.019,120.908]],"c":false}]},{"i":{"x":0.833,"y":1},"o":{"x":0.333,"y":0},"t":190,"s":[{"i":[[0,0],[1.65,39.212],[93.183,-3.921],[-3.506,-83.301],[-29.644,-22.524]],"o":[[28.002,-25.137],[-3.506,-83.301],[-93.182,3.921],[1.655,39.319],[0,0]],"v":[[128.377,125.759],[170.168,27.273],[-5.51,-130.93],[-167.275,41.473],[-117.645,135.881]],"c":false}]},{"i":{"x":0.833,"y":1},"o":{"x":0.333,"y":0},"t":208,"s":[{"i":[[0,0],[-3.351,39.104],[92.925,7.964],[7.119,-83.071],[-26.538,-26.112]],"o":[[30.972,-21.371],[7.119,-83.071],[-92.924,-7.964],[-3.36,39.21],[0,0]],"v":[[111.237,140.989],[165.216,48.619],[11.09,-130.646],[-171.292,19.779],[-134.074,119.732]],"c":false}]},{"t":216,"s":[{"i":[[0,0],[0,39.247],[93.266,0],[0,-83.375],[-28.671,-23.75]],"o":[[29.034,-23.938],[0,-83.375],[-93.265,0],[0,39.353],[0,0]],"v":[[122.976,131.046],[168.871,34.404],[0,-131.046],[-168.871,34.404],[-123.254,130.814]],"c":false}]}]},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":0,"k":[0.980392158031,0.564705908298,0.086274512112,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":10},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"fl","c":{"a":0,"k":[1,0.835294127464,0.152941182256,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 1","bm":0,"hd":false}],"ip":0,"op":304,"st":0,"bm":0},{"ddd":0,"ind":36,"ty":4,"nm":"body_bl","parent":37,"sr":1,"ks":{"p":{"a":0,"k":[-119.736,-0.714,0]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0.833,"y":1},"o":{"x":0.333,"y":0},"t":154,"s":[{"i":[[0.532,30.674],[-7.534,10.558]],"o":[[-0.532,-30.634],[7.534,-10.558]],"v":[[-4.68,39.243],[16.13,-34.978]],"c":false}]},{"i":{"x":0.833,"y":1},"o":{"x":0.333,"y":0},"t":170,"s":[{"i":[[0.532,30.674],[-7.534,10.558]],"o":[[-0.532,-30.634],[7.534,-10.558]],"v":[[-18.107,55.658],[2.703,-18.562]],"c":false}]},{"i":{"x":0.833,"y":1},"o":{"x":0.333,"y":0},"t":190,"s":[{"i":[[0.532,30.674],[-7.534,10.558]],"o":[[-0.532,-30.634],[7.534,-10.558]],"v":[[-1.438,35.627],[19.371,-38.593]],"c":false}]},{"i":{"x":0.833,"y":1},"o":{"x":0.333,"y":0},"t":208,"s":[{"i":[[4.283,30.378],[-6.185,11.401]],"o":[[-4.278,-30.338],[6.185,-11.401]],"v":[[-6.173,61.533],[5.395,-14.676]],"c":false}]},{"t":216,"s":[{"i":[[0.532,30.674],[-7.534,10.558]],"o":[[-0.532,-30.634],[7.534,-10.558]],"v":[[-4.68,39.243],[16.13,-34.978]],"c":false}]}]},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":10},"lc":2,"lj":2,"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":"Group 1","bm":0,"hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":60,"s":[5]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":72,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":84,"s":[5]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":96,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":108,"s":[5]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":120,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":132,"s":[5]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":144,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":156,"s":[5]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":168,"s":[5]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":180,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":192,"s":[5]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":204,"s":[5]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":216,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":228,"s":[5]},{"t":240,"s":[5]}]},"e":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":60,"s":[100]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":72,"s":[95]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":84,"s":[100]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":96,"s":[95]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":108,"s":[100]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":120,"s":[95]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":132,"s":[100]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":144,"s":[95]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":156,"s":[100]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":168,"s":[100]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":180,"s":[95]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":192,"s":[100]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":204,"s":[100]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":216,"s":[95]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":228,"s":[100]},{"t":240,"s":[100]}]},"o":{"a":0,"k":0},"m":1,"nm":"Trim Paths 1","hd":false}],"ip":0,"op":304,"st":0,"bm":0},{"ddd":0,"ind":37,"ty":4,"nm":"body","parent":16,"sr":1,"ks":{"r":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":152,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":170,"s":[8.001]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":190,"s":[-5.672]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":208,"s":[8.001]},{"t":216,"s":[0]}]},"p":{"a":0,"k":[60,60,0]},"a":{"a":0,"k":[0,96.715,0]},"s":{"a":1,"k":[{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":60,"s":[100,100,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":70,"s":[98,102,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":80,"s":[102,98,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":90,"s":[100,100,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":140,"s":[100,100,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":150,"s":[102,98,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":160,"s":[98,102,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":170,"s":[100,100,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":200,"s":[100,100,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":210,"s":[102,98,100]},{"t":220,"s":[100,100,100]}]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0.833,"y":1},"o":{"x":0.333,"y":0},"t":154,"s":[{"i":[[71.236,0],[5.903,43.474],[-2.258,8.046],[-3.176,8.703],[-80.635,0],[-6.187,-98.296]],"o":[[-70.876,0],[-1.544,-11.374],[3.64,-12.969],[26.363,-72.246],[88.008,0],[4.493,71.386]],"v":[[9.675,96.704],[-140.688,40.912],[-139.291,9.007],[-130.851,-17.988],[9.675,-96.715],[170.594,27.852]],"c":true}]},{"i":{"x":0.833,"y":1},"o":{"x":0.333,"y":0},"t":170,"s":[{"i":[[67.887,-11.068],[12.142,42.029],[-0.946,8.299],[-1.722,9.091],[-77.788,0],[-20.63,-96.141]],"o":[[-67.543,11.012],[-3.177,-10.996],[1.525,-13.378],[14.294,-75.464],[84.9,0],[14.982,69.821]],"v":[[0.936,100.7],[-150.719,68.948],[-154.17,37.213],[-150.173,9.235],[14.946,-96.715],[143.968,7.681]],"c":true}]},{"i":{"x":0.833,"y":1},"o":{"x":0.333,"y":0},"t":190,"s":[{"i":[[72.128,5.61],[2.5,43.804],[-2.93,7.843],[-3.176,8.703],[-80.635,0],[1.597,-98.478]],"o":[[-71.763,-5.581],[-0.654,-11.461],[4.723,-12.642],[26.363,-72.246],[88.008,0],[-1.16,71.518]],"v":[[5.171,103.309],[-142.612,35.849],[-138.646,4.154],[-130.851,-17.988],[9.675,-96.715],[173.612,47.342]],"c":true}]},{"i":{"x":0.833,"y":1},"o":{"x":0.333,"y":0},"t":208,"s":[{"i":[[67.774,-11.068],[12.121,42.029],[-0.945,8.299],[-1.719,9.091],[-77.659,0],[-20.595,-96.141]],"o":[[-67.431,11.012],[-3.171,-10.996],[1.523,-13.378],[14.271,-75.464],[84.76,0],[14.957,69.821]],"v":[[10.671,99.32],[-140.733,67.567],[-144.178,35.833],[-140.188,7.855],[24.658,-98.095],[153.466,6.301]],"c":true}]},{"t":216,"s":[{"i":[[71.236,0],[5.903,43.474],[-2.258,8.046],[-3.176,8.703],[-80.635,0],[-6.187,-98.296]],"o":[[-70.876,0],[-1.544,-11.374],[3.64,-12.969],[26.363,-72.246],[88.008,0],[4.493,71.386]],"v":[[9.675,96.704],[-140.688,40.912],[-139.291,9.007],[-130.851,-17.988],[9.675,-96.715],[170.594,27.852]],"c":true}]}]},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":0,"k":[0.980392158031,0.564705908298,0.086274512112,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":10},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"fl","c":{"a":0,"k":[1,0.835294127464,0.152941182256,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 1","bm":0,"hd":false}],"ip":0,"op":304,"st":0,"bm":0},{"ddd":0,"ind":38,"ty":4,"nm":"wing_r","parent":20,"sr":1,"ks":{"r":{"a":0,"k":-10.217},"p":{"a":0,"k":[-47.701,27.595,0]},"a":{"a":0,"k":[-55.027,0,0]},"s":{"a":0,"k":[97.223,102.418,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[0,0],[-1.344,-14.601],[18.156,3.909]],"o":[[29.698,34.178],[7.257,81.386],[0,0]],"v":[[-63.22,-73.982],[42.009,-45.869],[-105.875,19.506]],"c":false}},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":0,"k":[0.980392158031,0.564705908298,0.086274512112,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":10},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"fl","c":{"a":0,"k":[1,0.835294127464,0.152941182256,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 1","bm":0,"hd":false}],"ip":0,"op":304,"st":0,"bm":0}]}],"layers":[{"ddd":0,"ind":1,"ty":0,"nm":"_032_SIM","refId":"comp_0","sr":1,"ks":{"p":{"a":0,"k":[256,256,0]},"a":{"a":0,"k":[256,256,0]}},"ao":0,"w":512,"h":512,"ip":0,"op":180,"st":-60,"bm":0}]} \ No newline at end of file diff --git a/TMessagesProj/src/main/res/raw/utyan_newborn.json b/TMessagesProj/src/main/res/raw/utyan_newborn.json deleted file mode 100644 index 7d6a61feb..000000000 --- a/TMessagesProj/src/main/res/raw/utyan_newborn.json +++ /dev/null @@ -1 +0,0 @@ -{"v":"5.8.1","fr":60,"ip":0,"op":150,"w":512,"h":512,"nm":"_2_chik_noline_referce","ddd":0,"assets":[{"id":"comp_0","nm":"_2_chik_noline_easestop","fr":60,"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"egg_b_tr 6","parent":2,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-18.479,-43.267,0],"ix":2,"l":2},"a":{"a":0,"k":[-18.479,-43.267,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,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-36.71,-90.037],[-12.471,-111.182],[-17.842,-139.982],[-7.757,-147.278]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.717999994755,0.705999970436,0.620000004768,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":8,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[18.23,46.77],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"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":"tm","s":{"a":1,"k":[{"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":79,"s":[0]},{"t":81,"s":[0]}],"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":47,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":54,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":79,"s":[100]},{"t":81,"s":[28]}],"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":81,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"egg_b_tr 5","parent":10,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":-0.355,"ix":10},"p":{"a":0,"k":[146.387,290.13,0],"ix":2,"l":2},"a":{"a":0,"k":[-18.479,-43.267,0],"ix":1,"l":2},"s":{"a":0,"k":[80,80,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]],"o":[[8.08,-7.048],[0,0],[0,0],[0,0]],"v":[[-42.089,-89.053],[-15.239,-111.549],[-17.842,-139.982],[-7.757,-147.278]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.717999994755,0.705999970436,0.620000004768,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":8,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[18.23,46.77],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"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":"tm","s":{"a":1,"k":[{"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":79,"s":[0]},{"t":81,"s":[0]}],"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":47,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":54,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":79,"s":[100]},{"t":81,"s":[28]}],"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":81,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":3,"nm":"grandnull","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[254.153,386.731,0],"ix":2,"l":2},"a":{"a":0,"k":[60,60,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"ip":0,"op":212,"st":0,"bm":0},{"ddd":0,"ind":4,"ty":3,"nm":"NULL CONTROL","parent":3,"sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[1],"y":[0]},"t":0,"s":[0]},{"i":{"x":[0.535],"y":[1]},"o":{"x":[0.536],"y":[0]},"t":11.211,"s":[-9.809]},{"i":{"x":[0],"y":[1]},"o":{"x":[0.473],"y":[0]},"t":19.061,"s":[12.154]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":26.666,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[1],"y":[0]},"t":33.334,"s":[0]},{"i":{"x":[0.535],"y":[1]},"o":{"x":[0.536],"y":[0]},"t":44.547,"s":[-9.809]},{"i":{"x":[0],"y":[1]},"o":{"x":[0.473],"y":[0]},"t":52.395,"s":[12.154]},{"t":60,"s":[0]}],"ix":10},"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":0,"s":[57.77,176.006,0],"to":[0,0,0],"ti":[0,0,0]},{"t":60,"s":[57.77,176.006,0]}],"ix":2,"l":2},"a":{"a":0,"k":[60,60,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"ip":0,"op":212,"st":0,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":"egg_t_6","parent":126,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[181.76,160.78,0],"ix":2,"l":2},"a":{"a":0,"k":[201.509,179.53,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.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[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],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-0.002,-127.966]],"v":[[-181.485,100.295],[-160.692,120.39],[-148.352,105.01],[-136.002,131.24],[-121.102,149.24],[-102.062,124.76],[-94.702,131.24],[-69.362,110.16],[-52.692,106.56],[-43.142,124.76],[-43.142,144.61],[-25.432,133.81],[-13.092,145.13],[-8.972,159.53],[24.967,117.82],[45.487,129.91],[61.478,92.14],[95.938,103.98],[105.198,128.67],[126.277,145.64],[138.038,114.78],[148.908,122.59],[154.568,141.53],[181.509,97.928]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.717999994755,0.705999970436,0.620000004768,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":8,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[201.509,179.53],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"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":"tm","s":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":14,"s":[50]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":20,"s":[29]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":47,"s":[29]},{"t":52,"s":[0]}],"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":14,"s":[50]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":20,"s":[66]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":47,"s":[66]},{"t":52,"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":70,"st":0,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":"egg_t_81","parent":118,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[181.759,159.78,0],"ix":2,"l":2},"a":{"a":0,"k":[201.509,179.53,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":1,"k":[{"i":{"x":0,"y":1},"o":{"x":1,"y":0},"t":70,"s":[{"i":[[0,-127.967],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.453,135.49],[-69.112,114.41],[-52.442,110.81],[-42.892,129.01],[-42.892,148.86],[-25.182,138.06],[-12.842,149.38],[-8.722,163.78],[25.217,122.07],[45.737,134.16],[61.728,96.39],[96.188,108.23],[105.448,132.92],[126.527,149.89],[138.288,119.03],[149.158,126.84],[154.818,145.78]],"c":true}]},{"i":{"x":0.833,"y":1},"o":{"x":1,"y":0},"t":160,"s":[{"i":[[0,-127.967],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.453,135.49],[-69.112,114.41],[-52.442,110.81],[-42.892,129.01],[-42.892,148.86],[-25.182,138.06],[-12.842,149.38],[-8.722,163.78],[25.217,122.07],[45.737,134.16],[61.728,96.39],[96.188,108.23],[105.448,132.92],[126.527,149.89],[138.288,119.03],[149.158,126.84],[154.818,145.78]],"c":true}]},{"t":170,"s":[{"i":[[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[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],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-0.002,-127.966]],"v":[[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.452,135.49],[-69.112,114.41],[-52.442,110.81],[-42.892,129.01],[-42.892,148.86],[-25.182,138.06],[-12.842,149.38],[-8.722,163.78],[25.217,122.07],[45.737,134.16],[61.728,96.39],[96.188,108.23],[105.448,132.92],[126.527,149.89],[138.288,119.03],[149.158,126.84],[154.818,145.78],[181.759,102.178]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.717999994755,0.705999970436,0.620000004768,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":170,"s":[8]},{"t":179,"s":[0]}],"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[201.509,179.53],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"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":170,"op":186,"st":0,"bm":0},{"ddd":0,"ind":7,"ty":4,"nm":"egg_t_23","parent":118,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[181.759,159.78,0],"ix":2,"l":2},"a":{"a":0,"k":[201.509,179.53,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":1,"k":[{"i":{"x":0,"y":1},"o":{"x":1,"y":0},"t":70,"s":[{"i":[[99.14,0],[0,-127.967],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[-99.14,0],[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-0.002,-127.966]],"v":[[0.25,-155.28],[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.452,135.49],[-69.112,114.41],[-52.442,110.81],[-42.892,129.01],[-42.892,148.86],[-25.182,138.06],[-12.842,149.38],[-8.722,163.78],[25.217,122.07],[45.737,134.16],[61.728,96.39],[96.188,108.23],[105.448,132.92],[126.527,149.89],[138.288,119.03],[149.158,126.84],[154.818,145.78],[181.759,102.178]],"c":true}]},{"t":160,"s":[{"i":[[99.14,0],[0,-127.967],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[-99.14,0],[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-0.002,-127.966]],"v":[[0.25,-155.28],[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.452,135.49],[-69.112,114.41],[-52.442,110.81],[-42.892,129.01],[-42.892,148.86],[-25.182,138.06],[-12.842,149.38],[-8.722,163.78],[25.217,122.07],[45.737,134.16],[61.728,96.39],[96.188,108.23],[105.448,132.92],[126.527,149.89],[138.288,119.03],[149.158,126.84],[154.818,145.78],[181.759,102.178]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.717999994755,0.705999970436,0.620000004768,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":8,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[201.509,179.53],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"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":166,"op":170,"st":0,"bm":0},{"ddd":0,"ind":8,"ty":4,"nm":"egg_t_18","parent":118,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[181.759,159.78,0],"ix":2,"l":2},"a":{"a":0,"k":[201.509,179.53,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":1,"k":[{"i":{"x":0,"y":1},"o":{"x":1,"y":0},"t":70,"s":[{"i":[[24.95,-19.767],[0,-89.581],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[58.602,45.959]],"o":[[-58.226,46.131],[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-0.001,-89.939],[-24.778,-19.432]],"v":[[-82.669,-123.861],[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.452,135.49],[-69.112,114.41],[-52.442,110.81],[-42.892,129.01],[-42.892,148.86],[-25.182,138.06],[-12.842,149.38],[-8.722,163.78],[25.217,122.07],[45.737,134.16],[61.728,96.39],[96.188,108.23],[105.448,132.92],[126.527,149.89],[138.288,119.03],[149.158,126.84],[154.818,145.78],[181.759,102.178],[82.468,-124.412]],"c":true}]},{"i":{"x":0.833,"y":1},"o":{"x":1,"y":0},"t":160,"s":[{"i":[[24.95,-19.767],[0,-89.581],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[58.602,45.959]],"o":[[-58.226,46.131],[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-0.001,-89.939],[-24.778,-19.432]],"v":[[-82.669,-123.861],[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.452,135.49],[-69.112,114.41],[-52.442,110.81],[-42.892,129.01],[-42.892,148.86],[-25.182,138.06],[-12.842,149.38],[-8.722,163.78],[25.217,122.07],[45.737,134.16],[61.728,96.39],[96.188,108.23],[105.448,132.92],[126.527,149.89],[138.288,119.03],[149.158,126.84],[154.818,145.78],[181.759,102.178],[82.468,-124.412]],"c":true}]},{"t":165,"s":[{"i":[[46.665,-3.093],[0,-84.4],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[53.231,48.02]],"o":[[-52.841,48.138],[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-0.001,-84.778],[-51.798,-3.447]],"v":[[-92.589,-115.421],[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.452,135.49],[-69.112,114.41],[-52.442,110.81],[-42.892,129.01],[-42.892,148.86],[-25.182,138.06],[-12.842,149.38],[-8.722,163.78],[25.217,122.07],[45.737,134.16],[61.728,96.39],[96.188,108.23],[105.448,132.92],[126.527,149.89],[138.288,119.03],[149.158,126.84],[154.818,145.78],[181.759,102.178],[92.375,-116.068]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.717999994755,0.705999970436,0.620000004768,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":8,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[201.509,179.53],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"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":165,"op":166,"st":0,"bm":0},{"ddd":0,"ind":9,"ty":4,"nm":"egg_t_17","parent":118,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[181.759,159.78,0],"ix":2,"l":2},"a":{"a":0,"k":[201.509,179.53,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":1,"k":[{"i":{"x":0,"y":1},"o":{"x":1,"y":0},"t":70,"s":[{"i":[[32.825,-46.917],[0,-65.144],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[33.991,48.638]],"o":[[-34.038,48.65],[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-0.001,-65.092],[-32.833,-46.981]],"v":[[-125.876,-77.152],[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.452,135.49],[-69.112,114.41],[-52.442,110.81],[-42.892,129.01],[-42.892,148.86],[-25.182,138.06],[-12.842,149.38],[-8.722,163.78],[25.217,122.07],[45.737,134.16],[61.728,96.39],[96.188,108.23],[105.448,132.92],[126.527,149.89],[138.288,119.03],[149.158,126.84],[154.818,145.78],[181.759,102.178],[126.456,-77.038]],"c":true}]},{"i":{"x":0.833,"y":1},"o":{"x":1,"y":0},"t":160,"s":[{"i":[[32.825,-46.917],[0,-65.144],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[33.991,48.638]],"o":[[-34.038,48.65],[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-0.001,-65.092],[-32.833,-46.981]],"v":[[-125.876,-77.152],[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.452,135.49],[-69.112,114.41],[-52.442,110.81],[-42.892,129.01],[-42.892,148.86],[-25.182,138.06],[-12.842,149.38],[-8.722,163.78],[25.217,122.07],[45.737,134.16],[61.728,96.39],[96.188,108.23],[105.448,132.92],[126.527,149.89],[138.288,119.03],[149.158,126.84],[154.818,145.78],[181.759,102.178],[126.456,-77.038]],"c":true}]},{"t":164,"s":[{"i":[[57.71,-3.99],[0,-59.703],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[29.153,47.044]],"o":[[-29.197,47.062],[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-0.001,-59.652],[-47.63,-8.609]],"v":[[-134.133,-64.62],[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.452,135.49],[-69.112,114.41],[-52.442,110.81],[-42.892,129.01],[-42.892,148.86],[-25.182,138.06],[-12.842,149.38],[-8.722,163.78],[25.217,122.07],[45.737,134.16],[61.728,96.39],[96.188,108.23],[105.448,132.92],[126.527,149.89],[138.288,119.03],[149.158,126.84],[154.818,145.78],[181.759,102.178],[134.707,-64.501]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.717999994755,0.705999970436,0.620000004768,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":8,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[201.509,179.53],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"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":164,"op":165,"st":0,"bm":0},{"ddd":0,"ind":10,"ty":4,"nm":"egg_t_16","parent":118,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[181.759,159.78,0],"ix":2,"l":2},"a":{"a":0,"k":[201.509,179.53,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":1,"k":[{"i":{"x":0,"y":1},"o":{"x":1,"y":0},"t":70,"s":[{"i":[[32.591,-71.193],[0,-46.475],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[17.771,39.902]],"o":[[-18.586,40.601],[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-0.001,-45.35],[-32.373,-72.69]],"v":[[-151.809,-31.571],[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.452,135.49],[-69.112,114.41],[-52.442,110.81],[-42.892,129.01],[-42.892,148.86],[-25.182,138.06],[-12.842,149.38],[-8.722,163.78],[25.217,122.07],[45.737,134.16],[61.728,96.39],[96.188,108.23],[105.448,132.92],[126.527,149.89],[138.288,119.03],[149.158,126.84],[154.818,145.78],[181.759,102.178],[153.643,-28.617]],"c":true}]},{"i":{"x":0.833,"y":1},"o":{"x":1,"y":0},"t":160,"s":[{"i":[[32.591,-71.193],[0,-46.475],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[17.771,39.902]],"o":[[-18.586,40.601],[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-0.001,-45.35],[-32.373,-72.69]],"v":[[-151.809,-31.571],[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.452,135.49],[-69.112,114.41],[-52.442,110.81],[-42.892,129.01],[-42.892,148.86],[-25.182,138.06],[-12.842,149.38],[-8.722,163.78],[25.217,122.07],[45.737,134.16],[61.728,96.39],[96.188,108.23],[105.448,132.92],[126.527,149.89],[138.288,119.03],[149.158,126.84],[154.818,145.78],[181.759,102.178],[153.643,-28.617]],"c":true}]},{"t":163,"s":[{"i":[[64.472,-5.011],[0,-42.058],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[14.765,37.016]],"o":[[-15.466,37.737],[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-0.001,-41.017],[-70.454,-16.819]],"v":[[-156.896,-19.837],[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.452,135.49],[-69.112,114.41],[-52.442,110.81],[-42.892,129.01],[-42.892,148.86],[-25.182,138.06],[-12.842,149.38],[-8.722,163.78],[25.217,122.07],[45.737,134.16],[61.728,96.39],[96.188,108.23],[105.448,132.92],[126.527,149.89],[138.288,119.03],[149.158,126.84],[154.818,145.78],[181.759,102.178],[158.53,-17.03]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.717999994755,0.705999970436,0.620000004768,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":8,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[201.509,179.53],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"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":163,"op":164,"st":0,"bm":0},{"ddd":0,"ind":11,"ty":4,"nm":"egg_t_15","parent":118,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[181.759,159.78,0],"ix":2,"l":2},"a":{"a":0,"k":[201.509,179.53,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":1,"k":[{"i":{"x":0,"y":1},"o":{"x":1,"y":0},"t":70,"s":[{"i":[[27.378,-91.558],[0,-31.11],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[8.219,28.496]],"o":[[-8.794,29.408],[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,-30.02],[-26.817,-92.976]],"v":[[-167.598,10.464],[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.452,135.49],[-69.112,114.41],[-52.442,110.81],[-42.892,129.01],[-42.892,148.86],[-25.182,138.06],[-12.842,149.38],[-8.722,163.78],[25.217,122.07],[45.737,134.16],[61.728,96.39],[96.188,108.23],[105.448,132.92],[126.527,149.89],[138.288,119.03],[149.158,126.84],[154.818,145.78],[181.759,102.178],[169.006,13.559]],"c":true}]},{"i":{"x":0.833,"y":1},"o":{"x":1,"y":0},"t":160,"s":[{"i":[[27.378,-91.558],[0,-31.11],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[8.219,28.496]],"o":[[-8.794,29.408],[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,-30.02],[-26.817,-92.976]],"v":[[-167.598,10.464],[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.452,135.49],[-69.112,114.41],[-52.442,110.81],[-42.892,129.01],[-42.892,148.86],[-25.182,138.06],[-12.842,149.38],[-8.722,163.78],[25.217,122.07],[45.737,134.16],[61.728,96.39],[96.188,108.23],[105.448,132.92],[126.527,149.89],[138.288,119.03],[149.158,126.84],[154.818,145.78],[181.759,102.178],[169.006,13.559]],"c":true}]},{"t":162,"s":[{"i":[[107.699,-11.215],[0,-27.992],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[6.72,25.908]],"o":[[-7.196,26.767],[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,-27.004],[-65.795,-15.553]],"v":[[-170.122,19.357],[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.452,135.49],[-69.112,114.41],[-52.442,110.81],[-42.892,129.01],[-42.892,148.86],[-25.182,138.06],[-12.842,149.38],[-8.722,163.78],[25.217,122.07],[45.737,134.16],[61.728,96.39],[96.188,108.23],[105.448,132.92],[126.527,149.89],[138.288,119.03],[149.158,126.84],[154.818,145.78],[181.759,102.178],[171.371,22.195]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.717999994755,0.705999970436,0.620000004768,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":8,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[201.509,179.53],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"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":162,"op":163,"st":0,"bm":0},{"ddd":0,"ind":12,"ty":4,"nm":"egg_t_14","parent":118,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[181.759,159.78,0],"ix":2,"l":2},"a":{"a":0,"k":[201.509,179.53,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":1,"k":[{"i":{"x":0,"y":1},"o":{"x":1,"y":0},"t":70,"s":[{"i":[[85.449,0],[19.735,-106.678],[0,-19.177],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[-84.283,0],[-3.479,18.804],[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,-17.671]],"v":[[0.25,-155.28],[-175.931,44.989],[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.452,135.49],[-69.112,114.41],[-52.442,110.81],[-42.892,129.01],[-42.892,148.86],[-25.182,138.06],[-12.842,149.38],[-8.722,163.78],[25.217,122.07],[45.737,134.16],[61.728,96.39],[96.188,108.23],[105.448,132.92],[126.527,149.89],[138.288,119.03],[149.158,126.84],[154.818,145.78],[181.759,102.178]],"c":true}]},{"i":{"x":0.833,"y":1},"o":{"x":1,"y":0},"t":160,"s":[{"i":[[85.449,0],[19.735,-106.678],[0,-19.177],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[-84.283,0],[-3.479,18.804],[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,-17.671]],"v":[[0.25,-155.28],[-175.931,44.989],[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.452,135.49],[-69.112,114.41],[-52.442,110.81],[-42.892,129.01],[-42.892,148.86],[-25.182,138.06],[-12.842,149.38],[-8.722,163.78],[25.217,122.07],[45.737,134.16],[61.728,96.39],[96.188,108.23],[105.448,132.92],[126.527,149.89],[138.288,119.03],[149.158,126.84],[154.818,145.78],[181.759,102.178]],"c":true}]},{"t":161,"s":[{"i":[[128.521,-14.996],[0,-17.22],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[2.407,15.663]],"o":[[-2.823,16.956],[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,-15.865],[-70.009,-15.999]],"v":[[-176.945,50.759],[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.452,135.49],[-69.112,114.41],[-52.442,110.81],[-42.892,129.01],[-42.892,148.86],[-25.182,138.06],[-12.842,149.38],[-8.722,163.78],[25.217,122.07],[45.737,134.16],[61.728,96.39],[96.188,108.23],[105.448,132.92],[126.527,149.89],[138.288,119.03],[149.158,126.84],[154.818,145.78],[181.759,102.178],[178.086,54.761]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.717999994755,0.705999970436,0.620000004768,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":8,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[201.509,179.53],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"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":161,"op":162,"st":0,"bm":0},{"ddd":0,"ind":13,"ty":4,"nm":"egg_t_13","parent":118,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[181.759,159.78,0],"ix":2,"l":2},"a":{"a":0,"k":[201.509,179.53,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":1,"k":[{"i":{"x":0,"y":1},"o":{"x":1,"y":0},"t":70,"s":[{"i":[[10.689,-118.329],[0,-9.212],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0.538,7.383]],"o":[[-0.829,9.178],[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,-7.398],[-8.768,-120.321]],"v":[[-180.004,74.572],[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.452,135.49],[-69.112,114.41],[-52.442,110.81],[-42.892,129.01],[-42.892,148.86],[-25.182,138.06],[-12.842,149.38],[-8.722,163.78],[25.217,122.07],[45.737,134.16],[61.728,96.39],[96.188,108.23],[105.448,132.92],[126.527,149.89],[138.288,119.03],[149.158,126.84],[154.818,145.78],[181.759,102.178],[180.946,79.994]],"c":true}]},{"t":160,"s":[{"i":[[124.822,-19.096],[0,-8.268],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0.435,6.63]],"o":[[-0.67,8.246],[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,-6.641],[-43.027,-12.465]],"v":[[-180.246,77.393],[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.452,135.49],[-69.112,114.41],[-52.442,110.81],[-42.892,129.01],[-42.892,148.86],[-25.182,138.06],[-12.842,149.38],[-8.722,163.78],[25.217,122.07],[45.737,134.16],[61.728,96.39],[96.188,108.23],[105.448,132.92],[126.527,149.89],[138.288,119.03],[149.158,126.84],[154.818,145.78],[181.759,102.178],[181.103,82.262]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.717999994755,0.705999970436,0.620000004768,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":8,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[201.509,179.53],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"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":160,"op":161,"st":0,"bm":0},{"ddd":0,"ind":14,"ty":4,"nm":"egg_t_12","parent":118,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[181.759,159.78,0],"ix":2,"l":2},"a":{"a":0,"k":[201.509,179.53,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":1,"k":[{"i":{"x":0.833,"y":1},"o":{"x":1,"y":0},"t":70,"s":[{"i":[[99.14,0],[0,-127.967],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[-99.14,0],[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[0.25,-155.28],[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.452,135.49],[-69.112,114.41],[-52.442,110.81],[-42.892,129.01],[-42.892,148.86],[-25.182,138.06],[-12.842,149.38],[-8.722,163.78],[25.217,122.07],[45.737,134.16],[61.728,96.39],[96.188,108.23],[105.448,132.92],[126.527,149.89],[138.288,119.03],[149.158,126.84],[154.818,145.78]],"c":true}]},{"i":{"x":0,"y":1},"o":{"x":0.167,"y":0},"t":159,"s":[{"i":[[82.336,-11.719],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[-0.785,0.112],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-51.683,-20.716]],"v":[[-181.259,99.681],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.452,135.49],[-69.112,114.41],[-52.442,110.81],[-42.892,129.01],[-42.892,148.86],[-25.182,138.06],[-12.842,149.38],[-8.722,163.78],[25.217,122.07],[45.738,134.16],[61.728,96.39],[96.188,108.23],[105.448,132.92],[126.528,149.89],[138.288,119.03],[149.158,126.84],[154.818,145.78],[179.76,104.678]],"c":false}]},{"t":160,"s":[{"i":[[99.14,0],[0,-127.967],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[-99.14,0],[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[0.25,-155.28],[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.452,135.49],[-69.112,114.41],[-52.442,110.81],[-42.892,129.01],[-42.892,148.86],[-25.182,138.06],[-12.842,149.38],[-8.722,163.78],[25.217,122.07],[45.737,134.16],[61.728,96.39],[96.188,108.23],[105.448,132.92],[126.527,149.89],[138.288,119.03],[149.158,126.84],[154.818,145.78]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.717999994755,0.705999970436,0.620000004768,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":8,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[201.509,179.53],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"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":159,"op":160,"st":0,"bm":0},{"ddd":0,"ind":15,"ty":4,"nm":"egg_t_22","parent":118,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[181.759,159.78,0],"ix":2,"l":2},"a":{"a":0,"k":[201.509,179.53,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":1,"k":[{"i":{"x":0.833,"y":1},"o":{"x":1,"y":0},"t":70,"s":[{"i":[[0,0],[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],[-0.002,-127.966]],"v":[[105.448,132.92],[126.527,149.89],[138.288,119.03],[149.158,126.84],[154.818,145.78],[172.972,116.399],[181.759,102.178]],"c":true}]},{"i":{"x":0,"y":1},"o":{"x":0.167,"y":0},"t":158,"s":[{"i":[[0,0],[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],[0,0]],"v":[[97.688,109.23],[105.448,132.92],[126.527,149.89],[138.288,119.03],[149.158,126.84],[154.818,145.78],[171.47,118.83]],"c":false}]},{"t":160,"s":[{"i":[[0,0],[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],[-0.002,-127.966]],"v":[[105.448,132.92],[126.527,149.89],[138.288,119.03],[149.158,126.84],[154.818,145.78],[172.972,116.399],[181.759,102.178]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.717999994755,0.705999970436,0.620000004768,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":8,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[201.509,179.53],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"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":158,"op":159,"st":0,"bm":0},{"ddd":0,"ind":16,"ty":4,"nm":"egg_t_21","parent":118,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[181.759,159.78,0],"ix":2,"l":2},"a":{"a":0,"k":[201.509,179.53,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":1,"k":[{"i":{"x":0.833,"y":1},"o":{"x":1,"y":0},"t":70,"s":[{"i":[[99.14,0],[0,-127.967],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[-99.14,0],[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[0.25,-155.28],[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.452,135.49]],"c":true}]},{"i":{"x":0,"y":1},"o":{"x":0.167,"y":0},"t":158,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-6.645,13.26]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[2.073,-4.137]],"v":[[-53.943,108.31],[-42.892,129.01],[-42.892,148.86],[-25.182,138.06],[-12.842,149.38],[-8.722,163.78],[25.218,122.07],[45.737,134.16],[53.904,108.81]],"c":false}]},{"t":160,"s":[{"i":[[99.14,0],[0,-127.967],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[-99.14,0],[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[0.25,-155.28],[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.452,135.49]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.717999994755,0.705999970436,0.620000004768,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":8,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[201.509,179.53],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"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":158,"op":159,"st":0,"bm":0},{"ddd":0,"ind":17,"ty":4,"nm":"egg_t_11","parent":118,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[181.759,159.78,0],"ix":2,"l":2},"a":{"a":0,"k":[201.509,179.53,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":1,"k":[{"i":{"x":0.833,"y":1},"o":{"x":1,"y":0},"t":70,"s":[{"i":[[0,-127.967],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-181.259,102.181],[-181.235,104.545],[-170.29,115.123],[-160.442,124.64],[-150.966,112.828],[-148.102,109.26],[-147.165,111.251],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.453,135.49]],"c":true}]},{"i":{"x":0,"y":1},"o":{"x":0.167,"y":0},"t":158,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[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],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-170.473,114.946],[-160.442,124.64],[-151.96,114.067],[-148.852,113.51],[-146.017,113.689],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.452,135.49],[-69.112,114.41],[-53.943,108.81]],"c":false}]},{"t":160,"s":[{"i":[[0,-127.967],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-181.259,102.181],[-181.235,104.545],[-170.29,115.123],[-160.442,124.64],[-150.966,112.828],[-148.102,109.26],[-147.165,111.251],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.453,135.49]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.717999994755,0.705999970436,0.620000004768,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":8,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[201.509,179.53],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"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":158,"op":159,"st":0,"bm":0},{"ddd":0,"ind":18,"ty":4,"nm":"egg_t_20","parent":118,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[181.759,159.78,0],"ix":2,"l":2},"a":{"a":0,"k":[201.509,179.53,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":1,"k":[{"i":{"x":0.833,"y":1},"o":{"x":1,"y":0},"t":70,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0.611,6.042]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,-8.372],[-8.722,-86.321]],"v":[[126.527,149.89],[138.288,119.03],[149.158,126.84],[154.818,145.78],[161.03,135.726],[181.759,102.178],[180.822,80.619]],"c":true}]},{"i":{"x":0,"y":1},"o":{"x":0.167,"y":0},"t":157,"s":[{"i":[[0,0],[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],[0,0]],"v":[[102.138,124.095],[105.448,132.92],[126.527,149.89],[135.288,127.53],[149.658,129.09],[154.818,145.78],[163.209,132.2]],"c":false}]},{"t":160,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0.611,6.042]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,-8.372],[-8.722,-86.321]],"v":[[126.527,149.89],[138.288,119.03],[149.158,126.84],[154.818,145.78],[161.03,135.726],[181.759,102.178],[180.822,80.619]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.717999994755,0.705999970436,0.620000004768,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":8,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[201.509,179.53],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"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":157,"op":158,"st":0,"bm":0},{"ddd":0,"ind":19,"ty":4,"nm":"egg_t_19","parent":118,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[181.759,159.78,0],"ix":2,"l":2},"a":{"a":0,"k":[201.509,179.53,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":1,"k":[{"i":{"x":0.833,"y":1},"o":{"x":1,"y":0},"t":70,"s":[{"i":[[-0.685,3.059],[-9.375,11.891],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[1.607,-7.177],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-0.002,-127.966]],"v":[[46.657,129.242],[61.728,96.39],[96.188,108.23],[105.448,132.92],[126.527,149.89],[138.287,119.03],[149.157,126.84],[154.818,145.78],[181.759,102.178]],"c":true}]},{"i":{"x":0,"y":1},"o":{"x":0.167,"y":0},"t":157,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-2.204,7.069]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-20.991,0.003]],"v":[[-46.442,122.81],[-42.892,129.01],[-42.892,148.86],[-25.182,138.06],[-12.842,149.38],[-8.722,163.78],[25.217,122.07],[45.737,134.16],[48.568,122.615]],"c":false}]},{"t":160,"s":[{"i":[[-0.685,3.059],[-9.375,11.891],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[1.607,-7.177],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-0.002,-127.966]],"v":[[46.657,129.242],[61.728,96.39],[96.188,108.23],[105.448,132.92],[126.527,149.89],[138.287,119.03],[149.157,126.84],[154.818,145.78],[181.759,102.178]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.717999994755,0.705999970436,0.620000004768,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":8,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[201.509,179.53],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"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":157,"op":158,"st":0,"bm":0},{"ddd":0,"ind":20,"ty":4,"nm":"egg_t_10","parent":118,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[181.759,159.78,0],"ix":2,"l":2},"a":{"a":0,"k":[201.509,179.53,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":1,"k":[{"i":{"x":0.833,"y":1},"o":{"x":1,"y":0},"t":70,"s":[{"i":[[0,-127.967],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-138.058,130.593],[-135.752,135.49]],"c":true}]},{"i":{"x":0,"y":1},"o":{"x":0.167,"y":0},"t":157,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[1.137,2.415],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-139.163,128.246],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.452,135.49],[-80.718,124.065]],"c":false}]},{"t":160,"s":[{"i":[[0,-127.967],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-138.058,130.593],[-135.752,135.49]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.717999994755,0.705999970436,0.620000004768,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":8,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[201.509,179.53],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"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":157,"op":158,"st":0,"bm":0},{"ddd":0,"ind":21,"ty":4,"nm":"egg_t_80","parent":118,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[181.759,159.78,0],"ix":2,"l":2},"a":{"a":0,"k":[201.509,179.53,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":1,"k":[{"i":{"x":0.833,"y":1},"o":{"x":1,"y":0},"t":70,"s":[{"i":[[99.14,0],[0,-127.967],[-0.007,-0.789],[0,0],[0,0],[0,0]],"o":[[-99.14,0],[0,0.793],[0,0],[0,0],[0,0],[0,0]],"v":[[0.25,-155.28],[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49]],"c":true}]},{"i":{"x":0,"y":1},"o":{"x":0.167,"y":0},"t":83,"s":[{"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":[[-43.892,132.01],[-42.892,148.86],[-25.182,138.06],[-12.842,149.38],[-8.722,163.78],[17.278,131.827]],"c":false}]},{"t":160,"s":[{"i":[[99.14,0],[0,-127.967],[-0.007,-0.789],[0,0],[0,0],[0,0]],"o":[[-99.14,0],[0,0.793],[0,0],[0,0],[0,0],[0,0]],"v":[[0.25,-155.28],[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.717999994755,0.705999970436,0.620000004768,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":8,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[201.509,179.53],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"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":83,"op":84,"st":0,"bm":0},{"ddd":0,"ind":22,"ty":4,"nm":"egg_t_90","parent":118,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[181.759,159.78,0],"ix":2,"l":2},"a":{"a":0,"k":[201.509,179.53,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":1,"k":[{"i":{"x":0.833,"y":1},"o":{"x":1,"y":0},"t":70,"s":[{"i":[[0,-127.967],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01]],"c":true}]},{"i":{"x":0,"y":1},"o":{"x":0.167,"y":0},"t":82,"s":[{"i":[[0,0],[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],[0,0]],"v":[[100.452,120.267],[105.448,132.92],[126.527,149.89],[135.788,123.53],[149.157,126.84],[154.818,145.78],[166.399,127.038]],"c":false}]},{"t":160,"s":[{"i":[[0,-127.967],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.717999994755,0.705999970436,0.620000004768,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":8,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[201.509,179.53],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"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":82,"op":83,"st":0,"bm":0},{"ddd":0,"ind":23,"ty":4,"nm":"egg_t_89","parent":118,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[181.759,159.78,0],"ix":2,"l":2},"a":{"a":0,"k":[201.509,179.53,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":1,"k":[{"i":{"x":0.833,"y":1},"o":{"x":1,"y":0},"t":70,"s":[{"i":[[99.14,0],[0,-127.967],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[-99.14,0],[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[0.25,-155.28],[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.452,135.49]],"c":true}]},{"i":{"x":0,"y":1},"o":{"x":0.167,"y":0},"t":82,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-3.577,9.555]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-44.168,-3.001]],"v":[[-48.947,117.471],[-42.892,129.01],[-42.892,148.86],[-25.182,138.06],[-12.842,149.38],[-8.722,163.78],[25.218,122.07],[45.737,134.16],[50.244,117.222]],"c":false}]},{"t":160,"s":[{"i":[[99.14,0],[0,-127.967],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[-99.14,0],[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[0.25,-155.28],[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.452,135.49]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.717999994755,0.705999970436,0.620000004768,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":8,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[201.509,179.53],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"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":82,"op":83,"st":0,"bm":0},{"ddd":0,"ind":24,"ty":4,"nm":"egg_t_79","parent":118,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[181.759,159.78,0],"ix":2,"l":2},"a":{"a":0,"k":[201.509,179.53,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":1,"k":[{"i":{"x":0.833,"y":1},"o":{"x":1,"y":0},"t":70,"s":[{"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.002,-127.966]],"v":[[105.448,132.92],[126.527,149.89],[138.288,119.03],[149.158,126.84],[154.818,145.78],[181.759,102.178]],"c":true}]},{"i":{"x":0,"y":1},"o":{"x":0.167,"y":0},"t":82,"s":[{"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":[[-142.462,121.239],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.452,135.49],[-72.782,117.29]],"c":false}]},{"t":160,"s":[{"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.002,-127.966]],"v":[[105.448,132.92],[126.527,149.89],[138.288,119.03],[149.158,126.84],[154.818,145.78],[181.759,102.178]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.717999994755,0.705999970436,0.620000004768,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":8,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[201.509,179.53],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"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":82,"op":83,"st":0,"bm":0},{"ddd":0,"ind":25,"ty":4,"nm":"egg_t_78","parent":118,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[181.759,159.78,0],"ix":2,"l":2},"a":{"a":0,"k":[201.509,179.53,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":1,"k":[{"i":{"x":0.833,"y":1},"o":{"x":1,"y":0},"t":70,"s":[{"i":[[99.14,0],[0,-127.967],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0]],"o":[[-99.14,0],[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[0.25,-155.28],[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-98.274,132.126],[-94.453,135.49],[-69.112,114.41],[-52.442,110.81],[-42.892,129.01],[-42.892,148.86],[-25.182,138.06],[-12.842,149.38],[-8.723,163.78],[25.217,122.07],[45.737,134.16],[61.729,96.39],[96.188,108.23],[105.448,132.92],[126.527,149.89],[138.288,119.03]],"c":true}]},{"i":{"x":0,"y":1},"o":{"x":0.167,"y":0},"t":81,"s":[{"i":[[-0.004,-0.401],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[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],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-180.235,105.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.452,135.49],[-69.113,114.41],[-52.442,110.81],[-42.892,129.01],[-42.892,148.86],[-25.182,138.06],[-12.842,149.38],[-8.722,163.78],[25.217,122.07],[45.737,134.16],[61.729,101.39],[96.188,108.23],[105.448,132.92],[126.527,149.89],[138.288,119.03],[149.158,126.84],[154.818,145.78],[177.243,109.487]],"c":false}]},{"t":160,"s":[{"i":[[99.14,0],[0,-127.967],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0]],"o":[[-99.14,0],[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[0.25,-155.28],[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-98.274,132.126],[-94.453,135.49],[-69.112,114.41],[-52.442,110.81],[-42.892,129.01],[-42.892,148.86],[-25.182,138.06],[-12.842,149.38],[-8.723,163.78],[25.217,122.07],[45.737,134.16],[61.729,96.39],[96.188,108.23],[105.448,132.92],[126.527,149.89],[138.288,119.03]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.717999994755,0.705999970436,0.620000004768,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":8,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[201.509,179.53],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"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":81,"op":82,"st":0,"bm":0},{"ddd":0,"ind":26,"ty":4,"nm":"egg_t_77","parent":118,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[181.759,159.78,0],"ix":2,"l":2},"a":{"a":0,"k":[201.509,179.53,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":1,"k":[{"i":{"x":0.833,"y":1},"o":{"x":1,"y":0},"t":70,"s":[{"i":[[10.622,-118.401],[0,-9.147],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0.582,7.682]],"o":[[-0.818,9.115],[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,-7.699],[-9.094,-119.994]],"v":[[-180.021,74.765],[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.452,135.49],[-69.112,114.41],[-52.442,110.81],[-42.892,129.01],[-42.892,148.86],[-25.182,138.06],[-12.842,149.38],[-8.722,163.78],[25.217,122.07],[45.737,134.16],[61.728,96.39],[96.188,108.23],[105.448,132.92],[126.527,149.89],[138.288,119.03],[149.158,126.84],[154.818,145.78],[181.759,102.178],[180.879,79.092]],"c":true}]},{"i":{"x":0,"y":1},"o":{"x":0.167,"y":0},"t":80,"s":[{"i":[[123.336,-12.013],[0,-8.21],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0.47,6.899]],"o":[[-0.661,8.188],[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,-6.911],[-154.472,-18.4]],"v":[[-180.26,77.567],[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.452,135.49],[-69.112,114.41],[-52.442,110.81],[-42.892,129.01],[-42.892,148.86],[-25.182,138.06],[-12.842,149.38],[-8.722,163.78],[25.217,122.07],[45.737,134.16],[61.728,96.39],[96.188,108.23],[105.448,132.92],[126.527,149.89],[138.288,119.03],[149.158,126.84],[154.818,145.78],[181.759,102.178],[181.049,81.453]],"c":false}]},{"t":160,"s":[{"i":[[10.622,-118.401],[0,-9.147],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0.582,7.682]],"o":[[-0.818,9.115],[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,-7.699],[-9.094,-119.994]],"v":[[-180.021,74.765],[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.452,135.49],[-69.112,114.41],[-52.442,110.81],[-42.892,129.01],[-42.892,148.86],[-25.182,138.06],[-12.842,149.38],[-8.722,163.78],[25.217,122.07],[45.737,134.16],[61.728,96.39],[96.188,108.23],[105.448,132.92],[126.527,149.89],[138.288,119.03],[149.158,126.84],[154.818,145.78],[181.759,102.178],[180.879,79.092]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.717999994755,0.705999970436,0.620000004768,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":8,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[201.509,179.53],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"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":80,"op":81,"st":0,"bm":0},{"ddd":0,"ind":27,"ty":4,"nm":"egg_t_76","parent":118,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[181.759,159.78,0],"ix":2,"l":2},"a":{"a":0,"k":[201.509,179.53,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":1,"k":[{"i":{"x":0.833,"y":1},"o":{"x":1,"y":0},"t":70,"s":[{"i":[[23.972,-99.244],[0,-25.141],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[5.146,22.785]],"o":[[-5.861,24.266],[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,-23.492],[-22.887,-101.326]],"v":[[-172.219,27.574],[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.452,135.49],[-69.112,114.41],[-52.442,110.81],[-42.892,129.01],[-42.892,148.86],[-25.182,138.06],[-12.842,149.38],[-8.722,163.78],[25.217,122.07],[45.737,134.16],[61.728,96.39],[96.188,108.23],[105.448,132.92],[126.527,149.89],[138.288,119.03],[149.158,126.84],[154.818,145.78],[181.759,102.178],[173.836,32.357]],"c":true}]},{"i":{"x":0,"y":1},"o":{"x":0.167,"y":0},"t":79,"s":[{"i":[[99.994,-12.501],[0,-22.593],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[4.187,20.601]],"o":[[-4.774,21.967],[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,-21.105],[-102.755,-13.847]],"v":[[-173.918,34.979],[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.452,135.49],[-69.112,114.41],[-52.442,110.81],[-42.892,129.01],[-42.892,148.86],[-25.182,138.06],[-12.842,149.38],[-8.722,163.78],[25.217,122.07],[45.737,134.16],[61.728,96.39],[96.188,108.23],[105.448,132.92],[126.527,149.89],[138.288,119.03],[149.158,126.84],[154.818,145.78],[181.759,102.178],[175.331,39.325]],"c":false}]},{"t":160,"s":[{"i":[[23.972,-99.244],[0,-25.141],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[5.146,22.785]],"o":[[-5.861,24.266],[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,-23.492],[-22.887,-101.326]],"v":[[-172.219,27.574],[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.452,135.49],[-69.112,114.41],[-52.442,110.81],[-42.892,129.01],[-42.892,148.86],[-25.182,138.06],[-12.842,149.38],[-8.722,163.78],[25.217,122.07],[45.737,134.16],[61.728,96.39],[96.188,108.23],[105.448,132.92],[126.527,149.89],[138.288,119.03],[149.158,126.84],[154.818,145.78],[181.759,102.178],[173.836,32.357]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.717999994755,0.705999970436,0.620000004768,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":8,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[201.509,179.53],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"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":79,"op":80,"st":0,"bm":0},{"ddd":0,"ind":28,"ty":4,"nm":"egg_t_75","parent":118,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[181.759,159.78,0],"ix":2,"l":2},"a":{"a":0,"k":[201.509,179.53,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":1,"k":[{"i":{"x":0.833,"y":1},"o":{"x":1,"y":0},"t":70,"s":[{"i":[[33.354,-63.059],[0,-52.607],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[22.474,43.499]],"o":[[-23.284,44.02],[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-0.001,-51.586],[-33.276,-64.407]],"v":[[-144.055,-47.311],[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.452,135.49],[-69.112,114.41],[-52.442,110.81],[-42.892,129.01],[-42.892,148.86],[-25.182,138.06],[-12.842,149.38],[-8.722,163.78],[25.217,122.07],[45.737,134.16],[61.728,96.39],[96.188,108.23],[105.448,132.92],[126.527,149.89],[138.288,119.03],[149.158,126.84],[154.818,145.78],[181.759,102.178],[145.899,-44.74]],"c":true}]},{"i":{"x":0,"y":1},"o":{"x":0.167,"y":0},"t":78,"s":[{"i":[[87.812,-6.089],[0,-47.771],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[18.835,40.807]],"o":[[-19.545,41.38],[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-0.001,-46.813],[-98.323,-11.581]],"v":[[-150.236,-34.953],[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.452,135.49],[-69.112,114.41],[-52.442,110.81],[-42.892,129.01],[-42.892,148.86],[-25.182,138.06],[-12.842,149.38],[-8.722,163.78],[25.217,122.07],[45.737,134.16],[61.728,96.39],[96.188,108.23],[105.448,132.92],[126.527,149.89],[138.288,119.03],[149.158,126.84],[154.818,145.78],[181.759,102.178],[151.9,-32.461]],"c":false}]},{"t":160,"s":[{"i":[[33.354,-63.059],[0,-52.607],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[22.474,43.499]],"o":[[-23.284,44.02],[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-0.001,-51.586],[-33.276,-64.407]],"v":[[-144.055,-47.311],[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.452,135.49],[-69.112,114.41],[-52.442,110.81],[-42.892,129.01],[-42.892,148.86],[-25.182,138.06],[-12.842,149.38],[-8.722,163.78],[25.217,122.07],[45.737,134.16],[61.728,96.39],[96.188,108.23],[105.448,132.92],[126.527,149.89],[138.288,119.03],[149.158,126.84],[154.818,145.78],[181.759,102.178],[145.899,-44.74]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.717999994755,0.705999970436,0.620000004768,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":8,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[201.509,179.53],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"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":78,"op":79,"st":0,"bm":0},{"ddd":0,"ind":29,"ty":4,"nm":"egg_t_74","parent":118,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[181.759,159.78,0],"ix":2,"l":2},"a":{"a":0,"k":[201.509,179.53,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":1,"k":[{"i":{"x":0.833,"y":1},"o":{"x":1,"y":0},"t":70,"s":[{"i":[[17.832,-9.166],[0,-102.587],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[71.209,37.788]],"o":[[-72.075,37.047],[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-0.002,-101.78],[-18.32,-9.722]],"v":[[-56.248,-141.021],[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.452,135.49],[-69.112,114.41],[-52.442,110.81],[-42.892,129.01],[-42.892,148.86],[-25.182,138.06],[-12.842,149.38],[-8.722,163.78],[25.217,122.07],[45.737,134.16],[61.728,96.39],[96.188,108.23],[105.448,132.92],[126.527,149.89],[138.288,119.03],[149.158,126.84],[154.818,145.78],[181.759,102.178],[58.442,-140.136]],"c":true}]},{"i":{"x":0,"y":1},"o":{"x":0.167,"y":0},"t":77,"s":[{"i":[[29.168,0.107],[0,-98.586],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[66.814,41.184]],"o":[[-67.78,40.49],[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-0.002,-97.682],[-34.371,-1.52]],"v":[[-64.591,-136.387],[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.452,135.49],[-69.112,114.41],[-52.442,110.81],[-42.892,129.01],[-42.892,148.86],[-25.182,138.06],[-12.842,149.38],[-8.722,163.78],[25.217,122.07],[45.737,134.16],[61.728,96.39],[96.188,108.23],[105.448,132.92],[126.527,149.89],[138.288,119.03],[149.158,126.84],[154.818,145.78],[181.759,102.178],[66.948,-135.26]],"c":false}]},{"t":160,"s":[{"i":[[17.832,-9.166],[0,-102.587],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[71.209,37.788]],"o":[[-72.075,37.047],[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-0.002,-101.78],[-18.32,-9.722]],"v":[[-56.248,-141.021],[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.452,135.49],[-69.112,114.41],[-52.442,110.81],[-42.892,129.01],[-42.892,148.86],[-25.182,138.06],[-12.842,149.38],[-8.722,163.78],[25.217,122.07],[45.737,134.16],[61.728,96.39],[96.188,108.23],[105.448,132.92],[126.527,149.89],[138.288,119.03],[149.158,126.84],[154.818,145.78],[181.759,102.178],[58.442,-140.136]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.717999994755,0.705999970436,0.620000004768,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":8,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[201.509,179.53],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"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":77,"op":78,"st":0,"bm":0},{"ddd":0,"ind":30,"ty":4,"nm":"egg_t_4","parent":118,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[181.759,159.78,0],"ix":2,"l":2},"a":{"a":0,"k":[201.509,179.53,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":1,"k":[{"i":{"x":0,"y":1},"o":{"x":1,"y":0},"t":70,"s":[{"i":[[99.14,0],[0,-127.967],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[-99.14,0],[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-0.002,-127.966]],"v":[[0.25,-155.28],[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.452,135.49],[-69.112,114.41],[-52.442,110.81],[-42.892,129.01],[-42.892,148.86],[-25.182,138.06],[-12.842,149.38],[-8.722,163.78],[25.217,122.07],[45.737,134.16],[61.728,96.39],[96.188,108.23],[105.448,132.92],[126.527,149.89],[138.288,119.03],[149.158,126.84],[154.818,145.78],[181.759,102.178]],"c":true}]},{"t":160,"s":[{"i":[[99.14,0],[0,-127.967],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[-99.14,0],[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-0.002,-127.966]],"v":[[0.25,-155.28],[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.452,135.49],[-69.112,114.41],[-52.442,110.81],[-42.892,129.01],[-42.892,148.86],[-25.182,138.06],[-12.842,149.38],[-8.722,163.78],[25.217,122.07],[45.737,134.16],[61.728,96.39],[96.188,108.23],[105.448,132.92],[126.527,149.89],[138.288,119.03],[149.158,126.84],[154.818,145.78],[181.759,102.178]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.717999994755,0.705999970436,0.620000004768,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":8,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[201.509,179.53],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"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":70,"op":77,"st":0,"bm":0},{"ddd":0,"ind":31,"ty":4,"nm":"egg_bl17","parent":118,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[107.034,99.923,0],"ix":2,"l":2},"a":{"a":0,"k":[18.048,23.191,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":[[-1.749,-2.071],[2.071,-1.749],[1.749,2.072],[-2.072,1.75]],"o":[[1.749,2.071],[-2.071,1.75],[-1.75,-2.071],[2.071,-1.749]],"v":[[3.751,-3.168],[3.168,3.75],[-3.75,3.167],[-3.167,-3.751]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"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":0,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector 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":[30.347,40.632],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-4.948,-5.859],[5.859,-4.948],[4.948,5.859],[-5.859,4.948]],"o":[[4.948,5.859],[-5.859,4.948],[-4.948,-5.859],[5.859,-4.948]],"v":[[10.609,-8.96],[8.96,10.609],[-10.609,8.959],[-8.96,-10.609]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"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":0,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector 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":[15.806,15.807],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":3,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":165,"op":180,"st":0,"bm":0},{"ddd":0,"ind":32,"ty":4,"nm":"egg_bl16","parent":118,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[107.034,99.923,0],"ix":2,"l":2},"a":{"a":0,"k":[18.048,23.191,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":[[-1.749,-2.071],[2.071,-1.749],[1.749,2.072],[-2.072,1.75]],"o":[[1.749,2.071],[-2.071,1.75],[-1.75,-2.071],[2.071,-1.749]],"v":[[3.751,-3.168],[3.168,3.75],[-3.75,3.167],[-3.167,-3.751]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"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":0,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector 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":[30.347,40.632],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-4.948,-5.859],[-0.262,-2.711],[3.62,-3.057],[4.948,5.859],[-0.207,3.436],[-3.947,0.25]],"o":[[1.891,2.239],[0.423,4.385],[-5.859,4.948],[-2.396,-2.838],[0.22,-3.659],[12.003,-0.76]],"v":[[7.109,0.04],[13.821,-1.347],[8.96,10.609],[-10.609,8.959],[-13.861,-0.833],[-2.96,-1.609]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"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":0,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector 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":[15.806,15.807],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":3,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":164,"op":165,"st":0,"bm":0},{"ddd":0,"ind":33,"ty":4,"nm":"egg_bl3","parent":118,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[107.034,99.923,0],"ix":2,"l":2},"a":{"a":0,"k":[18.048,23.191,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":[[-1.749,-2.071],[2.071,-1.749],[1.749,2.072],[-2.072,1.75]],"o":[[1.749,2.071],[-2.071,1.75],[-1.75,-2.071],[2.071,-1.749]],"v":[[3.751,-3.168],[3.168,3.75],[-3.75,3.167],[-3.167,-3.751]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"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":0,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector 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":[30.347,40.632],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-4.948,-5.859],[5.859,-4.948],[4.948,5.859],[-5.859,4.948]],"o":[[4.948,5.859],[-5.859,4.948],[-4.948,-5.859],[5.859,-4.948]],"v":[[10.609,-8.96],[8.96,10.609],[-10.609,8.959],[-8.96,-10.609]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"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":0,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector 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":[15.806,15.807],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":3,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":77,"st":0,"bm":0},{"ddd":0,"ind":34,"ty":4,"nm":"egg_bl15","parent":118,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[130.808,146.134,0],"ix":2,"l":2},"a":{"a":0,"k":[103.948,123.542,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":[[17.63,-60.68],[47.011,13.658],[-17.629,60.679],[-47.01,-13.659]],"o":[[-17.63,60.68],[-47.01,-13.659],[17.63,-60.68],[47.011,13.658]],"v":[[86.068,37.456],[-28.236,109.633],[-86.069,-12.556],[35.469,-109.633]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"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":0,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.957000017166,0.949000000954,0.929000020027,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":[103.948,123.542],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"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":166,"op":180,"st":0,"bm":0},{"ddd":0,"ind":35,"ty":4,"nm":"egg_bl14","parent":118,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[130.808,146.134,0],"ix":2,"l":2},"a":{"a":0,"k":[103.948,123.542,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":[[16.009,-55.1],[47.011,13.658],[-17.629,60.679],[-30.814,16.075],[-35.246,0.552]],"o":[[-17.63,60.68],[-47.01,-13.659],[11.359,-39.097],[18.263,-0.455],[38.28,21.725]],"v":[[86.068,37.456],[-28.236,109.633],[-86.069,-12.556],[-16.234,-102.414],[47.774,-104.421]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"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":0,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.957000017166,0.949000000954,0.929000020027,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":[103.948,123.542],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"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":165,"op":166,"st":0,"bm":0},{"ddd":0,"ind":36,"ty":4,"nm":"egg_bl13","parent":118,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[130.808,146.134,0],"ix":2,"l":2},"a":{"a":0,"k":[103.948,123.542,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":[[8.999,-30.973],[47.011,13.658],[-17.629,60.679],[-7.123,11.723],[-60.408,-0.531]],"o":[[-17.63,60.68],[-47.01,-13.659],[3.865,-13.304],[54.856,-6.088],[9.508,27.799]],"v":[[86.068,37.456],[-28.236,109.633],[-86.069,-12.556],[-69.327,-50.377],[84.437,-55.433]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"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":0,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.957000017166,0.949000000954,0.929000020027,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":[103.948,123.542],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"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":164,"op":165,"st":0,"bm":0},{"ddd":0,"ind":37,"ty":4,"nm":"egg_bl12","parent":118,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[130.808,146.134,0],"ix":2,"l":2},"a":{"a":0,"k":[103.948,123.542,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":[[4.69,-16.141],[47.011,13.658],[-14.155,57.852],[-69.608,-1.013]],"o":[[-17.63,60.68],[-45.468,-13.211],[0.48,-1.962],[0.562,16.51]],"v":[[86.068,37.456],[-28.236,109.633],[-87.656,-6.626],[92.136,-12.19]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"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":0,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.957000017166,0.949000000954,0.929000020027,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":[103.948,123.542],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"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":163,"op":164,"st":0,"bm":0},{"ddd":0,"ind":38,"ty":4,"nm":"egg_bl11","parent":118,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[130.808,146.134,0],"ix":2,"l":2},"a":{"a":0,"k":[103.948,123.542,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":[[1.33,-4.578],[47.011,13.658],[2.981,39.387],[-56.872,0.238]],"o":[[-17.63,60.68],[-35.075,-10.191],[35.564,-2.543],[-0.893,4.684]],"v":[[86.068,37.456],[-28.236,109.633],[-91.036,30.829],[89.4,23.548]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"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":0,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.957000017166,0.949000000954,0.929000020027,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":[103.948,123.542],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"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":162,"op":163,"st":0,"bm":0},{"ddd":0,"ind":39,"ty":4,"nm":"egg_bl10","parent":118,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[130.808,146.134,0],"ix":2,"l":2},"a":{"a":0,"k":[103.948,123.542,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":[[-44.024,-1.23],[42.443,12.331],[10.193,24.095]],"o":[[-21.242,48.522],[-25.483,-7.404],[48.469,-5.275]],"v":[[80.053,54.137],[-28.236,109.633],[-83.941,60.683]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"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":0,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.957000017166,0.949000000954,0.929000020027,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":[103.948,123.542],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"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":161,"op":162,"st":0,"bm":0},{"ddd":0,"ind":40,"ty":4,"nm":"egg_bl9","parent":118,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[130.808,146.134,0],"ix":2,"l":2},"a":{"a":0,"k":[103.948,123.542,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":[[-41.549,1.556],[33.892,9.846],[10.588,11.612]],"o":[[-23.652,29.267],[-15.896,-4.619],[48.522,-1.932]],"v":[[64.578,79.887],[-28.236,109.633],[-68.494,84.875]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"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":0,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.957000017166,0.949000000954,0.929000020027,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":[103.948,123.542],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"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":160,"op":161,"st":0,"bm":0},{"ddd":0,"ind":41,"ty":4,"nm":"Shape Layer 4","parent":10,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":51,"s":[0]},{"t":55,"s":[100]}],"ix":11},"r":{"a":0,"k":-10.372,"ix":10},"p":{"a":0,"k":[161.097,239.971,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-4.302,36.792],[-21.186,47.659],[-17.164,58.925],[16.01,39.441]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.988235354424,0.960784375668,0.901960849762,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":"Shape 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":78,"op":79,"st":0,"bm":0},{"ddd":0,"ind":42,"ty":4,"nm":"Shape Layer 3","parent":10,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":51,"s":[0]},{"t":55,"s":[100]}],"ix":11},"r":{"a":0,"k":-10.372,"ix":10},"p":{"a":0,"k":[150.866,301.747,0],"ix":2,"l":2},"a":{"a":0,"k":[-21.186,58.925,0],"ix":1,"l":2},"s":{"a":0,"k":[81.255,81.255,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],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[16.152,-6.03],[4.498,-1.206],[4.281,31.268],[-21.186,47.659],[-17.164,58.925],[16.01,39.441],[14.28,10.927],[24.404,2.971]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.988235354424,0.960784375668,0.901960849762,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":"Shape 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":78,"st":0,"bm":0},{"ddd":0,"ind":43,"ty":4,"nm":"egg_bl18","parent":118,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[130.808,146.134,0],"ix":2,"l":2},"a":{"a":0,"k":[103.948,123.542,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":[[-17.63,60.68],[45.422,-2.369],[-30.653,-8.906]],"o":[[-61.54,-2.602],[7.242,32.059],[47.011,13.658]],"v":[[85.068,39.956],[-88.894,45.224],[-28.236,109.633]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"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":0,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.957000017166,0.949000000954,0.929000020027,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":[103.948,123.542],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"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":77,"op":78,"st":0,"bm":0},{"ddd":0,"ind":44,"ty":4,"nm":"egg_bl2","parent":118,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[130.808,146.134,0],"ix":2,"l":2},"a":{"a":0,"k":[103.948,123.542,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":[[17.63,-60.68],[47.011,13.658],[-17.629,60.679],[-47.01,-13.659]],"o":[[-17.63,60.68],[-47.01,-13.659],[17.63,-60.68],[47.011,13.658]],"v":[[86.068,37.456],[-28.236,109.633],[-86.069,-12.556],[35.469,-109.633]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"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":0,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.957000017166,0.949000000954,0.929000020027,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":[103.948,123.542],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"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":77,"st":0,"bm":0},{"ddd":0,"ind":45,"ty":4,"nm":"egg_bl4","parent":118,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[241.403,207.828,0],"ix":2,"l":2},"a":{"a":0,"k":[21.324,22.678,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":[[8.288,-10.035],[6.939,5.73],[-8.287,10.036],[-6.939,-5.73]],"o":[[-8.288,10.035],[-6.939,-5.73],[8.288,-10.035],[6.939,5.73]],"v":[[12.621,11.117],[-13.356,16.698],[-12.787,-9.866],[14.135,-16.698]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"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":0,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.957000017166,0.949000000954,0.929000020027,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":[21.324,22.678],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"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":162,"op":180,"st":0,"bm":0},{"ddd":0,"ind":46,"ty":4,"nm":"egg_bl6","parent":118,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[241.403,207.828,0],"ix":2,"l":2},"a":{"a":0,"k":[21.324,22.678,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":[[3.96,-4.795],[6.939,5.73],[-4.755,8.597],[0.396,-5.252]],"o":[[-8.288,10.035],[-5.887,-4.861],[0.85,-1.536],[-0.362,4.806]],"v":[[12.621,11.117],[-13.356,16.698],[-15.941,-5.269],[19.049,-3.739]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"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":0,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.957000017166,0.949000000954,0.929000020027,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":[21.324,22.678],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"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":161,"op":162,"st":0,"bm":0},{"ddd":0,"ind":47,"ty":4,"nm":"egg_bl1","parent":118,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[241.403,207.828,0],"ix":2,"l":2},"a":{"a":0,"k":[21.324,22.678,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":[[8.288,-10.035],[6.939,5.73],[-8.287,10.036],[-6.939,-5.73]],"o":[[-8.288,10.035],[-6.939,-5.73],[8.288,-10.035],[6.939,5.73]],"v":[[12.621,11.117],[-13.356,16.698],[-12.787,-9.866],[14.135,-16.698]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"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":0,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.957000017166,0.949000000954,0.929000020027,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":[21.324,22.678],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"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":78,"st":0,"bm":0},{"ddd":0,"ind":48,"ty":4,"nm":"egg_t_33","parent":118,"sr":1,"ks":{"o":{"a":0,"k":32,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[297.327,158.314,0],"ix":2,"l":2},"a":{"a":0,"k":[65.94,147.105,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":[[75.56,33.82],[0,-74.74],[11.258,-25.099],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[46.73,43.02],[0,33.566],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,-105.81]],"v":[[-65.94,-147.105],[12.41,45.985],[-5.23,134.274],[10.71,147.106],[22.47,116.246],[33.34,124.056],[39,142.996],[65.94,99.396],[65.94,99.395]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"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":0,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.717999994755,0.705999970436,0.620000004768,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":[65.94,147.106],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"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":166,"op":170,"st":0,"bm":0},{"ddd":0,"ind":49,"ty":4,"nm":"egg_t_32","parent":118,"sr":1,"ks":{"o":{"a":0,"k":32,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[297.327,158.314,0],"ix":2,"l":2},"a":{"a":0,"k":[65.94,147.105,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":[[7.64,0.757],[0,-58.717],[11.258,-25.099],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[50.465,48.763]],"o":[[31.026,43.493],[0,33.566],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,-82.072],[-6.582,-1.398]],"v":[[-38.131,-115.306],[12.41,45.985],[-5.23,134.274],[10.71,147.106],[22.47,116.246],[33.34,124.056],[39,142.996],[65.94,99.396],[65.94,99.395],[-18.41,-114.151]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"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":0,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.717999994755,0.705999970436,0.620000004768,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":[65.94,147.106],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"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":165,"op":166,"st":0,"bm":0},{"ddd":0,"ind":50,"ty":4,"nm":"egg_t_31","parent":118,"sr":1,"ks":{"o":{"a":0,"k":32,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[297.327,158.314,0],"ix":2,"l":2},"a":{"a":0,"k":[65.94,147.105,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":[[10.108,2.239],[0,-39.023],[11.258,-25.099],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[27.778,46.449]],"o":[[14.89,34.662],[0,33.566],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,-58.047],[-13.204,-1.677]],"v":[[-11.099,-66.884],[12.41,45.985],[-5.23,134.274],[10.71,147.106],[22.47,116.246],[33.34,124.056],[39,142.996],[65.94,99.396],[65.94,99.395],[21.212,-63.467]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"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":0,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.717999994755,0.705999970436,0.620000004768,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":[65.94,147.106],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"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":164,"op":165,"st":0,"bm":0},{"ddd":0,"ind":51,"ty":4,"nm":"egg_t_30","parent":118,"sr":1,"ks":{"o":{"a":0,"k":32,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[297.327,158.314,0],"ix":2,"l":2},"a":{"a":0,"k":[65.94,147.105,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":[[11.899,0.525],[0,-22.718],[11.258,-25.099],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[13.729,35.896]],"o":[[5.379,21.903],[0,33.566],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,-39.439],[-8.878,-3.856]],"v":[[4.11,-21.408],[12.41,45.985],[-5.23,134.274],[10.71,147.106],[22.47,116.246],[33.34,124.056],[39,142.996],[65.94,99.396],[65.94,99.395],[44.386,-15.528]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"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":0,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.717999994755,0.705999970436,0.620000004768,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":[65.94,147.106],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"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":163,"op":164,"st":0,"bm":0},{"ddd":0,"ind":52,"ty":4,"nm":"egg_t_29","parent":118,"sr":1,"ks":{"o":{"a":0,"k":32,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[297.327,158.314,0],"ix":2,"l":2},"a":{"a":0,"k":[65.94,147.105,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":[[20.698,4.033],[0,-9.818],[11.258,-25.099],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[5.957,24.456]],"o":[[1.054,9.764],[0,33.566],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,-25.354],[-17.741,-5.563]],"v":[[10.811,16.574],[12.41,45.985],[-5.23,134.274],[10.71,147.106],[22.47,116.246],[33.34,124.056],[39,142.996],[65.94,99.396],[65.94,99.395],[56.749,24.17]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"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":0,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.717999994755,0.705999970436,0.620000004768,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":[65.94,147.106],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"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":162,"op":163,"st":0,"bm":0},{"ddd":0,"ind":53,"ty":4,"nm":"egg_t_28","parent":118,"sr":1,"ks":{"o":{"a":0,"k":32,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[297.327,158.314,0],"ix":2,"l":2},"a":{"a":0,"k":[65.94,147.105,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":[[20.099,2.243],[11.258,-25.099],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[1.955,14.118]],"o":[[0,33.566],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,-14.261],[-16.453,-4.507]],"v":[[12.41,48.485],[-5.23,134.274],[10.71,147.106],[22.47,116.246],[33.34,124.056],[39,142.996],[65.94,99.396],[65.94,99.395],[62.962,56.735]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"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":0,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.717999994755,0.705999970436,0.620000004768,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":[65.94,147.106],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"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":161,"op":162,"st":0,"bm":0},{"ddd":0,"ind":54,"ty":4,"nm":"egg_t_27","parent":118,"sr":1,"ks":{"o":{"a":0,"k":32,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[297.327,158.314,0],"ix":2,"l":2},"a":{"a":0,"k":[65.94,147.105,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":[[5.448,-1.632],[10.243,1.97],[7.919,-17.656],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0.305,5.548]],"o":[[-11.052,-4.132],[-2.57,21.931],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,-5.553],[-17.471,-2.474]],"v":[[35.56,78.895],[10.766,74.793],[-5.23,134.274],[10.71,147.106],[22.47,116.246],[33.34,124.056],[39,142.996],[65.94,99.396],[65.94,99.395],[65.48,82.737]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"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":0,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.717999994755,0.705999970436,0.620000004768,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":[65.94,147.106],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"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":160,"op":161,"st":0,"bm":0},{"ddd":0,"ind":55,"ty":4,"nm":"egg_t_26","parent":118,"sr":1,"ks":{"o":{"a":0,"k":32,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[297.327,158.314,0],"ix":2,"l":2},"a":{"a":0,"k":[65.94,147.105,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":[[14.818,0.179],[5.252,-11.71],[0,0],[0,0],[0,0],[0,0],[-9.452,15.297],[-1.136,1.838],[0,0]],"o":[[-2.977,13.62],[0,0],[0,0],[0,0],[0,0],[0,0],[1.369,-2.215],[0,0],[-9.932,-2.967]],"v":[[7.19,96.249],[-5.23,134.274],[10.71,147.106],[22.47,116.246],[33.34,124.056],[39,142.996],[62.157,105.519],[54.94,102.396],[49.44,101.895]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"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":0,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.717999994755,0.705999970436,0.620000004768,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":[65.94,147.106],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"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":159,"op":160,"st":0,"bm":0},{"ddd":0,"ind":56,"ty":4,"nm":"egg_t_25","parent":118,"sr":1,"ks":{"o":{"a":0,"k":32,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[297.327,158.314,0],"ix":2,"l":2},"a":{"a":0,"k":[65.94,147.105,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":[[12.853,0.454],[2.979,-6.642],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[-2.268,7.265],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-9.432,-3.033]],"v":[[2.656,113.407],[-5.23,134.274],[10.71,147.106],[22.47,116.246],[33.34,124.056],[39,142.996],[52.492,121.16],[46.94,118.896],[36.94,118.395]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"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":0,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.717999994755,0.705999970436,0.620000004768,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":[65.94,147.106],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"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":158,"op":159,"st":0,"bm":0},{"ddd":0,"ind":57,"ty":4,"nm":"egg_t_24","parent":118,"sr":1,"ks":{"o":{"a":0,"k":32,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[297.327,158.314,0],"ix":2,"l":2},"a":{"a":0,"k":[65.94,147.105,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":[[30.085,1.784],[1.098,-2.448],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[-1.004,2.534],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-2.076,126.8],[-5.23,134.274],[10.71,147.106],[17.288,129.845],[23.22,128.496],[35.09,131.056],[39,142.996],[45.928,131.784]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"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":0,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.717999994755,0.705999970436,0.620000004768,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":[65.94,147.106],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"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":157,"op":158,"st":0,"bm":0},{"ddd":0,"ind":58,"ty":4,"nm":"egg_t_72","parent":118,"sr":1,"ks":{"o":{"a":0,"k":32,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[297.327,158.314,0],"ix":2,"l":2},"a":{"a":0,"k":[65.94,147.105,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":[[35.745,5.225],[1.79,-3.99],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[-1.537,4.217],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-0.236,121.962],[-5.23,134.274],[10.71,147.106],[19.97,125.746],[34.34,127.056],[39,142.996],[47.526,129.197]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"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":0,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.717999994755,0.705999970436,0.620000004768,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":[65.94,147.106],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"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":82,"op":83,"st":0,"bm":0},{"ddd":0,"ind":59,"ty":4,"nm":"egg_t_71","parent":118,"sr":1,"ks":{"o":{"a":0,"k":32,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[297.327,158.314,0],"ix":2,"l":2},"a":{"a":0,"k":[65.94,147.105,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":[[27.501,1],[4.329,-9.65],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[-2.801,10.955],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[5.508,103.349],[-5.23,134.274],[10.71,147.106],[22.47,116.246],[33.34,124.056],[39,142.996],[58.989,110.646]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"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":0,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.717999994755,0.705999970436,0.620000004768,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":[65.94,147.106],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"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":81,"op":82,"st":0,"bm":0},{"ddd":0,"ind":60,"ty":4,"nm":"egg_t_70","parent":118,"sr":1,"ks":{"o":{"a":0,"k":32,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[297.327,158.314,0],"ix":2,"l":2},"a":{"a":0,"k":[65.94,147.105,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":[[16.773,0.973],[7.889,-17.588],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0.297,5.472]],"o":[[-2.582,21.831],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,-5.477],[-16.484,-2.447]],"v":[[10.736,75.046],[-5.23,134.274],[10.71,147.106],[22.47,116.246],[33.34,124.056],[39,142.996],[65.94,99.396],[65.94,99.395],[65.493,82.966]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"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":0,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.717999994755,0.705999970436,0.620000004768,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":[65.94,147.106],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"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":80,"op":81,"st":0,"bm":0},{"ddd":0,"ind":61,"ty":4,"nm":"egg_t_69","parent":118,"sr":1,"ks":{"o":{"a":0,"k":32,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[297.327,158.314,0],"ix":2,"l":2},"a":{"a":0,"k":[65.94,147.105,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":[[19.893,3.005],[0,-4.182],[11.258,-25.099],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[3.558,19.016]],"o":[[0.195,4.18],[0,33.566],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,-19.401],[-16.48,-5.097]],"v":[[12.116,33.439],[12.41,45.985],[-5.23,134.274],[10.71,147.106],[22.47,116.246],[33.34,124.056],[39,142.996],[65.94,99.396],[65.94,99.395],[60.488,41.541]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"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":0,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.717999994755,0.705999970436,0.620000004768,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":[65.94,147.106],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"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":79,"op":80,"st":0,"bm":0},{"ddd":0,"ind":62,"ty":4,"nm":"egg_t_68","parent":118,"sr":1,"ks":{"o":{"a":0,"k":32,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[297.327,158.314,0],"ix":2,"l":2},"a":{"a":0,"k":[65.94,147.105,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,0],[0,-27.386],[11.258,-25.099],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,33.566],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,-44.843],[0,0]],"v":[[0.487,-34.792],[12.41,45.985],[-5.23,134.274],[10.71,147.106],[22.47,116.246],[33.34,124.056],[39,142.996],[65.94,99.396],[65.94,99.395],[38.415,-30.065]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"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":0,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.717999994755,0.705999970436,0.620000004768,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":[65.94,147.106],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"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":78,"op":79,"st":0,"bm":0},{"ddd":0,"ind":63,"ty":4,"nm":"egg_t_67","parent":118,"sr":1,"ks":{"o":{"a":0,"k":32,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[297.327,158.314,0],"ix":2,"l":2},"a":{"a":0,"k":[65.94,147.105,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":[[-4.261,-4.788],[0,-67.44],[11.258,-25.099],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[63.059,43.619]],"o":[[39.36,44.23],[0,33.566],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,-94.149],[-7.81,-5.402]],"v":[[-52.695,-133.605],[12.41,45.985],[-5.23,134.274],[10.71,147.106],[22.47,116.246],[33.34,124.056],[39,142.996],[65.94,99.396],[65.94,99.395],[-41.709,-133.361]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"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":0,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.717999994755,0.705999970436,0.620000004768,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":[65.94,147.106],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"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":77,"op":78,"st":0,"bm":0},{"ddd":0,"ind":64,"ty":4,"nm":"egg_t_3","parent":118,"sr":1,"ks":{"o":{"a":0,"k":32,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[297.327,158.314,0],"ix":2,"l":2},"a":{"a":0,"k":[65.94,147.105,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":[[75.56,33.82],[0,-74.74],[11.258,-25.099],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[46.73,43.02],[0,33.566],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,-105.81]],"v":[[-65.94,-147.105],[12.41,45.985],[-5.23,134.274],[10.71,147.106],[22.47,116.246],[33.34,124.056],[39,142.996],[65.94,99.396],[65.94,99.395]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"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":0,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.717999994755,0.705999970436,0.620000004768,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":[65.94,147.106],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"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":70,"op":77,"st":0,"bm":0},{"ddd":0,"ind":65,"ty":4,"nm":"egg_t_43","parent":118,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[181.76,168.724,0],"ix":2,"l":2},"a":{"a":0,"k":[167.715,150.835,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":[[91.47,0],[0,-118.066],[-0.428,-6.06],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,9.295]],"o":[[-91.469,0],[0,6.333],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0.913,-8.701],[0,-118.066]],"v":[[-0.001,-150.585],[-167.465,86.956],[-166.807,105.537],[-160.693,111.446],[-148.353,96.066],[-136.003,122.295],[-121.103,140.295],[-102.062,115.816],[-94.703,122.295],[-69.363,101.215],[-52.693,97.616],[-43.143,115.816],[-43.143,135.665],[-25.433,124.865],[-13.093,136.186],[-8.973,150.585],[24.967,108.876],[45.487,120.965],[61.478,83.196],[95.937,95.036],[105.197,119.725],[126.277,136.696],[138.037,105.835],[148.907,113.645],[154.567,132.585],[166.079,113.954],[167.465,86.956]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"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":0,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.925000011921,0.913999974728,0.882000029087,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":[167.715,150.835],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"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":166,"op":170,"st":0,"bm":0},{"ddd":0,"ind":66,"ty":4,"nm":"egg_t_42","parent":118,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[181.76,168.724,0],"ix":2,"l":2},"a":{"a":0,"k":[167.715,150.835,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":[[37.711,-1.388],[0,-84.62],[-0.428,-6.06],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,9.295],[56.985,40.926]],"o":[[-55.793,41.562],[0,6.333],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0.913,-8.701],[0,-85.747],[-30.319,-3.251]],"v":[[-72.634,-124.57],[-167.465,86.955],[-166.807,105.538],[-160.693,111.446],[-148.353,96.066],[-136.003,122.296],[-121.103,140.295],[-102.062,115.816],[-94.703,122.296],[-69.363,101.216],[-52.693,97.616],[-43.143,115.816],[-43.143,135.665],[-25.433,124.865],[-13.093,136.186],[-8.973,150.585],[24.967,108.876],[45.487,120.965],[61.478,83.196],[95.937,95.036],[105.197,119.725],[126.277,136.696],[138.037,105.835],[148.907,113.645],[154.567,132.585],[166.079,113.954],[167.465,86.955],[70.396,-126.208]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"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":0,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.925000011921,0.913999974728,0.882000029087,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":[167.715,150.835],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"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":165,"op":166,"st":0,"bm":0},{"ddd":0,"ind":67,"ty":4,"nm":"egg_t_41","parent":118,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[181.76,168.724,0],"ix":2,"l":2},"a":{"a":0,"k":[167.715,150.835,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":[[71.525,-1.815],[0,-57.785],[-0.428,-6.06],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,9.295],[30.644,44.686]],"o":[[-29.313,44.288],[0,6.333],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0.913,-8.701],[0,-59.267],[-56.095,-1.935]],"v":[[-119.948,-73.24],[-167.465,86.955],[-166.807,105.537],[-160.693,111.446],[-148.353,96.066],[-136.003,122.295],[-121.103,140.296],[-102.062,115.816],[-94.703,122.295],[-69.363,101.215],[-52.693,97.616],[-43.143,115.816],[-43.143,135.665],[-25.433,124.865],[-13.093,136.186],[-8.973,150.585],[24.967,108.876],[45.487,120.965],[61.478,83.196],[95.937,95.036],[105.197,119.725],[126.277,136.696],[138.037,105.835],[148.907,113.645],[154.567,132.585],[166.079,113.954],[167.465,86.955],[117.671,-76.62]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"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":0,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.925000011921,0.913999974728,0.882000029087,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":[167.715,150.835],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"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":164,"op":165,"st":0,"bm":0},{"ddd":0,"ind":68,"ty":4,"nm":"egg_t_40","parent":118,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[181.76,168.724,0],"ix":2,"l":2},"a":{"a":0,"k":[167.715,150.835,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":[[67.845,-5.566],[0,-40.336],[-0.428,-6.06],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,9.295],[15.074,35.606]],"o":[[-15.327,35.845],[0,6.333],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0.913,-8.701],[0,-39.974],[-66.103,-9.033]],"v":[[-143.268,-29.727],[-167.465,86.956],[-166.807,105.538],[-160.693,111.446],[-148.353,96.066],[-136.003,122.296],[-121.103,140.296],[-102.062,115.816],[-94.703,122.296],[-69.363,101.216],[-52.693,97.616],[-43.143,115.816],[-43.143,135.665],[-25.433,124.866],[-13.093,136.186],[-8.973,150.585],[24.967,108.876],[45.487,120.965],[61.478,83.196],[95.937,95.036],[105.197,119.725],[126.277,136.696],[138.037,105.835],[148.907,113.645],[154.567,132.585],[166.079,113.954],[167.465,86.956],[143.679,-28.76]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"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":0,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.925000011921,0.913999974728,0.882000029087,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":[167.715,150.835],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"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":163,"op":164,"st":0,"bm":0},{"ddd":0,"ind":69,"ty":4,"nm":"egg_t_39","parent":118,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[181.76,168.724,0],"ix":2,"l":2},"a":{"a":0,"k":[167.715,150.835,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":[[83.23,-8.207],[0,-25.874],[-0.428,-6.06],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,9.295],[6.735,24.865]],"o":[[-6.662,24.737],[0,6.333],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0.913,-8.701],[0,-26.022],[-80.462,-12.281]],"v":[[-157.153,10.404],[-167.465,86.956],[-166.807,105.538],[-160.693,111.446],[-148.353,96.066],[-136.003,122.295],[-121.103,140.295],[-102.062,115.816],[-94.703,122.295],[-69.363,101.215],[-52.693,97.616],[-43.143,115.816],[-43.143,135.665],[-25.433,124.865],[-13.093,136.186],[-8.973,150.585],[24.967,108.876],[45.487,120.965],[61.478,83.196],[95.937,95.035],[105.197,119.725],[126.277,136.696],[138.037,105.835],[148.907,113.645],[154.567,132.585],[166.079,113.954],[167.465,86.956],[157.038,9.978]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"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":0,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.925000011921,0.913999974728,0.882000029087,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":[167.715,150.835],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"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":162,"op":163,"st":0,"bm":0},{"ddd":0,"ind":70,"ty":4,"nm":"egg_t_38","parent":118,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[181.76,168.724,0],"ix":2,"l":2},"a":{"a":0,"k":[167.715,150.835,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":[[36.609,1.018],[0,-15.79],[-0.428,-6.06],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,9.295],[2.384,14.971]],"o":[[-2.574,15.551],[0,6.333],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0.913,-8.701],[0,-15.182],[-147.248,-20.279]],"v":[[-163.533,39.8],[-167.465,86.955],[-166.807,105.537],[-160.693,111.446],[-148.353,96.066],[-136.003,122.295],[-121.103,140.296],[-102.062,115.816],[-94.703,122.295],[-69.363,101.215],[-52.693,97.616],[-43.143,115.816],[-43.143,135.665],[-25.433,124.865],[-13.093,136.186],[-8.973,150.585],[24.967,108.876],[45.487,120.965],[61.478,83.196],[95.937,95.036],[105.197,119.725],[126.277,136.696],[138.037,105.835],[148.907,113.645],[154.567,132.585],[166.079,113.954],[167.465,86.955],[163.824,41.597]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"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":0,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.925000011921,0.913999974728,0.882000029087,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":[167.715,150.835],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"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":161,"op":162,"st":0,"bm":0},{"ddd":0,"ind":71,"ty":4,"nm":"egg_t_37","parent":118,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[181.76,168.724,0],"ix":2,"l":2},"a":{"a":0,"k":[167.715,150.835,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":[[5.324,-8.084],[0,-6.676],[-0.428,-6.06],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,9.295],[0.309,5.371]],"o":[[-0.475,6.663],[0,6.333],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0.913,-8.701],[0,-5.376],[-0.422,-13.976]],"v":[[-166.748,66.936],[-167.465,86.956],[-166.807,105.538],[-160.693,111.446],[-148.353,96.066],[-136.003,122.295],[-121.103,140.295],[-102.062,115.816],[-94.703,122.295],[-69.363,101.215],[-52.693,97.616],[-43.143,115.816],[-43.143,135.665],[-25.433,124.865],[-13.093,136.186],[-8.973,150.585],[24.967,108.876],[45.487,120.965],[61.478,83.196],[95.937,95.035],[105.197,119.725],[126.277,136.696],[138.037,105.835],[148.907,113.645],[154.567,132.585],[166.079,113.954],[167.465,86.956],[166.998,70.829]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"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":0,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.925000011921,0.913999974728,0.882000029087,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":[167.715,150.835],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"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":160,"op":161,"st":0,"bm":0},{"ddd":0,"ind":72,"ty":4,"nm":"egg_t_36","parent":118,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[181.76,168.724,0],"ix":2,"l":2},"a":{"a":0,"k":[167.715,150.835,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":[[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-0.161,7.154],[80.398,0.72],[-0.017,-0.869],[-0.313,-4.439],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[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],[0,0],[0.713,-6.79],[0.022,-0.968],[-86.784,-0.778],[0.089,4.583],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[61.478,83.196],[95.937,95.036],[105.197,119.725],[126.277,136.696],[138.038,105.835],[148.908,113.645],[154.567,132.585],[166.079,113.954],[167.397,93.036],[10.584,80.223],[-167.417,90.008],[-166.807,105.537],[-160.693,111.446],[-148.353,96.066],[-136.003,122.295],[-121.103,140.295],[-102.062,115.816],[-94.703,122.295],[-69.363,101.215],[-52.693,97.616],[-43.143,115.816],[-43.143,135.665],[-25.433,124.865],[-13.093,136.186],[-8.973,150.585],[24.967,108.876],[45.487,120.965]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"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":0,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.925000011921,0.913999974728,0.882000029087,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":[167.715,150.835],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"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":159,"op":160,"st":0,"bm":0},{"ddd":0,"ind":73,"ty":4,"nm":"egg_t_46","parent":118,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[181.76,168.724,0],"ix":2,"l":2},"a":{"a":0,"k":[167.715,150.835,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,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-0.129,1.483]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0.154,-1.466],[0.635,-7.32]],"v":[[98.434,101.692],[105.197,119.725],[126.277,136.696],[138.037,105.835],[148.907,113.645],[154.567,132.585],[166.079,113.954],[166.503,109.532]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"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":0,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.925000011921,0.913999974728,0.882000029087,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":[167.715,150.835],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"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":158,"op":159,"st":0,"bm":0},{"ddd":0,"ind":74,"ty":4,"nm":"egg_t_35","parent":118,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[181.76,168.724,0],"ix":2,"l":2},"a":{"a":0,"k":[167.715,150.835,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,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-5.399,11.983],[-0.428,-6.06],[0,0],[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],[0,0],[0,0],[2.29,-5.083],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-52.693,97.616],[-43.143,115.816],[-43.143,135.665],[-25.433,124.865],[-13.093,136.186],[-8.973,150.585],[24.967,108.876],[45.487,120.965],[52.178,98.722],[-166.807,105.537],[-160.693,111.446],[-145.853,106.566],[-136.003,122.295],[-121.103,140.295],[-102.062,115.816],[-94.703,122.295],[-69.363,101.215]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"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":0,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.925000011921,0.913999974728,0.882000029087,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":[167.715,150.835],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"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":158,"op":159,"st":0,"bm":0},{"ddd":0,"ind":75,"ty":4,"nm":"egg_t_45","parent":118,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[181.76,168.724,0],"ix":2,"l":2},"a":{"a":0,"k":[167.715,150.835,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,0],[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],[0,0]],"v":[[104.076,115.424],[105.197,119.725],[126.277,136.696],[134.787,118.835],[149.907,120.895],[154.567,132.585],[160.644,122.752]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"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":0,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.925000011921,0.913999974728,0.882000029087,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":[167.715,150.835],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"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":157,"op":158,"st":0,"bm":0},{"ddd":0,"ind":76,"ty":4,"nm":"egg_t_44","parent":118,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[181.76,168.724,0],"ix":2,"l":2},"a":{"a":0,"k":[167.715,150.835,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,0],[0,0],[-1.363,3.943],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[1.273,-3.683],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[23.967,113.376],[45.487,120.965],[46.803,114.357],[-43.143,113.816],[-43.143,135.665],[-25.433,124.865],[-13.093,136.186],[-8.973,150.585]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"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":0,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.925000011921,0.913999974728,0.882000029087,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":[167.715,150.835],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"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":157,"op":158,"st":0,"bm":0},{"ddd":0,"ind":77,"ty":4,"nm":"egg_t_34","parent":118,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[181.76,168.724,0],"ix":2,"l":2},"a":{"a":0,"k":[167.715,150.835,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,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":[[-102.062,115.816],[-94.703,122.295],[-87.022,115.906],[-137.367,119.397],[-136.003,122.295],[-121.103,140.295]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"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":0,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.925000011921,0.913999974728,0.882000029087,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":[167.715,150.835],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"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":157,"op":158,"st":0,"bm":0},{"ddd":0,"ind":78,"ty":4,"nm":"egg_t_88","parent":118,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[181.76,168.724,0],"ix":2,"l":2},"a":{"a":0,"k":[167.715,150.835,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,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,4.149],[0,0],[0,0],[0,0],[0,0]],"v":[[13.989,122.368],[-42.143,123.219],[-43.143,135.665],[-25.433,124.865],[-13.093,136.185],[-8.973,150.585]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"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":0,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.925000011921,0.913999974728,0.882000029087,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":[167.715,150.835],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"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":83,"op":84,"st":0,"bm":0},{"ddd":0,"ind":79,"ty":4,"nm":"egg_t_87","parent":118,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[181.76,168.724,0],"ix":2,"l":2},"a":{"a":0,"k":[167.715,150.835,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,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-1.902,3.081],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[55.427,1.098]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-45.958,-0.91]],"v":[[-140.757,112.198],[-136.003,122.295],[-121.103,140.295],[-102.062,115.815],[-94.703,122.295],[-76.863,107.715],[-48.192,107.116],[-43.143,115.815],[-43.143,135.665],[-25.433,124.865],[-13.093,136.185],[-8.973,150.585],[24.967,108.875],[45.487,120.965],[49.478,109.196],[105.438,113.035],[105.197,119.725],[126.277,136.695],[136.037,114.835],[148.907,116.145],[154.567,132.585],[162.976,118.214],[-2.957,106.947]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"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":0,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.925000011921,0.913999974728,0.882000029087,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":[167.715,150.835],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"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":82,"op":83,"st":0,"bm":0},{"ddd":0,"ind":80,"ty":4,"nm":"egg_t_86","parent":118,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[181.76,168.724,0],"ix":2,"l":2},"a":{"a":0,"k":[167.715,150.835,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.042,-1.365],[-0.246,-3.49],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-0.227,5.271],[80.529,0.763]],"o":[[0.109,3.578],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0.532,-5.068],[0.078,-1.821],[-86.592,-0.821]],"v":[[-167.343,94.936],[-166.807,105.537],[-160.693,111.445],[-148.353,96.066],[-136.003,122.295],[-121.103,140.295],[-102.062,115.815],[-94.703,122.295],[-69.363,101.215],[-52.692,97.616],[-43.143,115.815],[-43.143,135.665],[-25.433,124.865],[-13.093,136.185],[-8.973,150.585],[24.967,108.875],[45.487,120.965],[60.978,87.696],[95.938,95.035],[105.198,119.725],[126.277,136.695],[138.037,105.835],[148.907,113.645],[154.568,132.585],[166.079,113.954],[167.221,98.445],[10.072,86.869]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"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":0,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.925000011921,0.913999974728,0.882000029087,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":[167.715,150.835],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"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":81,"op":82,"st":0,"bm":0},{"ddd":0,"ind":81,"ty":4,"nm":"egg_t_85","parent":118,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[181.76,168.724,0],"ix":2,"l":2},"a":{"a":0,"k":[167.715,150.835,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,0],[0,-6.934],[-0.428,-6.06],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,9.295],[0,0],[81.51,1.64]],"o":[[0,0],[0,6.333],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0.913,-8.701],[0,-5.458],[0,0],[-62.483,-1.257]],"v":[[-166.691,66.163],[-167.465,86.955],[-166.807,105.537],[-160.693,111.446],[-148.353,96.066],[-136.003,122.295],[-121.103,140.295],[-102.062,115.815],[-94.703,122.295],[-69.363,101.215],[-52.693,97.616],[-43.143,115.815],[-43.143,135.665],[-25.433,124.865],[-13.093,136.185],[-8.973,150.585],[24.967,108.875],[45.487,120.965],[61.478,83.196],[95.937,95.036],[105.197,119.725],[126.277,136.695],[138.037,105.835],[148.907,113.645],[154.567,132.585],[166.079,113.954],[167.465,86.955],[166.984,70.585],[-2.441,58.366]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"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":0,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.925000011921,0.913999974728,0.882000029087,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":[167.715,150.835],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"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":80,"op":81,"st":0,"bm":0},{"ddd":0,"ind":82,"ty":4,"nm":"egg_t_84","parent":118,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[181.76,168.724,0],"ix":2,"l":2},"a":{"a":0,"k":[167.715,150.835,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,0],[0,-21.293],[-0.428,-6.06],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,9.295],[0,0],[80.019,0.044]],"o":[[0,0],[0,6.333],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0.913,-8.701],[0,-19.645],[0,0],[-67.007,-0.037]],"v":[[-160.405,23.649],[-167.465,86.955],[-166.807,105.537],[-160.693,111.445],[-148.353,96.066],[-136.003,122.295],[-121.103,140.295],[-102.062,115.815],[-94.703,122.295],[-69.363,101.215],[-52.693,97.615],[-43.143,115.815],[-43.143,135.665],[-25.433,124.865],[-13.093,136.185],[-8.973,150.585],[24.967,108.875],[45.487,120.965],[61.478,83.196],[95.937,95.036],[105.197,119.725],[126.277,136.695],[138.037,105.835],[148.907,113.645],[154.567,132.585],[166.079,113.954],[167.465,86.955],[161.432,28.46],[2.583,16.571]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"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":0,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.925000011921,0.913999974728,0.882000029087,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":[167.715,150.835],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"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":79,"op":80,"st":0,"bm":0},{"ddd":0,"ind":83,"ty":4,"nm":"egg_t_83","parent":118,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[181.76,168.724,0],"ix":2,"l":2},"a":{"a":0,"k":[167.715,150.835,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":[[47.93,-2.289],[0,-46.846],[-0.428,-6.06],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,9.295],[18.576,38.6]],"o":[[-20.148,39.739],[0,6.333],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0.913,-8.701],[0,-44.798],[-68.372,-15.543]],"v":[[-135.353,-46.697],[-167.465,86.955],[-166.807,105.537],[-160.693,111.445],[-148.353,96.066],[-136.003,122.295],[-121.103,140.295],[-102.062,115.815],[-94.703,122.295],[-69.363,101.215],[-52.693,97.616],[-43.143,115.815],[-43.143,135.665],[-25.433,124.865],[-13.093,136.185],[-8.973,150.585],[24.967,108.875],[45.487,120.965],[61.478,83.196],[95.937,95.035],[105.197,119.725],[126.277,136.695],[138.037,105.835],[148.907,113.645],[154.567,132.585],[166.079,113.954],[167.465,86.955],[137.948,-41.444]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"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":0,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.925000011921,0.913999974728,0.882000029087,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":[167.715,150.835],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"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":78,"op":79,"st":0,"bm":0},{"ddd":0,"ind":84,"ty":4,"nm":"egg_t_82","parent":118,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[181.76,168.724,0],"ix":2,"l":2},"a":{"a":0,"k":[167.715,150.835,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":[[14.517,-0.497],[0,-103.316],[-0.428,-6.06],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,9.295],[74.533,26.022]],"o":[[-75.832,24.472],[0,6.333],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0.913,-8.701],[0,-102.108],[-15.515,-1.388]],"v":[[-33.44,-145.227],[-167.465,86.955],[-166.807,105.537],[-160.693,111.446],[-148.353,96.065],[-136.003,122.296],[-121.103,140.296],[-102.062,115.816],[-94.703,122.296],[-69.363,101.215],[-52.693,97.616],[-43.143,115.816],[-43.143,135.665],[-25.433,124.866],[-13.093,136.186],[-8.973,150.585],[24.967,108.876],[45.487,120.965],[61.478,83.196],[95.937,95.035],[105.197,119.725],[126.277,136.696],[138.037,105.835],[148.907,113.645],[154.567,132.585],[166.079,113.954],[167.465,86.955],[36.092,-144.336]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"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":0,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.925000011921,0.913999974728,0.882000029087,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":[167.715,150.835],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"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":77,"op":78,"st":0,"bm":0},{"ddd":0,"ind":85,"ty":4,"nm":"egg_t_2","parent":118,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[181.76,168.724,0],"ix":2,"l":2},"a":{"a":0,"k":[167.715,150.835,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":[[91.47,0],[0,-118.066],[-0.428,-6.06],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,9.295]],"o":[[-91.469,0],[0,6.333],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0.913,-8.701],[0,-118.066]],"v":[[-0.001,-150.585],[-167.465,86.956],[-166.807,105.537],[-160.693,111.446],[-148.353,96.066],[-136.003,122.295],[-121.103,140.295],[-102.062,115.816],[-94.703,122.295],[-69.363,101.215],[-52.693,97.616],[-43.143,115.816],[-43.143,135.665],[-25.433,124.865],[-13.093,136.186],[-8.973,150.585],[24.967,108.876],[45.487,120.965],[61.478,83.196],[95.937,95.036],[105.197,119.725],[126.277,136.696],[138.037,105.835],[148.907,113.645],[154.567,132.585],[166.079,113.954],[167.465,86.956]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"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":0,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.925000011921,0.913999974728,0.882000029087,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":[167.715,150.835],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"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":70,"op":77,"st":0,"bm":0},{"ddd":0,"ind":86,"ty":4,"nm":"egg_b_tr4","parent":89,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[9.999,39.154,0],"ix":2,"l":2},"a":{"a":0,"k":[42.686,10,0],"ix":1,"l":2},"s":{"a":0,"k":[80,80,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.724,"y":1},"o":{"x":0.167,"y":0},"t":170,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[15.64,-16.328],[-2.068,-9.128],[-16.343,12.486]],"c":false}]},{"t":179,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[21.03,-13.267],[-1.365,-5.285],[-16.343,12.486]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.717999994755,0.705999970436,0.620000004768,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.724],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":170,"s":[8]},{"t":179,"s":[0]}],"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[26.343,22.486],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"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":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":50.666,"s":[0]},{"t":54,"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":185,"st":0,"bm":0},{"ddd":0,"ind":87,"ty":4,"nm":"egg_b_tr3","parent":89,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[9.999,39.154,0],"ix":2,"l":2},"a":{"a":0,"k":[42.686,10,0],"ix":1,"l":2},"s":{"a":0,"k":[80,80,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.724,"y":1},"o":{"x":0.167,"y":0},"t":170,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[16.343,-12.486],[-1.365,-5.285],[-16.343,12.486]],"c":false}]},{"t":179,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[21.03,-13.267],[-1.365,-5.285],[-16.343,12.486]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.717999994755,0.705999970436,0.620000004768,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.724],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":170,"s":[8]},{"t":179,"s":[0]}],"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[26.343,22.486],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"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":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":50.666,"s":[0]},{"t":54,"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":185,"st":0,"bm":0},{"ddd":0,"ind":88,"ty":4,"nm":"egg_b_tr 4","parent":126,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[172.538,318.809,0],"ix":2,"l":2},"a":{"a":0,"k":[26.211,6.5,0],"ix":1,"l":2},"s":{"a":0,"k":[80,80,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.724,"y":1},"o":{"x":0.167,"y":0},"t":170,"s":[{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[13.698,-49.098],[-4.388,-8.319],[-0.757,16.556],[4.372,24.411]],"c":false}]},{"t":179,"s":[{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[9.948,-35.348],[-4.388,-8.319],[-0.757,16.556],[4.372,24.411]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.717999994755,0.705999970436,0.620000004768,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.724],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":54,"s":[6]},{"i":{"x":[0.724],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":170,"s":[8]},{"t":179,"s":[0]}],"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[18.23,46.77],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"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":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":47,"s":[0]},{"t":54,"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":187,"st":0,"bm":0},{"ddd":0,"ind":89,"ty":4,"nm":"egg_b_tr 3","parent":126,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[172.538,318.809,0],"ix":2,"l":2},"a":{"a":0,"k":[26.211,6.5,0],"ix":1,"l":2},"s":{"a":0,"k":[80,80,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.724,"y":1},"o":{"x":0.167,"y":0},"t":170,"s":[{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[6.418,-47.145],[-8.231,-7.616],[-0.758,16.556],[5.141,24.27]],"c":false}]},{"t":179,"s":[{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[9.948,-35.348],[-4.388,-8.319],[-0.757,16.556],[4.372,24.411]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.717999994755,0.705999970436,0.620000004768,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.724],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":54,"s":[6]},{"i":{"x":[0.724],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":170,"s":[8]},{"t":179,"s":[0]}],"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[18.23,46.77],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"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":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":47,"s":[0]},{"t":54,"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":187,"st":0,"bm":0},{"ddd":0,"ind":90,"ty":4,"nm":"egg_full_8","parent":93,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[181.76,231.454,0],"ix":2,"l":2},"a":{"a":0,"k":[201.51,251.204,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,-127.967],[99.141,0],[0,127.967],[-99.14,0]],"o":[[0,127.967],[-99.14,0],[0,-127.967],[99.141,0]],"v":[[181.51,26.257],[0,231.204],[-181.51,26.257],[0,-231.204]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.717999994755,0.705999970436,0.620000004768,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":8,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[201.51,251.204],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"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":170,"op":210,"st":150,"bm":0},{"ddd":0,"ind":91,"ty":4,"nm":"egg_full_7","parent":93,"sr":1,"ks":{"o":{"a":0,"k":32,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[182.672,236.934,0],"ix":2,"l":2},"a":{"a":0,"k":[180.595,225.725,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,-105.81],[99.14,0],[12.65,108.53],[-63.35,0],[0,114],[46.73,43.02]],"o":[[0,127.97],[-90.5,0],[26.54,61.77],[88.53,0],[0,-74.74],[75.56,33.82]],"v":[[180.595,20.775],[-0.915,225.725],[-180.595,53.045],[-35.015,149.945],[127.065,-32.635],[48.715,-225.725]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"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":0,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.717999994755,0.705999970436,0.620000004768,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":[180.595,225.725],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"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":170,"op":210,"st":150,"bm":0},{"ddd":0,"ind":92,"ty":4,"nm":"egg_full_6","parent":93,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[181.76,231.454,0],"ix":2,"l":2},"a":{"a":0,"k":[167.715,213.566,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,-118.066],[91.47,0],[0,118.066],[-91.469,0]],"o":[[0,118.066],[-91.469,0],[0,-118.066],[91.47,0]],"v":[[167.465,24.225],[-0.001,213.316],[-167.465,24.225],[-0.001,-213.316]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.925000011921,0.913999974728,0.882000029087,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":[167.715,213.566],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"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":170,"op":210,"st":150,"bm":0},{"ddd":0,"ind":93,"ty":4,"nm":"egg_full__02","parent":3,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[57.77,174.006,0],"ix":2,"l":2},"a":{"a":0,"k":[181.76,462.659,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,-127.967],[99.141,0],[0,127.967],[-99.14,0]],"o":[[0,127.967],[-99.14,0],[0,-127.967],[99.141,0]],"v":[[181.51,26.257],[0,231.204],[-181.51,26.257],[0,-231.204]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"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":0,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.987999975681,0.961000025272,0.902000010014,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":[181.76,231.454],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"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":170,"op":210,"st":150,"bm":0},{"ddd":0,"ind":94,"ty":4,"nm":"Shape Layer 2","parent":126,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":51,"s":[0]},{"t":55,"s":[100]}],"ix":11},"r":{"a":0,"k":-6.732,"ix":10},"p":{"a":0,"k":[184.257,315.806,0],"ix":2,"l":2},"a":{"a":0,"k":[22,104.25,0],"ix":1,"l":2},"s":{"a":0,"k":[70.899,70.899,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],[0,0],[0,0],[0,0],[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],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[13.25,104.25],[-11.75,144.5],[-31.5,149],[-52,163.25],[-51.843,172.029],[-44.5,174.25],[-26.5,158.75],[-17.75,155.75],[-15.75,174.25],[-9,184.75],[-1.5,188.75],[0,176.75],[-3.952,165.128],[-3.953,148.378],[22,107.75]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.988235354424,0.960784375668,0.901960849762,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":"Shape 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":180,"st":0,"bm":0},{"ddd":0,"ind":95,"ty":4,"nm":"egg_t_60","parent":118,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[181.759,159.78,0],"ix":2,"l":2},"a":{"a":0,"k":[201.509,179.53,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":1,"k":[{"i":{"x":0,"y":1},"o":{"x":1,"y":0},"t":70,"s":[{"i":[[99.14,0],[0,-127.967],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[-99.14,0],[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-0.002,-127.966]],"v":[[0.25,-155.28],[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.452,135.49],[-69.112,114.41],[-52.442,110.81],[-42.892,129.01],[-42.892,148.86],[-25.182,138.06],[-12.842,149.38],[-8.722,163.78],[25.217,122.07],[45.737,134.16],[61.728,96.39],[96.188,108.23],[105.448,132.92],[126.527,149.89],[138.288,119.03],[149.158,126.84],[154.818,145.78],[181.759,102.178]],"c":true}]},{"t":160,"s":[{"i":[[99.14,0],[0,-127.967],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[-99.14,0],[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-0.002,-127.966]],"v":[[0.25,-155.28],[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.452,135.49],[-69.112,114.41],[-52.442,110.81],[-42.892,129.01],[-42.892,148.86],[-25.182,138.06],[-12.842,149.38],[-8.722,163.78],[25.217,122.07],[45.737,134.16],[61.728,96.39],[96.188,108.23],[105.448,132.92],[126.527,149.89],[138.288,119.03],[149.158,126.84],[154.818,145.78],[181.759,102.178]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[201.509,179.53],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":1,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.988235354424,0.960784375668,0.901960849762,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":166,"op":170,"st":0,"bm":0},{"ddd":0,"ind":96,"ty":4,"nm":"egg_t_59","parent":118,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[181.759,159.78,0],"ix":2,"l":2},"a":{"a":0,"k":[201.509,179.53,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":1,"k":[{"i":{"x":0,"y":1},"o":{"x":1,"y":0},"t":70,"s":[{"i":[[24.95,-19.767],[0,-89.581],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[58.602,45.959]],"o":[[-58.226,46.131],[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-0.001,-89.939],[-24.778,-19.432]],"v":[[-82.669,-123.861],[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.452,135.49],[-69.112,114.41],[-52.442,110.81],[-42.892,129.01],[-42.892,148.86],[-25.182,138.06],[-12.842,149.38],[-8.722,163.78],[25.217,122.07],[45.737,134.16],[61.728,96.39],[96.188,108.23],[105.448,132.92],[126.527,149.89],[138.288,119.03],[149.158,126.84],[154.818,145.78],[181.759,102.178],[82.468,-124.412]],"c":true}]},{"i":{"x":0.833,"y":1},"o":{"x":1,"y":0},"t":160,"s":[{"i":[[24.95,-19.767],[0,-89.581],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[58.602,45.959]],"o":[[-58.226,46.131],[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-0.001,-89.939],[-24.778,-19.432]],"v":[[-82.669,-123.861],[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.452,135.49],[-69.112,114.41],[-52.442,110.81],[-42.892,129.01],[-42.892,148.86],[-25.182,138.06],[-12.842,149.38],[-8.722,163.78],[25.217,122.07],[45.737,134.16],[61.728,96.39],[96.188,108.23],[105.448,132.92],[126.527,149.89],[138.288,119.03],[149.158,126.84],[154.818,145.78],[181.759,102.178],[82.468,-124.412]],"c":true}]},{"t":165,"s":[{"i":[[53.231,48.02],[46.665,-3.093],[0,-84.4],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[-51.798,-3.447],[-52.841,48.138],[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-0.001,-84.778]],"v":[[92.375,-116.068],[-92.589,-115.421],[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.452,135.49],[-69.112,114.41],[-52.442,110.81],[-42.892,129.01],[-42.892,148.86],[-25.182,138.06],[-12.842,149.38],[-8.722,163.78],[25.217,122.07],[45.737,134.16],[61.728,96.39],[96.188,108.23],[105.448,132.92],[126.527,149.89],[138.288,119.03],[149.158,126.84],[154.818,145.78],[181.759,102.178]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[201.509,179.53],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":1,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.988235354424,0.960784375668,0.901960849762,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":165,"op":166,"st":0,"bm":0},{"ddd":0,"ind":97,"ty":4,"nm":"egg_t_58","parent":118,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[181.759,159.78,0],"ix":2,"l":2},"a":{"a":0,"k":[201.509,179.53,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":1,"k":[{"i":{"x":0,"y":1},"o":{"x":1,"y":0},"t":70,"s":[{"i":[[32.825,-46.917],[0,-65.144],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[33.991,48.638]],"o":[[-34.038,48.65],[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-0.001,-65.092],[-32.833,-46.981]],"v":[[-125.876,-77.152],[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.452,135.49],[-69.112,114.41],[-52.442,110.81],[-42.892,129.01],[-42.892,148.86],[-25.182,138.06],[-12.842,149.38],[-8.722,163.78],[25.217,122.07],[45.737,134.16],[61.728,96.39],[96.188,108.23],[105.448,132.92],[126.527,149.89],[138.288,119.03],[149.158,126.84],[154.818,145.78],[181.759,102.178],[126.456,-77.038]],"c":true}]},{"i":{"x":0.833,"y":1},"o":{"x":1,"y":0},"t":160,"s":[{"i":[[32.825,-46.917],[0,-65.144],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[33.991,48.638]],"o":[[-34.038,48.65],[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-0.001,-65.092],[-32.833,-46.981]],"v":[[-125.876,-77.152],[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.452,135.49],[-69.112,114.41],[-52.442,110.81],[-42.892,129.01],[-42.892,148.86],[-25.182,138.06],[-12.842,149.38],[-8.722,163.78],[25.217,122.07],[45.737,134.16],[61.728,96.39],[96.188,108.23],[105.448,132.92],[126.527,149.89],[138.288,119.03],[149.158,126.84],[154.818,145.78],[181.759,102.178],[126.456,-77.038]],"c":true}]},{"t":164,"s":[{"i":[[57.71,-3.99],[0,-59.703],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[29.153,47.044]],"o":[[-29.197,47.062],[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-0.001,-59.652],[-47.63,-8.609]],"v":[[-134.133,-64.62],[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.452,135.49],[-69.112,114.41],[-52.442,110.81],[-42.892,129.01],[-42.892,148.86],[-25.182,138.06],[-12.842,149.38],[-8.722,163.78],[25.217,122.07],[45.737,134.16],[61.728,96.39],[96.188,108.23],[105.448,132.92],[126.527,149.89],[138.288,119.03],[149.158,126.84],[154.818,145.78],[181.759,102.178],[134.707,-64.501]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[201.509,179.53],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":1,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.988235354424,0.960784375668,0.901960849762,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":164,"op":165,"st":0,"bm":0},{"ddd":0,"ind":98,"ty":4,"nm":"egg_t_57","parent":118,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[181.759,159.78,0],"ix":2,"l":2},"a":{"a":0,"k":[201.509,179.53,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":1,"k":[{"i":{"x":0,"y":1},"o":{"x":1,"y":0},"t":70,"s":[{"i":[[32.591,-71.193],[0,-46.475],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[17.771,39.902]],"o":[[-18.586,40.601],[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-0.001,-45.35],[-32.373,-72.69]],"v":[[-151.809,-31.571],[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.452,135.49],[-69.112,114.41],[-52.442,110.81],[-42.892,129.01],[-42.892,148.86],[-25.182,138.06],[-12.842,149.38],[-8.722,163.78],[25.217,122.07],[45.737,134.16],[61.728,96.39],[96.188,108.23],[105.448,132.92],[126.527,149.89],[138.288,119.03],[149.158,126.84],[154.818,145.78],[181.759,102.178],[153.643,-28.617]],"c":true}]},{"i":{"x":0.833,"y":1},"o":{"x":1,"y":0},"t":160,"s":[{"i":[[32.591,-71.193],[0,-46.475],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[17.771,39.902]],"o":[[-18.586,40.601],[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-0.001,-45.35],[-32.373,-72.69]],"v":[[-151.809,-31.571],[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.452,135.49],[-69.112,114.41],[-52.442,110.81],[-42.892,129.01],[-42.892,148.86],[-25.182,138.06],[-12.842,149.38],[-8.722,163.78],[25.217,122.07],[45.737,134.16],[61.728,96.39],[96.188,108.23],[105.448,132.92],[126.527,149.89],[138.288,119.03],[149.158,126.84],[154.818,145.78],[181.759,102.178],[153.643,-28.617]],"c":true}]},{"t":163,"s":[{"i":[[64.472,-5.011],[0,-42.058],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[14.765,37.016]],"o":[[-15.466,37.737],[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-0.001,-41.017],[-70.454,-16.819]],"v":[[-156.896,-19.837],[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.452,135.49],[-69.112,114.41],[-52.442,110.81],[-42.892,129.01],[-42.892,148.86],[-25.182,138.06],[-12.842,149.38],[-8.722,163.78],[25.217,122.07],[45.737,134.16],[61.728,96.39],[96.188,108.23],[105.448,132.92],[126.527,149.89],[138.288,119.03],[149.158,126.84],[154.818,145.78],[181.759,102.178],[158.53,-17.03]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[201.509,179.53],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":1,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.988235354424,0.960784375668,0.901960849762,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":163,"op":164,"st":0,"bm":0},{"ddd":0,"ind":99,"ty":4,"nm":"egg_t_56","parent":118,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[181.759,159.78,0],"ix":2,"l":2},"a":{"a":0,"k":[201.509,179.53,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":1,"k":[{"i":{"x":0,"y":1},"o":{"x":1,"y":0},"t":70,"s":[{"i":[[27.378,-91.558],[0,-31.11],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[8.219,28.496]],"o":[[-8.794,29.408],[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,-30.02],[-26.817,-92.976]],"v":[[-167.598,10.464],[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.452,135.49],[-69.112,114.41],[-52.442,110.81],[-42.892,129.01],[-42.892,148.86],[-25.182,138.06],[-12.842,149.38],[-8.722,163.78],[25.217,122.07],[45.737,134.16],[61.728,96.39],[96.188,108.23],[105.448,132.92],[126.527,149.89],[138.288,119.03],[149.158,126.84],[154.818,145.78],[181.759,102.178],[169.006,13.559]],"c":true}]},{"i":{"x":0.833,"y":1},"o":{"x":1,"y":0},"t":160,"s":[{"i":[[27.378,-91.558],[0,-31.11],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[8.219,28.496]],"o":[[-8.794,29.408],[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,-30.02],[-26.817,-92.976]],"v":[[-167.598,10.464],[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.452,135.49],[-69.112,114.41],[-52.442,110.81],[-42.892,129.01],[-42.892,148.86],[-25.182,138.06],[-12.842,149.38],[-8.722,163.78],[25.217,122.07],[45.737,134.16],[61.728,96.39],[96.188,108.23],[105.448,132.92],[126.527,149.89],[138.288,119.03],[149.158,126.84],[154.818,145.78],[181.759,102.178],[169.006,13.559]],"c":true}]},{"t":162,"s":[{"i":[[107.699,-11.215],[0,-27.992],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[6.72,25.908]],"o":[[-7.196,26.767],[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,-27.004],[-65.795,-15.553]],"v":[[-170.122,19.357],[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.452,135.49],[-69.112,114.41],[-52.442,110.81],[-42.892,129.01],[-42.892,148.86],[-25.182,138.06],[-12.842,149.38],[-8.722,163.78],[25.217,122.07],[45.737,134.16],[61.728,96.39],[96.188,108.23],[105.448,132.92],[126.527,149.89],[138.288,119.03],[149.158,126.84],[154.818,145.78],[181.759,102.178],[171.371,22.195]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[201.509,179.53],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":1,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.988235354424,0.960784375668,0.901960849762,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":162,"op":163,"st":0,"bm":0},{"ddd":0,"ind":100,"ty":4,"nm":"egg_t_55","parent":118,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[181.759,159.78,0],"ix":2,"l":2},"a":{"a":0,"k":[201.509,179.53,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":1,"k":[{"i":{"x":0,"y":1},"o":{"x":1,"y":0},"t":70,"s":[{"i":[[85.449,0],[19.735,-106.678],[0,-19.177],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[-84.283,0],[-3.479,18.804],[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,-17.671]],"v":[[0.25,-155.28],[-175.931,44.989],[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.452,135.49],[-69.112,114.41],[-52.442,110.81],[-42.892,129.01],[-42.892,148.86],[-25.182,138.06],[-12.842,149.38],[-8.722,163.78],[25.217,122.07],[45.737,134.16],[61.728,96.39],[96.188,108.23],[105.448,132.92],[126.527,149.89],[138.288,119.03],[149.158,126.84],[154.818,145.78],[181.759,102.178]],"c":true}]},{"i":{"x":0.833,"y":1},"o":{"x":1,"y":0},"t":160,"s":[{"i":[[85.449,0],[19.735,-106.678],[0,-19.177],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[-84.283,0],[-3.479,18.804],[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,-17.671]],"v":[[0.25,-155.28],[-175.931,44.989],[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.452,135.49],[-69.112,114.41],[-52.442,110.81],[-42.892,129.01],[-42.892,148.86],[-25.182,138.06],[-12.842,149.38],[-8.722,163.78],[25.217,122.07],[45.737,134.16],[61.728,96.39],[96.188,108.23],[105.448,132.92],[126.527,149.89],[138.288,119.03],[149.158,126.84],[154.818,145.78],[181.759,102.178]],"c":true}]},{"t":161,"s":[{"i":[[128.521,-14.996],[0,-17.22],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[2.407,15.663]],"o":[[-2.823,16.956],[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,-15.865],[-70.009,-15.999]],"v":[[-176.945,50.759],[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.452,135.49],[-69.112,114.41],[-52.442,110.81],[-42.892,129.01],[-42.892,148.86],[-25.182,138.06],[-12.842,149.38],[-8.722,163.78],[25.217,122.07],[45.737,134.16],[61.728,96.39],[96.188,108.23],[105.448,132.92],[126.527,149.89],[138.288,119.03],[149.158,126.84],[154.818,145.78],[181.759,102.178],[178.086,54.761]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[201.509,179.53],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":1,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.988235354424,0.960784375668,0.901960849762,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":161,"op":162,"st":0,"bm":0},{"ddd":0,"ind":101,"ty":4,"nm":"egg_t_54","parent":118,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[181.759,159.78,0],"ix":2,"l":2},"a":{"a":0,"k":[201.509,179.53,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":1,"k":[{"i":{"x":0,"y":1},"o":{"x":1,"y":0},"t":70,"s":[{"i":[[10.689,-118.329],[0,-9.212],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0.538,7.383]],"o":[[-0.829,9.178],[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,-7.398],[-8.768,-120.321]],"v":[[-180.004,74.572],[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.452,135.49],[-69.112,114.41],[-52.442,110.81],[-42.892,129.01],[-42.892,148.86],[-25.182,138.06],[-12.842,149.38],[-8.722,163.78],[25.217,122.07],[45.737,134.16],[61.728,96.39],[96.188,108.23],[105.448,132.92],[126.527,149.89],[138.288,119.03],[149.158,126.84],[154.818,145.78],[181.759,102.178],[180.946,79.994]],"c":true}]},{"t":160,"s":[{"i":[[124.822,-19.096],[0,-8.268],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0.435,6.63]],"o":[[-0.67,8.246],[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,-6.641],[-43.027,-12.465]],"v":[[-180.246,77.393],[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.452,135.49],[-69.112,114.41],[-52.442,110.81],[-42.892,129.01],[-42.892,148.86],[-25.182,138.06],[-12.842,149.38],[-8.722,163.78],[25.217,122.07],[45.737,134.16],[61.728,96.39],[96.188,108.23],[105.448,132.92],[126.527,149.89],[138.288,119.03],[149.158,126.84],[154.818,145.78],[181.759,102.178],[181.103,82.262]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[201.509,179.53],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":1,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.988235354424,0.960784375668,0.901960849762,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":160,"op":161,"st":0,"bm":0},{"ddd":0,"ind":102,"ty":4,"nm":"egg_t_53","parent":118,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[181.759,159.78,0],"ix":2,"l":2},"a":{"a":0,"k":[201.509,179.53,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":1,"k":[{"i":{"x":0.833,"y":1},"o":{"x":1,"y":0},"t":70,"s":[{"i":[[99.14,0],[0,-127.967],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[-99.14,0],[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[0.25,-155.28],[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.452,135.49],[-69.112,114.41],[-52.442,110.81],[-42.892,129.01],[-42.892,148.86],[-25.182,138.06],[-12.842,149.38],[-8.722,163.78],[25.217,122.07],[45.737,134.16],[61.728,96.39],[96.188,108.23],[105.448,132.92],[126.527,149.89],[138.288,119.03],[149.158,126.84],[154.818,145.78]],"c":true}]},{"i":{"x":0,"y":1},"o":{"x":0.167,"y":0},"t":159,"s":[{"i":[[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[82.336,-11.719],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[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],[0,0],[-51.683,-20.716],[-0.785,0.112],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[61.728,96.39],[96.188,108.23],[105.448,132.92],[126.528,149.89],[138.288,119.03],[149.158,126.84],[154.818,145.78],[179.76,104.678],[-181.259,99.681],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.452,135.49],[-69.112,114.41],[-52.442,110.81],[-42.892,129.01],[-42.892,148.86],[-25.182,138.06],[-12.842,149.38],[-8.722,163.78],[25.217,122.07],[45.738,134.16]],"c":true}]},{"t":160,"s":[{"i":[[99.14,0],[0,-127.967],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[-99.14,0],[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[0.25,-155.28],[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.452,135.49],[-69.112,114.41],[-52.442,110.81],[-42.892,129.01],[-42.892,148.86],[-25.182,138.06],[-12.842,149.38],[-8.722,163.78],[25.217,122.07],[45.737,134.16],[61.728,96.39],[96.188,108.23],[105.448,132.92],[126.527,149.89],[138.288,119.03],[149.158,126.84],[154.818,145.78]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[201.509,179.53],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":1,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.988235354424,0.960784375668,0.901960849762,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":159,"op":160,"st":0,"bm":0},{"ddd":0,"ind":103,"ty":4,"nm":"egg_t_52","parent":118,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[181.759,159.78,0],"ix":2,"l":2},"a":{"a":0,"k":[201.509,179.53,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":1,"k":[{"i":{"x":0.833,"y":1},"o":{"x":1,"y":0},"t":70,"s":[{"i":[[0,0],[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],[-0.002,-127.966]],"v":[[105.448,132.92],[126.527,149.89],[138.288,119.03],[149.158,126.84],[154.818,145.78],[172.972,116.399],[181.759,102.178]],"c":true}]},{"i":{"x":0,"y":1},"o":{"x":0.167,"y":0},"t":158,"s":[{"i":[[0,0],[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],[0,0]],"v":[[97.688,109.23],[105.448,132.92],[126.527,149.89],[138.288,119.03],[149.158,126.84],[154.818,145.78],[171.47,118.83]],"c":true}]},{"t":160,"s":[{"i":[[0,0],[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],[-0.002,-127.966]],"v":[[105.448,132.92],[126.527,149.89],[138.288,119.03],[149.158,126.84],[154.818,145.78],[172.972,116.399],[181.759,102.178]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[201.509,179.53],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":1,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.988235354424,0.960784375668,0.901960849762,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":158,"op":159,"st":0,"bm":0},{"ddd":0,"ind":104,"ty":4,"nm":"egg_t_51","parent":118,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[181.759,159.78,0],"ix":2,"l":2},"a":{"a":0,"k":[201.509,179.53,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":1,"k":[{"i":{"x":0.833,"y":1},"o":{"x":1,"y":0},"t":70,"s":[{"i":[[99.14,0],[0,-127.967],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[-99.14,0],[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[0.25,-155.28],[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.452,135.49]],"c":true}]},{"i":{"x":0,"y":1},"o":{"x":0.167,"y":0},"t":158,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-6.645,13.26]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[2.073,-4.137]],"v":[[-53.943,108.31],[-42.892,129.01],[-42.892,148.86],[-25.182,138.06],[-12.842,149.38],[-8.722,163.78],[25.218,122.07],[45.737,134.16],[53.904,108.81]],"c":true}]},{"t":160,"s":[{"i":[[99.14,0],[0,-127.967],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[-99.14,0],[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[0.25,-155.28],[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.452,135.49]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[201.509,179.53],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":1,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.988235354424,0.960784375668,0.901960849762,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":158,"op":159,"st":0,"bm":0},{"ddd":0,"ind":105,"ty":4,"nm":"egg_t_50","parent":118,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[181.759,159.78,0],"ix":2,"l":2},"a":{"a":0,"k":[201.509,179.53,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":1,"k":[{"i":{"x":0.833,"y":1},"o":{"x":1,"y":0},"t":70,"s":[{"i":[[0,-127.967],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-181.259,102.181],[-181.235,104.545],[-170.29,115.123],[-160.442,124.64],[-150.966,112.828],[-148.102,109.26],[-147.165,111.251],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.453,135.49]],"c":true}]},{"i":{"x":0,"y":1},"o":{"x":0.167,"y":0},"t":158,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[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],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-53.943,108.81],[-170.473,114.946],[-160.442,124.64],[-151.96,114.067],[-148.852,113.51],[-146.017,113.689],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.452,135.49],[-69.112,114.41]],"c":true}]},{"t":160,"s":[{"i":[[0,-127.967],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-181.259,102.181],[-181.235,104.545],[-170.29,115.123],[-160.442,124.64],[-150.966,112.828],[-148.102,109.26],[-147.165,111.251],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.453,135.49]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[201.509,179.53],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":1,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.988235354424,0.960784375668,0.901960849762,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":158,"op":159,"st":0,"bm":0},{"ddd":0,"ind":106,"ty":4,"nm":"egg_t_49","parent":118,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[181.759,159.78,0],"ix":2,"l":2},"a":{"a":0,"k":[201.509,179.53,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":1,"k":[{"i":{"x":0.833,"y":1},"o":{"x":1,"y":0},"t":70,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0.611,6.042]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,-8.372],[-8.722,-86.321]],"v":[[105.448,132.92],[126.527,149.89],[138.288,119.03],[149.158,126.84],[154.818,145.78],[161.03,135.726],[181.759,102.178],[180.822,80.619]],"c":true}]},{"i":{"x":0,"y":1},"o":{"x":0.167,"y":0},"t":157,"s":[{"i":[[6.25,2],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[-6.25,-2],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[163.576,131.868],[102.138,124.095],[105.448,132.92],[126.527,149.89],[135.288,127.53],[149.658,129.09],[154.818,145.78],[163.209,132.2]],"c":false}]},{"t":160,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0.611,6.042]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,-8.372],[-8.722,-86.321]],"v":[[105.448,132.92],[126.527,149.89],[138.288,119.03],[149.158,126.84],[154.818,145.78],[161.03,135.726],[181.759,102.178],[180.822,80.619]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[201.509,179.53],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":1,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.988235354424,0.960784375668,0.901960849762,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":157,"op":158,"st":0,"bm":0},{"ddd":0,"ind":107,"ty":4,"nm":"egg_t_48","parent":118,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[181.759,159.78,0],"ix":2,"l":2},"a":{"a":0,"k":[201.509,179.53,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":1,"k":[{"i":{"x":0.833,"y":1},"o":{"x":1,"y":0},"t":70,"s":[{"i":[[-0.685,3.059],[-9.375,11.891],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[1.607,-7.177],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-0.002,-127.966]],"v":[[46.657,129.242],[61.728,96.39],[96.188,108.23],[105.448,132.92],[126.527,149.89],[138.287,119.03],[149.157,126.84],[154.818,145.78],[181.759,102.178]],"c":true}]},{"i":{"x":0,"y":1},"o":{"x":0.167,"y":0},"t":157,"s":[{"i":[[0,0],[0,0],[-2.204,7.069],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[-20.991,0.003],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[25.217,122.07],[45.737,134.16],[48.568,122.615],[-46.442,122.81],[-42.892,129.01],[-42.892,148.86],[-25.182,138.06],[-12.842,149.38],[-8.722,163.78]],"c":true}]},{"t":160,"s":[{"i":[[-0.685,3.059],[-9.375,11.891],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[1.607,-7.177],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-0.002,-127.966]],"v":[[46.657,129.242],[61.728,96.39],[96.188,108.23],[105.448,132.92],[126.527,149.89],[138.287,119.03],[149.157,126.84],[154.818,145.78],[181.759,102.178]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[201.509,179.53],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":1,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.988235354424,0.960784375668,0.901960849762,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":157,"op":158,"st":0,"bm":0},{"ddd":0,"ind":108,"ty":4,"nm":"egg_t_47","parent":118,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[181.759,159.78,0],"ix":2,"l":2},"a":{"a":0,"k":[201.509,179.53,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":1,"k":[{"i":{"x":0.833,"y":1},"o":{"x":1,"y":0},"t":70,"s":[{"i":[[0,-127.967],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-138.058,130.593],[-135.752,135.49]],"c":true}]},{"i":{"x":0,"y":1},"o":{"x":0.167,"y":0},"t":157,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[1.137,2.415],[0,0],[0,0],[0,0],[0,0]],"v":[[-80.718,124.065],[-139.163,128.246],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.452,135.49]],"c":true}]},{"t":160,"s":[{"i":[[0,-127.967],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-138.058,130.593],[-135.752,135.49]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[201.509,179.53],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":1,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.988235354424,0.960784375668,0.901960849762,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":157,"op":158,"st":0,"bm":0},{"ddd":0,"ind":109,"ty":4,"nm":"egg_t_100","parent":118,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[181.759,159.78,0],"ix":2,"l":2},"a":{"a":0,"k":[201.509,179.53,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":1,"k":[{"i":{"x":0.833,"y":1},"o":{"x":1,"y":0},"t":70,"s":[{"i":[[99.14,0],[0,-127.967],[-0.007,-0.789],[0,0],[0,0],[0,0]],"o":[[-99.14,0],[0,0.793],[0,0],[0,0],[0,0],[0,0]],"v":[[0.25,-155.28],[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49]],"c":true}]},{"i":{"x":0,"y":1},"o":{"x":0.167,"y":0},"t":83,"s":[{"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.278,131.827],[-43.892,132.01],[-42.892,148.86],[-25.182,138.06],[-12.842,149.38],[-8.722,163.78]],"c":true}]},{"t":160,"s":[{"i":[[99.14,0],[0,-127.967],[-0.007,-0.789],[0,0],[0,0],[0,0]],"o":[[-99.14,0],[0,0.793],[0,0],[0,0],[0,0],[0,0]],"v":[[0.25,-155.28],[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[201.509,179.53],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":1,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.988235354424,0.960784375668,0.901960849762,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":83,"op":84,"st":0,"bm":0},{"ddd":0,"ind":110,"ty":4,"nm":"egg_t_99","parent":118,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[181.759,159.78,0],"ix":2,"l":2},"a":{"a":0,"k":[201.509,179.53,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":1,"k":[{"i":{"x":0.833,"y":1},"o":{"x":1,"y":0},"t":70,"s":[{"i":[[0,-127.967],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01]],"c":true}]},{"i":{"x":0,"y":1},"o":{"x":0.167,"y":0},"t":82,"s":[{"i":[[0,0],[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],[0,0]],"v":[[100.452,120.267],[105.448,132.92],[126.527,149.89],[135.788,123.53],[149.157,126.84],[154.818,145.78],[166.399,127.038]],"c":true}]},{"t":160,"s":[{"i":[[0,-127.967],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[201.509,179.53],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":1,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.988235354424,0.960784375668,0.901960849762,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":82,"op":83,"st":0,"bm":0},{"ddd":0,"ind":111,"ty":4,"nm":"egg_t_98","parent":118,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[181.759,159.78,0],"ix":2,"l":2},"a":{"a":0,"k":[201.509,179.53,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":1,"k":[{"i":{"x":0.833,"y":1},"o":{"x":1,"y":0},"t":70,"s":[{"i":[[99.14,0],[0,-127.967],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[-99.14,0],[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[0.25,-155.28],[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.452,135.49]],"c":true}]},{"i":{"x":0,"y":1},"o":{"x":0.167,"y":0},"t":82,"s":[{"i":[[-3.577,9.555],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[-44.168,-3.001],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[50.244,117.222],[-48.947,117.471],[-42.892,129.01],[-42.892,148.86],[-25.182,138.06],[-12.842,149.38],[-8.722,163.78],[25.218,122.07],[45.737,134.16]],"c":true}]},{"t":160,"s":[{"i":[[99.14,0],[0,-127.967],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[-99.14,0],[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[0.25,-155.28],[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.452,135.49]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[201.509,179.53],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":1,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.988235354424,0.960784375668,0.901960849762,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":82,"op":83,"st":0,"bm":0},{"ddd":0,"ind":112,"ty":4,"nm":"egg_t_97","parent":118,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[181.759,159.78,0],"ix":2,"l":2},"a":{"a":0,"k":[201.509,179.53,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":1,"k":[{"i":{"x":0.833,"y":1},"o":{"x":1,"y":0},"t":70,"s":[{"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.002,-127.966]],"v":[[105.448,132.92],[126.527,149.89],[138.288,119.03],[149.158,126.84],[154.818,145.78],[181.759,102.178]],"c":true}]},{"i":{"x":0,"y":1},"o":{"x":0.167,"y":0},"t":82,"s":[{"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":[[-72.782,117.29],[-142.462,121.239],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.452,135.49]],"c":true}]},{"t":160,"s":[{"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.002,-127.966]],"v":[[105.448,132.92],[126.527,149.89],[138.288,119.03],[149.158,126.84],[154.818,145.78],[181.759,102.178]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[201.509,179.53],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":1,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.988235354424,0.960784375668,0.901960849762,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":82,"op":83,"st":0,"bm":0},{"ddd":0,"ind":113,"ty":4,"nm":"egg_t_96","parent":118,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[181.759,159.78,0],"ix":2,"l":2},"a":{"a":0,"k":[201.509,179.53,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":1,"k":[{"i":{"x":0.833,"y":1},"o":{"x":1,"y":0},"t":70,"s":[{"i":[[99.14,0],[0,-127.967],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[-99.14,0],[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[0.25,-155.28],[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-98.274,132.126],[-94.453,135.49],[-69.112,114.41],[-52.442,110.81],[-42.892,129.01],[-42.892,148.86],[-25.182,138.06],[-12.842,149.38],[-8.723,163.78],[25.217,122.07],[45.737,134.16],[61.729,96.39],[96.188,108.23],[105.448,132.92],[126.527,149.89],[138.288,119.03],[149.158,126.84]],"c":true}]},{"i":{"x":0,"y":1},"o":{"x":0.167,"y":0},"t":81,"s":[{"i":[[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[87.822,1.068],[-0.004,-0.401],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[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],[0,0],[0,0],[-90.868,-1.106],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[61.729,96.39],[96.188,108.23],[105.448,132.92],[126.527,149.89],[138.288,119.03],[149.158,126.84],[154.818,145.78],[177.243,109.487],[5.072,95.275],[-180.235,105.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.452,135.49],[-69.113,114.41],[-52.442,110.81],[-42.892,129.01],[-42.892,148.86],[-25.182,138.06],[-12.842,149.38],[-8.722,163.78],[25.217,122.07],[45.737,134.16]],"c":true}]},{"t":160,"s":[{"i":[[99.14,0],[0,-127.967],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[-99.14,0],[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[0.25,-155.28],[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-98.274,132.126],[-94.453,135.49],[-69.112,114.41],[-52.442,110.81],[-42.892,129.01],[-42.892,148.86],[-25.182,138.06],[-12.842,149.38],[-8.723,163.78],[25.217,122.07],[45.737,134.16],[61.729,96.39],[96.188,108.23],[105.448,132.92],[126.527,149.89],[138.288,119.03],[149.158,126.84]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[201.509,179.53],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":1,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.988235354424,0.960784375668,0.901960849762,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":81,"op":82,"st":0,"bm":0},{"ddd":0,"ind":114,"ty":4,"nm":"egg_t_95","parent":118,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[181.759,159.78,0],"ix":2,"l":2},"a":{"a":0,"k":[201.509,179.53,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":1,"k":[{"i":{"x":0.833,"y":1},"o":{"x":1,"y":0},"t":70,"s":[{"i":[[10.622,-118.401],[0,-9.147],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0.582,7.682]],"o":[[-0.818,9.115],[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,-7.699],[-9.094,-119.994]],"v":[[-180.021,74.765],[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.452,135.49],[-69.112,114.41],[-52.442,110.81],[-42.892,129.01],[-42.892,148.86],[-25.182,138.06],[-12.842,149.38],[-8.722,163.78],[25.217,122.07],[45.737,134.16],[61.728,96.39],[96.188,108.23],[105.448,132.92],[126.527,149.89],[138.288,119.03],[149.158,126.84],[154.818,145.78],[181.759,102.178],[180.879,79.092]],"c":true}]},{"i":{"x":0,"y":1},"o":{"x":0.167,"y":0},"t":80,"s":[{"i":[[123.336,-12.013],[0,-8.21],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0.47,6.899]],"o":[[-0.661,8.188],[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,-6.911],[-154.472,-18.4]],"v":[[-180.26,77.567],[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.452,135.49],[-69.112,114.41],[-52.442,110.81],[-42.892,129.01],[-42.892,148.86],[-25.182,138.06],[-12.842,149.38],[-8.722,163.78],[25.217,122.07],[45.737,134.16],[61.728,96.39],[96.188,108.23],[105.448,132.92],[126.527,149.89],[138.288,119.03],[149.158,126.84],[154.818,145.78],[181.759,102.178],[181.049,81.453]],"c":true}]},{"t":160,"s":[{"i":[[10.622,-118.401],[0,-9.147],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0.582,7.682]],"o":[[-0.818,9.115],[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,-7.699],[-9.094,-119.994]],"v":[[-180.021,74.765],[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.452,135.49],[-69.112,114.41],[-52.442,110.81],[-42.892,129.01],[-42.892,148.86],[-25.182,138.06],[-12.842,149.38],[-8.722,163.78],[25.217,122.07],[45.737,134.16],[61.728,96.39],[96.188,108.23],[105.448,132.92],[126.527,149.89],[138.288,119.03],[149.158,126.84],[154.818,145.78],[181.759,102.178],[180.879,79.092]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[201.509,179.53],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":1,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.988235354424,0.960784375668,0.901960849762,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":80,"op":81,"st":0,"bm":0},{"ddd":0,"ind":115,"ty":4,"nm":"egg_t_94","parent":118,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[181.759,159.78,0],"ix":2,"l":2},"a":{"a":0,"k":[201.509,179.53,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":1,"k":[{"i":{"x":0.833,"y":1},"o":{"x":1,"y":0},"t":70,"s":[{"i":[[23.972,-99.244],[0,-25.141],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[5.146,22.785]],"o":[[-5.861,24.266],[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,-23.492],[-22.887,-101.326]],"v":[[-172.219,27.574],[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.452,135.49],[-69.112,114.41],[-52.442,110.81],[-42.892,129.01],[-42.892,148.86],[-25.182,138.06],[-12.842,149.38],[-8.722,163.78],[25.217,122.07],[45.737,134.16],[61.728,96.39],[96.188,108.23],[105.448,132.92],[126.527,149.89],[138.288,119.03],[149.158,126.84],[154.818,145.78],[181.759,102.178],[173.836,32.357]],"c":true}]},{"i":{"x":0,"y":1},"o":{"x":0.167,"y":0},"t":79,"s":[{"i":[[99.994,-12.501],[0,-22.593],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[4.187,20.601]],"o":[[-4.774,21.967],[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,-21.105],[-102.755,-13.847]],"v":[[-173.918,34.979],[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.452,135.49],[-69.112,114.41],[-52.442,110.81],[-42.892,129.01],[-42.892,148.86],[-25.182,138.06],[-12.842,149.38],[-8.722,163.78],[25.217,122.07],[45.737,134.16],[61.728,96.39],[96.188,108.23],[105.448,132.92],[126.527,149.89],[138.288,119.03],[149.158,126.84],[154.818,145.78],[181.759,102.178],[175.331,39.325]],"c":true}]},{"t":160,"s":[{"i":[[23.972,-99.244],[0,-25.141],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[5.146,22.785]],"o":[[-5.861,24.266],[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,-23.492],[-22.887,-101.326]],"v":[[-172.219,27.574],[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.452,135.49],[-69.112,114.41],[-52.442,110.81],[-42.892,129.01],[-42.892,148.86],[-25.182,138.06],[-12.842,149.38],[-8.722,163.78],[25.217,122.07],[45.737,134.16],[61.728,96.39],[96.188,108.23],[105.448,132.92],[126.527,149.89],[138.288,119.03],[149.158,126.84],[154.818,145.78],[181.759,102.178],[173.836,32.357]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[201.509,179.53],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":1,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.988235354424,0.960784375668,0.901960849762,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":79,"op":80,"st":0,"bm":0},{"ddd":0,"ind":116,"ty":4,"nm":"egg_t_93","parent":118,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[181.759,159.78,0],"ix":2,"l":2},"a":{"a":0,"k":[201.509,179.53,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":1,"k":[{"i":{"x":0.833,"y":1},"o":{"x":1,"y":0},"t":70,"s":[{"i":[[33.354,-63.059],[0,-52.607],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[22.474,43.499]],"o":[[-23.284,44.02],[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-0.001,-51.586],[-33.276,-64.407]],"v":[[-144.055,-47.311],[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.452,135.49],[-69.112,114.41],[-52.442,110.81],[-42.892,129.01],[-42.892,148.86],[-25.182,138.06],[-12.842,149.38],[-8.722,163.78],[25.217,122.07],[45.737,134.16],[61.728,96.39],[96.188,108.23],[105.448,132.92],[126.527,149.89],[138.288,119.03],[149.158,126.84],[154.818,145.78],[181.759,102.178],[145.899,-44.74]],"c":true}]},{"i":{"x":0,"y":1},"o":{"x":0.167,"y":0},"t":78,"s":[{"i":[[87.812,-6.089],[0,-47.771],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[18.835,40.807]],"o":[[-19.545,41.38],[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-0.001,-46.813],[-98.323,-11.581]],"v":[[-150.236,-34.953],[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.452,135.49],[-69.112,114.41],[-52.442,110.81],[-42.892,129.01],[-42.892,148.86],[-25.182,138.06],[-12.842,149.38],[-8.722,163.78],[25.217,122.07],[45.737,134.16],[61.728,96.39],[96.188,108.23],[105.448,132.92],[126.527,149.89],[138.288,119.03],[149.158,126.84],[154.818,145.78],[181.759,102.178],[151.9,-32.461]],"c":true}]},{"t":160,"s":[{"i":[[33.354,-63.059],[0,-52.607],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[22.474,43.499]],"o":[[-23.284,44.02],[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-0.001,-51.586],[-33.276,-64.407]],"v":[[-144.055,-47.311],[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.452,135.49],[-69.112,114.41],[-52.442,110.81],[-42.892,129.01],[-42.892,148.86],[-25.182,138.06],[-12.842,149.38],[-8.722,163.78],[25.217,122.07],[45.737,134.16],[61.728,96.39],[96.188,108.23],[105.448,132.92],[126.527,149.89],[138.288,119.03],[149.158,126.84],[154.818,145.78],[181.759,102.178],[145.899,-44.74]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[201.509,179.53],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":1,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.988235354424,0.960784375668,0.901960849762,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":78,"op":79,"st":0,"bm":0},{"ddd":0,"ind":117,"ty":4,"nm":"egg_t_92","parent":118,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[181.759,159.78,0],"ix":2,"l":2},"a":{"a":0,"k":[201.509,179.53,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":1,"k":[{"i":{"x":0.833,"y":1},"o":{"x":1,"y":0},"t":70,"s":[{"i":[[17.832,-9.166],[0,-102.587],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[71.209,37.788]],"o":[[-72.075,37.047],[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-0.002,-101.78],[-18.32,-9.722]],"v":[[-56.248,-141.021],[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.452,135.49],[-69.112,114.41],[-52.442,110.81],[-42.892,129.01],[-42.892,148.86],[-25.182,138.06],[-12.842,149.38],[-8.722,163.78],[25.217,122.07],[45.737,134.16],[61.728,96.39],[96.188,108.23],[105.448,132.92],[126.527,149.89],[138.288,119.03],[149.158,126.84],[154.818,145.78],[181.759,102.178],[58.442,-140.136]],"c":true}]},{"i":{"x":0,"y":1},"o":{"x":0.167,"y":0},"t":77,"s":[{"i":[[29.168,0.107],[0,-98.586],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[66.814,41.184]],"o":[[-67.78,40.49],[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-0.002,-97.682],[-34.371,-1.52]],"v":[[-64.591,-136.387],[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.452,135.49],[-69.112,114.41],[-52.442,110.81],[-42.892,129.01],[-42.892,148.86],[-25.182,138.06],[-12.842,149.38],[-8.722,163.78],[25.217,122.07],[45.737,134.16],[61.728,96.39],[96.188,108.23],[105.448,132.92],[126.527,149.89],[138.288,119.03],[149.158,126.84],[154.818,145.78],[181.759,102.178],[66.948,-135.26]],"c":true}]},{"t":160,"s":[{"i":[[17.832,-9.166],[0,-102.587],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[71.209,37.788]],"o":[[-72.075,37.047],[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-0.002,-101.78],[-18.32,-9.722]],"v":[[-56.248,-141.021],[-181.259,102.181],[-181.235,104.545],[-160.442,124.64],[-148.102,109.26],[-135.752,135.49],[-120.852,153.49],[-101.812,129.01],[-94.452,135.49],[-69.112,114.41],[-52.442,110.81],[-42.892,129.01],[-42.892,148.86],[-25.182,138.06],[-12.842,149.38],[-8.722,163.78],[25.217,122.07],[45.737,134.16],[61.728,96.39],[96.188,108.23],[105.448,132.92],[126.527,149.89],[138.288,119.03],[149.158,126.84],[154.818,145.78],[181.759,102.178],[58.442,-140.136]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[201.509,179.53],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":1,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.988235354424,0.960784375668,0.901960849762,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":77,"op":78,"st":0,"bm":0},{"ddd":0,"ind":118,"ty":4,"nm":"egg_t_1","parent":4,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0,"y":1},"o":{"x":0.301,"y":0},"t":75,"s":[60,-405.409,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":0.667},"o":{"x":0.167,"y":0.167},"t":89,"s":[60,-759.409,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.817,"y":1},"o":{"x":0.768,"y":0},"t":150,"s":[60,-759.409,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":1},"o":{"x":0.32,"y":0},"t":168,"s":[60,-380.681,0],"to":[0,0,0],"ti":[0,0,0]},{"t":170,"s":[60,-403.409,0]}],"ix":2,"l":2},"a":{"a":0,"k":[181.759,0.25,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[1,1,0.333],"y":[0,0,0]},"t":75,"s":[100,100,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"t":82,"s":[100,100,100]},{"i":{"x":[0,0,0.667],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"t":150,"s":[100,100,100]},{"t":170,"s":[100,100,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":1,"y":0},"t":75,"s":[{"i":[[99.14,0],[0,-127.967],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[-99.14,0],[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-0.002,-127.966]],"v":[[0,-159.53],[-181.509,97.931],[-181.485,100.295],[-160.692,120.39],[-148.352,105.01],[-136.002,131.24],[-121.102,149.24],[-102.062,124.76],[-94.702,131.24],[-69.362,110.16],[-52.692,106.56],[-43.142,124.76],[-43.142,144.61],[-25.432,133.81],[-13.092,145.13],[-8.972,159.53],[24.967,117.82],[45.487,129.91],[61.478,92.14],[95.938,103.98],[105.198,128.67],[126.277,145.64],[138.038,114.78],[148.908,122.59],[154.568,141.53],[181.509,97.928]],"c":true}]},{"t":160,"s":[{"i":[[99.14,0],[0,-127.967],[-0.007,-0.789],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[-99.14,0],[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-0.002,-127.966]],"v":[[0,-159.53],[-181.509,97.931],[-181.485,100.295],[-160.692,120.39],[-148.352,105.01],[-136.002,131.24],[-121.102,149.24],[-102.062,124.76],[-94.702,131.24],[-69.362,110.16],[-52.692,106.56],[-43.142,124.76],[-43.142,144.61],[-25.432,133.81],[-13.092,145.13],[-8.972,159.53],[24.967,117.82],[45.487,129.91],[61.478,92.14],[95.938,103.98],[105.198,128.67],[126.277,145.64],[138.038,114.78],[148.908,122.59],[154.568,141.53],[181.509,97.928]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"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":0,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.988235354424,0.960784375668,0.901960849762,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":[181.759,159.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":70,"op":77,"st":0,"bm":0},{"ddd":0,"ind":119,"ty":4,"nm":"egg_t_7","parent":120,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[201.51,181.53,0],"ix":2,"l":2},"a":{"a":0,"k":[201.509,179.53,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":1,"k":[{"i":{"x":0.833,"y":1},"o":{"x":0.167,"y":0},"t":82,"s":[{"i":[[0,-127.967],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-0.002,-127.966]],"v":[[-181.259,94.681],[-160.442,117.14],[-148.102,101.76],[-135.752,127.99],[-120.852,145.99],[-101.812,121.51],[-94.452,127.99],[-69.112,106.91],[-52.442,103.31],[-42.892,121.51],[-42.892,141.36],[-25.182,130.56],[-12.842,141.88],[-8.722,156.28],[25.217,114.57],[45.737,126.66],[61.728,88.89],[96.188,100.73],[105.448,125.42],[126.527,142.39],[138.288,111.53],[149.158,119.34],[154.818,138.28],[181.759,94.678]],"c":false}]},{"t":85,"s":[{"i":[[0,-127.967],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.371,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-0.002,-127.966]],"v":[[-181.259,94.681],[-160.442,117.14],[-148.102,101.76],[-135.752,127.99],[-120.852,145.99],[-101.812,121.51],[-94.452,127.99],[-69.112,106.91],[-52.442,103.31],[-42.892,121.51],[-42.892,141.36],[-25.182,130.56],[-12.842,141.88],[-8.722,156.28],[25.217,114.57],[45.737,126.66],[61.728,88.89],[96.188,100.73],[105.448,125.42],[126.527,142.39],[138.288,111.53],[149.158,119.34],[154.818,138.28],[181.759,94.678]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.717999994755,0.705999970436,0.620000004768,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":8,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[201.509,179.53],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"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":75,"op":170,"st":0,"bm":0},{"ddd":0,"ind":120,"ty":4,"nm":"egg_full_9","parent":126,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[181.76,229.454,0],"ix":2,"l":2},"a":{"a":0,"k":[201.51,251.204,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,-127.967],[99.141,0],[0,127.967]],"o":[[0,127.967],[-99.14,0],[0,-127.967]],"v":[[181.51,26.257],[0,233.204],[-181.51,26.257]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.717999994755,0.705999970436,0.620000004768,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":8,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[201.51,251.204],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"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":-20,"op":170,"st":0,"bm":0},{"ddd":0,"ind":121,"ty":4,"nm":"egg_b_6","parent":126,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[1],"y":[1]},"o":{"x":[0.167],"y":[0.167]},"t":14,"s":[0]},{"t":20,"s":[100],"h":1},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":47,"s":[0]},{"t":55,"s":[100]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[181.768,298.559,0],"ix":2,"l":2},"a":{"a":0,"k":[181.75,43.89,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,0],[0.58,-7.25],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0.04,5.16],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.37,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,7.62],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.73,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-0.3,-4.99],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[181.5,-37.85],[180.63,-15.54],[158.77,18.91],[148.39,15.35],[141.79,-4.84],[129.71,26.02],[99.52,4.72],[90.01,-19.97],[67.13,-29.91],[50.93,9.95],[27.64,-3.8],[-12.96,43.64],[-19.95,19.84],[-28.57,12.01],[-52.18,24.2],[-52.18,-6.45],[-59.14,-17.06],[-70.26,-12.46],[-94.29,7.62],[-100.85,2.14],[-120.41,26.62],[-141.72,3.62],[-150.4,-14.61],[-159.87,-2.11],[-180.98,-20.26],[-181.5,-35.49],[-160.7,-15.39],[-148.36,-30.77],[-136.01,-4.54],[-121.11,13.46],[-102.07,-11.02],[-94.71,-4.54],[-69.37,-25.62],[-52.7,-29.22],[-43.15,-11.02],[-43.15,8.83],[-25.44,-1.97],[-13.1,9.35],[-8.98,23.75],[24.96,-17.96],[45.48,-5.87],[61.47,-43.64],[95.93,-31.8],[105.19,-7.11],[126.27,9.86],[138.03,-21],[148.9,-13.19],[154.56,5.75]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"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":0,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.987999975681,0.961000025272,0.902000010014,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":[181.75,43.89],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"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":47,"op":170,"st":0,"bm":0},{"ddd":0,"ind":122,"ty":4,"nm":"egg_b_4","parent":126,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":14,"s":[0]},{"t":20,"s":[100],"h":1}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[181.768,298.559,0],"ix":2,"l":2},"a":{"a":0,"k":[181.75,43.89,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,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.37,16.96]],"o":[[-13.73,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[67.13,-29.91],[50.93,9.95],[27.64,-3.8],[-12.96,43.64],[-19.95,19.84],[-28.57,12.01],[-52.18,24.2],[-52.18,-6.45],[-59.14,-17.06],[-70.26,-12.46],[-69.37,-25.62],[-52.7,-29.22],[-43.15,-11.02],[-43.15,8.83],[-25.44,-1.97],[-13.1,9.35],[-8.98,23.75],[24.96,-17.96],[45.48,-5.87],[61.47,-43.64]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"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":0,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.987999975681,0.961000025272,0.902000010014,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":[181.75,43.89],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"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":-16,"op":170,"st":0,"bm":0},{"ddd":0,"ind":123,"ty":4,"nm":"egg_full_4","parent":126,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[181.76,231.454,0],"ix":2,"l":2},"a":{"a":0,"k":[201.51,251.204,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,-127.967],[99.141,0],[0,127.967],[-99.14,0]],"o":[[0,127.967],[-99.14,0],[0,-127.967],[99.141,0]],"v":[[181.51,26.257],[0,231.204],[-181.51,26.257],[0,-229.204]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.717999994755,0.705999970436,0.620000004768,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":8,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[201.51,251.204],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"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":70,"st":0,"bm":0},{"ddd":0,"ind":124,"ty":4,"nm":"egg_full_3","parent":126,"sr":1,"ks":{"o":{"a":0,"k":32,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[182.672,236.934,0],"ix":2,"l":2},"a":{"a":0,"k":[180.595,225.725,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,-105.81],[99.14,0],[12.65,108.53],[-63.35,0],[0,114],[46.73,43.02]],"o":[[0,127.97],[-90.5,0],[26.54,61.77],[88.53,0],[0,-74.74],[75.56,33.82]],"v":[[180.595,20.775],[-0.915,225.725],[-180.595,53.045],[-35.015,147.945],[127.065,-32.635],[48.715,-225.725]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"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":0,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.717999994755,0.705999970436,0.620000004768,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":[180.595,225.725],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"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":70,"st":0,"bm":0},{"ddd":0,"ind":125,"ty":4,"nm":"egg_full_2","parent":126,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[181.76,230.454,0],"ix":2,"l":2},"a":{"a":0,"k":[167.715,213.566,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,-118.066],[91.47,0],[0,118.066],[-91.469,0]],"o":[[0,118.066],[-91.469,0],[0,-118.066],[91.47,0]],"v":[[167.465,24.225],[-0.001,213.316],[-170.465,24.225],[-0.001,-213.316]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.925000011921,0.913999974728,0.882000029087,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":[167.715,213.566],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"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":70,"st":0,"bm":0},{"ddd":0,"ind":126,"ty":4,"nm":"egg_full__0","parent":4,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[60,60,0],"ix":2,"l":2},"a":{"a":0,"k":[181.76,462.659,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,-127.967],[99.141,0],[0,127.967],[-99.14,0]],"o":[[0,127.967],[-99.14,0],[0,-127.967],[99.141,0]],"v":[[181.51,26.257],[0,231.204],[-181.51,26.257],[0,-229.204]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"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":0,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.987999975681,0.961000025272,0.902000010014,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":[181.76,231.454],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"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":70,"st":0,"bm":0},{"ddd":0,"ind":127,"ty":4,"nm":"egg_b_3","parent":129,"sr":1,"ks":{"o":{"a":0,"k":32,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[182.85,108.515,0],"ix":2,"l":2},"a":{"a":0,"k":[180.4,102.475,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,0],[99.14,0],[11.489,98.62],[-63.35,0],[-26.98,60.1],[0,0],[0,0],[0,0],[0,0]],"o":[[0,127.97],[-98.843,0],[26.54,61.77],[62.44,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[180.4,-102.475],[-1.11,102.475],[-180.4,-69.985],[-34.82,26.915],[109.59,-67.305],[125.17,-54.765],[136.93,-85.625],[147.8,-77.815],[153.46,-58.875]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"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":0,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.717999994755,0.705999970436,0.620000004768,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":[180.4,102.475],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"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":70,"op":170,"st":0,"bm":0},{"ddd":0,"ind":128,"ty":4,"nm":"egg_b_2","parent":129,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[181.75,108.515,0],"ix":2,"l":2},"a":{"a":0,"k":[181.75,102.725,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,0],[99.14,0],[1,126.56],[0,0],[-86.32,0],[-12.45,107.48]],"o":[[0,127.97],[-98.53,0],[0,0],[10.18,111.57],[84.56,0],[0,0]],"v":[[181.5,-102.475],[-0.01,102.475],[-181.5,-100.115],[-171.29,-88.315],[-0.01,85.385],[170.58,-81.565]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"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":0,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.987999975681,0.961000025272,0.902000010014,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":[181.75,102.725],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"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":70,"op":170,"st":0,"bm":0},{"ddd":0,"ind":129,"ty":4,"nm":"egg_b_1","parent":3,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[57.778,68.636,0],"ix":2,"l":2},"a":{"a":0,"k":[181.75,105.62,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,0],[99.14,0],[1,126.56],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-13.37,16.96],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,127.97],[-98.53,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[181.5,-99.58],[-0.01,105.37],[-181.5,-97.22],[-160.7,-77.12],[-148.36,-92.5],[-136.01,-66.27],[-121.11,-48.27],[-102.07,-72.75],[-94.71,-66.27],[-69.37,-87.35],[-52.7,-90.95],[-43.15,-72.75],[-43.15,-52.9],[-25.44,-63.7],[-13.1,-52.38],[-8.98,-37.98],[24.96,-79.69],[45.48,-67.6],[61.47,-105.37],[95.93,-93.53],[105.19,-68.84],[126.27,-51.87],[138.03,-82.73],[148.9,-74.92],[154.56,-55.98]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"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":0,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.925000011921,0.913999974728,0.882000029087,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":[181.75,105.62],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"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":70,"op":170,"st":0,"bm":0},{"ddd":0,"ind":130,"ty":4,"nm":"beak2","parent":133,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[21.624,20.618,0],"ix":2,"l":2},"a":{"a":0,"k":[18.347,20.86,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":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0},"t":70,"s":[{"i":[[-1.828,-2.368],[0,0],[3.137,-10.389],[0,0],[0.913,1.794],[-0.878,10.652],[-2.73,-0.727]],"o":[[0,0],[-5.922,9.312],[0,0],[-1.692,1.09],[0.954,-11.939],[2.757,-1.154],[2.729,0.728]],"v":[[9.64,-14.264],[9.64,-14.264],[-4.586,18.72],[-4.599,18.734],[-9.64,17.372],[-5.552,-18.305],[2.794,-19.098]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":85,"s":[{"i":[[-1.828,-2.368],[0,0],[1.883,-5.692],[0,0],[0.913,1.794],[0.975,3.473],[-2.73,-0.727]],"o":[[0,0],[-4.156,4.062],[0,0],[-1.692,1.09],[0.934,-7.922],[2.757,-1.154],[2.729,0.728]],"v":[[9.64,-14.264],[9.64,-14.264],[-0.336,2.97],[-0.349,2.984],[-5.39,1.622],[-5.552,-18.305],[2.794,-19.098]],"c":true}]},{"i":{"x":0,"y":1},"o":{"x":0.333,"y":0},"t":89,"s":[{"i":[[-1.828,-2.368],[0,0],[3.137,-10.389],[0,0],[0.913,1.794],[-0.878,10.652],[-2.73,-0.727]],"o":[[0,0],[-5.922,9.312],[0,0],[-1.692,1.09],[0.954,-11.939],[2.757,-1.154],[2.729,0.728]],"v":[[9.64,-14.264],[9.64,-14.264],[-4.586,18.72],[-4.599,18.734],[-9.64,17.372],[-5.552,-18.305],[2.794,-19.098]],"c":true}]},{"i":{"x":0.833,"y":1},"o":{"x":0.666,"y":0},"t":96.451,"s":[{"i":[[-1.828,-2.368],[0,0],[-0.771,-5.51],[0,0],[0.913,1.794],[2.644,3.293],[-2.73,-0.727]],"o":[[0,0],[2.741,4.972],[0,0],[-1.692,1.09],[-7.117,-10.102],[2.757,-1.154],[2.729,0.728]],"v":[[14.606,-16.108],[15.317,-15.54],[23.63,9.077],[23.617,9.091],[19.306,8.575],[0,-18.956],[8.346,-19.749]],"c":true}]},{"i":{"x":0.355,"y":1},"o":{"x":0.167,"y":0},"t":103.227,"s":[{"i":[[-1.828,-2.368],[0,0],[3.137,-10.389],[0,0],[1.594,0.716],[-0.878,10.652],[-2.73,-0.727]],"o":[[0,0],[-5.922,9.312],[0,0],[-2.314,-0.062],[0.954,-11.939],[2.757,-1.154],[2.729,0.728]],"v":[[9.64,-14.264],[9.64,-14.264],[-2.426,8.701],[-2.439,8.715],[-7.48,7.353],[-5.552,-18.305],[2.794,-19.098]],"c":true}]},{"i":{"x":0,"y":1},"o":{"x":0.578,"y":0},"t":110,"s":[{"i":[[-1.828,-2.368],[0,0],[0.108,-0.668],[0,0],[0.913,1.794],[0.13,1.056],[-2.73,-0.727]],"o":[[0,0],[-3.643,9.427],[0,0],[-1.692,1.09],[-0.374,-5.681],[2.757,-1.154],[2.729,0.728]],"v":[[9.64,-14.264],[9.64,-14.264],[-22.071,11.277],[-22.084,11.291],[-27.125,9.929],[-5.552,-18.305],[2.794,-19.098]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0},"t":140,"s":[{"i":[[-1.828,-2.368],[0,0],[3.137,-10.389],[0,0],[1.594,0.716],[-0.878,10.652],[-2.73,-0.727]],"o":[[0,0],[-5.922,9.312],[0,0],[-2.314,-0.062],[0.954,-11.939],[2.757,-1.154],[2.729,0.728]],"v":[[9.64,-14.264],[9.64,-14.264],[-2.426,8.701],[-2.439,8.715],[-7.48,7.353],[-5.552,-18.305],[2.794,-19.098]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0},"t":151,"s":[{"i":[[-1.828,-2.368],[0,0],[3.137,-10.389],[0,0],[1.762,0.853],[-0.878,10.652],[-2.73,-0.727]],"o":[[0,0],[-5.922,9.312],[0,0],[-1.158,-0.109],[0.954,-11.939],[2.757,-1.154],[2.729,0.728]],"v":[[9.64,-14.264],[9.64,-14.264],[-2.426,8.701],[-2.439,8.715],[-7.48,7.353],[-5.552,-18.305],[2.794,-19.098]],"c":true}]},{"t":160,"s":[{"i":[[-1.828,-2.368],[0,0],[0.108,-0.668],[0,0],[2.426,0.344],[0.13,1.056],[-2.73,-0.727]],"o":[[0,0],[-2.938,3.046],[0,0],[-1.386,-1.089],[0.708,-2.043],[2.757,-1.154],[2.729,0.728]],"v":[[9.64,-14.264],[9.64,-14.264],[0.833,3.412],[0.82,3.426],[-4.221,2.064],[-5.552,-18.305],[2.794,-19.098]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"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":0,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.949000000954,0.713999986649,0.141000002623,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":[20.616,21.639],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":70,"s":[{"i":[[1.553,-1.014],[0,0],[0.919,1.803],[0,0],[-0.725,1.779],[-8.599,-2.292],[1.555,-10.337]],"o":[[0,0],[-1.696,1.107],[0,0],[-0.907,-1.779],[3.905,-9.592],[8.706,2.32],[-0.355,1.746]],"v":[[13.576,11.313],[-2.31,19.503],[-7.37,18.155],[-17.065,3.156],[-17.372,-2.414],[5.062,-18.319],[16.542,7.023]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":85,"s":[{"i":[[1.553,-1.014],[0,0],[0.919,1.803],[0,0],[-0.725,1.779],[-8.599,-2.292],[1.555,-10.337]],"o":[[0,0],[-1.696,1.107],[0,0],[-0.907,-1.779],[3.905,-9.592],[8.706,2.32],[-0.355,1.746]],"v":[[13.576,11.313],[1.94,3.753],[-3.12,2.405],[-17.065,3.156],[-17.372,-2.414],[5.062,-18.319],[16.542,7.023]],"c":true}]},{"i":{"x":0,"y":1},"o":{"x":0.333,"y":0},"t":89,"s":[{"i":[[1.553,-1.014],[0,0],[0.919,1.803],[0,0],[-0.725,1.779],[-8.599,-2.292],[1.555,-10.337]],"o":[[0,0],[-1.696,1.107],[0,0],[-0.907,-1.779],[3.905,-9.592],[8.706,2.32],[-0.355,1.746]],"v":[[13.576,11.313],[-2.31,19.503],[-7.37,18.155],[-17.065,3.156],[-17.372,-2.414],[5.062,-18.319],[16.542,7.023]],"c":true}]},{"i":{"x":0.833,"y":1},"o":{"x":0.666,"y":0},"t":96.451,"s":[{"i":[[-0.354,-2.379],[0,0],[4.672,1.076],[0,0],[-0.725,1.779],[-8.599,-2.292],[-2.304,-4.433]],"o":[[0.664,4.458],[-1.696,1.107],[0,0],[-0.907,-1.779],[3.905,-9.592],[8.706,2.32],[1.912,3.678]],"v":[[25.787,3.217],[25.906,9.86],[19.672,9.377],[-11.707,2.486],[-11.82,-3.065],[10.614,-18.97],[22.743,-6.638]],"c":true}]},{"i":{"x":0.355,"y":1},"o":{"x":0.167,"y":0},"t":103.227,"s":[{"i":[[1.553,-1.014],[0,0],[1.843,0.552],[0,0],[-0.725,1.779],[-8.599,-2.292],[1.555,-10.337]],"o":[[0,0],[-2.324,-0.28],[0,0],[-0.907,-1.779],[3.905,-9.592],[8.706,2.32],[-0.355,1.746]],"v":[[13.576,11.313],[-0.15,9.484],[-5.21,8.136],[-17.065,3.156],[-17.372,-2.414],[5.062,-18.319],[16.542,7.023]],"c":true}]},{"i":{"x":0,"y":1},"o":{"x":0.578,"y":0},"t":110,"s":[{"i":[[1.221,-1.209],[0,0],[0.919,1.803],[-2.124,4.06],[-2.045,2.04],[-8.599,-2.292],[1.555,-10.337]],"o":[[-0.236,0.994],[-1.696,1.107],[0,0],[2.109,-4.032],[5.644,-5.63],[8.706,2.32],[-0.355,1.746]],"v":[[14.093,11.775],[-19.795,12.06],[-24.855,10.712],[-22.958,2.829],[-15.758,-8.886],[5.062,-18.319],[16.542,7.023]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0},"t":140,"s":[{"i":[[1.553,-1.014],[0,0],[1.843,0.552],[0,0],[-0.725,1.779],[-8.599,-2.292],[1.555,-10.337]],"o":[[0,0],[-2.324,-0.28],[0,0],[-0.907,-1.779],[3.905,-9.592],[8.706,2.32],[-0.355,1.746]],"v":[[13.576,11.313],[-0.15,9.484],[-5.21,8.136],[-17.065,3.156],[-17.372,-2.414],[5.062,-18.319],[16.542,7.023]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0},"t":151,"s":[{"i":[[1.553,-1.014],[0,0],[2.088,0.873],[0,0],[-0.725,1.779],[-8.599,-2.292],[1.555,-10.337]],"o":[[0,0],[-1.759,-0.151],[0,0],[-0.907,-1.779],[3.905,-9.592],[8.706,2.32],[-0.355,1.746]],"v":[[13.576,11.313],[-0.15,9.484],[-5.21,8.136],[-17.065,3.156],[-17.372,-2.414],[5.062,-18.319],[16.542,7.023]],"c":true}]},{"t":160,"s":[{"i":[[1.553,-1.014],[0,0],[2.722,0.086],[0,0],[-0.725,1.779],[-8.599,-2.292],[1.555,-10.337]],"o":[[0,0],[-1.314,-1.143],[0,0],[-0.907,-1.779],[3.905,-9.592],[8.706,2.32],[-0.355,1.746]],"v":[[13.576,11.313],[3.109,4.195],[-1.951,2.847],[-17.065,3.156],[-17.372,-2.414],[5.062,-18.319],[16.542,7.023]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"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":0,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.96899998188,0.552999973297,0.086000002921,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":[18.371,20.969],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":3,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":70,"op":170,"st":0,"bm":0},{"ddd":0,"ind":131,"ty":3,"nm":"NULL CONTROL","parent":145,"sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":89,"s":[6.002]},{"i":{"x":[0.355],"y":[1]},"o":{"x":[0.666],"y":[0]},"t":96.451,"s":[-2.783]},{"i":{"x":[0],"y":[1]},"o":{"x":[0.578],"y":[0]},"t":110,"s":[8.998]},{"t":140,"s":[6.002]}],"ix":10},"p":{"a":1,"k":[{"i":{"x":0,"y":1},"o":{"x":0.333,"y":0},"t":89,"s":[97.22,142.747,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.355,"y":1},"o":{"x":0.666,"y":0},"t":96.451,"s":[138.01,152.756,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0,"y":1},"o":{"x":0.578,"y":0},"t":110,"s":[48.177,136.503,0],"to":[0,0,0],"ti":[0,0,0]},{"t":140,"s":[97.22,142.747,0]}],"ix":2,"l":2},"a":{"a":0,"k":[60,60,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"ip":70,"op":170,"st":0,"bm":0},{"ddd":0,"ind":132,"ty":4,"nm":"Shape Layer 6","parent":133,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":22.631,"ix":10},"p":{"a":0,"k":[-58.833,24.044,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0,"y":1},"o":{"x":0.333,"y":0},"t":89,"s":[{"i":[[2,3.375],[3.125,0.875],[-3.75,-7],[-2.987,-3.616],[-1.252,3.611]],"o":[[-11.875,4.375],[0.375,2.5],[3.75,7],[2.736,3.312],[0.696,-2.008]],"v":[[79.86,-33.288],[66.25,-32],[67.536,-26.283],[72.995,-17.937],[78.248,-18.765]],"c":true}]},{"i":{"x":0.833,"y":1},"o":{"x":0.666,"y":0},"t":96.451,"s":[{"i":[[2,3.375],[3.125,0.875],[-3.75,-7],[-6.509,-3.107],[1,1.875]],"o":[[-11.875,4.375],[0.375,2.5],[3.75,7],[5.5,2.625],[-1,-1.875]],"v":[[91.125,-36.875],[66.25,-32],[69,-27.5],[89.75,-10.125],[96.25,-11.625]],"c":true}]},{"i":{"x":0.355,"y":1},"o":{"x":0.167,"y":0},"t":103.227,"s":[{"i":[[2,3.375],[3.125,0.875],[-3.75,-7],[-2.987,-3.616],[-1.252,3.611]],"o":[[-11.875,4.375],[0.375,2.5],[3.75,7],[2.736,3.312],[0.696,-2.008]],"v":[[90.64,-32.738],[66.25,-32],[58.686,-24.647],[75.985,-4.507],[81.237,-5.335]],"c":true}]},{"i":{"x":0,"y":1},"o":{"x":0.578,"y":0},"t":110,"s":[{"i":[[2,3.375],[3.125,0.875],[-2.418,-7.564],[-2.555,-3.875],[-3.003,2.982]],"o":[[-11.875,4.375],[0.375,2.5],[1.051,3.288],[3.648,5.534],[4.954,-4.919]],"v":[[88.173,-28.956],[66.25,-32],[60.605,-22.558],[64.925,-9.393],[72.835,-6.897]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0},"t":140,"s":[{"i":[[2,3.375],[3.125,0.875],[-3.75,-7],[-2.987,-3.616],[-1.252,3.611]],"o":[[-11.875,4.375],[0.375,2.5],[3.75,7],[2.736,3.312],[0.696,-2.008]],"v":[[90.64,-32.738],[66.25,-32],[58.686,-24.647],[75.985,-4.507],[81.237,-5.335]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0},"t":151,"s":[{"i":[[2,3.375],[3.125,0.875],[-3.75,-7],[-2.987,-3.616],[-1.252,3.611]],"o":[[-11.875,4.375],[0.375,2.5],[3.75,7],[2.736,3.312],[0.696,-2.008]],"v":[[90.64,-32.738],[66.25,-32],[58.686,-24.647],[75.985,-4.507],[81.237,-5.335]],"c":true}]},{"t":160,"s":[{"i":[[2,0.074],[3.125,0.019],[-3.75,-0.154],[-2.987,-0.079],[-1.252,0.079]],"o":[[-11.875,0.096],[0.375,0.055],[3.75,0.154],[2.736,0.073],[0.696,-0.044]],"v":[[79.86,-33.288],[66.25,-33.26],[67.536,-33.135],[70.622,-32.87],[75.874,-32.888]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.807843208313,0.458823561668,0,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":3,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.611642181873,0.043521407992,0.043521407992,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":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":89,"op":162,"st":0,"bm":0},{"ddd":0,"ind":133,"ty":4,"nm":"beak1","parent":131,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":-6.002,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":70,"s":[60,60,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":84.801,"s":[55.817,20.219,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":0.667},"o":{"x":0.167,"y":0.167},"t":89,"s":[60,60,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":0.667},"o":{"x":0.167,"y":0.167},"t":140,"s":[60,60,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0},"t":151,"s":[60,60,0],"to":[0,0,0],"ti":[0,0,0]},{"t":160,"s":[65.491,22.752,0]}],"ix":2,"l":2},"a":{"a":0,"k":[19.915,25.962,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":1,"k":[{"i":{"x":0,"y":1},"o":{"x":0.333,"y":0},"t":89,"s":[{"i":[[0.235,-0.882],[4.834,-3.642],[3.479,0.927],[2.18,4.669],[-1.57,5.888],[-9.487,-2.529],[1.556,-10.336]],"o":[[-1.486,5.573],[-4.445,3.349],[-3.263,-0.87],[-2.669,-5.717],[2.849,-10.689],[8.705,2.321],[-0.136,0.927]],"v":[[17.557,4.873],[6.907,19.51],[-5.889,23.777],[-14.445,14.64],[-16.813,-4.288],[6.63,-23.183],[18.109,2.158]],"c":true}]},{"i":{"x":0.833,"y":1},"o":{"x":0.666,"y":0},"t":96.451,"s":[{"i":[[0.235,-0.882],[1.19,-3.323],[3.68,3.492],[2.18,4.669],[-1.57,5.888],[-9.487,-2.529],[1.556,-10.336]],"o":[[-1.358,5.092],[-3.374,2.565],[-2.88,-2.733],[-2.669,-5.717],[2.849,-10.689],[8.705,2.321],[-0.136,0.927]],"v":[[16.389,0.201],[13.447,27.399],[-3.875,20.566],[-9.373,10.267],[-11.261,-4.94],[12.182,-23.835],[23.661,1.507]],"c":true}]},{"i":{"x":0.355,"y":1},"o":{"x":0.167,"y":0},"t":103.227,"s":[{"i":[[0.222,-0.882],[4.573,-3.642],[3.291,0.927],[3.12,9.735],[-1.485,5.888],[-8.974,-2.529],[1.472,-10.336]],"o":[[-1.406,5.573],[-4.205,3.349],[-3.087,-0.87],[-1.915,-5.976],[2.695,-10.689],[8.235,2.321],[-0.129,0.927]],"v":[[17.912,5.604],[6.791,25.373],[-6.375,32.466],[-15.833,18.159],[-15.758,-3.822],[7.575,-22.453],[18.434,2.889]],"c":true}]},{"i":{"x":0,"y":1},"o":{"x":0.578,"y":0},"t":110,"s":[{"i":[[-0.075,-0.91],[2.837,-3.44],[3.262,-0.922],[5.204,4.51],[-1.435,5.381],[-9.487,-2.529],[1.556,-10.336]],"o":[[0.317,3.838],[-3.541,4.294],[-6.744,1.906],[-0.166,-3.014],[2.849,-10.689],[8.705,2.321],[-0.136,0.927]],"v":[[17.557,4.873],[12.2,17.103],[0.373,23.136],[-15.378,20.963],[-16.813,-4.288],[6.63,-23.183],[18.109,2.159]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0},"t":140,"s":[{"i":[[0.222,-0.882],[4.573,-3.642],[3.291,0.927],[3.12,9.735],[-1.485,5.888],[-8.974,-2.529],[1.472,-10.336]],"o":[[-1.406,5.573],[-4.205,3.349],[-3.087,-0.87],[-1.915,-5.976],[2.695,-10.689],[8.235,2.321],[-0.129,0.927]],"v":[[17.912,5.604],[6.791,25.373],[-6.375,32.466],[-15.833,18.159],[-15.758,-3.822],[7.575,-22.453],[18.434,2.889]],"c":true}]},{"i":{"x":0.833,"y":1},"o":{"x":0.167,"y":0},"t":151,"s":[{"i":[[0.222,-0.882],[4.573,-3.642],[3.291,0.927],[3.12,9.735],[-1.485,5.888],[-8.974,-2.529],[1.472,-10.336]],"o":[[-1.406,5.573],[-4.205,3.349],[-3.087,-0.87],[-1.915,-5.976],[2.695,-10.689],[8.235,2.321],[-0.129,0.927]],"v":[[17.912,5.604],[6.791,25.373],[-6.375,32.466],[-15.833,18.159],[-15.758,-3.822],[7.575,-22.453],[18.434,2.889]],"c":true}]},{"t":160,"s":[{"i":[[0.235,-0.882],[4.834,-3.642],[3.479,0.927],[2.18,4.669],[-1.57,5.888],[-9.487,-2.529],[1.556,-10.336]],"o":[[-1.486,5.573],[-4.445,3.349],[-3.263,-0.87],[-2.669,-5.717],[2.849,-10.689],[8.705,2.321],[-0.136,0.927]],"v":[[17.557,4.873],[6.907,19.51],[-5.889,23.777],[-14.445,14.64],[-16.813,-4.288],[6.63,-23.183],[18.109,2.158]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"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":0,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.583999991417,0.226999998093,0.012000000104,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":[19.915,25.963],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"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":70,"op":170,"st":0,"bm":0},{"ddd":0,"ind":134,"ty":4,"nm":"beak_shad","parent":133,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[23.104,40.172,0],"ix":2,"l":2},"a":{"a":0,"k":[22.318,28.428,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":1,"k":[{"i":{"x":0,"y":1},"o":{"x":0.333,"y":0},"t":89,"s":[{"i":[[0,0],[0.325,-12.821],[-13.76,-2.314],[8.575,29.159]],"o":[[0,0],[-0.282,11.143],[18.343,3.086],[0,0]],"v":[[-15.174,-28.178],[-21.786,-7.822],[-5.876,25.092],[13.492,-26.524]],"c":true}]},{"i":{"x":0.382,"y":1},"o":{"x":0.666,"y":0},"t":96.451,"s":[{"i":[[0,0],[4.393,-13.371],[-13.76,-2.314],[8.575,29.159]],"o":[[0,0],[-3.479,10.59],[18.343,3.086],[0,0]],"v":[[-5.756,-32.905],[-22.483,-9.725],[-9.497,13.625],[12.795,-28.427]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.949,"y":0},"t":110,"s":[{"i":[[0,0],[0.325,-12.821],[-13.76,-2.314],[8.575,29.159]],"o":[[0,0],[-0.282,11.143],[18.343,3.086],[0,0]],"v":[[-15.174,-28.178],[-21.786,-7.822],[0.835,21.455],[13.492,-26.524]],"c":true}]},{"t":140,"s":[{"i":[[0,0],[0.325,-12.821],[-13.76,-2.314],[8.575,29.159]],"o":[[0,0],[-0.282,11.143],[18.343,3.086],[0,0]],"v":[[-15.174,-28.178],[-21.786,-7.822],[-5.876,25.092],[13.492,-26.524]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"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":0,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.987999975681,0.796000003815,0.11400000006,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":[22.317,28.428],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"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":70,"op":170,"st":0,"bm":0},{"ddd":0,"ind":135,"ty":4,"nm":"eye_l_bl2","parent":137,"sr":1,"ks":{"o":{"a":1,"k":[{"t":85,"s":[0],"h":1},{"t":88,"s":[100],"h":1},{"t":112,"s":[0],"h":1},{"t":116,"s":[100],"h":1}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[20.782,11.647,0],"ix":2,"l":2},"a":{"a":0,"k":[9.274,6.623,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":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":85,"s":[{"i":[[1.39,-1.603],[4.591,1.224],[0.081,0.849],[-4.591,-1.224]],"o":[[0.205,-0.083],[-4.591,-1.224],[-0.156,-2.117],[4.591,1.224]],"v":[[7.479,9.653],[-0.257,5.082],[-9.148,5.221],[0.038,4.351]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0},"t":92,"s":[{"i":[[0.546,-2.05],[4.591,1.224],[-0.877,3.292],[-4.591,-1.224]],"o":[[-0.858,3.22],[-4.591,-1.224],[0.547,-2.051],[4.591,1.224]],"v":[[8.479,3.153],[-0.007,1.582],[-8.148,-1.279],[1.789,-5.149]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0},"t":108.691,"s":[{"i":[[0.546,-2.05],[4.591,1.224],[-0.877,3.292],[-4.591,-1.224]],"o":[[-0.858,3.22],[-4.591,-1.224],[0.547,-2.051],[4.591,1.224]],"v":[[8.479,3.153],[-0.007,1.582],[-8.148,-1.279],[1.789,-5.149]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":113.539,"s":[{"i":[[1.39,-1.603],[4.591,1.224],[0.081,0.849],[-4.591,-1.224]],"o":[[0.205,-0.083],[-4.591,-1.224],[-0.156,-2.117],[4.591,1.224]],"v":[[7.479,9.653],[-0.257,5.082],[-9.148,5.221],[0.038,4.351]],"c":true}]},{"t":120,"s":[{"i":[[0.546,-2.05],[4.591,1.224],[-0.877,3.292],[-4.591,-1.224]],"o":[[-0.858,3.22],[-4.591,-1.224],[0.547,-2.051],[4.591,1.224]],"v":[[8.479,3.153],[-0.007,1.582],[-8.148,-1.279],[1.789,-5.149]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"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":0,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.961000025272,0.961000025272,0.961000025272,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":[9.274,6.623],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"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":70,"op":170,"st":0,"bm":0},{"ddd":0,"ind":136,"ty":4,"nm":"eye_l_bl1","parent":137,"sr":1,"ks":{"o":{"a":1,"k":[{"t":85,"s":[0],"h":1},{"t":88,"s":[100],"h":1},{"t":112,"s":[0],"h":1},{"t":116,"s":[100],"h":1}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[17.514,28.882,0],"ix":2,"l":2},"a":{"a":0,"k":[12.335,11.569,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":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":85,"s":[{"i":[[0.154,-0.694],[6.231,1.661],[-0.839,1.802],[-6.231,-1.661]],"o":[[-0.846,0.306],[-6.231,-1.661],[0.221,-0.762],[6.231,1.661]],"v":[[12.298,-5.972],[1.515,-11.092],[-9.02,-11.403],[1.737,-10.929]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0},"t":92,"s":[{"i":[[1.788,-6.706],[6.231,1.661],[-1.066,3.998],[-6.231,-1.661]],"o":[[-1.066,3.999],[-6.231,-1.661],[1.71,-6.416],[6.231,1.661]],"v":[[10.298,0.778],[-3.486,9.658],[-11.02,-4.903],[-0.264,-2.429]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0},"t":108.691,"s":[{"i":[[1.788,-6.706],[6.231,1.661],[-1.066,3.998],[-6.231,-1.661]],"o":[[-1.066,3.999],[-6.231,-1.661],[1.71,-6.416],[6.231,1.661]],"v":[[10.298,0.778],[-3.486,9.658],[-11.02,-4.903],[-0.264,-2.429]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":113.539,"s":[{"i":[[0.154,-0.694],[6.231,1.661],[-0.839,1.802],[-6.231,-1.661]],"o":[[-0.846,0.306],[-6.231,-1.661],[0.221,-0.762],[6.231,1.661]],"v":[[12.298,-5.972],[1.515,-11.092],[-9.02,-11.403],[1.737,-10.929]],"c":true}]},{"t":120,"s":[{"i":[[1.788,-6.706],[6.231,1.661],[-1.066,3.998],[-6.231,-1.661]],"o":[[-1.066,3.999],[-6.231,-1.661],[1.71,-6.416],[6.231,1.661]],"v":[[10.298,0.778],[-3.486,9.658],[-11.02,-4.903],[-0.264,-2.429]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"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":0,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.282000005245,0.286000013351,0.286000013351,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":[12.335,11.57],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"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":70,"op":170,"st":0,"bm":0},{"ddd":0,"ind":137,"ty":4,"nm":"eye_l","parent":133,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0,"y":1},"o":{"x":0.333,"y":0},"t":89,"s":[-10.692,-13.618,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":1},"o":{"x":0.666,"y":0},"t":96.451,"s":[-9.449,-12.553,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.355,"y":1},"o":{"x":0.167,"y":0.167},"t":103.227,"s":[-10.692,-13.618,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0,"y":1},"o":{"x":0.578,"y":0},"t":110,"s":[-0.953,-12.908,0],"to":[0,0,0],"ti":[0,0,0]},{"t":140,"s":[-10.692,-13.618,0]}],"ix":2,"l":2},"a":{"a":0,"k":[18.32,22.44,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0,0,0],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":89,"s":[100,100,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,1,1]},"o":{"x":[0.621,0.621,0.621],"y":[0,0,0]},"t":96.451,"s":[100,100,100]},{"i":{"x":[0.355,0.355,0.355],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0,0]},"t":103.227,"s":[100,100,100]},{"i":{"x":[0,0,0],"y":[1,1,1]},"o":{"x":[0.578,0.578,0.578],"y":[0,0,0]},"t":110,"s":[80,100,100]},{"t":140,"s":[100,100,100]}],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":85,"s":[{"i":[[3.909,-2.445],[8.357,2.228],[1.027,4.56],[-8.357,-2.228]],"o":[[-3.986,2.493],[-8.356,-2.227],[-1.151,-5.112],[8.357,2.227]],"v":[[15.132,4.033],[0.929,-1.788],[-15.132,-4.033],[3.072,-7.212]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0},"t":92,"s":[{"i":[[2.939,-11.025],[8.357,2.228],[-2.939,11.024],[-8.357,-2.228]],"o":[[-2.939,11.025],[-8.356,-2.227],[2.939,-11.025],[8.357,2.227]],"v":[[15.132,4.033],[-5.322,19.962],[-15.132,-4.033],[5.322,-19.962]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0},"t":108.691,"s":[{"i":[[2.939,-11.025],[8.357,2.228],[-2.939,11.024],[-8.357,-2.228]],"o":[[-2.939,11.025],[-8.356,-2.227],[2.939,-11.025],[8.357,2.227]],"v":[[15.132,4.033],[-5.322,19.962],[-15.132,-4.033],[5.322,-19.962]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":113.539,"s":[{"i":[[3.909,-2.445],[8.357,2.228],[1.027,4.56],[-8.357,-2.228]],"o":[[-3.986,2.493],[-8.356,-2.227],[-1.151,-5.112],[8.357,2.227]],"v":[[15.132,4.033],[0.929,-1.788],[-15.132,-4.033],[3.072,-7.212]],"c":true}]},{"t":120,"s":[{"i":[[2.939,-11.025],[8.357,2.228],[-2.939,11.024],[-8.357,-2.228]],"o":[[-2.939,11.025],[-8.356,-2.227],[2.939,-11.025],[8.357,2.227]],"v":[[15.132,4.033],[-5.322,19.962],[-15.132,-4.033],[5.322,-19.962]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"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":0,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.067000001669,0.067000001669,0.067000001669,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":[18.32,22.44],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"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":70,"op":170,"st":0,"bm":0},{"ddd":0,"ind":138,"ty":4,"nm":"eye_r_bl2","parent":140,"sr":1,"ks":{"o":{"a":1,"k":[{"t":85,"s":[0],"h":1},{"t":88,"s":[100],"h":1},{"t":112,"s":[0],"h":1},{"t":116,"s":[100],"h":1}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[20.782,11.647,0],"ix":2,"l":2},"a":{"a":0,"k":[9.274,6.623,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":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":85,"s":[{"i":[[0.261,-0.794],[4.591,1.224],[0.137,0.138],[-4.591,-1.224]],"o":[[-0.315,1.263],[-4.591,-1.224],[-0.163,-1.359],[4.591,1.224]],"v":[[7.729,9.403],[-0.007,4.582],[-11.148,4.471],[-0.462,4.601]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0},"t":92,"s":[{"i":[[0.546,-2.05],[4.591,1.224],[-0.877,3.292],[-4.591,-1.224]],"o":[[-0.858,3.22],[-4.591,-1.224],[0.547,-2.051],[4.591,1.224]],"v":[[8.479,3.153],[-0.007,1.582],[-8.147,-1.279],[1.789,-5.149]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0},"t":108.691,"s":[{"i":[[0.546,-2.05],[4.591,1.224],[-0.877,3.292],[-4.591,-1.224]],"o":[[-0.858,3.22],[-4.591,-1.224],[0.547,-2.051],[4.591,1.224]],"v":[[8.479,3.153],[-0.007,1.582],[-8.147,-1.279],[1.789,-5.149]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":113.539,"s":[{"i":[[0.261,-0.794],[4.591,1.224],[0.137,0.138],[-4.591,-1.224]],"o":[[-0.315,1.263],[-4.591,-1.224],[-0.163,-1.359],[4.591,1.224]],"v":[[7.729,9.403],[-0.007,4.582],[-11.148,4.471],[-0.462,4.601]],"c":true}]},{"t":120,"s":[{"i":[[0.546,-2.05],[4.591,1.224],[-0.877,3.292],[-4.591,-1.224]],"o":[[-0.858,3.22],[-4.591,-1.224],[0.547,-2.051],[4.591,1.224]],"v":[[8.479,3.153],[-0.007,1.582],[-8.147,-1.279],[1.789,-5.149]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"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":0,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.961000025272,0.961000025272,0.961000025272,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":[9.274,6.623],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"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":70,"op":170,"st":0,"bm":0},{"ddd":0,"ind":139,"ty":4,"nm":"eye_r_bl1","parent":140,"sr":1,"ks":{"o":{"a":1,"k":[{"t":85,"s":[0],"h":1},{"t":88,"s":[100],"h":1},{"t":112,"s":[0],"h":1},{"t":116,"s":[100],"h":1}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[17.514,28.882,0],"ix":2,"l":2},"a":{"a":0,"k":[12.336,11.57,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":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":85,"s":[{"i":[[1.867,-0.418],[6.231,1.661],[-0.355,1.246],[-6.231,-1.661]],"o":[[-1.54,0.345],[-6.231,-1.661],[0.277,-0.223],[6.231,1.661]],"v":[[11.048,-4.972],[1.015,-10.592],[-10.019,-10.653],[0.987,-11.179]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0},"t":92,"s":[{"i":[[1.788,-6.706],[6.231,1.661],[-1.066,3.998],[-6.231,-1.661]],"o":[[-1.066,3.999],[-6.231,-1.661],[1.71,-6.416],[6.231,1.661]],"v":[[10.298,0.778],[-3.486,9.658],[-11.02,-4.903],[-0.263,-2.429]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0},"t":108.691,"s":[{"i":[[1.788,-6.706],[6.231,1.661],[-1.066,3.998],[-6.231,-1.661]],"o":[[-1.066,3.999],[-6.231,-1.661],[1.71,-6.416],[6.231,1.661]],"v":[[10.298,0.778],[-3.486,9.658],[-11.02,-4.903],[-0.263,-2.429]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":113.539,"s":[{"i":[[1.867,-0.418],[6.231,1.661],[-0.355,1.246],[-6.231,-1.661]],"o":[[-1.54,0.345],[-6.231,-1.661],[0.277,-0.223],[6.231,1.661]],"v":[[11.048,-4.972],[1.015,-10.592],[-10.019,-10.653],[0.987,-11.179]],"c":true}]},{"t":120,"s":[{"i":[[1.788,-6.706],[6.231,1.661],[-1.066,3.998],[-6.231,-1.661]],"o":[[-1.066,3.999],[-6.231,-1.661],[1.71,-6.416],[6.231,1.661]],"v":[[10.298,0.778],[-3.486,9.658],[-11.02,-4.903],[-0.263,-2.429]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"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":0,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.282000005245,0.286000013351,0.286000013351,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":[12.335,11.57],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"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":70,"op":170,"st":0,"bm":0},{"ddd":0,"ind":140,"ty":4,"nm":"eye_r","parent":133,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0,"y":1},"o":{"x":0.333,"y":0},"t":89,"s":[67.002,7.093,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.877},"o":{"x":0.666,"y":0},"t":96.451,"s":[58.626,-0.605,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.355,"y":1},"o":{"x":0.167,"y":0.134},"t":103.227,"s":[67.002,7.093,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0,"y":1},"o":{"x":0.578,"y":0},"t":110,"s":[67.261,7.284,0],"to":[0,0,0],"ti":[0,0,0]},{"t":140,"s":[67.002,7.093,0]}],"ix":2,"l":2},"a":{"a":0,"k":[18.32,22.439,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0,0,0],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":89,"s":[100,100,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,1,1]},"o":{"x":[0.621,0.621,0.621],"y":[0,0,0]},"t":96.451,"s":[80,100,100]},{"i":{"x":[0.355,0.355,0.355],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"t":103.227,"s":[100,100,100]},{"i":{"x":[0,0,0],"y":[1,1,1]},"o":{"x":[0.578,0.578,0.578],"y":[0,0,0]},"t":110,"s":[100,100,100]},{"t":140,"s":[100,100,100]}],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":85,"s":[{"i":[[2.634,-3.48],[8.357,2.228],[1.332,4.35],[-8.357,-2.228]],"o":[[-3.431,4.533],[-8.356,-2.227],[-1.216,-3.968],[8.357,2.227]],"v":[[15.132,4.033],[0.179,-2.788],[-15.131,-4.033],[2.321,-6.712]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0},"t":92,"s":[{"i":[[2.939,-11.025],[8.357,2.228],[-2.939,11.024],[-8.357,-2.228]],"o":[[-2.939,11.025],[-8.356,-2.227],[2.939,-11.025],[8.357,2.227]],"v":[[15.132,4.033],[-5.321,19.962],[-15.131,-4.033],[5.321,-19.962]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0},"t":108.691,"s":[{"i":[[2.939,-11.025],[8.357,2.228],[-2.939,11.024],[-8.357,-2.228]],"o":[[-2.939,11.025],[-8.356,-2.227],[2.939,-11.025],[8.357,2.227]],"v":[[15.132,4.033],[-5.321,19.962],[-15.131,-4.033],[5.321,-19.962]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":113.539,"s":[{"i":[[2.634,-3.48],[8.357,2.228],[1.332,4.35],[-8.357,-2.228]],"o":[[-3.431,4.533],[-8.356,-2.227],[-1.216,-3.968],[8.357,2.227]],"v":[[15.132,4.033],[0.179,-2.788],[-15.131,-4.033],[2.321,-6.712]],"c":true}]},{"t":120,"s":[{"i":[[2.939,-11.025],[8.357,2.228],[-2.939,11.024],[-8.357,-2.228]],"o":[[-2.939,11.025],[-8.356,-2.227],[2.939,-11.025],[8.357,2.227]],"v":[[15.132,4.033],[-5.321,19.962],[-15.131,-4.033],[5.321,-19.962]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"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":0,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.067000001669,0.067000001669,0.067000001669,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":[18.32,22.44],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"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":70,"op":170,"st":0,"bm":0},{"ddd":0,"ind":141,"ty":4,"nm":"head_bl","parent":145,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.453],"y":[1]},"o":{"x":[0.773],"y":[0]},"t":80,"s":[0]},{"i":{"x":[0.355],"y":[1]},"o":{"x":[0.62],"y":[0]},"t":95,"s":[6.555]},{"i":{"x":[0],"y":[1]},"o":{"x":[0.578],"y":[0]},"t":110,"s":[0]},{"t":140,"s":[6.555]}],"ix":10},"p":{"a":1,"k":[{"i":{"x":0.453,"y":1},"o":{"x":0.773,"y":0},"t":80,"s":[139.506,32.601,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.355,"y":1},"o":{"x":0.62,"y":0},"t":95,"s":[149.436,41.692,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0,"y":1},"o":{"x":0.578,"y":0},"t":110,"s":[139.506,32.601,0],"to":[0,0,0],"ti":[0,0,0]},{"t":140,"s":[149.436,41.692,0]}],"ix":2,"l":2},"a":{"a":0,"k":[25.789,20.981,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,0],[-6.378,-3.534]],"o":[[0,0],[0,0]],"v":[[-5.29,-2.599],[5.29,2.599]],"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":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":[20.29,17.599],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"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":[[0,0],[-1.313,-0.891]],"o":[[1.243,0.787],[0,0]],"v":[[-1.919,-1.258],[1.919,1.258]],"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":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":[34.659,25.704],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"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}],"ip":70,"op":170,"st":0,"bm":0},{"ddd":0,"ind":142,"ty":4,"nm":"head4","parent":145,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[103.985,91.496,0],"ix":2,"l":2},"a":{"a":0,"k":[117.329,111.246,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,0],[-3.696,13.867],[58.314,15.545],[13.471,-50.535],[-5.642,-12.859],[-11.388,-10.339]],"o":[[14.991,-7.265],[13.272,-49.788],[-59.056,-15.742],[-3.456,12.963],[0,0],[0,0]],"v":[[52.787,91.246],[84.057,54.218],[23.35,-75.504],[-93.873,6.787],[-90.094,46.283],[-72.377,71.821]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.808000028133,0.458999991417,0,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":8,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[117.329,111.246],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"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":"tm","s":{"a":1,"k":[{"i":{"x":[0.453],"y":[1]},"o":{"x":[0.773],"y":[0]},"t":80,"s":[0]},{"i":{"x":[0.355],"y":[1]},"o":{"x":[0.62],"y":[0]},"t":95,"s":[0]},{"i":{"x":[0],"y":[1]},"o":{"x":[0.578],"y":[0]},"t":110,"s":[0]},{"t":140,"s":[0]}],"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.453],"y":[1]},"o":{"x":[0.773],"y":[0]},"t":80,"s":[100]},{"i":{"x":[0.355],"y":[1]},"o":{"x":[0.62],"y":[0]},"t":95,"s":[94]},{"i":{"x":[0],"y":[1]},"o":{"x":[0.578],"y":[0]},"t":110,"s":[100]},{"t":140,"s":[94]}],"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":70,"op":170,"st":0,"bm":0},{"ddd":0,"ind":143,"ty":4,"nm":"head3","parent":145,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[113.858,59.375,0],"ix":2,"l":2},"a":{"a":0,"k":[60.724,41.946,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":[[4.216,-15.817],[31.07,8.282],[-4.217,15.817],[-31.023,-8.457]],"o":[[-4.216,15.817],[-31.07,-8.283],[4.216,-15.817],[31.962,8.712]],"v":[[56.258,19.771],[-7.634,33.414],[-56.257,-10.222],[10.601,-33.239]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"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":0,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.991999983788,0.991999983788,0.615999996662,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":[60.724,41.946],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"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":70,"op":170,"st":0,"bm":0},{"ddd":0,"ind":144,"ty":4,"nm":"head2","parent":145,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[103.527,87.848,0],"ix":2,"l":2},"a":{"a":0,"k":[82.548,74.918,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":[[9.177,-34.428],[39.206,9.704],[-6.819,25.581],[-46.907,-12.504]],"o":[[-6.819,25.581],[-49.703,-12.303],[9.315,-34.944],[46.318,12.347]],"v":[[73.121,40.486],[-14.262,64.964],[-75.479,-0.4],[21.027,-62.164]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"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":0,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.995999991894,0.902000010014,0.234999999404,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":[82.548,74.918],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"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":70,"op":170,"st":0,"bm":0},{"ddd":0,"ind":145,"ty":4,"nm":"head1","parent":149,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.453],"y":[1]},"o":{"x":[0.773],"y":[0]},"t":80,"s":[0]},{"i":{"x":[0.355],"y":[1]},"o":{"x":[0.62],"y":[0]},"t":95,"s":[-20.676]},{"i":{"x":[0],"y":[1]},"o":{"x":[0.578],"y":[0]},"t":110,"s":[0]},{"t":140,"s":[-20.676]}],"ix":10},"p":{"a":1,"k":[{"i":{"x":0.453,"y":1},"o":{"x":0.773,"y":0},"t":80,"s":[124.041,75.846,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.355,"y":1},"o":{"x":0.62,"y":0},"t":95,"s":[144.041,75.846,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0,"y":1},"o":{"x":0.578,"y":0},"t":110,"s":[124.041,75.846,0],"to":[0,0,0],"ti":[0,0,0]},{"t":140,"s":[144.041,75.846,0]}],"ix":2,"l":2},"a":{"a":0,"k":[100.375,195.015,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":[[13.272,-49.788],[49.134,13.098],[-9.861,36.993],[-59.057,-15.742]],"o":[[-9.861,36.993],[-49.134,-13.097],[13.471,-50.535],[58.314,15.545]],"v":[[87.26,43.46],[-20.142,88.907],[-90.671,-3.972],[26.553,-86.262]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"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":0,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.987999975681,0.796000003815,0.11400000006,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":[100.782,102.255],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"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":70,"op":170,"st":0,"bm":0},{"ddd":0,"ind":146,"ty":4,"nm":"body4","parent":149,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[122.654,122.223,0],"ix":2,"l":2},"a":{"a":0,"k":[142.404,141.973,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,-66.537],[67.602,0],[0,49.438],[-81.253,0]],"o":[[0,49.438],[-67.602,0],[0,-67.536],[80.233,0]],"v":[[122.404,24.542],[0,121.973],[-122.404,24.542],[0,-121.972]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.808000028133,0.458999991417,0,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":8,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[142.404,141.973],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"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":70,"op":170,"st":0,"bm":0},{"ddd":0,"ind":147,"ty":4,"nm":"body3","parent":149,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[120.726,53.422,0],"ix":2,"l":2},"a":{"a":0,"k":[92.328,39.364,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":[[-24.938,-25.244],[44.659,0],[11.674,24.528],[-41.222,0]],"o":[[-11.941,24.289],[-44.957,0],[25.61,-37.204],[40.817,0]],"v":[[92.079,-6.395],[1.971,39.114],[-92.079,-1.91],[1.971,-39.114]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"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":0,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,0.662999987602,0.071000002325,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":[92.328,39.364],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"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":70,"op":170,"st":0,"bm":0},{"ddd":0,"ind":148,"ty":4,"nm":"body2","parent":149,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[122.654,82.349,0],"ix":2,"l":2},"a":{"a":0,"k":[87.4,49.029,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,-29.679],[50.826,0],[0,25.413],[-47.996,0]],"o":[[0,25.413],[-50.825,0],[0,-28.565],[47.927,0]],"v":[[87.15,5.752],[-0.001,48.779],[-87.15,5.752],[-0.001,-48.779]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"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":0,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.987999975681,0.875,0.224000006914,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":[87.4,49.029],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"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":70,"op":170,"st":0,"bm":0},{"ddd":0,"ind":149,"ty":4,"nm":"body1","parent":3,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.453],"y":[1]},"o":{"x":[0.773],"y":[0]},"t":80,"s":[-4]},{"i":{"x":[0.355],"y":[1]},"o":{"x":[0.62],"y":[0]},"t":95,"s":[6.83]},{"i":{"x":[0],"y":[1]},"o":{"x":[0.578],"y":[0]},"t":110,"s":[-4]},{"t":140,"s":[0]}],"ix":10},"p":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":70,"s":[67.584,171.386,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0,"y":0},"o":{"x":0.167,"y":0.167},"t":85,"s":[67.584,115.386,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":0.667},"o":{"x":0.167,"y":0.167},"t":140,"s":[67.584,115.386,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0},"t":151,"s":[67.584,115.386,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":1},"o":{"x":0.167,"y":0},"t":155,"s":[67.584,95.386,0],"to":[0,0,0],"ti":[0,0,0]},{"t":166,"s":[67.584,171.386,0]}],"ix":2,"l":2},"a":{"a":0,"k":[122.654,244.195,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,-66.537],[67.602,0],[0,49.438],[-81.253,0]],"o":[[0,49.438],[-67.602,0],[0,-67.536],[80.233,0]],"v":[[122.404,24.542],[0,121.973],[-122.404,24.542],[0,-121.973]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"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":0,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.987999975681,0.796000003815,0.11400000006,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":[122.654,122.223],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"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":70,"op":170,"st":0,"bm":0},{"ddd":0,"ind":150,"ty":4,"nm":"wing_r4","parent":155,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[88.898,65.006,0],"ix":2,"l":2},"a":{"a":0,"k":[90.221,63.386,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":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":87,"s":[{"i":[[-22.559,17.979],[-30.942,-4.12],[-3.037,-15.396],[36.756,0.551]],"o":[[0,0],[52.631,7.008],[3.483,17.655],[-34.454,-0.517]],"v":[[-67.412,-44.501],[-18.895,-53.049],[61.467,-52.565],[-33.624,14.61]],"c":true}]},{"i":{"x":0.833,"y":1},"o":{"x":0.333,"y":0},"t":92,"s":[{"i":[[-22.559,17.979],[-29.54,-10.087],[3.158,-11.365],[33.255,-9.026]],"o":[[0,0],[42.069,14.367],[-2.773,9.981],[-33.255,9.026]],"v":[[-67.412,-44.501],[-18.895,-53.049],[47.313,11.257],[-33.624,14.61]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":97,"s":[{"i":[[-22.559,17.979],[-30.942,-4.12],[-3.037,-15.396],[36.756,0.551]],"o":[[0,0],[52.631,7.008],[3.483,17.655],[-34.454,-0.517]],"v":[[-67.412,-44.501],[-18.895,-53.049],[61.467,-52.565],[-33.624,14.61]],"c":true}]},{"i":{"x":0.833,"y":1},"o":{"x":0.333,"y":0},"t":102,"s":[{"i":[[-22.559,17.979],[-29.54,-10.087],[3.158,-11.365],[33.255,-9.026]],"o":[[0,0],[42.069,14.367],[-2.773,9.981],[-33.255,9.026]],"v":[[-67.412,-44.501],[-18.895,-53.049],[47.313,11.257],[-33.624,14.61]],"c":true}]},{"i":{"x":0.833,"y":1},"o":{"x":0.333,"y":0},"t":107,"s":[{"i":[[-22.559,17.979],[-30.942,-4.12],[-3.037,-15.396],[36.756,0.551]],"o":[[0,0],[52.631,7.008],[3.483,17.655],[-34.454,-0.517]],"v":[[-67.412,-44.501],[-18.895,-53.049],[61.467,-52.565],[-33.624,14.61]],"c":true}]},{"i":{"x":0.833,"y":1},"o":{"x":0.167,"y":0},"t":112,"s":[{"i":[[-22.559,17.979],[-29.54,-10.087],[3.158,-11.365],[33.255,-9.026]],"o":[[0,0],[42.069,14.367],[-2.773,9.981],[-33.255,9.026]],"v":[[-67.412,-44.501],[-18.895,-53.049],[47.313,11.257],[-33.624,14.61]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0},"t":154,"s":[{"i":[[-22.559,17.979],[-29.54,-10.087],[3.158,-11.365],[33.255,-9.026]],"o":[[0,0],[42.069,14.367],[-2.773,9.981],[-33.255,9.026]],"v":[[-67.412,-44.501],[-18.895,-53.049],[47.313,11.257],[-33.624,14.61]],"c":true}]},{"t":161,"s":[{"i":[[-22.559,17.979],[-28.894,-11.81],[1.9,-11.642],[36.756,0.551]],"o":[[0,0],[44.231,18.078],[-2.898,17.761],[-34.454,-0.517]],"v":[[-67.412,-44.501],[-18.895,-53.049],[60.021,-17.548],[-33.624,14.61]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.808000028133,0.458999991417,0,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":8,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[90.221,63.386],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"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":76,"op":170,"st":0,"bm":0},{"ddd":0,"ind":151,"ty":4,"nm":"wing_r3","parent":155,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[84.717,30.786,0],"ix":2,"l":2},"a":{"a":0,"k":[50.514,39.922,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":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":87,"s":[{"i":[[0,0],[-26.186,3.797]],"o":[[0,0],[0,0]],"v":[[-21.999,-10.559],[33.374,-12.153]],"c":false}]},{"i":{"x":0.833,"y":1},"o":{"x":0.333,"y":0},"t":92,"s":[{"i":[[0,0],[-21.858,-21.337]],"o":[[0,0],[0,0]],"v":[[-23.014,-12.422],[23.014,12.422]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":97,"s":[{"i":[[0,0],[-26.186,3.797]],"o":[[0,0],[0,0]],"v":[[-21.999,-10.559],[33.374,-12.153]],"c":false}]},{"i":{"x":0.833,"y":1},"o":{"x":0.333,"y":0},"t":102,"s":[{"i":[[0,0],[-21.858,-21.337]],"o":[[0,0],[0,0]],"v":[[-23.014,-12.422],[23.014,12.422]],"c":false}]},{"i":{"x":0.833,"y":1},"o":{"x":0.333,"y":0},"t":107,"s":[{"i":[[0,0],[-26.186,3.797]],"o":[[0,0],[0,0]],"v":[[-21.999,-10.559],[33.374,-12.153]],"c":false}]},{"i":{"x":0.833,"y":1},"o":{"x":0.167,"y":0},"t":112,"s":[{"i":[[0,0],[-21.858,-21.337]],"o":[[0,0],[0,0]],"v":[[-23.014,-12.422],[23.014,12.422]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0},"t":154,"s":[{"i":[[0,0],[-21.858,-21.337]],"o":[[0,0],[0,0]],"v":[[-23.014,-12.422],[23.014,12.422]],"c":false}]},{"t":161,"s":[{"i":[[0,0],[-18.503,-7.991]],"o":[[0,0],[0,0]],"v":[[-11.898,-4.625],[32.063,6.381]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.995999991894,0.902000010014,0.234999999404,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":11,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[50.514,39.922],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"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":76,"op":170,"st":0,"bm":0},{"ddd":0,"ind":152,"ty":4,"nm":"wing_r2","parent":155,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[75.174,39.177,0],"ix":2,"l":2},"a":{"a":0,"k":[65.77,39.179,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":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":87,"s":[{"i":[[-10.869,-14.243],[-8.842,7.045],[-27.243,-2.537],[-10.226,-3.612],[-0.687,2.477],[47.214,4.823],[0,0]],"o":[[-4.376,-11.157],[0,0],[39.19,3.65],[5.054,-0.088],[3.161,-11.364],[-28.886,-2.951],[-13.15,10.49]],"v":[[-52.283,25.876],[-46.975,-4.999],[-4.458,-12.492],[69.508,-17.811],[73.092,-27.568],[-6.611,-26.531],[-52.37,-20.296]],"c":true}]},{"i":{"x":0.833,"y":1},"o":{"x":0.333,"y":0},"t":92,"s":[{"i":[[-10.869,-14.243],[-8.842,7.045],[-25.893,-8.84],[-3.366,-13.37],[-0.687,2.477],[42.065,14.368],[0,0]],"o":[[-4.376,-11.157],[0,0],[32.123,10.971],[5.054,-0.088],[3.161,-11.364],[-29.542,-10.085],[-13.15,10.49]],"v":[[-52.283,25.876],[-46.975,-4.999],[-4.458,-12.492],[53.33,38.93],[62.359,35.467],[-3.845,-28.844],[-52.37,-20.296]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":97,"s":[{"i":[[-10.869,-14.243],[-8.842,7.045],[-27.243,-2.537],[-10.226,-3.612],[-0.687,2.477],[47.214,4.823],[0,0]],"o":[[-4.376,-11.157],[0,0],[39.19,3.65],[5.054,-0.088],[3.161,-11.364],[-28.886,-2.951],[-13.15,10.49]],"v":[[-52.283,25.876],[-46.975,-4.999],[-4.458,-12.492],[69.508,-17.811],[73.092,-27.568],[-6.611,-26.531],[-52.37,-20.296]],"c":true}]},{"i":{"x":0.833,"y":1},"o":{"x":0.333,"y":0},"t":102,"s":[{"i":[[-10.869,-14.243],[-8.842,7.045],[-25.893,-8.84],[-3.366,-13.37],[-0.687,2.477],[42.065,14.368],[0,0]],"o":[[-4.376,-11.157],[0,0],[32.123,10.971],[5.054,-0.088],[3.161,-11.364],[-29.542,-10.085],[-13.15,10.49]],"v":[[-52.283,25.876],[-46.975,-4.999],[-4.458,-12.492],[53.33,38.93],[62.359,35.467],[-3.845,-28.844],[-52.37,-20.296]],"c":true}]},{"i":{"x":0.833,"y":1},"o":{"x":0.333,"y":0},"t":107,"s":[{"i":[[-10.869,-14.243],[-8.842,7.045],[-27.243,-2.537],[-10.226,-3.612],[-0.687,2.477],[47.214,4.823],[0,0]],"o":[[-4.376,-11.157],[0,0],[39.19,3.65],[5.054,-0.088],[3.161,-11.364],[-28.886,-2.951],[-13.15,10.49]],"v":[[-52.283,25.876],[-46.975,-4.999],[-4.458,-12.492],[69.508,-17.811],[73.092,-27.568],[-6.611,-26.531],[-52.37,-20.296]],"c":true}]},{"i":{"x":0.833,"y":1},"o":{"x":0.167,"y":0},"t":112,"s":[{"i":[[-10.869,-14.243],[-8.842,7.045],[-25.893,-8.84],[-3.366,-13.37],[-0.687,2.477],[42.065,14.368],[0,0]],"o":[[-4.376,-11.157],[0,0],[32.123,10.971],[5.054,-0.088],[3.161,-11.364],[-29.542,-10.085],[-13.15,10.49]],"v":[[-52.283,25.876],[-46.975,-4.999],[-4.458,-12.492],[53.33,38.93],[62.359,35.467],[-3.845,-28.844],[-52.37,-20.296]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0},"t":154,"s":[{"i":[[-10.869,-14.243],[-8.842,7.045],[-25.893,-8.84],[-3.366,-13.37],[-0.687,2.477],[42.065,14.368],[0,0]],"o":[[-4.376,-11.157],[0,0],[32.123,10.971],[5.054,-0.088],[3.161,-11.364],[-29.542,-10.085],[-13.15,10.49]],"v":[[-52.283,25.876],[-46.975,-4.999],[-4.458,-12.492],[53.33,38.93],[62.359,35.467],[-3.845,-28.844],[-52.37,-20.296]],"c":true}]},{"t":161,"s":[{"i":[[-10.869,-14.243],[-8.842,7.045],[-27.243,-2.537],[-10.226,-3.612],[-0.568,2.507],[48.234,10.409],[0,0]],"o":[[-4.376,-11.157],[0,0],[39.19,3.65],[5.054,-0.088],[2.06,-9.099],[-28.383,-6.125],[-13.15,10.49]],"v":[[-52.283,25.876],[-46.975,-4.999],[-2.091,-5.905],[69.335,15.722],[72.919,5.966],[-7.949,-22.863],[-52.37,-20.296]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"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":0,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.987999975681,0.796000003815,0.11400000006,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":[65.77,39.18],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"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":76,"op":170,"st":0,"bm":0},{"ddd":0,"ind":153,"ty":3,"nm":"NULL CONTROL","parent":3,"sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.453,"y":1},"o":{"x":0.773,"y":0},"t":80,"s":[52.416,-56.006,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.355,"y":1},"o":{"x":0.62,"y":0},"t":95,"s":[80.416,-56.006,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0,"y":1},"o":{"x":0.578,"y":0},"t":110,"s":[56.416,-56.006,0],"to":[0,0,0],"ti":[0,0,0]},{"t":140,"s":[67.416,-56.006,0]}],"ix":2,"l":2},"a":{"a":0,"k":[60,60,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"ip":70,"op":170,"st":0,"bm":0},{"ddd":0,"ind":154,"ty":3,"nm":"NULL CONTROL","parent":153,"sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":70,"s":[35.411]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":85,"s":[-3.748]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":151,"s":[-3.748]},{"t":158,"s":[-66.476]}],"ix":10},"p":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":70,"s":[98.066,119.369,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":0.667},"o":{"x":0.167,"y":0.167},"t":85,"s":[98.066,49.369,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":1},"o":{"x":0.167,"y":0},"t":151,"s":[98.066,49.369,0],"to":[0,0,0],"ti":[0,0,0]},{"t":166,"s":[98.066,119.369,0]}],"ix":2,"l":2},"a":{"a":0,"k":[60,60,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"ip":70,"op":170,"st":0,"bm":0},{"ddd":0,"ind":155,"ty":4,"nm":"wing_r1","parent":154,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":85,"s":[-25.358]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":90,"s":[10.739]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":95,"s":[-25.358]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":100,"s":[10.739]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":105,"s":[-25.358]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":110,"s":[7.704]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":150,"s":[7.704]},{"t":168,"s":[-8.239]}],"ix":10},"p":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":80,"s":[60,60,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":0.667},"o":{"x":0.333,"y":0.333},"t":85,"s":[100,60,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":0.667},"o":{"x":0.167,"y":0.167},"t":92,"s":[100,60,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0},"t":151,"s":[100,60,0],"to":[0,0,0],"ti":[0,0,0]},{"t":158,"s":[78.192,104.994,0]}],"ix":2,"l":2},"a":{"a":0,"k":[13.816,43.208,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":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":87,"s":[{"i":[[-22.559,17.979],[-30.942,-4.12],[-3.037,-15.396],[36.756,0.551]],"o":[[0,0],[52.631,7.008],[3.483,17.655],[-34.454,-0.517]],"v":[[-47.662,-24.751],[0.855,-33.299],[81.217,-32.815],[-13.874,34.36]],"c":true}]},{"i":{"x":0.833,"y":1},"o":{"x":0.333,"y":0},"t":92,"s":[{"i":[[-22.559,17.979],[-29.54,-10.087],[3.158,-11.365],[33.255,-9.026]],"o":[[0,0],[42.069,14.367],[-2.773,9.981],[-33.255,9.026]],"v":[[-47.662,-24.751],[0.855,-33.299],[67.063,31.007],[-13.874,34.36]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":97,"s":[{"i":[[-22.559,17.979],[-30.942,-4.12],[-3.037,-15.396],[36.756,0.551]],"o":[[0,0],[52.631,7.008],[3.483,17.655],[-34.454,-0.517]],"v":[[-47.662,-24.751],[0.855,-33.299],[81.217,-32.815],[-13.874,34.36]],"c":true}]},{"i":{"x":0.833,"y":1},"o":{"x":0.333,"y":0},"t":102,"s":[{"i":[[-22.559,17.979],[-29.54,-10.087],[3.158,-11.365],[33.255,-9.026]],"o":[[0,0],[42.069,14.367],[-2.773,9.981],[-33.255,9.026]],"v":[[-47.662,-24.751],[0.855,-33.299],[67.063,31.007],[-13.874,34.36]],"c":true}]},{"i":{"x":0.833,"y":1},"o":{"x":0.333,"y":0},"t":107,"s":[{"i":[[-22.559,17.979],[-30.942,-4.12],[-3.037,-15.396],[36.756,0.551]],"o":[[0,0],[52.631,7.008],[3.483,17.655],[-34.454,-0.517]],"v":[[-47.662,-24.751],[0.855,-33.299],[81.217,-32.815],[-13.874,34.36]],"c":true}]},{"i":{"x":0.833,"y":1},"o":{"x":0.167,"y":0},"t":112,"s":[{"i":[[-22.559,17.979],[-29.54,-10.087],[3.158,-11.365],[33.255,-9.026]],"o":[[0,0],[42.069,14.367],[-2.773,9.981],[-33.255,9.026]],"v":[[-47.662,-24.751],[0.855,-33.299],[67.063,31.007],[-13.874,34.36]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0},"t":154,"s":[{"i":[[-22.559,17.979],[-29.54,-10.087],[3.158,-11.365],[33.255,-9.026]],"o":[[0,0],[42.069,14.367],[-2.773,9.981],[-33.255,9.026]],"v":[[-47.662,-24.751],[0.855,-33.299],[67.063,31.007],[-13.874,34.36]],"c":true}]},{"t":161,"s":[{"i":[[-22.559,17.979],[-28.894,-11.81],[1.9,-11.642],[36.756,0.551]],"o":[[0,0],[44.231,18.078],[-2.898,17.761],[-34.454,-0.517]],"v":[[-47.662,-24.751],[0.855,-33.299],[79.771,2.202],[-13.874,34.36]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"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":0,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,0.666999995708,0.071000002325,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":[70.471,43.636],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"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":76,"op":170,"st":0,"bm":0},{"ddd":0,"ind":156,"ty":4,"nm":"wing_l4","parent":160,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[68.46,47.555,0],"ix":2,"l":2},"a":{"a":0,"k":[88.21,67.305,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":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":87,"s":[{"i":[[24.496,15.235],[28.69,-12.299],[-2.268,-13.172],[-55.682,3.877]],"o":[[0,0],[-44.491,19.072],[1.757,10.209],[34.375,-2.394]],"v":[[43.714,-31.002],[-5.467,-33.851],[-83.747,-13.32],[17.025,31.635]],"c":true}]},{"i":{"x":0.833,"y":1},"o":{"x":0.333,"y":0},"t":92,"s":[{"i":[[24.496,15.235],[28.167,-13.453],[-4.457,-10.921],[-34.079,-5.099]],"o":[[0,0],[-40.115,19.158],[3.914,9.591],[34.079,5.1]],"v":[[43.714,-31.002],[-5.467,-33.851],[-63.753,37.713],[17.025,31.635]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":97,"s":[{"i":[[24.496,15.235],[28.69,-12.299],[-2.268,-13.172],[-55.682,3.877]],"o":[[0,0],[-44.491,19.072],[1.757,10.209],[34.375,-2.394]],"v":[[43.714,-31.002],[-5.467,-33.851],[-83.747,-13.32],[17.025,31.635]],"c":true}]},{"i":{"x":0.833,"y":1},"o":{"x":0.333,"y":0},"t":102,"s":[{"i":[[24.496,15.235],[28.167,-13.453],[-4.457,-10.921],[-34.079,-5.099]],"o":[[0,0],[-40.115,19.158],[3.914,9.591],[34.079,5.1]],"v":[[43.714,-31.002],[-5.467,-33.851],[-63.753,37.713],[17.025,31.635]],"c":true}]},{"i":{"x":0.833,"y":1},"o":{"x":0.333,"y":0},"t":107,"s":[{"i":[[24.496,15.235],[28.69,-12.299],[-2.268,-13.172],[-55.682,3.877]],"o":[[0,0],[-44.491,19.072],[1.757,10.209],[34.375,-2.394]],"v":[[43.714,-31.002],[-5.467,-33.851],[-83.747,-13.32],[17.025,31.635]],"c":true}]},{"i":{"x":0.833,"y":1},"o":{"x":0.167,"y":0},"t":112,"s":[{"i":[[24.496,15.235],[28.167,-13.453],[-4.457,-10.921],[-34.079,-5.099]],"o":[[0,0],[-40.115,19.158],[3.914,9.591],[34.079,5.1]],"v":[[43.714,-31.002],[-5.467,-33.851],[-63.753,37.713],[17.025,31.635]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0},"t":154,"s":[{"i":[[24.496,15.235],[28.167,-13.453],[-4.457,-10.921],[-34.079,-5.099]],"o":[[0,0],[-40.115,19.158],[3.914,9.591],[34.079,5.1]],"v":[[43.714,-31.002],[-5.467,-33.851],[-63.753,37.713],[17.025,31.635]],"c":true}]},{"t":161,"s":[{"i":[[24.496,15.235],[26.957,-15.738],[-4.457,-10.921],[-45.137,3.088]],"o":[[0,0],[-38.597,22.534],[3.914,9.591],[34.378,-2.352]],"v":[[43.714,-31.002],[-5.467,-33.851],[-77.315,-1.635],[17.025,31.635]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.808000028133,0.458999991417,0,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":8,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[88.21,67.305],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"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":76,"op":170,"st":0,"bm":0},{"ddd":0,"ind":157,"ty":4,"nm":"wing_l3","parent":160,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[67.223,25.602,0],"ix":2,"l":2},"a":{"a":0,"k":[49.357,37.615,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":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":87,"s":[{"i":[[0,0],[-14.525,-1.794]],"o":[[13.36,-4.762],[0,0]],"v":[[-23.298,5.736],[16.026,-6.364]],"c":false}]},{"i":{"x":0.833,"y":1},"o":{"x":0.333,"y":0},"t":92,"s":[{"i":[[0,0],[-20.743,-3.772]],"o":[[0,0],[0,0]],"v":[[-21.857,10.114],[21.857,-6.343]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":97,"s":[{"i":[[0,0],[-14.525,-1.794]],"o":[[13.36,-4.762],[0,0]],"v":[[-23.298,5.736],[16.026,-6.364]],"c":false}]},{"i":{"x":0.833,"y":1},"o":{"x":0.333,"y":0},"t":102,"s":[{"i":[[0,0],[-20.743,-3.772]],"o":[[0,0],[0,0]],"v":[[-21.857,10.114],[21.857,-6.343]],"c":false}]},{"i":{"x":0.833,"y":1},"o":{"x":0.333,"y":0},"t":107,"s":[{"i":[[0,0],[-14.525,-1.794]],"o":[[13.36,-4.762],[0,0]],"v":[[-23.298,5.736],[16.026,-6.364]],"c":false}]},{"i":{"x":0.833,"y":1},"o":{"x":0.167,"y":0},"t":112,"s":[{"i":[[0,0],[-20.743,-3.772]],"o":[[0,0],[0,0]],"v":[[-21.857,10.114],[21.857,-6.343]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0},"t":154,"s":[{"i":[[0,0],[-20.743,-3.772]],"o":[[0,0],[0,0]],"v":[[-21.857,10.114],[21.857,-6.343]],"c":false}]},{"t":161,"s":[{"i":[[0,0],[-25.065,5.635]],"o":[[0,0],[0,0]],"v":[[-29.896,8.838],[21.857,-6.343]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.995999991894,0.902000010014,0.234999999404,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":11,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[49.357,37.615],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"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":76,"op":170,"st":0,"bm":0},{"ddd":0,"ind":158,"ty":4,"nm":"wing_l2","parent":160,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[63.424,44.203,0],"ix":2,"l":2},"a":{"a":0,"k":[63.425,44.205,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":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":87,"s":[{"i":[[9.14,-15.41],[9.6,5.97],[25.341,-10.455],[17.759,1.762],[0.97,2.38],[-40.11,19.16],[0,0]],"o":[[3.05,-11.59],[0,0],[-31.379,12.946],[-5.03,0.5],[-4.46,-10.92],[28.17,-13.45],[14.28,8.89]],"v":[[54.035,18.215],[45.175,-11.835],[1.052,-16.054],[-73.26,-4.569],[-76.092,-12.594],[-0.435,-30.505],[48.755,-27.655]],"c":true}]},{"i":{"x":0.833,"y":1},"o":{"x":0.333,"y":0},"t":92,"s":[{"i":[[9.14,-15.41],[9.6,5.97],[24.689,-11.79],[1.79,-13.67],[0.97,2.38],[-40.11,19.16],[0,0]],"o":[[3.05,-11.59],[0,0],[-30.63,14.63],[-5.03,0.5],[-4.46,-10.92],[28.17,-13.45],[14.28,8.89]],"v":[[54.035,18.215],[45.175,-11.835],[2.075,-14.335],[-49.345,43.455],[-58.715,41.065],[-0.435,-30.505],[48.755,-27.655]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":97,"s":[{"i":[[9.14,-15.41],[9.6,5.97],[25.341,-10.455],[17.759,1.762],[0.97,2.38],[-40.11,19.16],[0,0]],"o":[[3.05,-11.59],[0,0],[-31.379,12.946],[-5.03,0.5],[-4.46,-10.92],[28.17,-13.45],[14.28,8.89]],"v":[[54.035,18.215],[45.175,-11.835],[1.052,-16.054],[-73.26,-4.569],[-76.092,-12.594],[-0.435,-30.505],[48.755,-27.655]],"c":true}]},{"i":{"x":0.833,"y":1},"o":{"x":0.333,"y":0},"t":102,"s":[{"i":[[9.14,-15.41],[9.6,5.97],[24.689,-11.79],[1.79,-13.67],[0.97,2.38],[-40.11,19.16],[0,0]],"o":[[3.05,-11.59],[0,0],[-30.63,14.63],[-5.03,0.5],[-4.46,-10.92],[28.17,-13.45],[14.28,8.89]],"v":[[54.035,18.215],[45.175,-11.835],[2.075,-14.335],[-49.345,43.455],[-58.715,41.065],[-0.435,-30.505],[48.755,-27.655]],"c":true}]},{"i":{"x":0.833,"y":1},"o":{"x":0.333,"y":0},"t":107,"s":[{"i":[[9.14,-15.41],[9.6,5.97],[25.341,-10.455],[17.759,1.762],[0.97,2.38],[-40.11,19.16],[0,0]],"o":[[3.05,-11.59],[0,0],[-31.379,12.946],[-5.03,0.5],[-4.46,-10.92],[28.17,-13.45],[14.28,8.89]],"v":[[54.035,18.215],[45.175,-11.835],[1.052,-16.054],[-73.26,-4.569],[-76.092,-12.594],[-0.435,-30.505],[48.755,-27.655]],"c":true}]},{"i":{"x":0.833,"y":1},"o":{"x":0.167,"y":0},"t":112,"s":[{"i":[[9.14,-15.41],[9.6,5.97],[24.689,-11.79],[1.79,-13.67],[0.97,2.38],[-40.11,19.16],[0,0]],"o":[[3.05,-11.59],[0,0],[-30.63,14.63],[-5.03,0.5],[-4.46,-10.92],[28.17,-13.45],[14.28,8.89]],"v":[[54.035,18.215],[45.175,-11.835],[2.075,-14.335],[-49.345,43.455],[-58.715,41.065],[-0.435,-30.505],[48.755,-27.655]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0},"t":154,"s":[{"i":[[9.14,-15.41],[9.6,5.97],[24.689,-11.79],[1.79,-13.67],[0.97,2.38],[-40.11,19.16],[0,0]],"o":[[3.05,-11.59],[0,0],[-30.63,14.63],[-5.03,0.5],[-4.46,-10.92],[28.17,-13.45],[14.28,8.89]],"v":[[54.035,18.215],[45.175,-11.835],[2.075,-14.335],[-49.345,43.455],[-58.715,41.065],[-0.435,-30.505],[48.755,-27.655]],"c":true}]},{"t":161,"s":[{"i":[[9.14,-15.41],[9.6,5.97],[25.124,-10.832],[22.705,-1.343],[0.97,2.38],[-40.11,19.16],[0,0]],"o":[[3.05,-11.59],[0,0],[-32.087,13.833],[-5.03,0.5],[-4.46,-10.92],[28.17,-13.45],[14.28,8.89]],"v":[[54.035,18.215],[45.175,-11.835],[2.075,-14.335],[-65.631,5.789],[-70.63,-1.412],[-0.435,-30.505],[48.755,-27.655]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"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":0,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.987999975681,0.796000003815,0.11400000006,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":[63.425,44.205],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"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":76,"op":170,"st":0,"bm":0},{"ddd":0,"ind":159,"ty":3,"nm":"NULL CONTROL","parent":153,"sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":70,"s":[-52.273]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":85,"s":[-3.748]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":151,"s":[-3.748]},{"t":158,"s":[60.261]}],"ix":10},"p":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":70,"s":[21.934,140.631,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":0.667},"o":{"x":0.167,"y":0.167},"t":85,"s":[21.934,70.631,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":1},"o":{"x":0.167,"y":0},"t":151,"s":[21.934,70.631,0],"to":[0,0,0],"ti":[0,0,0]},{"t":166,"s":[21.934,140.631,0]}],"ix":2,"l":2},"a":{"a":0,"k":[60,60,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"ip":70,"op":170,"st":0,"bm":0},{"ddd":0,"ind":160,"ty":4,"nm":"wing_l1","parent":159,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":85,"s":[44.874]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":90,"s":[16.506]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":95,"s":[44.874]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":100,"s":[16.506]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":105,"s":[44.874]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":110,"s":[15.391]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":150,"s":[15.391]},{"t":168,"s":[7.417]}],"ix":10},"p":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":80,"s":[60,60,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":0.667},"o":{"x":0.333,"y":0.333},"t":85,"s":[20,60,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":0.667},"o":{"x":0.167,"y":0.167},"t":92,"s":[20,60,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0},"t":151,"s":[20,60,0],"to":[0,0,0],"ti":[0,0,0]},{"t":158,"s":[29.436,109.101,0]}],"ix":2,"l":2},"a":{"a":0,"k":[123.721,48.108,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":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":87,"s":[{"i":[[24.496,15.235],[28.167,-13.453],[-2.055,-11.615],[-34.193,-0.139]],"o":[[0,0],[-40.115,19.158],[5.28,29.839],[34.458,0.141]],"v":[[43.714,-31.002],[-5.467,-33.851],[-81.666,-15.139],[17.025,31.635]],"c":true}]},{"i":{"x":0.833,"y":1},"o":{"x":0.333,"y":0},"t":92,"s":[{"i":[[24.496,15.235],[28.167,-13.453],[-4.457,-10.921],[-34.079,-5.099]],"o":[[0,0],[-40.115,19.158],[3.914,9.591],[34.079,5.1]],"v":[[43.714,-31.002],[-5.467,-33.851],[-63.753,37.713],[17.025,31.635]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":97,"s":[{"i":[[24.496,15.235],[28.167,-13.453],[-2.055,-11.615],[-34.193,-0.139]],"o":[[0,0],[-40.115,19.158],[5.28,29.839],[34.458,0.141]],"v":[[43.714,-31.002],[-5.467,-33.851],[-81.666,-15.139],[17.025,31.635]],"c":true}]},{"i":{"x":0.833,"y":1},"o":{"x":0.333,"y":0},"t":102,"s":[{"i":[[24.496,15.235],[28.167,-13.453],[-4.457,-10.921],[-34.079,-5.099]],"o":[[0,0],[-40.115,19.158],[3.914,9.591],[34.079,5.1]],"v":[[43.714,-31.002],[-5.467,-33.851],[-63.753,37.713],[17.025,31.635]],"c":true}]},{"i":{"x":0.833,"y":1},"o":{"x":0.333,"y":0},"t":107,"s":[{"i":[[24.496,15.235],[28.167,-13.453],[-2.055,-11.615],[-34.193,-0.139]],"o":[[0,0],[-40.115,19.158],[5.28,29.839],[34.458,0.141]],"v":[[43.714,-31.002],[-5.467,-33.851],[-81.666,-15.139],[17.025,31.635]],"c":true}]},{"i":{"x":0.833,"y":1},"o":{"x":0.167,"y":0},"t":112,"s":[{"i":[[24.496,15.235],[28.167,-13.453],[-4.457,-10.921],[-34.079,-5.099]],"o":[[0,0],[-40.115,19.158],[3.914,9.591],[34.079,5.1]],"v":[[43.714,-31.002],[-5.467,-33.851],[-63.753,37.713],[17.025,31.635]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0},"t":154,"s":[{"i":[[24.496,15.235],[28.167,-13.453],[-4.457,-10.921],[-34.079,-5.099]],"o":[[0,0],[-40.115,19.158],[3.914,9.591],[34.079,5.1]],"v":[[43.714,-31.002],[-5.467,-33.851],[-63.753,37.713],[17.025,31.635]],"c":true}]},{"t":161,"s":[{"i":[[24.496,15.235],[28.167,-13.453],[-4.457,-10.921],[-46.212,9.075]],"o":[[0,0],[-40.115,19.158],[3.914,9.591],[41.222,-8.095]],"v":[[43.714,-31.002],[-5.467,-33.851],[-78.963,1.493],[17.025,31.635]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"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":0,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,0.666999995708,0.071000002325,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":[68.46,47.555],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"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":76,"op":170,"st":0,"bm":0},{"ddd":0,"ind":161,"ty":4,"nm":"egg_back1","parent":3,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[56.065,23.756,0],"ix":2,"l":2},"a":{"a":0,"k":[204.214,88.403,0],"ix":1,"l":2},"s":{"a":0,"k":[99,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-2.887,123.603],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-53.828,-27.429]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[53.829,27.428]],"v":[[184.403,-53.325],[176.443,-42.625],[166.1,-57.987],[153.26,-40.297],[130.529,-68.403],[97.475,-34.649],[34.529,-47.146],[-17.352,-34.649],[-48.443,-51.526],[-107.592,-41.414],[-143.414,-60.99],[-162.613,-47.146],[-178.786,-52.84],[-130.385,40.283]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.407999992371,0.31400001049,0.175999999046,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":8,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[204.214,88.403],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"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":[[-2.887,123.603],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-53.828,-27.429]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[53.829,27.428]],"v":[[184.403,-53.325],[176.443,-42.625],[166.1,-57.987],[153.26,-40.297],[130.529,-68.403],[97.475,-34.649],[34.529,-47.146],[-17.352,-34.649],[-48.443,-51.526],[-107.592,-41.414],[-143.414,-60.99],[-162.613,-47.146],[-178.786,-52.84],[-130.385,40.283]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"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":0,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.592000007629,0.455000013113,0.224000006914,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":[204.214,88.403],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":3,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":76,"op":170,"st":0,"bm":0}]}],"layers":[{"ddd":0,"ind":1,"ty":0,"nm":"_2_chik_noline_easestop","refId":"comp_0","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[256,256,0],"ix":2,"l":2},"a":{"a":0,"k":[256,256,0],"ix":1,"l":2},"s":{"a":0,"k":[-100,100,100],"ix":6,"l":2}},"ao":0,"w":512,"h":512,"ip":0,"op":151,"st":0,"bm":0}],"markers":[]} \ No newline at end of file diff --git a/TMessagesProj/src/main/res/raw/utyan_newborn.tgs b/TMessagesProj/src/main/res/raw/utyan_newborn.tgs new file mode 100644 index 000000000..2f94c5a6f --- /dev/null +++ b/TMessagesProj/src/main/res/raw/utyan_newborn.tgs @@ -0,0 +1 @@ +{"tgs":1,"v":"5.5.2","fr":60,"ip":0,"op":180,"w":512,"h":512,"nm":"_053_EGG_OUT","ddd":0,"assets":[{"id":"comp_0","layers":[{"ddd":0,"ind":1,"ty":3,"nm":"NULL CONTROL","sr":1,"ks":{"o":{"a":0,"k":0},"p":{"a":0,"k":[256,500.908,0]},"a":{"a":0,"k":[60,60,0]},"s":{"a":0,"k":[95,95,100]}},"ao":0,"ip":0,"op":306,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"egg_bl","parent":7,"sr":1,"ks":{"p":{"a":0,"k":[1.654,-64.199,0]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[-3.507,17.894],[0,0],[0,0],[-6.251,2.166],[0,0],[-1.281,2.528],[0,0],[0,0],[0,0],[-5.421,3.864],[0,0],[0,0],[-4.03,3.473],[0,0],[0,0],[-2.076,9.679],[0,0],[0,0],[-3.197,3.921],[0,0]],"o":[[0,0],[0,0],[1.312,6.485],[0,0],[2.678,-0.928],[0,0],[0,0],[0,0],[3.051,5.917],[0,0],[0,0],[4.107,3.382],[0,0],[0,0],[5.12,8.472],[0,0],[0,0],[4.556,2.2],[0,0],[1.352,10.622]],"v":[[-164.175,-40.735],[-145.036,-31.339],[-135.736,14.617],[-121.445,22.776],[-104.028,16.741],[-97.856,11.354],[-81.739,-20.458],[-52.901,-35.705],[-26.524,15.453],[-10.466,19.344],[13.833,2.025],[21.231,8.116],[35.313,7.959],[58.552,-12.067],[87.272,35.453],[107.313,32.091],[119.522,-24.843],[146.379,-11.875],[159.603,-14.811],[164.175,-20.42]],"c":false}},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":8},"lc":2,"lj":2,"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":"Group 1","bm":0,"hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":70,"s":[50]},{"t":80,"s":[16],"h":1},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":112,"s":[16]},{"t":120,"s":[0]}]},"e":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":70,"s":[50]},{"t":80,"s":[86],"h":1},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":112,"s":[86]},{"t":120,"s":[100]}]},"o":{"a":0,"k":0},"m":1,"nm":"Trim Paths 1","hd":false}],"ip":50,"op":300,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"egg 2","parent":11,"sr":1,"ks":{"p":{"a":0,"k":[-0.594,98.167,0]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[3.782,18.863],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[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],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-5.396,22.871]],"v":[[172.088,-108.121],[153.042,-84.761],[114.065,-103.58],[98.698,-31.912],[62.644,-91.567],[29.846,-63.305],[15.926,-74.767],[-15.49,-52.375],[-46.99,-113.467],[-87.569,-92.011],[-105.293,-57.03],[-124.069,-50.524],[-134.557,-102.346],[-169.594,-119.546]],"c":false}},"nm":"Path 1","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":70,"s":[50]},{"t":80,"s":[15.82],"h":1},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":112,"s":[15.82]},{"t":120,"s":[0]}]},"e":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":70,"s":[50]},{"t":80,"s":[84.18],"h":1},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":112,"s":[84.18]},{"t":120,"s":[100]}]},"o":{"a":0,"k":0},"m":1,"nm":"Trim Paths 1","hd":false},{"ty":"st","c":{"a":0,"k":[0.717647075653,0.674509823322,0.603921592236,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":10},"lc":2,"lj":2,"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":"Group 1","bm":0,"hd":false}],"ip":8,"op":300,"st":0,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"egg 3","parent":11,"sr":1,"ks":{"p":{"a":0,"k":[-0.594,98.167,0]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,-20.217],[-103.123,0],[0,103.123],[3.782,18.863]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-5.396,22.871],[0,103.123],[103.123,0],[0,-16.835],[0,0]],"v":[[153.042,-84.761],[114.065,-103.58],[98.698,-31.912],[62.644,-91.567],[29.846,-63.305],[15.926,-74.767],[-15.49,-52.375],[-46.99,-113.467],[-87.569,-92.011],[-105.293,-57.03],[-124.069,-50.524],[-134.557,-102.346],[-169.594,-119.546],[-177.863,-54.108],[0,119.546],[177.863,-54.108],[172.088,-108.121]],"c":true}},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":0,"k":[0.717647075653,0.674509823322,0.603921592236,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":10},"lc":2,"lj":2,"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":"Group 1","bm":0,"hd":false}],"ip":126,"op":300,"st":0,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":"egg_bl6","parent":11,"sr":1,"ks":{"o":{"a":0,"k":33},"p":{"a":0,"k":[-23.168,-72.905,0]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[0,0],[0,0],[7.414,-22.016],[-30.787,0],[-21.435,25.701],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[20.572,16.425],[39.248,0],[-2.431,-5.464],[0,0],[0,0],[0,0],[0,0]],"v":[[-23.583,58.273],[-63.986,78.271],[-78.395,110.505],[0,136.252],[93.834,95.402],[84.283,80.451],[51.159,108.396],[38.957,95.834],[6.844,119.212]],"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 1","bm":0,"hd":false}],"ip":126,"op":294,"st":0,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":"egg_bl5","parent":11,"sr":1,"ks":{"o":{"a":0,"k":33},"p":{"a":0,"k":[-13.915,-37.733,0]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[1.456,-6.35],[1.056,-6.227],[-88.193,0],[-10.366,79.967],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[-1.456,6.35],[6.364,85.29],[84.846,0],[-11.741,-5.796],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-156.184,18.535],[-159.956,37.417],[-0.26,179.98],[158.468,47.009],[129.234,32.812],[110.853,101.029],[76.152,44.867],[41.318,73.686],[28.099,60.509],[-2.625,80.909],[-34.816,21.358],[-74.896,43.459],[-91.491,78.677],[-110.842,83.056],[-122.333,32.211]],"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 1","bm":0,"hd":false}],"ip":126,"op":294,"st":0,"bm":0},{"ddd":0,"ind":7,"ty":4,"nm":"egg","parent":11,"sr":1,"ks":{"p":{"a":0,"k":[-0.594,98.167,0]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,-20.217],[-103.123,0],[0,103.123],[3.782,18.863]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-5.396,22.871],[0,103.123],[103.123,0],[0,-16.835],[0,0]],"v":[[153.042,-84.761],[114.065,-103.58],[98.698,-31.912],[62.644,-91.567],[29.846,-63.305],[15.926,-74.767],[-15.49,-52.375],[-46.99,-113.467],[-87.569,-92.011],[-105.293,-57.03],[-124.069,-50.524],[-134.557,-102.346],[-169.594,-119.546],[-177.863,-54.108],[0,119.546],[177.863,-54.108],[172.088,-108.121]],"c":true}},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.878431379795,0.847058832645,0.796078443527,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 1","bm":0,"hd":false}],"ip":126,"op":300,"st":0,"bm":0},{"ddd":0,"ind":8,"ty":4,"nm":"egg_str","parent":11,"sr":1,"ks":{},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[0,-103.123],[103.123,0],[0,103.123],[-103.123,0]],"o":[[0,103.123],[-103.123,0],[0,-103.123],[103.123,0]],"v":[[177.863,44.06],[0,217.713],[-177.863,44.06],[0,-217.713]],"c":true}},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":0,"k":[0.717647075653,0.674509823322,0.603921592236,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":10},"lc":2,"lj":2,"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":"Group 1","bm":0,"hd":false}],"ip":0,"op":126,"st":0,"bm":0},{"ddd":0,"ind":9,"ty":4,"nm":"egg_bl2","parent":11,"sr":1,"ks":{"o":{"a":0,"k":33},"p":{"a":0,"k":[-23.168,-72.905,0]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[0,-69.541],[69.541,0],[0,69.541],[-69.541,0]],"o":[[0,69.541],[-69.541,0],[0,-69.541],[69.541,0]],"v":[[119.943,19.148],[0,136.252],[-119.943,19.148],[0,-136.252]],"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 1","bm":0,"hd":false}],"ip":0,"op":126,"st":0,"bm":0},{"ddd":0,"ind":10,"ty":4,"nm":"egg_bl1","parent":11,"sr":1,"ks":{"o":{"a":0,"k":33},"p":{"a":0,"k":[-13.915,-37.733,0]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[16.754,-98.773],[-88.193,0],[0,92.891],[71.198,27.043],[9.085,0]],"o":[[6.364,85.291],[92.891,0],[0,-78.661],[-8.613,-2.316],[-89.171,0]],"v":[[-159.956,37.417],[-0.26,179.98],[159.956,23.557],[40.477,-176.428],[13.915,-179.98]],"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 1","bm":0,"hd":false}],"ip":0,"op":126,"st":0,"bm":0},{"ddd":0,"ind":11,"ty":4,"nm":"egg1","parent":1,"sr":1,"ks":{"r":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":60,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":66.666,"s":[10]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":73.334,"s":[-10]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":81.334,"s":[10]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":93.334,"s":[-5]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":100,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":110,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":118.484,"s":[10]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":126.971,"s":[-10]},{"t":138,"s":[0]}]},"p":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":60,"s":[60,60,0],"to":[0,-0.667,0],"ti":[0,0.667,0]},{"i":{"x":0.667,"y":0.667},"o":{"x":0.333,"y":0.333},"t":66.666,"s":[60,56,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":93.334,"s":[60,56,0],"to":[0,0.667,0],"ti":[0,-0.667,0]},{"i":{"x":0.667,"y":0.667},"o":{"x":0.167,"y":0.167},"t":100,"s":[60,60,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":110,"s":[60,60,0],"to":[0,-0.667,0],"ti":[0,0.667,0]},{"i":{"x":0.667,"y":0.667},"o":{"x":0.333,"y":0.333},"t":118.484,"s":[60,56,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0},"t":127.818,"s":[60,56,0],"to":[0,0.667,0],"ti":[0,-0.667,0]},{"t":138,"s":[60,60,0]}]},"a":{"a":0,"k":[0,217.713,0]},"s":{"a":1,"k":[{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":62,"s":[100,100,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":68,"s":[103,97,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":76,"s":[98,102,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":88,"s":[103,97,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":98,"s":[100,100,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":112,"s":[100,100,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":122,"s":[105,95,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"t":136,"s":[95,105,100]},{"t":150,"s":[100,100,100]}]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[0,-103.123],[103.123,0],[0,103.123],[-103.123,0]],"o":[[0,103.123],[-103.123,0],[0,-103.123],[103.123,0]],"v":[[177.863,44.06],[0,217.713],[-177.863,44.06],[0,-217.713]],"c":true}},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.878431379795,0.847058832645,0.796078443527,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 1","bm":0,"hd":false}],"ip":0,"op":126,"st":0,"bm":0},{"ddd":0,"ind":12,"ty":4,"nm":"hat 2","parent":16,"sr":1,"ks":{"p":{"a":0,"k":[123.535,31.198,0]},"a":{"a":0,"k":[123.535,31.198,0]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0.833,"y":1},"o":{"x":0.333,"y":0},"t":126,"s":[{"i":[[51.485,0],[33.612,-96.651],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[-51.247,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-27.112,-106.94]],"v":[[-0.221,-57.456],[-159.478,94.998],[-117.172,145.81],[-51.356,106.349],[-14.171,157.805],[35.63,123.868],[86.825,158.355],[114.915,100.139],[153.449,99.729]],"c":true}]},{"i":{"x":0.833,"y":1},"o":{"x":0.333,"y":0},"t":136,"s":[{"i":[[51.485,0],[31.539,-52.074],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[-51.247,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-31.567,-52.438]],"v":[[-0.221,-57.456],[-127.241,33.8],[-100.496,57.456],[-36.511,32.863],[4.779,57.456],[39.497,20.887],[93.689,49.278],[104.97,26.739],[127.241,34.528]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":166,"s":[{"i":[[51.485,0],[31.539,-52.074],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[-51.247,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-31.567,-52.438]],"v":[[-0.221,-57.456],[-127.241,33.8],[-100.496,57.456],[-36.511,32.863],[4.779,57.456],[39.497,20.887],[93.689,49.278],[104.97,26.739],[127.241,34.528]],"c":true}]},{"t":190,"s":[{"i":[[51.485,0],[31.539,-52.074],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[-51.247,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-31.567,-52.438]],"v":[[-0.221,-57.456],[-127.241,33.8],[-93.79,37.179],[-43.469,-4.001],[0.912,29.506],[37.749,-16.727],[89.886,21.263],[101.34,9.386],[127.241,34.528]],"c":true}],"h":1},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":212,"s":[{"i":[[51.485,0],[31.539,-52.074],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[-51.247,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-31.567,-52.438]],"v":[[-0.221,-57.456],[-127.241,33.8],[-93.79,37.179],[-43.469,-4.001],[0.912,29.506],[37.749,-16.727],[89.886,21.263],[101.34,9.386],[127.241,34.528]],"c":true}]},{"t":226,"s":[{"i":[[51.485,0],[31.539,-52.074],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[-51.247,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-31.567,-52.438]],"v":[[-0.221,-57.456],[-127.241,33.8],[-100.496,57.456],[-36.511,32.863],[4.779,57.456],[39.497,20.887],[93.689,49.278],[104.97,26.739],[127.241,34.528]],"c":true}]}]},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":0,"k":[0.717647075653,0.674509823322,0.603921592236,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":10},"lc":2,"lj":2,"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":"Group 1","bm":0,"hd":false}],"ip":126,"op":300,"st":0,"bm":0},{"ddd":0,"ind":13,"ty":4,"nm":"egg_bl4","parent":16,"sr":1,"ks":{"o":{"a":0,"k":33},"p":{"a":0,"k":[-23.725,84.558,0]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0.833,"y":1},"o":{"x":0.333,"y":0},"t":126,"s":[{"i":[[51.411,0],[34.704,-91.659],[0,0],[0,0],[0,0],[0,0],[0,0],[34.301,37.077]],"o":[[-47.702,12.346],[11.558,10.226],[0,0],[0,0],[0,0],[0,0],[0,0],[-17.858,-52.568]],"v":[[0,-136.252],[-134.489,8.781],[-93.067,57.884],[-28.648,24.451],[8.022,72.302],[58.117,39.375],[108.866,72.806],[119.542,-17.214]],"c":true}]},{"i":{"x":0.833,"y":1},"o":{"x":0.333,"y":0},"t":136,"s":[{"i":[[51.411,0],[29.927,-43.172],[0,0],[0,0],[0,0],[0,0],[-9.722,-5.787],[-9.305,-6.754]],"o":[[-47.702,12.346],[11.558,10.226],[0,0],[0,0],[0,0],[0,0],[8.451,5.03],[-17.858,-52.567]],"v":[[0,-136.252],[-104.498,-51.594],[-78.861,-28.511],[-12.879,-51.194],[28.573,-27.881],[65.195,-64.669],[82.076,-55.051],[110.22,-36.758]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":166,"s":[{"i":[[51.411,0],[29.927,-43.172],[0,0],[0,0],[0,0],[0,0],[-9.722,-5.787],[-9.305,-6.754]],"o":[[-47.702,12.346],[11.558,10.226],[0,0],[0,0],[0,0],[0,0],[8.451,5.03],[-17.858,-52.567]],"v":[[0,-136.252],[-104.498,-51.594],[-78.861,-28.511],[-12.879,-51.194],[28.573,-27.881],[65.195,-64.669],[82.076,-55.051],[110.22,-36.758]],"c":true}]},{"t":190,"s":[{"i":[[51.411,0],[29.927,-43.172],[0,0],[0,0],[0,0],[0,0],[-6.579,-5.164],[-6.97,-6.819]],"o":[[-47.702,12.346],[15.523,1.968],[0,0],[0,0],[0,0],[0,0],[5.719,4.488],[-8.788,-27.002]],"v":[[0,-136.252],[-104.498,-51.594],[-70.476,-45.736],[-20.561,-87.741],[24.706,-55.219],[61.053,-102.542],[72.239,-94.241],[92.137,-76.914]],"c":true}],"h":1},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":212,"s":[{"i":[[51.411,0],[29.927,-43.172],[0,0],[0,0],[0,0],[0,0],[-6.579,-5.164],[-6.97,-6.819]],"o":[[-47.702,12.346],[15.523,1.968],[0,0],[0,0],[0,0],[0,0],[5.719,4.488],[-8.788,-27.002]],"v":[[0,-136.252],[-104.498,-51.594],[-70.476,-45.736],[-20.561,-87.741],[24.706,-55.219],[61.053,-102.542],[72.239,-94.241],[92.137,-76.914]],"c":true}]},{"t":226,"s":[{"i":[[51.411,0],[29.927,-43.172],[0,0],[0,0],[0,0],[0,0],[-9.722,-5.787],[-9.305,-6.754]],"o":[[-47.702,12.346],[11.558,10.226],[0,0],[0,0],[0,0],[0,0],[8.451,5.03],[-17.858,-52.567]],"v":[[0,-136.252],[-104.498,-51.594],[-78.861,-28.511],[-12.879,-51.194],[28.573,-27.881],[65.195,-64.669],[82.076,-55.051],[110.22,-36.758]],"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 1","bm":0,"hd":false}],"ip":126,"op":290,"st":0,"bm":0},{"ddd":0,"ind":14,"ty":4,"nm":"egg_bl3","parent":16,"sr":1,"ks":{"o":{"a":0,"k":33},"p":{"a":0,"k":[-14.472,119.73,0]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0.833,"y":1},"o":{"x":0.167,"y":0},"t":126,"s":[{"i":[[9.085,0],[39.887,-100.793],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-1.72,1.118],[37.666,14.307]],"o":[[-51.484,0],[7.723,7.735],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-12.437,-83.837],[-8.613,-2.316]],"v":[[13.915,-179.98],[-144.763,-26.189],[-101.906,24.267],[-38.001,-13.529],[-0.769,37.726],[48.518,5.975],[99.231,37.249],[128.496,-17.943],[146.193,-37.555],[40.477,-176.428]],"c":true}]},{"i":{"x":0.833,"y":1},"o":{"x":0.333,"y":0},"t":136,"s":[{"i":[[9.085,0],[31.566,-52.435],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-1.72,1.118],[37.666,14.307]],"o":[[-51.484,0],[7.723,7.735],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-21.083,-39.675],[-8.613,-2.316]],"v":[[13.915,-179.98],[-113.543,-88.002],[-87.567,-63.657],[-21.528,-87.352],[18.255,-63.613],[54.762,-98.376],[108.13,-72.457],[119.662,-92.193],[130.478,-89.32],[40.477,-176.428]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":166,"s":[{"i":[[9.085,0],[31.566,-52.435],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-1.72,1.118],[37.666,14.307]],"o":[[-51.484,0],[7.723,7.735],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-21.083,-39.675],[-8.613,-2.316]],"v":[[13.915,-179.98],[-113.543,-88.002],[-87.567,-63.657],[-21.528,-87.352],[18.255,-63.613],[54.762,-98.376],[108.13,-72.457],[119.662,-92.193],[130.478,-89.32],[40.477,-176.428]],"c":true}]},{"t":190,"s":[{"i":[[9.085,0],[31.566,-52.435],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-1.72,1.118],[37.666,14.307]],"o":[[-51.484,0],[17.888,5.056],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-21.083,-39.675],[-8.613,-2.316]],"v":[[13.915,-179.98],[-113.543,-88.002],[-80.288,-82.971],[-29.819,-123.044],[15.245,-90.333],[51.727,-134.161],[104.871,-100.649],[116.07,-108.995],[129.844,-97.531],[40.477,-176.428]],"c":true}],"h":1},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":212,"s":[{"i":[[9.085,0],[31.566,-52.435],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-1.72,1.118],[37.666,14.307]],"o":[[-51.484,0],[17.888,5.056],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-21.083,-39.675],[-8.613,-2.316]],"v":[[13.915,-179.98],[-113.543,-88.002],[-80.288,-82.971],[-29.819,-123.044],[15.245,-90.333],[51.727,-134.161],[104.871,-100.649],[116.07,-108.995],[129.844,-97.531],[40.477,-176.428]],"c":true}]},{"t":226,"s":[{"i":[[9.085,0],[31.566,-52.435],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-1.72,1.118],[37.666,14.307]],"o":[[-51.484,0],[7.723,7.735],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-21.083,-39.675],[-8.613,-2.316]],"v":[[13.915,-179.98],[-113.543,-88.002],[-87.567,-63.657],[-21.528,-87.352],[18.255,-63.613],[54.762,-98.376],[108.13,-72.457],[119.662,-92.193],[130.478,-89.32],[40.477,-176.428]],"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 1","bm":0,"hd":false}],"ip":126,"op":290,"st":0,"bm":0},{"ddd":0,"ind":15,"ty":4,"nm":"Layer 38","parent":16,"sr":1,"ks":{"p":{"a":0,"k":[-3.3,26.816,0]},"s":{"a":0,"k":[105.263,105.263,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0.833,"y":1},"o":{"x":0.167,"y":0},"t":126,"s":[{"i":[[0,0],[0,0],[0,0],[2.355,-2.481],[0,0],[0,0],[2.19,-0.842],[0,0],[0,0]],"o":[[0,0],[0,0],[-3.03,-1.587],[0,0],[0,0],[-2.016,-1.201],[0,0],[0,0],[0,0]],"v":[[102.228,63.773],[80.907,113.294],[39.124,82.405],[30.023,83.915],[-9.206,110.988],[-41.849,66.01],[-48.51,65.442],[-106.89,99.08],[-131.204,72.623]],"c":false}]},{"i":{"x":0.833,"y":1},"o":{"x":0.333,"y":0},"t":136,"s":[{"i":[[0,0],[0,0],[0,0],[2.355,-2.481],[0,0],[0,0],[2.19,-0.842],[0,0],[0,0]],"o":[[0,0],[0,0],[-3.03,-1.587],[0,0],[0,0],[-2.016,-1.201],[0,0],[0,0],[0,0]],"v":[[95.194,-6.017],[88.205,7.945],[43.992,-15.218],[34.891,-13.709],[6.13,16.584],[-27.394,-3.382],[-34.055,-3.951],[-90.377,17.697],[-98.18,10.795]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":166,"s":[{"i":[[0,0],[0,0],[0,0],[2.355,-2.481],[0,0],[0,0],[2.19,-0.842],[0,0],[0,0]],"o":[[0,0],[0,0],[-3.03,-1.587],[0,0],[0,0],[-2.016,-1.201],[0,0],[0,0],[0,0]],"v":[[95.194,-6.017],[88.205,7.945],[43.992,-15.218],[34.891,-13.709],[6.13,16.584],[-27.394,-3.382],[-34.055,-3.951],[-90.377,17.697],[-98.18,10.795]],"c":false}]},{"t":190,"s":[{"i":[[0,0],[0,0],[0,0],[2.355,-2.481],[0,0],[0,0],[2.19,-0.842],[0,0],[0,0]],"o":[[0,0],[0,0],[-3.03,-1.587],[0,0],[0,0],[-2.016,-1.201],[0,0],[0,0],[0,0]],"v":[[95.092,-21.436],[86.916,-16.616],[41.713,-50.927],[32.612,-49.418],[2.864,-9.094],[-36.348,-38.372],[-43.009,-38.941],[-88.278,0.486],[-101.87,-0.455]],"c":false}],"h":1},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":212,"s":[{"i":[[0,0],[0,0],[0,0],[2.355,-2.481],[0,0],[0,0],[2.19,-0.842],[0,0],[0,0]],"o":[[0,0],[0,0],[-3.03,-1.587],[0,0],[0,0],[-2.016,-1.201],[0,0],[0,0],[0,0]],"v":[[95.092,-21.436],[86.916,-16.616],[41.713,-50.927],[32.612,-49.418],[2.864,-9.094],[-36.348,-38.372],[-43.009,-38.941],[-88.278,0.486],[-101.87,-0.455]],"c":false}]},{"t":226,"s":[{"i":[[0,0],[0,0],[0,0],[2.355,-2.481],[0,0],[0,0],[2.19,-0.842],[0,0],[0,0]],"o":[[0,0],[0,0],[-3.03,-1.587],[0,0],[0,0],[-2.016,-1.201],[0,0],[0,0],[0,0]],"v":[[95.194,-6.017],[88.205,7.945],[43.992,-15.218],[34.891,-13.709],[6.13,16.584],[-27.394,-3.382],[-34.055,-3.951],[-90.377,17.697],[-98.18,10.795]],"c":false}]}]},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":10},"lc":2,"lj":2,"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":"Group 1","bm":0,"hd":false}],"ip":0,"op":300,"st":0,"bm":0},{"ddd":0,"ind":16,"ty":4,"nm":"hat","parent":26,"sr":1,"ks":{"r":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":166,"s":[0]},{"t":190,"s":[37.905],"h":1},{"i":{"x":[0.667],"y":[1]},"o":{"x":[1],"y":[0]},"t":212,"s":[37.905]},{"t":226,"s":[0]}]},"p":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":166,"s":[0.939,-82.485,0],"to":[9.814,-32.669,0],"ti":[-38.822,-18.461,0]},{"t":190,"s":[105.196,-115.024,0],"h":1},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":212,"s":[105.196,-115.024,0],"to":[9.187,-4.882,0],"ti":[14.326,-36.582,0]},{"t":226,"s":[0.939,-82.485,0]}]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0.833,"y":1},"o":{"x":0.333,"y":0},"t":126,"s":[{"i":[[51.485,0],[33.612,-96.651],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[-51.247,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-27.112,-106.94]],"v":[[-0.221,-57.456],[-159.478,94.998],[-117.172,145.81],[-51.356,106.349],[-14.171,157.805],[35.63,123.868],[86.825,158.355],[114.915,100.139],[153.449,99.729]],"c":true}]},{"i":{"x":0.833,"y":1},"o":{"x":0.333,"y":0},"t":136,"s":[{"i":[[51.485,0],[31.539,-52.074],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[-51.247,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-31.567,-52.438]],"v":[[-0.221,-57.456],[-127.241,33.8],[-100.496,57.456],[-36.511,32.863],[4.779,57.456],[39.497,20.887],[93.689,49.278],[104.97,26.739],[127.241,34.528]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":166,"s":[{"i":[[51.485,0],[31.539,-52.074],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[-51.247,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-31.567,-52.438]],"v":[[-0.221,-57.456],[-127.241,33.8],[-100.496,57.456],[-36.511,32.863],[4.779,57.456],[39.497,20.887],[93.689,49.278],[104.97,26.739],[127.241,34.528]],"c":true}]},{"t":190,"s":[{"i":[[51.485,0],[31.539,-52.074],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[-51.247,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-31.567,-52.438]],"v":[[-0.221,-57.456],[-127.241,33.8],[-93.79,37.179],[-43.469,-4.001],[0.912,29.506],[37.749,-16.727],[89.886,21.263],[101.34,9.386],[127.241,34.528]],"c":true}],"h":1},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":212,"s":[{"i":[[51.485,0],[31.539,-52.074],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[-51.247,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-31.567,-52.438]],"v":[[-0.221,-57.456],[-127.241,33.8],[-93.79,37.179],[-43.469,-4.001],[0.912,29.506],[37.749,-16.727],[89.886,21.263],[101.34,9.386],[127.241,34.528]],"c":true}]},{"t":226,"s":[{"i":[[51.485,0],[31.539,-52.074],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[-51.247,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-31.567,-52.438]],"v":[[-0.221,-57.456],[-127.241,33.8],[-100.496,57.456],[-36.511,32.863],[4.779,57.456],[39.497,20.887],[93.689,49.278],[104.97,26.739],[127.241,34.528]],"c":true}]}]},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":0,"k":[0.717647075653,0.674509823322,0.603921592236,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":10},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.878431379795,0.847058832645,0.796078443527,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 1","bm":0,"hd":false}],"ip":126,"op":300,"st":0,"bm":0},{"ddd":0,"ind":17,"ty":4,"nm":"eye_bl 2","parent":18,"sr":1,"ks":{"p":{"a":0,"k":[-5.931,-13.756,0]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":100,"s":[{"i":[[0.401,-3.998],[3.998,0.401],[-0.401,3.998],[-3.998,-0.401]],"o":[[-0.401,3.998],[-3.998,-0.401],[0.401,-3.998],[3.998,0.401]],"v":[[7.24,0.727],[-0.727,7.24],[-7.24,-0.727],[0.727,-7.24]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":106,"s":[{"i":[[0.5,-0.569],[3.408,0.887],[-0.5,0.569],[-3.408,-0.887]],"o":[[-0.5,0.569],[-3.408,-0.887],[0.5,-0.569],[3.408,0.887]],"v":[[6.202,27.043],[-0.876,26.467],[-6.141,23.829],[0.936,24.405]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0},"t":112,"s":[{"i":[[0.401,-3.998],[3.998,0.401],[-0.401,3.998],[-3.998,-0.401]],"o":[[-0.401,3.998],[-3.998,-0.401],[0.401,-3.998],[3.998,0.401]],"v":[[7.24,0.727],[-0.727,7.24],[-7.24,-0.727],[0.727,-7.24]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":136,"s":[{"i":[[0.401,-3.998],[3.998,0.401],[-0.401,3.998],[-3.998,-0.401]],"o":[[-0.401,3.998],[-3.998,-0.401],[0.401,-3.998],[3.998,0.401]],"v":[[7.24,0.727],[-0.727,7.24],[-7.24,-0.727],[0.727,-7.24]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":142,"s":[{"i":[[0.5,-0.569],[3.408,0.887],[-0.5,0.569],[-3.408,-0.887]],"o":[[-0.5,0.569],[-3.408,-0.887],[0.5,-0.569],[3.408,0.887]],"v":[[6.202,27.043],[-0.876,26.467],[-6.141,23.829],[0.936,24.405]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0},"t":148,"s":[{"i":[[0.401,-3.998],[3.998,0.401],[-0.401,3.998],[-3.998,-0.401]],"o":[[-0.401,3.998],[-3.998,-0.401],[0.401,-3.998],[3.998,0.401]],"v":[[7.24,0.727],[-0.727,7.24],[-7.24,-0.727],[0.727,-7.24]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":170,"s":[{"i":[[0.401,-3.998],[3.998,0.401],[-0.401,3.998],[-3.998,-0.401]],"o":[[-0.401,3.998],[-3.998,-0.401],[0.401,-3.998],[3.998,0.401]],"v":[[7.24,0.727],[-0.727,7.24],[-7.24,-0.727],[0.727,-7.24]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":176,"s":[{"i":[[0.5,-0.569],[3.408,0.887],[-0.5,0.569],[-3.408,-0.887]],"o":[[-0.5,0.569],[-3.408,-0.887],[0.5,-0.569],[3.408,0.887]],"v":[[6.202,27.043],[-0.876,26.467],[-6.141,23.829],[0.936,24.405]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":198,"s":[{"i":[[0.5,-0.569],[3.408,0.887],[-0.5,0.569],[-3.408,-0.887]],"o":[[-0.5,0.569],[-3.408,-0.887],[0.5,-0.569],[3.408,0.887]],"v":[[6.202,27.043],[-0.876,26.467],[-6.141,23.829],[0.936,24.405]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":204,"s":[{"i":[[0.401,-3.998],[3.998,0.401],[-0.401,3.998],[-3.998,-0.401]],"o":[[-0.401,3.998],[-3.998,-0.401],[0.401,-3.998],[3.998,0.401]],"v":[[7.24,0.727],[-0.727,7.24],[-7.24,-0.727],[0.727,-7.24]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":228,"s":[{"i":[[0.401,-3.998],[3.998,0.401],[-0.401,3.998],[-3.998,-0.401]],"o":[[-0.401,3.998],[-3.998,-0.401],[0.401,-3.998],[3.998,0.401]],"v":[[7.24,0.727],[-0.727,7.24],[-7.24,-0.727],[0.727,-7.24]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":234,"s":[{"i":[[0.5,-0.569],[3.408,0.887],[-0.5,0.569],[-3.408,-0.887]],"o":[[-0.5,0.569],[-3.408,-0.887],[0.5,-0.569],[3.408,0.887]],"v":[[6.202,27.043],[-0.876,26.467],[-6.141,23.829],[0.936,24.405]],"c":true}]},{"t":240,"s":[{"i":[[0.401,-3.998],[3.998,0.401],[-0.401,3.998],[-3.998,-0.401]],"o":[[-0.401,3.998],[-3.998,-0.401],[0.401,-3.998],[3.998,0.401]],"v":[[7.24,0.727],[-0.727,7.24],[-7.24,-0.727],[0.727,-7.24]],"c":true}]}]},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":1,"k":[{"i":{"x":[0],"y":[1]},"o":{"x":[1],"y":[0]},"t":100,"s":[1,1,1,1]},{"i":{"x":[0],"y":[1]},"o":{"x":[1],"y":[0]},"t":106,"s":[0,0,0,1]},{"i":{"x":[0],"y":[1]},"o":{"x":[1.925],"y":[0]},"t":112,"s":[1,1,1,1]},{"i":{"x":[0],"y":[1]},"o":{"x":[1],"y":[0]},"t":136,"s":[1,1,1,1]},{"i":{"x":[0],"y":[1]},"o":{"x":[1],"y":[0]},"t":142,"s":[0,0,0,1]},{"i":{"x":[0.585],"y":[1]},"o":{"x":[1],"y":[0]},"t":148,"s":[1,1,1,1]},{"i":{"x":[0],"y":[1]},"o":{"x":[1],"y":[0]},"t":170,"s":[1,1,1,1]},{"i":{"x":[0],"y":[1]},"o":{"x":[1],"y":[0]},"t":176,"s":[0,0,0,1]},{"i":{"x":[0],"y":[1]},"o":{"x":[1],"y":[0]},"t":198,"s":[0,0,0,1]},{"i":{"x":[0],"y":[1]},"o":{"x":[1],"y":[0]},"t":204,"s":[1,1,1,1]},{"i":{"x":[0],"y":[1]},"o":{"x":[1],"y":[0]},"t":228,"s":[1,1,1,1]},{"i":{"x":[0],"y":[1]},"o":{"x":[1],"y":[0]},"t":234,"s":[0,0,0,1]},{"t":240,"s":[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 1","bm":0,"hd":false}],"ip":60,"op":300,"st":0,"bm":0},{"ddd":0,"ind":18,"ty":4,"nm":"eye 2","parent":22,"sr":1,"ks":{"p":{"a":1,"k":[{"i":{"x":0.667,"y":0.667},"o":{"x":0.333,"y":0.333},"t":152,"s":[71.553,-58.199,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":166,"s":[71.553,-58.199,0],"to":[-1.247,0.1,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":190,"s":[64.073,-57.597,0],"to":[0,0,0],"ti":[-1.247,0.1,0]},{"t":212,"s":[71.553,-58.199,0]}]},"s":{"a":1,"k":[{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":152,"s":[100,100,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":166,"s":[100,100,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":190,"s":[90,100,100]},{"t":212,"s":[100,100,100]}]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":100,"s":[{"i":[[-0.205,-16.477],[13.692,-0.17],[0.205,16.477],[-13.692,0.17]],"o":[[0.205,16.477],[-13.692,0.17],[-0.205,-16.477],[13.692,-0.17]],"v":[[24.792,-0.308],[0.37,29.834],[-24.792,0.308],[-0.37,-29.834]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":106,"s":[{"i":[[-1.122,-0.585],[24.759,-1.288],[-2.473,1.548],[-18.833,1.007]],"o":[[2.467,1.287],[-13.675,0.711],[1.796,-1.124],[24.776,-1.325]],"v":[[28.644,-2.91],[0.35,13.972],[-24.494,-0.078],[0.305,10.663]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0},"t":112,"s":[{"i":[[-0.205,-16.477],[13.692,-0.17],[0.205,16.477],[-13.692,0.17]],"o":[[0.205,16.477],[-13.692,0.17],[-0.205,-16.477],[13.692,-0.17]],"v":[[24.792,-0.308],[0.37,29.834],[-24.792,0.308],[-0.37,-29.834]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":136,"s":[{"i":[[-0.205,-16.477],[13.692,-0.17],[0.205,16.477],[-13.692,0.17]],"o":[[0.205,16.477],[-13.692,0.17],[-0.205,-16.477],[13.692,-0.17]],"v":[[24.792,-0.308],[0.37,29.834],[-24.792,0.308],[-0.37,-29.834]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":142,"s":[{"i":[[-1.122,-0.585],[24.759,-1.288],[-2.473,1.548],[-18.833,1.007]],"o":[[2.467,1.287],[-13.675,0.711],[1.796,-1.124],[24.776,-1.325]],"v":[[28.644,-2.91],[0.35,13.972],[-24.494,-0.078],[0.305,10.663]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0},"t":148,"s":[{"i":[[-0.205,-16.477],[13.692,-0.17],[0.205,16.477],[-13.692,0.17]],"o":[[0.205,16.477],[-13.692,0.17],[-0.205,-16.477],[13.692,-0.17]],"v":[[24.792,-0.308],[0.37,29.834],[-24.792,0.308],[-0.37,-29.834]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":170,"s":[{"i":[[-0.205,-16.477],[13.692,-0.17],[0.205,16.477],[-13.692,0.17]],"o":[[0.205,16.477],[-13.692,0.17],[-0.205,-16.477],[13.692,-0.17]],"v":[[24.792,-0.308],[0.37,29.834],[-24.792,0.308],[-0.37,-29.834]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":176,"s":[{"i":[[-1.122,-0.585],[24.793,-0.029],[-2.473,1.548],[-19.728,0.15]],"o":[[2.467,1.287],[-18.217,0.021],[1.796,-1.124],[24.811,-0.188]],"v":[[28.644,-2.91],[0.35,13.972],[-24.494,-0.078],[1.335,5.48]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":198,"s":[{"i":[[-1.122,-0.585],[24.759,-1.288],[-2.473,1.548],[-18.833,1.007]],"o":[[2.467,1.287],[-13.675,0.711],[1.796,-1.124],[24.776,-1.325]],"v":[[28.644,-2.91],[0.35,13.972],[-24.494,-0.078],[0.305,10.663]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":204,"s":[{"i":[[-0.205,-16.477],[13.692,-0.17],[0.205,16.477],[-13.692,0.17]],"o":[[0.205,16.477],[-13.692,0.17],[-0.205,-16.477],[13.692,-0.17]],"v":[[24.792,-0.308],[0.37,29.834],[-24.792,0.308],[-0.37,-29.834]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":228,"s":[{"i":[[-0.205,-16.477],[13.692,-0.17],[0.205,16.477],[-13.692,0.17]],"o":[[0.205,16.477],[-13.692,0.17],[-0.205,-16.477],[13.692,-0.17]],"v":[[24.792,-0.308],[0.37,29.834],[-24.792,0.308],[-0.37,-29.834]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":234,"s":[{"i":[[-1.122,-0.585],[24.759,-1.288],[-2.473,1.548],[-18.833,1.007]],"o":[[2.467,1.287],[-13.675,0.711],[1.796,-1.124],[24.776,-1.325]],"v":[[28.644,-2.91],[0.35,13.972],[-24.494,-0.078],[0.305,10.663]],"c":true}]},{"t":240,"s":[{"i":[[-0.205,-16.477],[13.692,-0.17],[0.205,16.477],[-13.692,0.17]],"o":[[0.205,16.477],[-13.692,0.17],[-0.205,-16.477],[13.692,-0.17]],"v":[[24.792,-0.308],[0.37,29.834],[-24.792,0.308],[-0.37,-29.834]],"c":true}]}]},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":0,"k":[0,0,0,1]},"o":{"a":0,"k":100},"w":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":100,"s":[3]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":106,"s":[8]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.185],"y":[0]},"t":112,"s":[3]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":136,"s":[3]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":142,"s":[8]},{"i":{"x":[0.738],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":148,"s":[3]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":170,"s":[3]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":176,"s":[8]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":198,"s":[8]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":204,"s":[3]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":228,"s":[3]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":234,"s":[8]},{"t":240,"s":[3]}]},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0,0,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 1","bm":0,"hd":false}],"ip":60,"op":300,"st":0,"bm":0},{"ddd":0,"ind":19,"ty":4,"nm":"eye_bl","parent":20,"sr":1,"ks":{"p":{"a":0,"k":[-5.931,-13.756,0]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":100,"s":[{"i":[[0.401,-3.998],[3.998,0.401],[-0.401,3.998],[-3.998,-0.401]],"o":[[-0.401,3.998],[-3.998,-0.401],[0.401,-3.998],[3.998,0.401]],"v":[[7.24,0.727],[-0.727,7.24],[-7.24,-0.727],[0.727,-7.24]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":106,"s":[{"i":[[0.5,-0.569],[3.408,0.887],[-0.5,0.569],[-3.408,-0.887]],"o":[[-0.5,0.569],[-3.408,-0.887],[0.5,-0.569],[3.408,0.887]],"v":[[6.202,27.043],[-0.876,26.467],[-6.141,23.829],[0.936,24.405]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0},"t":112,"s":[{"i":[[0.401,-3.998],[3.998,0.401],[-0.401,3.998],[-3.998,-0.401]],"o":[[-0.401,3.998],[-3.998,-0.401],[0.401,-3.998],[3.998,0.401]],"v":[[7.24,0.727],[-0.727,7.24],[-7.24,-0.727],[0.727,-7.24]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":136,"s":[{"i":[[0.401,-3.998],[3.998,0.401],[-0.401,3.998],[-3.998,-0.401]],"o":[[-0.401,3.998],[-3.998,-0.401],[0.401,-3.998],[3.998,0.401]],"v":[[7.24,0.727],[-0.727,7.24],[-7.24,-0.727],[0.727,-7.24]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":142,"s":[{"i":[[0.5,-0.569],[3.408,0.887],[-0.5,0.569],[-3.408,-0.887]],"o":[[-0.5,0.569],[-3.408,-0.887],[0.5,-0.569],[3.408,0.887]],"v":[[6.202,27.043],[-0.876,26.467],[-6.141,23.829],[0.936,24.405]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0},"t":148,"s":[{"i":[[0.401,-3.998],[3.998,0.401],[-0.401,3.998],[-3.998,-0.401]],"o":[[-0.401,3.998],[-3.998,-0.401],[0.401,-3.998],[3.998,0.401]],"v":[[7.24,0.727],[-0.727,7.24],[-7.24,-0.727],[0.727,-7.24]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":170,"s":[{"i":[[0.401,-3.998],[3.998,0.401],[-0.401,3.998],[-3.998,-0.401]],"o":[[-0.401,3.998],[-3.998,-0.401],[0.401,-3.998],[3.998,0.401]],"v":[[7.24,0.727],[-0.727,7.24],[-7.24,-0.727],[0.727,-7.24]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":176,"s":[{"i":[[0.5,-0.569],[3.408,0.887],[-0.5,0.569],[-3.408,-0.887]],"o":[[-0.5,0.569],[-3.408,-0.887],[0.5,-0.569],[3.408,0.887]],"v":[[6.202,27.043],[-0.876,26.467],[-6.141,23.829],[0.936,24.405]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":198,"s":[{"i":[[0.5,-0.569],[3.408,0.887],[-0.5,0.569],[-3.408,-0.887]],"o":[[-0.5,0.569],[-3.408,-0.887],[0.5,-0.569],[3.408,0.887]],"v":[[6.202,27.043],[-0.876,26.467],[-6.141,23.829],[0.936,24.405]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":204,"s":[{"i":[[0.401,-3.998],[3.998,0.401],[-0.401,3.998],[-3.998,-0.401]],"o":[[-0.401,3.998],[-3.998,-0.401],[0.401,-3.998],[3.998,0.401]],"v":[[7.24,0.727],[-0.727,7.24],[-7.24,-0.727],[0.727,-7.24]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":228,"s":[{"i":[[0.401,-3.998],[3.998,0.401],[-0.401,3.998],[-3.998,-0.401]],"o":[[-0.401,3.998],[-3.998,-0.401],[0.401,-3.998],[3.998,0.401]],"v":[[7.24,0.727],[-0.727,7.24],[-7.24,-0.727],[0.727,-7.24]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":234,"s":[{"i":[[0.5,-0.569],[3.408,0.887],[-0.5,0.569],[-3.408,-0.887]],"o":[[-0.5,0.569],[-3.408,-0.887],[0.5,-0.569],[3.408,0.887]],"v":[[6.202,27.043],[-0.876,26.467],[-6.141,23.829],[0.936,24.405]],"c":true}]},{"t":240,"s":[{"i":[[0.401,-3.998],[3.998,0.401],[-0.401,3.998],[-3.998,-0.401]],"o":[[-0.401,3.998],[-3.998,-0.401],[0.401,-3.998],[3.998,0.401]],"v":[[7.24,0.727],[-0.727,7.24],[-7.24,-0.727],[0.727,-7.24]],"c":true}]}]},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":1,"k":[{"i":{"x":[0],"y":[1]},"o":{"x":[1],"y":[0]},"t":100,"s":[1,1,1,1]},{"i":{"x":[0],"y":[1]},"o":{"x":[1],"y":[0]},"t":106,"s":[0,0,0,1]},{"i":{"x":[0],"y":[1]},"o":{"x":[1.925],"y":[0]},"t":112,"s":[1,1,1,1]},{"i":{"x":[0],"y":[1]},"o":{"x":[1],"y":[0]},"t":136,"s":[1,1,1,1]},{"i":{"x":[0],"y":[1]},"o":{"x":[1],"y":[0]},"t":142,"s":[0,0,0,1]},{"i":{"x":[0.585],"y":[1]},"o":{"x":[1],"y":[0]},"t":148,"s":[1,1,1,1]},{"i":{"x":[0],"y":[1]},"o":{"x":[1],"y":[0]},"t":170,"s":[1,1,1,1]},{"i":{"x":[0],"y":[1]},"o":{"x":[1],"y":[0]},"t":176,"s":[0,0,0,1]},{"i":{"x":[0],"y":[1]},"o":{"x":[1],"y":[0]},"t":198,"s":[0,0,0,1]},{"i":{"x":[0],"y":[1]},"o":{"x":[1],"y":[0]},"t":204,"s":[1,1,1,1]},{"i":{"x":[0],"y":[1]},"o":{"x":[1],"y":[0]},"t":228,"s":[1,1,1,1]},{"i":{"x":[0],"y":[1]},"o":{"x":[1],"y":[0]},"t":234,"s":[0,0,0,1]},{"t":240,"s":[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 1","bm":0,"hd":false}],"ip":60,"op":300,"st":0,"bm":0},{"ddd":0,"ind":20,"ty":4,"nm":"eye","parent":22,"sr":1,"ks":{"p":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":152,"s":[-76.447,-58.199,0],"to":[1.318,0.183,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":166,"s":[-68.541,-57.099,0],"to":[0,0,0],"ti":[1.318,0.183,0]},{"i":{"x":0.667,"y":0.667},"o":{"x":0.333,"y":0.333},"t":190,"s":[-76.447,-58.199,0],"to":[0,0,0],"ti":[0,0,0]},{"t":212,"s":[-76.447,-58.199,0]}]},"s":{"a":1,"k":[{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":152,"s":[100,100,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":166,"s":[90,100,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":190,"s":[100,100,100]},{"t":212,"s":[100,100,100]}]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":100,"s":[{"i":[[-0.205,-16.477],[13.692,-0.17],[0.205,16.477],[-13.692,0.17]],"o":[[0.205,16.477],[-13.692,0.17],[-0.205,-16.477],[13.692,-0.17]],"v":[[24.792,-0.308],[0.37,29.834],[-24.792,0.308],[-0.37,-29.834]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":106,"s":[{"i":[[-1.122,-0.585],[24.759,-1.288],[-2.473,1.548],[-18.833,1.007]],"o":[[2.467,1.287],[-13.675,0.711],[1.796,-1.124],[24.776,-1.325]],"v":[[28.644,-2.91],[0.35,13.972],[-24.494,-0.078],[0.305,10.663]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0},"t":112,"s":[{"i":[[-0.205,-16.477],[13.692,-0.17],[0.205,16.477],[-13.692,0.17]],"o":[[0.205,16.477],[-13.692,0.17],[-0.205,-16.477],[13.692,-0.17]],"v":[[24.792,-0.308],[0.37,29.834],[-24.792,0.308],[-0.37,-29.834]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":136,"s":[{"i":[[-0.205,-16.477],[13.692,-0.17],[0.205,16.477],[-13.692,0.17]],"o":[[0.205,16.477],[-13.692,0.17],[-0.205,-16.477],[13.692,-0.17]],"v":[[24.792,-0.308],[0.37,29.834],[-24.792,0.308],[-0.37,-29.834]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":142,"s":[{"i":[[-1.122,-0.585],[24.759,-1.288],[-2.473,1.548],[-18.833,1.007]],"o":[[2.467,1.287],[-13.675,0.711],[1.796,-1.124],[24.776,-1.325]],"v":[[28.644,-2.91],[0.35,13.972],[-24.494,-0.078],[0.305,10.663]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0},"t":148,"s":[{"i":[[-0.205,-16.477],[13.692,-0.17],[0.205,16.477],[-13.692,0.17]],"o":[[0.205,16.477],[-13.692,0.17],[-0.205,-16.477],[13.692,-0.17]],"v":[[24.792,-0.308],[0.37,29.834],[-24.792,0.308],[-0.37,-29.834]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":170,"s":[{"i":[[-0.205,-16.477],[13.692,-0.17],[0.205,16.477],[-13.692,0.17]],"o":[[0.205,16.477],[-13.692,0.17],[-0.205,-16.477],[13.692,-0.17]],"v":[[24.792,-0.308],[0.37,29.834],[-24.792,0.308],[-0.37,-29.834]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":176,"s":[{"i":[[-1.122,-0.585],[24.793,-0.029],[-2.473,1.548],[-19.728,0.15]],"o":[[2.467,1.287],[-18.217,0.021],[1.796,-1.124],[24.811,-0.188]],"v":[[28.644,-2.91],[0.35,13.972],[-24.494,-0.078],[1.335,5.48]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":198,"s":[{"i":[[-1.122,-0.585],[24.759,-1.288],[-2.473,1.548],[-18.833,1.007]],"o":[[2.467,1.287],[-13.675,0.711],[1.796,-1.124],[24.776,-1.325]],"v":[[28.644,-2.91],[0.35,13.972],[-24.494,-0.078],[0.305,10.663]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":204,"s":[{"i":[[-0.205,-16.477],[13.692,-0.17],[0.205,16.477],[-13.692,0.17]],"o":[[0.205,16.477],[-13.692,0.17],[-0.205,-16.477],[13.692,-0.17]],"v":[[24.792,-0.308],[0.37,29.834],[-24.792,0.308],[-0.37,-29.834]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":228,"s":[{"i":[[-0.205,-16.477],[13.692,-0.17],[0.205,16.477],[-13.692,0.17]],"o":[[0.205,16.477],[-13.692,0.17],[-0.205,-16.477],[13.692,-0.17]],"v":[[24.792,-0.308],[0.37,29.834],[-24.792,0.308],[-0.37,-29.834]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":234,"s":[{"i":[[-1.122,-0.585],[24.759,-1.288],[-2.473,1.548],[-18.833,1.007]],"o":[[2.467,1.287],[-13.675,0.711],[1.796,-1.124],[24.776,-1.325]],"v":[[28.644,-2.91],[0.35,13.972],[-24.494,-0.078],[0.305,10.663]],"c":true}]},{"t":240,"s":[{"i":[[-0.205,-16.477],[13.692,-0.17],[0.205,16.477],[-13.692,0.17]],"o":[[0.205,16.477],[-13.692,0.17],[-0.205,-16.477],[13.692,-0.17]],"v":[[24.792,-0.308],[0.37,29.834],[-24.792,0.308],[-0.37,-29.834]],"c":true}]}]},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":0,"k":[0,0,0,1]},"o":{"a":0,"k":100},"w":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":100,"s":[3]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":106,"s":[8]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.185],"y":[0]},"t":112,"s":[3]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":136,"s":[3]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":142,"s":[8]},{"i":{"x":[0.738],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":148,"s":[3]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":170,"s":[3]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":176,"s":[8]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":198,"s":[8]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":204,"s":[3]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":228,"s":[3]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":234,"s":[8]},{"t":240,"s":[3]}]},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0,0,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 1","bm":0,"hd":false}],"ip":60,"op":300,"st":0,"bm":0},{"ddd":0,"ind":21,"ty":4,"nm":"beak_bl","parent":24,"sr":1,"ks":{"o":{"a":0,"k":33},"p":{"a":0,"k":[-21.085,-12.859,0]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":152,"s":[{"i":[[-8.717,1.178],[-5.525,11.05]],"o":[[8.215,-1.111],[3.916,-7.833]],"v":[[-13.902,8.257],[13.902,-8.257]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":166,"s":[{"i":[[-8.717,1.178],[-5.525,11.05]],"o":[[8.215,-1.111],[3.916,-7.833]],"v":[[-13.902,8.257],[13.902,-8.257]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":228,"s":[{"i":[[-8.717,1.178],[-5.525,11.05]],"o":[[8.215,-1.111],[3.916,-7.833]],"v":[[-13.902,8.257],[13.902,-8.257]],"c":false}]},{"t":242,"s":[{"i":[[-8.717,1.178],[-5.525,11.05]],"o":[[8.215,-1.111],[3.916,-7.833]],"v":[[-13.902,8.257],[13.902,-8.257]],"c":false}]}]},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":8},"lc":2,"lj":2,"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":"Group 1","bm":0,"hd":false}],"ip":60,"op":300,"st":0,"bm":0},{"ddd":0,"ind":22,"ty":4,"nm":"mouth","parent":24,"sr":1,"ks":{"o":{"a":1,"k":[{"t":104,"s":[0],"h":1},{"t":152,"s":[100],"h":1},{"t":240,"s":[0],"h":1}]},"p":{"a":0,"k":[1.036,14.348,0]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":152,"s":[{"i":[[18.855,4.147],[-16.363,1.196],[-7.193,3.594]],"o":[[4.333,0.853],[18.111,-1.324],[-15.424,7.974]],"v":[[-32.488,-9.198],[1.276,-6.041],[32.39,-12.417]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":166,"s":[{"i":[[16.286,0.667],[-16.402,0.395],[-8.343,13.613]],"o":[[5.359,6.089],[11.173,-0.269],[-14.142,3.08]],"v":[[-31.783,-6.869],[0.583,9.942],[31.783,-9.952]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":228,"s":[{"i":[[16.286,0.667],[-16.402,0.395],[-8.343,13.613]],"o":[[5.359,6.089],[11.173,-0.269],[-14.142,3.08]],"v":[[-31.783,-6.869],[0.583,9.942],[31.783,-9.952]],"c":true}]},{"t":240,"s":[{"i":[[18.855,4.147],[-16.363,1.196],[-7.193,3.594]],"o":[[4.333,0.853],[18.111,-1.324],[-15.424,7.974]],"v":[[-32.488,-9.198],[1.276,-6.041],[32.39,-12.417]],"c":true}]}]},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":0,"k":[0.490196079016,0.035294119269,0.035294119269,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":8},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.490196079016,0.035294119269,0.035294119269,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 1","bm":0,"hd":false}],"ip":60,"op":300,"st":0,"bm":0},{"ddd":0,"ind":23,"ty":4,"nm":"lips","parent":24,"sr":1,"ks":{"p":{"a":0,"k":[1.701,4.903,0]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":152,"s":[{"i":[[0,0],[-27.403,11.373]],"o":[[25.831,5.896],[0,0]],"v":[[-42.55,-2.052],[42.957,-7.148]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":166,"s":[{"i":[[0,0],[-34.325,6.961]],"o":[[23.321,0.63],[0,0]],"v":[[-42.027,2.058],[42.027,-2.673]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":228,"s":[{"i":[[0,0],[-34.325,6.961]],"o":[[23.321,0.63],[0,0]],"v":[[-42.027,2.058],[42.027,-2.673]],"c":false}]},{"t":242,"s":[{"i":[[0,0],[-27.403,11.373]],"o":[[25.831,5.896],[0,0]],"v":[[-42.55,-2.052],[42.957,-7.148]],"c":false}]}]},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":0,"k":[0.490196079016,0.035294119269,0.035294119269,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":8},"lc":2,"lj":2,"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":"Group 1","bm":0,"hd":false}],"ip":60,"op":300,"st":0,"bm":0},{"ddd":0,"ind":24,"ty":4,"nm":"beak","parent":26,"sr":1,"ks":{"r":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":152,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":166,"s":[-12.998]},{"t":190,"s":[0.178],"h":1},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":212,"s":[0.178]},{"t":234,"s":[0]}]},"p":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":152,"s":[1.026,53.198,0],"to":[1.697,-7.68,0],"ti":[7.422,-6.804,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":166,"s":[-10.732,42.411,0],"to":[19.253,-22.069,0],"ti":[6.204,-22.149,0]},{"t":190,"s":[6.973,73.474,0],"h":1},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":212,"s":[6.973,73.474,0],"to":[-0.182,-14.626,0],"ti":[2.164,-3.681,0]},{"t":234,"s":[1.026,53.198,0]}]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":152,"s":[{"i":[[15.624,0.527],[12.064,-0.021],[37.03,-3.608],[-17.096,-6.557],[-17.932,1.474],[-12.049,7.878]],"o":[[-37.988,-2.814],[-14.971,0.026],[-18.714,1.483],[19.171,7.353],[21.022,-1.728],[10.622,-6.945]],"v":[[41.776,-15.026],[0.351,-38.361],[-41.611,-12.1],[-43.815,12.487],[6.294,20.861],[50.368,5.864]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":166,"s":[{"i":[[15.624,0.527],[12.064,-0.021],[37.03,-3.608],[-13.94,-2.768],[-17.989,0.354],[-7.667,20.847]],"o":[[-37.988,-2.814],[-14.971,0.026],[-18.714,1.483],[9.28,23.039],[17.989,-0.354],[14.609,-0.252]],"v":[[41.776,-15.026],[0.351,-38.361],[-41.611,-12.1],[-42.381,7.693],[3.441,38.35],[44.016,2.253]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":228,"s":[{"i":[[15.624,0.527],[12.064,-0.021],[37.03,-3.608],[-13.94,-2.768],[-17.989,0.354],[-7.667,20.847]],"o":[[-37.988,-2.814],[-14.971,0.026],[-18.714,1.483],[9.28,23.039],[17.989,-0.354],[14.609,-0.252]],"v":[[41.776,-15.026],[0.351,-38.361],[-41.611,-12.1],[-42.381,7.693],[3.441,38.35],[44.016,2.253]],"c":true}]},{"t":242,"s":[{"i":[[15.624,0.527],[12.064,-0.021],[37.03,-3.608],[-17.096,-6.557],[-17.932,1.474],[-12.049,7.878]],"o":[[-37.988,-2.814],[-14.971,0.026],[-18.714,1.483],[19.171,7.353],[21.022,-1.728],[10.622,-6.945]],"v":[[41.776,-15.026],[0.351,-38.361],[-41.611,-12.1],[-43.815,12.487],[6.294,20.861],[50.368,5.864]],"c":true}]}]},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":0,"k":[0.811764717102,0.207843139768,0.007843137719,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":8},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"fl","c":{"a":0,"k":[1,0.364705890417,0.121568627656,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 1","bm":0,"hd":false}],"ip":60,"op":300,"st":0,"bm":0},{"ddd":0,"ind":25,"ty":4,"nm":"Group 1","parent":26,"sr":1,"ks":{"p":{"a":0,"k":[-117.062,11.459,0]},"s":{"a":0,"k":[105.263,105.263,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":166,"s":[{"i":[[0,0],[-31.516,26.673]],"o":[[-0.034,-0.717],[13.121,-11.105]],"v":[[-1.209,24.606],[23.614,-41.458]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":172,"s":[{"i":[[0,0],[-79.176,26.109]],"o":[[-0.034,-0.717],[16.324,-5.383]],"v":[[-1.209,24.606],[76.412,-77.172]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":220,"s":[{"i":[[0,0],[-79.176,26.109]],"o":[[-0.034,-0.717],[16.324,-5.383]],"v":[[-1.209,24.606],[76.412,-77.172]],"c":false}]},{"t":226,"s":[{"i":[[0,0],[-31.516,26.673]],"o":[[-0.034,-0.717],[13.121,-11.105]],"v":[[-1.209,24.606],[23.614,-41.458]],"c":false}]}]},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":8},"lc":2,"lj":2,"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":"Group 1","bm":0,"hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":60,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":72,"s":[5]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":84,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":96,"s":[5]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":108,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":120,"s":[5]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":132,"s":[5]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":144,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":156,"s":[5]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":168,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":180,"s":[5]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":192,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":204,"s":[5]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":216,"s":[5]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":228,"s":[0]},{"t":240,"s":[0]}]},"e":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":60,"s":[95]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":72,"s":[100]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":84,"s":[95]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":96,"s":[100]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":108,"s":[95]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":120,"s":[100]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":132,"s":[100]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":144,"s":[95]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":156,"s":[100]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":168,"s":[95]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":180,"s":[100]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":192,"s":[95]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":204,"s":[100]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":216,"s":[100]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":228,"s":[95]},{"t":240,"s":[95]}]},"o":{"a":0,"k":0},"m":1,"nm":"Trim Paths 2","hd":false}],"ip":0,"op":300,"st":0,"bm":0},{"ddd":0,"ind":26,"ty":4,"nm":"head","parent":32,"sr":1,"ks":{"r":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":154,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":166,"s":[-10.658]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":186,"s":[16.261]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":210,"s":[16.261]},{"t":226,"s":[0]}]},"p":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.7,"y":0},"t":126,"s":[-2.137,13.016,0],"to":[0.5,-9,0],"ti":[-0.5,9,0]},{"i":{"x":0.667,"y":0.667},"o":{"x":0.7,"y":0.7},"t":142,"s":[0.863,-40.984,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":154,"s":[0.863,-40.984,0],"to":[-4.5,-1.667,0],"ti":[-1.833,-2,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":166,"s":[-26.137,-50.984,0],"to":[1.833,2,0],"ti":[-6.333,-3.667,0]},{"i":{"x":0.667,"y":0.667},"o":{"x":0.333,"y":0.333},"t":186,"s":[11.863,-28.984,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":210,"s":[11.863,-28.984,0],"to":[-1.833,-2,0],"ti":[1.833,2,0]},{"t":226,"s":[0.863,-40.984,0]}]},"a":{"a":0,"k":[0,105.595,0]},"s":{"a":1,"k":[{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":154,"s":[100,100,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":162,"s":[98,102,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":176,"s":[102,98,100]},{"t":196,"s":[100,100,100]}]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":154,"s":[{"i":[[-4.466,5.42],[0,25.261],[78.003,0],[0,-69.731],[-18.777,-19.089]],"o":[[14.917,-18.104],[0,-69.731],[-78.003,0],[0,28.799],[2.682,2.727]],"v":[[117.967,98.538],[141.236,32.779],[0,-105.595],[-141.236,32.779],[-111.608,105.595]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":166,"s":[{"i":[[-4.774,5.151],[-1.47,25.219],[77.871,4.54],[4.058,-69.613],[-17.634,-20.149]],"o":[[15.945,-17.205],[4.058,-69.613],[-77.87,-4.54],[-1.676,28.75],[2.519,2.878]],"v":[[117.397,105.896],[144.453,41.603],[11.509,-104.757],[-137.541,25.163],[-112.201,99.58]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":186,"s":[{"i":[[-3.517,6.079],[4.141,24.92],[76.948,-12.787],[-11.431,-68.788],[-21.652,-15.753]],"o":[[11.747,-20.304],[-11.431,-68.788],[-76.947,12.787],[4.721,28.41],[3.093,2.25]],"v":[[126.305,79.696],[138.479,11.012],[-23.53,-102.339],[-140.172,57.316],[-99.009,124.29]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":210,"s":[{"i":[[-3.517,6.079],[4.141,24.92],[76.948,-12.787],[-11.431,-68.788],[-21.652,-15.753]],"o":[[11.747,-20.304],[-11.431,-68.788],[-76.947,12.787],[4.721,28.41],[3.093,2.25]],"v":[[126.305,79.696],[138.479,11.012],[-23.53,-102.339],[-140.172,57.316],[-99.009,124.29]],"c":false}]},{"t":226,"s":[{"i":[[-4.466,5.42],[0,25.261],[78.003,0],[0,-69.731],[-18.777,-19.089]],"o":[[14.917,-18.104],[0,-69.731],[-78.003,0],[0,28.799],[2.682,2.727]],"v":[[117.967,98.538],[141.236,32.779],[0,-105.595],[-141.236,32.779],[-111.608,105.595]],"c":false}]}]},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":0,"k":[0.980392158031,0.564705908298,0.086274512112,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":10},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"fl","c":{"a":0,"k":[1,0.835294127464,0.152941182256,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 1","bm":0,"hd":false}],"ip":60,"op":300,"st":0,"bm":0},{"ddd":0,"ind":27,"ty":4,"nm":"Layer 39","parent":28,"sr":1,"ks":{"o":{"a":0,"k":50},"p":{"a":0,"k":[-7.202,50.028,0]},"s":{"a":0,"k":[105.263,105.263,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":166,"s":[{"i":[[0,0],[0,0],[0,0],[2.355,-2.481],[0,0],[0,0],[2.19,-0.842],[0,0]],"o":[[0,0],[0,0],[-3.03,-1.587],[0,0],[0,0],[-2.016,-1.201],[0,0],[0,0]],"v":[[98.401,-27.012],[91.412,-13.05],[47.199,-36.213],[38.098,-34.703],[9.337,-4.411],[-24.187,-24.377],[-30.848,-24.946],[-87.17,-3.298]],"c":false}]},{"t":190,"s":[{"i":[[0,0],[0,0],[0,0],[2.355,-2.481],[0,0],[0,0],[2.19,-0.842],[0,0]],"o":[[0,0],[0,0],[-3.03,-1.587],[0,0],[0,0],[-2.016,-1.201],[0,0],[0,0]],"v":[[99.678,-21.818],[91.302,-5.479],[47.346,-30.299],[38.245,-28.789],[9.457,2.405],[-24.04,-18.463],[-30.701,-19.031],[-86.873,4.566]],"c":false}],"h":1},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":212,"s":[{"i":[[0,0],[0,0],[0,0],[2.355,-2.481],[0,0],[0,0],[2.19,-0.842],[0,0]],"o":[[0,0],[0,0],[-3.03,-1.587],[0,0],[0,0],[-2.016,-1.201],[0,0],[0,0]],"v":[[99.678,-21.818],[91.302,-5.479],[47.346,-30.299],[38.245,-28.789],[9.457,2.405],[-24.04,-18.463],[-30.701,-19.031],[-86.873,4.566]],"c":false}]},{"t":226,"s":[{"i":[[0,0],[0,0],[0,0],[2.355,-2.481],[0,0],[0,0],[2.19,-0.842],[0,0]],"o":[[0,0],[0,0],[-3.03,-1.587],[0,0],[0,0],[-2.016,-1.201],[0,0],[0,0]],"v":[[98.401,-27.012],[91.412,-13.05],[47.199,-36.213],[38.098,-34.703],[9.337,-4.411],[-24.187,-24.377],[-30.848,-24.946],[-87.17,-3.298]],"c":false}]}]},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":0,"k":[0.917647118662,0.898039275525,0.862745157878,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":10},"lc":2,"lj":2,"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":"Group 1","bm":0,"hd":false}],"ip":0,"op":300,"st":0,"bm":0},{"ddd":0,"ind":28,"ty":4,"nm":"hat 3","parent":16,"sr":1,"ks":{},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":166,"s":[{"i":[[51.485,0],[31.539,-52.074],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[-51.247,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-31.567,-52.438]],"v":[[-0.221,-57.456],[-127.241,33.8],[-100.496,57.456],[-36.511,32.863],[4.779,57.456],[39.497,20.887],[93.689,49.278],[104.97,26.739],[127.241,34.528]],"c":true}]},{"t":190,"s":[{"i":[[51.485,0],[31.539,-52.074],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[-51.247,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-31.567,-52.438]],"v":[[-0.221,-57.456],[-127.241,33.8],[-100.719,65.049],[-36.734,40.456],[4.556,65.049],[39.274,28.481],[93.466,56.871],[104.747,34.333],[127.241,34.528]],"c":true}],"h":1},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":212,"s":[{"i":[[51.485,0],[31.539,-52.074],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[-51.247,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-31.567,-52.438]],"v":[[-0.221,-57.456],[-127.241,33.8],[-100.719,65.049],[-36.734,40.456],[4.556,65.049],[39.274,28.481],[93.466,56.871],[104.747,34.333],[127.241,34.528]],"c":true}]},{"t":226,"s":[{"i":[[51.485,0],[31.539,-52.074],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[-51.247,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-31.567,-52.438]],"v":[[-0.221,-57.456],[-127.241,33.8],[-100.496,57.456],[-36.511,32.863],[4.779,57.456],[39.497,20.887],[93.689,49.278],[104.97,26.739],[127.241,34.528]],"c":true}]}]},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":0,"k":[0.717647075653,0.674509823322,0.603921592236,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":10},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.809911151961,0.774132463044,0.71599222819,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 1","bm":0,"hd":false}],"ip":60,"op":300,"st":0,"bm":0},{"ddd":0,"ind":29,"ty":4,"nm":"wing","parent":32,"sr":1,"ks":{"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":154,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":166,"s":[-41.998]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[1],"y":[0]},"t":190,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":212,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":226,"s":[-41.998]},{"t":236,"s":[0]}]},"p":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.7,"y":0},"t":118,"s":[67.833,-2.967,0],"to":[7.148,-3.993,0],"ti":[-7.148,3.993,0]},{"i":{"x":0.667,"y":0.667},"o":{"x":0.7,"y":0.7},"t":134,"s":[110.723,-26.923,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":154,"s":[110.723,-26.923,0],"to":[-2.833,-8.5,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":166,"s":[93.723,-77.923,0],"to":[0,0,0],"ti":[-2.833,-8.5,0]},{"i":{"x":0.667,"y":0.667},"o":{"x":1,"y":1},"t":190,"s":[110.723,-26.923,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":212,"s":[110.723,-26.923,0],"to":[1.06,-3.907,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":226,"s":[117.083,-50.367,0],"to":[0,0,0],"ti":[1.06,-3.907,0]},{"t":236,"s":[110.723,-26.923,0]}]},"a":{"a":0,"k":[-38,10,0]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":154,"s":[{"i":[[-26.375,10.894],[-10.894,-9.299],[15.481,-6.88]],"o":[[26.375,-10.894],[10.894,9.299],[-15.481,6.88]],"v":[[-51.094,-17.505],[50.007,-36.63],[-28.733,39.258]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":166,"s":[{"i":[[-28.013,5.439],[-14.323,-0.025],[110.256,-18.389]],"o":[[82.606,-16.04],[25.955,0.046],[-16.71,2.787]],"v":[[-51.094,-17.505],[40.159,-122.382],[-51.991,56.361]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":1,"y":0},"t":190,"s":[{"i":[[-26.489,10.614],[-10.894,-9.299],[41.775,-72.863]],"o":[[61.398,-24.603],[10.894,9.299],[-8.426,14.697]],"v":[[-52.915,-37.647],[75.033,-53.431],[-22.097,62.688]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":212,"s":[{"i":[[-26.489,10.614],[-10.894,-9.299],[36.773,-81.774]],"o":[[61.398,-24.603],[10.894,9.299],[-6.948,15.451]],"v":[[-52.915,-37.647],[73.837,-56.271],[-5.191,70.407]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":226,"s":[{"i":[[-28.013,5.439],[-14.323,-0.025],[154.158,-2.538]],"o":[[82.606,-16.04],[25.955,0.046],[-16.939,0.279]],"v":[[-51.094,-17.505],[60.479,-100.012],[-68.541,50.439]],"c":false}]},{"t":236,"s":[{"i":[[-24.807,14.104],[-10.894,-9.299],[25.623,-24.231]],"o":[[35.353,-20.099],[10.894,9.299],[-12.309,11.64]],"v":[[-51.094,-17.505],[53.164,-23.999],[-26.628,42.416]],"c":false}]}]},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":0,"k":[0.980392158031,0.564705908298,0.086274512112,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":10},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"fl","c":{"a":0,"k":[1,0.835294127464,0.152941182256,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 1","bm":0,"hd":false}],"ip":60,"op":300,"st":0,"bm":0},{"ddd":0,"ind":30,"ty":4,"nm":"Group 2","parent":31,"sr":1,"ks":{"r":{"a":0,"k":87.025},"p":{"a":0,"k":[-22.432,-25.336,0]},"a":{"a":0,"k":[-3.703,14.028,0]},"s":{"a":0,"k":[105.263,105.263,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":156,"s":[{"i":[[0,0],[-1.88,12.796]],"o":[[-0.021,-0.44],[1.184,-8.054]],"v":[[-4.221,24.977],[-3.046,3.079]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":168,"s":[{"i":[[0,0],[-1.88,12.796]],"o":[[-0.021,-0.44],[1.184,-8.054]],"v":[[2.911,12.803],[-0.313,-10.663]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":1,"y":0},"t":190,"s":[{"i":[[0,0],[-0.892,16.675]],"o":[[0.049,-0.438],[0.435,-8.129]],"v":[[9.974,6.265],[13.383,-24.109]],"c":false}]},{"i":{"x":0.833,"y":0.771},"o":{"x":0.333,"y":0},"t":212,"s":[{"i":[[0,0],[-4.153,14.442]],"o":[[-0.021,-0.44],[2.25,-7.824]],"v":[[2.498,0.447],[15.576,-23.398]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0.229},"t":224,"s":[{"i":[[0,0],[-4.331,10.606]],"o":[[-0.021,-0.44],[3.078,-7.536]],"v":[[-16.415,23.679],[-3.338,-0.166]],"c":false}]},{"t":238,"s":[{"i":[[0,0],[-1.88,12.796]],"o":[[-0.021,-0.44],[1.184,-8.054]],"v":[[1.914,22.542],[-0.118,-0.273]],"c":false}]}]},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":8},"lc":2,"lj":2,"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":"Group 1","bm":0,"hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":60,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":72,"s":[5]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":84,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":96,"s":[5]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":108,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":120,"s":[5]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":132,"s":[5]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":144,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":156,"s":[5]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":168,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":180,"s":[5]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":192,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":204,"s":[5]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":216,"s":[5]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":228,"s":[0]},{"t":240,"s":[0]}]},"e":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":60,"s":[95]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":72,"s":[100]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":84,"s":[95]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":96,"s":[100]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":108,"s":[95]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":120,"s":[100]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":132,"s":[100]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":144,"s":[95]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":156,"s":[100]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":168,"s":[95]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":180,"s":[100]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":192,"s":[95]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":204,"s":[100]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":216,"s":[100]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":228,"s":[95]},{"t":240,"s":[95]}]},"o":{"a":0,"k":0},"m":1,"nm":"Trim Paths 1","hd":false}],"ip":0,"op":300,"st":0,"bm":0},{"ddd":0,"ind":31,"ty":4,"nm":"wing","parent":32,"sr":1,"ks":{"r":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":210,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":220,"s":[23.836]},{"t":234,"s":[0]}]},"p":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.7,"y":0},"t":118,"s":[-72.05,-11.733,0],"to":[-6.108,-2.813,0],"ti":[6.108,2.813,0]},{"t":134,"s":[-108.7,-28.609,0]}]},"a":{"a":0,"k":[28,7,0]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":156,"s":[{"i":[[44.723,19.495],[6.88,-6.88],[-21.215,-12.041]],"o":[[-44.723,-19.495],[-6.88,6.88],[21.215,12.041]],"v":[[55.051,-21.113],[-54.463,-33.792],[15.3,37.944]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":168,"s":[{"i":[[40.019,27.905],[6.88,-6.88],[-12.005,-38.832]],"o":[[-50.639,-35.31],[-6.88,6.88],[7.205,23.305]],"v":[[55.051,-21.113],[-33.354,-19.801],[15.3,37.944]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":1,"y":0},"t":190,"s":[{"i":[[43.781,-21.527],[6.88,-6.88],[-36.462,3.735]],"o":[[-35.333,17.373],[-6.88,6.88],[24.267,-2.486]],"v":[[55.002,-33.744],[-28.249,-25.127],[24.734,27.382]],"c":false}]},{"i":{"x":0.833,"y":0.771},"o":{"x":0.333,"y":0},"t":212,"s":[{"i":[[31.423,-37.32],[6.88,-6.88],[-21.215,-12.041]],"o":[[-30.66,36.415],[-6.88,6.88],[21.215,12.041]],"v":[[54.449,-31.891],[-14.199,-34.428],[15.3,37.944]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0.229},"t":224,"s":[{"i":[[38.977,-5.05],[6.88,-6.88],[-21.215,-12.041]],"o":[[-38.648,4.659],[-6.88,6.88],[21.215,12.041]],"v":[[46.091,-30.836],[-50.254,-51.54],[15.3,37.944]],"c":false}]},{"t":238,"s":[{"i":[[41.97,24.874],[6.88,-6.88],[-27.724,-35.81]],"o":[[-49.58,-29.385],[-6.88,6.88],[14.933,19.289]],"v":[[55.051,-21.113],[-54.463,-21.16],[15.3,37.944]],"c":false}]}]},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":0,"k":[0.980392158031,0.564705908298,0.086274512112,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":10},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"fl","c":{"a":0,"k":[1,0.835294127464,0.152941182256,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 1","bm":0,"hd":false}],"ip":60,"op":300,"st":0,"bm":0},{"ddd":0,"ind":32,"ty":4,"nm":"body","parent":11,"sr":1,"ks":{"r":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":154,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":166,"s":[-8.077]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[1],"y":[0]},"t":190,"s":[-4]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":212,"s":[-8.077]},{"t":238,"s":[0]}]},"p":{"a":0,"k":[0.389,106.033,0]},"a":{"a":0,"k":[-1.366,88.432,0]},"s":{"a":1,"k":[{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":154,"s":[100,100,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":166,"s":[102,97,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"t":176,"s":[100,100,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"t":198,"s":[100,100,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"t":210,"s":[100,100,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":222,"s":[104,96,100]},{"t":234,"s":[100,100,100]}]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":156,"s":[{"i":[[64.383,0],[6.394,38.501],[-25.026,0],[-12.695,-155.506]],"o":[[-55.365,0],[-22.826,-137.447],[73.802,0],[0,41.974]],"v":[[-12.594,88.432],[-146.58,44.158],[-17.431,-112.855],[146.58,44.662]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":168,"s":[{"i":[[64.383,0],[2.301,38.485],[-24.793,-1.896],[-31.206,-151.304]],"o":[[-55.365,0],[-22.007,-135.548],[75.527,6.194],[0,41.974]],"v":[[-12.594,88.432],[-146.58,44.158],[-35.39,-122.327],[146.58,44.662]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":190,"s":[{"i":[[64.383,0],[-6.704,38.449],[-24.28,-6.067],[20.527,-81.097]],"o":[[-55.365,0],[26.413,-151.494],[79.321,19.822],[0,41.974]],"v":[[-12.594,88.432],[-146.58,44.158],[30.572,-112.038],[146.58,44.662]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":212,"s":[{"i":[[64.383,0],[-6.704,38.449],[-24.28,-6.067],[20.527,-81.097]],"o":[[-55.365,0],[26.413,-151.494],[79.321,19.822],[0,41.974]],"v":[[-12.594,88.432],[-146.58,44.158],[30.572,-112.038],[146.58,44.662]],"c":true}]},{"t":228,"s":[{"i":[[64.383,0],[6.394,38.501],[-25.026,0],[-12.695,-155.506]],"o":[[-55.365,0],[-22.826,-137.447],[73.802,0],[0,41.974]],"v":[[-12.594,88.432],[-146.58,44.158],[-17.431,-112.855],[146.58,44.662]],"c":true}]}]},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":0,"k":[0.980392158031,0.564705908298,0.086274512112,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":10},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"fl","c":{"a":0,"k":[1,0.835294127464,0.152941182256,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 1","bm":0,"hd":false}],"ip":60,"op":300,"st":0,"bm":0},{"ddd":0,"ind":33,"ty":4,"nm":"egg 4","parent":11,"sr":1,"ks":{"p":{"a":0,"k":[-0.594,98.167,0]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,-20.217],[-103.123,0],[0,103.123],[3.782,18.863]],"o":[[0,0],[0,0],[0,0],[-5.396,22.871],[0,103.123],[103.123,0],[0,-16.835],[0,0]],"v":[[144.621,-98.445],[114.065,-103.58],[-126.136,-117.083],[-169.594,-119.546],[-177.863,-54.108],[0,119.546],[177.863,-54.108],[172.088,-108.121]],"c":true}},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":0,"k":[0.717647075653,0.674509823322,0.603921592236,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":10},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.811764765721,0.772549079446,0.717647058824,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 1","bm":0,"hd":false}],"ip":132,"op":300,"st":0,"bm":0}]}],"layers":[{"ddd":0,"ind":1,"ty":0,"nm":"_053_EGG","refId":"comp_0","sr":1,"ks":{"p":{"a":0,"k":[256,256,0]},"a":{"a":0,"k":[256,256,0]}},"ao":0,"w":512,"h":512,"ip":0,"op":180,"st":-60,"bm":0}]} \ No newline at end of file diff --git a/TMessagesProj/src/main/res/values-night/styles.xml b/TMessagesProj/src/main/res/values-night/styles.xml index 6758ec954..85bbd39fd 100644 --- a/TMessagesProj/src/main/res/values-night/styles.xml +++ b/TMessagesProj/src/main/res/values-night/styles.xml @@ -20,6 +20,9 @@ #232d3a #000000 false + @drawable/tg_splash_320 + @integer/splash_screen_duration + ?android:windowBackground +