diff --git a/TMessagesProj/jni/CMakeLists.txt b/TMessagesProj/jni/CMakeLists.txt index c74732f31d2..570d5ed9bb0 100644 --- a/TMessagesProj/jni/CMakeLists.txt +++ b/TMessagesProj/jni/CMakeLists.txt @@ -425,7 +425,7 @@ target_include_directories(breakpad PUBLIC #voip include(${CMAKE_HOME_DIRECTORY}/voip/CMakeLists.txt) -set(NATIVE_LIB "tmessages.47") +set(NATIVE_LIB "tmessages.48") #tmessages add_library(${NATIVE_LIB} SHARED diff --git a/TMessagesProj/jni/TgNetWrapper.cpp b/TMessagesProj/jni/TgNetWrapper.cpp index 7ee850d7caf..211f32b83b6 100644 --- a/TMessagesProj/jni/TgNetWrapper.cpp +++ b/TMessagesProj/jni/TgNetWrapper.cpp @@ -8,19 +8,15 @@ #include "tgnet/FileLog.h" JavaVM *java; -jclass jclass_RequestDelegateInternal; -jmethodID jclass_RequestDelegateInternal_run; jclass jclass_RequestTimeDelegate; jmethodID jclass_RequestTimeDelegate_run; -jclass jclass_QuickAckDelegate; -jmethodID jclass_QuickAckDelegate_run; - -jclass jclass_WriteToSocketDelegate; -jmethodID jclass_WriteToSocketDelegate_run; - jclass jclass_ConnectionsManager; +jmethodID jclass_ConnectionsManager_onRequestClear; +jmethodID jclass_ConnectionsManager_onRequestComplete; +jmethodID jclass_ConnectionsManager_onRequestQuickAck; +jmethodID jclass_ConnectionsManager_onRequestWriteToSocket; jmethodID jclass_ConnectionsManager_onUnparsedMessageReceived; jmethodID jclass_ConnectionsManager_onUpdate; jmethodID jclass_ConnectionsManager_onSessionCreated; @@ -93,22 +89,10 @@ jint getTimeDifference(JNIEnv *env, jclass c, jint instanceNum) { return ConnectionsManager::getInstance(instanceNum).getTimeDifference(); } -void sendRequest(JNIEnv *env, jclass c, jint instanceNum, jlong object, jobject onComplete, jobject onQuickAck, jobject onWriteToSocket, jint flags, jint datacenterId, jint connetionType, jboolean immediate, jint token) { +void sendRequest(JNIEnv *env, jclass c, jint instanceNum, jlong object, jint flags, jint datacenterId, jint connectionType, jboolean immediate, jint token) { TL_api_request *request = new TL_api_request(); request->request = (NativeByteBuffer *) (intptr_t) object; - if (onComplete != nullptr) { - DEBUG_REF("sendRequest onComplete"); - onComplete = env->NewGlobalRef(onComplete); - } - if (onQuickAck != nullptr) { - DEBUG_REF("sendRequest onQuickAck"); - onQuickAck = env->NewGlobalRef(onQuickAck); - } - if (onWriteToSocket != nullptr) { - DEBUG_REF("sendRequest onWriteToSocket"); - onWriteToSocket = env->NewGlobalRef(onWriteToSocket); - } - ConnectionsManager::getInstance(instanceNum).sendRequest(request, ([onComplete, instanceNum](TLObject *response, TL_error *error, int32_t networkType, int64_t responseTime, int64_t msgId) { + ConnectionsManager::getInstance(instanceNum).sendRequest(request, ([instanceNum, token](TLObject *response, TL_error *error, int32_t networkType, int64_t responseTime, int64_t msgId) { TL_api_response *resp = (TL_api_response *) response; jlong ptr = 0; jint errorCode = 0; @@ -125,25 +109,23 @@ void sendRequest(JNIEnv *env, jclass c, jint instanceNum, jlong object, jobject errorText = jniEnv[instanceNum]->NewStringUTF("UTF-8 ERROR"); } } - if (onComplete != nullptr) { - jniEnv[instanceNum]->CallVoidMethod(onComplete, jclass_RequestDelegateInternal_run, ptr, errorCode, errorText, networkType, responseTime, msgId); - } + jniEnv[instanceNum]->CallStaticVoidMethod(jclass_ConnectionsManager, jclass_ConnectionsManager_onRequestComplete, instanceNum, token, ptr, errorCode, errorText, networkType, responseTime, msgId); if (errorText != nullptr) { jniEnv[instanceNum]->DeleteLocalRef(errorText); } - }), ([onQuickAck, instanceNum] { - if (onQuickAck != nullptr) { - jniEnv[instanceNum]->CallVoidMethod(onQuickAck, jclass_QuickAckDelegate_run); - } - }), ([onWriteToSocket, instanceNum] { - if (onWriteToSocket != nullptr) { - jniEnv[instanceNum]->CallVoidMethod(onWriteToSocket, jclass_WriteToSocketDelegate_run); - } - }), (uint32_t) flags, (uint32_t) datacenterId, (ConnectionType) connetionType, immediate, token, onComplete, onQuickAck, onWriteToSocket); + }), ([instanceNum, token] { + jniEnv[instanceNum]->CallStaticVoidMethod(jclass_ConnectionsManager, jclass_ConnectionsManager_onRequestQuickAck, instanceNum, token); + }), ([instanceNum, token] { + jniEnv[instanceNum]->CallStaticVoidMethod(jclass_ConnectionsManager, jclass_ConnectionsManager_onRequestWriteToSocket, instanceNum, token); + }), ([instanceNum, token] { + jniEnv[instanceNum]->CallStaticVoidMethod(jclass_ConnectionsManager, jclass_ConnectionsManager_onRequestClear, instanceNum, token, false); + }), (uint32_t) flags, (uint32_t) datacenterId, (ConnectionType) connectionType, immediate, token); } void cancelRequest(JNIEnv *env, jclass c, jint instanceNum, jint token, jboolean notifyServer) { - return ConnectionsManager::getInstance(instanceNum).cancelRequest(token, notifyServer); + return ConnectionsManager::getInstance(instanceNum).cancelRequest(token, notifyServer, ([instanceNum, token]() -> void { + jniEnv[instanceNum]->CallStaticVoidMethod(jclass_ConnectionsManager, jclass_ConnectionsManager_onRequestClear, instanceNum, token, true); + })); } void failNotRunningRequest(JNIEnv *env, jclass c, jint instanceNum, jint token) { @@ -452,7 +434,7 @@ static JNINativeMethod ConnectionsManagerMethods[] = { {"native_getCurrentDatacenterId", "(I)I", (void *) getCurrentDatacenterId}, {"native_isTestBackend", "(I)I", (void *) isTestBackend}, {"native_getTimeDifference", "(I)I", (void *) getTimeDifference}, - {"native_sendRequest", "(IJLorg/telegram/tgnet/RequestDelegateInternal;Lorg/telegram/tgnet/QuickAckDelegate;Lorg/telegram/tgnet/WriteToSocketDelegate;IIIZI)V", (void *) sendRequest}, + {"native_sendRequest", "(IJIIIZI)V", (void *) sendRequest}, {"native_cancelRequest", "(IIZ)V", (void *) cancelRequest}, {"native_cleanUp", "(IZ)V", (void *) cleanUp}, {"native_cancelRequestsForGuid", "(II)V", (void *) cancelRequestsForGuid}, @@ -503,16 +485,6 @@ extern "C" int registerNativeTgNetFunctions(JavaVM *vm, JNIEnv *env) { return JNI_FALSE; } - DEBUG_REF("RequestDelegateInternal class"); - jclass_RequestDelegateInternal = (jclass) env->NewGlobalRef(env->FindClass("org/telegram/tgnet/RequestDelegateInternal")); - if (jclass_RequestDelegateInternal == 0) { - return JNI_FALSE; - } - jclass_RequestDelegateInternal_run = env->GetMethodID(jclass_RequestDelegateInternal, "run", "(JILjava/lang/String;IJJ)V"); - if (jclass_RequestDelegateInternal_run == 0) { - return JNI_FALSE; - } - DEBUG_REF("RequestTimeDelegate class"); jclass_RequestTimeDelegate = (jclass) env->NewGlobalRef(env->FindClass("org/telegram/tgnet/RequestTimeDelegate")); if (jclass_RequestTimeDelegate == 0) { @@ -523,28 +495,25 @@ extern "C" int registerNativeTgNetFunctions(JavaVM *vm, JNIEnv *env) { return JNI_FALSE; } - DEBUG_REF("QuickAckDelegate class"); - jclass_QuickAckDelegate = (jclass) env->NewGlobalRef(env->FindClass("org/telegram/tgnet/QuickAckDelegate")); - if (jclass_RequestDelegateInternal == 0) { + DEBUG_REF("ConnectionsManager class"); + jclass_ConnectionsManager = (jclass) env->NewGlobalRef(env->FindClass("org/telegram/tgnet/ConnectionsManager")); + if (jclass_ConnectionsManager == 0) { return JNI_FALSE; } - jclass_QuickAckDelegate_run = env->GetMethodID(jclass_QuickAckDelegate, "run", "()V"); - if (jclass_QuickAckDelegate_run == 0) { + jclass_ConnectionsManager_onRequestClear = env->GetStaticMethodID(jclass_ConnectionsManager, "onRequestClear", "(IIZ)V"); + if (jclass_ConnectionsManager_onRequestClear == 0) { return JNI_FALSE; } - - DEBUG_REF("WriteToSocketDelegate class"); - jclass_WriteToSocketDelegate = (jclass) env->NewGlobalRef(env->FindClass("org/telegram/tgnet/WriteToSocketDelegate")); - if (jclass_WriteToSocketDelegate == 0) { + jclass_ConnectionsManager_onRequestComplete = env->GetStaticMethodID(jclass_ConnectionsManager, "onRequestComplete", "(IIJILjava/lang/String;IJJ)V"); + if (jclass_ConnectionsManager_onRequestComplete == 0) { return JNI_FALSE; } - jclass_WriteToSocketDelegate_run = env->GetMethodID(jclass_WriteToSocketDelegate, "run", "()V"); - if (jclass_WriteToSocketDelegate_run == 0) { + jclass_ConnectionsManager_onRequestWriteToSocket = env->GetStaticMethodID(jclass_ConnectionsManager, "onRequestWriteToSocket", "(II)V"); + if (jclass_ConnectionsManager_onRequestWriteToSocket == 0) { return JNI_FALSE; } - DEBUG_REF("ConnectionsManager class"); - jclass_ConnectionsManager = (jclass) env->NewGlobalRef(env->FindClass("org/telegram/tgnet/ConnectionsManager")); - if (jclass_ConnectionsManager == 0) { + jclass_ConnectionsManager_onRequestQuickAck = env->GetStaticMethodID(jclass_ConnectionsManager, "onRequestQuickAck", "(II)V"); + if (jclass_ConnectionsManager_onRequestQuickAck == 0) { return JNI_FALSE; } jclass_ConnectionsManager_onUnparsedMessageReceived = env->GetStaticMethodID(jclass_ConnectionsManager, "onUnparsedMessageReceived", "(JIJ)V"); diff --git a/TMessagesProj/jni/tgnet/ConnectionsManager.cpp b/TMessagesProj/jni/tgnet/ConnectionsManager.cpp index 79fda991fb6..1a0b2d9b67e 100644 --- a/TMessagesProj/jni/tgnet/ConnectionsManager.cpp +++ b/TMessagesProj/jni/tgnet/ConnectionsManager.cpp @@ -649,6 +649,7 @@ void ConnectionsManager::cleanUp(bool resetKeys, int32_t datacenterId) { request->onComplete(nullptr, error, 0, 0, request->messageId); delete error; } + DEBUG_D("1) erase request %d 0x%" PRIx64, request->requestToken, request->messageId); iter = runningRequests.erase(iter); } quickAckIdToRequestIds.clear(); @@ -753,6 +754,7 @@ void ConnectionsManager::onConnectionClosed(Connection *connection, int reason) Request *request = iter2->get(); if (connection->getConnectionToken() == request->connectionToken && request->requestToken == proxyCheckInfo->requestToken && (request->connectionType & 0x0000ffff) == ConnectionTypeProxy) { request->completed = true; + DEBUG_D("2) erase request %d 0x%" PRIx64, request->requestToken, request->messageId); runningRequests.erase(iter2); proxyCheckInfo->onRequestTime(-1); found = true; @@ -943,9 +945,14 @@ void ConnectionsManager::onConnectionDataReceived(Connection *connection, Native TLObject *object = nullptr; + long req_msg_id = 0; if (processedStatus != 1) { deserializingDatacenter = datacenter; object = TLdeserialize(nullptr, messageLength, data); + TL_rpc_result* res = dynamic_cast(object); + if (res != nullptr) { + req_msg_id = res->req_msg_id; + } if (processedStatus == 2) { if (object == nullptr) { connection->recreateSession(); @@ -970,13 +977,13 @@ void ConnectionsManager::onConnectionDataReceived(Connection *connection, Native sendMessagesToConnectionWithConfirmation(messages, connection, false); } } else { - if (LOGS_ENABLED) DEBUG_D("connection(%p, account%u, dc%u, type %d) received unparsed packet on 0x%" PRIx64, connection, instanceNum, datacenter->getDatacenterId(), connection->getConnectionType(), messageId); + if (LOGS_ENABLED) DEBUG_D("connection(%p, account%u, dc%u, type %d) received unparsed packet on 0x%" PRIx64, connection, instanceNum, datacenter->getDatacenterId(), connection->getConnectionType(), req_msg_id); if (delegate != nullptr) { delegate->onUnparsedMessageReceived(messageId, data, connection->getConnectionType(), instanceNum); } } } else { - if (LOGS_ENABLED) DEBUG_D("connection(%p, account%u, dc%u, type %d) received unprocessed packet on 0x%" PRIx64, connection, instanceNum, datacenter->getDatacenterId(), connection->getConnectionType(), messageId); + if (LOGS_ENABLED) DEBUG_D("connection(%p, account%u, dc%u, type %d) received unprocessed packet on 0x%" PRIx64, connection, instanceNum, datacenter->getDatacenterId(), connection->getConnectionType(), req_msg_id); std::vector> messages; sendMessagesToConnectionWithConfirmation(messages, connection, false); } @@ -1014,8 +1021,8 @@ bool ConnectionsManager::hasPendingRequestsForConnection(Connection *connection) } TLObject *ConnectionsManager::getRequestWithMessageId(int64_t messageId) { - for (auto & runningRequest : runningRequests) { - Request *request = runningRequest.get(); + for (auto & iter : runningRequests) { + Request *request = iter.get(); if (request->messageId == messageId) { return request->rawRequest; } @@ -1162,6 +1169,7 @@ void ConnectionsManager::processServerResponse(TLObject *message, int64_t messag if (LOGS_ENABLED) DEBUG_D("got ping response for request %p, %" PRId64, request->rawRequest, ping); request->completed = true; proxyCheckInfo->onRequestTime(ping); + DEBUG_D("3) erase request %d 0x%" PRIx64, request->requestToken, request->messageId); runningRequests.erase(iter2); break; } @@ -1196,6 +1204,7 @@ void ConnectionsManager::processServerResponse(TLObject *message, int64_t messag if (request->respondsToMessageId(requestMid)) { request->onComplete(response, nullptr, connection->currentNetworkType, timeMessage, requestMid); request->completed = true; + DEBUG_D("4) erase request %d 0x%" PRIx64, request->requestToken, request->messageId); runningRequests.erase(iter); break; } @@ -1372,6 +1381,37 @@ void ConnectionsManager::processServerResponse(TLObject *message, int64_t messag implicitError->code = -1000; implicitError->text = ""; } + + if (hasResult) { + // when receiving TL_rpc_answer_dropped_running, we want to still listen for a little for the response, as it may come + TL_rpc_answer_dropped_running* droppedRunning = dynamic_cast(response->result.get()); + if (droppedRunning != nullptr) { + TL_rpc_drop_answer* dropAnswer = dynamic_cast(request->rawRequest); + if (dropAnswer != nullptr) { + int64_t originalMessageId = dropAnswer->req_msg_id; + Request* originalRequest = nullptr; + for (auto iter2 = runningRequests.begin(); iter2 != runningRequests.end(); iter2++) { + Request *request2 = iter2->get(); + if (request2->messageId == originalMessageId) { + originalRequest = request2; + break; + } + } + if (originalRequest != nullptr && (originalRequest->requestFlags & RequestFlagListenAfterCancel) != 0) { + if (LOGS_ENABLED) DEBUG_D("doNotClearOnDrop = true; msgid=0x%" PRIx64, originalMessageId); + originalRequest->disableClearCallback = false; + originalRequest->doNotClearOnDrop = true; + originalRequest->clearAfter = (int32_t) (getCurrentTimeMonotonicMillis() / 1000) + 25; + originalRequest->onRequestClearCallback = request->onRequestClearCallback; + request->onRequestClearCallback = nullptr; + } else { + if (LOGS_ENABLED) DEBUG_D("not found request; msgid=0x%" PRIx64, originalMessageId); + } + } else { + if (LOGS_ENABLED) DEBUG_D("not found dropAnswer; msgid=0x%" PRIx64, request->messageId); + } + } + } } if (!discardResponse) { @@ -1441,6 +1481,7 @@ void ConnectionsManager::processServerResponse(TLObject *message, int64_t messag } request->completed = true; removeRequestFromGuid(request->requestToken); + if (LOGS_ENABLED) DEBUG_D("5) erase request %d 0x%" PRIx64, request->requestToken, request->messageId); runningRequests.erase(iter); } else { request->messageId = 0; @@ -1584,7 +1625,7 @@ void ConnectionsManager::processServerResponse(TLObject *message, int64_t messag } if (LOGS_ENABLED) DEBUG_D("got TL_msg_detailed_info for rpc request %p - %s", request->rawRequest, typeid(*request->rawRequest).name()); auto currentTime = (int32_t) (getCurrentTimeMonotonicMillis() / 1000); - if (request->lastResendTime == 0 || abs(currentTime - request->lastResendTime) >= 60) { + if (!request->cancelled && (request->lastResendTime == 0 || abs(currentTime - request->lastResendTime) >= 60)) { request->lastResendTime = currentTime; requestResend = true; } else { @@ -1779,8 +1820,8 @@ void ConnectionsManager::detachConnection(ConnectionSocket *connection) { } } -int32_t ConnectionsManager::sendRequestInternal(TLObject *object, onCompleteFunc onComplete, onQuickAckFunc onQuickAck, uint32_t flags, uint32_t datacenterId, ConnectionType connetionType, bool immediate) { - auto request = new Request(instanceNum, lastRequestToken++, connetionType, flags, datacenterId, onComplete, onQuickAck, nullptr); +int32_t ConnectionsManager::sendRequestInternal(TLObject *object, onCompleteFunc onComplete, onQuickAckFunc onQuickAck, onRequestClearFunc onClear, uint32_t flags, uint32_t datacenterId, ConnectionType connectionType, bool immediate) { + auto request = new Request(instanceNum, lastRequestToken++, connectionType, flags, datacenterId, onComplete, onQuickAck, nullptr, onClear); request->rawRequest = object; request->rpcRequest = wrapInLayer(object, getDatacenterWithId(datacenterId), request); auto cancelledIterator = tokensToBeCancelled.find(request->requestToken); @@ -1802,17 +1843,17 @@ int32_t ConnectionsManager::sendRequestInternal(TLObject *object, onCompleteFunc return request->requestToken; } -int32_t ConnectionsManager::sendRequest(TLObject *object, onCompleteFunc onComplete, onQuickAckFunc onQuickAck, uint32_t flags, uint32_t datacenterId, ConnectionType connetionType, bool immediate) { +int32_t ConnectionsManager::sendRequest(TLObject *object, onCompleteFunc onComplete, onQuickAckFunc onQuickAck, onRequestClearFunc onClear, uint32_t flags, uint32_t datacenterId, ConnectionType connectionType, bool immediate) { int32_t requestToken = lastRequestToken++; - return sendRequest(object, onComplete, onQuickAck, flags, datacenterId, connetionType, immediate, requestToken); + return sendRequest(object, onComplete, onQuickAck, onClear, flags, datacenterId, connectionType, immediate, requestToken); } -int32_t ConnectionsManager::sendRequest(TLObject *object, onCompleteFunc onComplete, onQuickAckFunc onQuickAck, uint32_t flags, uint32_t datacenterId, ConnectionType connetionType, bool immediate, int32_t requestToken) { +int32_t ConnectionsManager::sendRequest(TLObject *object, onCompleteFunc onComplete, onQuickAckFunc onQuickAck, onRequestClearFunc onClear, uint32_t flags, uint32_t datacenterId, ConnectionType connectionType, bool immediate, int32_t requestToken) { if (requestToken == 0) { requestToken = lastRequestToken++; } - scheduleTask([&, requestToken, object, onComplete, onQuickAck, flags, datacenterId, connetionType, immediate] { - auto request = new Request(instanceNum, requestToken, connetionType, flags, datacenterId, onComplete, onQuickAck, nullptr); + scheduleTask([&, requestToken, object, onComplete, onQuickAck, onClear, flags, datacenterId, connectionType, immediate] { + auto request = new Request(instanceNum, requestToken, connectionType, flags, datacenterId, onComplete, onQuickAck, nullptr, onClear); request->rawRequest = object; request->rpcRequest = wrapInLayer(object, getDatacenterWithId(datacenterId), request); auto cancelledIterator = tokensToBeCancelled.find(request->requestToken); @@ -1835,14 +1876,11 @@ int32_t ConnectionsManager::sendRequest(TLObject *object, onCompleteFunc onCompl } #ifdef ANDROID -void ConnectionsManager::sendRequest(TLObject *object, onCompleteFunc onComplete, onQuickAckFunc onQuickAck, onWriteToSocketFunc onWriteToSocket, uint32_t flags, uint32_t datacenterId, ConnectionType connetionType, bool immediate, int32_t requestToken, jobject ptr1, jobject ptr2, jobject ptr3) { - scheduleTask([&, requestToken, object, onComplete, onQuickAck, onWriteToSocket, flags, datacenterId, connetionType, immediate, ptr1, ptr2, ptr3] { +void ConnectionsManager::sendRequest(TLObject *object, onCompleteFunc onComplete, onQuickAckFunc onQuickAck, onWriteToSocketFunc onWriteToSocket, onRequestClearFunc onClear, uint32_t flags, uint32_t datacenterId, ConnectionType connectionType, bool immediate, int32_t requestToken) { + scheduleTask([&, requestToken, object, onComplete, onQuickAck, onWriteToSocket, onClear, flags, datacenterId, connectionType, immediate] { if (LOGS_ENABLED) DEBUG_D("send request %p - %s", object, typeid(*object).name()); - auto request = new Request(instanceNum, requestToken, connetionType, flags, datacenterId, onComplete, onQuickAck, onWriteToSocket); + auto request = new Request(instanceNum, requestToken, connectionType, flags, datacenterId, onComplete, onQuickAck, onWriteToSocket, onClear); request->rawRequest = object; - request->ptr1 = ptr1; - request->ptr2 = ptr2; - request->ptr3 = ptr3; request->rpcRequest = wrapInLayer(object, getDatacenterWithId(datacenterId), request); if (LOGS_ENABLED) DEBUG_D("send request wrapped %p - %s", request->rpcRequest.get(), typeid(*(request->rpcRequest.get())).name()); auto cancelledIterator = tokensToBeCancelled.find(request->requestToken); @@ -1872,7 +1910,7 @@ void ConnectionsManager::cancelRequestsForGuid(int32_t guid) { std::vector &requests = iter->second; size_t count = requests.size(); for (uint32_t a = 0; a < count; a++) { - cancelRequestInternal(requests[a], 0, true, false); + cancelRequestInternal(requests[a], 0, true, false, nullptr); auto iter2 = guidsByRequests.find(requests[a]); if (iter2 != guidsByRequests.end()) { guidsByRequests.erase(iter2); @@ -1966,7 +2004,7 @@ void ConnectionsManager::removeRequestFromGuid(int32_t requestToken) { } } -bool ConnectionsManager::cancelRequestInternal(int32_t token, int64_t messageId, bool notifyServer, bool removeFromClass) { +bool ConnectionsManager::cancelRequestInternal(int32_t token, int64_t messageId, bool notifyServer, bool removeFromClass, onRequestCancelDoneFunc onCancelled) { if (!tokensToBeCancelled.empty() && (connectionState != ConnectionStateWaitingForNetwork || tokensToBeCancelled.size() > 5000)) { tokensToBeCancelled.clear(); } @@ -1975,7 +2013,8 @@ bool ConnectionsManager::cancelRequestInternal(int32_t token, int64_t messageId, Request *request = iter->get(); if ((token != 0 && request->requestToken == token) || (messageId != 0 && request->respondsToMessageId(messageId))) { request->cancelled = true; - if (LOGS_ENABLED) DEBUG_D("cancelled queued rpc request %p - %s of messageId 0x%" PRIx64, request->rawRequest, typeid(*request->rawRequest).name(), request->messageId); + const char* type = request->rawRequest == nullptr ? "" : typeid(*request->rawRequest).name(); + if (LOGS_ENABLED) DEBUG_D("cancelled queued rpc request %p - %s of messageId 0x%" PRIx64, request->rawRequest, type, request->messageId); requestsQueue.erase(iter); if (removeFromClass) { removeRequestFromGuid(token); @@ -1988,7 +2027,8 @@ bool ConnectionsManager::cancelRequestInternal(int32_t token, int64_t messageId, Request *request = iter->get(); if ((token != 0 && request->requestToken == token) || (messageId != 0 && request->respondsToMessageId(messageId))) { request->cancelled = true; - if (LOGS_ENABLED) DEBUG_D("cancelled waiting login rpc request %p - %s", request->rawRequest, typeid(*request->rawRequest).name()); + const char* type = request->rawRequest == nullptr ? "" : typeid(*request->rawRequest).name(); + if (LOGS_ENABLED) DEBUG_D("cancelled waiting login rpc request %p - %s", request->rawRequest, type); waitingLoginRequests.erase(iter); if (removeFromClass) { removeRequestFromGuid(token); @@ -1999,15 +2039,57 @@ bool ConnectionsManager::cancelRequestInternal(int32_t token, int64_t messageId, for (auto iter = runningRequests.begin(); iter != runningRequests.end(); iter++) { Request *request = iter->get(); + if (request == nullptr) continue; if ((token != 0 && request->requestToken == token) || (messageId != 0 && request->respondsToMessageId(messageId))) { + request->cancelled = true; + bool erase = true; + if ((request->requestFlags & RequestFlagListenAfterCancel) != 0) { + int32_t token = request->requestToken; + auto oldOnCancelled = onCancelled; + if (onCancelled != nullptr) { + request->disableClearCallback = true; + } + onCancelled = [this, oldOnCancelled, token]() -> void { + for (auto iter2 = runningRequests.begin(); iter2 != runningRequests.end(); iter2++) { + Request *request2 = iter2->get(); + if (request2->requestToken == token && !request2->doNotClearOnDrop) { + request2->disableClearCallback = true; + if (LOGS_ENABLED) DEBUG_D("6) erase request %d 0x%" PRIx64, request2->requestToken, request2->messageId); + runningRequests.erase(iter2); + break; + } + } + if (oldOnCancelled != nullptr) { + oldOnCancelled(); + } + }; + erase = false; + } if (notifyServer) { auto dropAnswer = new TL_rpc_drop_answer(); dropAnswer->req_msg_id = request->messageId; - sendRequest(dropAnswer, nullptr, nullptr, RequestFlagEnableUnauthorized | RequestFlagWithoutLogin | RequestFlagFailOnServerErrors | RequestFlagIsCancel, request->datacenterId, request->connectionType, true); + if (onCancelled != nullptr) { + sendRequest(dropAnswer, ([onCancelled](TLObject *response, TL_error *error, int32_t networkType, int64_t responseTime, int64_t msgId) -> void { + if (onCancelled != nullptr) { + onCancelled(); + } + }), nullptr, ([onCancelled]() -> void { + if (onCancelled != nullptr) { + onCancelled(); + } + }), RequestFlagEnableUnauthorized | RequestFlagWithoutLogin | RequestFlagFailOnServerErrors | RequestFlagIsCancel, request->datacenterId, request->connectionType, true); + } else { + sendRequest(dropAnswer, nullptr, nullptr, nullptr, RequestFlagEnableUnauthorized | RequestFlagWithoutLogin | RequestFlagFailOnServerErrors | RequestFlagIsCancel, request->datacenterId, request->connectionType, true); + } + } else if (onCancelled != nullptr) { + onCancelled(); + } + const char* type = request->rawRequest == nullptr ? "" : typeid(*request->rawRequest).name(); + if (LOGS_ENABLED) DEBUG_D("cancelled running rpc request %p - %s, of messageId 0x%" PRIx64 " notify=%d", request->rawRequest, type, request->messageId, notifyServer); + if (erase) { + if (LOGS_ENABLED) DEBUG_D("7) erase request %d 0x%" PRIx64, request->requestToken, request->messageId); + runningRequests.erase(iter); } - request->cancelled = true; - if (LOGS_ENABLED) DEBUG_D("cancelled running rpc request %p - %s, of messageId 0x%" PRIx64, request->rawRequest, typeid(*request->rawRequest).name(), request->messageId); - runningRequests.erase(iter); if (removeFromClass) { removeRequestFromGuid(token); } @@ -2023,12 +2105,12 @@ bool ConnectionsManager::cancelRequestInternal(int32_t token, int64_t messageId, return false; } -void ConnectionsManager::cancelRequest(int32_t token, bool notifyServer) { +void ConnectionsManager::cancelRequest(int32_t token, bool notifyServer, onRequestCancelDoneFunc onCancelled) { if (token == 0) { return; } - scheduleTask([&, token, notifyServer] { - cancelRequestInternal(token, 0, notifyServer, true); + scheduleTask([&, token, notifyServer, onCancelled] { + cancelRequestInternal(token, 0, notifyServer, true, onCancelled); }); } @@ -2170,7 +2252,7 @@ void ConnectionsManager::requestSaltsForDatacenter(Datacenter *datacenter, bool datacenter->mergeServerSalts((TL_future_salts *) response, media); saveConfig(); } - }, nullptr, RequestFlagWithoutLogin | RequestFlagEnableUnauthorized | RequestFlagUseUnboundKey, datacenter->getDatacenterId(), connectionType, true); + }, nullptr, nullptr, RequestFlagWithoutLogin | RequestFlagEnableUnauthorized | RequestFlagUseUnboundKey, datacenter->getDatacenterId(), connectionType, true); } void ConnectionsManager::clearRequestsForDatacenter(Datacenter *datacenter, HandshakeType type) { @@ -2206,7 +2288,7 @@ void ConnectionsManager::registerForInternalPushUpdates() { } saveConfig(); registeringForPush = false; - }, nullptr, 0, DEFAULT_DATACENTER_ID, ConnectionTypeGeneric, true); + }, nullptr, nullptr, 0, DEFAULT_DATACENTER_ID, ConnectionTypeGeneric, true); } @@ -2220,6 +2302,13 @@ inline void addMessageToDatacenter(uint32_t datacenterId, NetworkMessage *networ } } +// since we no longer save 3 global refs per request, can we make request count limits higher? +#define MAX_GENERAL_REQUESTS 60 * 8 +#define MAX_DOWNLOAD_REQUESTS_CANCELS 24 * 2 +#define MAX_DOWNLOAD_REQUESTS_PREMIUM 32 * 2 +#define MAX_DOWNLOAD_REQUESTS 16 * 2 +#define MAX_UPLOAD_REQUESTS 10 * 3 + void ConnectionsManager::processRequestQueue(uint32_t connectionTypes, uint32_t dc) { genericMessagesToDatacenters.clear(); genericMediaMessagesToDatacenters.clear(); @@ -2239,6 +2328,15 @@ void ConnectionsManager::processRequestQueue(uint32_t connectionTypes, uint32_t for (auto iter = runningRequests.begin(); iter != runningRequests.end();) { Request *request = iter->get(); + if (request->cancelled) { + if (request->doNotClearOnDrop && currentTime > request->clearAfter) { + DEBUG_D("16) erase request %d 0x%" PRIx64, request->requestToken, request->messageId); + iter = runningRequests.erase(iter); + } else { + iter++; + } + continue; + } const std::type_info &typeInfo = typeid(*request->rawRequest); uint32_t datacenterId = request->datacenterId; @@ -2296,6 +2394,7 @@ void ConnectionsManager::processRequestQueue(uint32_t connectionTypes, uint32_t if (request->startTime != 0 && abs(currentTime - requestStartTime) >= timeout) { if (LOGS_ENABLED) DEBUG_D("move %s to requestsQueue", typeid(*request->rawRequest).name()); requestsQueue.push_back(std::move(*iter)); + DEBUG_D("10) erase request %d 0x%" PRIx64, request->requestToken, request->messageId); iter = runningRequests.erase(iter); continue; } @@ -2319,6 +2418,7 @@ void ConnectionsManager::processRequestQueue(uint32_t connectionTypes, uint32_t if (request->needInitRequest(requestDatacenter, currentVersion) && !request->hasInitFlag() && request->rawRequest->isNeedLayer()) { if (LOGS_ENABLED) DEBUG_D("move %p - %s to requestsQueue because of initConnection", request->rawRequest, typeid(*request->rawRequest).name()); requestsQueue.push_back(std::move(*iter)); + DEBUG_D("11) erase request %d 0x%" PRIx64, request->requestToken, request->messageId); iter = runningRequests.erase(iter); continue; } @@ -2403,6 +2503,7 @@ void ConnectionsManager::processRequestQueue(uint32_t connectionTypes, uint32_t error->text = "RETRY_LIMIT"; request->onComplete(nullptr, error, connection->currentNetworkType, 0, request->messageId); delete error; + DEBUG_D("12) erase request %d 0x%" PRIx64, request->requestToken, request->messageId); iter = runningRequests.erase(iter); continue; } @@ -2600,7 +2701,7 @@ void ConnectionsManager::processRequestQueue(uint32_t connectionTypes, uint32_t switch (request->connectionType & 0x0000ffff) { case ConnectionTypeGeneric: case ConnectionTypeGenericMedia: - if (!canUseUnboundKey && genericRunningRequestCount >= 60) { + if (!canUseUnboundKey && genericRunningRequestCount >= MAX_GENERAL_REQUESTS) { iter++; if (LOGS_ENABLED) DEBUG_D("skip queue, token = %d: generic type: running generic requests >= 60", request->requestToken); @@ -2625,11 +2726,11 @@ void ConnectionsManager::processRequestQueue(uint32_t connectionTypes, uint32_t } int max; if (request->isCancelRequest()) { - max = 24; + max = MAX_DOWNLOAD_REQUESTS_CANCELS; } else if (currentUserPremium) { - max = 32; + max = MAX_DOWNLOAD_REQUESTS_PREMIUM; } else { - max = 16; + max = MAX_DOWNLOAD_REQUESTS; } if (currentCount >= max) { iter++; @@ -2656,7 +2757,7 @@ void ConnectionsManager::processRequestQueue(uint32_t connectionTypes, uint32_t DEBUG_D("skip queue, token = %d: upload type: network unavailable", request->requestToken); continue; } - if (uploadRunningRequestCount >= 10) { + if (uploadRunningRequestCount >= MAX_UPLOAD_REQUESTS) { iter++; if (LOGS_ENABLED) DEBUG_D("skip queue, token = %d: upload type: running upload requests >= 10", request->requestToken); @@ -3229,7 +3330,7 @@ void ConnectionsManager::updateDcSettings(uint32_t dcNum, bool workaround, bool } else { updatingDcSettings = false; } - }, nullptr, RequestFlagEnableUnauthorized | RequestFlagWithoutLogin | RequestFlagUseUnboundKey | (workaround ? 0 : RequestFlagTryDifferentDc), dcNum == 0 ? currentDatacenterId : dcNum, workaround ? ConnectionTypeTemp : ConnectionTypeGeneric, true); + }, nullptr, nullptr, RequestFlagEnableUnauthorized | RequestFlagWithoutLogin | RequestFlagUseUnboundKey | (workaround ? 0 : RequestFlagTryDifferentDc), dcNum == 0 ? currentDatacenterId : dcNum, workaround ? ConnectionTypeTemp : ConnectionTypeGeneric, true); } void ConnectionsManager::moveToDatacenter(uint32_t datacenterId) { @@ -3268,7 +3369,7 @@ void ConnectionsManager::authorizeOnMovingDatacenter() { } else { moveToDatacenter(movingToDatacenterId); } - }, nullptr, RequestFlagWithoutLogin, datacenter->getDatacenterId(), ConnectionTypeGeneric, true); + }, nullptr, nullptr, RequestFlagWithoutLogin, datacenter->getDatacenterId(), ConnectionTypeGeneric, true); } else { authorizedOnMovingDatacenter(); } @@ -3692,7 +3793,7 @@ void ConnectionsManager::checkProxyInternal(ProxyCheckInfo *proxyCheckInfo) { proxyCheckInfo->connectionNum = freeConnectionNum; auto request = new TL_ping(); request->ping_id = proxyCheckInfo->pingId; - proxyCheckInfo->requestToken = sendRequest(request, nullptr, nullptr, RequestFlagEnableUnauthorized | RequestFlagWithoutLogin, DEFAULT_DATACENTER_ID, connectionType, true, 0); + proxyCheckInfo->requestToken = sendRequest(request, nullptr, nullptr, nullptr, RequestFlagEnableUnauthorized | RequestFlagWithoutLogin, DEFAULT_DATACENTER_ID, connectionType, true, 0); proxyActiveChecks.push_back(std::unique_ptr(proxyCheckInfo)); } else if (PFS_ENABLED) { if (datacenter->isHandshaking(false)) { @@ -3735,7 +3836,7 @@ void ConnectionsManager::reconnect(int32_t dcId, int32_t connectionType) { Connection *connection = datacenter->getConnectionByType(connectionType, false, 0); if (connection != nullptr) { - DEBUG_D("discard connection dcId=%d connectionType=%d", dcId, + if (LOGS_ENABLED) DEBUG_D("discard connection dcId=%d connectionType=%d", dcId, connectionType); connection->suspendConnection(true); } diff --git a/TMessagesProj/jni/tgnet/ConnectionsManager.h b/TMessagesProj/jni/tgnet/ConnectionsManager.h index 7ab328353de..0302988b117 100644 --- a/TMessagesProj/jni/tgnet/ConnectionsManager.h +++ b/TMessagesProj/jni/tgnet/ConnectionsManager.h @@ -49,9 +49,9 @@ class ConnectionsManager { uint32_t getCurrentDatacenterId(); bool isTestBackend(); int32_t getTimeDifference(); - int32_t sendRequest(TLObject *object, onCompleteFunc onComplete, onQuickAckFunc onQuickAck, uint32_t flags, uint32_t datacenterId, ConnectionType connetionType, bool immediate); - int32_t sendRequest(TLObject *object, onCompleteFunc onComplete, onQuickAckFunc onQuickAck, uint32_t flags, uint32_t datacenterId, ConnectionType connetionType, bool immediate, int32_t requestToken); - void cancelRequest(int32_t token, bool notifyServer); + int32_t sendRequest(TLObject *object, onCompleteFunc onComplete, onQuickAckFunc onQuickAck, onRequestClearFunc onClear, uint32_t flags, uint32_t datacenterId, ConnectionType connectionType, bool immediate); + int32_t sendRequest(TLObject *object, onCompleteFunc onComplete, onQuickAckFunc onQuickAck, onRequestClearFunc onClear, uint32_t flags, uint32_t datacenterId, ConnectionType connectionType, bool immediate, int32_t requestToken); + void cancelRequest(int32_t token, bool notifyServer, onRequestCancelDoneFunc onCancelled); void cleanUp(bool resetKeys, int32_t datacenterId); void cancelRequestsForGuid(int32_t guid); void bindRequestToGuid(int32_t requestToken, int32_t guid); @@ -76,7 +76,7 @@ class ConnectionsManager { int64_t checkProxy(std::string address, uint16_t port, std::string username, std::string password, std::string secret, onRequestTimeFunc requestTimeFunc, jobject ptr1); #ifdef ANDROID - void sendRequest(TLObject *object, onCompleteFunc onComplete, onQuickAckFunc onQuickAck, onWriteToSocketFunc onWriteToSocket, uint32_t flags, uint32_t datacenterId, ConnectionType connetionType, bool immediate, int32_t requestToken, jobject ptr1, jobject ptr2, jobject ptr3); + void sendRequest(TLObject *object, onCompleteFunc onComplete, onQuickAckFunc onQuickAck, onWriteToSocketFunc onWriteToSocket, onRequestClearFunc onClear, uint32_t flags, uint32_t datacenterId, ConnectionType connectionType, bool immediate, int32_t requestToken); static void useJavaVM(JavaVM *vm, bool useJavaByteBuffers); #endif @@ -106,9 +106,9 @@ class ConnectionsManager { Datacenter *getDatacenterWithId(uint32_t datacenterId); std::unique_ptr wrapInLayer(TLObject *object, Datacenter *datacenter, Request *baseRequest); void removeRequestFromGuid(int32_t requestToken); - bool cancelRequestInternal(int32_t token, int64_t messageId, bool notifyServer, bool removeFromClass); + bool cancelRequestInternal(int32_t token, int64_t messageId, bool notifyServer, bool removeFromClass, onRequestCancelDoneFunc onCancelled); int callEvents(int64_t now); - int32_t sendRequestInternal(TLObject *object, onCompleteFunc onComplete, onQuickAckFunc onQuickAck, uint32_t flags, uint32_t datacenterId, ConnectionType connetionType, bool immediate); + int32_t sendRequestInternal(TLObject *object, onCompleteFunc onComplete, onQuickAckFunc onQuickAck, onRequestClearFunc onClear, uint32_t flags, uint32_t datacenterId, ConnectionType connetionType, bool immediate); void checkPendingTasks(); void scheduleTask(std::function task); diff --git a/TMessagesProj/jni/tgnet/Datacenter.cpp b/TMessagesProj/jni/tgnet/Datacenter.cpp index 89979cd46f8..18500428f9a 100644 --- a/TMessagesProj/jni/tgnet/Datacenter.cpp +++ b/TMessagesProj/jni/tgnet/Datacenter.cpp @@ -1450,12 +1450,12 @@ void Datacenter::exportAuthorization() { if (LOGS_ENABLED) DEBUG_D("dc%u failed import authorization", datacenterId); } exportingAuthorization = false; - }, nullptr, RequestFlagEnableUnauthorized | RequestFlagWithoutLogin, datacenterId, ConnectionTypeGeneric, true); + }, nullptr, nullptr, RequestFlagEnableUnauthorized | RequestFlagWithoutLogin, datacenterId, ConnectionTypeGeneric, true); } else { if (LOGS_ENABLED) DEBUG_D("dc%u failed export authorization", datacenterId); exportingAuthorization = false; } - }, nullptr, 0, DEFAULT_DATACENTER_ID, ConnectionTypeGeneric, true); + }, nullptr, nullptr, 0, DEFAULT_DATACENTER_ID, ConnectionTypeGeneric, true); } bool Datacenter::isExportingAuthorization() { diff --git a/TMessagesProj/jni/tgnet/Defines.h b/TMessagesProj/jni/tgnet/Defines.h index 91205e6b3ef..d2255212dba 100644 --- a/TMessagesProj/jni/tgnet/Defines.h +++ b/TMessagesProj/jni/tgnet/Defines.h @@ -50,6 +50,8 @@ class ConnectionSocket; typedef std::function onCompleteFunc; typedef std::function onQuickAckFunc; typedef std::function onWriteToSocketFunc; +typedef std::function onRequestClearFunc; +typedef std::function onRequestCancelDoneFunc; typedef std::function fillParamsFunc; typedef std::function onRequestTimeFunc; typedef std::list> requestsList; @@ -171,6 +173,7 @@ enum RequestFlag { RequestFlagUseUnboundKey = 256, RequestFlagResendAfter = 512, RequestFlagIgnoreFloodWait = 1024, + RequestFlagListenAfterCancel = 2048, RequestFlagIsCancel = 32768 }; diff --git a/TMessagesProj/jni/tgnet/Handshake.cpp b/TMessagesProj/jni/tgnet/Handshake.cpp index 88d842dfc65..3a0700ba40b 100644 --- a/TMessagesProj/jni/tgnet/Handshake.cpp +++ b/TMessagesProj/jni/tgnet/Handshake.cpp @@ -94,7 +94,7 @@ void Handshake::cleanupHandshake() { authKeyTempPending = nullptr; } if (authKeyPendingMessageId != 0 || authKeyPendingRequestId != 0) { - ConnectionsManager::getInstance(currentDatacenter->instanceNum).cancelRequestInternal(authKeyPendingRequestId, authKeyPendingMessageId, false, false); + ConnectionsManager::getInstance(currentDatacenter->instanceNum).cancelRequestInternal(authKeyPendingRequestId, authKeyPendingMessageId, false, false, nullptr); authKeyPendingMessageId = 0; authKeyPendingRequestId = 0; } @@ -327,575 +327,589 @@ void Handshake::processHandshakeResponse(TLObject *message, int64_t messageId) { } const std::type_info &typeInfo = typeid(*message); if (typeInfo == typeid(TL_resPQ)) { - if (handshakeState != 1) { - sendAckRequest(messageId); - return; - } + processHandshakeResponse_resPQ(message, messageId); + } else if (dynamic_cast(message)) { + processHandshakeResponse_serverDHParams(message, messageId); + } else if (dynamic_cast(message)) { + processHandshakeResponse_serverDHParamsAnswer(message, messageId); + } +} - handshakeState = 2; - auto result = (TL_resPQ *) message; - if (authNonce->isEqualTo(result->nonce.get())) { - std::string key = ""; - int64_t keyFingerprint = 0; +void Handshake::processHandshakeResponse_resPQ(TLObject *message, int64_t messageId) { + if (handshakeState != 1) { + sendAckRequest(messageId); + return; + } - size_t count1 = result->server_public_key_fingerprints.size(); - if (currentDatacenter->isCdnDatacenter) { - auto iter = cdnPublicKeysFingerprints.find(currentDatacenter->datacenterId); - if (iter != cdnPublicKeysFingerprints.end()) { - for (uint32_t a = 0; a < count1; a++) { - if ((uint64_t) result->server_public_key_fingerprints[a] == iter->second) { - keyFingerprint = iter->second; - key = cdnPublicKeys[currentDatacenter->datacenterId]; - } + handshakeState = 2; + auto result = (TL_resPQ *) message; + if (authNonce->isEqualTo(result->nonce.get())) { + std::string key = ""; + int64_t keyFingerprint = 0; + + size_t count1 = result->server_public_key_fingerprints.size(); + if (currentDatacenter->isCdnDatacenter) { + auto iter = cdnPublicKeysFingerprints.find(currentDatacenter->datacenterId); + if (iter != cdnPublicKeysFingerprints.end()) { + for (uint32_t a = 0; a < count1; a++) { + if ((uint64_t) result->server_public_key_fingerprints[a] == iter->second) { + keyFingerprint = iter->second; + key = cdnPublicKeys[currentDatacenter->datacenterId]; } } - } else { - if (serverPublicKeys.empty()) { - if (ConnectionsManager::getInstance(currentDatacenter->instanceNum).testBackend) { - serverPublicKeys.emplace_back("-----BEGIN RSA PUBLIC KEY-----\n" - "MIIBCgKCAQEAyMEdY1aR+sCR3ZSJrtztKTKqigvO/vBfqACJLZtS7QMgCGXJ6XIR\n" - "yy7mx66W0/sOFa7/1mAZtEoIokDP3ShoqF4fVNb6XeqgQfaUHd8wJpDWHcR2OFwv\n" - "plUUI1PLTktZ9uW2WE23b+ixNwJjJGwBDJPQEQFBE+vfmH0JP503wr5INS1poWg/\n" - "j25sIWeYPHYeOrFp/eXaqhISP6G+q2IeTaWTXpwZj4LzXq5YOpk4bYEQ6mvRq7D1\n" - "aHWfYmlEGepfaYR8Q0YqvvhYtMte3ITnuSJs171+GDqpdKcSwHnd6FudwGO4pcCO\n" - "j4WcDuXc2CTHgH8gFTNhp/Y8/SpDOhvn9QIDAQAB\n" - "-----END RSA PUBLIC KEY-----"); - serverPublicKeysFingerprints.push_back(0xb25898df208d2603); - } else { - serverPublicKeys.emplace_back("-----BEGIN RSA PUBLIC KEY-----\n" - "MIIBCgKCAQEA6LszBcC1LGzyr992NzE0ieY+BSaOW622Aa9Bd4ZHLl+TuFQ4lo4g\n" - "5nKaMBwK/BIb9xUfg0Q29/2mgIR6Zr9krM7HjuIcCzFvDtr+L0GQjae9H0pRB2OO\n" - "62cECs5HKhT5DZ98K33vmWiLowc621dQuwKWSQKjWf50XYFw42h21P2KXUGyp2y/\n" - "+aEyZ+uVgLLQbRA1dEjSDZ2iGRy12Mk5gpYc397aYp438fsJoHIgJ2lgMv5h7WY9\n" - "t6N/byY9Nw9p21Og3AoXSL2q/2IJ1WRUhebgAdGVMlV1fkuOQoEzR7EdpqtQD9Cs\n" - "5+bfo3Nhmcyvk5ftB0WkJ9z6bNZ7yxrP8wIDAQAB\n" - "-----END RSA PUBLIC KEY-----"); - serverPublicKeysFingerprints.push_back(0xd09d1d85de64fd85); - } + } + } else { + if (serverPublicKeys.empty()) { + if (ConnectionsManager::getInstance(currentDatacenter->instanceNum).testBackend) { + serverPublicKeys.emplace_back("-----BEGIN RSA PUBLIC KEY-----\n" + "MIIBCgKCAQEAyMEdY1aR+sCR3ZSJrtztKTKqigvO/vBfqACJLZtS7QMgCGXJ6XIR\n" + "yy7mx66W0/sOFa7/1mAZtEoIokDP3ShoqF4fVNb6XeqgQfaUHd8wJpDWHcR2OFwv\n" + "plUUI1PLTktZ9uW2WE23b+ixNwJjJGwBDJPQEQFBE+vfmH0JP503wr5INS1poWg/\n" + "j25sIWeYPHYeOrFp/eXaqhISP6G+q2IeTaWTXpwZj4LzXq5YOpk4bYEQ6mvRq7D1\n" + "aHWfYmlEGepfaYR8Q0YqvvhYtMte3ITnuSJs171+GDqpdKcSwHnd6FudwGO4pcCO\n" + "j4WcDuXc2CTHgH8gFTNhp/Y8/SpDOhvn9QIDAQAB\n" + "-----END RSA PUBLIC KEY-----"); + serverPublicKeysFingerprints.push_back(0xb25898df208d2603); + } else { + serverPublicKeys.emplace_back("-----BEGIN RSA PUBLIC KEY-----\n" + "MIIBCgKCAQEA6LszBcC1LGzyr992NzE0ieY+BSaOW622Aa9Bd4ZHLl+TuFQ4lo4g\n" + "5nKaMBwK/BIb9xUfg0Q29/2mgIR6Zr9krM7HjuIcCzFvDtr+L0GQjae9H0pRB2OO\n" + "62cECs5HKhT5DZ98K33vmWiLowc621dQuwKWSQKjWf50XYFw42h21P2KXUGyp2y/\n" + "+aEyZ+uVgLLQbRA1dEjSDZ2iGRy12Mk5gpYc397aYp438fsJoHIgJ2lgMv5h7WY9\n" + "t6N/byY9Nw9p21Og3AoXSL2q/2IJ1WRUhebgAdGVMlV1fkuOQoEzR7EdpqtQD9Cs\n" + "5+bfo3Nhmcyvk5ftB0WkJ9z6bNZ7yxrP8wIDAQAB\n" + "-----END RSA PUBLIC KEY-----"); + serverPublicKeysFingerprints.push_back(0xd09d1d85de64fd85); } + } - size_t count2 = serverPublicKeysFingerprints.size(); - for (uint32_t a = 0; a < count1; a++) { - for (uint32_t b = 0; b < count2; b++) { - if ((uint64_t) result->server_public_key_fingerprints[a] == serverPublicKeysFingerprints[b]) { - keyFingerprint = result->server_public_key_fingerprints[a]; - key = serverPublicKeys[b]; - break; - } - } - if (keyFingerprint != 0) { + size_t count2 = serverPublicKeysFingerprints.size(); + for (uint32_t a = 0; a < count1; a++) { + for (uint32_t b = 0; b < count2; b++) { + if ((uint64_t) result->server_public_key_fingerprints[a] == serverPublicKeysFingerprints[b]) { + keyFingerprint = result->server_public_key_fingerprints[a]; + key = serverPublicKeys[b]; break; } } - } - - if (keyFingerprint == 0) { - if (currentDatacenter->isCdnDatacenter) { - if (LOGS_ENABLED) DEBUG_D("account%u dc%u handshake: can't find valid cdn server public key, type = %d", currentDatacenter->instanceNum, currentDatacenter->datacenterId, handshakeType); - loadCdnConfig(currentDatacenter); - } else { - if (LOGS_ENABLED) DEBUG_E("account%u dc%u handshake: can't find valid server public key, type = %d", currentDatacenter->instanceNum, currentDatacenter->datacenterId, handshakeType); - beginHandshake(false); + if (keyFingerprint != 0) { + break; } - return; } + } - authServerNonce = new ByteArray(result->server_nonce.get()); - - uint64_t pq = ((uint64_t) (result->pq->bytes[0] & 0xff) << 56) | - ((uint64_t) (result->pq->bytes[1] & 0xff) << 48) | - ((uint64_t) (result->pq->bytes[2] & 0xff) << 40) | - ((uint64_t) (result->pq->bytes[3] & 0xff) << 32) | - ((uint64_t) (result->pq->bytes[4] & 0xff) << 24) | - ((uint64_t) (result->pq->bytes[5] & 0xff) << 16) | - ((uint64_t) (result->pq->bytes[6] & 0xff) << 8) | - ((uint64_t) (result->pq->bytes[7] & 0xff)); - uint32_t p, q; - if (!factorizeValue(pq, p, q)) { + if (keyFingerprint == 0) { + if (currentDatacenter->isCdnDatacenter) { + if (LOGS_ENABLED) DEBUG_D("account%u dc%u handshake: can't find valid cdn server public key, type = %d", currentDatacenter->instanceNum, currentDatacenter->datacenterId, handshakeType); + loadCdnConfig(currentDatacenter); + } else { + if (LOGS_ENABLED) DEBUG_E("account%u dc%u handshake: can't find valid server public key, type = %d", currentDatacenter->instanceNum, currentDatacenter->datacenterId, handshakeType); beginHandshake(false); - return; } + return; + } - auto request = new TL_req_DH_params(); - request->nonce = std::make_unique(new ByteArray(authNonce)); - request->server_nonce = std::make_unique(new ByteArray(authServerNonce)); - request->p = std::make_unique(new ByteArray(4)); - request->p->bytes[3] = (uint8_t) p; - request->p->bytes[2] = (uint8_t) (p >> 8); - request->p->bytes[1] = (uint8_t) (p >> 16); - request->p->bytes[0] = (uint8_t) (p >> 24); - request->q = std::make_unique(new ByteArray(4)); - request->q->bytes[3] = (uint8_t) q; - request->q->bytes[2] = (uint8_t) (q >> 8); - request->q->bytes[1] = (uint8_t) (q >> 16); - request->q->bytes[0] = (uint8_t) (q >> 24); - request->public_key_fingerprint = keyFingerprint; - - TLObject *innerData; - if (handshakeType == HandshakeTypePerm) { - auto tl_p_q_inner_data = new TL_p_q_inner_data_dc(); - tl_p_q_inner_data->nonce = std::make_unique(authNonce); - tl_p_q_inner_data->server_nonce = std::make_unique(authServerNonce); - tl_p_q_inner_data->pq = std::make_unique(new ByteArray(result->pq.get())); - tl_p_q_inner_data->p = std::make_unique(new ByteArray(request->p.get())); - tl_p_q_inner_data->q = std::make_unique(new ByteArray(request->q.get())); - tl_p_q_inner_data->new_nonce = std::make_unique(new ByteArray(32)); + authServerNonce = new ByteArray(result->server_nonce.get()); + + uint64_t pq = ((uint64_t) (result->pq->bytes[0] & 0xff) << 56) | + ((uint64_t) (result->pq->bytes[1] & 0xff) << 48) | + ((uint64_t) (result->pq->bytes[2] & 0xff) << 40) | + ((uint64_t) (result->pq->bytes[3] & 0xff) << 32) | + ((uint64_t) (result->pq->bytes[4] & 0xff) << 24) | + ((uint64_t) (result->pq->bytes[5] & 0xff) << 16) | + ((uint64_t) (result->pq->bytes[6] & 0xff) << 8) | + ((uint64_t) (result->pq->bytes[7] & 0xff)); + uint32_t p, q; + if (!factorizeValue(pq, p, q)) { + beginHandshake(false); + return; + } + + auto request = new TL_req_DH_params(); + request->nonce = std::make_unique(new ByteArray(authNonce)); + request->server_nonce = std::make_unique(new ByteArray(authServerNonce)); + request->p = std::make_unique(new ByteArray(4)); + request->p->bytes[3] = (uint8_t) p; + request->p->bytes[2] = (uint8_t) (p >> 8); + request->p->bytes[1] = (uint8_t) (p >> 16); + request->p->bytes[0] = (uint8_t) (p >> 24); + request->q = std::make_unique(new ByteArray(4)); + request->q->bytes[3] = (uint8_t) q; + request->q->bytes[2] = (uint8_t) (q >> 8); + request->q->bytes[1] = (uint8_t) (q >> 16); + request->q->bytes[0] = (uint8_t) (q >> 24); + request->public_key_fingerprint = keyFingerprint; + + TLObject *innerData; + if (handshakeType == HandshakeTypePerm) { + auto tl_p_q_inner_data = new TL_p_q_inner_data_dc(); + tl_p_q_inner_data->nonce = std::make_unique(authNonce); + tl_p_q_inner_data->server_nonce = std::make_unique(authServerNonce); + tl_p_q_inner_data->pq = std::make_unique(new ByteArray(result->pq.get())); + tl_p_q_inner_data->p = std::make_unique(new ByteArray(request->p.get())); + tl_p_q_inner_data->q = std::make_unique(new ByteArray(request->q.get())); + tl_p_q_inner_data->new_nonce = std::make_unique(new ByteArray(32)); + if (ConnectionsManager::getInstance(currentDatacenter->instanceNum).testBackend) { + tl_p_q_inner_data->dc = 10000 + currentDatacenter->datacenterId; + } else { + tl_p_q_inner_data->dc = currentDatacenter->datacenterId; + } + RAND_bytes(tl_p_q_inner_data->new_nonce->bytes, 32); + authNewNonce = new ByteArray(tl_p_q_inner_data->new_nonce.get()); + innerData = tl_p_q_inner_data; + } else { + auto tl_p_q_inner_data_temp = new TL_p_q_inner_data_temp_dc(); + tl_p_q_inner_data_temp->nonce = std::make_unique(new ByteArray(authNonce)); + tl_p_q_inner_data_temp->server_nonce = std::make_unique(new ByteArray(authServerNonce)); + tl_p_q_inner_data_temp->pq = std::make_unique(new ByteArray(result->pq.get())); + tl_p_q_inner_data_temp->p = std::make_unique(new ByteArray(request->p.get())); + tl_p_q_inner_data_temp->q = std::make_unique(new ByteArray(request->q.get())); + tl_p_q_inner_data_temp->new_nonce = std::make_unique(new ByteArray(32)); + if (handshakeType == HandshakeTypeMediaTemp) { if (ConnectionsManager::getInstance(currentDatacenter->instanceNum).testBackend) { - tl_p_q_inner_data->dc = 10000 + currentDatacenter->datacenterId; + tl_p_q_inner_data_temp->dc = -(10000 + currentDatacenter->datacenterId); } else { - tl_p_q_inner_data->dc = currentDatacenter->datacenterId; + tl_p_q_inner_data_temp->dc = -currentDatacenter->datacenterId; } - RAND_bytes(tl_p_q_inner_data->new_nonce->bytes, 32); - authNewNonce = new ByteArray(tl_p_q_inner_data->new_nonce.get()); - innerData = tl_p_q_inner_data; } else { - auto tl_p_q_inner_data_temp = new TL_p_q_inner_data_temp_dc(); - tl_p_q_inner_data_temp->nonce = std::make_unique(new ByteArray(authNonce)); - tl_p_q_inner_data_temp->server_nonce = std::make_unique(new ByteArray(authServerNonce)); - tl_p_q_inner_data_temp->pq = std::make_unique(new ByteArray(result->pq.get())); - tl_p_q_inner_data_temp->p = std::make_unique(new ByteArray(request->p.get())); - tl_p_q_inner_data_temp->q = std::make_unique(new ByteArray(request->q.get())); - tl_p_q_inner_data_temp->new_nonce = std::make_unique(new ByteArray(32)); - if (handshakeType == HandshakeTypeMediaTemp) { - if (ConnectionsManager::getInstance(currentDatacenter->instanceNum).testBackend) { - tl_p_q_inner_data_temp->dc = -(10000 + currentDatacenter->datacenterId); - } else { - tl_p_q_inner_data_temp->dc = -currentDatacenter->datacenterId; - } + if (ConnectionsManager::getInstance(currentDatacenter->instanceNum).testBackend) { + tl_p_q_inner_data_temp->dc = 10000 + currentDatacenter->datacenterId; } else { - if (ConnectionsManager::getInstance(currentDatacenter->instanceNum).testBackend) { - tl_p_q_inner_data_temp->dc = 10000 + currentDatacenter->datacenterId; - } else { - tl_p_q_inner_data_temp->dc = currentDatacenter->datacenterId; - } + tl_p_q_inner_data_temp->dc = currentDatacenter->datacenterId; } - tl_p_q_inner_data_temp->expires_in = TEMP_AUTH_KEY_EXPIRE_TIME; - RAND_bytes(tl_p_q_inner_data_temp->new_nonce->bytes, 32); - authNewNonce = new ByteArray(tl_p_q_inner_data_temp->new_nonce.get()); - innerData = tl_p_q_inner_data_temp; } + tl_p_q_inner_data_temp->expires_in = TEMP_AUTH_KEY_EXPIRE_TIME; + RAND_bytes(tl_p_q_inner_data_temp->new_nonce->bytes, 32); + authNewNonce = new ByteArray(tl_p_q_inner_data_temp->new_nonce.get()); + innerData = tl_p_q_inner_data_temp; + } - uint32_t innerDataSize = innerData->getObjectSize(); - if (innerDataSize > 144) { - if (LOGS_ENABLED) DEBUG_E("account%u dc%u handshake: inner data too large %d, type = %d", currentDatacenter->instanceNum, currentDatacenter->datacenterId, innerDataSize, handshakeType); - delete innerData; - beginHandshake(false); - return; - } - uint32_t keySize = 32; - uint32_t ivSize = 32; - uint32_t paddedDataSize = 192; - uint32_t encryptedDataSize = keySize + paddedDataSize + SHA256_DIGEST_LENGTH; - uint32_t additionalSize = innerDataSize < paddedDataSize ? paddedDataSize - innerDataSize : 0; - NativeByteBuffer *innerDataBuffer = BuffersStorage::getInstance().getFreeBuffer(encryptedDataSize + paddedDataSize + ivSize + SHA256_DIGEST_LENGTH + 256); - - innerDataBuffer->position(encryptedDataSize); - innerData->serializeToStream(innerDataBuffer); + uint32_t innerDataSize = innerData->getObjectSize(); + if (innerDataSize > 144) { + if (LOGS_ENABLED) DEBUG_E("account%u dc%u handshake: inner data too large %d, type = %d", currentDatacenter->instanceNum, currentDatacenter->datacenterId, innerDataSize, handshakeType); delete innerData; + beginHandshake(false); + return; + } + uint32_t keySize = 32; + uint32_t ivSize = 32; + uint32_t paddedDataSize = 192; + uint32_t encryptedDataSize = keySize + paddedDataSize + SHA256_DIGEST_LENGTH; + uint32_t additionalSize = innerDataSize < paddedDataSize ? paddedDataSize - innerDataSize : 0; + NativeByteBuffer *innerDataBuffer = BuffersStorage::getInstance().getFreeBuffer(encryptedDataSize + paddedDataSize + ivSize + SHA256_DIGEST_LENGTH + 256); + + innerDataBuffer->position(encryptedDataSize); + innerData->serializeToStream(innerDataBuffer); + delete innerData; + + BIO *keyBio = BIO_new(BIO_s_mem()); + BIO_write(keyBio, key.c_str(), (int) key.length()); + RSA *rsaKey = PEM_read_bio_RSAPublicKey(keyBio, nullptr, nullptr, nullptr); + BIO_free(keyBio); + + while (true) { + RAND_bytes(innerDataBuffer->bytes() + encryptedDataSize + innerDataSize, additionalSize); + for (uint32_t i = 0; i < paddedDataSize; i++) { + innerDataBuffer->bytes()[keySize + i] = innerDataBuffer->bytes()[encryptedDataSize + paddedDataSize - i - 1]; + } - BIO *keyBio = BIO_new(BIO_s_mem()); - BIO_write(keyBio, key.c_str(), (int) key.length()); - RSA *rsaKey = PEM_read_bio_RSAPublicKey(keyBio, nullptr, nullptr, nullptr); - BIO_free(keyBio); - - while (true) { - RAND_bytes(innerDataBuffer->bytes() + encryptedDataSize + innerDataSize, additionalSize); - for (uint32_t i = 0; i < paddedDataSize; i++) { - innerDataBuffer->bytes()[keySize + i] = innerDataBuffer->bytes()[encryptedDataSize + paddedDataSize - i - 1]; - } - - RAND_bytes(innerDataBuffer->bytes(), keySize); - SHA256_CTX sha256Ctx; - SHA256_Init(&sha256Ctx); - SHA256_Update(&sha256Ctx, innerDataBuffer->bytes(), keySize); - SHA256_Update(&sha256Ctx, innerDataBuffer->bytes() + encryptedDataSize, paddedDataSize); - SHA256_Final(innerDataBuffer->bytes() + keySize + paddedDataSize, &sha256Ctx); + RAND_bytes(innerDataBuffer->bytes(), keySize); + SHA256_CTX sha256Ctx; + SHA256_Init(&sha256Ctx); + SHA256_Update(&sha256Ctx, innerDataBuffer->bytes(), keySize); + SHA256_Update(&sha256Ctx, innerDataBuffer->bytes() + encryptedDataSize, paddedDataSize); + SHA256_Final(innerDataBuffer->bytes() + keySize + paddedDataSize, &sha256Ctx); - memset(innerDataBuffer->bytes() + encryptedDataSize + paddedDataSize, 0, ivSize); - Datacenter::aesIgeEncryption(innerDataBuffer->bytes() + keySize, innerDataBuffer->bytes(), innerDataBuffer->bytes() + encryptedDataSize + paddedDataSize, true, true, paddedDataSize + SHA256_DIGEST_LENGTH); + memset(innerDataBuffer->bytes() + encryptedDataSize + paddedDataSize, 0, ivSize); + Datacenter::aesIgeEncryption(innerDataBuffer->bytes() + keySize, innerDataBuffer->bytes(), innerDataBuffer->bytes() + encryptedDataSize + paddedDataSize, true, true, paddedDataSize + SHA256_DIGEST_LENGTH); - SHA256_Init(&sha256Ctx); - SHA256_Update(&sha256Ctx, innerDataBuffer->bytes() + keySize, paddedDataSize + SHA256_DIGEST_LENGTH); - SHA256_Final(innerDataBuffer->bytes() + encryptedDataSize + paddedDataSize + ivSize, &sha256Ctx); + SHA256_Init(&sha256Ctx); + SHA256_Update(&sha256Ctx, innerDataBuffer->bytes() + keySize, paddedDataSize + SHA256_DIGEST_LENGTH); + SHA256_Final(innerDataBuffer->bytes() + encryptedDataSize + paddedDataSize + ivSize, &sha256Ctx); - for (uint32_t i = 0; i < keySize; i++) { - innerDataBuffer->bytes()[i] ^= innerDataBuffer->bytes()[encryptedDataSize + paddedDataSize + ivSize + i]; - } + for (uint32_t i = 0; i < keySize; i++) { + innerDataBuffer->bytes()[i] ^= innerDataBuffer->bytes()[encryptedDataSize + paddedDataSize + ivSize + i]; + } - bool ok = false; - uint32_t offset = encryptedDataSize + paddedDataSize + ivSize + SHA256_DIGEST_LENGTH; - size_t resLen = BN_bn2bin(rsaKey->n, innerDataBuffer->bytes() + offset); - const auto shift = (256 - resLen); + bool ok = false; + uint32_t offset = encryptedDataSize + paddedDataSize + ivSize + SHA256_DIGEST_LENGTH; + size_t resLen = BN_bn2bin(rsaKey->n, innerDataBuffer->bytes() + offset); + const auto shift = (256 - resLen); - for (auto i = 0; i != 256; ++i) { - const auto a = innerDataBuffer->bytes()[i]; - const auto b = (i < shift) ? 0 : innerDataBuffer->bytes()[offset + i - shift]; - if (a > b) { - break; - } else if (a < b) { - ok = true; - break; - } - } - if (ok) { + for (auto i = 0; i != 256; ++i) { + const auto a = innerDataBuffer->bytes()[i]; + const auto b = (i < shift) ? 0 : innerDataBuffer->bytes()[offset + i - shift]; + if (a > b) { + break; + } else if (a < b) { + ok = true; break; } } - - if (bnContext == nullptr) { - bnContext = BN_CTX_new(); - } - BIGNUM *a = BN_bin2bn(innerDataBuffer->bytes(), encryptedDataSize, nullptr); - BIGNUM *r = BN_new(); - BN_mod_exp(r, a, rsaKey->e, rsaKey->n, bnContext); - uint32_t size = BN_num_bytes(r); - auto rsaEncryptedData = new ByteArray(size >= 256 ? size : 256); - BN_bn2bin(r, rsaEncryptedData->bytes + (size < 256 ? (256 - size) : 0)); - if (256 - size > 0) { - memset(rsaEncryptedData->bytes, 0, 256 - size); + if (ok) { + break; } - BN_free(a); - BN_free(r); - RSA_free(rsaKey); - innerDataBuffer->reuse(); - - request->encrypted_data = std::unique_ptr(rsaEncryptedData); + } - sendAckRequest(messageId); - sendRequestData(request, true); - } else { - if (LOGS_ENABLED) DEBUG_E("account%u dc%u handshake: invalid client nonce, type = %d", currentDatacenter->instanceNum, currentDatacenter->datacenterId, handshakeType); - beginHandshake(false); + if (bnContext == nullptr) { + bnContext = BN_CTX_new(); } - } else if (dynamic_cast(message)) { - if (typeInfo == typeid(TL_server_DH_params_ok)) { - if (handshakeState != 2) { - sendAckRequest(messageId); - return; - } + BIGNUM *a = BN_bin2bn(innerDataBuffer->bytes(), encryptedDataSize, nullptr); + BIGNUM *r = BN_new(); + BN_mod_exp(r, a, rsaKey->e, rsaKey->n, bnContext); + uint32_t size = BN_num_bytes(r); + auto rsaEncryptedData = new ByteArray(size >= 256 ? size : 256); + BN_bn2bin(r, rsaEncryptedData->bytes + (size < 256 ? (256 - size) : 0)); + if (256 - size > 0) { + memset(rsaEncryptedData->bytes, 0, 256 - size); + } + BN_free(a); + BN_free(r); + RSA_free(rsaKey); + innerDataBuffer->reuse(); - handshakeState = 3; + request->encrypted_data = std::unique_ptr(rsaEncryptedData); - TL_server_DH_params_ok *result = (TL_server_DH_params_ok *) message; + sendAckRequest(messageId); + sendRequestData(request, true); + } else { + if (LOGS_ENABLED) DEBUG_E("account%u dc%u handshake: invalid client nonce, type = %d", currentDatacenter->instanceNum, currentDatacenter->datacenterId, handshakeType); + beginHandshake(false); + } +} - NativeByteBuffer *tmpAesKeyAndIv = BuffersStorage::getInstance().getFreeBuffer(84); +void Handshake::processHandshakeResponse_serverDHParams(TLObject *message, int64_t messageId) { + const std::type_info &typeInfo = typeid(*message); + if (typeInfo == typeid(TL_server_DH_params_ok)) { + if (handshakeState != 2) { + sendAckRequest(messageId); + return; + } - NativeByteBuffer *newNonceAndServerNonce = BuffersStorage::getInstance().getFreeBuffer(authNewNonce->length + authServerNonce->length); - newNonceAndServerNonce->writeBytes(authNewNonce); - newNonceAndServerNonce->writeBytes(authServerNonce); - SHA1(newNonceAndServerNonce->bytes(), newNonceAndServerNonce->limit(), tmpAesKeyAndIv->bytes()); - newNonceAndServerNonce->reuse(); + handshakeState = 3; - NativeByteBuffer *serverNonceAndNewNonce = BuffersStorage::getInstance().getFreeBuffer(authServerNonce->length + authNewNonce->length); - serverNonceAndNewNonce->writeBytes(authServerNonce); - serverNonceAndNewNonce->writeBytes(authNewNonce); - SHA1(serverNonceAndNewNonce->bytes(), serverNonceAndNewNonce->limit(), tmpAesKeyAndIv->bytes() + 20); - serverNonceAndNewNonce->reuse(); + TL_server_DH_params_ok *result = (TL_server_DH_params_ok *) message; - NativeByteBuffer *newNonceAndNewNonce = BuffersStorage::getInstance().getFreeBuffer(authNewNonce->length + authNewNonce->length); - newNonceAndNewNonce->writeBytes(authNewNonce); - newNonceAndNewNonce->writeBytes(authNewNonce); - SHA1(newNonceAndNewNonce->bytes(), newNonceAndNewNonce->limit(), tmpAesKeyAndIv->bytes() + 40); - newNonceAndNewNonce->reuse(); + NativeByteBuffer *tmpAesKeyAndIv = BuffersStorage::getInstance().getFreeBuffer(84); - memcpy(tmpAesKeyAndIv->bytes() + 60, authNewNonce->bytes, 4); - Datacenter::aesIgeEncryption(result->encrypted_answer->bytes, tmpAesKeyAndIv->bytes(), tmpAesKeyAndIv->bytes() + 32, false, false, result->encrypted_answer->length); + NativeByteBuffer *newNonceAndServerNonce = BuffersStorage::getInstance().getFreeBuffer(authNewNonce->length + authServerNonce->length); + newNonceAndServerNonce->writeBytes(authNewNonce); + newNonceAndServerNonce->writeBytes(authServerNonce); + SHA1(newNonceAndServerNonce->bytes(), newNonceAndServerNonce->limit(), tmpAesKeyAndIv->bytes()); + newNonceAndServerNonce->reuse(); - bool hashVerified = false; - for (uint32_t i = 0; i < 16; i++) { - SHA1(result->encrypted_answer->bytes + SHA_DIGEST_LENGTH, result->encrypted_answer->length - i - SHA_DIGEST_LENGTH, tmpAesKeyAndIv->bytes() + 64); - if (!memcmp(tmpAesKeyAndIv->bytes() + 64, result->encrypted_answer->bytes, SHA_DIGEST_LENGTH)) { - hashVerified = true; - break; - } - } + NativeByteBuffer *serverNonceAndNewNonce = BuffersStorage::getInstance().getFreeBuffer(authServerNonce->length + authNewNonce->length); + serverNonceAndNewNonce->writeBytes(authServerNonce); + serverNonceAndNewNonce->writeBytes(authNewNonce); + SHA1(serverNonceAndNewNonce->bytes(), serverNonceAndNewNonce->limit(), tmpAesKeyAndIv->bytes() + 20); + serverNonceAndNewNonce->reuse(); - if (!hashVerified) { - if (LOGS_ENABLED) DEBUG_E("account%u dc%u handshake: can't decode DH params, type = %d", currentDatacenter->instanceNum, currentDatacenter->datacenterId, handshakeType); - beginHandshake(false); - return; - } + NativeByteBuffer *newNonceAndNewNonce = BuffersStorage::getInstance().getFreeBuffer(authNewNonce->length + authNewNonce->length); + newNonceAndNewNonce->writeBytes(authNewNonce); + newNonceAndNewNonce->writeBytes(authNewNonce); + SHA1(newNonceAndNewNonce->bytes(), newNonceAndNewNonce->limit(), tmpAesKeyAndIv->bytes() + 40); + newNonceAndNewNonce->reuse(); - bool error = false; - NativeByteBuffer *answerWithHash = new NativeByteBuffer(result->encrypted_answer->bytes + SHA_DIGEST_LENGTH, result->encrypted_answer->length - SHA_DIGEST_LENGTH); - uint32_t constructor = answerWithHash->readUint32(&error); - TL_server_DH_inner_data *dhInnerData = TL_server_DH_inner_data::TLdeserialize(answerWithHash, constructor, currentDatacenter->instanceNum, error); - delete answerWithHash; + memcpy(tmpAesKeyAndIv->bytes() + 60, authNewNonce->bytes, 4); + Datacenter::aesIgeEncryption(result->encrypted_answer->bytes, tmpAesKeyAndIv->bytes(), tmpAesKeyAndIv->bytes() + 32, false, false, result->encrypted_answer->length); - if (error) { - if (LOGS_ENABLED) DEBUG_E("account%u dc%u handshake: can't parse decoded DH params, type = %d", currentDatacenter->instanceNum, currentDatacenter->datacenterId, handshakeType); - beginHandshake(false); - return; + bool hashVerified = false; + for (uint32_t i = 0; i < 16; i++) { + SHA1(result->encrypted_answer->bytes + SHA_DIGEST_LENGTH, result->encrypted_answer->length - i - SHA_DIGEST_LENGTH, tmpAesKeyAndIv->bytes() + 64); + if (!memcmp(tmpAesKeyAndIv->bytes() + 64, result->encrypted_answer->bytes, SHA_DIGEST_LENGTH)) { + hashVerified = true; + break; } + } - if (!authNonce->isEqualTo(dhInnerData->nonce.get())) { - if (LOGS_ENABLED) DEBUG_E("account%u dc%u handshake: invalid DH nonce, type = %d", currentDatacenter->instanceNum, currentDatacenter->datacenterId, handshakeType); - beginHandshake(false); - return; - } + if (!hashVerified) { + if (LOGS_ENABLED) DEBUG_E("account%u dc%u handshake: can't decode DH params, type = %d", currentDatacenter->instanceNum, currentDatacenter->datacenterId, handshakeType); + beginHandshake(false); + return; + } - if (!authServerNonce->isEqualTo(dhInnerData->server_nonce.get())) { - if (LOGS_ENABLED) DEBUG_E("account%u dc%u handshake: invalid DH server nonce, type = %d", currentDatacenter->instanceNum, currentDatacenter->datacenterId, handshakeType); - beginHandshake(false); - return; - } + bool error = false; + NativeByteBuffer *answerWithHash = new NativeByteBuffer(result->encrypted_answer->bytes + SHA_DIGEST_LENGTH, result->encrypted_answer->length - SHA_DIGEST_LENGTH); + uint32_t constructor = answerWithHash->readUint32(&error); + TL_server_DH_inner_data *dhInnerData = TL_server_DH_inner_data::TLdeserialize(answerWithHash, constructor, currentDatacenter->instanceNum, error); + delete answerWithHash; - BIGNUM *p = BN_bin2bn(dhInnerData->dh_prime->bytes, dhInnerData->dh_prime->length, NULL); - if (p == nullptr) { - if (LOGS_ENABLED) DEBUG_E("can't allocate BIGNUM p"); - exit(1); - } - if (!isGoodPrime(p, dhInnerData->g)) { - if (LOGS_ENABLED) DEBUG_E("account%u dc%u handshake: bad prime, type = %d", currentDatacenter->instanceNum, currentDatacenter->datacenterId, handshakeType); - beginHandshake(false); - BN_free(p); - return; - } + if (error) { + if (LOGS_ENABLED) DEBUG_E("account%u dc%u handshake: can't parse decoded DH params, type = %d", currentDatacenter->instanceNum, currentDatacenter->datacenterId, handshakeType); + beginHandshake(false); + return; + } - BIGNUM *g_a = BN_new(); - if (g_a == nullptr) { - if (LOGS_ENABLED) DEBUG_E("can't allocate BIGNUM g_a"); - exit(1); - } - BN_bin2bn(dhInnerData->g_a->bytes, dhInnerData->g_a->length, g_a); - if (!isGoodGaAndGb(g_a, p)) { - if (LOGS_ENABLED) DEBUG_E("account%u dc%u handshake: bad prime and g_a, type = %d", currentDatacenter->instanceNum, currentDatacenter->datacenterId, handshakeType); - beginHandshake(false); - BN_free(p); - BN_free(g_a); - return; - } + if (!authNonce->isEqualTo(dhInnerData->nonce.get())) { + if (LOGS_ENABLED) DEBUG_E("account%u dc%u handshake: invalid DH nonce, type = %d", currentDatacenter->instanceNum, currentDatacenter->datacenterId, handshakeType); + beginHandshake(false); + return; + } - BIGNUM *g = BN_new(); - if (g == nullptr) { - if (LOGS_ENABLED) DEBUG_E("can't allocate BIGNUM g"); - exit(1); - } - if (!BN_set_word(g, dhInnerData->g)) { - if (LOGS_ENABLED) DEBUG_E("OpenSSL error at BN_set_word(g_b, dhInnerData->g)"); - beginHandshake(false); - BN_free(g); - BN_free(g_a); - BN_free(p); - return; - } - thread_local static uint8_t bytes[256]; - RAND_bytes(bytes, 256); - BIGNUM *b = BN_bin2bn(bytes, 256, NULL); - if (b == nullptr) { - if (LOGS_ENABLED) DEBUG_E("can't allocate BIGNUM b"); - exit(1); - } + if (!authServerNonce->isEqualTo(dhInnerData->server_nonce.get())) { + if (LOGS_ENABLED) DEBUG_E("account%u dc%u handshake: invalid DH server nonce, type = %d", currentDatacenter->instanceNum, currentDatacenter->datacenterId, handshakeType); + beginHandshake(false); + return; + } - BIGNUM *g_b = BN_new(); - if (!BN_mod_exp(g_b, g, b, p, bnContext)) { - if (LOGS_ENABLED) DEBUG_E("OpenSSL error at BN_mod_exp(g_b, g, b, p, bnContext)"); - beginHandshake(false); - BN_free(g); - BN_free(g_a); - BN_free(g_b); - BN_free(b); - BN_free(p); - return; - } + BIGNUM *p = BN_bin2bn(dhInnerData->dh_prime->bytes, dhInnerData->dh_prime->length, NULL); + if (p == nullptr) { + if (LOGS_ENABLED) DEBUG_E("can't allocate BIGNUM p"); + exit(1); + } + if (!isGoodPrime(p, dhInnerData->g)) { + if (LOGS_ENABLED) DEBUG_E("account%u dc%u handshake: bad prime, type = %d", currentDatacenter->instanceNum, currentDatacenter->datacenterId, handshakeType); + beginHandshake(false); + BN_free(p); + return; + } - TL_client_DH_inner_data *clientInnerData = new TL_client_DH_inner_data(); - clientInnerData->g_b = std::unique_ptr(new ByteArray(BN_num_bytes(g_b))); - BN_bn2bin(g_b, clientInnerData->g_b->bytes); - clientInnerData->nonce = std::unique_ptr(new ByteArray(authNonce)); - clientInnerData->server_nonce = std::unique_ptr(new ByteArray(authServerNonce)); - clientInnerData->retry_id = 0; - BN_free(g_b); - BN_free(g); + BIGNUM *g_a = BN_new(); + if (g_a == nullptr) { + if (LOGS_ENABLED) DEBUG_E("can't allocate BIGNUM g_a"); + exit(1); + } + BN_bin2bn(dhInnerData->g_a->bytes, dhInnerData->g_a->length, g_a); + if (!isGoodGaAndGb(g_a, p)) { + if (LOGS_ENABLED) DEBUG_E("account%u dc%u handshake: bad prime and g_a, type = %d", currentDatacenter->instanceNum, currentDatacenter->datacenterId, handshakeType); + beginHandshake(false); + BN_free(p); + BN_free(g_a); + return; + } - BIGNUM *authKeyNum = BN_new(); - BN_mod_exp(authKeyNum, g_a, b, p, bnContext); - size_t l = BN_num_bytes(authKeyNum); - handshakeAuthKey = new ByteArray(256); - BN_bn2bin(authKeyNum, handshakeAuthKey->bytes); - if (l < 256) { - memmove(handshakeAuthKey->bytes + 256 - l, handshakeAuthKey->bytes, l); - memset(handshakeAuthKey->bytes, 0, 256 - l); - } + BIGNUM *g = BN_new(); + if (g == nullptr) { + if (LOGS_ENABLED) DEBUG_E("can't allocate BIGNUM g"); + exit(1); + } + if (!BN_set_word(g, dhInnerData->g)) { + if (LOGS_ENABLED) DEBUG_E("OpenSSL error at BN_set_word(g_b, dhInnerData->g)"); + beginHandshake(false); + BN_free(g); + BN_free(g_a); + BN_free(p); + return; + } + thread_local static uint8_t bytes[256]; + RAND_bytes(bytes, 256); + BIGNUM *b = BN_bin2bn(bytes, 256, NULL); + if (b == nullptr) { + if (LOGS_ENABLED) DEBUG_E("can't allocate BIGNUM b"); + exit(1); + } - BN_free(authKeyNum); + BIGNUM *g_b = BN_new(); + if (!BN_mod_exp(g_b, g, b, p, bnContext)) { + if (LOGS_ENABLED) DEBUG_E("OpenSSL error at BN_mod_exp(g_b, g, b, p, bnContext)"); + beginHandshake(false); + BN_free(g); BN_free(g_a); + BN_free(g_b); BN_free(b); BN_free(p); + return; + } - uint32_t clientInnerDataSize = clientInnerData->getObjectSize(); - uint32_t additionalSize = (clientInnerDataSize + SHA_DIGEST_LENGTH) % 16; - if (additionalSize != 0) { - additionalSize = 16 - additionalSize; - } - NativeByteBuffer *clientInnerDataBuffer = BuffersStorage::getInstance().getFreeBuffer(clientInnerDataSize + additionalSize + SHA_DIGEST_LENGTH); - clientInnerDataBuffer->position(SHA_DIGEST_LENGTH); - clientInnerData->serializeToStream(clientInnerDataBuffer); - delete clientInnerData; - - SHA1(clientInnerDataBuffer->bytes() + SHA_DIGEST_LENGTH, clientInnerDataSize, clientInnerDataBuffer->bytes()); - - if (additionalSize != 0) { - RAND_bytes(clientInnerDataBuffer->bytes() + SHA_DIGEST_LENGTH + clientInnerDataSize, additionalSize); - } + TL_client_DH_inner_data *clientInnerData = new TL_client_DH_inner_data(); + clientInnerData->g_b = std::unique_ptr(new ByteArray(BN_num_bytes(g_b))); + BN_bn2bin(g_b, clientInnerData->g_b->bytes); + clientInnerData->nonce = std::unique_ptr(new ByteArray(authNonce)); + clientInnerData->server_nonce = std::unique_ptr(new ByteArray(authServerNonce)); + clientInnerData->retry_id = 0; + BN_free(g_b); + BN_free(g); + + BIGNUM *authKeyNum = BN_new(); + BN_mod_exp(authKeyNum, g_a, b, p, bnContext); + size_t l = BN_num_bytes(authKeyNum); + handshakeAuthKey = new ByteArray(256); + BN_bn2bin(authKeyNum, handshakeAuthKey->bytes); + if (l < 256) { + memmove(handshakeAuthKey->bytes + 256 - l, handshakeAuthKey->bytes, l); + memset(handshakeAuthKey->bytes, 0, 256 - l); + } - TL_set_client_DH_params *setClientDhParams = new TL_set_client_DH_params(); - setClientDhParams->nonce = std::unique_ptr(new ByteArray(authNonce)); - setClientDhParams->server_nonce = std::unique_ptr(new ByteArray(authServerNonce)); - Datacenter::aesIgeEncryption(clientInnerDataBuffer->bytes(), tmpAesKeyAndIv->bytes(), tmpAesKeyAndIv->bytes() + 32, true, false, clientInnerDataBuffer->limit()); - setClientDhParams->encrypted_data = std::unique_ptr(new ByteArray(clientInnerDataBuffer->bytes(), clientInnerDataBuffer->limit())); - clientInnerDataBuffer->reuse(); - tmpAesKeyAndIv->reuse(); + BN_free(authKeyNum); + BN_free(g_a); + BN_free(b); + BN_free(p); - sendAckRequest(messageId); - sendRequestData(setClientDhParams, true); + uint32_t clientInnerDataSize = clientInnerData->getObjectSize(); + uint32_t additionalSize = (clientInnerDataSize + SHA_DIGEST_LENGTH) % 16; + if (additionalSize != 0) { + additionalSize = 16 - additionalSize; + } + NativeByteBuffer *clientInnerDataBuffer = BuffersStorage::getInstance().getFreeBuffer(clientInnerDataSize + additionalSize + SHA_DIGEST_LENGTH); + clientInnerDataBuffer->position(SHA_DIGEST_LENGTH); + clientInnerData->serializeToStream(clientInnerDataBuffer); + delete clientInnerData; - int32_t currentTime = (int32_t) (ConnectionsManager::getInstance(currentDatacenter->instanceNum).getCurrentTimeMillis() / 1000); - timeDifference = dhInnerData->server_time - currentTime; + SHA1(clientInnerDataBuffer->bytes() + SHA_DIGEST_LENGTH, clientInnerDataSize, clientInnerDataBuffer->bytes()); - handshakeServerSalt = new TL_future_salt(); - handshakeServerSalt->valid_since = currentTime + timeDifference - 5; - handshakeServerSalt->valid_until = handshakeServerSalt->valid_since + 30 * 60; - for (int32_t a = 7; a >= 0; a--) { - handshakeServerSalt->salt <<= 8; - handshakeServerSalt->salt |= (authNewNonce->bytes[a] ^ authServerNonce->bytes[a]); - } - } else { - if (LOGS_ENABLED) DEBUG_E("account%u dc%u handshake: can't set DH params, type = %d", currentDatacenter->instanceNum, currentDatacenter->datacenterId, handshakeType); - beginHandshake(false); - } - } else if (dynamic_cast(message)) { - if (handshakeState != 3) { - sendAckRequest(messageId); - return; + if (additionalSize != 0) { + RAND_bytes(clientInnerDataBuffer->bytes() + SHA_DIGEST_LENGTH + clientInnerDataSize, additionalSize); } - handshakeState = 4; + TL_set_client_DH_params *setClientDhParams = new TL_set_client_DH_params(); + setClientDhParams->nonce = std::unique_ptr(new ByteArray(authNonce)); + setClientDhParams->server_nonce = std::unique_ptr(new ByteArray(authServerNonce)); + Datacenter::aesIgeEncryption(clientInnerDataBuffer->bytes(), tmpAesKeyAndIv->bytes(), tmpAesKeyAndIv->bytes() + 32, true, false, clientInnerDataBuffer->limit()); + setClientDhParams->encrypted_data = std::unique_ptr(new ByteArray(clientInnerDataBuffer->bytes(), clientInnerDataBuffer->limit())); + clientInnerDataBuffer->reuse(); + tmpAesKeyAndIv->reuse(); - Set_client_DH_params_answer *result = (Set_client_DH_params_answer *) message; + sendAckRequest(messageId); + sendRequestData(setClientDhParams, true); - if (!authNonce->isEqualTo(result->nonce.get())) { - if (LOGS_ENABLED) DEBUG_E("account%u dc%u handshake: invalid DH answer nonce, type = %d", currentDatacenter->instanceNum, currentDatacenter->datacenterId, handshakeType); - beginHandshake(false); - return; - } - if (!authServerNonce->isEqualTo(result->server_nonce.get())) { - if (LOGS_ENABLED) DEBUG_E("account%u dc%u handshake: invalid DH answer server nonce, type = %d", currentDatacenter->instanceNum, currentDatacenter->datacenterId, handshakeType); - beginHandshake(false); - return; + int32_t currentTime = (int32_t) (ConnectionsManager::getInstance(currentDatacenter->instanceNum).getCurrentTimeMillis() / 1000); + timeDifference = dhInnerData->server_time - currentTime; + + handshakeServerSalt = new TL_future_salt(); + handshakeServerSalt->valid_since = currentTime + timeDifference - 5; + handshakeServerSalt->valid_until = handshakeServerSalt->valid_since + 30 * 60; + for (int32_t a = 7; a >= 0; a--) { + handshakeServerSalt->salt <<= 8; + handshakeServerSalt->salt |= (authNewNonce->bytes[a] ^ authServerNonce->bytes[a]); } + } else { + if (LOGS_ENABLED) DEBUG_E("account%u dc%u handshake: can't set DH params, type = %d", currentDatacenter->instanceNum, currentDatacenter->datacenterId, handshakeType); + beginHandshake(false); + } +} +void Handshake::processHandshakeResponse_serverDHParamsAnswer(TLObject *message, int64_t messageId) { + if (handshakeState != 3) { sendAckRequest(messageId); + return; + } + const std::type_info &typeInfo = typeid(*message); - uint32_t authKeyAuxHashLength = authNewNonce->length + SHA_DIGEST_LENGTH + 1; - NativeByteBuffer *authKeyAuxHashBuffer = BuffersStorage::getInstance().getFreeBuffer(authKeyAuxHashLength + SHA_DIGEST_LENGTH); - authKeyAuxHashBuffer->writeBytes(authNewNonce); - SHA1(handshakeAuthKey->bytes, handshakeAuthKey->length, authKeyAuxHashBuffer->bytes() + authNewNonce->length + 1); + handshakeState = 4; - if (typeInfo == typeid(TL_dh_gen_ok)) { - authKeyAuxHashBuffer->writeByte(1); - SHA1(authKeyAuxHashBuffer->bytes(), authKeyAuxHashLength - 12, authKeyAuxHashBuffer->bytes() + authKeyAuxHashLength); + Set_client_DH_params_answer *result = (Set_client_DH_params_answer *) message; - if (memcmp(result->new_nonce_hash1->bytes, authKeyAuxHashBuffer->bytes() + authKeyAuxHashLength + SHA_DIGEST_LENGTH - 16, 16)) { - if (LOGS_ENABLED) DEBUG_E("account%u dc%u handshake: invalid DH answer nonce hash 1, type = %d", currentDatacenter->instanceNum, currentDatacenter->datacenterId, handshakeType); - authKeyAuxHashBuffer->reuse(); - beginHandshake(false); - } else { - if (LOGS_ENABLED) DEBUG_D("account%u dc%u handshake: completed, time difference = %d, type = %d", currentDatacenter->instanceNum, currentDatacenter->datacenterId, timeDifference, handshakeType); - authKeyAuxHashBuffer->position(authNewNonce->length + 1 + 12); - authKeyTempPendingId = authKeyAuxHashBuffer->readInt64(nullptr); - authKeyAuxHashBuffer->reuse(); - - if (handshakeRequest != nullptr) { - delete handshakeRequest; - handshakeRequest = nullptr; - } + if (!authNonce->isEqualTo(result->nonce.get())) { + if (LOGS_ENABLED) DEBUG_E("account%u dc%u handshake: invalid DH answer nonce, type = %d", currentDatacenter->instanceNum, currentDatacenter->datacenterId, handshakeType); + beginHandshake(false); + return; + } + if (!authServerNonce->isEqualTo(result->server_nonce.get())) { + if (LOGS_ENABLED) DEBUG_E("account%u dc%u handshake: invalid DH answer server nonce, type = %d", currentDatacenter->instanceNum, currentDatacenter->datacenterId, handshakeType); + beginHandshake(false); + return; + } - std::unique_ptr salt = std::unique_ptr(handshakeServerSalt); - currentDatacenter->clearServerSalts(handshakeType == HandshakeTypeMediaTemp); - currentDatacenter->addServerSalt(salt, handshakeType == HandshakeTypeMediaTemp); - handshakeServerSalt = nullptr; - - if (handshakeType == HandshakeTypePerm) { - ConnectionsManager::getInstance(currentDatacenter->instanceNum).scheduleTask([&] { - ByteArray *authKey = handshakeAuthKey; - handshakeAuthKey = nullptr; - delegate->onHandshakeComplete(this, authKeyTempPendingId, authKey, timeDifference); - }); - } else { - authKeyTempPending = handshakeAuthKey; - handshakeAuthKey = nullptr; + sendAckRequest(messageId); - Connection *connection = getConnection(); - - TL_auth_bindTempAuthKey *request = new TL_auth_bindTempAuthKey(); - request->initFunc = [&, request, connection](int64_t messageId) { - TL_bind_auth_key_inner *inner = new TL_bind_auth_key_inner(); - inner->expires_at = ConnectionsManager::getInstance(currentDatacenter->instanceNum).getCurrentTime() + timeDifference + TEMP_AUTH_KEY_EXPIRE_TIME; - inner->perm_auth_key_id = currentDatacenter->authKeyPermId; - inner->temp_auth_key_id = authKeyTempPendingId; - RAND_bytes((uint8_t *) &inner->nonce, 8); - inner->temp_session_id = connection->getSessionId(); - - NetworkMessage *networkMessage = new NetworkMessage(); - networkMessage->message = std::make_unique(); - networkMessage->message->msg_id = authKeyPendingMessageId = messageId; - networkMessage->message->bytes = inner->getObjectSize(); - networkMessage->message->body = std::unique_ptr(inner); - networkMessage->message->seqno = 0; - - std::vector> array; - array.push_back(std::unique_ptr(networkMessage)); - - request->perm_auth_key_id = inner->perm_auth_key_id; - request->nonce = inner->nonce; - request->expires_at = inner->expires_at; - request->encrypted_message = currentDatacenter->createRequestsData(array, nullptr, connection, true); - }; - - authKeyPendingRequestId = ConnectionsManager::getInstance(currentDatacenter->instanceNum).sendRequest(request, [&](TLObject *response, TL_error *error, int32_t networkType, int64_t responseTime, int64_t msgId) { - authKeyPendingMessageId = 0; - authKeyPendingRequestId = 0; - if (response != nullptr && typeid(*response) == typeid(TL_boolTrue)) { - if (LOGS_ENABLED) DEBUG_D("account%u dc%u handshake: bind completed", currentDatacenter->instanceNum, currentDatacenter->datacenterId); - ConnectionsManager::getInstance(currentDatacenter->instanceNum).scheduleTask([&] { - ByteArray *authKey = authKeyTempPending; - authKeyTempPending = nullptr; - delegate->onHandshakeComplete(this, authKeyTempPendingId, authKey, timeDifference); - }); - } else if (error == nullptr || error->code != 400 || error->text.find("ENCRYPTED_MESSAGE_INVALID") == std::string::npos) { - ConnectionsManager::getInstance(currentDatacenter->instanceNum).scheduleTask([&] { - beginHandshake(true); - }); - } - }, nullptr, RequestFlagWithoutLogin | RequestFlagEnableUnauthorized | RequestFlagUseUnboundKey, currentDatacenter->datacenterId, connection->getConnectionType(), true, 0); - } - } - } else if (typeInfo == typeid(TL_dh_gen_retry)) { - authKeyAuxHashBuffer->writeByte(2); - SHA1(authKeyAuxHashBuffer->bytes(), authKeyAuxHashLength - 12, authKeyAuxHashBuffer->bytes() + authKeyAuxHashLength); + uint32_t authKeyAuxHashLength = authNewNonce->length + SHA_DIGEST_LENGTH + 1; + NativeByteBuffer *authKeyAuxHashBuffer = BuffersStorage::getInstance().getFreeBuffer(authKeyAuxHashLength + SHA_DIGEST_LENGTH); + authKeyAuxHashBuffer->writeBytes(authNewNonce); + SHA1(handshakeAuthKey->bytes, handshakeAuthKey->length, authKeyAuxHashBuffer->bytes() + authNewNonce->length + 1); - if (memcmp(result->new_nonce_hash2->bytes, authKeyAuxHashBuffer->bytes() + authKeyAuxHashLength + SHA_DIGEST_LENGTH - 16, 16)) { - if (LOGS_ENABLED) DEBUG_E("account%u dc%u handshake: invalid DH answer nonce hash 2, type = %d", currentDatacenter->instanceNum, currentDatacenter->datacenterId, handshakeType); - beginHandshake(false); - } else { - if (LOGS_ENABLED) DEBUG_D("account%u dc%u handshake: retry DH, type = %d", currentDatacenter->instanceNum, currentDatacenter->datacenterId, handshakeType); - beginHandshake(false); - } + if (typeInfo == typeid(TL_dh_gen_ok)) { + authKeyAuxHashBuffer->writeByte(1); + SHA1(authKeyAuxHashBuffer->bytes(), authKeyAuxHashLength - 12, authKeyAuxHashBuffer->bytes() + authKeyAuxHashLength); + + if (memcmp(result->new_nonce_hash1->bytes, authKeyAuxHashBuffer->bytes() + authKeyAuxHashLength + SHA_DIGEST_LENGTH - 16, 16)) { + if (LOGS_ENABLED) DEBUG_E("account%u dc%u handshake: invalid DH answer nonce hash 1, type = %d", currentDatacenter->instanceNum, currentDatacenter->datacenterId, handshakeType); + authKeyAuxHashBuffer->reuse(); + beginHandshake(false); + } else { + if (LOGS_ENABLED) DEBUG_D("account%u dc%u handshake: completed, time difference = %d, type = %d", currentDatacenter->instanceNum, currentDatacenter->datacenterId, timeDifference, handshakeType); + authKeyAuxHashBuffer->position(authNewNonce->length + 1 + 12); + authKeyTempPendingId = authKeyAuxHashBuffer->readInt64(nullptr); authKeyAuxHashBuffer->reuse(); - } else if (typeInfo == typeid(TL_dh_gen_fail)) { - authKeyAuxHashBuffer->writeByte(3); - SHA1(authKeyAuxHashBuffer->bytes(), authKeyAuxHashLength - 12, authKeyAuxHashBuffer->bytes() + authKeyAuxHashLength); - if (memcmp(result->new_nonce_hash3->bytes, authKeyAuxHashBuffer->bytes() + authKeyAuxHashLength + SHA_DIGEST_LENGTH - 16, 16)) { - if (LOGS_ENABLED) DEBUG_E("account%u dc%u handshake: invalid DH answer nonce hash 3, type = %d", currentDatacenter->instanceNum, currentDatacenter->datacenterId, handshakeType); - beginHandshake(false); + if (handshakeRequest != nullptr) { + delete handshakeRequest; + handshakeRequest = nullptr; + } + + std::unique_ptr salt = std::unique_ptr(handshakeServerSalt); + currentDatacenter->clearServerSalts(handshakeType == HandshakeTypeMediaTemp); + currentDatacenter->addServerSalt(salt, handshakeType == HandshakeTypeMediaTemp); + handshakeServerSalt = nullptr; + + if (handshakeType == HandshakeTypePerm) { + ConnectionsManager::getInstance(currentDatacenter->instanceNum).scheduleTask([&] { + ByteArray *authKey = handshakeAuthKey; + handshakeAuthKey = nullptr; + delegate->onHandshakeComplete(this, authKeyTempPendingId, authKey, timeDifference); + }); } else { - if (LOGS_ENABLED) DEBUG_E("account%u dc%u handshake: server declined DH params, type = %d", currentDatacenter->instanceNum, currentDatacenter->datacenterId, handshakeType); - beginHandshake(false); + authKeyTempPending = handshakeAuthKey; + handshakeAuthKey = nullptr; + + Connection *connection = getConnection(); + + TL_auth_bindTempAuthKey *request = new TL_auth_bindTempAuthKey(); + request->initFunc = [&, request, connection](int64_t messageId) { + TL_bind_auth_key_inner *inner = new TL_bind_auth_key_inner(); + inner->expires_at = ConnectionsManager::getInstance(currentDatacenter->instanceNum).getCurrentTime() + timeDifference + TEMP_AUTH_KEY_EXPIRE_TIME; + inner->perm_auth_key_id = currentDatacenter->authKeyPermId; + inner->temp_auth_key_id = authKeyTempPendingId; + RAND_bytes((uint8_t *) &inner->nonce, 8); + inner->temp_session_id = connection->getSessionId(); + + NetworkMessage *networkMessage = new NetworkMessage(); + networkMessage->message = std::make_unique(); + networkMessage->message->msg_id = authKeyPendingMessageId = messageId; + networkMessage->message->bytes = inner->getObjectSize(); + networkMessage->message->body = std::unique_ptr(inner); + networkMessage->message->seqno = 0; + + std::vector> array; + array.push_back(std::unique_ptr(networkMessage)); + + request->perm_auth_key_id = inner->perm_auth_key_id; + request->nonce = inner->nonce; + request->expires_at = inner->expires_at; + request->encrypted_message = currentDatacenter->createRequestsData(array, nullptr, connection, true); + }; + + authKeyPendingRequestId = ConnectionsManager::getInstance(currentDatacenter->instanceNum).sendRequest(request, [&](TLObject *response, TL_error *error, int32_t networkType, int64_t responseTime, int64_t msgId) { + authKeyPendingMessageId = 0; + authKeyPendingRequestId = 0; + if (response != nullptr && typeid(*response) == typeid(TL_boolTrue)) { + if (LOGS_ENABLED) DEBUG_D("account%u dc%u handshake: bind completed", currentDatacenter->instanceNum, currentDatacenter->datacenterId); + ConnectionsManager::getInstance(currentDatacenter->instanceNum).scheduleTask([&] { + ByteArray *authKey = authKeyTempPending; + authKeyTempPending = nullptr; + delegate->onHandshakeComplete(this, authKeyTempPendingId, authKey, timeDifference); + }); + } else if (error == nullptr || error->code != 400 || error->text.find("ENCRYPTED_MESSAGE_INVALID") == std::string::npos) { + ConnectionsManager::getInstance(currentDatacenter->instanceNum).scheduleTask([&] { + beginHandshake(true); + }); + } + }, nullptr, nullptr, RequestFlagWithoutLogin | RequestFlagEnableUnauthorized | RequestFlagUseUnboundKey, currentDatacenter->datacenterId, connection->getConnectionType(), true, 0); } - authKeyAuxHashBuffer->reuse(); } + } else if (typeInfo == typeid(TL_dh_gen_retry)) { + authKeyAuxHashBuffer->writeByte(2); + SHA1(authKeyAuxHashBuffer->bytes(), authKeyAuxHashLength - 12, authKeyAuxHashBuffer->bytes() + authKeyAuxHashLength); + + if (memcmp(result->new_nonce_hash2->bytes, authKeyAuxHashBuffer->bytes() + authKeyAuxHashLength + SHA_DIGEST_LENGTH - 16, 16)) { + if (LOGS_ENABLED) DEBUG_E("account%u dc%u handshake: invalid DH answer nonce hash 2, type = %d", currentDatacenter->instanceNum, currentDatacenter->datacenterId, handshakeType); + beginHandshake(false); + } else { + if (LOGS_ENABLED) DEBUG_D("account%u dc%u handshake: retry DH, type = %d", currentDatacenter->instanceNum, currentDatacenter->datacenterId, handshakeType); + beginHandshake(false); + } + authKeyAuxHashBuffer->reuse(); + } else if (typeInfo == typeid(TL_dh_gen_fail)) { + authKeyAuxHashBuffer->writeByte(3); + SHA1(authKeyAuxHashBuffer->bytes(), authKeyAuxHashLength - 12, authKeyAuxHashBuffer->bytes() + authKeyAuxHashLength); + + if (memcmp(result->new_nonce_hash3->bytes, authKeyAuxHashBuffer->bytes() + authKeyAuxHashLength + SHA_DIGEST_LENGTH - 16, 16)) { + if (LOGS_ENABLED) DEBUG_E("account%u dc%u handshake: invalid DH answer nonce hash 3, type = %d", currentDatacenter->instanceNum, currentDatacenter->datacenterId, handshakeType); + beginHandshake(false); + } else { + if (LOGS_ENABLED) DEBUG_E("account%u dc%u handshake: server declined DH params, type = %d", currentDatacenter->instanceNum, currentDatacenter->datacenterId, handshakeType); + beginHandshake(false); + } + authKeyAuxHashBuffer->reuse(); } } @@ -1017,7 +1031,7 @@ void Handshake::loadCdnConfig(Datacenter *datacenter) { saveCdnConfig(datacenter); } loadingCdnKeys = false; - }, nullptr, RequestFlagEnableUnauthorized | RequestFlagWithoutLogin, DEFAULT_DATACENTER_ID, ConnectionTypeGeneric, true); + }, nullptr, nullptr, RequestFlagEnableUnauthorized | RequestFlagWithoutLogin, DEFAULT_DATACENTER_ID, ConnectionTypeGeneric, true); } HandshakeType Handshake::getType() { diff --git a/TMessagesProj/jni/tgnet/Handshake.h b/TMessagesProj/jni/tgnet/Handshake.h index 2e712760ad6..9c2616c6df3 100644 --- a/TMessagesProj/jni/tgnet/Handshake.h +++ b/TMessagesProj/jni/tgnet/Handshake.h @@ -27,6 +27,9 @@ class Handshake { void beginHandshake(bool reconnect); void cleanupHandshake(); void processHandshakeResponse(TLObject *message, int64_t messageId); + void processHandshakeResponse_resPQ(TLObject *message, int64_t messageId); + void processHandshakeResponse_serverDHParams(TLObject *message, int64_t messageId); + void processHandshakeResponse_serverDHParamsAnswer(TLObject *message, int64_t messageId); void onHandshakeConnectionConnected(); void onHandshakeConnectionClosed(); static void cleanupServerKeys(); diff --git a/TMessagesProj/jni/tgnet/Request.cpp b/TMessagesProj/jni/tgnet/Request.cpp index 9aec8bfc402..1d95236c897 100644 --- a/TMessagesProj/jni/tgnet/Request.cpp +++ b/TMessagesProj/jni/tgnet/Request.cpp @@ -15,7 +15,7 @@ #include "Connection.h" #include "FileLog.h" -Request::Request(int32_t instance, int32_t token, ConnectionType type, uint32_t flags, uint32_t datacenter, onCompleteFunc completeFunc, onQuickAckFunc quickAckFunc, onWriteToSocketFunc writeToSocketFunc) { +Request::Request(int32_t instance, int32_t token, ConnectionType type, uint32_t flags, uint32_t datacenter, onCompleteFunc completeFunc, onQuickAckFunc quickAckFunc, onWriteToSocketFunc writeToSocketFunc, onRequestClearFunc onClearFunc) { requestToken = token; connectionType = type; requestFlags = flags; @@ -23,28 +23,15 @@ Request::Request(int32_t instance, int32_t token, ConnectionType type, uint32_t onCompleteRequestCallback = completeFunc; onQuickAckCallback = quickAckFunc; onWriteToSocketCallback = writeToSocketFunc; + onRequestClearCallback = onClearFunc; dataType = (uint8_t) (requestFlags >> 24); instanceNum = instance; } Request::~Request() { -#ifdef ANDROID - if (ptr1 != nullptr) { - DEBUG_DELREF("tgnet request ptr1"); - jniEnv[instanceNum]->DeleteGlobalRef(ptr1); - ptr1 = nullptr; + if (!completedSent && !disableClearCallback && onRequestClearCallback != nullptr) { + onRequestClearCallback(); } - if (ptr2 != nullptr) { - DEBUG_DELREF("tgnet request ptr2"); - jniEnv[instanceNum]->DeleteGlobalRef(ptr2); - ptr2 = nullptr; - } - if (ptr3 != nullptr) { - DEBUG_DELREF("tgnet request ptr3"); - jniEnv[instanceNum]->DeleteGlobalRef(ptr3); - ptr3 = nullptr; - } -#endif } void Request::addRespondMessageId(int64_t id) { @@ -67,6 +54,7 @@ void Request::clear(bool time) { void Request::onComplete(TLObject *result, TL_error *error, int32_t networkType, int64_t responseTime, int64_t requestMsgId) { if (onCompleteRequestCallback != nullptr && (result != nullptr || error != nullptr)) { + completedSent = true; onCompleteRequestCallback(result, error, networkType, responseTime, requestMsgId); } } diff --git a/TMessagesProj/jni/tgnet/Request.h b/TMessagesProj/jni/tgnet/Request.h index 2013a6526c8..bf360f9d459 100644 --- a/TMessagesProj/jni/tgnet/Request.h +++ b/TMessagesProj/jni/tgnet/Request.h @@ -24,7 +24,7 @@ class Datacenter; class Request { public: - Request(int32_t instance, int32_t token, ConnectionType type, uint32_t flags, uint32_t datacenter, onCompleteFunc completeFunc, onQuickAckFunc quickAckFunc, onWriteToSocketFunc writeToSocketFunc); + Request(int32_t instance, int32_t token, ConnectionType type, uint32_t flags, uint32_t datacenter, onCompleteFunc completeFunc, onQuickAckFunc quickAckFunc, onWriteToSocketFunc writeToSocketFunc, onRequestClearFunc onClearFunc); ~Request(); int64_t messageId = 0; @@ -37,6 +37,7 @@ class Request { int32_t failedByFloodWait = 0; ConnectionType connectionType; uint32_t requestFlags; + bool completedSent = false; bool completed = false; bool cancelled = false; bool isInitRequest = false; @@ -55,6 +56,10 @@ class Request { onCompleteFunc onCompleteRequestCallback; onQuickAckFunc onQuickAckCallback; onWriteToSocketFunc onWriteToSocketCallback; + bool disableClearCallback = false; + bool doNotClearOnDrop = false; + int32_t clearAfter = 0; + onRequestClearFunc onRequestClearCallback; void addRespondMessageId(int64_t id); bool respondsToMessageId(int64_t id); @@ -68,12 +73,6 @@ class Request { bool needInitRequest(Datacenter *datacenter, uint32_t currentVersion); TLObject *getRpcRequest(); -#ifdef ANDROID - jobject ptr1 = nullptr; - jobject ptr2 = nullptr; - jobject ptr3 = nullptr; -#endif - private: std::vector respondsToMessageIds; }; diff --git a/TMessagesProj/proguard-rules.pro b/TMessagesProj/proguard-rules.pro index 4f37671f258..dead1442f70 100644 --- a/TMessagesProj/proguard-rules.pro +++ b/TMessagesProj/proguard-rules.pro @@ -17,11 +17,8 @@ -keep class org.telegram.SQLite.** { *; } -keep class org.telegram.tgnet.ConnectionsManager { *; } -keep class org.telegram.tgnet.NativeByteBuffer { *; } --keep class org.telegram.tgnet.RequestDelegateInternal { *; } -keep class org.telegram.tgnet.RequestTimeDelegate { *; } -keep class org.telegram.tgnet.RequestDelegate { *; } --keep class org.telegram.tgnet.QuickAckDelegate { *; } --keep class org.telegram.tgnet.WriteToSocketDelegate { *; } -keep class com.google.android.exoplayer2.ext.** { *; } -keep class com.google.android.exoplayer2.extractor.FlacStreamMetadata { *; } -keep class com.google.android.exoplayer2.metadata.flac.PictureFrame { *; } diff --git a/TMessagesProj/src/main/AndroidManifest.xml b/TMessagesProj/src/main/AndroidManifest.xml index 63066e626a5..be5cda36858 100644 --- a/TMessagesProj/src/main/AndroidManifest.xml +++ b/TMessagesProj/src/main/AndroidManifest.xml @@ -353,6 +353,11 @@ android:configChanges="keyboard|keyboardHidden|orientation|screenSize|uiMode" android:exported="true"> + + .5) { + uv.x = 1.0 - uv.x; + } + } + float mixValue = clamp(distance(uv.xy, vec2(0.0)), 0.0, 1.0); + vec4 gradientColorFinal = vec4(mix(gradientColor1, gradientColor2, mixValue), 1.0); + + float modelNormalSpec = normalSpec, modelSpec1 = 0.0, modelSpec2 = 0.05; + + float darken = 1. - length(modelViewVertex - vec3(30., -75., 50.)) / 200.; + + if (border > 0.) { + modelNormalSpec += border; + modelSpec1 += border; + modelSpec2 += border; + } + + + vec3 angleW = normalize(viewDirectionW + vLightPosition2); + float specComp2 = max(0., dot(finalNormal, angleW)); + specComp2 = pow(specComp2, max(1., 128.)) * modelSpec1; + + angleW = normalize(viewDirectionW + vLightPosition4); + float specComp3 = max(0., dot(finalNormal, angleW)); + specComp3 = pow(specComp3, max(1., 30.)) * modelSpec2; + + angleW = normalize(viewDirectionW + vLightPositionNormal); + float normalSpecComp = max(0., dot(finalNormal, angleW)); + normalSpecComp = pow(normalSpecComp, max(1., 128.)) * modelNormalSpec; + + angleW = normalize(viewDirectionW + vLightPosition2); + float normalSpecComp2 = max(0., dot(finalNormal, angleW)); + normalSpecComp2 = pow(normalSpecComp2, max(1., 128.)) * modelNormalSpec; + + vec4 normalSpecFinal = vec4(normalSpecColor, 0.0) * normalSpecComp2; + vec4 specFinal = vec4(color, 0.0) * (specComp2 + specComp3); + +// float snap = fract((-gl_FragCoord.x / resolution.x + gl_FragCoord.y / resolution.y) / 20.0 + .2 * time) > .9 ? 1. : 0.; + + vec4 fragColor = gradientColorFinal + specFinal; + vec4 backgroundColor = texture2D(u_BackgroundTexture, vec2(gradientPosition.x + (gl_FragCoord.x / resolution.x) * gradientPosition.y, gradientPosition.z + (1.0 - (gl_FragCoord.y / resolution.y)) * gradientPosition.w)); + vec4 color4 = mix(backgroundColor, fragColor, diffuse); + if (night) { + angleW = normalize(viewDirectionW + vLightPosition2); + float normalSpecComp = max(0., dot(finalNormal, angleW)); + normalSpecComp = pow(normalSpecComp, max(1., 128.)); + if (normalSpecComp > .2 && modelIndex != 0) { + color4.rgb += vec3(.5) * max(0., vTextureNormal.x) * normalSpecComp; + } + if (modelIndex == 1) { + color4.rgb *= .9; + } else { + color4.rgb += vec3(1.0) * .17; + } + } else { + if (modelIndex == 1) { + if (darken > .5) { + color4.rgb *= vec3(0.78039, 0.77254, 0.95294); + } else { + color4.rgb *= vec3(0.83921, 0.83529, 0.96862); + } + } else { + if (darken > .5) { + color4.rgb *= vec3(.945098, .94117, 1.0); + color4.rgb += vec3(.06) * border; + } + } + } + gl_FragColor = color4 * f_alpha; +} \ No newline at end of file diff --git a/TMessagesProj/src/main/java/androidx/recyclerview/widget/DefaultItemAnimator.java b/TMessagesProj/src/main/java/androidx/recyclerview/widget/DefaultItemAnimator.java index b351c8746b6..5aac333f086 100644 --- a/TMessagesProj/src/main/java/androidx/recyclerview/widget/DefaultItemAnimator.java +++ b/TMessagesProj/src/main/java/androidx/recyclerview/widget/DefaultItemAnimator.java @@ -20,6 +20,7 @@ import android.animation.TimeInterpolator; import android.animation.ValueAnimator; import android.os.Build; +import android.util.Log; import android.view.View; import android.view.ViewPropertyAnimator; import android.view.animation.Interpolator; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/ApplicationLoader.java b/TMessagesProj/src/main/java/org/telegram/messenger/ApplicationLoader.java index e9cbc86b03d..5f0d8d1d1db 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/ApplicationLoader.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/ApplicationLoader.java @@ -41,6 +41,7 @@ import org.telegram.messenger.voip.VideoCapturerDevice; import org.telegram.tgnet.ConnectionsManager; import org.telegram.tgnet.TLRPC; +import org.telegram.ui.ActionBar.BaseFragment; import org.telegram.ui.Adapters.DrawerLayoutAdapter; import org.telegram.ui.Components.ForegroundDetector; import org.telegram.ui.Components.Premium.boosts.BoostRepository; @@ -606,7 +607,7 @@ public void processUpdate(int currentAccount, TLRPC.Update update) { } - public boolean onSuggestionFill(String suggestion, String[] output, boolean[] closeable) { + public boolean onSuggestionFill(String suggestion, CharSequence[] output, boolean[] closeable) { return false; } @@ -626,4 +627,16 @@ public boolean consumePush(int account, JSONObject json) { return false; } + public void onResume() { + + } + + public boolean onPause() { + return false; + } + + public BaseFragment openSettings(int n) { + return null; + } + } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/ChatObject.java b/TMessagesProj/src/main/java/org/telegram/messenger/ChatObject.java index 5168aafb352..f7bc863d778 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/ChatObject.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/ChatObject.java @@ -1727,14 +1727,14 @@ public static boolean isBoosted(TLRPC.ChatFull chatFull) { return chatFull != null && chatFull.boosts_applied > 0; } - public static boolean isGroupAndSupportBoost(TLRPC.Chat chat) { - return isMegagroup(chat); - } - public static boolean isForum(TLRPC.Chat chat) { return chat != null && chat.forum; } + public static boolean hasStories(TLRPC.Chat chat) { + return chat != null && MessagesController.getInstance(UserConfig.selectedAccount).getStoriesController().hasStories(-chat.id); + } + public static boolean isMegagroup(int currentAccount, long chatId) { TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(chatId); return ChatObject.isChannel(chat) && chat.megagroup; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/ContactsController.java b/TMessagesProj/src/main/java/org/telegram/messenger/ContactsController.java index 2c6bfd3eb73..bc9e83e613c 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/ContactsController.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/ContactsController.java @@ -15,6 +15,7 @@ import android.content.ContentProviderResult; import android.content.ContentResolver; import android.content.ContentValues; +import android.content.Context; import android.content.SharedPreferences; import android.content.pm.PackageManager; import android.database.ContentObserver; @@ -36,6 +37,7 @@ import org.telegram.tgnet.ConnectionsManager; import org.telegram.tgnet.TLObject; import org.telegram.tgnet.TLRPC; +import org.telegram.ui.ActionBar.BaseFragment; import org.telegram.ui.Components.Bulletin; import java.text.CollationKey; @@ -2454,6 +2456,52 @@ public void addContact(TLRPC.User user, boolean exception) { }, ConnectionsManager.RequestFlagFailOnServerErrors | ConnectionsManager.RequestFlagCanCompress); } + public void deleteContactsUndoable(Context context, BaseFragment fragment, final ArrayList users) { + if (users == null || users.isEmpty()) { + return; + } + + HashMap deletedContacts = new HashMap<>(); + + for (int i = 0, N = users.size(); i < N; i++) { + TLRPC.User user = users.get(i); + TLRPC.TL_contact contact = contactsDict.get(user.id); + + user.contact = false; + contacts.remove(contact); + contactsDict.remove(user.id); + + deletedContacts.put(user, contact); + } + buildContactsSectionsArrays(false); + getNotificationCenter().postNotificationName(NotificationCenter.updateInterfaces, MessagesController.UPDATE_MASK_NAME); + getNotificationCenter().postNotificationName(NotificationCenter.contactsDidLoad); + + Bulletin.SimpleLayout layout = new Bulletin.SimpleLayout(context, fragment.getResourceProvider()); + layout.setTimer(); + layout.textView.setText(LocaleController.formatPluralString("ContactsDeletedUndo", deletedContacts.size())); + Bulletin.UndoButton undoButton = new Bulletin.UndoButton(context, true, true, fragment.getResourceProvider()); + undoButton.setUndoAction(() -> { + for (HashMap.Entry entry : deletedContacts.entrySet()) { + TLRPC.User user = entry.getKey(); + TLRPC.TL_contact contact = entry.getValue(); + + user.contact = true; + contacts.add(contact); + contactsDict.put(user.id, contact); + } + buildContactsSectionsArrays(true); + getNotificationCenter().postNotificationName(NotificationCenter.updateInterfaces, MessagesController.UPDATE_MASK_NAME); + getNotificationCenter().postNotificationName(NotificationCenter.contactsDidLoad); + }); + undoButton.setDelayedAction(() -> { + deleteContact(users, false); + }); + layout.setButton(undoButton); + Bulletin bulletin = Bulletin.make(fragment, layout, Bulletin.DURATION_PROLONG); + bulletin.show(); + } + public void deleteContact(final ArrayList users, boolean showBulletin) { if (users == null || users.isEmpty()) { return; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/DatabaseMigrationHelper.java b/TMessagesProj/src/main/java/org/telegram/messenger/DatabaseMigrationHelper.java index 72d9b98974a..90976a4433f 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/DatabaseMigrationHelper.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/DatabaseMigrationHelper.java @@ -1427,6 +1427,54 @@ public static int migrate(MessagesStorage messagesStorage, int version) throws E version = 143; } + if (version == 143) { + database.executeFast("ALTER TABLE dialog_filter ADD COLUMN color INTEGER default -1").stepThis().dispose(); + database.executeFast("PRAGMA user_version = 144").stepThis().dispose(); + version = 144; + } + + if (version == 144) { +// database.executeFast("CREATE TABLE business_messages(mid INTEGER, type INTEGER, topic_id INTEGER, send_state INTEGER, date INTEGER, data BLOB, ttl INTEGER, replydata BLOB, reply_to_message_id INTEGER, PRIMARY KEY(mid, type))").stepThis().dispose(); +// database.executeFast("CREATE INDEX IF NOT EXISTS send_state_idx_business_messages ON business_messages(mid, send_state, date);").stepThis().dispose(); +// database.executeFast("CREATE INDEX IF NOT EXISTS type_topic_date_idx_business_messages ON business_messages(type, topic_id, date);").stepThis().dispose(); +// database.executeFast("CREATE INDEX IF NOT EXISTS reply_to_idx_business_messages ON business_messages(mid, reply_to_message_id);").stepThis().dispose(); +// database.executeFast("CREATE INDEX IF NOT EXISTS idx_to_reply_business_messages ON business_messages(reply_to_message_id, mid);").stepThis().dispose(); + + database.executeFast("PRAGMA user_version = 145").stepThis().dispose(); + version = 145; + } + + if (version == 145) { + database.executeFast("CREATE TABLE business_replies(topic_id INTEGER PRIMARY KEY, name TEXT, order_value INTEGER);").stepThis().dispose(); + + database.executeFast("PRAGMA user_version = 146").stepThis().dispose(); + version = 146; + } + + if (version == 146) { + database.executeFast("CREATE TABLE quick_replies_messages(mid INTEGER, topic_id INTEGER, send_state INTEGER, date INTEGER, data BLOB, ttl INTEGER, replydata BLOB, reply_to_message_id INTEGER, PRIMARY KEY(mid, topic_id))").stepThis().dispose(); + database.executeFast("CREATE INDEX IF NOT EXISTS send_state_idx_quick_replies_messages ON quick_replies_messages(mid, send_state, date);").stepThis().dispose(); + database.executeFast("CREATE INDEX IF NOT EXISTS topic_date_idx_quick_replies_messages ON quick_replies_messages(topic_id, date);").stepThis().dispose(); + database.executeFast("CREATE INDEX IF NOT EXISTS reply_to_idx_quick_replies_messages ON quick_replies_messages(mid, reply_to_message_id);").stepThis().dispose(); + database.executeFast("CREATE INDEX IF NOT EXISTS idx_to_reply_quick_replies_messages ON quick_replies_messages(reply_to_message_id, mid);").stepThis().dispose(); + + database.executeFast("PRAGMA user_version = 147").stepThis().dispose(); + version = 147; + } + + if (version == 147) { + database.executeFast("ALTER TABLE business_replies ADD COLUMN count INTEGER default 0").stepThis().dispose(); + + database.executeFast("PRAGMA user_version = 148").stepThis().dispose(); + version = 148; + } + + if (version == 148) { + database.executeFast("ALTER TABLE topics ADD COLUMN edit_date INTEGER default 0").stepThis().dispose(); + database.executeFast("PRAGMA user_version = 149").stepThis().dispose(); + version = 149; + } + return version; } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/FileLoadOperation.java b/TMessagesProj/src/main/java/org/telegram/messenger/FileLoadOperation.java index 7242bc8cc34..e13e9975f31 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/FileLoadOperation.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/FileLoadOperation.java @@ -8,6 +8,8 @@ package org.telegram.messenger; +import android.util.Log; + import org.telegram.messenger.utils.ImmutableByteArrayOutputStream; import org.telegram.tgnet.ConnectionsManager; import org.telegram.tgnet.NativeByteBuffer; @@ -48,6 +50,7 @@ public class FileLoadOperation { public boolean isStory; public void setStream(FileLoadOperationStream stream, boolean streamPriority, long streamOffset) { + FileLog.e("FileLoadOperation " + getFileName() + " setStream(" + stream + ")"); this.stream = stream; this.streamOffset = streamOffset; this.streamPriority = streamPriority; @@ -101,6 +104,8 @@ protected static class RequestInfo { private TLRPC.TL_upload_webFile responseWeb; private TLRPC.TL_upload_cdnFile responseCdn; private boolean forceSmallChunk; + public boolean cancelling, cancelled; + public Runnable whenCancelled; } public static class Range { @@ -140,6 +145,7 @@ private PreloadRange(long o, long l) { private final static int stateFailed = 2; private final static int stateFinished = 3; private final static int stateCanceled = 4; + private final static int stateCancelling = 5; private int downloadChunkSize = 1024 * 32; private int downloadChunkSizeBig = 1024 * 128; @@ -234,6 +240,7 @@ private PreloadRange(long o, long l) { private boolean requestingCdnOffsets; private ArrayList requestInfos; + private ArrayList cancelledRequestInfos; private ArrayList delayedRequestInfos; private File cacheFileTemp; @@ -760,6 +767,7 @@ protected void removeStreamListener(final FileLoadOperationStream operation) { if (streamListeners == null) { return; } + FileLog.e("FileLoadOperation " + getFileName() + " removing stream listener " + stream); streamListeners.remove(operation); }); } @@ -781,7 +789,7 @@ public void pause() { if (BuildVars.LOGS_ENABLED) { FileLog.d("debug_loading:" + cacheFileFinal.getName() + " pause operation, clear requests"); } - clearOperaion(null, false); + clearOperation(null, false, true); } else { for (int i = 0; i < requestInfos.size(); i++) { ConnectionsManager.getInstance(currentAccount).failNotRunningRequest(requestInfos.get(i).requestToken); @@ -845,9 +853,10 @@ public boolean start(final FileLoadOperationStream stream, final long streamOffs } else { streamStartOffset = streamOffset / currentDownloadChunkSize * currentDownloadChunkSize; } -// if (!streamListeners.contains(stream)) { -// streamListeners.add(stream); -// } + if (!streamListeners.contains(stream)) { + streamListeners.add(stream); + FileLog.e("FileLoadOperation " + getFileName() + " start, adding stream " + stream); + } if (alreadyStarted) { if (preloadedBytesRanges != null && getDownloadedLengthFromOffsetInternal(notLoadedBytesRanges, streamStartOffset, 1) == 0) { if (preloadedBytesRanges.get(streamStartOffset) != null) { @@ -948,6 +957,7 @@ public boolean start(final FileLoadOperationStream stream, final long streamOffs } requestInfos = new ArrayList<>(currentMaxDownloadRequests); + cancelledRequestInfos = new ArrayList<>(); delayedRequestInfos = new ArrayList<>(currentMaxDownloadRequests - 1); state = stateDownloading; @@ -1264,6 +1274,7 @@ public void setIsPreloadVideoOperation(boolean value) { if (isPreloadVideoOperation == value || value && totalBytesCount <= preloadMaxBytes) { return; } + FileLog.e("setIsPreloadVideoOperation " + value + " file=" + fileName); if (!value && isPreloadVideoOperation) { if (state == stateFinished) { isPreloadVideoOperation = value; @@ -1273,7 +1284,7 @@ public void setIsPreloadVideoOperation(boolean value) { } else if (state == stateDownloading) { Utilities.stageQueue.postRunnable(() -> { requestedBytesCount = 0; - clearOperaion(null, true); + clearOperation(null, true, true); isPreloadVideoOperation = value; startDownloadRequest(-1); }); @@ -1300,8 +1311,12 @@ public void cancel() { private void cancel(boolean deleteFiles) { Utilities.stageQueue.postRunnable(() -> { if (state != stateFinished && state != stateFailed) { - cancelRequests(); - onFail(false, 1); + state = stateCancelling; + cancelRequests(() -> { + if (state == stateCancelling) { + onFail(false, 1); + } + }); } if (deleteFiles) { if (cacheFileFinal != null) { @@ -1353,13 +1368,36 @@ private void cancel(boolean deleteFiles) { }); } - private void cancelRequests() { + private void cancelRequests(Runnable fullyCancelled) { + FileLog.d("cancelRequests" + (fullyCancelled != null ? " with callback" : "")); if (requestInfos != null) { + int[] waitingForCancelledCount = new int[1]; int[] waitingDownloadSize = new int[2]; for (int a = 0; a < requestInfos.size(); a++) { RequestInfo requestInfo = requestInfos.get(a); if (requestInfo.requestToken != 0) { - ConnectionsManager.getInstance(currentAccount).cancelRequest(requestInfo.requestToken, true); + requestInfo.cancelling = true; + if (fullyCancelled == null) { + requestInfo.cancelled = true; + FileLog.d("cancelRequests cancel " + requestInfo.requestToken); + ConnectionsManager.getInstance(currentAccount).cancelRequest(requestInfo.requestToken, true); + } else { + requestInfo.whenCancelled = () -> { + requestInfo.whenCancelled = null; + requestInfo.cancelled = true; + waitingForCancelledCount[0]--; + if (waitingForCancelledCount[0] == 0) { + fullyCancelled.run(); + } + }; + waitingForCancelledCount[0]++; + FileLog.d("cancelRequests cancel " + requestInfo.requestToken + " with callback"); + ConnectionsManager.getInstance(currentAccount).cancelRequest(requestInfo.requestToken, true, () -> { + if (requestInfo.whenCancelled != null) { + requestInfo.whenCancelled.run(); + } + }); + } int index = requestInfo.connectionType == ConnectionsManager.ConnectionTypeDownload ? 0 : 1; waitingDownloadSize[index] += requestInfo.chunkSize; } @@ -1371,7 +1409,6 @@ private void cancelRequests() { ConnectionsManager.getInstance(currentAccount).discardConnection(datacenterId, connectionType); } } - } } @@ -1462,7 +1499,7 @@ private void cleanup() { } private void onFinishLoadingFile(final boolean increment, int finishCode, boolean preload) { - if (state != stateDownloading) { + if (state != stateDownloading && state != stateCancelling) { return; } state = stateFinished; @@ -1729,9 +1766,9 @@ private void requestFileOffsets(long offset) { } protected boolean processRequestResult(RequestInfo requestInfo, TLRPC.TL_error error) { - if (state != stateDownloading) { + if (state != stateDownloading && state != stateCancelling) { if (BuildVars.DEBUG_VERSION && state == stateFinished) { - FileLog.e(new FileLog.IgnoreSentException("trying to write to finished file " + fileName + " offset " + requestInfo.offset + " " + totalBytesCount)); + FileLog.e(new FileLog.IgnoreSentException("trying to write to finished file " + fileName + " offset " + requestInfo.offset + " " + totalBytesCount + " reqToken="+requestInfo.requestToken+" (state=" + state + ")")); } return false; } @@ -1957,7 +1994,7 @@ protected boolean processRequestResult(RequestInfo requestInfo, TLRPC.TL_error e if (finishedDownloading) { onFinishLoadingFile(true, FINISH_CODE_DEFAULT, finishPreload); - } else if (state != stateCanceled) { + } else if (state != stateCanceled && state != stateCancelling) { startDownloadRequest(requestInfo.connectionType); } } catch (Exception e) { @@ -1973,6 +2010,9 @@ protected boolean processRequestResult(RequestInfo requestInfo, TLRPC.TL_error e } } else { if (error.text.contains("LIMIT_INVALID") && !requestInfo.forceSmallChunk) { + if (requestInfo.whenCancelled != null) { + requestInfo.whenCancelled.run(); + } removePart(notRequestedBytesRanges, requestInfo.offset, requestInfo.offset + requestInfo.chunkSize); if (!forceSmallChunk) { forceSmallChunk = true; @@ -2060,7 +2100,7 @@ protected void onFail(boolean thread, final int reason) { } } - private void clearOperaion(RequestInfo currentInfo, boolean preloadChanged) { + private void clearOperation(RequestInfo currentInfo, boolean preloadChanged, boolean acceptChunksAfterCancel) { long minOffset = Long.MAX_VALUE; int[] waitingDownloadSize = new int[2]; for (int a = 0; a < requestInfos.size(); a++) { @@ -2075,7 +2115,23 @@ private void clearOperaion(RequestInfo currentInfo, boolean preloadChanged) { continue; } if (info.requestToken != 0) { - ConnectionsManager.getInstance(currentAccount).cancelRequest(info.requestToken, true); + info.cancelling = true; + if (acceptChunksAfterCancel) { + cancelledRequestInfos.add(info); + info.whenCancelled = () -> { + info.whenCancelled = null; + cancelledRequestInfos.remove(info); + info.cancelled = true; + }; + ConnectionsManager.getInstance(currentAccount).cancelRequest(info.requestToken, true, () -> { + if (info.whenCancelled != null) { + info.whenCancelled.run(); + } + }); + } else { + ConnectionsManager.getInstance(currentAccount).cancelRequest(info.requestToken, true); + info.cancelled = true; + } } } for (int i = 0; i < 2; i++) { @@ -2118,7 +2174,7 @@ private void requestReference(RequestInfo requestInfo) { if (requestingReference) { return; } - clearOperaion(null, false); + clearOperation(null, false, false); requestingReference = true; if (parentObject instanceof MessageObject) { MessageObject messageObject = (MessageObject) parentObject; @@ -2142,6 +2198,9 @@ protected void startDownloadRequest(int useConnectionType) { if (BuildVars.LOGS_ENABLED && FULL_LOGS) { FileLog.d(fileName + " startDownloadRequest"); } + if (state == stateCancelling) { + state = stateDownloading; + } if (paused || reuploadingCdn || state != stateDownloading || requestingReference || (!isStory && streamPriorityStartOffset == 0 && (!nextPartWasPreloaded && (requestInfos.size() + delayedRequestInfos.size() >= currentMaxDownloadRequests))) || (isPreloadVideoOperation && (requestedBytesCount > preloadMaxBytes || moovFound != 0 && requestInfos.size() > 0))) { @@ -2338,11 +2397,45 @@ protected void startDownloadRequest(int useConnectionType) { if (BuildVars.LOGS_ENABLED) { requestInfo.requestStartTime = System.currentTimeMillis(); } + flags |= ConnectionsManager.RequestFlagListenAfterCancel; int datacenterId = isCdn ? cdnDatacenterId : this.datacenterId; requestInfo.requestToken = ConnectionsManager.getInstance(currentAccount).sendRequestSync(request, (response, error) -> { - if (!requestInfos.contains(requestInfo)) { + if (requestInfo.cancelled) { + FileLog.e("received chunk but definitely cancelled offset=" + requestInfo.offset + " size=" + requestInfo.chunkSize + " token=" + requestInfo.requestToken); return; } + if (requestInfo.cancelling) { + FileLog.e("received cancelled chunk after cancelRequests! offset=" + requestInfo.offset + " size=" + requestInfo.chunkSize + " token=" + requestInfo.requestToken); + } + if (!requestInfos.contains(requestInfo)) { + if (!cancelledRequestInfos.contains(requestInfo)) { + return; + } + + boolean replaced = false; + for (int i = 0; i < requestInfos.size(); ++i) { + RequestInfo r = requestInfos.get(i); + if (r != null && r != requestInfo && r.offset == requestInfo.offset && r.chunkSize == requestInfo.chunkSize) { + FileLog.e("received cancelled chunk faster than new one! received=" + requestInfo.requestToken + " new=" + r.requestToken); + if (!replaced) { + requestInfos.set(i, requestInfo); + replaced = true; + } else { + requestInfos.remove(i); + i--; + } + } + } + } + for (int i = 0; i < cancelledRequestInfos.size(); ++i) { + RequestInfo r = cancelledRequestInfos.get(i); + if (r != null && r != requestInfo && r.offset == requestInfo.offset && r.chunkSize == requestInfo.chunkSize) { + FileLog.e("received new chunk faster than cancelled one! received=" + requestInfo.requestToken + " cancelled=" + r.requestToken); + cancelledRequestInfos.remove(i); + i--; + } + } + if (BuildVars.LOGS_ENABLED) { FileLog.d("debug_loading: " + cacheFileFinal.getName() + " time=" + (System.currentTimeMillis() - requestInfo.requestStartTime) + " dcId=" + datacenterId + " cdn=" + isCdn + " conType=" + connectionType + " reqId" + requestInfo.requestToken); } @@ -2353,6 +2446,9 @@ protected void startDownloadRequest(int useConnectionType) { priorityRequestInfo = null; } if (error != null) { + if (requestInfo.whenCancelled != null) { + requestInfo.whenCancelled.run(); + } if (error.code == -2000) { requestInfos.remove(requestInfo); requestedBytesCount -= requestInfo.chunkSize; @@ -2364,7 +2460,7 @@ protected void startDownloadRequest(int useConnectionType) { } else if (request instanceof TLRPC.TL_upload_getCdnFile) { if (error.text.equals("FILE_TOKEN_INVALID")) { isCdn = false; - clearOperaion(requestInfo, false); + clearOperation(requestInfo, false, false); startDownloadRequest(connectionType); return; } @@ -2382,6 +2478,9 @@ protected void startDownloadRequest(int useConnectionType) { } } if (res.encryption_iv == null || res.encryption_key == null || res.encryption_iv.length != 16 || res.encryption_key.length != 32) { + if (requestInfo.whenCancelled != null) { + requestInfo.whenCancelled.run(); + } error = new TLRPC.TL_error(); error.text = "bad redirect response"; error.code = 400; @@ -2396,12 +2495,12 @@ protected void startDownloadRequest(int useConnectionType) { cdnIv = res.encryption_iv; cdnKey = res.encryption_key; cdnToken = res.file_token; - clearOperaion(requestInfo, false); + clearOperation(requestInfo, false, false); startDownloadRequest(connectionType); } } else if (response instanceof TLRPC.TL_upload_cdnFileReuploadNeeded) { if (!reuploadingCdn) { - clearOperaion(requestInfo, false); + clearOperation(requestInfo, false, false); reuploadingCdn = true; TLRPC.TL_upload_cdnFileReuploadNeeded res = (TLRPC.TL_upload_cdnFileReuploadNeeded) response; TLRPC.TL_upload_reuploadCdnFile req = new TLRPC.TL_upload_reuploadCdnFile(); @@ -2424,7 +2523,7 @@ protected void startDownloadRequest(int useConnectionType) { } else { if (error1.text.equals("FILE_TOKEN_INVALID") || error1.text.equals("REQUEST_TOKEN_INVALID")) { isCdn = false; - clearOperaion(requestInfo, false); + clearOperation(requestInfo, false, false); startDownloadRequest(connectionType); } else { onFail(false, 0); @@ -2459,6 +2558,9 @@ protected void startDownloadRequest(int useConnectionType) { } } processRequestResult(requestInfo, error); + if (requestInfo.whenCancelled != null) { + requestInfo.whenCancelled.run(); + } } }, null, null, flags, datacenterId, connectionType, isLast); if (BuildVars.LOGS_ENABLED) { diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/FileLoader.java b/TMessagesProj/src/main/java/org/telegram/messenger/FileLoader.java index 948cfdcb143..aefe3e522ff 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/FileLoader.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/FileLoader.java @@ -727,7 +727,7 @@ public void loadFile(WebFile document, int priority, int cacheType) { } - private FileLoadOperation loadFileInternal(final TLRPC.Document document, final SecureDocument secureDocument, final WebFile webDocument, TLRPC.TL_fileLocationToBeDeprecated location, final ImageLocation imageLocation, Object parentObject, final String locationExt, final long locationSize, int priority, final FileLoadOperationStream stream, final long streamOffset, boolean streamPriority, final int cacheType) { + private FileLoadOperation loadFileInternal(final TLRPC.Document document, final SecureDocument secureDocument, final WebFile webDocument, TLRPC.TL_fileLocationToBeDeprecated location, final ImageLocation imageLocation, Object parentObject, final String locationExt, final long locationSize, int priority, FileLoadOperationStream stream, final long streamOffset, boolean streamPriority, final int cacheType) { String fileName; if (location != null) { fileName = getAttachFileName(location, locationExt); @@ -976,6 +976,9 @@ public boolean isLocallyCreatedFile(String path) { loadOperationPaths.put(finalFileName, operation); operation.setPriority(priority); + if (stream == null) { + stream = FileStreamLoadOperation.allStreams.get(documentId); + } if (stream != null) { operation.setStream(stream, streamPriority, streamOffset); } @@ -984,7 +987,7 @@ public boolean isLocallyCreatedFile(String path) { loaderQueue.checkLoadingOperations(operation.isStory && priority >= FileLoaderPriorityQueue.PRIORITY_VALUE_MAX); if (BuildVars.LOGS_ENABLED) { - FileLog.d("create load operation fileName=" + finalFileName + " documentName=" + getDocumentFileName(document) + " size=" + AndroidUtilities.formatFileSize(operation.totalBytesCount) + " position in queue " + operation.getPositionInQueue() + " account=" + currentAccount + " cacheType=" + cacheType + " priority=" + operation.getPriority()); + FileLog.d("create load operation fileName=" + finalFileName + " documentName=" + getDocumentFileName(document) + " size=" + AndroidUtilities.formatFileSize(operation.totalBytesCount) + " position in queue " + operation.getPositionInQueue() + " account=" + currentAccount + " cacheType=" + cacheType + " priority=" + operation.getPriority() + " stream=" + stream); } return operation; } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/FileLoaderPriorityQueue.java b/TMessagesProj/src/main/java/org/telegram/messenger/FileLoaderPriorityQueue.java index 9cb0eb75605..2f8ff93f86a 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/FileLoaderPriorityQueue.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/FileLoaderPriorityQueue.java @@ -97,7 +97,7 @@ private void checkLoadingOperationInternal() { FileLoadOperation operation = allOperations.get(i); if (i > 0 && !pauseAllNextOperations) { if (type == TYPE_LARGE) { - if (prevOperation != null && prevOperation.isStory && prevOperation.getPriority() >= PRIORITY_VALUE_MAX) { + if (prevOperation != null && prevOperation.isStory && prevOperation.getPriority() >= PRIORITY_VALUE_MAX && operation.getPriority() <= PRIORITY_VALUE_LOW) { pauseAllNextOperations = true; } } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/FileStreamLoadOperation.java b/TMessagesProj/src/main/java/org/telegram/messenger/FileStreamLoadOperation.java index dbe256405c5..683cbdc2376 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/FileStreamLoadOperation.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/FileStreamLoadOperation.java @@ -32,6 +32,8 @@ public class FileStreamLoadOperation extends BaseDataSource implements FileLoadOperationStream { + public static final ConcurrentHashMap allStreams = new ConcurrentHashMap<>(); + private FileLoadOperation loadOperation; private Uri uri; @@ -91,6 +93,7 @@ public long open(DataSpec dataSpec) throws IOException { } else if (document.mime_type.startsWith("audio")) { document.attributes.add(new TLRPC.TL_documentAttributeAudio()); } + allStreams.put(document.id, this); loadOperation = FileLoader.getInstance(currentAccount).loadStreamFile(this, document, null, parentObject, currentOffset = dataSpec.position, false, getCurrentPriority()); bytesRemaining = dataSpec.length == C.LENGTH_UNSET ? document.size - dataSpec.position : dataSpec.length; if (bytesRemaining < 0) { @@ -111,6 +114,7 @@ public long open(DataSpec dataSpec) throws IOException { } } } +// FileLog.e("FileStreamLoadOperation " + document.id + " open operation=" + loadOperation + " currentFile=" + currentFile + " file=" + file + " bytesRemaining=" + bytesRemaining + " me=" + this); return bytesRemaining; } @@ -125,8 +129,10 @@ private int getCurrentPriority() { @Override public int read(byte[] buffer, int offset, int readLength) throws IOException { if (readLength == 0) { +// FileLog.e("FileStreamLoadOperation " + document.id + " read 0 return"); return 0; } else if (bytesRemaining == 0) { +// FileLog.e("FileStreamLoadOperation " + document.id + " read RESULT_END_OF_INPUT"); return C.RESULT_END_OF_INPUT; } else { int availableLength = 0; @@ -141,14 +147,17 @@ public int read(byte[] buffer, int offset, int readLength) throws IOException { countDownLatch = new CountDownLatch(1); FileLoadOperation loadOperation = FileLoader.getInstance(currentAccount).loadStreamFile(this, document, null, parentObject, currentOffset, false, getCurrentPriority()); if (this.loadOperation != loadOperation) { +// FileLog.e("FileStreamLoadOperation " + document.id + " read: changed operation!"); this.loadOperation.removeStreamListener(this); this.loadOperation = loadOperation; } +// FileLog.e("FileStreamLoadOperation " + document.id + " read sleeping.... Zzz"); if (countDownLatch != null) { countDownLatch.await(); countDownLatch = null; } } +// FileLog.e("FileStreamLoadOperation " + document.id + " read availableLength=" + availableLength); File currentFileFast = loadOperation.getCurrentFileFast(); if (file == null || !Objects.equals(currentFile, currentFileFast)) { if (BuildVars.LOGS_ENABLED) { @@ -161,6 +170,7 @@ public int read(byte[] buffer, int offset, int readLength) throws IOException { } } +// FileLog.e("FileStreamLoadOperation " + document.id + " read update file from " + currentFile + " to " + currentFileFast + " me=" + this); currentFile = currentFileFast; if (currentFile != null) { try { @@ -173,9 +183,12 @@ public int read(byte[] buffer, int offset, int readLength) throws IOException { } } + } else { +// FileLog.e("FileStreamLoadOperation " + document.id + " read have exact same file"); } } if (!opened) { +// FileLog.e("FileStreamLoadOperation " + document.id + " read return, not opened"); return 0; } bytesRead = file.read(buffer, offset, availableLength); @@ -198,6 +211,7 @@ public Uri getUri() { @Override public void close() { +// FileLog.e("FileStreamLoadOperation " + document.id + " close me=" + this); if (loadOperation != null) { loadOperation.removeStreamListener(this); } @@ -210,6 +224,7 @@ public void close() { file = null; } uri = null; + allStreams.remove(document.id); if (opened) { opened = false; transferEnded(); @@ -223,6 +238,7 @@ public void close() { @Override public void newDataAvailable() { +// FileLog.e("FileStreamLoadOperation " + document.id + " newDataAvailable me=" + this); if (countDownLatch != null) { countDownLatch.countDown(); countDownLatch = null; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/GoogleMapsProvider.java b/TMessagesProj/src/main/java/org/telegram/messenger/GoogleMapsProvider.java index 5f483178087..cb418e1c1d2 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/GoogleMapsProvider.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/GoogleMapsProvider.java @@ -5,9 +5,11 @@ import android.graphics.Bitmap; import android.graphics.Point; import android.location.Location; +import android.opengl.GLSurfaceView; import android.os.Bundle; import android.view.MotionEvent; import android.view.View; +import android.view.ViewGroup; import androidx.core.util.Consumer; @@ -533,6 +535,8 @@ public final static class GoogleMapView implements IMapView { private ITouchInterceptor interceptInterceptor; private Runnable onLayoutListener; + private GLSurfaceView glSurfaceView; + private GoogleMapView(Context context) { mapView = new MapView(context) { @Override @@ -583,7 +587,28 @@ public View getView() { @Override public void getMapAsync(Consumer callback) { - mapView.getMapAsync(googleMap -> callback.accept(new GoogleMapImpl(googleMap))); + mapView.getMapAsync(googleMap -> { + callback.accept(new GoogleMapImpl(googleMap)); + findGlSurfaceView(mapView); + }); + } + + @Override + public GLSurfaceView getGlSurfaceView() { + return glSurfaceView; + } + + private void findGlSurfaceView(View v) { + if (v instanceof GLSurfaceView) { + glSurfaceView = (GLSurfaceView) v; + } + + if (v instanceof ViewGroup) { + ViewGroup vg = (ViewGroup) v; + for (int i = 0; i < vg.getChildCount(); i++) { + findGlSurfaceView(vg.getChildAt(i)); + } + } } @Override diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/LocaleController.java b/TMessagesProj/src/main/java/org/telegram/messenger/LocaleController.java index c1aadfada11..5dd423042b8 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/LocaleController.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/LocaleController.java @@ -34,6 +34,9 @@ import java.io.FileInputStream; import java.io.FileWriter; import java.text.NumberFormat; +import java.time.Instant; +import java.time.ZoneId; +import java.time.format.TextStyle; import java.util.ArrayList; import java.util.Calendar; import java.util.Collection; @@ -57,6 +60,7 @@ public class LocaleController { public static int nameDisplayOrder = 1; public static boolean is24HourFormat = false; public FastDateFormat formatterDay; + public FastDateFormat formatterConstDay; public FastDateFormat formatterWeek; public FastDateFormat formatterWeekLong; public FastDateFormat formatterDayMonth; @@ -1865,7 +1869,7 @@ public static String formatStatusExpireDateTime(long date) { return "LOC_ERR"; } - public static String formatDateTime(long date) { + public static String formatDateTime(long date, boolean useToday) { try { date *= 1000; Calendar rightNow = Calendar.getInstance(); @@ -1875,9 +1879,9 @@ public static String formatDateTime(long date) { int dateDay = rightNow.get(Calendar.DAY_OF_YEAR); int dateYear = rightNow.get(Calendar.YEAR); - if (dateDay == day && year == dateYear) { + if (dateDay == day && year == dateYear && useToday) { return LocaleController.formatString("TodayAtFormattedWithToday", R.string.TodayAtFormattedWithToday, getInstance().formatterDay.format(new Date(date))); - } else if (dateDay + 1 == day && year == dateYear) { + } else if (dateDay + 1 == day && year == dateYear && useToday) { return LocaleController.formatString("YesterdayAtFormatted", R.string.YesterdayAtFormatted, getInstance().formatterDay.format(new Date(date))); } else if (Math.abs(System.currentTimeMillis() - date) < 31536000000L) { return LocaleController.formatString("formatDateAtTime", R.string.formatDateAtTime, getInstance().chatDate.format(new Date(date)), getInstance().formatterDay.format(new Date(date))); @@ -1890,6 +1894,20 @@ public static String formatDateTime(long date) { return "LOC_ERR"; } + public static String formatShortDateTime(long date) { + try { + date *= 1000; + if (Math.abs(System.currentTimeMillis() - date) < 31536000000L) { + return getInstance().formatterScheduleDay.format(new Date(date)) + ", " + getInstance().formatterDay.format(new Date(date)); + } else { + return getInstance().formatterScheduleYear.format(new Date(date)) + ", " + getInstance().formatterDay.format(new Date(date)); + } + } catch (Exception e) { + FileLog.e(e); + } + return "LOC_ERR"; + } + public static String formatLocationUpdateDate(long date) { try { date *= 1000; @@ -2028,6 +2046,7 @@ public void recreateFormatters() { formatterScheduleDay = createFormatter(locale, getStringInternal("formatDateSchedule", R.string.formatDateSchedule), "MMM d"); formatterScheduleYear = createFormatter(locale, getStringInternal("formatDateScheduleYear", R.string.formatDateScheduleYear), "MMM d yyyy"); formatterDay = createFormatter(lang.toLowerCase().equals("ar") || lang.toLowerCase().equals("ko") ? locale : Locale.US, is24HourFormat ? getStringInternal("formatterDay24H", R.string.formatterDay24H) : getStringInternal("formatterDay12H", R.string.formatterDay12H), is24HourFormat ? "HH:mm" : "h:mm a"); + formatterConstDay = createFormatter(lang.toLowerCase().equals("ar") || lang.toLowerCase().equals("ko") ? locale : Locale.US, is24HourFormat ? "HH:mm" : "h:mm a", is24HourFormat ? "HH:mm" : "h:mm a"); formatterStats = createFormatter(locale, is24HourFormat ? getStringInternal("formatterStats24H", R.string.formatterStats24H) : getStringInternal("formatterStats12H", R.string.formatterStats12H), is24HourFormat ? "MMM dd yyyy, HH:mm" : "MMM dd yyyy, h:mm a"); formatterBannedUntil = createFormatter(locale, is24HourFormat ? getStringInternal("formatterBannedUntil24H", R.string.formatterBannedUntil24H) : getStringInternal("formatterBannedUntil12H", R.string.formatterBannedUntil12H), is24HourFormat ? "MMM dd yyyy, HH:mm" : "MMM dd yyyy, h:mm a"); formatterBannedUntilThisYear = createFormatter(locale, is24HourFormat ? getStringInternal("formatterBannedUntilThisYear24H", R.string.formatterBannedUntilThisYear24H) : getStringInternal("formatterBannedUntilThisYear12H", R.string.formatterBannedUntilThisYear12H), is24HourFormat ? "MMM dd, HH:mm" : "MMM dd, h:mm a"); @@ -3565,4 +3584,17 @@ private void patched(String lng) { } MessagesController.getGlobalMainSettings().edit().putBoolean("lngpack_patched_" + lng, true).apply(); } + + public static String getTimeZoneName(String timeZoneId, boolean full) { + TimeZone timeZone = TimeZone.getTimeZone(timeZoneId); + if (timeZone == null) return ""; + String name = timeZone.getDisplayName(true, TimeZone.SHORT, getInstance().getCurrentLocale()); + if (full) { + String longname = timeZone.getDisplayName(true, TimeZone.LONG, getInstance().getCurrentLocale()); + if (!TextUtils.equals(longname, name)) { + name = longname + ", " + name; + } + } + return name; + } } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/LocationController.java b/TMessagesProj/src/main/java/org/telegram/messenger/LocationController.java index eee5cd401c6..be0e391901e 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/LocationController.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/LocationController.java @@ -1001,8 +1001,13 @@ public interface LocationFetchCallback { void onLocationAddressAvailable(String address, String displayAddress, TLRPC.TL_messageMediaVenue city, TLRPC.TL_messageMediaVenue street, Location location); } + public static final int TYPE_BIZ = 1; + private static HashMap callbacks = new HashMap<>(); public static void fetchLocationAddress(Location location, LocationFetchCallback callback) { + fetchLocationAddress(location, 0, callback); + } + public static void fetchLocationAddress(Location location, int type, LocationFetchCallback callback) { if (callback == null) { return; } @@ -1033,16 +1038,65 @@ public static void fetchLocationAddress(Location location, LocationFetchCallback List
addresses = gcd.getFromLocation(location.getLatitude(), location.getLongitude(), 1); if (addresses.size() > 0) { Address address = addresses.get(0); - boolean hasAny = false; - String arg; + if (type == TYPE_BIZ) { + ArrayList parts = new ArrayList<>(); + + String arg = null; + try { + arg = address.getAddressLine(0); + } catch (Exception ignore) {} + if (TextUtils.isEmpty(arg)) { + try { + parts.add(address.getSubThoroughfare()); + } catch (Exception ignore) {} + try { + parts.add(address.getThoroughfare()); + } catch (Exception ignore) {} + try { + parts.add(address.getAdminArea()); + } catch (Exception ignore) {} + try { + parts.add(address.getCountryName()); + } catch (Exception ignore) {} + } else { + parts.add(arg); + } + + for (int i = 0; i < parts.size(); ++i) { + if (parts.get(i) != null) { + String[] partsInside = parts.get(i).split(", "); + if (partsInside.length > 1) { + parts.remove(i); + for (int j = 0; j < partsInside.length; ++j) { + parts.add(i, partsInside[j]); + i++; + } + } + } + } + for (int i = 0; i < parts.size(); ++i) { + if (TextUtils.isEmpty(parts.get(i)) || parts.indexOf(parts.get(i)) != i || parts.get(i).matches("^\\s*\\d{4,}\\s*$")) { + parts.remove(i); + i--; + } + } + + name = displayName = parts.isEmpty() ? null : TextUtils.join(", ", parts); + city = null; + street = null; + countryCode = null; + } else { - StringBuilder nameBuilder = new StringBuilder(); - StringBuilder displayNameBuilder = new StringBuilder(); - StringBuilder cityBuilder = new StringBuilder(); - StringBuilder streetBuilder = new StringBuilder(); + boolean hasAny = false; + String arg; - String locality = null; - String feature = null; + StringBuilder nameBuilder = new StringBuilder(); + StringBuilder displayNameBuilder = new StringBuilder(); + StringBuilder cityBuilder = new StringBuilder(); + StringBuilder streetBuilder = new StringBuilder(); + + String locality = null; + String feature = null; // String addressLine = null; // try { // addressLine = address.getAddressLine(0); @@ -1063,148 +1117,149 @@ public static void fetchLocationAddress(Location location, LocationFetchCallback //// feature = parts[0].replace(",", "").trim(); // } // } - if (TextUtils.isEmpty(locality)) { - locality = address.getLocality(); - } - if (TextUtils.isEmpty(locality)) { - locality = address.getSubAdminArea(); - } - if (TextUtils.isEmpty(locality)) { - locality = address.getAdminArea(); - } - -// if (TextUtils.isEmpty(feature) && !TextUtils.equals(address.getFeatureName(), locality) && !TextUtils.equals(address.getFeatureName(), address.getCountryName())) { -// feature = address.getFeatureName(); -// } - if (TextUtils.isEmpty(feature) && !TextUtils.equals(address.getThoroughfare(), locality) && !TextUtils.equals(address.getThoroughfare(), address.getCountryName())) { - feature = address.getThoroughfare(); - } - if (TextUtils.isEmpty(feature) && !TextUtils.equals(address.getSubLocality(), locality) && !TextUtils.equals(address.getSubLocality(), address.getCountryName())) { - feature = address.getSubLocality(); - } - if (TextUtils.isEmpty(feature) && !TextUtils.equals(address.getLocality(), locality) && !TextUtils.equals(address.getLocality(), address.getCountryName())) { - feature = address.getLocality(); - } - if (!TextUtils.isEmpty(feature) && !TextUtils.equals(feature, locality) && !TextUtils.equals(feature, address.getCountryName())) { - if (streetBuilder.length() > 0) { - streetBuilder.append(", "); + if (TextUtils.isEmpty(locality)) { + locality = address.getLocality(); } - streetBuilder.append(feature); - } else { - streetBuilder = null; - } - if (!TextUtils.isEmpty(locality)) { - if (cityBuilder.length() > 0) { - cityBuilder.append(", "); + if (TextUtils.isEmpty(locality)) { + locality = address.getSubAdminArea(); + } + if (TextUtils.isEmpty(locality)) { + locality = address.getAdminArea(); + } + if (TextUtils.isEmpty(feature) && !TextUtils.equals(address.getThoroughfare(), locality) && !TextUtils.equals(address.getThoroughfare(), address.getCountryName())) { + feature = address.getThoroughfare(); + } + if (TextUtils.isEmpty(feature) && !TextUtils.equals(address.getSubLocality(), locality) && !TextUtils.equals(address.getSubLocality(), address.getCountryName())) { + feature = address.getSubLocality(); + } + if (TextUtils.isEmpty(feature) && !TextUtils.equals(address.getLocality(), locality) && !TextUtils.equals(address.getLocality(), address.getCountryName())) { + feature = address.getLocality(); } - cityBuilder.append(locality); - onlyCountry = false; - if (streetBuilder != null) { + if (!TextUtils.isEmpty(feature) && !TextUtils.equals(feature, locality) && !TextUtils.equals(feature, address.getCountryName())) { if (streetBuilder.length() > 0) { streetBuilder.append(", "); } - streetBuilder.append(locality); + streetBuilder.append(feature); + } else { + streetBuilder = null; + } + if (!TextUtils.isEmpty(locality)) { + if (cityBuilder.length() > 0) { + cityBuilder.append(", "); + } + cityBuilder.append(locality); + onlyCountry = false; + if (streetBuilder != null) { + if (streetBuilder.length() > 0) { + streetBuilder.append(", "); + } + streetBuilder.append(locality); + } } - } - arg = address.getSubThoroughfare(); - if (!TextUtils.isEmpty(arg)) { - nameBuilder.append(arg); - hasAny = true; - } - arg = address.getThoroughfare(); - if (!TextUtils.isEmpty(arg)) { - if (nameBuilder.length() > 0) { - nameBuilder.append(" "); + arg = address.getSubThoroughfare(); + if (!TextUtils.isEmpty(arg)) { + nameBuilder.append(arg); + hasAny = true; } - nameBuilder.append(arg); - hasAny = true; - } - if (!hasAny) { - arg = address.getAdminArea(); + arg = address.getThoroughfare(); if (!TextUtils.isEmpty(arg)) { if (nameBuilder.length() > 0) { - nameBuilder.append(", "); + nameBuilder.append(" "); } nameBuilder.append(arg); + hasAny = true; } - arg = address.getSubAdminArea(); + if (!hasAny) { + arg = address.getAdminArea(); + if (!TextUtils.isEmpty(arg)) { + if (nameBuilder.length() > 0) { + nameBuilder.append(", "); + } + nameBuilder.append(arg); + } + arg = address.getSubAdminArea(); + if (!TextUtils.isEmpty(arg)) { + if (nameBuilder.length() > 0) { + nameBuilder.append(", "); + } + nameBuilder.append(arg); + } + } + arg = address.getLocality(); if (!TextUtils.isEmpty(arg)) { if (nameBuilder.length() > 0) { nameBuilder.append(", "); } nameBuilder.append(arg); } - } - arg = address.getLocality(); - if (!TextUtils.isEmpty(arg)) { - if (nameBuilder.length() > 0) { - nameBuilder.append(", "); - } - nameBuilder.append(arg); - } - countryCode = address.getCountryCode(); - arg = address.getCountryName(); - if (!TextUtils.isEmpty(arg)) { - if (nameBuilder.length() > 0) { - nameBuilder.append(", "); - } - nameBuilder.append(arg); - String shortCountry = arg; - final String lng = finalLocale.getLanguage(); - if (("US".equals(address.getCountryCode()) || "AE".equals(address.getCountryCode())) && ("en".equals(lng) || "uk".equals(lng) || "ru".equals(lng)) || "GB".equals(address.getCountryCode()) && "en".equals(lng)) { - shortCountry = ""; - String[] words = arg.split(" "); - for (String word : words) { - if (word.length() > 0) - shortCountry += word.charAt(0); + countryCode = address.getCountryCode(); + arg = address.getCountryName(); + if (!TextUtils.isEmpty(arg)) { + if (nameBuilder.length() > 0) { + nameBuilder.append(", "); } - } else if ("US".equals(address.getCountryCode())) { - shortCountry = "USA"; - } - if (cityBuilder.length() > 0) { - cityBuilder.append(", "); + nameBuilder.append(arg); + String shortCountry = arg; + final String lng = finalLocale.getLanguage(); + if (("US".equals(address.getCountryCode()) || "AE".equals(address.getCountryCode())) && ("en".equals(lng) || "uk".equals(lng) || "ru".equals(lng)) || "GB".equals(address.getCountryCode()) && "en".equals(lng)) { + shortCountry = ""; + String[] words = arg.split(" "); + for (String word : words) { + if (word.length() > 0) + shortCountry += word.charAt(0); + } + } else if ("US".equals(address.getCountryCode())) { + shortCountry = "USA"; + } + if (cityBuilder.length() > 0) { + cityBuilder.append(", "); + } + cityBuilder.append(shortCountry); } - cityBuilder.append(shortCountry); - } - arg = address.getCountryName(); - if (!TextUtils.isEmpty(arg)) { - if (displayNameBuilder.length() > 0) { - displayNameBuilder.append(", "); - } - displayNameBuilder.append(arg); - } - arg = address.getLocality(); - if (!TextUtils.isEmpty(arg)) { - if (displayNameBuilder.length() > 0) { - displayNameBuilder.append(", "); - } - displayNameBuilder.append(arg); - } - if (!hasAny) { - arg = address.getAdminArea(); + arg = address.getCountryName(); if (!TextUtils.isEmpty(arg)) { if (displayNameBuilder.length() > 0) { displayNameBuilder.append(", "); } displayNameBuilder.append(arg); } - arg = address.getSubAdminArea(); + arg = address.getLocality(); if (!TextUtils.isEmpty(arg)) { if (displayNameBuilder.length() > 0) { displayNameBuilder.append(", "); } displayNameBuilder.append(arg); } - } + if (!hasAny) { + arg = address.getAdminArea(); + if (!TextUtils.isEmpty(arg)) { + if (displayNameBuilder.length() > 0) { + displayNameBuilder.append(", "); + } + displayNameBuilder.append(arg); + } + arg = address.getSubAdminArea(); + if (!TextUtils.isEmpty(arg)) { + if (displayNameBuilder.length() > 0) { + displayNameBuilder.append(", "); + } + displayNameBuilder.append(arg); + } + } - name = nameBuilder.toString(); - displayName = displayNameBuilder.toString(); - city = cityBuilder.toString(); - street = streetBuilder == null ? null : streetBuilder.toString(); + name = nameBuilder.toString(); + displayName = displayNameBuilder.toString(); + city = cityBuilder.toString(); + street = streetBuilder == null ? null : streetBuilder.toString(); + } } else { - name = displayName = String.format(Locale.US, "Unknown address (%f,%f)", location.getLatitude(), location.getLongitude()); + if (type == TYPE_BIZ) { + name = displayName = null; + } else { + name = displayName = String.format(Locale.US, "Unknown address (%f,%f)", location.getLatitude(), location.getLongitude()); + } city = null; street = null; } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/MediaController.java b/TMessagesProj/src/main/java/org/telegram/messenger/MediaController.java index 934b8481a5e..50d831d7a34 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/MediaController.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/MediaController.java @@ -54,8 +54,6 @@ import android.telephony.PhoneStateListener; import android.telephony.TelephonyManager; import android.text.TextUtils; -import android.util.Log; -import android.util.LongSparseArray; import android.util.Pair; import android.util.SparseArray; import android.view.HapticFeedbackConstants; @@ -772,6 +770,8 @@ public void run() { private MessageObject recordReplyingMsg; private MessageObject recordReplyingTopMsg; private TL_stories.StoryItem recordReplyingStory; + private String recordQuickReplyShortcut; + private int recordQuickReplyShortcutId; public short[] recordSamples = new short[1024]; public long samplesCount; @@ -1951,7 +1951,7 @@ private void raiseToSpeakUpdated(boolean raised) { if (recordingAudio != null) { toggleRecordingPause(false); } else if (raised) { - startRecording(raiseChat.getCurrentAccount(), raiseChat.getDialogId(), null, raiseChat.getThreadMessage(), null, raiseChat.getClassGuid(), false); + startRecording(raiseChat.getCurrentAccount(), raiseChat.getDialogId(), null, raiseChat.getThreadMessage(), null, raiseChat.getClassGuid(), false, raiseChat != null ? raiseChat.quickReplyShortcut : null, raiseChat != null ? raiseChat.getQuickReplyId() : 0); } else { stopRecording(2, false, 0, false); } @@ -1973,7 +1973,7 @@ public void startRecordingIfFromSpeaker() { return; } raiseToEarRecord = true; - startRecording(raiseChat.getCurrentAccount(), raiseChat.getDialogId(), null, raiseChat.getThreadMessage(), null, raiseChat.getClassGuid(), false); + startRecording(raiseChat.getCurrentAccount(), raiseChat.getDialogId(), null, raiseChat.getThreadMessage(), null, raiseChat.getClassGuid(), false, raiseChat != null ? raiseChat.quickReplyShortcut : null, raiseChat != null ? raiseChat.getQuickReplyId() : 0); ignoreOnPause = true; } @@ -3198,7 +3198,7 @@ public boolean playMessage(final MessageObject messageObject, boolean silent) { } return true; } - if (!messageObject.isOut() && messageObject.isContentUnread()) { + if (!messageObject.isOut() && (messageObject.isContentUnread())) { MessagesController.getInstance(messageObject.currentAccount).markMessageContentAsRead(messageObject); } boolean notify = !playMusicAgain; @@ -3829,7 +3829,7 @@ public void requestAudioFocus(boolean request) { } } - public void prepareResumedRecording(int currentAccount, MediaDataController.DraftVoice draft, long dialogId, MessageObject replyToMsg, MessageObject replyToTopMsg, TL_stories.StoryItem replyStory, int guid, boolean manual) { + public void prepareResumedRecording(int currentAccount, MediaDataController.DraftVoice draft, long dialogId, MessageObject replyToMsg, MessageObject replyToTopMsg, TL_stories.StoryItem replyStory, int guid, boolean manual, String query_shortcut, int query_shortcut_id) { manualRecording = manual; requestAudioFocus(true); recordQueue.cancelRunnable(recordStartRunnable); @@ -3871,6 +3871,8 @@ public boolean delete() { recordReplyingMsg = replyToMsg; recordReplyingTopMsg = replyToTopMsg; recordReplyingStory = replyStory; + recordQuickReplyShortcut = query_shortcut; + recordQuickReplyShortcutId = query_shortcut_id; } catch (Exception e) { FileLog.e(e); recordingAudio = null; @@ -3918,12 +3920,15 @@ public boolean delete() { public void toggleRecordingPause(boolean voiceOnce) { recordQueue.postRunnable(() -> { - if (audioRecorder == null || recordingAudio == null || recordingAudioFile == null) { + if (recordingAudio == null || recordingAudioFile == null) { return; } audioRecorderPaused = !audioRecorderPaused; final boolean isPaused = audioRecorderPaused; if (isPaused) { + if (audioRecorder == null) { + return; + } sendAfterDone = 4; audioRecorder.stop(); audioRecorder.release(); @@ -3989,7 +3994,7 @@ public void toggleRecordingPause(boolean voiceOnce) { }); } - public void startRecording(int currentAccount, long dialogId, MessageObject replyToMsg, MessageObject replyToTopMsg, TL_stories.StoryItem replyStory, int guid, boolean manual) { + public void startRecording(int currentAccount, long dialogId, MessageObject replyToMsg, MessageObject replyToTopMsg, TL_stories.StoryItem replyStory, int guid, boolean manual, String quick_shortcut, int quick_shortcut_id) { boolean paused = false; if (playingMessageObject != null && isPlayingMessage(playingMessageObject) && !isMessagePaused()) { paused = true; @@ -4064,6 +4069,8 @@ public boolean delete() { recordReplyingMsg = replyToMsg; recordReplyingTopMsg = replyToTopMsg; recordReplyingStory = replyStory; + recordQuickReplyShortcut = quick_shortcut; + recordQuickReplyShortcutId = quick_shortcut_id; fileBuffer.rewind(); audioRecorder.startRecording(); @@ -4174,6 +4181,8 @@ private void stopRecordingInternal(final int send, boolean notify, int scheduleD if (send == 1) { SendMessagesHelper.SendMessageParams params = SendMessagesHelper.SendMessageParams.of(audioToSend, null, recordingAudioFileToSend.getAbsolutePath(), recordDialogId, recordReplyingMsg, recordReplyingTopMsg, null, null, null, null, notify, scheduleDate, once ? 0x7FFFFFFF : 0, null, null, false); params.replyToStoryItem = recordReplyingStory; + params.quick_reply_shortcut = recordQuickReplyShortcut; + params.quick_reply_shortcut_id = recordQuickReplyShortcutId; SendMessagesHelper.getInstance(recordingCurrentAccount).sendMessage(params); } NotificationCenter.getInstance(recordingCurrentAccount).postNotificationName(NotificationCenter.audioDidSent, recordingGuid, send == 2 ? audioToSend : null, send == 2 ? recordingAudioFileToSend.getAbsolutePath() : null); diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/MediaDataController.java b/TMessagesProj/src/main/java/org/telegram/messenger/MediaDataController.java index 00a969dfbbc..5c2a949a5f0 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/MediaDataController.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/MediaDataController.java @@ -66,6 +66,7 @@ import org.telegram.ui.Components.AnimatedEmojiSpan; import org.telegram.ui.Components.AvatarDrawable; import org.telegram.ui.Components.BackupImageView; +import org.telegram.ui.Components.BotWebViewSheet; import org.telegram.ui.Components.Bulletin; import org.telegram.ui.Components.ChatThemeBottomSheet; import org.telegram.ui.Components.QuoteSpan; @@ -75,7 +76,6 @@ import org.telegram.ui.Components.TextStyleSpan; import org.telegram.ui.Components.URLSpanReplacement; import org.telegram.ui.Components.URLSpanUserMention; -import org.telegram.ui.Components.voip.PrivateVideoPreviewDialog; import org.telegram.ui.LaunchActivity; import org.telegram.ui.PremiumPreviewFragment; import org.telegram.ui.Stories.StoriesStorage; @@ -218,7 +218,7 @@ private void loadRepliesOfDraftReplies(final ArrayList messages) getMessagesStorage().checkSQLException(e); } } - getMessagesStorage().loadReplyMessages(replyMessageOwners, dialogReplyMessagesIds, usersToLoad, chatsToLoad, false); + getMessagesStorage().loadReplyMessages(replyMessageOwners, dialogReplyMessagesIds, usersToLoad, chatsToLoad, 0); } catch (Exception e) { FileLog.e(e); } @@ -589,6 +589,10 @@ public void processLoadedMenuBots(TLRPC.TL_attachMenuBots bots, long hash, int d } } + public boolean isMenuBotsUpdatedLocal() { + return menuBotsUpdatedLocal; + } + public void updateAttachMenuBotsInCache() { if (getAttachMenuBots() != null) { putMenuBotsToCache(getAttachMenuBots(), menuBotsUpdateHash, menuBotsUpdateDate); @@ -1224,6 +1228,7 @@ public void setPlaceholderImage(BackupImageView imageView, String setName, Strin if (document != null) { Drawable thumbDrawable = DocumentObject.getSvgThumb(document, Theme.key_windowBackgroundWhiteGrayIcon, 0.2f, 1f, null); imageView.setImage(ImageLocation.getForDocument(document), filter, thumbDrawable, 0, document); + imageView.invalidate(); } }); } @@ -3815,7 +3820,7 @@ public void searchMessagesInChat(String query, long dialogId, long mergeDialogId } }; if (isSaved) { - loadReplyMessagesForMessages(messageObjects, dialogId, false, lastReplyMessageId, done, guid); + loadReplyMessagesForMessages(messageObjects, dialogId, 0, lastReplyMessageId, done, guid); } else { done.run(); } @@ -5211,6 +5216,9 @@ private void deletePeer(long dialogId, int type) { }); } + + public static int SHORTCUT_TYPE_USER_OR_CHAT = 0; + public static int SHORTCUT_TYPE_ATTACHED_BOT = 1; private Intent createIntrnalShortcutIntent(long dialogId) { Intent shortcutIntent = new Intent(ApplicationLoader.applicationContext, OpenChatReceiver.class); @@ -5234,10 +5242,28 @@ private Intent createIntrnalShortcutIntent(long dialogId) { return shortcutIntent; } - public void installShortcut(long dialogId) { - try { - Intent shortcutIntent = createIntrnalShortcutIntent(dialogId); + private Intent createIntrnalAttachedBotShortcutIntent(long botId, int botType) { + if (botId == 0 || botType != BotWebViewSheet.TYPE_WEB_VIEW_BOT_APP) { + return null; + } + Intent shortcutIntent = new Intent(ApplicationLoader.applicationContext, OpenAttachedMenuBotReceiver.class); + if (DialogObject.isUserDialog(botId)) { + shortcutIntent.putExtra("botId", botId); + } else { + return null; + } + shortcutIntent.putExtra("currentAccount", currentAccount); + shortcutIntent.setAction(OpenAttachedMenuBotReceiver.ACTION + botId); + shortcutIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); + return shortcutIntent; + } + public void installShortcut(long dialogId, int type) { + try { + Intent shortcutIntent = type == SHORTCUT_TYPE_USER_OR_CHAT ? createIntrnalShortcutIntent(dialogId) : createIntrnalAttachedBotShortcutIntent(dialogId, BotWebViewSheet.TYPE_WEB_VIEW_BOT_APP); + if (shortcutIntent == null) { + return; + } TLRPC.User user = null; TLRPC.Chat chat = null; if (DialogObject.isEncryptedDialog(dialogId)) { @@ -5264,7 +5290,12 @@ public void installShortcut(long dialogId) { boolean overrideAvatar = false; if (user != null) { - if (UserObject.isReplyUser(user)) { + if (type == SHORTCUT_TYPE_ATTACHED_BOT) { + name = UserObject.getUserName(MessagesController.getInstance(currentAccount).getUser(dialogId)); + if (user.photo != null) { + photo = user.photo.photo_small; + } + } else if (UserObject.isReplyUser(user)) { name = LocaleController.getString("RepliesTitle", R.string.RepliesTitle); overrideAvatar = true; } else if (UserObject.isUserSelf(user)) { @@ -5336,8 +5367,9 @@ public void installShortcut(long dialogId) { } } if (Build.VERSION.SDK_INT >= 26) { + String idPrefix = type == SHORTCUT_TYPE_USER_OR_CHAT ? "sdid_" : "bdid_"; ShortcutInfoCompat.Builder pinShortcutInfo = - new ShortcutInfoCompat.Builder(ApplicationLoader.applicationContext, "sdid_" + dialogId) + new ShortcutInfoCompat.Builder(ApplicationLoader.applicationContext, idPrefix + dialogId) .setShortLabel(name) .setIntent(shortcutIntent); @@ -5392,12 +5424,17 @@ public void installShortcut(long dialogId) { } } - public void uninstallShortcut(long dialogId) { + public void uninstallShortcut(long dialogId, int type) { try { if (Build.VERSION.SDK_INT >= 26) { ArrayList arrayList = new ArrayList<>(); - arrayList.add("sdid_" + dialogId); - arrayList.add("ndid_" + dialogId); + if (type == SHORTCUT_TYPE_USER_OR_CHAT) { + arrayList.add("sdid_" + dialogId); + arrayList.add("ndid_" + dialogId); + } + if (type == SHORTCUT_TYPE_ATTACHED_BOT) { + arrayList.add("bdid_" + dialogId); + } ShortcutManagerCompat.removeDynamicShortcuts(ApplicationLoader.applicationContext, arrayList); if (Build.VERSION.SDK_INT >= 30) { ShortcutManager shortcutManager = ApplicationLoader.applicationContext.getSystemService(ShortcutManager.class); @@ -5426,13 +5463,20 @@ public void uninstallShortcut(long dialogId) { String name; if (user != null) { - name = ContactsController.formatName(user.first_name, user.last_name); + if (type == SHORTCUT_TYPE_USER_OR_CHAT) { + name = ContactsController.formatName(user.first_name, user.last_name); + } else if (type == SHORTCUT_TYPE_ATTACHED_BOT) { + name = user.first_name; + } else { + name = ""; + } } else { name = chat.title; } + Intent shortcutIntent = type == SHORTCUT_TYPE_USER_OR_CHAT ? createIntrnalShortcutIntent(dialogId) : createIntrnalAttachedBotShortcutIntent(dialogId, BotWebViewSheet.TYPE_WEB_VIEW_BOT_APP); Intent addIntent = new Intent(); - addIntent.putExtra(Intent.EXTRA_SHORTCUT_INTENT, createIntrnalShortcutIntent(dialogId)); + addIntent.putExtra(Intent.EXTRA_SHORTCUT_INTENT, shortcutIntent); addIntent.putExtra(Intent.EXTRA_SHORTCUT_NAME, name); addIntent.putExtra("duplicate", false); @@ -5443,6 +5487,20 @@ public void uninstallShortcut(long dialogId) { FileLog.e(e); } } + + public boolean isShortcutAdded(long dialogId, int type) { + if (Build.VERSION.SDK_INT >= 26) { + String idPrefix = type == SHORTCUT_TYPE_USER_OR_CHAT ? "sdid_" : "bdid_"; + String id = idPrefix + dialogId; + List shortcuts = ShortcutManagerCompat.getShortcuts(ApplicationLoader.applicationContext, ShortcutManagerCompat.FLAG_MATCH_PINNED); + for (int i = 0; i < shortcuts.size(); i++) { + if (shortcuts.get(i).getId().equals(id)) { + return true; + } + } + } + return false; + } //---------------- SEARCH END ---------------- private static Comparator entityComparator = (entity1, entity2) -> { @@ -5735,7 +5793,8 @@ private static void removeEmptyMessages(ArrayList messages) { } } - public void loadReplyMessagesForMessages(ArrayList messages, long dialogId, boolean scheduled, long threadMessageId, Runnable callback, int classGuid) { + public void loadReplyMessagesForMessages(ArrayList messages, long dialogId, int mode, long threadMessageId, Runnable callback, int classGuid) { + final boolean scheduled = mode == ChatActivity.MODE_SCHEDULED; if (DialogObject.isEncryptedDialog(dialogId)) { ArrayList replyMessages = new ArrayList<>(); LongSparseArray> replyMessageRandomOwners = new LongSparseArray<>(); @@ -5819,6 +5878,33 @@ public void loadReplyMessagesForMessages(ArrayList messages, long LongSparseArray>> replyMessageOwners = new LongSparseArray<>(); LongSparseArray> dialogReplyMessagesIds = new LongSparseArray<>(); LongSparseArray> messagesWithUnknownStories = null; + for (int a = 0; a < messages.size(); a++) { + MessageObject messageObject = messages.get(a); + if (messageObject == null) { + continue; + } + if (!messageObject.isReplyToStory() && messageObject.isReply() && messageObject.getId() > 0) { + if (messageObject.messageOwner.reply_to.reply_to_peer_id != null) { + continue; + } + int reply_to_id = messageObject.messageOwner.reply_to.reply_to_msg_id; + for (int j = 0; j < messages.size(); ++j) { + if (a == j) continue; + if (messages.get(j) != null && messages.get(j).getId() == reply_to_id) { + messageObject.replyMessageObject = messages.get(j); + messageObject.applyTimestampsHighlightForReplyMsg(); + if (messageObject.messageOwner.action instanceof TLRPC.TL_messageActionPinMessage) { + messageObject.generatePinMessageText(null, null); + } else if (messageObject.messageOwner.action instanceof TLRPC.TL_messageActionGameScore) { + messageObject.generateGameMessageText(null); + } else if (messageObject.messageOwner.action instanceof TLRPC.TL_messageActionPaymentSent) { + messageObject.generatePaymentSentMessageText(null); + } + break; + } + } + } + } for (int a = 0; a < messages.size(); a++) { MessageObject messageObject = messages.get(a); if (messageObject == null) { @@ -6836,6 +6922,26 @@ public ArrayList getEntities(CharSequence[] message, boolea if (allowStrike) { cs = parsePattern(cs, STRIKE_PATTERN, entities, obj -> new TLRPC.TL_messageEntityStrike()); } + + // trim again in case some whitespace inside tags + while (cs.length() > 0 && (cs.charAt(0) == '\n' || cs.charAt(0) == ' ')) { + cs = cs.subSequence(1, cs.length()); + for (int i = 0; i < entities.size(); ++i) { + TLRPC.MessageEntity entity = entities.get(i); + if (entity.offset == 0) entity.length--; + entity.offset = Math.max(0, entity.offset - 1); + } + } + while (cs.length() > 0 && (cs.charAt(cs.length() - 1) == '\n' || cs.charAt(cs.length() - 1) == ' ')) { + cs = cs.subSequence(0, cs.length() - 1); + for (int i = 0; i < entities.size(); ++i) { + TLRPC.MessageEntity entity = entities.get(i); + if (entity.offset + entity.length > cs.length()) { + entity.length--; + } + } + } + message[0] = cs; return entities; @@ -7255,7 +7361,7 @@ public void saveDraft(long dialogId, long threadId, TLRPC.DraftMessage draft, TL } catch (Exception e) { getMessagesStorage().checkSQLException(e); } - getMessagesStorage().loadReplyMessages(replyMessageOwners, dialogReplyMessagesIds, usersToLoad, chatsToLoad, false); + getMessagesStorage().loadReplyMessages(replyMessageOwners, dialogReplyMessagesIds, usersToLoad, chatsToLoad, 0); } } cursor.dispose(); @@ -8261,6 +8367,7 @@ public void fillWithAnimatedEmoji(ArrayList result, Integer maxAn final Runnable fillRunnable = () -> { ArrayList featuredSets = getFeaturedEmojiSets(); ArrayList animatedResult = new ArrayList<>(); + HashSet foundEmojis = new HashSet<>(); ArrayList animatedEmoji = new ArrayList<>(); final int maxAnimatedPerEmoji = maxAnimatedPerEmojiInput == null ? (result.size() > 5 ? 1 : (result.size() > 2 ? 2 : 3)) : maxAnimatedPerEmojiInput; int len = maxAnimatedPerEmojiInput == null ? Math.min(15, result.size()) : result.size(); @@ -8326,14 +8433,8 @@ public void fillWithAnimatedEmoji(ArrayList result, Integer maxAn } } if (document != null && document.attributes != null && !animatedEmoji.contains(document)) { - boolean duplicate = false; - for (int l = 0; l < animatedEmoji.size(); ++l) { - if (animatedEmoji.get(l).id == document.id) { - duplicate = true; - break; - } - } - if (!duplicate) { + if (!foundEmojis.contains(document.id)) { + foundEmojis.add(document.id); animatedEmoji.add(document); if (animatedEmoji.size() >= maxAnimatedPerEmoji) { break; @@ -8357,14 +8458,8 @@ public void fillWithAnimatedEmoji(ArrayList result, Integer maxAn } if (attribute != null && !TextUtils.isEmpty(attribute.alt) && attribute.alt.contains(emoji) && (isPremium || attribute.free || set.set != null && set.set.short_name != null && set.set.short_name.equals(topicIconsName))) { - boolean duplicate = false; - for (int l = 0; l < animatedEmoji.size(); ++l) { - if (animatedEmoji.get(l).id == document.id) { - duplicate = true; - break; - } - } - if (!duplicate) { + if (!foundEmojis.contains(document.id)) { + foundEmojis.add(document.id); animatedEmoji.add(document); if (animatedEmoji.size() >= maxAnimatedPerEmoji) { break; @@ -8402,14 +8497,8 @@ public void fillWithAnimatedEmoji(ArrayList result, Integer maxAn } if (attribute != null && !TextUtils.isEmpty(attribute.alt) && attribute.alt.contains(emoji) && (isPremium || attribute.free || set.set != null && set.set.short_name != null && set.set.short_name.equals(topicIconsName))) { - boolean duplicate = false; - for (int l = 0; l < animatedEmoji.size(); ++l) { - if (animatedEmoji.get(l).id == document.id) { - duplicate = true; - break; - } - } - if (!duplicate) { + if (!foundEmojis.contains(document.id)) { + foundEmojis.add(document.id); animatedEmoji.add(document); if (animatedEmoji.size() >= maxAnimatedPerEmoji) { break; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/MessageObject.java b/TMessagesProj/src/main/java/org/telegram/messenger/MessageObject.java index 3f808f42e01..633ec9a1c05 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/MessageObject.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/MessageObject.java @@ -33,8 +33,6 @@ import android.text.style.URLSpan; import android.text.util.Linkify; import android.util.Base64; -import android.util.Log; -import android.util.SparseIntArray; import androidx.annotation.NonNull; import androidx.collection.LongSparseArray; @@ -49,7 +47,9 @@ import org.telegram.tgnet.TLRPC; import org.telegram.tgnet.tl.TL_stories; import org.telegram.ui.ActionBar.Theme; +import org.telegram.ui.Business.QuickRepliesController; import org.telegram.ui.Cells.ChatMessageCell; +import org.telegram.ui.ChatActivity; import org.telegram.ui.Components.AnimatedEmojiDrawable; import org.telegram.ui.Components.AnimatedEmojiSpan; import org.telegram.ui.Components.AvatarDrawable; @@ -59,7 +59,6 @@ import org.telegram.ui.Components.QuoteSpan; import org.telegram.ui.Components.Reactions.ReactionsLayoutInBubble; import org.telegram.ui.Components.Reactions.ReactionsUtils; -import org.telegram.ui.Components.StaticLayoutEx; import org.telegram.ui.Components.Text; import org.telegram.ui.Components.TextStyleSpan; import org.telegram.ui.Components.TranscribeButton; @@ -244,6 +243,15 @@ public class MessageObject { public boolean preview; public boolean previewForward; + public int getChatMode() { + if (scheduled) { + return ChatActivity.MODE_SCHEDULED; + } else if (isQuickReply()) { + return ChatActivity.MODE_QUICK_REPLIES; + } + return 0; + } + public ArrayList checkedVotes; public CharSequence editingMessage; @@ -314,10 +322,12 @@ public class MessageObject { }; public boolean isRepostPreview; public boolean isRepostVideoPreview; + public boolean business; public boolean forceAvatar; public Drawable customAvatarDrawable; public boolean isSaved; public boolean isSavedFiltered; + public String quick_reply_shortcut; private byte[] randomWaveform; public boolean drawServiceWithDefaultTypeface; @@ -366,6 +376,9 @@ private static long getTopicId(int currentAccount, TLRPC.Message message) { public static long getTopicId(int currentAccount, TLRPC.Message message, boolean sureIsForum) { final long selfId = UserConfig.getInstance(currentAccount).getClientUserId(); + if ((message.flags & 1073741824) != 0 && DialogObject.getPeerDialogId(message.peer_id) == selfId) { + return message.quick_reply_shortcut_id; + } if (!sureIsForum && message != null && currentAccount >= 0 && DialogObject.getPeerDialogId(message.peer_id) == selfId) { return getSavedDialogId(selfId, message); } @@ -1619,7 +1632,7 @@ public MessageObject(int accountNum, TLRPC.Message message, MessageObject replyT } } - private void checkBigAnimatedEmoji() { + protected void checkBigAnimatedEmoji() { emojiAnimatedSticker = null; emojiAnimatedStickerId = null; if (emojiOnlyCount == 1 && !(getMedia(messageOwner) instanceof TLRPC.TL_messageMediaWebPage) && !(getMedia(messageOwner) instanceof TLRPC.TL_messageMediaInvoice) && (getMedia(messageOwner) instanceof TLRPC.TL_messageMediaEmpty || getMedia(messageOwner) == null) && this.messageOwner.grouped_id == 0) { @@ -6300,7 +6313,16 @@ public boolean needDrawShareButton() { if (isSaved) { long selfId = UserConfig.getInstance(currentAccount).clientUserId; long dialogId = MessageObject.getSavedDialogId(selfId, messageOwner); - return dialogId != selfId && dialogId != UserObject.ANONYMOUS; + if (dialogId == selfId || dialogId == UserObject.ANONYMOUS) { + return false; + } + if (messageOwner == null || messageOwner.fwd_from == null) { + return false; + } + if (messageOwner.fwd_from.from_id == null && messageOwner.fwd_from.saved_from_id == null) { + return false; + } + return true; } if (type == TYPE_JOINED_CHANNEL) { return false; @@ -8745,6 +8767,9 @@ public String getMusicTitle(boolean unknown) { return title; } else if (attribute instanceof TLRPC.TL_documentAttributeVideo) { if (attribute.round_message) { + if (isQuickReply()) { + return LocaleController.formatString(R.string.BusinessInReplies, "/" + getQuickReplyDisplayName()); + } return LocaleController.formatDateAudio(messageOwner.date, true); } } @@ -8971,6 +8996,7 @@ public boolean canEditMessageScheduleTime(TLRPC.Chat chat) { } public boolean canForwardMessage() { + if (isQuickReply()) return false; return !(messageOwner instanceof TLRPC.TL_message_secret) && !needDrawBluredPreview() && !isLiveLocation() && type != MessageObject.TYPE_PHONE_CALL && !isSponsored() && !messageOwner.noforwards; } @@ -10050,4 +10076,85 @@ public static int findQuoteStart(String text, String quote, int quote_offset) { } return prevIndex; } + + public void applyQuickReply(String name, int id) { + if (messageOwner == null) return; + if (id != 0) { + messageOwner.flags |= 1073741824; + messageOwner.quick_reply_shortcut_id = id; +// } + TLRPC.TL_inputQuickReplyShortcutId shortcut = new TLRPC.TL_inputQuickReplyShortcutId(); + shortcut.shortcut_id = id; + messageOwner.quick_reply_shortcut = shortcut; + } else if (name != null) { + TLRPC.TL_inputQuickReplyShortcut shortcut = new TLRPC.TL_inputQuickReplyShortcut(); + shortcut.shortcut = name; + messageOwner.quick_reply_shortcut = shortcut; + } else { + messageOwner.flags &=~ 1073741824; + messageOwner.quick_reply_shortcut_id = 0; + messageOwner.quick_reply_shortcut = null; + } + } + + public static int getQuickReplyId(TLRPC.Message message) { + if (message == null) return 0; + if ((message.flags & 1073741824) != 0) { + return message.quick_reply_shortcut_id; + } + if (message.quick_reply_shortcut instanceof TLRPC.TL_inputQuickReplyShortcutId) { + return ((TLRPC.TL_inputQuickReplyShortcutId) message.quick_reply_shortcut).shortcut_id; + } + return 0; + } + + public static int getQuickReplyId(int currentAccount, TLRPC.Message message) { + if (message == null) return 0; + if ((message.flags & 1073741824) != 0) { + return message.quick_reply_shortcut_id; + } + if (message.quick_reply_shortcut instanceof TLRPC.TL_inputQuickReplyShortcutId) { + return ((TLRPC.TL_inputQuickReplyShortcutId) message.quick_reply_shortcut).shortcut_id; + } + String replyName = getQuickReplyName(message); + if (replyName != null) { + QuickRepliesController.QuickReply reply = QuickRepliesController.getInstance(currentAccount).findReply(replyName); + if (reply != null) { + return reply.id; + } + } + return 0; + } + + public int getQuickReplyId() { + return getQuickReplyId(messageOwner); + } + + public static String getQuickReplyName(TLRPC.Message message) { + if (message == null) return null; + if (message.quick_reply_shortcut instanceof TLRPC.TL_inputQuickReplyShortcut) { + return ((TLRPC.TL_inputQuickReplyShortcut) message.quick_reply_shortcut).shortcut; + } + return null; + } + + public String getQuickReplyName() { + return getQuickReplyName(messageOwner); + } + + public String getQuickReplyDisplayName() { + String name = getQuickReplyName(); + if (name != null) return name; + QuickRepliesController.QuickReply quickReply = QuickRepliesController.getInstance(currentAccount).findReply(getQuickReplyId()); + if (quickReply != null) return quickReply.name; + return ""; + } + + public static boolean isQuickReply(TLRPC.Message message) { + return message != null && ((message.flags & 1073741824) != 0 || message.quick_reply_shortcut != null); + } + + public boolean isQuickReply() { + return isQuickReply(messageOwner); + } } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/MessagesController.java b/TMessagesProj/src/main/java/org/telegram/messenger/MessagesController.java index 0274455dccf..ee8868f205f 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/MessagesController.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/MessagesController.java @@ -27,6 +27,7 @@ import android.telephony.TelephonyManager; import android.text.TextUtils; import android.util.Base64; +import android.util.Log; import android.util.Pair; import android.util.SparseArray; import android.util.SparseBooleanArray; @@ -40,8 +41,6 @@ import androidx.core.graphics.ColorUtils; import androidx.core.util.Consumer; -import com.google.android.exoplayer2.util.Log; - import org.telegram.SQLite.SQLiteCursor; import org.telegram.SQLite.SQLiteDatabase; import org.telegram.SQLite.SQLiteException; @@ -61,6 +60,7 @@ import org.telegram.ui.ActionBar.AlertDialog; import org.telegram.ui.ActionBar.BaseFragment; import org.telegram.ui.ActionBar.Theme; +import org.telegram.ui.Business.QuickRepliesController; import org.telegram.ui.ChatActivity; import org.telegram.ui.ChatReactionsEditActivity; import org.telegram.ui.ChatRightsEditActivity; @@ -69,7 +69,6 @@ import org.telegram.ui.Components.BulletinFactory; import org.telegram.ui.Components.ImageUpdater; import org.telegram.ui.Components.JoinCallAlert; -import org.telegram.ui.Components.JoinGroupAlert; import org.telegram.ui.Components.MotionBackgroundDrawable; import org.telegram.ui.Components.Premium.LimitReachedBottomSheet; import org.telegram.ui.Components.Reactions.ReactionsLayoutInBubble; @@ -232,6 +231,7 @@ public ChatlistUpdatesStat(TL_chatlists.TL_chatlists_chatlistUpdates value) { private int pollsToCheckSize; private long lastViewsCheckTime; public SparseIntArray premiumFeaturesTypesToPosition = new SparseIntArray(); + public SparseIntArray businessFeaturesTypesToPosition = new SparseIntArray(); public ArrayList dialogFilters = new ArrayList<>(); public ArrayList frozenDialogFilters = null; @@ -285,6 +285,7 @@ public ChatlistUpdatesStat(TL_chatlists.TL_chatlists_chatlistUpdates value) { private LongSparseArray> reloadingSavedWebpagesPending = new LongSparseArray<>(); private LongSparseArray lastScheduledServerQueryTime = new LongSparseArray<>(); + private LongSparseArray lastQuickReplyServerQueryTime = new LongSparseArray<>(); private LongSparseArray lastSavedServerQueryTime = new LongSparseArray<>(); private LongSparseArray lastServerQueryTime = new LongSparseArray<>(); @@ -492,6 +493,7 @@ protected boolean useCache(Integer arguments) { public float animatedEmojisZoom; public boolean filtersEnabled; public boolean getfileExperimentalParams; + public boolean smsjobsStickyNotificationEnabled; public boolean collectDeviceStats; public boolean showFiltersTooltip; public String venueSearchBot; @@ -586,6 +588,8 @@ protected boolean useCache(Integer arguments) { public int groupWallpaperLevelMin; public int groupCustomWallpaperLevelMin; public int groupTranscribeLevelMin; + public int quickRepliesLimit; + public int quickReplyMessagesLimit; public int savedDialogsPinnedLimitDefault; public int savedDialogsPinnedLimitPremium; @@ -636,6 +640,7 @@ public boolean premiumPurchaseBlocked() { public String storiesEntities; public int checkResetLangpack; + public boolean folderTags; public void getNextReactionMention(long dialogId, long topicId, int count, Consumer callback) { final MessagesStorage messagesStorage = getMessagesStorage(); @@ -970,6 +975,7 @@ public boolean equals(Object obj) { public void clearQueryTime() { lastServerQueryTime.clear(); lastScheduledServerQueryTime.clear(); + lastQuickReplyServerQueryTime.clear(); lastSavedServerQueryTime.clear(); } @@ -1067,6 +1073,7 @@ public static class DialogFilter { public LongSparseIntArray pinnedDialogs = new LongSparseIntArray(); public ArrayList dialogs = new ArrayList<>(); public ArrayList dialogsForward = new ArrayList<>(); + public int color; public ArrayList invites = null; @@ -1379,6 +1386,7 @@ public MessagesController(int num) { saveGifsWithStickers = mainPreferences.getBoolean("saveGifsWithStickers", false); filtersEnabled = mainPreferences.getBoolean("filtersEnabled", false); getfileExperimentalParams = mainPreferences.getBoolean("getfileExperimentalParams", false); + smsjobsStickyNotificationEnabled = mainPreferences.getBoolean("smsjobsStickyNotificationEnabled", false); showFiltersTooltip = mainPreferences.getBoolean("showFiltersTooltip", false); autoarchiveAvailable = mainPreferences.getBoolean("autoarchiveAvailable", false); groupCallVideoMaxParticipants = mainPreferences.getInt("groipCallVideoMaxParticipants", 30); @@ -1465,6 +1473,8 @@ public MessagesController(int num) { groupWallpaperLevelMin = mainPreferences.getInt("groupWallpaperLevelMin", 1); groupCustomWallpaperLevelMin = mainPreferences.getInt("groupCustomWallpaperLevelMin", 1); groupTranscribeLevelMin = mainPreferences.getInt("groupTranscribeLevelMin", 1); + quickRepliesLimit = mainPreferences.getInt("quickRepliesLimit", 10); + quickReplyMessagesLimit = mainPreferences.getInt("quickReplyMessagesLimit", 20); channelWallpaperLevelMin = mainPreferences.getInt("channelWallpaperLevelMin", 1); channelCustomWallpaperLevelMin = mainPreferences.getInt("channelCustomWallpaperLevelMin", 1); chatlistInvitesLimitPremium = mainPreferences.getInt("chatlistInvitesLimitPremium", isTest ? 5 : 20); @@ -1489,6 +1499,7 @@ public MessagesController(int num) { savedDialogsPinnedLimitPremium = mainPreferences.getInt("savedDialogsPinnedLimitPremium", 6); storyQualityFull = mainPreferences.getBoolean("storyQualityFull", true); savedViewAsChats = mainPreferences.getBoolean("savedViewAsChats", false); + folderTags = mainPreferences.getBoolean("folderTags", false); scheduleTranscriptionUpdate(); BuildVars.GOOGLE_AUTH_CLIENT_ID = mainPreferences.getString("googleAuthClientId", BuildVars.GOOGLE_AUTH_CLIENT_ID); if (mainPreferences.contains("dcDomainName2")) { @@ -1508,7 +1519,8 @@ public MessagesController(int num) { directPaymentsCurrency.addAll(currencySet); } - loadPremiumFeaturesPreviewOrder(mainPreferences.getString("premiumFeaturesTypesToPosition", null)); + loadPremiumFeaturesPreviewOrder(premiumFeaturesTypesToPosition, mainPreferences.getString("premiumFeaturesTypesToPosition", null)); + loadPremiumFeaturesPreviewOrder(businessFeaturesTypesToPosition, mainPreferences.getString("businessFeaturesTypesToPosition", null)); if (pendingSuggestions != null) { pendingSuggestions = new HashSet<>(pendingSuggestions); } else { @@ -2106,7 +2118,26 @@ public void loadRemoteFilters(boolean force, Utilities.Callback whenDon TLRPC.TL_messages_getDialogFilters req = new TLRPC.TL_messages_getDialogFilters(); getConnectionsManager().sendRequest(req, (response, error) -> { if (response instanceof TLRPC.Vector) { - getMessagesStorage().checkLoadedRemoteFilters((TLRPC.Vector) response, () -> { + ArrayList filters = new ArrayList<>(); + TLRPC.Vector vector = (TLRPC.Vector) response; + for (int i = 0; i < vector.objects.size(); ++i) { + filters.add((TLRPC.DialogFilter) vector.objects.get(i)); + } + getMessagesStorage().checkLoadedRemoteFilters(filters, () -> { + if (onLoadedRemoteFilters != null) { + onLoadedRemoteFilters.run(true); + onLoadedRemoteFilters = null; + } + }); + } else if (response instanceof TLRPC.TL_messages_dialogFilters) { + TLRPC.TL_messages_dialogFilters res = (TLRPC.TL_messages_dialogFilters) response; + if (folderTags != res.tags_enabled) { + setFolderTags(res.tags_enabled); + AndroidUtilities.runOnUIThread(() -> { + getNotificationCenter().postNotificationName(NotificationCenter.dialogFiltersUpdated); + }); + } + getMessagesStorage().checkLoadedRemoteFilters(res.filters, () -> { if (onLoadedRemoteFilters != null) { onLoadedRemoteFilters.run(true); onLoadedRemoteFilters = null; @@ -2475,7 +2506,14 @@ private void applyAppConfig(TLRPC.TL_jsonObject object) { case "premium_promo_order": { if (value.value instanceof TLRPC.TL_jsonArray) { TLRPC.TL_jsonArray order = (TLRPC.TL_jsonArray) value.value; - changed = savePremiumFeaturesPreviewOrder(editor, order.value); + changed = savePremiumFeaturesPreviewOrder("premiumFeaturesTypesToPosition", premiumFeaturesTypesToPosition, editor, order.value); + } + break; + } + case "business_promo_order": { + if (value.value instanceof TLRPC.TL_jsonArray) { + TLRPC.TL_jsonArray order = (TLRPC.TL_jsonArray) value.value; + changed = savePremiumFeaturesPreviewOrder("businessFeaturesTypesToPosition", businessFeaturesTypesToPosition, editor, order.value); } break; } @@ -2501,6 +2539,17 @@ private void applyAppConfig(TLRPC.TL_jsonObject object) { } break; } + case "smsjobs_sticky_notification_enabled": { + if (value.value instanceof TLRPC.TL_jsonBool) { + TLRPC.TL_jsonBool bool = (TLRPC.TL_jsonBool) value.value; + if (bool.value != smsjobsStickyNotificationEnabled) { + smsjobsStickyNotificationEnabled = bool.value; + editor.putBoolean("smsjobsStickyNotificationEnabled", smsjobsStickyNotificationEnabled); + changed = true; + } + } + break; + } case "dialog_filters_enabled": { if (value.value instanceof TLRPC.TL_jsonBool) { TLRPC.TL_jsonBool bool = (TLRPC.TL_jsonBool) value.value; @@ -3698,6 +3747,28 @@ private void applyAppConfig(TLRPC.TL_jsonObject object) { } break; } + case "quick_replies_limit": { + if (value.value instanceof TLRPC.TL_jsonNumber) { + TLRPC.TL_jsonNumber num = (TLRPC.TL_jsonNumber) value.value; + if (num.value != quickRepliesLimit) { + quickRepliesLimit = (int) num.value; + editor.putInt("quickRepliesLimit", quickRepliesLimit); + changed = true; + } + } + break; + } + case "quick_reply_messages_limit": { + if (value.value instanceof TLRPC.TL_jsonNumber) { + TLRPC.TL_jsonNumber num = (TLRPC.TL_jsonNumber) value.value; + if (num.value != quickReplyMessagesLimit) { + quickReplyMessagesLimit = (int) num.value; + editor.putInt("quickReplyMessagesLimit", quickReplyMessagesLimit); + changed = true; + } + } + break; + } case "group_wallpaper_level_min": { if (value.value instanceof TLRPC.TL_jsonNumber) { TLRPC.TL_jsonNumber num = (TLRPC.TL_jsonNumber) value.value; @@ -4315,13 +4386,13 @@ public static PeerColor fromString(String string) { private void resetAppConfig() { getfileExperimentalParams = false; collectDeviceStats = false; - mainPreferences.edit().remove("getfileExperimentalParams").apply(); + smsjobsStickyNotificationEnabled = false; + mainPreferences.edit().remove("getfileExperimentalParams").remove("smsjobsStickyNotificationEnabled").apply(); } - private boolean savePremiumFeaturesPreviewOrder(SharedPreferences.Editor editor, ArrayList value) { + private boolean savePremiumFeaturesPreviewOrder(String key, SparseIntArray array, SharedPreferences.Editor editor, ArrayList value) { StringBuilder stringBuilder = new StringBuilder(); - StringBuilder storiesBuilder = new StringBuilder(); - premiumFeaturesTypesToPosition.clear(); + array.clear(); for (int i = 0; i < value.size(); i++) { String s = null; if (value.get(i) instanceof TLRPC.TL_jsonString) { @@ -4330,7 +4401,7 @@ private boolean savePremiumFeaturesPreviewOrder(SharedPreferences.Editor editor, if (s != null) { int type = PremiumPreviewFragment.serverStringToFeatureType(s); if (type >= 0) { - premiumFeaturesTypesToPosition.put(type, i); + array.put(type, i); if (stringBuilder.length() > 0) { stringBuilder.append('_'); } @@ -4342,26 +4413,26 @@ private boolean savePremiumFeaturesPreviewOrder(SharedPreferences.Editor editor, boolean changed; if (stringBuilder.length() > 0) { String string = stringBuilder.toString(); - changed = !string.equals(mainPreferences.getString("premiumFeaturesTypesToPosition", null)); - editor.putString("premiumFeaturesTypesToPosition", string); + changed = !string.equals(mainPreferences.getString(key, null)); + editor.putString(key, string); } else { - editor.remove("premiumFeaturesTypesToPosition"); - changed = mainPreferences.getString("premiumFeaturesTypesToPosition", null) != null; + editor.remove(key); + changed = mainPreferences.getString(key, null) != null; } return changed; } - private void loadPremiumFeaturesPreviewOrder(String string) { - premiumFeaturesTypesToPosition.clear(); + private void loadPremiumFeaturesPreviewOrder(SparseIntArray array, String string) { + array.clear(); if (string != null) { String[] types = string.split("_"); for (int i = 0; i < types.length; i++) { int type = Integer.parseInt(types[i]); - premiumFeaturesTypesToPosition.put(type, i); + array.put(type, i); } } - } + public void removeSuggestion(long did, String suggestion) { if (TextUtils.isEmpty(suggestion)) { return; @@ -4693,6 +4764,24 @@ public TLRPC.Peer getPeer(long id) { return inputPeer; } + + public String getPeerName(long dialogId) { + return getPeerName(dialogId, false); + } + public String getPeerName(long dialogId, boolean firstName) { + if (dialogId >= 0) { + TLRPC.User user = getUser(dialogId); + if (firstName) { + return UserObject.getFirstName(user, true); + } else { + return UserObject.getUserName(user); + } + } else { + TLRPC.Chat chat = getChat(-dialogId); + return chat == null ? "" : chat.title; + } + } + @Override public void didReceivedNotification(int id, int account, Object... args) { if (id == NotificationCenter.fileUploaded) { @@ -5120,6 +5209,7 @@ public void cleanup() { } lastScheduledServerQueryTime.clear(); + lastQuickReplyServerQueryTime.clear(); lastSavedServerQueryTime.clear(); lastServerQueryTime.clear(); reloadingWebpages.clear(); @@ -6620,7 +6710,7 @@ private boolean checkDeletingTask(boolean runnable) { if (task != null) { for (int a = 0, N = task.size(); a < N; a++) { ArrayList mids = task.valueAt(a); - deleteMessages(mids, null, null, task.keyAt(a), true, false, !mids.isEmpty() && mids.get(0) > 0); + deleteMessages(mids, null, null, task.keyAt(a), 0, true, 0, !mids.isEmpty() && mids.get(0) > 0); } } if (taskMedia != null) { @@ -6935,6 +7025,7 @@ public void loadCache() { } } if (photo != null) { + count = Math.max(position + 1, count); photoEntries.put(position, photo); } } @@ -7611,15 +7702,17 @@ public void markDialogMessageAsDeleted(long dialogId, ArrayList message } } - public void deleteMessages(ArrayList messages, ArrayList randoms, TLRPC.EncryptedChat encryptedChat, long dialogId, boolean forAll, boolean scheduled) { - deleteMessages(messages, randoms, encryptedChat, dialogId, forAll, scheduled, false, 0, null); + public void deleteMessages(ArrayList messages, ArrayList randoms, TLRPC.EncryptedChat encryptedChat, long dialogId, int topicId, boolean forAll, int mode) { + deleteMessages(messages, randoms, encryptedChat, dialogId, forAll, mode, false, 0, null, topicId); } - public void deleteMessages(ArrayList messages, ArrayList randoms, TLRPC.EncryptedChat encryptedChat, long dialogId, boolean forAll, boolean scheduled, boolean cacheOnly) { - deleteMessages(messages, randoms, encryptedChat, dialogId, forAll, scheduled, cacheOnly, 0, null); + public void deleteMessages(ArrayList messages, ArrayList randoms, TLRPC.EncryptedChat encryptedChat, long dialogId, int topicId, boolean forAll, int mode, boolean cacheOnly) { + deleteMessages(messages, randoms, encryptedChat, dialogId, forAll, mode, cacheOnly, 0, null, topicId); } - public void deleteMessages(ArrayList messages, ArrayList randoms, TLRPC.EncryptedChat encryptedChat, long dialogId, boolean forAll, boolean scheduled, boolean cacheOnly, long taskId, TLObject taskRequest) { + public void deleteMessages(ArrayList messages, ArrayList randoms, TLRPC.EncryptedChat encryptedChat, long dialogId, boolean forAll, int mode, boolean cacheOnly, long taskId, TLObject taskRequest, int topicId) { + final boolean scheduled = mode == ChatActivity.MODE_SCHEDULED; + final boolean quickReplies = mode == ChatActivity.MODE_QUICK_REPLIES; if ((messages == null || messages.isEmpty()) && taskId == 0) { return; } @@ -7642,7 +7735,12 @@ public void deleteMessages(ArrayList messages, ArrayList randoms, } } if (scheduled) { - getMessagesStorage().markMessagesAsDeleted(dialogId, messages, true, false, true); + getMessagesStorage().markMessagesAsDeleted(dialogId, messages, true, false, ChatActivity.MODE_SCHEDULED, 0); + } else if (quickReplies) { + if (mode == ChatActivity.MODE_QUICK_REPLIES) { + QuickRepliesController.getInstance(currentAccount).deleteLocalMessages(messages); + } + getMessagesStorage().markMessagesAsDeleted(dialogId, messages, true, false, ChatActivity.MODE_QUICK_REPLIES, topicId); } else { if (channelId == 0) { for (int a = 0; a < messages.size(); a++) { @@ -7655,7 +7753,7 @@ public void deleteMessages(ArrayList messages, ArrayList randoms, } else { markDialogMessageAsDeleted(dialogId, messages); } - getMessagesStorage().markMessagesAsDeleted(dialogId, messages, true, forAll, false); + getMessagesStorage().markMessagesAsDeleted(dialogId, messages, true, forAll, 0, topicId); getMessagesStorage().updateDialogsWithDeletedMessages(dialogId, channelId, messages, null, true); } getNotificationCenter().postNotificationName(NotificationCenter.messagesDeleted, messages, channelId, scheduled); @@ -7694,6 +7792,38 @@ public void deleteMessages(ArrayList messages, ArrayList randoms, newTaskId = getMessagesStorage().createPendingTask(data); } + getConnectionsManager().sendRequest(req, (response, error) -> { + if (error == null) { + TLRPC.Updates updates = (TLRPC.Updates) response; + processUpdates(updates, false); + } + if (newTaskId != 0) { + getMessagesStorage().removePendingTask(newTaskId); + } + }); + } else if (quickReplies) { + TLRPC.TL_messages_deleteQuickReplyMessages req; + if (taskRequest instanceof TLRPC.TL_messages_deleteQuickReplyMessages) { + req = (TLRPC.TL_messages_deleteQuickReplyMessages) taskRequest; + newTaskId = taskId; + } else { + req = new TLRPC.TL_messages_deleteQuickReplyMessages(); + req.id = toSend; + req.shortcut_id = topicId; + + NativeByteBuffer data = null; + try { + data = new NativeByteBuffer(4 + 8 + 4 + req.getObjectSize()); + data.writeInt32(103); + data.writeInt64(dialogId); + data.writeInt32(topicId); + req.serializeToStream(data); + } catch (Exception e) { + FileLog.e(e); + } + newTaskId = getMessagesStorage().createPendingTask(data); + } + getConnectionsManager().sendRequest(req, (response, error) -> { if (error == null) { TLRPC.Updates updates = (TLRPC.Updates) response; @@ -8080,7 +8210,7 @@ protected void deleteDialog(long did, int first, int onlyHistory, int max_id, bo return; } if (onlyHistory == 0 || onlyHistory == 3) { - getMediaDataController().uninstallShortcut(did); + getMediaDataController().uninstallShortcut(did, MediaDataController.SHORTCUT_TYPE_USER_OR_CHAT); } int max_id_delete = max_id; @@ -8173,7 +8303,7 @@ protected void deleteDialog(long did, int first, int onlyHistory, int max_id, bo objArr.add(obj); ArrayList arr = new ArrayList<>(); arr.add(message); - updateInterfaceWithMessages(did, objArr, false); + updateInterfaceWithMessages(did, objArr, 0); getMessagesStorage().putMessages(arr, false, true, false, 0, false, 0, 0); } else { dialog.top_message = 0; @@ -9474,10 +9604,28 @@ private void loadMessagesInternal(long dialogId, long mergeDialogId, boolean loa if (BuildVars.LOGS_ENABLED && loaderLogger == null && mode == 0) { loaderLogger = new MessageLoaderLogger(dialogId, loadIndex, count); } - if ((threadMessageId == 0 || isTopic || mode == ChatActivity.MODE_SAVED) && mode != ChatActivity.MODE_PINNED && (fromCache || DialogObject.isEncryptedDialog(dialogId))) { + if ((threadMessageId == 0 || isTopic || mode == ChatActivity.MODE_SAVED || mode == ChatActivity.MODE_QUICK_REPLIES) && mode != ChatActivity.MODE_PINNED && (fromCache || DialogObject.isEncryptedDialog(dialogId))) { getMessagesStorage().getMessages(dialogId, mergeDialogId, loadInfo, count, max_id, offset_date, minDate, classGuid, load_type, mode, threadMessageId, loadIndex, processMessages, isTopic, loaderLogger); } else { - if (threadMessageId != 0) { + if (mode == ChatActivity.MODE_QUICK_REPLIES) { + TLRPC.TL_messages_getQuickReplyMessages req = new TLRPC.TL_messages_getQuickReplyMessages(); + req.shortcut_id = (int) threadMessageId; + req.hash = hash; + int reqId = getConnectionsManager().sendRequest(req, (response, error) -> { + if (response != null) { + TLRPC.messages_Messages res = (TLRPC.messages_Messages) response; + if (res instanceof TLRPC.TL_messages_messagesNotModified) { + return; + } + processLoadedMessages(res, res.messages.size(), dialogId, mergeDialogId, count, max_id, offset_date, false, classGuid, first_unread, last_message_id, unread_count, last_date, load_type, false, mode, threadMessageId, loadIndex, queryFromServer, mentionsCount, processMessages, isTopic, null); + } else if (error != null) { + if ("SHORTCUT_INVALID".equals(error.text)) { + processLoadedMessages(new TLRPC.TL_messages_messages(), 0, dialogId, mergeDialogId, count, max_id, offset_date, false, classGuid, first_unread, last_message_id, unread_count, last_date, load_type, false, mode, threadMessageId, loadIndex, queryFromServer, mentionsCount, processMessages, isTopic, null); + } + } + }); + getConnectionsManager().bindRequestToGuid(reqId, classGuid); + } else if (threadMessageId != 0) { if (mode == ChatActivity.MODE_SAVED) { TLRPC.TL_messages_getSavedHistory req = new TLRPC.TL_messages_getSavedHistory(); req.peer = getInputPeer(threadMessageId); @@ -9807,6 +9955,8 @@ public void processLoadedMessages(TLRPC.messages_Messages messagesRes, int resCo } if (mode == ChatActivity.MODE_SCHEDULED) { reload = ((SystemClock.elapsedRealtime() - lastScheduledServerQueryTime.get(dialogId, 0L)) > 60 * 1000); + } else if (mode == ChatActivity.MODE_QUICK_REPLIES) { + reload = ((SystemClock.elapsedRealtime() - lastQuickReplyServerQueryTime.get(threadMessageId, 0L)) > 60 * 1000); } else if (mode == ChatActivity.MODE_SAVED) { reload = resCount == 0 && (!isInitialLoading || (SystemClock.elapsedRealtime() - lastSavedServerQueryTime.get(threadMessageId, 0L)) > 60 * 1000 || isCache); } else { @@ -9815,6 +9965,8 @@ public void processLoadedMessages(TLRPC.messages_Messages messagesRes, int resCo if (!DialogObject.isEncryptedDialog(dialogId) && isCache && reload) { if (mode == ChatActivity.MODE_SCHEDULED) { lastScheduledServerQueryTime.put(dialogId, SystemClock.elapsedRealtime()); + } else if (mode == ChatActivity.MODE_QUICK_REPLIES) { + lastQuickReplyServerQueryTime.put(threadMessageId, SystemClock.elapsedRealtime()); } else if (mode == ChatActivity.MODE_SAVED) { lastSavedServerQueryTime.put(threadMessageId, SystemClock.elapsedRealtime()); } else if (mode == ChatActivity.MODE_DEFAULT) { @@ -9851,6 +10003,19 @@ public void processLoadedMessages(TLRPC.messages_Messages messagesRes, int resCo } hash = MediaDataController.calcHash(hash, date); } + } else if (mode == ChatActivity.MODE_QUICK_REPLIES) { + for (int a = 0, N = messagesRes.messages.size(); a < N; a++) { + TLRPC.Message message = messagesRes.messages.get(a); + if (message.id < 0) { + continue; + } + hash = MediaDataController.calcHash(hash, message.id); + if ((message.flags & TLRPC.MESSAGE_FLAG_EDITED) != 0) { + hash = MediaDataController.calcHash(hash, message.edit_date); + } else { + hash = MediaDataController.calcHash(hash, 0); + } + } } if (loaderLogger != null) { loaderLogger.reload(); @@ -9897,7 +10062,7 @@ public void processLoadedMessages(TLRPC.messages_Messages messagesRes, int resCo } } } - if (threadMessageId == 0 || isTopic || mode == ChatActivity.MODE_SAVED) { + if (threadMessageId == 0 || isTopic || mode == ChatActivity.MODE_SAVED || mode == ChatActivity.MODE_QUICK_REPLIES) { getMessagesStorage().putMessages(messagesRes, dialogId, load_type, max_id, createDialog, mode, threadMessageId); } if (mode == ChatActivity.MODE_SAVED) { @@ -9962,6 +10127,29 @@ public void processLoadedMessages(TLRPC.messages_Messages messagesRes, int resCo } return o2.messageOwner.date - o1.messageOwner.date; }); + } else if (mode == ChatActivity.MODE_QUICK_REPLIES) { + Collections.sort(objects, (a, b) -> b.getId() - a.getId()); + for (int i = 0; i < objects.size(); ++i) { + MessageObject msg = objects.get(i); + if (msg.isReply()) { + final int msgId = msg.messageOwner.reply_to.reply_to_msg_id; + for (int j = 0; j < objects.size(); ++j) { + if (i == j) continue; + if (objects.get(j) != msg && objects.get(j).getId() == msgId) { + msg.replyMessageObject = objects.get(j); + msg.applyTimestampsHighlightForReplyMsg(); + if (msg.messageOwner.action instanceof TLRPC.TL_messageActionPinMessage) { + msg.generatePinMessageText(null, null); + } else if (msg.messageOwner.action instanceof TLRPC.TL_messageActionGameScore) { + msg.generateGameMessageText(null); + } else if (msg.messageOwner.action instanceof TLRPC.TL_messageActionPaymentSent) { + msg.generatePaymentSentMessageText(null); + } + break; + } + } + } + } } AndroidUtilities.runOnUIThread(() -> { putUsers(messagesRes.users, isCache); @@ -9994,9 +10182,9 @@ public void processLoadedMessages(TLRPC.messages_Messages messagesRes, int resCo getNotificationCenter().postNotificationName(NotificationCenter.scheduledMessagesUpdated, dialogId, objects.size(), false); } - if (!DialogObject.isEncryptedDialog(dialogId)) { + if (!DialogObject.isEncryptedDialog(dialogId) && mode != ChatActivity.MODE_QUICK_REPLIES) { int finalFirst_unread_final = first_unread_final; - getMediaDataController().loadReplyMessagesForMessages(objects, dialogId, mode == 1, threadMessageId, () -> { + getMediaDataController().loadReplyMessagesForMessages(objects, dialogId, mode, threadMessageId, () -> { if (!needProcess) { getNotificationCenter().postNotificationName(NotificationCenter.messagesDidLoadWithoutProcess, classGuid, resCount, isCache, isEnd, last_message_id); } else { @@ -14009,7 +14197,7 @@ protected void getChannelDifference(long channelId, int newDialogType, long task if (!msgUpdates.isEmpty()) { SparseArray corrected = new SparseArray<>(); for (TLRPC.TL_updateMessageID update : msgUpdates) { - long[] ids = getMessagesStorage().updateMessageStateAndId(update.random_id, -channelId, null, update.id, 0, false, -1); + long[] ids = getMessagesStorage().updateMessageStateAndId(update.random_id, -channelId, null, update.id, 0, false, -1, 0); if (ids != null) { corrected.put(update.id, ids); } @@ -14074,7 +14262,7 @@ protected void getChannelDifference(long channelId, int newDialogType, long task for (int a = 0; a < messages.size(); a++) { long key = messages.keyAt(a); ArrayList value = messages.valueAt(a); - updateInterfaceWithMessages(key, value, false); + updateInterfaceWithMessages(key, value, 0); } getNotificationCenter().postNotificationName(NotificationCenter.dialogsNeedReload); }); @@ -14265,7 +14453,7 @@ public void getDifference(int pts, int date, int qts, boolean slice) { SparseArray corrected = new SparseArray<>(); for (int a = 0; a < msgUpdates.size(); a++) { TLRPC.TL_updateMessageID update = msgUpdates.get(a); - long[] ids = getMessagesStorage().updateMessageStateAndId(update.random_id, 0, null, update.id, 0, false, -1); + long[] ids = getMessagesStorage().updateMessageStateAndId(update.random_id, 0, null, update.id, 0, false, -1, 0); if (ids != null) { corrected.put(update.id, ids); } @@ -14356,9 +14544,9 @@ public void getDifference(int pts, int date, int qts, boolean slice) { for (int a = 0; a < messages.size(); a++) { long dialogId = messages.keyAt(a); ArrayList arr = messages.valueAt(a); - getMediaDataController().loadReplyMessagesForMessages(arr, dialogId, false, 0, () -> { + getMediaDataController().loadReplyMessagesForMessages(arr, dialogId, 0, 0, () -> { AndroidUtilities.runOnUIThread(() -> { - updateInterfaceWithMessages(dialogId, arr, false); + updateInterfaceWithMessages(dialogId, arr, 0); getNotificationCenter().postNotificationName(NotificationCenter.dialogsNeedReload); }); }, 0); @@ -14875,7 +15063,7 @@ public void generateJoinMessage(long chatId, boolean ignoreLeft) { getMessagesStorage().putMessages(messagesArr, true, true, false, 0, 0, 0); AndroidUtilities.runOnUIThread(() -> { - updateInterfaceWithMessages(-chatId, pushMessages, false); + updateInterfaceWithMessages(-chatId, pushMessages, 0); getNotificationCenter().postNotificationName(NotificationCenter.dialogsNeedReload); }); } @@ -14908,7 +15096,7 @@ protected void deleteMessagesByPush(long dialogId, ArrayList ids, long } }); getMessagesStorage().deletePushMessages(dialogId, ids); - ArrayList dialogIds = getMessagesStorage().markMessagesAsDeleted(dialogId, ids, false, true, false); + ArrayList dialogIds = getMessagesStorage().markMessagesAsDeleted(dialogId, ids, false, true, 0, 0); getMessagesStorage().updateDialogsWithDeletedMessages(dialogId, channelId, ids, dialogIds, false); }); } @@ -14980,7 +15168,7 @@ public void checkChatInviter(long chatId, boolean createMessage) { AndroidUtilities.runOnUIThread(() -> { gettingChatInviters.delete(chatId); if (pushMessages != null) { - updateInterfaceWithMessages(-chatId, pushMessages, false); + updateInterfaceWithMessages(-chatId, pushMessages, 0); getNotificationCenter().postNotificationName(NotificationCenter.dialogsNeedReload); } getNotificationCenter().postNotificationName(NotificationCenter.didLoadChatInviter, chatId, res.participant.inviter_id); @@ -15295,7 +15483,7 @@ public void processUpdates(final TLRPC.Updates updates, boolean fromQueue) { if (printUpdate) { getNotificationCenter().postNotificationName(NotificationCenter.updateInterfaces, UPDATE_MASK_USER_PRINT); } - updateInterfaceWithMessages(userId, objArr, false); + updateInterfaceWithMessages(userId, objArr, 0); getNotificationCenter().postNotificationName(NotificationCenter.dialogsNeedReload); }); } else { @@ -15308,7 +15496,7 @@ public void processUpdates(final TLRPC.Updates updates, boolean fromQueue) { getNotificationCenter().postNotificationName(NotificationCenter.updateInterfaces, UPDATE_MASK_USER_PRINT); } - updateInterfaceWithMessages(-updates.chat_id, objArr, false); + updateInterfaceWithMessages(-updates.chat_id, objArr, 0); getNotificationCenter().postNotificationName(NotificationCenter.dialogsNeedReload); }); } @@ -15700,6 +15888,7 @@ public boolean processUpdateArray(ArrayList updates, ArrayList> markContentAsReadMessages = null; SparseIntArray markAsReadEncrypted = null; LongSparseArray> deletedMessages = null; + LongSparseArray> deletedQuickReplyMessages = null; LongSparseArray> scheduledDeletedMessages = null; LongSparseArray> groupSpeakingActions = null; LongSparseIntArray importingActions = null; @@ -16025,6 +16214,21 @@ public boolean processUpdateArray(ArrayList updates, ArrayList(); + } + ArrayList arrayList = deletedQuickReplyMessages.get(update.shortcut_id); + if (arrayList == null) { + arrayList = new ArrayList<>(); + deletedQuickReplyMessages.put(update.shortcut_id, arrayList); + } + arrayList.addAll(update.messages); + if (updatesOnMainThread == null) { + updatesOnMainThread = new ArrayList<>(); + } + updatesOnMainThread.add(baseUpdate); } else if (baseUpdate instanceof TLRPC.TL_updateDeleteScheduledMessages) { TLRPC.TL_updateDeleteScheduledMessages update = (TLRPC.TL_updateDeleteScheduledMessages) baseUpdate; @@ -16168,7 +16372,7 @@ public boolean processUpdateArray(ArrayList updates, ArrayList(); } chatInfoToUpdate.add(update.participants); - } if (baseUpdate instanceof TL_stories.TL_updateStory) { + } else if (baseUpdate instanceof TL_stories.TL_updateStory) { getStoriesController().processUpdate((TL_stories.TL_updateStory) baseUpdate); } else if (baseUpdate instanceof TLRPC.TL_updateUserStatus) { interfaceUpdateMask |= UPDATE_MASK_STATUS; @@ -16212,7 +16416,7 @@ public boolean processUpdateArray(ArrayList updates, ArrayList(); } updatesOnMainThread.add(baseUpdate); - }else if (baseUpdate instanceof TLRPC.TL_updateUserPhone) { + } else if (baseUpdate instanceof TLRPC.TL_updateUserPhone) { interfaceUpdateMask |= UPDATE_MASK_PHONE; if (updatesOnMainThread == null) { updatesOnMainThread = new ArrayList<>(); @@ -17658,6 +17862,8 @@ public boolean processUpdateArray(ArrayList updates, ArrayList updates, ArrayList value = messagesFinal.valueAt(a); - if (updateInterfaceWithMessages(key, value, false)) { + if (updateInterfaceWithMessages(key, value, 0)) { sorted = true; } } @@ -17770,7 +17976,7 @@ public boolean processUpdateArray(ArrayList updates, ArrayList value = scheduledMessagesFinal.valueAt(a); - updateInterfaceWithMessages(key, value, true); + updateInterfaceWithMessages(key, value, 0); } } if (editingMessagesFinal != null) { @@ -17812,7 +18018,7 @@ public boolean processUpdateArray(ArrayList updates, ArrayList updates, ArrayList> markContentAsReadMessagesFinal = markContentAsReadMessages; SparseIntArray markAsReadEncryptedFinal = markAsReadEncrypted; LongSparseArray> deletedMessagesFinal = deletedMessages; + LongSparseArray> deletedQuickRepliesMessagesFinal = deletedQuickReplyMessages; LongSparseArray> scheduledDeletedMessagesFinal = scheduledDeletedMessages; LongSparseIntArray clearHistoryMessagesFinal = clearHistoryMessages; getMessagesStorage().getStorageQueue().postRunnable(() -> AndroidUtilities.runOnUIThread(() -> { @@ -17972,6 +18179,16 @@ public boolean processUpdateArray(ArrayList updates, ArrayList arrayList = deletedQuickRepliesMessagesFinal.valueAt(a); + if (arrayList == null) { + continue; + } + getNotificationCenter().postNotificationName(NotificationCenter.quickRepliesDeleted, arrayList, topicId); + } + } if (scheduledDeletedMessagesFinal != null) { for (int a = 0, size = scheduledDeletedMessagesFinal.size(); a < size; a++) { long key = scheduledDeletedMessagesFinal.keyAt(a); @@ -18038,17 +18255,27 @@ public boolean processUpdateArray(ArrayList updates, ArrayList arrayList = deletedMessages.valueAt(a); getMessagesStorage().getStorageQueue().postRunnable(() -> { - ArrayList dialogIds = getMessagesStorage().markMessagesAsDeleted(key, arrayList, false, true, false); + ArrayList dialogIds = getMessagesStorage().markMessagesAsDeleted(key, arrayList, false, true, 0, 0); getMessagesStorage().updateDialogsWithDeletedMessages(key, -key, arrayList, dialogIds, false); }); - + } + } + if (deletedQuickReplyMessages != null) { + final long selfId = getUserConfig().getClientUserId(); + for (int a = 0, size = deletedQuickReplyMessages.size(); a < size; a++) { + long topicId = deletedQuickReplyMessages.keyAt(a); + ArrayList ids = deletedQuickReplyMessages.valueAt(a); + getMessagesStorage().getStorageQueue().postRunnable(() -> { + ArrayList dialogIds = getMessagesStorage().markMessagesAsDeleted(selfId, ids, false, true, ChatActivity.MODE_QUICK_REPLIES, (int) topicId); + getMessagesStorage().updateDialogsWithDeletedMessages(selfId, -selfId, ids, dialogIds, false); + }); } } if (scheduledDeletedMessages != null) { for (int a = 0, size = scheduledDeletedMessages.size(); a < size; a++) { long key = scheduledDeletedMessages.keyAt(a); ArrayList arrayList = scheduledDeletedMessages.valueAt(a); - getMessagesStorage().markMessagesAsDeleted(key, arrayList, true, false, true); + getMessagesStorage().markMessagesAsDeleted(key, arrayList, true, false, ChatActivity.MODE_SCHEDULED, 0); } } if (clearHistoryMessages != null) { @@ -18498,17 +18725,19 @@ private boolean updatePrintingUsersWithNewMessages(long uid, ArrayList messages, boolean scheduled) { + public boolean updateInterfaceWithMessages(long dialogId, ArrayList messages, int mode) { if (messages == null || messages.isEmpty()) { return false; } + final boolean scheduled = mode == ChatActivity.MODE_SCHEDULED; + final boolean quickReplies = mode == ChatActivity.MODE_QUICK_REPLIES; boolean isEncryptedChat = DialogObject.isEncryptedDialog(dialogId); MessageObject lastMessage = null; long channelId = 0; boolean updateRating = false; boolean hasNotOutMessage = false; - if (!scheduled) { + if (!scheduled && !quickReplies) { for (int a = 0; a < messages.size(); a++) { MessageObject message = messages.get(a); if (lastMessage == null || (!isEncryptedChat && message.getId() > lastMessage.getId() || (isEncryptedChat || message.getId() < 0 && lastMessage.getId() < 0) && message.getId() < lastMessage.getId()) || message.messageOwner.date > lastMessage.messageOwner.date) { @@ -18546,8 +18775,11 @@ public boolean updateInterfaceWithMessages(long dialogId, ArrayList { ArrayList dbMessages = getMessagesStorage().getCachedMessagesInRange(dialogId, minDate, maxDate); - getMessagesStorage().markMessagesAsDeleted(dialogId, dbMessages, false, true, false); + getMessagesStorage().markMessagesAsDeleted(dialogId, dbMessages, false, true, 0, 0); getMessagesStorage().updateDialogsWithDeletedMessages(dialogId, 0, dbMessages, null, false); AndroidUtilities.runOnUIThread(() -> { getNotificationCenter().postNotificationName(NotificationCenter.messagesDeleted, dbMessages, channelId, false); @@ -20353,6 +20589,10 @@ public void setSavedViewAs(boolean chats) { } } + public void setFolderTags(boolean value) { + mainPreferences.edit().putBoolean("folderTags", folderTags = value).apply(); + } + public boolean isStoryQualityFullOnAccount() { return getUserConfig().isPremium() && storyQualityFull; } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/MessagesStorage.java b/TMessagesProj/src/main/java/org/telegram/messenger/MessagesStorage.java index d8d2ec73d0f..fc62317ed96 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/MessagesStorage.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/MessagesStorage.java @@ -42,6 +42,7 @@ import org.telegram.tgnet.tl.TL_stories; import org.telegram.ui.ActionBar.Theme; import org.telegram.ui.Adapters.DialogsSearchAdapter; +import org.telegram.ui.Business.QuickRepliesController; import org.telegram.ui.ChatActivity; import org.telegram.ui.Components.Reactions.ReactionsLayoutInBubble; import org.telegram.ui.DialogsActivity; @@ -105,7 +106,7 @@ public class MessagesStorage extends BaseController { } } - public final static int LAST_DB_VERSION = 143; + public final static int LAST_DB_VERSION = 149; private boolean databaseMigrationInProgress; public boolean showClearDatabaseAlert; private LongSparseIntArray dialogIsForum = new LongSparseIntArray(); @@ -442,6 +443,7 @@ private boolean recoverDatabase() { "messages_holes", "media_holes_v2", "scheduled_messages_v2", + "quick_replies", "messages_v2", "download_queue", "user_contacts_v7", @@ -558,7 +560,7 @@ public static void createTables(SQLiteDatabase database) throws SQLiteException database.executeFast("CREATE INDEX IF NOT EXISTS folder_id_idx_dialogs ON dialogs(folder_id);").stepThis().dispose(); database.executeFast("CREATE INDEX IF NOT EXISTS flags_idx_dialogs ON dialogs(flags);").stepThis().dispose(); - database.executeFast("CREATE TABLE dialog_filter(id INTEGER PRIMARY KEY, ord INTEGER, unread_count INTEGER, flags INTEGER, title TEXT)").stepThis().dispose(); + database.executeFast("CREATE TABLE dialog_filter(id INTEGER PRIMARY KEY, ord INTEGER, unread_count INTEGER, flags INTEGER, title TEXT, color INTEGER DEFAULT -1)").stepThis().dispose(); database.executeFast("CREATE TABLE dialog_filter_ep(id INTEGER, peer INTEGER, PRIMARY KEY (id, peer))").stepThis().dispose(); database.executeFast("CREATE TABLE dialog_filter_pin_v2(id INTEGER, peer INTEGER, pin INTEGER, PRIMARY KEY (id, peer))").stepThis().dispose(); @@ -682,7 +684,7 @@ public static void createTables(SQLiteDatabase database) throws SQLiteException database.executeFast("CREATE TABLE media_holes_topics(uid INTEGER, topic_id INTEGER, type INTEGER, start INTEGER, end INTEGER, PRIMARY KEY(uid, topic_id, type, start));").stepThis().dispose(); database.executeFast("CREATE INDEX IF NOT EXISTS uid_end_media_holes_topics ON media_holes_topics(uid, topic_id, type, end);").stepThis().dispose(); - database.executeFast("CREATE TABLE topics(did INTEGER, topic_id INTEGER, data BLOB, top_message INTEGER, topic_message BLOB, unread_count INTEGER, max_read_id INTEGER, unread_mentions INTEGER, unread_reactions INTEGER, read_outbox INTEGER, pinned INTEGER, total_messages_count INTEGER, hidden INTEGER, PRIMARY KEY(did, topic_id));").stepThis().dispose(); + database.executeFast("CREATE TABLE topics(did INTEGER, topic_id INTEGER, data BLOB, top_message INTEGER, topic_message BLOB, unread_count INTEGER, max_read_id INTEGER, unread_mentions INTEGER, unread_reactions INTEGER, read_outbox INTEGER, pinned INTEGER, total_messages_count INTEGER, hidden INTEGER, edit_date INTEGER, PRIMARY KEY(did, topic_id));").stepThis().dispose(); database.executeFast("CREATE INDEX IF NOT EXISTS did_top_message_topics ON topics(did, top_message);").stepThis().dispose(); database.executeFast("CREATE INDEX IF NOT EXISTS did_topics ON topics(did);").stepThis().dispose(); @@ -713,6 +715,13 @@ public static void createTables(SQLiteDatabase database) throws SQLiteException database.executeFast("CREATE INDEX IF NOT EXISTS tag_topic_idx_tag_message_id ON tag_message_id(topic_id, tag);").stepThis().dispose(); database.executeFast("CREATE INDEX IF NOT EXISTS tag_topic_text_idx_tag_message_id ON tag_message_id(topic_id, tag, text COLLATE NOCASE);").stepThis().dispose(); + database.executeFast("CREATE TABLE business_replies(topic_id INTEGER PRIMARY KEY, name TEXT, order_value INTEGER, count INTEGER);").stepThis().dispose(); + database.executeFast("CREATE TABLE quick_replies_messages(mid INTEGER, topic_id INTEGER, send_state INTEGER, date INTEGER, data BLOB, ttl INTEGER, replydata BLOB, reply_to_message_id INTEGER, PRIMARY KEY(mid, topic_id))").stepThis().dispose(); + database.executeFast("CREATE INDEX IF NOT EXISTS topic_date_idx_quick_replies_messages ON quick_replies_messages(topic_id, date);").stepThis().dispose(); + database.executeFast("CREATE INDEX IF NOT EXISTS reply_to_idx_quick_replies_messages ON quick_replies_messages(mid, reply_to_message_id);").stepThis().dispose(); + database.executeFast("CREATE INDEX IF NOT EXISTS idx_to_reply_quick_replies_messages ON quick_replies_messages(reply_to_message_id, mid);").stepThis().dispose(); + + database.executeFast("PRAGMA user_version = " + MessagesStorage.LAST_DB_VERSION).stepThis().dispose(); } @@ -1026,7 +1035,7 @@ private void loadPendingTasks() { removePendingTask(taskId); } else { TLObject finalRequest = request; - AndroidUtilities.runOnUIThread(() -> getMessagesController().deleteMessages(null, null, null, -channelId, true, false, false, taskId, finalRequest)); + AndroidUtilities.runOnUIThread(() -> getMessagesController().deleteMessages(null, null, null, -channelId, true, 0, false, taskId, finalRequest, 0)); } break; } @@ -1041,7 +1050,23 @@ private void loadPendingTasks() { removePendingTask(taskId); } else { TLObject finalRequest = request; - AndroidUtilities.runOnUIThread(() -> getMessagesController().deleteMessages(null, null, null, dialogId, true, false, false, taskId, finalRequest)); + AndroidUtilities.runOnUIThread(() -> getMessagesController().deleteMessages(null, null, null, dialogId, true, 0, false, taskId, finalRequest, 0)); + } + break; + } + case 103: { + long dialogId = data.readInt64(false); + int topicId = data.readInt32(false); + int constructor = data.readInt32(false); + TLObject request = TLRPC.TL_messages_deleteMessages.TLdeserialize(data, constructor, false); + if (request == null) { + request = TLRPC.TL_channels_deleteMessages.TLdeserialize(data, constructor, false); + } + if (request == null) { + removePendingTask(taskId); + } else { + TLObject finalRequest = request; + AndroidUtilities.runOnUIThread(() -> getMessagesController().deleteMessages(null, null, null, dialogId, true, 0, false, taskId, finalRequest, topicId)); } break; } @@ -1143,7 +1168,7 @@ private void loadPendingTasks() { if (request == null) { removePendingTask(taskId); } else { - AndroidUtilities.runOnUIThread(() -> getMessagesController().deleteMessages(null, null, null, dialogId, true, true, false, taskId, request)); + AndroidUtilities.runOnUIThread(() -> getMessagesController().deleteMessages(null, null, null, dialogId, true, ChatActivity.MODE_SCHEDULED, false, taskId, request, 0)); } break; } @@ -1364,6 +1389,8 @@ public void clearLocalDatabase() { database.executeFast("DELETE FROM dialog_photos").stepThis().dispose(); database.executeFast("DELETE FROM dialog_photos_count").stepThis().dispose(); database.executeFast("DELETE FROM saved_reaction_tags").stepThis().dispose(); + database.executeFast("DELETE FROM business_replies").stepThis().dispose(); + database.executeFast("DELETE FROM quick_replies_messages").stepThis().dispose(); cursor = database.queryFinalized("SELECT did FROM dialogs WHERE 1"); @@ -1464,17 +1491,17 @@ public void clearLocalDatabase() { }); } - public void saveTopics(long dialogId, List topics, boolean replace, boolean useQueue) { + public void saveTopics(long dialogId, List topics, boolean replace, boolean useQueue, int date) { if (useQueue) { storageQueue.postRunnable(() -> { - saveTopicsInternal(dialogId, topics, replace, true); + saveTopicsInternal(dialogId, topics, replace, true, date); }); } else { - saveTopicsInternal(dialogId, topics, replace, false); + saveTopicsInternal(dialogId, topics, replace, false, date); } } - private void saveTopicsInternal(long dialogId, List topics, boolean replace, boolean inTransaction) { + private void saveTopicsInternal(long dialogId, List topics, boolean replace, boolean inTransaction, int date) { SQLitePreparedStatement state = null; try { HashSet existingTopics = new HashSet<>(); @@ -1495,7 +1522,7 @@ private void saveTopicsInternal(long dialogId, List topics, if (replace) { database.executeFast("DELETE FROM topics WHERE did = " + dialogId).stepThis().dispose(); } - state = database.executeFast("REPLACE INTO topics VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"); + state = database.executeFast("REPLACE INTO topics VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"); if (inTransaction) { database.beginTransaction(); } @@ -1528,6 +1555,7 @@ private void saveTopicsInternal(long dialogId, List topics, } state.bindInteger(12, topic.totalMessagesCount); state.bindInteger(13, topic.hidden ? 1 : 0); + state.bindInteger(14, date); state.step(); messageData.reuse(); @@ -1563,6 +1591,10 @@ private void saveTopicsInternal(long dialogId, List topics, } public void updateTopicData(long dialogId, TLRPC.TL_forumTopic fromTopic, int flags) { + updateTopicData(dialogId, fromTopic, flags, getConnectionsManager().getCurrentTime()); + } + + public void updateTopicData(long dialogId, TLRPC.TL_forumTopic fromTopic, int flags, int date) { if (fromTopic == null) { return; } @@ -1582,10 +1614,12 @@ public void updateTopicData(long dialogId, TLRPC.TL_forumTopic fromTopic, int fl return; } } + int currentEditDate = 0; TLRPC.TL_forumTopic topicToUpdate = null; - cursor = database.queryFinalized(String.format(Locale.US, "SELECT data FROM topics WHERE did = %d AND topic_id = %d", dialogId, fromTopic.id)); + cursor = database.queryFinalized(String.format(Locale.US, "SELECT data, edit_date FROM topics WHERE did = %d AND topic_id = %d", dialogId, fromTopic.id)); if (cursor.next()) { NativeByteBuffer data = cursor.byteBufferValue(0); + currentEditDate = cursor.intValue(1); if (data != null) { topicToUpdate = TLRPC.TL_forumTopic.TLdeserialize(data, data.readInt32(true), true); data.reuse(); @@ -1594,7 +1628,7 @@ public void updateTopicData(long dialogId, TLRPC.TL_forumTopic fromTopic, int fl cursor.dispose(); cursor = null; - if (topicToUpdate != null) { + if (topicToUpdate != null && (currentEditDate == 0 || currentEditDate <= date)) { if ((flags & TopicsController.TOPIC_FLAG_TITLE) != 0) { topicToUpdate.title = fromTopic.title; } @@ -1613,17 +1647,23 @@ public void updateTopicData(long dialogId, TLRPC.TL_forumTopic fromTopic, int fl if ((flags & TopicsController.TOPIC_FLAG_HIDE) != 0) { topicToUpdate.hidden = fromTopic.hidden; } - state = database.executeFast("UPDATE topics SET data = ?, pinned = ?, hidden = ? WHERE did = ? AND topic_id = ?"); + state = database.executeFast("UPDATE topics SET data = ?, pinned = ?, hidden = ?, edit_date = ? WHERE did = ? AND topic_id = ?"); database.beginTransaction(); NativeByteBuffer data = new NativeByteBuffer(topicToUpdate.getObjectSize()); topicToUpdate.serializeToStream(data); state.bindByteBuffer(1, data); state.bindInteger(2, pinnedOrder); state.bindInteger(3, topicToUpdate.hidden ? 1 : 0); - state.bindLong(4, dialogId); - state.bindInteger(5, topicToUpdate.id); + state.bindInteger(4, date); + state.bindLong(5, dialogId); + state.bindInteger(6, topicToUpdate.id); state.step(); data.reuse(); + + int finalFlags = flags; + AndroidUtilities.runOnUIThread(() -> { + getMessagesController().getTopicsController().updateTopicInUi(dialogId, fromTopic, finalFlags); + }); } } catch (Exception e) { checkSQLException(e); @@ -1774,7 +1814,7 @@ public void loadTopics(long dialogId, Consumer> c } } - loadReplyMessages(replyMessageOwners, dialogReplyMessagesIds, usersToLoad, chatsToLoad, false); + loadReplyMessages(replyMessageOwners, dialogReplyMessagesIds, usersToLoad, chatsToLoad, 0); ArrayList chats = new ArrayList<>(); ArrayList users = new ArrayList<>(); @@ -1956,7 +1996,7 @@ public void deleteSavedDialog(long did) { cursor.dispose(); cursor = null; if (!mids.isEmpty()) { - markMessagesAsDeletedInternal(selfId, mids, true, false); + markMessagesAsDeletedInternal(selfId, mids, true, 0, 0); updateDialogsWithDeletedMessages(selfId, -selfId, mids, null, false); AndroidUtilities.runOnUIThread(() -> { getMessagesController().markDialogMessageAsDeleted(selfId, mids); @@ -2373,7 +2413,7 @@ private void loadDialogFilters() { usersToLoad.add(getUserConfig().getClientUserId()); - filtersCursor = database.queryFinalized("SELECT id, ord, unread_count, flags, title FROM dialog_filter WHERE 1"); + filtersCursor = database.queryFinalized("SELECT id, ord, unread_count, flags, title, color FROM dialog_filter WHERE 1"); boolean updateCounters = false; boolean hasDefaultFilter = false; @@ -2384,6 +2424,7 @@ private void loadDialogFilters() { filter.pendingUnreadCount = filter.unreadCount = -1;//filtersCursor.intValue(2); filter.flags = filtersCursor.intValue(3); filter.name = filtersCursor.stringValue(4); + filter.color = filtersCursor.intValue(5); dialogFilters.add(filter); dialogFiltersMap.put(filter.id, filter); filtersById.put(filter.id, filter); @@ -2444,6 +2485,7 @@ private void loadDialogFilters() { MessagesController.DialogFilter filter = new MessagesController.DialogFilter(); filter.id = 0; filter.order = 0; + filter.color = -1; filter.name = "ALL_CHATS"; for (int i = 0; i < dialogFilters.size(); i++) { dialogFilters.get(i).order++; @@ -2452,12 +2494,13 @@ private void loadDialogFilters() { dialogFiltersMap.put(filter.id, filter); filtersById.put(filter.id, filter); - state = database.executeFast("REPLACE INTO dialog_filter VALUES(?, ?, ?, ?, ?)"); + state = database.executeFast("REPLACE INTO dialog_filter VALUES(?, ?, ?, ?, ?, ?)"); state.bindInteger(1, filter.id); state.bindInteger(2, filter.order); state.bindInteger(3, filter.unreadCount); state.bindInteger(4, filter.flags); state.bindString(5, filter.name); + state.bindInteger(6, filter.color); state.stepThis().dispose(); state = null; } @@ -2930,12 +2973,13 @@ private void saveDialogFilterInternal(MessagesController.DialogFilter filter, bo dialogFiltersMap.put(filter.id, filter); } - state = database.executeFast("REPLACE INTO dialog_filter VALUES(?, ?, ?, ?, ?)"); + state = database.executeFast("REPLACE INTO dialog_filter VALUES(?, ?, ?, ?, ?, ?)"); state.bindInteger(1, filter.id); state.bindInteger(2, filter.order); state.bindInteger(3, filter.unreadCount); state.bindInteger(4, filter.flags); state.bindString(5, filter.id == 0 ? "ALL_CHATS" : filter.name); + state.bindInteger(6, filter.color); state.step(); state.dispose(); state = null; @@ -3011,7 +3055,7 @@ private ArrayList toPeerIds(ArrayList inputPeers) { return array; } - public void checkLoadedRemoteFilters(TLRPC.Vector vector, Runnable onDone) { + public void checkLoadedRemoteFilters(ArrayList vector, Runnable onDone) { storageQueue.postRunnable(() -> { try { SparseArray filtersToDelete = new SparseArray<>(); @@ -3031,8 +3075,8 @@ public void checkLoadedRemoteFilters(TLRPC.Vector vector, Runnable onDone) { ArrayList filtersToSave = new ArrayList<>(); HashMap> filterDialogRemovals = new HashMap<>(); HashSet filtersUnreadCounterReset = new HashSet<>(); - for (int a = 0, N = vector.objects.size(); a < N; a++) { - TLRPC.DialogFilter newFilter = (TLRPC.DialogFilter) vector.objects.get(a); + for (int a = 0, N = vector.size(); a < N; a++) { + TLRPC.DialogFilter newFilter = (TLRPC.DialogFilter) vector.get(a); filtersOrder.add(newFilter.id); int newFlags = 0; if (newFilter.contacts) { @@ -3075,6 +3119,11 @@ public void checkLoadedRemoteFilters(TLRPC.Vector vector, Runnable onDone) { changed = true; filter.name = newFilter.title; } + final int color = (newFilter.flags & 134217728) != 0 ? newFilter.color : -1; + if (filter.color != color) { + filter.color = color; + changed = true; + } if (filter.flags != newFlags) { filter.flags = newFlags; changed = true; @@ -3209,6 +3258,7 @@ public void checkLoadedRemoteFilters(TLRPC.Vector vector, Runnable onDone) { filter.id = newFilter.id; filter.flags = newFlags; filter.name = newFilter.title; + filter.color = (newFilter.flags & 134217728) != 0 ? newFilter.color : -1; filter.pendingUnreadCount = -1; for (int c = 0; c < 2; c++) { if (c == 0) { @@ -3428,7 +3478,7 @@ public void saveDialogFiltersOrder() { protected static void addReplyMessages(TLRPC.Message message, LongSparseArray>> replyMessageOwners, LongSparseArray> dialogReplyMessagesIds) { int messageId = message.reply_to.reply_to_msg_id; - long dialogId = MessageObject.getReplyToDialogId(message); + long dialogId = (message.flags & 1073741824) != 0 ? message.quick_reply_shortcut_id : MessageObject.getReplyToDialogId(message); SparseArray> sparseArray = replyMessageOwners.get(dialogId); ArrayList ids = dialogReplyMessagesIds.get(dialogId); if (sparseArray == null) { @@ -3450,11 +3500,15 @@ protected static void addReplyMessages(TLRPC.Message message, LongSparseArray>> replyMessageOwners, LongSparseArray> dialogReplyMessagesIds, ArrayList usersToLoad, ArrayList chatsToLoad, boolean scheduled) throws SQLiteException { + protected void loadReplyMessages(LongSparseArray>> replyMessageOwners, LongSparseArray> dialogReplyMessagesIds, ArrayList usersToLoad, ArrayList chatsToLoad, int mode) throws SQLiteException { if (replyMessageOwners.isEmpty()) { return; } + final boolean scheduled = mode == ChatActivity.MODE_SCHEDULED; + final boolean quickReplies = mode == ChatActivity.MODE_QUICK_REPLIES; + final long selfId = getUserConfig().getClientUserId(); + for (int b = 0, N2 = replyMessageOwners.size(); b < N2; b++) { long dialogId = replyMessageOwners.keyAt(b); SparseArray> owners = replyMessageOwners.valueAt(b); @@ -3469,7 +3523,9 @@ protected void loadReplyMessages(LongSparseArray { SQLiteCursor cursor = null; + SQLiteCursor cursor2 = null; try { SparseArray messageHashMap = new SparseArray<>(); ArrayList messages = new ArrayList<>(); @@ -8007,6 +8070,66 @@ public void getUnsentMessages(int count) { cursor.dispose(); cursor = null; + final long selfId = getUserConfig().getClientUserId(); + cursor = database.queryFinalized("SELECT m.data, m.send_state, m.mid, m.date, m.topic_id, m.ttl FROM quick_replies_messages as m WHERE (m.mid < 0 AND m.send_state = 1) OR (m.mid > 0 AND m.send_state = 3) ORDER BY mid DESC"); + while (cursor.next()) { + NativeByteBuffer data = cursor.byteBufferValue(0); + if (data != null) { + TLRPC.Message message = TLRPC.Message.TLdeserialize(data, data.readInt32(false), false); + message.send_state = cursor.intValue(1); + message.readAttachPath(data, getUserConfig().clientUserId); + data.reuse(); + if (messageHashMap.indexOfKey(message.id) < 0) { + message.id = cursor.intValue(2); + String topicName = null; + int topic_id = cursor.intValue(4); + cursor2 = database.queryFinalized("SELECT name FROM business_replies WHERE topic_id = ?", topic_id); + if (cursor2.next()) { + topicName = cursor2.stringValue(1); + } + cursor2.dispose(); + if (topicName == null) { + database.executeFast("DELETE FROM quick_replies_messages WHERE mid = " + message.id + " AND topic_id = " + topic_id).stepThis().dispose(); + continue; + } + TLRPC.TL_inputQuickReplyShortcut shortcut = new TLRPC.TL_inputQuickReplyShortcut(); + shortcut.shortcut = topicName; + message.quick_reply_shortcut = shortcut; + message.quick_reply_shortcut_id = topic_id; + if (topic_id != 0) { + message.flags |= 1073741824; + } + message.date = cursor.intValue(3); + message.ttl = cursor.intValue(5); + scheduledMessages.add(message); + messageHashMap.put(message.id, message); + + if (DialogObject.isEncryptedDialog(message.dialog_id)) { + int encryptedChatId = DialogObject.getEncryptedChatId(message.dialog_id); + if (!encryptedChatIds.contains(encryptedChatId)) { + encryptedChatIds.add(encryptedChatId); + } + } else if (DialogObject.isUserDialog(message.dialog_id)) { + if (!usersToLoad.contains(message.dialog_id)) { + usersToLoad.add(message.dialog_id); + } + } else { + if (!chatsToLoad.contains(-message.dialog_id)) { + chatsToLoad.add(-message.dialog_id); + } + } + + addUsersAndChatsFromMessage(message, usersToLoad, chatsToLoad, null); + + if (message.send_state != 3 && (message.peer_id.channel_id == 0 && !MessageObject.isUnread(message) && !DialogObject.isEncryptedDialog(message.dialog_id) || message.id > 0)) { + message.send_state = 0; + } + } + } + } + cursor.dispose(); + cursor = null; + if (!encryptedChatIds.isEmpty()) { getEncryptedChatsInternal(TextUtils.join(",", encryptedChatIds), encryptedChats, usersToLoad); } @@ -8166,6 +8289,7 @@ public Runnable getMessagesInternal(long dialogId, long mergeDialogId, int count long startLoadTime = SystemClock.elapsedRealtime(); SQLiteCursor cursor = null; final boolean scheduled = mode == ChatActivity.MODE_SCHEDULED; + final boolean quickReplies = mode == ChatActivity.MODE_QUICK_REPLIES; try { ArrayList usersToLoad = new ArrayList<>(); ArrayList chatsToLoad = new ArrayList<>(); @@ -8241,6 +8365,59 @@ public Runnable getMessagesInternal(long dialogId, long mergeDialogId, int count } cursor.dispose(); cursor = null; + } else if (quickReplies) { + isEnd = true; + if (threadMessageId != 0) { + cursor = database.queryFinalized("SELECT m.data, m.send_state, m.mid, m.date, m.replydata, m.ttl FROM quick_replies_messages as m WHERE m.topic_id = ? ORDER BY m.mid DESC", threadMessageId); + while (cursor.next()) { + NativeByteBuffer data = cursor.byteBufferValue(0); + if (data != null) { + TLRPC.Message message = TLRPC.Message.TLdeserialize(data, data.readInt32(false), false); + message.send_state = cursor.intValue(1); + message.id = cursor.intValue(2); + if (message.id > 0 && message.send_state != 0 && message.send_state != 3) { + message.send_state = 0; + } + if (dialogId == currentUserId) { + message.out = true; + message.unread = false; + } else { + message.unread = true; + } + message.readAttachPath(data, currentUserId); + data.reuse(); + message.date = cursor.intValue(3); + message.dialog_id = dialogId; + if (message.ttl == 0) { + message.ttl = cursor.intValue(5); + } + res.messages.add(message); + + addUsersAndChatsFromMessage(message, usersToLoad, chatsToLoad, animatedEmojiToLoad); + + if (message.reply_to != null && (message.reply_to.reply_to_msg_id != 0 || message.reply_to.reply_to_random_id != 0)) { + if (!cursor.isNull(4)) { + data = cursor.byteBufferValue(4); + if (data != null) { + message.replyMessage = TLRPC.Message.TLdeserialize(data, data.readInt32(false), false); + message.replyMessage.readAttachPath(data, currentUserId); + data.reuse(); + if (message.replyMessage != null) { + addUsersAndChatsFromMessage(message.replyMessage, usersToLoad, chatsToLoad, animatedEmojiToLoad); + } + } + } + if (message.replyMessage == null) { + if (message.reply_to.reply_to_msg_id != 0) { + addReplyMessages(message, replyMessageOwners, dialogReplyMessagesIds); + } + } + } + } + } + cursor.dispose(); + cursor = null; + } } else { if (!DialogObject.isEncryptedDialog(dialogId)) { if (load_type == LOAD_AROUND_MESSAGE && minDate == 0) { @@ -8997,7 +9174,7 @@ public Runnable getMessagesInternal(long dialogId, long mergeDialogId, int count } } } else { - loadReplyMessages(replyMessageOwners, dialogReplyMessagesIds, usersToLoad, chatsToLoad, scheduled); + loadReplyMessages(replyMessageOwners, dialogReplyMessagesIds, usersToLoad, chatsToLoad, mode); } if (!usersToLoad.isEmpty()) { getUsersInternal(TextUtils.join(",", usersToLoad), res.users); @@ -10840,8 +11017,15 @@ private void putMessagesInternal(ArrayList messages, boolean with SQLitePreparedStatement state_media_topics = null; SQLiteCursor cursor = null; try { + if (messages != null && !messages.isEmpty() && MessageObject.isQuickReply(messages.get(0))) { + mode = ChatActivity.MODE_QUICK_REPLIES; + if (threadMessageId == 0) { + threadMessageId = MessageObject.getQuickReplyId(currentAccount, messages.get(0)); + } + } final boolean scheduled = mode == ChatActivity.MODE_SCHEDULED; final boolean saved = mode == ChatActivity.MODE_SAVED; + final boolean quickReplies = mode == ChatActivity.MODE_QUICK_REPLIES; final long selfId = getUserConfig().getClientUserId(); if (scheduled) { if (withTransaction) { @@ -10904,6 +11088,73 @@ private void putMessagesInternal(ArrayList messages, boolean with for (int a = 0, N = dialogsToUpdate.size(); a < N; a++) { broadcastScheduledMessagesChange(dialogsToUpdate.get(a)); } + } else if (quickReplies) { + if (withTransaction) { + database.beginTransaction(); + databaseInTransaction = true; + } + + state_messages = database.executeFast("REPLACE INTO quick_replies_messages VALUES(?, ?, ?, ?, ?, ?, NULL, 0)"); +// state_randoms = database.executeFast("REPLACE INTO randoms_v2 VALUES(?, ?, ?)"); + ArrayList dialogsToUpdate = new ArrayList<>(); + + for (int a = 0; a < messages.size(); a++) { + TLRPC.Message message = messages.get(a); + if (message instanceof TLRPC.TL_messageEmpty) { + continue; + } + fixUnsupportedMedia(message); + + state_messages.requery(); + int messageId = message.id; + if (message.local_id != 0) { + messageId = message.local_id; + } + MessageObject.normalizeFlags(message); + NativeByteBuffer data = new NativeByteBuffer(message.getObjectSize()); + message.serializeToStream(data); + + long topicId = MessageObject.getQuickReplyId(currentAccount, message); + + if (topicId != 0) { + database.executeFast(String.format(Locale.ENGLISH, "DELETE FROM quick_replies_messages WHERE mid = %d AND topic_id = %d", messageId, topicId)).stepThis().dispose(); + } + + long did = MessageObject.getDialogId(message); + state_messages.bindInteger(1, messageId); + state_messages.bindLong(2, topicId); + state_messages.bindInteger(3, message.send_state); + state_messages.bindInteger(4, message.date); + state_messages.bindByteBuffer(5, data); + state_messages.bindInteger(6, message.ttl); + state_messages.step(); + +// if (message.random_id != 0) { +// state_randoms.requery(); +// state_randoms.bindLong(1, message.random_id); +// state_randoms.bindInteger(2, messageId); +// state_randoms.bindLong(3, message.dialog_id); +// state_randoms.step(); +// } + + data.reuse(); + + if (!dialogsToUpdate.contains(did)) { + dialogsToUpdate.add(did); + } + } + state_messages.dispose(); + state_messages = null; +// state_randoms.dispose(); +// state_randoms = null; + + if (withTransaction) { + database.commitTransaction(); + databaseInTransaction = false; + } + for (int a = 0, N = dialogsToUpdate.size(); a < N; a++) { + broadcastQuickRepliesMessagesChange(dialogsToUpdate.get(a), threadMessageId); + } } else { if (ifNoLastMessage) { TLRPC.Message lastMessage = messages.get(0); @@ -12088,7 +12339,7 @@ private void createOrEditTopic(long dialogId, TLRPC.Message message) { } ArrayList topics = new ArrayList<>(); topics.add(forumTopic); - saveTopics(dialogId, topics, false, false); + saveTopics(dialogId, topics, false, false, message.date); AndroidUtilities.runOnUIThread(() -> { getMessagesController().getTopicsController().onTopicCreated(dialogId, forumTopic, false); }); @@ -12112,11 +12363,7 @@ private void createOrEditTopic(long dialogId, TLRPC.Message message) { if ((action.flags & 8) != 0) { flags += TopicsController.TOPIC_FLAG_HIDE; } - updateTopicData(dialogId, forumTopic, flags); - int finalFlags = flags; - AndroidUtilities.runOnUIThread(() -> { - getMessagesController().getTopicsController().updateTopicInUi(dialogId, forumTopic, finalFlags); - }); + updateTopicData(dialogId, forumTopic, flags, message.date); } } @@ -12135,11 +12382,17 @@ public void putMessages(ArrayList messages, boolean withTransacti } } - public void markMessageAsSendError(TLRPC.Message message, boolean scheduled) { + public void markMessageAsSendError(TLRPC.Message message, int _mode) { storageQueue.postRunnable(() -> { try { + int mode = _mode; long messageId = message.id; - if (scheduled) { + if (MessageObject.isQuickReply(message)) { + mode = ChatActivity.MODE_QUICK_REPLIES; + } + if (mode == ChatActivity.MODE_QUICK_REPLIES) { + database.executeFast(String.format(Locale.US, "UPDATE quick_replies_messages SET send_state = 2 WHERE mid = %d AND topic_id = %d", messageId, MessageObject.getQuickReplyId(currentAccount, message))).stepThis().dispose(); + } else if (mode == ChatActivity.MODE_SCHEDULED) { database.executeFast(String.format(Locale.US, "UPDATE scheduled_messages_v2 SET send_state = 2 WHERE mid = %d AND uid = %d", messageId, MessageObject.getDialogId(message))).stepThis().dispose(); } else { database.executeFast(String.format(Locale.US, "UPDATE messages_v2 SET send_state = 2 WHERE mid = %d AND uid = %d", messageId, MessageObject.getDialogId(message))).stepThis().dispose(); @@ -12171,7 +12424,7 @@ public void setMessageSeq(int mid, int seq_in, int seq_out) { }); } - private long[] updateMessageStateAndIdInternal(long randomId, long dialogId, Integer _oldId, int newId, int date, int scheduled) { + private long[] updateMessageStateAndIdInternal(long randomId, long dialogId, Integer _oldId, int newId, int date, int scheduled, int newTopicId) { SQLiteCursor cursor = null; int oldMessageId; @@ -12193,6 +12446,7 @@ private long[] updateMessageStateAndIdInternal(long randomId, long dialogId, Int return null; } } + final long selfId = getUserConfig().getClientUserId(); oldMessageId = _oldId; if (_oldId < 0 && scheduled == 1) { @@ -12231,6 +12485,7 @@ private long[] updateMessageStateAndIdInternal(long randomId, long dialogId, Int return null; } + int topicId = newTopicId; long did = 0; if (scheduled == -1 || scheduled == 0) { try { @@ -12246,6 +12501,19 @@ private long[] updateMessageStateAndIdInternal(long randomId, long dialogId, Int cursor.dispose(); } } + try { + cursor = database.queryFinalized(String.format(Locale.US, "SELECT topic_id FROM quick_replies_messages WHERE mid = %d LIMIT 1", oldMessageId)); + if (cursor.next()) { + topicId = cursor.intValue(0); + scheduled = 2; + } + } catch (Exception e) { + checkSQLException(e); + } finally { + if (cursor != null) { + cursor.dispose(); + } + } } if (scheduled == -1 || scheduled == 1) { @@ -12264,7 +12532,7 @@ private long[] updateMessageStateAndIdInternal(long randomId, long dialogId, Int } } - if (did == 0) { + if (did == 0 && scheduled != 2) { return null; } SQLitePreparedStatement state = null; @@ -12274,12 +12542,14 @@ private long[] updateMessageStateAndIdInternal(long randomId, long dialogId, Int try { if (scheduled == 0) { state = database.executeFast("UPDATE messages_v2 SET send_state = 0, date = ? WHERE mid = ? AND uid = ?"); - } else { + } else if (scheduled == 1) { state = database.executeFast("UPDATE scheduled_messages_v2 SET send_state = 0, date = ? WHERE mid = ? AND uid = ?"); + } else if (scheduled == 2) { + state = database.executeFast("UPDATE quick_replies_messages SET send_state = 0, date = ? WHERE mid = ? AND topic_id = ?"); } state.bindInteger(1, date); state.bindInteger(2, newId); - state.bindLong(3, did); + state.bindLong(3, scheduled == 2 ? topicId : did); state.step(); if (scheduled == 0) { @@ -12387,7 +12657,7 @@ private long[] updateMessageStateAndIdInternal(long randomId, long dialogId, Int state.dispose(); } } - } else { + } else if (scheduled == 1) { try { state = database.executeFast("UPDATE scheduled_messages_v2 SET mid = ?, send_state = 0 WHERE mid = ? AND uid = ?"); state.bindInteger(1, newId); @@ -12405,17 +12675,36 @@ private long[] updateMessageStateAndIdInternal(long randomId, long dialogId, Int state.dispose(); } } + } else if (scheduled == 2) { + try { + state = database.executeFast("UPDATE quick_replies_messages SET mid = ?, topic_id = ?, send_state = 0 WHERE mid = ? AND topic_id = ?"); + state.bindInteger(1, newId); + state.bindInteger(2, newTopicId); + state.bindInteger(3, oldMessageId); + state.bindLong(4, topicId); + state.step(); + } catch (Exception e) { + try { + database.executeFast(String.format(Locale.US, "DELETE FROM quick_replies_messages WHERE mid = %d AND topic_id = %d", oldMessageId, topicId)).stepThis().dispose(); + } catch (Exception e2) { + checkSQLException(e2); + } + } finally { + if (state != null) { + state.dispose(); + } + } } return new long[]{did, _oldId}; } } - public long[] updateMessageStateAndId(long random_id, long dialogId, Integer _oldId, int newId, int date, boolean useQueue, int scheduled) { + public long[] updateMessageStateAndId(long random_id, long dialogId, Integer _oldId, int newId, int date, boolean useQueue, int scheduled, int topicId) { if (useQueue) { - storageQueue.postRunnable(() -> updateMessageStateAndIdInternal(random_id, dialogId, _oldId, newId, date, scheduled)); + storageQueue.postRunnable(() -> updateMessageStateAndIdInternal(random_id, dialogId, _oldId, newId, date, scheduled, topicId)); } else { - return updateMessageStateAndIdInternal(random_id, dialogId, _oldId, newId, date, scheduled); + return updateMessageStateAndIdInternal(random_id, dialogId, _oldId, newId, date, scheduled, topicId); } return null; } @@ -12675,7 +12964,7 @@ public void markMessagesAsDeletedByRandoms(ArrayList messages) { ArrayList mids = dialogs.valueAt(a); AndroidUtilities.runOnUIThread(() -> getNotificationCenter().postNotificationName(NotificationCenter.messagesDeleted, mids, 0L, false)); updateDialogsWithReadMessagesInternal(mids, null, null, null, null); - markMessagesAsDeletedInternal(dialogId, mids, true, false); + markMessagesAsDeletedInternal(dialogId, mids, true, 0, 0); updateDialogsWithDeletedMessagesInternal(dialogId, 0, mids, null); } } @@ -12719,7 +13008,11 @@ private void broadcastScheduledMessagesChange(Long did) { } } - private ArrayList markMessagesAsDeletedInternal(long dialogId, ArrayList messages, boolean deleteFiles, boolean scheduled) { + private void broadcastQuickRepliesMessagesChange(Long type, long topic_id) { + AndroidUtilities.runOnUIThread(() -> getNotificationCenter().postNotificationName(NotificationCenter.quickRepliesUpdated)); + } + + private ArrayList markMessagesAsDeletedInternal(long dialogId, ArrayList messages, boolean deleteFiles, int mode, int threadMessageId) { SQLiteCursor cursor = null; SQLitePreparedStatement state = null; try { @@ -12727,7 +13020,40 @@ private ArrayList markMessagesAsDeletedInternal(long dialogId, ArrayList dialogsIds = new ArrayList<>(); - if (scheduled) { + final boolean scheduled = mode == ChatActivity.MODE_SCHEDULED; + final boolean quickReplies = mode == ChatActivity.MODE_QUICK_REPLIES; + if (quickReplies) { + String ids = TextUtils.join(",", messages); + +// LongSparseArray> dialogsToUpdate = new LongSparseArray<>(); +// +// cursor = database.queryFinalized(String.format(Locale.US, "SELECT topic_id FROM quick_replies_messages WHERE mid IN(%s)", ids)); +// try { +// while (cursor.next()) { +// long did = cursor.longValue(0); +// long topic_id = cursor.longValue(1); +// ArrayList topicIds = dialogsToUpdate.get(did); +// if (topicIds == null) { +// dialogsToUpdate.put(did, topicIds = new ArrayList<>()); +// topicIds.add(topic_id); +// } else if (topicIds.contains(topic_id)) { +// topicIds.add(topic_id); +// } +// } +// } catch (Exception e) { +// checkSQLException(e); +// } +// cursor.dispose(); +// cursor = null; + database.executeFast(String.format(Locale.US, "DELETE FROM quick_replies_messages WHERE mid IN(%s) AND topic_id = %d", ids, threadMessageId)).stepThis().dispose(); +// for (int a = 0, N = dialogsToUpdate.size(); a < N; a++) { +// long type = dialogsToUpdate.keyAt(a); +// ArrayList topicIds = dialogsToUpdate.valueAt(a); +// for (long topic_id : topicIds) { +// broadcastQuickRepliesMessagesChange(type, topic_id); +// } +// } + } else if (scheduled) { String ids = TextUtils.join(",", messages); ArrayList dialogsToUpdate = new ArrayList<>(); @@ -12886,7 +13212,7 @@ private ArrayList markMessagesAsDeletedInternal(long dialogId, ArrayList markMessagesAsDeletedInternal(long dialogId, ArrayList markMessagesAsDeletedInternal(long dialogId, ArrayList markMessagesAsDeleted(long dialogId, ArrayList messages, boolean useQueue, boolean deleteFiles, boolean scheduled) { + public ArrayList markMessagesAsDeleted(long dialogId, ArrayList messages, boolean useQueue, boolean deleteFiles, int mode, int topicId) { if (messages.isEmpty()) { return null; } if (useQueue) { - storageQueue.postRunnable(() -> markMessagesAsDeletedInternal(dialogId, messages, deleteFiles, scheduled)); + storageQueue.postRunnable(() -> markMessagesAsDeletedInternal(dialogId, messages, deleteFiles, mode, topicId)); } else { - return markMessagesAsDeletedInternal(dialogId, messages, deleteFiles, scheduled); + return markMessagesAsDeletedInternal(dialogId, messages, deleteFiles, mode, topicId); } return null; } @@ -14217,8 +14545,50 @@ public void putMessages(TLRPC.messages_Messages messages, long dialogId, int loa SQLitePreparedStatement state3 = null; SQLiteCursor cursor = null; try { + final long selfId = getUserConfig().getClientUserId(); final boolean scheduled = mode == ChatActivity.MODE_SCHEDULED; - if (scheduled) { + final boolean quickReplies = mode == ChatActivity.MODE_QUICK_REPLIES; + if (quickReplies) { +// final long type = dialogId; + +// database.executeFast(String.format(Locale.US, "DELETE FROM quick_replies_messages WHERE topic_id = %d AND mid > 0", topic_id)).stepThis().dispose(); + state_messages = database.executeFast("REPLACE INTO quick_replies_messages VALUES(?, ?, ?, ?, ?, ?, NULL, 0)"); + int count = messages.messages.size(); + for (int a = 0; a < count; a++) { + TLRPC.Message message = messages.messages.get(a); + if (message instanceof TLRPC.TL_messageEmpty) { + continue; + } + + long topic_id = MessageObject.getQuickReplyId(currentAccount, message); + if (topic_id != 0) { + database.executeFast(String.format(Locale.ENGLISH, "DELETE FROM quick_replies_messages WHERE mid = %d AND topic_id = %d", message.id, topic_id)).stepThis().dispose(); + } + + fixUnsupportedMedia(message); + MessageObject.normalizeFlags(message); + state_messages.requery(); + NativeByteBuffer data = new NativeByteBuffer(message.getObjectSize()); + message.serializeToStream(data); + state_messages.bindInteger(1, message.id); + state_messages.bindLong(2, topic_id); + state_messages.bindInteger(3, message.send_state); + state_messages.bindInteger(4, message.date); + state_messages.bindByteBuffer(5, data); + state_messages.bindInteger(6, message.ttl); + state_messages.step(); + data.reuse(); + } + state_messages.dispose(); + state_messages = null; + + putUsersInternal(messages.users); + putChatsInternal(messages.chats); + + database.commitTransaction(); +// broadcastScheduledMessagesChange(dialogId); + + } else if (scheduled) { database.executeFast(String.format(Locale.US, "DELETE FROM scheduled_messages_v2 WHERE uid = %d AND mid > 0", dialogId)).stepThis().dispose(); state_messages = database.executeFast("REPLACE INTO scheduled_messages_v2 VALUES(?, ?, ?, ?, ?, ?, NULL, 0)"); int count = messages.messages.size(); @@ -14279,7 +14649,6 @@ public void putMessages(TLRPC.messages_Messages messages, long dialogId, int loa closeHolesInMedia(dialogId, minId, maxId, -1, threadMessageId); } int count = messages.messages.size(); - final long selfId = getUserConfig().getClientUserId(); //load_type == 0 ? backward loading //load_type == 1 ? forward loading @@ -14977,6 +15346,9 @@ public void getDialogs(int folderId, int offset, int count, boolean loadDraftsPe } } dialog = dialogFolder; + if (dialogFolder.folder == null) { + continue; + } if (a == 0) { foldersToLoad.add(dialogFolder.folder.id); } @@ -15165,7 +15537,7 @@ public void getDialogs(int folderId, int offset, int count, boolean loadDraftsPe } } - loadReplyMessages(replyMessageOwners, dialogReplyMessagesIds, usersToLoad, chatsToLoad, false); + loadReplyMessages(replyMessageOwners, dialogReplyMessagesIds, usersToLoad, chatsToLoad, 0); if (draftsDialogIds != null) { ArrayList unloadedDialogs = new ArrayList<>(); @@ -16501,7 +16873,7 @@ public void updateUnreadReactionsCount(long dialogId, long topicId, int count, b try { int currentReactions = 0; if (increment) { - SQLiteCursor cursor = database.queryFinalized(String.format("SELECT unread_reactions FROM topics WHERE did = %d AND topic_id = %d", dialogId, topicId)); + SQLiteCursor cursor = database.queryFinalized(String.format(Locale.ENGLISH, "SELECT unread_reactions FROM topics WHERE did = %d AND topic_id = %d", dialogId, topicId)); if (cursor.next()) { currentReactions = cursor.intValue(0); } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/NativeLoader.java b/TMessagesProj/src/main/java/org/telegram/messenger/NativeLoader.java index eb6199d08b4..3c41a71807b 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/NativeLoader.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/NativeLoader.java @@ -22,7 +22,7 @@ public class NativeLoader { - private final static int LIB_VERSION = 47; + private final static int LIB_VERSION = 48; private final static String LIB_NAME = "tmessages." + LIB_VERSION; private final static String LIB_SO_NAME = "lib" + LIB_NAME + ".so"; private final static String LOCALE_LIB_SO_NAME = "lib" + LIB_NAME + "loc.so"; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/NotificationCenter.java b/TMessagesProj/src/main/java/org/telegram/messenger/NotificationCenter.java index 554ee868080..1877a492638 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/NotificationCenter.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/NotificationCenter.java @@ -138,6 +138,9 @@ public class NotificationCenter { public static final int recentEmojiStatusesUpdate = totalEvents++; public static final int updateSearchSettings = totalEvents++; public static final int updateTranscriptionLock = totalEvents++; + public static final int businessMessagesUpdated = totalEvents++; + public static final int quickRepliesUpdated = totalEvents++; + public static final int quickRepliesDeleted = totalEvents++; public static final int messageTranslated = totalEvents++; public static final int messageTranslating = totalEvents++; @@ -236,6 +239,7 @@ public class NotificationCenter { public static final int groupRestrictionsUnlockedByBoosts = totalEvents++; public static final int chatWasBoostedByUser = totalEvents++; public static final int groupPackUpdated = totalEvents++; + public static final int timezonesUpdated = totalEvents++; //global public static final int pushMessagesUpdated = totalEvents++; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/OpenAttachedMenuBotReceiver.java b/TMessagesProj/src/main/java/org/telegram/messenger/OpenAttachedMenuBotReceiver.java new file mode 100644 index 00000000000..e7520ab452a --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/OpenAttachedMenuBotReceiver.java @@ -0,0 +1,40 @@ +package org.telegram.messenger; + +import android.app.Activity; +import android.content.Intent; +import android.os.Bundle; + +import org.telegram.ui.LaunchActivity; + +public class OpenAttachedMenuBotReceiver extends Activity { + + public static String ACTION = "com.tmessages.openshortcutbot"; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + Intent intent = getIntent(); + if (intent == null) { + finish(); + return; + } + if (intent.getAction() == null || !intent.getAction().startsWith(ACTION)) { + finish(); + return; + } + try { + long botId = intent.getLongExtra("botId", 0); + if (botId == 0) { + return; + } + } catch (Throwable e) { + FileLog.e(e); + return; + } + Intent intent2 = new Intent(this, LaunchActivity.class); + intent2.setAction(intent.getAction()); + intent2.putExtras(intent); + startActivity(intent2); + finish(); + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/PushListenerController.java b/TMessagesProj/src/main/java/org/telegram/messenger/PushListenerController.java index afee56ae85e..277d24edcc2 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/PushListenerController.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/PushListenerController.java @@ -151,6 +151,7 @@ public static void processRemoteMessage(@PushType int pushType, String data, lon JSONObject json = new JSONObject(jsonString); if (ApplicationLoader.applicationLoaderInstance != null && ApplicationLoader.applicationLoaderInstance.consumePush(currentAccount, json)) { + countDownLatch.countDown(); return; } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/SecretChatHelper.java b/TMessagesProj/src/main/java/org/telegram/messenger/SecretChatHelper.java index e003ac849c8..2ee05412480 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/SecretChatHelper.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/SecretChatHelper.java @@ -476,7 +476,7 @@ public void sendTTLMessage(TLRPC.EncryptedChat encryptedChat, TLRPC.Message rese newMsgObj.wasJustSent = true; ArrayList objArr = new ArrayList<>(); objArr.add(newMsgObj); - getMessagesController().updateInterfaceWithMessages(message.dialog_id, objArr, false); + getMessagesController().updateInterfaceWithMessages(message.dialog_id, objArr, 0); getNotificationCenter().postNotificationName(NotificationCenter.dialogsNeedReload); } reqSend.random_id = message.random_id; @@ -506,7 +506,7 @@ public void sendScreenshotMessage(TLRPC.EncryptedChat encryptedChat, ArrayList objArr = new ArrayList<>(); objArr.add(newMsgObj); - getMessagesController().updateInterfaceWithMessages(message.dialog_id, objArr, false); + getMessagesController().updateInterfaceWithMessages(message.dialog_id, objArr, 0); getNotificationCenter().postNotificationName(NotificationCenter.dialogsNeedReload); } reqSend.random_id = message.random_id; @@ -756,7 +756,7 @@ protected void performSendEncryptedRequest(TLRPC.DecryptedMessage req, TLRPC.Mes if (isSecretInvisibleMessage(newMsgObj)) { res.date = 0; } - getMessagesStorage().updateMessageStateAndId(newMsgObj.random_id, 0, newMsgObj.id, newMsgObj.id, res.date, false, 0); + getMessagesStorage().updateMessageStateAndId(newMsgObj.random_id, 0, newMsgObj.id, newMsgObj.id, res.date, false, 0, 0); AndroidUtilities.runOnUIThread(() -> { newMsgObj.send_state = MessageObject.MESSAGE_SEND_STATE_SENT; getNotificationCenter().postNotificationName(NotificationCenter.messageReceivedByServer, newMsgObj.id, newMsgObj.id, newMsgObj, newMsgObj.dialog_id, 0L, existFlags, false); @@ -765,7 +765,7 @@ protected void performSendEncryptedRequest(TLRPC.DecryptedMessage req, TLRPC.Mes }); }); } else { - getMessagesStorage().markMessageAsSendError(newMsgObj, false); + getMessagesStorage().markMessageAsSendError(newMsgObj, 0); AndroidUtilities.runOnUIThread(() -> { newMsgObj.send_state = MessageObject.MESSAGE_SEND_STATE_SEND_ERROR; getNotificationCenter().postNotificationName(NotificationCenter.messageSendError, newMsgObj.id); diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/SendMessagesHelper.java b/TMessagesProj/src/main/java/org/telegram/messenger/SendMessagesHelper.java index b690f67337e..d2f196268c5 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/SendMessagesHelper.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/SendMessagesHelper.java @@ -34,7 +34,6 @@ import android.text.Spannable; import android.text.TextUtils; import android.util.Base64; -import android.util.Log; import android.util.SparseArray; import android.util.TypedValue; import android.view.Gravity; @@ -61,6 +60,7 @@ import org.telegram.ui.ActionBar.AlertDialog; import org.telegram.ui.ActionBar.BaseFragment; import org.telegram.ui.ActionBar.Theme; +import org.telegram.ui.Business.QuickRepliesController; import org.telegram.ui.Cells.ChatMessageCell; import org.telegram.ui.ChatActivity; import org.telegram.ui.Components.AlertsCreator; @@ -838,7 +838,7 @@ public void markAsError() { if (type == 4) { for (int a = 0; a < messageObjects.size(); a++) { MessageObject obj = messageObjects.get(a); - getMessagesStorage().markMessageAsSendError(obj.messageOwner, obj.scheduled); + getMessagesStorage().markMessageAsSendError(obj.messageOwner, obj.scheduled ? 1 : 0); obj.messageOwner.send_state = MessageObject.MESSAGE_SEND_STATE_SEND_ERROR; getNotificationCenter().postNotificationName(NotificationCenter.messageSendError, obj.getId()); processSentMessage(obj.getId()); @@ -846,7 +846,7 @@ public void markAsError() { } delayedMessages.remove( "group_" + groupId); } else { - getMessagesStorage().markMessageAsSendError(obj.messageOwner, obj.scheduled); + getMessagesStorage().markMessageAsSendError(obj.messageOwner, obj.scheduled ? 1 : 0); obj.messageOwner.send_state = MessageObject.MESSAGE_SEND_STATE_SEND_ERROR; getNotificationCenter().postNotificationName(NotificationCenter.messageSendError, obj.getId()); processSentMessage(obj.getId()); @@ -1134,7 +1134,15 @@ public void didReceivedNotification(int id, int account, final Object... args) { ArrayList messages = new ArrayList<>(); messages.add(obj.messageOwner); - getMessagesStorage().putMessages(messages, false, true, false, 0, obj.scheduled ? 1 : 0, 0); + int threadMessageId = 0; + int mode = 0; + if (obj.isQuickReply()) { + mode = ChatActivity.MODE_QUICK_REPLIES; + threadMessageId = obj.getQuickReplyId(); + } else if (obj.scheduled) { + mode = ChatActivity.MODE_SCHEDULED; + } + getMessagesStorage().putMessages(messages, false, true, false, 0, mode, threadMessageId); break; } } @@ -1145,7 +1153,15 @@ public void didReceivedNotification(int id, int account, final Object... args) { ArrayList messages = new ArrayList<>(); messages.add(message.obj.messageOwner); - getMessagesStorage().putMessages(messages, false, true, false, 0, message.obj.scheduled ? 1 : 0, 0); + int threadMessageId = 0; + int mode = 0; + if (message.obj.isQuickReply()) { + mode = ChatActivity.MODE_QUICK_REPLIES; + threadMessageId = message.obj.getQuickReplyId(); + } else if (message.obj.scheduled) { + mode = ChatActivity.MODE_SCHEDULED; + } + getMessagesStorage().putMessages(messages, false, true, false, 0, mode, threadMessageId); break; } } @@ -1348,6 +1364,7 @@ public void cancelSendingMessage(ArrayList objects) { boolean enc = false; boolean scheduled = false; long dialogId = 0; + int topicId = 0; for (int c = 0; c < objects.size(); c++) { MessageObject object = objects.get(c); if (object.scheduled) { @@ -1355,6 +1372,9 @@ public void cancelSendingMessage(ArrayList objects) { } dialogId = object.getDialogId(); messageIds.add(object.getId()); + if (object.isQuickReply()) { + topicId = object.getQuickReplyId(); + } TLRPC.Message sendingMessage = removeFromSendingMessages(object.getId(), object.scheduled); if (sendingMessage != null) { getConnectionsManager().cancelRequest(sendingMessage.reqId, true); @@ -1445,7 +1465,13 @@ public void cancelSendingMessage(ArrayList objects) { if (objects.size() == 1 && objects.get(0).isEditing() && objects.get(0).previousMedia != null) { revertEditingMessageObject(objects.get(0)); } else { - getMessagesController().deleteMessages(messageIds, null, null, dialogId, false, scheduled); + int mode = 0; + if (!objects.isEmpty() && objects.get(0).isQuickReply()) { + mode = ChatActivity.MODE_QUICK_REPLIES; + } else if (scheduled) { + mode = ChatActivity.MODE_SCHEDULED; + } + getMessagesController().deleteMessages(messageIds, null, null, dialogId, topicId, false, mode); } } @@ -1460,7 +1486,7 @@ public boolean retrySendMessage(MessageObject messageObject, boolean unsent) { int enc_id = DialogObject.getEncryptedChatId(messageObject.getDialogId()); TLRPC.EncryptedChat encryptedChat = getMessagesController().getEncryptedChat(enc_id); if (encryptedChat == null) { - getMessagesStorage().markMessageAsSendError(messageObject.messageOwner, messageObject.scheduled); + getMessagesStorage().markMessageAsSendError(messageObject.messageOwner, messageObject.scheduled ? 1 : 0); messageObject.messageOwner.send_state = MessageObject.MESSAGE_SEND_STATE_SEND_ERROR; getNotificationCenter().postNotificationName(NotificationCenter.messageSendError, messageObject.getId()); processSentMessage(messageObject.getId()); @@ -1616,7 +1642,7 @@ public void sendScreenshotMessage(TLRPC.User user, int messageId, TLRPC.Message newMsgObj.wasJustSent = true; ArrayList objArr = new ArrayList<>(); objArr.add(newMsgObj); - getMessagesController().updateInterfaceWithMessages(message.dialog_id, objArr, false); + getMessagesController().updateInterfaceWithMessages(message.dialog_id, objArr, 0); getNotificationCenter().postNotificationName(NotificationCenter.dialogsNeedReload); ArrayList arr = new ArrayList<>(); arr.add(message); @@ -1625,7 +1651,7 @@ public void sendScreenshotMessage(TLRPC.User user, int messageId, TLRPC.Message performSendMessageRequest(req, newMsgObj, null, null, null, null, false); } - public void sendSticker(TLRPC.Document document, String query, long peer, MessageObject replyToMsg, MessageObject replyToTopMsg, TL_stories.StoryItem storyItem, ChatActivity.ReplyQuote quote, MessageObject.SendAnimationData sendAnimationData, boolean notify, int scheduleDate, boolean updateStickersOrder, Object parentObject) { + public void sendSticker(TLRPC.Document document, String query, long peer, MessageObject replyToMsg, MessageObject replyToTopMsg, TL_stories.StoryItem storyItem, ChatActivity.ReplyQuote quote, MessageObject.SendAnimationData sendAnimationData, boolean notify, int scheduleDate, boolean updateStickersOrder, Object parentObject, String quick_reply_shortcut, int quick_reply_shortcut_id) { if (document == null) { return; } @@ -1726,6 +1752,8 @@ public void sendSticker(TLRPC.Document document, String query, long peer, Messag SendMessageParams sendMessageParams = SendMessageParams.of((TLRPC.TL_document) finalDocument, null, null, peer, replyToMsg, replyToTopMsg, null, null, null, null, notify, scheduleDate, 0, parentObject, sendAnimationData, false); sendMessageParams.replyToStoryItem = storyItem; sendMessageParams.replyQuote = quote; + sendMessageParams.quick_reply_shortcut = quick_reply_shortcut; + sendMessageParams.quick_reply_shortcut_id = quick_reply_shortcut_id; sendMessage(sendMessageParams); }); }); @@ -1740,6 +1768,8 @@ public void sendSticker(TLRPC.Document document, String query, long peer, Messag SendMessageParams sendMessageParams = SendMessageParams.of((TLRPC.TL_document) finalDocument, null, null, peer, replyToMsg, replyToTopMsg, null, null, null, params, notify, scheduleDate, 0, parentObject, sendAnimationData, updateStickersOrder); sendMessageParams.replyToStoryItem = storyItem; sendMessageParams.replyQuote = quote; + sendMessageParams.quick_reply_shortcut = quick_reply_shortcut; + sendMessageParams.quick_reply_shortcut_id = quick_reply_shortcut_id; sendMessage(sendMessageParams); } } @@ -1823,7 +1853,10 @@ public int sendMessage(ArrayList messages, final long peer, boole if (msgObj.getId() <= 0 || msgObj.needDrawBluredPreview()) { if (msgObj.type == MessageObject.TYPE_TEXT && !TextUtils.isEmpty(msgObj.messageText)) { TLRPC.WebPage webPage = msgObj.messageOwner.media != null ? msgObj.messageOwner.media.webpage : null; - sendMessage(SendMessageParams.of(msgObj.messageText.toString(), peer, null, replyToTopMsg, webPage, webPage != null, msgObj.messageOwner.entities, null, null, notify, scheduleDate, null, false)); + SendMessageParams params = SendMessageParams.of(msgObj.messageText.toString(), peer, null, replyToTopMsg, webPage, webPage != null, msgObj.messageOwner.entities, null, null, notify, scheduleDate, null, false); + params.quick_reply_shortcut = msgObj.getQuickReplyName(); + params.quick_reply_shortcut_id = msgObj.getQuickReplyId(); + sendMessage(params); } continue; } @@ -2141,7 +2174,7 @@ public int sendMessage(ArrayList messages, final long peer, boole if (arr.size() == 100 || a == messages.size() - 1 || a != messages.size() - 1 && messages.get(a + 1).getDialogId() != msgObj.getDialogId()) { getMessagesStorage().putMessages(new ArrayList<>(arr), false, true, false, 0, scheduleDate != 0 ? 1 : 0, 0); - getMessagesController().updateInterfaceWithMessages(peer, objArr, scheduleDate != 0); + getMessagesController().updateInterfaceWithMessages(peer, objArr, 0); getNotificationCenter().postNotificationName(NotificationCenter.dialogsNeedReload); getUserConfig().saveConfig(false); @@ -2199,7 +2232,7 @@ public int sendMessage(ArrayList messages, final long peer, boole int sentCount = 0; for (int a1 = 0; a1 < updates.updates.size(); a1++) { TLRPC.Update update = updates.updates.get(a1); - if (update instanceof TLRPC.TL_updateNewMessage || update instanceof TLRPC.TL_updateNewChannelMessage || update instanceof TLRPC.TL_updateNewScheduledMessage) { + if (update instanceof TLRPC.TL_updateNewMessage || update instanceof TLRPC.TL_updateNewChannelMessage || update instanceof TLRPC.TL_updateNewScheduledMessage || update instanceof TLRPC.TL_updateQuickReplyMessage) { boolean currentSchedule = scheduleDate != 0; @@ -2213,6 +2246,10 @@ public int sendMessage(ArrayList messages, final long peer, boole } else if (update instanceof TLRPC.TL_updateNewScheduledMessage) { TLRPC.TL_updateNewScheduledMessage updateNewMessage = (TLRPC.TL_updateNewScheduledMessage) update; message = updateNewMessage.message; + } else if (update instanceof TLRPC.TL_updateQuickReplyMessage) { + QuickRepliesController.getInstance(currentAccount).processUpdate(update, null, 0); + TLRPC.TL_updateQuickReplyMessage updateQuickReplyMessage = (TLRPC.TL_updateQuickReplyMessage) update; + message = updateQuickReplyMessage.message; } else { TLRPC.TL_updateNewChannelMessage updateNewChannelMessage = (TLRPC.TL_updateNewChannelMessage) update; message = updateNewChannelMessage.message; @@ -2260,13 +2297,13 @@ public int sendMessage(ArrayList messages, final long peer, boole AndroidUtilities.runOnUIThread(() -> { ArrayList messageIds = new ArrayList<>(); messageIds.add(oldId); - getMessagesController().deleteMessages(messageIds, null, null, newMsgObj1.dialog_id, false, true); + getMessagesController().deleteMessages(messageIds, null, null, newMsgObj1.dialog_id, newMsgObj1.quick_reply_shortcut_id, false, ChatActivity.MODE_SCHEDULED); getMessagesStorage().getStorageQueue().postRunnable(() -> { getMessagesStorage().putMessages(sentMessages, true, false, false, 0, 0, 0); AndroidUtilities.runOnUIThread(() -> { ArrayList messageObjects = new ArrayList<>(); messageObjects.add(new MessageObject(msgObj.currentAccount, msgObj.messageOwner, true, true)); - getMessagesController().updateInterfaceWithMessages(newMsgObj1.dialog_id, messageObjects, false); + getMessagesController().updateInterfaceWithMessages(newMsgObj1.dialog_id, messageObjects, 0); getMediaDataController().increasePeerRaiting(newMsgObj1.dialog_id); processSentMessage(oldId); removeFromSendingMessages(oldId, scheduleDate != 0); @@ -2275,8 +2312,12 @@ public int sendMessage(ArrayList messages, final long peer, boole }); } else { getMessagesStorage().getStorageQueue().postRunnable(() -> { - getMessagesStorage().updateMessageStateAndId(newMsgObj1.random_id, MessageObject.getPeerId(peer_id), oldId, newMsgObj1.id, 0, false, scheduleDate != 0 ? 1 : 0); - getMessagesStorage().putMessages(sentMessages, true, false, false, 0, scheduleDate != 0 ? 1 : 0, 0); + int mode = scheduleDate != 0 ? ChatActivity.MODE_SCHEDULED : 0; + if (message.quick_reply_shortcut_id != 0 || message.quick_reply_shortcut != null) { + mode = ChatActivity.MODE_QUICK_REPLIES; + } + getMessagesStorage().updateMessageStateAndId(newMsgObj1.random_id, MessageObject.getPeerId(peer_id), oldId, newMsgObj1.id, 0, false, scheduleDate != 0 ? 1 : 0, message.quick_reply_shortcut_id); + getMessagesStorage().putMessages(sentMessages, true, false, false, 0, mode, message.quick_reply_shortcut_id); AndroidUtilities.runOnUIThread(() -> { newMsgObj1.send_state = MessageObject.MESSAGE_SEND_STATE_SENT; getMediaDataController().increasePeerRaiting(peer); @@ -2298,7 +2339,7 @@ public int sendMessage(ArrayList messages, final long peer, boole } for (int a1 = 0; a1 < newMsgObjArr.size(); a1++) { final TLRPC.Message newMsgObj1 = newMsgObjArr.get(a1); - getMessagesStorage().markMessageAsSendError(newMsgObj1, scheduleDate != 0); + getMessagesStorage().markMessageAsSendError(newMsgObj1, scheduleDate != 0 ? 1 : 0); AndroidUtilities.runOnUIThread(() -> { newMsgObj1.send_state = MessageObject.MESSAGE_SEND_STATE_SEND_ERROR; getNotificationCenter().postNotificationName(NotificationCenter.messageSendError, newMsgObj1.id); @@ -2734,6 +2775,10 @@ public void editMessage(MessageObject messageObject, TLRPC.TL_photo photo, Video request.schedule_date = messageObject.messageOwner.date; request.flags |= 32768; } + if ((messageObject.messageOwner.flags & 1073741824) != 0) { + request.quick_reply_shortcut_id = messageObject.messageOwner.quick_reply_shortcut_id; + request.flags |= 131072; + } if (messageObject.editingMessage != null) { request.message = messageObject.editingMessage.toString(); request.flags |= 2048; @@ -2807,6 +2852,10 @@ public int editMessage(MessageObject messageObject, String message, boolean sear req.no_webpage = !searchLinks; } req.id = messageObject.getId(); + if (messageObject.messageOwner != null && (messageObject.messageOwner.flags & 1073741824) != 0) { + req.quick_reply_shortcut_id = messageObject.messageOwner.quick_reply_shortcut_id; + req.flags |= 131072; + } if (entities != null) { req.entities = entities; req.flags |= 8; @@ -3405,6 +3454,8 @@ public void sendMessage(SendMessageParams sendMessageParams) { TL_stories.StoryItem sendingStory = sendMessageParams.sendingStory; ChatActivity.ReplyQuote replyQuote = sendMessageParams.replyQuote; boolean invert_media = sendMessageParams.invert_media; + String quick_reply_shortcut = sendMessageParams.quick_reply_shortcut; + int quick_reply_shortcut_id = sendMessageParams.quick_reply_shortcut_id; if (user != null && user.phone == null) { return; @@ -3441,7 +3492,7 @@ public void sendMessage(SendMessageParams sendMessageParams) { encryptedChat = getMessagesController().getEncryptedChat(DialogObject.getEncryptedChatId(peer)); if (encryptedChat == null) { if (retryMessageObject != null) { - getMessagesStorage().markMessageAsSendError(retryMessageObject.messageOwner, retryMessageObject.scheduled); + getMessagesStorage().markMessageAsSendError(retryMessageObject.messageOwner, retryMessageObject.scheduled ? 1 : 0); retryMessageObject.messageOwner.send_state = MessageObject.MESSAGE_SEND_STATE_SEND_ERROR; getNotificationCenter().postNotificationName(NotificationCenter.messageSendError, retryMessageObject.getId()); processSentMessage(retryMessageObject.getId()); @@ -3799,6 +3850,21 @@ public void sendMessage(SendMessageParams sendMessageParams) { if (newMsg.random_id == 0) { newMsg.random_id = getNextRandomId(); } + if (quick_reply_shortcut != null || quick_reply_shortcut_id != 0) { + if (quick_reply_shortcut_id != 0) { + TLRPC.TL_inputQuickReplyShortcutId shortcut = new TLRPC.TL_inputQuickReplyShortcutId(); + shortcut.shortcut_id = quick_reply_shortcut_id; + newMsg.quick_reply_shortcut = shortcut; + } else { + TLRPC.TL_inputQuickReplyShortcut shortcut = new TLRPC.TL_inputQuickReplyShortcut(); + shortcut.shortcut = quick_reply_shortcut; + newMsg.quick_reply_shortcut = shortcut; + } + newMsg.quick_reply_shortcut_id = quick_reply_shortcut_id; + if (newMsg.quick_reply_shortcut_id != 0) { + newMsg.flags |= 1073741824; + } + } if (params != null && params.containsKey("bot")) { if (encryptedChat != null) { newMsg.via_bot_name = params.get("bot_name"); @@ -3812,7 +3878,13 @@ public void sendMessage(SendMessageParams sendMessageParams) { } newMsg.params = params; if (retryMessageObject == null || !retryMessageObject.resendAsIs) { - newMsg.date = scheduleDate != 0 ? scheduleDate : getConnectionsManager().getCurrentTime(); + if (quick_reply_shortcut != null) { + newMsg.date = 0; + } else if (scheduleDate != 0) { + newMsg.date = scheduleDate; + } else { + newMsg.date = getConnectionsManager().getCurrentTime(); + } if (sendToPeer instanceof TLRPC.TL_inputPeerChannel) { if (scheduleDate == 0 && isChannel) { newMsg.views = 1; @@ -4046,8 +4118,18 @@ public void sendMessage(SendMessageParams sendMessageParams) { objArr.add(newMsgObj); ArrayList arr = new ArrayList<>(); arr.add(newMsg); - MessagesStorage.getInstance(currentAccount).putMessages(arr, false, true, false, 0, scheduleDate != 0 ? 1 : 0, 0); - MessagesController.getInstance(currentAccount).updateInterfaceWithMessages(peer, objArr, scheduleDate != 0); + long threadMessageId = 0; + final int mode; + if (scheduleDate != 0) { + mode = ChatActivity.MODE_SCHEDULED; + } else if (quick_reply_shortcut != null) { + mode = ChatActivity.MODE_QUICK_REPLIES; + threadMessageId = newMsg.quick_reply_shortcut_id; + } else { + mode = 0; + } + MessagesStorage.getInstance(currentAccount).putMessages(arr, false, true, false, 0, mode, threadMessageId); + MessagesController.getInstance(currentAccount).updateInterfaceWithMessages(peer, objArr, mode); if (scheduleDate == 0) { NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.dialogsNeedReload); } @@ -4116,6 +4198,10 @@ public void sendMessage(SendMessageParams sendMessageParams) { reqSend.schedule_date = scheduleDate; reqSend.flags |= 1024; } + if (newMsg.quick_reply_shortcut != null) { + reqSend.flags |= 131072; + reqSend.quick_reply_shortcut = newMsg.quick_reply_shortcut; + } reqSend.invert_media = newMsg.invert_media; performSendMessageRequest(reqSend, newMsgObj, null, null, parentObject, params, scheduleDate != 0); if (retryMessageObject == null) { @@ -4135,6 +4221,10 @@ public void sendMessage(SendMessageParams sendMessageParams) { reqSend.reply_to = createReplyInput((TLRPC.TL_messageReplyHeader) newMsg.reply_to); reqSend.flags |= 1; } + if (newMsg.quick_reply_shortcut != null) { + reqSend.flags |= 131072; + reqSend.quick_reply_shortcut = newMsg.quick_reply_shortcut; + } if (updateStickersOrder && SharedConfig.updateStickersOrderOnSend) { reqSend.update_stickersets_order = true; } @@ -4486,6 +4576,10 @@ public void sendMessage(SendMessageParams sendMessageParams) { request.schedule_date = scheduleDate; request.flags |= 1024; } + if (newMsg.quick_reply_shortcut != null) { + request.quick_reply_shortcut = newMsg.quick_reply_shortcut; + request.flags |= 131072; + } delayedMessage.sendRequest = request; } delayedMessage.messageObjects.add(newMsgObj); @@ -4538,6 +4632,10 @@ public void sendMessage(SendMessageParams sendMessageParams) { if (updateStickersOrder && SharedConfig.updateStickersOrderOnSend) { request.update_stickersets_order = true; } + if (newMsg.quick_reply_shortcut != null) { + request.flags |= 131072; + request.quick_reply_shortcut = newMsg.quick_reply_shortcut; + } if (delayedMessage != null) { delayedMessage.sendRequest = request; @@ -4913,6 +5011,10 @@ public void sendMessage(SendMessageParams sendMessageParams) { TLRPC.TL_messages_sendInlineBotResult reqSend = new TLRPC.TL_messages_sendInlineBotResult(); reqSend.peer = sendToPeer; reqSend.random_id = newMsg.random_id; + if (newMsg.quick_reply_shortcut != null) { + reqSend.flags |= 131072; + reqSend.quick_reply_shortcut = newMsg.quick_reply_shortcut; + } if (newMsg.from_id != null) { reqSend.send_as = getMessagesController().getInputPeer(newMsg.from_id); @@ -4940,7 +5042,7 @@ public void sendMessage(SendMessageParams sendMessageParams) { } } catch (Exception e) { FileLog.e(e); - getMessagesStorage().markMessageAsSendError(newMsg, scheduleDate != 0); + getMessagesStorage().markMessageAsSendError(newMsg, scheduleDate != 0 ? 1 : 0); if (newMsgObj != null) { newMsgObj.messageOwner.send_state = MessageObject.MESSAGE_SEND_STATE_SEND_ERROR; } @@ -5400,8 +5502,19 @@ private void sendReadyToSendGroup(DelayedMessage message, boolean add, boolean c return; } else if (add) { delayedMessages.remove(key); - getMessagesStorage().putMessages(message.messages, false, true, false, 0, message.scheduled ? 1 : 0, 0); - getMessagesController().updateInterfaceWithMessages(message.peer, message.messageObjects, message.scheduled); + final int mode; + if (message.scheduled) { + mode = ChatActivity.MODE_SCHEDULED; + } else if ( + message.obj != null && message.obj.isQuickReply() || + message.messageObjects != null && !message.messageObjects.isEmpty() && message.messageObjects.get(0).isQuickReply() + ) { + mode = ChatActivity.MODE_QUICK_REPLIES; + } else { + mode = ChatActivity.MODE_DEFAULT; + } + getMessagesStorage().putMessages(message.messages, false, true, false, 0, mode, 0); + getMessagesController().updateInterfaceWithMessages(message.peer, message.messageObjects, mode); if (!message.scheduled) { getNotificationCenter().postNotificationName(NotificationCenter.dialogsNeedReload); } @@ -5610,7 +5723,7 @@ protected void performSendMessageRequestMulti(final TLRPC.TL_messages_sendMultiM if (!hasEmptyFile) { for (int i = 0; i < msgObjs.size(); i++) { TLRPC.Message newMsgObj = msgObjs.get(i).messageOwner; - getMessagesStorage().markMessageAsSendError(newMsgObj, scheduled); + getMessagesStorage().markMessageAsSendError(newMsgObj, scheduled ? 1 : 0); newMsgObj.send_state = MessageObject.MESSAGE_SEND_STATE_SEND_ERROR; getNotificationCenter().postNotificationName(NotificationCenter.messageSendError, newMsgObj.id); processSentMessage(newMsgObj.id); @@ -5684,6 +5797,12 @@ protected void performSendMessageRequestMulti(final TLRPC.TL_messages_sendMultiM newMessages.put(newMessage.message.id, newMessage.message); updatesArr.remove(a); a--; + } else if (update instanceof TLRPC.TL_updateQuickReplyMessage) { + QuickRepliesController.getInstance(currentAccount).processUpdate(update, msgObjs.isEmpty() ? null : msgObjs.get(0).getQuickReplyName(), msgObjs.isEmpty() ? null : msgObjs.get(0).getQuickReplyId()); + final TLRPC.TL_updateQuickReplyMessage newMessage = (TLRPC.TL_updateQuickReplyMessage) update; + newMessages.put(newMessage.message.id, newMessage.message); + updatesArr.remove(a); + a--; } } if (channelReplies != null) { @@ -5714,6 +5833,10 @@ protected void performSendMessageRequestMulti(final TLRPC.TL_messages_sendMultiM updateMediaPaths(msgObj, message, message.id, originalPath, false); existFlags = msgObj.getMediaExistanceFlags(); newMsgObj.id = message.id; + newMsgObj.quick_reply_shortcut_id = message.quick_reply_shortcut_id; + if (newMsgObj.quick_reply_shortcut_id != 0) { + newMsgObj.flags |= 1073741824; + } grouped_id = message.grouped_id; if (!scheduled) { @@ -5738,8 +5861,12 @@ protected void performSendMessageRequestMulti(final TLRPC.TL_messages_sendMultiM newMsgObj.send_state = MessageObject.MESSAGE_SEND_STATE_SENT; getNotificationCenter().postNotificationName(NotificationCenter.messageReceivedByServer, oldId, newMsgObj.id, newMsgObj, newMsgObj.dialog_id, grouped_id, existFlags, scheduled); getMessagesStorage().getStorageQueue().postRunnable(() -> { - getMessagesStorage().updateMessageStateAndId(newMsgObj.random_id, MessageObject.getPeerId(newMsgObj.peer_id), oldId, newMsgObj.id, 0, false, scheduled ? 1 : 0); - getMessagesStorage().putMessages(sentMessages, true, false, false, 0, scheduled ? 1 : 0, 0); + int mode = scheduled ? ChatActivity.MODE_SCHEDULED : 0; + if (newMsgObj.quick_reply_shortcut_id != 0 || newMsgObj.quick_reply_shortcut != null) { + mode = ChatActivity.MODE_QUICK_REPLIES; + } + getMessagesStorage().updateMessageStateAndId(newMsgObj.random_id, MessageObject.getPeerId(newMsgObj.peer_id), oldId, newMsgObj.id, 0, false, scheduled ? 1 : 0, newMsgObj.quick_reply_shortcut_id); + getMessagesStorage().putMessages(sentMessages, true, false, false, 0, mode, newMsgObj.quick_reply_shortcut_id); AndroidUtilities.runOnUIThread(() -> { getMediaDataController().increasePeerRaiting(newMsgObj.dialog_id); getNotificationCenter().postNotificationName(NotificationCenter.messageReceivedByServer, oldId, newMsgObj.id, newMsgObj, newMsgObj.dialog_id, grouped_id, existFlags, scheduled); @@ -5757,7 +5884,7 @@ protected void performSendMessageRequestMulti(final TLRPC.TL_messages_sendMultiM if (isSentError) { for (int i = 0; i < msgObjs.size(); i++) { TLRPC.Message newMsgObj = msgObjs.get(i).messageOwner; - getMessagesStorage().markMessageAsSendError(newMsgObj, scheduled); + getMessagesStorage().markMessageAsSendError(newMsgObj, scheduled ? 1 : 0); newMsgObj.send_state = MessageObject.MESSAGE_SEND_STATE_SEND_ERROR; getNotificationCenter().postNotificationName(NotificationCenter.messageSendError, newMsgObj.id); processSentMessage(newMsgObj.id); @@ -5865,6 +5992,11 @@ protected void performSendMessageRequest(final TLObject req, final MessageObject final TLRPC.TL_updateNewScheduledMessage newMessage = (TLRPC.TL_updateNewScheduledMessage) update; message = newMessage.message; break; + } else if (update instanceof TLRPC.TL_updateQuickReplyMessage) { + QuickRepliesController.getInstance(currentAccount).processUpdate(update, MessageObject.getQuickReplyName(newMsgObj), MessageObject.getQuickReplyId(newMsgObj)); + final TLRPC.TL_updateQuickReplyMessage newMessage = (TLRPC.TL_updateQuickReplyMessage) update; + message = newMessage.message; + break; } } if (message != null) { @@ -5986,6 +6118,12 @@ protected void performSendMessageRequest(final TLObject req, final MessageObject sentMessages.add(message = newMessage.message); updatesArr.remove(a); break; + } else if (update instanceof TLRPC.TL_updateQuickReplyMessage) { + QuickRepliesController.getInstance(currentAccount).processUpdate(update, msgObj.getQuickReplyName(), msgObj.getQuickReplyId()); + final TLRPC.TL_updateQuickReplyMessage newMessage = (TLRPC.TL_updateQuickReplyMessage) update; + sentMessages.add(message = newMessage.message); + updatesArr.remove(a); + break; } } if (channelReplies != null) { @@ -6012,6 +6150,10 @@ protected void performSendMessageRequest(final TLObject req, final MessageObject msgObj.messageOwner.flags |= 33554432; } msgObj.messageOwner.entities = message.entities; + msgObj.messageOwner.quick_reply_shortcut_id = message.quick_reply_shortcut_id; + if (msgObj.messageOwner.quick_reply_shortcut_id != 0) { + msgObj.messageOwner.flags |= 1073741824; + } updateMediaPaths(msgObj, message, message.id, originalPath, false); existFlags = msgObj.getMediaExistanceFlags(); newMsgObj.id = message.id; @@ -6041,13 +6183,13 @@ protected void performSendMessageRequest(final TLObject req, final MessageObject if (scheduled && !currentSchedule) { ArrayList messageIds = new ArrayList<>(); messageIds.add(oldId); - getMessagesController().deleteMessages(messageIds, null, null, newMsgObj.dialog_id, false, true); + getMessagesController().deleteMessages(messageIds, null, null, newMsgObj.dialog_id, 0, false, ChatActivity.MODE_SCHEDULED); getMessagesStorage().getStorageQueue().postRunnable(() -> { getMessagesStorage().putMessages(sentMessages, true, false, false, 0, false, 0, 0); AndroidUtilities.runOnUIThread(() -> { ArrayList messageObjects = new ArrayList<>(); messageObjects.add(new MessageObject(msgObj.currentAccount, msgObj.messageOwner, true, true)); - getMessagesController().updateInterfaceWithMessages(newMsgObj.dialog_id, messageObjects, false); + getMessagesController().updateInterfaceWithMessages(newMsgObj.dialog_id, messageObjects, 0); getMediaDataController().increasePeerRaiting(newMsgObj.dialog_id); processSentMessage(oldId); removeFromSendingMessages(oldId, scheduled); @@ -6056,8 +6198,12 @@ protected void performSendMessageRequest(final TLObject req, final MessageObject } else { getNotificationCenter().postNotificationName(NotificationCenter.messageReceivedByServer, oldId, newMsgObj.id, newMsgObj, newMsgObj.dialog_id, 0L, existFlags, scheduled); getMessagesStorage().getStorageQueue().postRunnable(() -> { - getMessagesStorage().updateMessageStateAndId(newMsgObj.random_id, MessageObject.getPeerId(newMsgObj.peer_id), oldId, newMsgObj.id, 0, false, scheduled ? 1 : 0); - getMessagesStorage().putMessages(sentMessages, true, false, false, 0, scheduled ? 1 : 0, 0); + int mode = scheduled ? ChatActivity.MODE_SCHEDULED : 0; + if (newMsgObj.quick_reply_shortcut_id != 0 || newMsgObj.quick_reply_shortcut != null) { + mode = ChatActivity.MODE_QUICK_REPLIES; + } + getMessagesStorage().updateMessageStateAndId(newMsgObj.random_id, MessageObject.getPeerId(newMsgObj.peer_id), oldId, newMsgObj.id, 0, false, scheduled ? 1 : 0, newMsgObj.quick_reply_shortcut_id); + getMessagesStorage().putMessages(sentMessages, true, false, false, 0, mode, newMsgObj.quick_reply_shortcut_id); AndroidUtilities.runOnUIThread(() -> { getMediaDataController().increasePeerRaiting(newMsgObj.dialog_id); getNotificationCenter().postNotificationName(NotificationCenter.messageReceivedByServer, oldId, newMsgObj.id, newMsgObj, newMsgObj.dialog_id, 0L, existFlags, scheduled); @@ -6072,7 +6218,7 @@ protected void performSendMessageRequest(final TLObject req, final MessageObject isSentError = true; } if (isSentError) { - getMessagesStorage().markMessageAsSendError(newMsgObj, scheduled); + getMessagesStorage().markMessageAsSendError(newMsgObj, scheduled ? 1 : 0); newMsgObj.send_state = MessageObject.MESSAGE_SEND_STATE_SEND_ERROR; getNotificationCenter().postNotificationName(NotificationCenter.messageSendError, newMsgObj.id); processSentMessage(newMsgObj.id); @@ -6273,7 +6419,7 @@ private void updateMediaPaths(MessageObject newMsgObj, TLRPC.Message sentMessage newMsg.media.document.size = sentMessage.media.document.size; newMsg.media.document.mime_type = sentMessage.media.document.mime_type; - if ((sentMessage.flags & TLRPC.MESSAGE_FLAG_FWD) == 0 && MessageObject.isOut(sentMessage)) { + if ((sentMessage.flags & TLRPC.MESSAGE_FLAG_FWD) == 0 && MessageObject.isOut(sentMessage) && !MessageObject.isQuickReply(sentMessage)) { if (MessageObject.isNewGifDocument(sentMessage.media.document)) { boolean save; if (MessageObject.isDocumentHasAttachedStickers(sentMessage.media.document)) { @@ -6583,7 +6729,7 @@ public TLRPC.TL_photo generatePhotoSizes(TLRPC.TL_photo photo, String path, Uri private final static int ERROR_TYPE_UNSUPPORTED = 1; private final static int ERROR_TYPE_FILE_TOO_LARGE = 2; - private static int prepareSendingDocumentInternal(AccountInstance accountInstance, String path, String originalPath, Uri uri, String mime, long dialogId, MessageObject replyToMsg, MessageObject replyToTopMsg, TL_stories.StoryItem storyItem, ChatActivity.ReplyQuote quote, final ArrayList entities, final MessageObject editingMessageObject, long[] groupId, boolean isGroupFinal, CharSequence caption, boolean notify, int scheduleDate, Integer[] docType, boolean forceDocument) { + private static int prepareSendingDocumentInternal(AccountInstance accountInstance, String path, String originalPath, Uri uri, String mime, long dialogId, MessageObject replyToMsg, MessageObject replyToTopMsg, TL_stories.StoryItem storyItem, ChatActivity.ReplyQuote quote, final ArrayList entities, final MessageObject editingMessageObject, long[] groupId, boolean isGroupFinal, CharSequence caption, boolean notify, int scheduleDate, Integer[] docType, boolean forceDocument, String quickReplyShortcut, int quickReplyShortcutId) { if ((path == null || path.length() == 0) && uri == null) { return ERROR_TYPE_UNSUPPORTED; } @@ -6859,6 +7005,8 @@ private static int prepareSendingDocumentInternal(AccountInstance accountInstanc SendMessageParams sendMessageParams = SendMessagesHelper.SendMessageParams.of(documentFinal, null, pathFinal, dialogId, replyToMsg, replyToTopMsg, captionFinal, entities, null, params, notify, scheduleDate, 0, parentFinal, null, false); sendMessageParams.replyToStoryItem = storyItem; sendMessageParams.replyQuote = quote; + sendMessageParams.quick_reply_shortcut = quickReplyShortcut; + sendMessageParams.quick_reply_shortcut_id = quickReplyShortcutId; accountInstance.getSendMessagesHelper().sendMessage(sendMessageParams); } }); @@ -6890,7 +7038,7 @@ private static boolean checkFileSize(AccountInstance accountInstance, Uri uri) { } @UiThread - public static void prepareSendingDocument(AccountInstance accountInstance, String path, String originalPath, Uri uri, String caption, String mine, long dialogId, MessageObject replyToMsg, MessageObject replyToTopMsg, TL_stories.StoryItem storyItem, ChatActivity.ReplyQuote quote, MessageObject editingMessageObject, boolean notify, int scheduleDate, InputContentInfoCompat inputContent) { + public static void prepareSendingDocument(AccountInstance accountInstance, String path, String originalPath, Uri uri, String caption, String mine, long dialogId, MessageObject replyToMsg, MessageObject replyToTopMsg, TL_stories.StoryItem storyItem, ChatActivity.ReplyQuote quote, MessageObject editingMessageObject, boolean notify, int scheduleDate, InputContentInfoCompat inputContent, String quickReplyShortcut, int quickReplyShortcutId) { if ((path == null || originalPath == null) && uri == null) { return; } @@ -6905,11 +7053,11 @@ public static void prepareSendingDocument(AccountInstance accountInstance, Strin paths.add(path); originalPaths.add(originalPath); } - prepareSendingDocuments(accountInstance, paths, originalPaths, uris, caption, mine, dialogId, replyToMsg, replyToTopMsg, storyItem, quote, editingMessageObject, notify, scheduleDate, inputContent); + prepareSendingDocuments(accountInstance, paths, originalPaths, uris, caption, mine, dialogId, replyToMsg, replyToTopMsg, storyItem, quote, editingMessageObject, notify, scheduleDate, inputContent, quickReplyShortcut, quickReplyShortcutId); } @UiThread - public static void prepareSendingAudioDocuments(AccountInstance accountInstance, ArrayList messageObjects, CharSequence caption, long dialogId, MessageObject replyToMsg, MessageObject replyToTopMsg, TL_stories.StoryItem storyItem, boolean notify, int scheduleDate, MessageObject editingMessageObject) { + public static void prepareSendingAudioDocuments(AccountInstance accountInstance, ArrayList messageObjects, CharSequence caption, long dialogId, MessageObject replyToMsg, MessageObject replyToTopMsg, TL_stories.StoryItem storyItem, boolean notify, int scheduleDate, MessageObject editingMessageObject, String quickReplyShortcut, int quickReplyShortcutId) { new Thread(() -> { int count = messageObjects.size(); long groupId = 0; @@ -6974,6 +7122,8 @@ public static void prepareSendingAudioDocuments(AccountInstance accountInstance, } else { SendMessageParams sendMessageParams = SendMessageParams.of(documentFinal, null, messageObject.messageOwner.attachPath, dialogId, replyToMsg, replyToTopMsg, captionFinal, entities, null, params, notify, scheduleDate, 0, parentFinal, null, false, false); sendMessageParams.replyToStoryItem = storyItem; + sendMessageParams.quick_reply_shortcut = quickReplyShortcut; + sendMessageParams.quick_reply_shortcut_id = quickReplyShortcutId; accountInstance.getSendMessagesHelper().sendMessage(sendMessageParams); } }); @@ -7002,7 +7152,7 @@ private static void finishGroup(AccountInstance accountInstance, long groupId, i } @UiThread - public static void prepareSendingDocuments(AccountInstance accountInstance, ArrayList paths, ArrayList originalPaths, ArrayList uris, String caption, String mime, long dialogId, MessageObject replyToMsg, MessageObject replyToTopMsg, TL_stories.StoryItem storyItem, ChatActivity.ReplyQuote quote, MessageObject editingMessageObject, boolean notify, int scheduleDate, InputContentInfoCompat inputContent) { + public static void prepareSendingDocuments(AccountInstance accountInstance, ArrayList paths, ArrayList originalPaths, ArrayList uris, String caption, String mime, long dialogId, MessageObject replyToMsg, MessageObject replyToTopMsg, TL_stories.StoryItem storyItem, ChatActivity.ReplyQuote quote, MessageObject editingMessageObject, boolean notify, int scheduleDate, InputContentInfoCompat inputContent, String quickReplyShortcut, int quickReplyShortcutId) { if (paths == null && originalPaths == null && uris == null || paths != null && originalPaths != null && paths.size() != originalPaths.size()) { return; } @@ -7027,7 +7177,7 @@ public static void prepareSendingDocuments(AccountInstance accountInstance, Arra } mediaCount++; long prevGroupId = groupId[0]; - error = prepareSendingDocumentInternal(accountInstance, paths.get(a), originalPaths.get(a), null, mime, dialogId, replyToMsg, replyToTopMsg, storyItem, quote, null, editingMessageObject, groupId, mediaCount == 10 || a == count - 1, captionFinal, notify, scheduleDate, docType, inputContent == null); + error = prepareSendingDocumentInternal(accountInstance, paths.get(a), originalPaths.get(a), null, mime, dialogId, replyToMsg, replyToTopMsg, storyItem, quote, null, editingMessageObject, groupId, mediaCount == 10 || a == count - 1, captionFinal, notify, scheduleDate, docType, inputContent == null, quickReplyShortcut, quickReplyShortcutId); if (prevGroupId != groupId[0] || groupId[0] == -1) { mediaCount = 1; } @@ -7048,7 +7198,7 @@ public static void prepareSendingDocuments(AccountInstance accountInstance, Arra } mediaCount++; long prevGroupId = groupId[0]; - error = prepareSendingDocumentInternal(accountInstance, null, null, uris.get(a), mime, dialogId, replyToMsg, replyToTopMsg, storyItem, quote, null, editingMessageObject, groupId, mediaCount == 10 || a == count - 1, captionFinal, notify, scheduleDate, docType, inputContent == null); + error = prepareSendingDocumentInternal(accountInstance, null, null, uris.get(a), mime, dialogId, replyToMsg, replyToTopMsg, storyItem, quote, null, editingMessageObject, groupId, mediaCount == 10 || a == count - 1, captionFinal, notify, scheduleDate, docType, inputContent == null, quickReplyShortcut, quickReplyShortcutId); if (prevGroupId != groupId[0] || groupId[0] == -1) { mediaCount = 1; } @@ -7079,12 +7229,12 @@ private static void handleError(int error, AccountInstance accountInstance) { } @UiThread - public static void prepareSendingPhoto(AccountInstance accountInstance, String imageFilePath, Uri imageUri, long dialogId, MessageObject replyToMsg, MessageObject replyToTopMsg, ChatActivity.ReplyQuote quote, CharSequence caption, ArrayList entities, ArrayList stickers, InputContentInfoCompat inputContent, int ttl, MessageObject editingMessageObject, boolean notify, int scheduleDate) { - prepareSendingPhoto(accountInstance, imageFilePath, null, imageUri, dialogId, replyToMsg, replyToTopMsg, null, null, entities, stickers, inputContent, ttl, editingMessageObject, null, notify, scheduleDate, false, caption); + public static void prepareSendingPhoto(AccountInstance accountInstance, String imageFilePath, Uri imageUri, long dialogId, MessageObject replyToMsg, MessageObject replyToTopMsg, ChatActivity.ReplyQuote quote, CharSequence caption, ArrayList entities, ArrayList stickers, InputContentInfoCompat inputContent, int ttl, MessageObject editingMessageObject, boolean notify, int scheduleDate, int mode, String quickReplyShortcut, int quickReplyShortcutId) { + prepareSendingPhoto(accountInstance, imageFilePath, null, imageUri, dialogId, replyToMsg, replyToTopMsg, null, null, entities, stickers, inputContent, ttl, editingMessageObject, null, notify, scheduleDate, mode, false, caption, quickReplyShortcut, quickReplyShortcutId); } @UiThread - public static void prepareSendingPhoto(AccountInstance accountInstance, String imageFilePath, String thumbFilePath, Uri imageUri, long dialogId, MessageObject replyToMsg, MessageObject replyToTopMsg, TL_stories.StoryItem storyItem, ChatActivity.ReplyQuote quote, ArrayList entities, ArrayList stickers, InputContentInfoCompat inputContent, int ttl, MessageObject editingMessageObject, VideoEditedInfo videoEditedInfo, boolean notify, int scheduleDate, boolean forceDocument, CharSequence caption) { + public static void prepareSendingPhoto(AccountInstance accountInstance, String imageFilePath, String thumbFilePath, Uri imageUri, long dialogId, MessageObject replyToMsg, MessageObject replyToTopMsg, TL_stories.StoryItem storyItem, ChatActivity.ReplyQuote quote, ArrayList entities, ArrayList stickers, InputContentInfoCompat inputContent, int ttl, MessageObject editingMessageObject, VideoEditedInfo videoEditedInfo, boolean notify, int scheduleDate, int mode, boolean forceDocument, CharSequence caption, String quickReplyShortcut, int quickReplyShortcutId) { SendingMediaInfo info = new SendingMediaInfo(); info.path = imageFilePath; info.thumbPath = thumbFilePath; @@ -7100,11 +7250,11 @@ public static void prepareSendingPhoto(AccountInstance accountInstance, String i info.videoEditedInfo = videoEditedInfo; ArrayList infos = new ArrayList<>(); infos.add(info); - prepareSendingMedia(accountInstance, infos, dialogId, replyToMsg, replyToTopMsg, null, quote, forceDocument, false, editingMessageObject, notify, scheduleDate, false, inputContent); + prepareSendingMedia(accountInstance, infos, dialogId, replyToMsg, replyToTopMsg, null, quote, forceDocument, false, editingMessageObject, notify, scheduleDate, mode, false, inputContent, quickReplyShortcut, quickReplyShortcutId); } @UiThread - public static void prepareSendingBotContextResult(BaseFragment fragment, AccountInstance accountInstance, TLRPC.BotInlineResult result, HashMap params, long dialogId, MessageObject replyToMsg, MessageObject replyToTopMsg, TL_stories.StoryItem storyItem, ChatActivity.ReplyQuote quote, boolean notify, int scheduleDate) { + public static void prepareSendingBotContextResult(BaseFragment fragment, AccountInstance accountInstance, TLRPC.BotInlineResult result, HashMap params, long dialogId, MessageObject replyToMsg, MessageObject replyToTopMsg, TL_stories.StoryItem storyItem, ChatActivity.ReplyQuote quote, boolean notify, int scheduleDate, String quick_reply_shortcut, int quick_reply_shortcut_id) { if (result == null) { return; } @@ -7384,6 +7534,8 @@ public static void prepareSendingBotContextResult(BaseFragment fragment, Account params2 = SendMessageParams.of(finalGame, dialogId, replyToMsg, replyToTopMsg, result.send_message.reply_markup, params, notify, scheduleDate); } if (params2 != null) { + params2.quick_reply_shortcut = quick_reply_shortcut; + params2.quick_reply_shortcut_id = quick_reply_shortcut_id; params2.replyToStoryItem = storyItem; params2.replyQuote = quote; accountInstance.getSendMessagesHelper().sendMessage(params2); @@ -7402,7 +7554,10 @@ public static void prepareSendingBotContextResult(BaseFragment fragment, Account } } } - accountInstance.getSendMessagesHelper().sendMessage(SendMessagesHelper.SendMessageParams.of(result.send_message.message, dialogId, replyToMsg, replyToTopMsg, webPage, !result.send_message.no_webpage, result.send_message.entities, result.send_message.reply_markup, params, notify, scheduleDate, null, false)); + SendMessagesHelper.SendMessageParams params2 = SendMessagesHelper.SendMessageParams.of(result.send_message.message, dialogId, replyToMsg, replyToTopMsg, webPage, !result.send_message.no_webpage, result.send_message.entities, result.send_message.reply_markup, params, notify, scheduleDate, null, false); + params2.quick_reply_shortcut = quick_reply_shortcut; + params2.quick_reply_shortcut_id = quick_reply_shortcut_id; + accountInstance.getSendMessagesHelper().sendMessage(params2); } else if (result.send_message instanceof TLRPC.TL_botInlineMessageMediaVenue) { TLRPC.TL_messageMediaVenue venue = new TLRPC.TL_messageMediaVenue(); venue.geo = result.send_message.geo; @@ -7414,21 +7569,28 @@ public static void prepareSendingBotContextResult(BaseFragment fragment, Account if (venue.venue_type == null) { venue.venue_type = ""; } - accountInstance.getSendMessagesHelper().sendMessage(SendMessagesHelper.SendMessageParams.of(venue, dialogId, replyToMsg, replyToTopMsg, result.send_message.reply_markup, params, notify, scheduleDate)); + SendMessagesHelper.SendMessageParams params2 = SendMessagesHelper.SendMessageParams.of(venue, dialogId, replyToMsg, replyToTopMsg, result.send_message.reply_markup, params, notify, scheduleDate); + params2.quick_reply_shortcut = quick_reply_shortcut; + params2.quick_reply_shortcut_id = quick_reply_shortcut_id; + accountInstance.getSendMessagesHelper().sendMessage(params2); } else if (result.send_message instanceof TLRPC.TL_botInlineMessageMediaGeo) { + SendMessagesHelper.SendMessageParams params2; if (result.send_message.period != 0 || result.send_message.proximity_notification_radius != 0) { TLRPC.TL_messageMediaGeoLive location = new TLRPC.TL_messageMediaGeoLive(); location.period = result.send_message.period != 0 ? result.send_message.period : 900; location.geo = result.send_message.geo; location.heading = result.send_message.heading; location.proximity_notification_radius = result.send_message.proximity_notification_radius; - accountInstance.getSendMessagesHelper().sendMessage(SendMessagesHelper.SendMessageParams.of(location, dialogId, replyToMsg, replyToTopMsg, result.send_message.reply_markup, params, notify, scheduleDate)); + params2 = SendMessagesHelper.SendMessageParams.of(location, dialogId, replyToMsg, replyToTopMsg, result.send_message.reply_markup, params, notify, scheduleDate); } else { TLRPC.TL_messageMediaGeo location = new TLRPC.TL_messageMediaGeo(); location.geo = result.send_message.geo; location.heading = result.send_message.heading; - accountInstance.getSendMessagesHelper().sendMessage(SendMessagesHelper.SendMessageParams.of(location, dialogId, replyToMsg, replyToTopMsg, result.send_message.reply_markup, params, notify, scheduleDate)); + params2 = SendMessagesHelper.SendMessageParams.of(location, dialogId, replyToMsg, replyToTopMsg, result.send_message.reply_markup, params, notify, scheduleDate); } + params2.quick_reply_shortcut = quick_reply_shortcut; + params2.quick_reply_shortcut_id = quick_reply_shortcut_id; + accountInstance.getSendMessagesHelper().sendMessage(params2); } else if (result.send_message instanceof TLRPC.TL_botInlineMessageMediaContact) { TLRPC.User user = new TLRPC.TL_user(); user.phone = result.send_message.phone_number; @@ -7439,7 +7601,10 @@ public static void prepareSendingBotContextResult(BaseFragment fragment, Account reason.platform = ""; reason.reason = ""; user.restriction_reason.add(reason); - accountInstance.getSendMessagesHelper().sendMessage(SendMessagesHelper.SendMessageParams.of(user, dialogId, replyToMsg, replyToTopMsg, result.send_message.reply_markup, params, notify, scheduleDate)); + SendMessagesHelper.SendMessageParams params2 = SendMessagesHelper.SendMessageParams.of(user, dialogId, replyToMsg, replyToTopMsg, result.send_message.reply_markup, params, notify, scheduleDate); + params2.quick_reply_shortcut = quick_reply_shortcut; + params2.quick_reply_shortcut_id = quick_reply_shortcut_id; + accountInstance.getSendMessagesHelper().sendMessage(params2); } else if (result.send_message instanceof TLRPC.TL_botInlineMessageMediaInvoice) { if (DialogObject.isEncryptedDialog(dialogId)) { return; //doesn't work in secret chats for now @@ -7457,12 +7622,18 @@ public static void prepareSendingBotContextResult(BaseFragment fragment, Account messageMediaInvoice.currency = invoice.currency; messageMediaInvoice.total_amount = invoice.total_amount; messageMediaInvoice.start_param = ""; - accountInstance.getSendMessagesHelper().sendMessage(SendMessagesHelper.SendMessageParams.of(messageMediaInvoice, dialogId, replyToMsg, replyToTopMsg, result.send_message.reply_markup, params, notify, scheduleDate)); + SendMessagesHelper.SendMessageParams params2 = SendMessagesHelper.SendMessageParams.of(messageMediaInvoice, dialogId, replyToMsg, replyToTopMsg, result.send_message.reply_markup, params, notify, scheduleDate); + params2.quick_reply_shortcut = quick_reply_shortcut; + params2.quick_reply_shortcut_id = quick_reply_shortcut_id; + accountInstance.getSendMessagesHelper().sendMessage(params2); } else if (result.send_message instanceof TLRPC.TL_botInlineMessageMediaWebPage) { TLRPC.TL_botInlineMessageMediaWebPage request = (TLRPC.TL_botInlineMessageMediaWebPage) result.send_message; TLRPC.WebPage webPage = new TLRPC.TL_webPagePending(); webPage.url = request.url; - accountInstance.getSendMessagesHelper().sendMessage(SendMessagesHelper.SendMessageParams.of(result.send_message.message, dialogId, replyToMsg, replyToTopMsg, webPage, !result.send_message.no_webpage, result.send_message.entities, result.send_message.reply_markup, params, notify, scheduleDate, null, false)); + SendMessagesHelper.SendMessageParams params2 = SendMessagesHelper.SendMessageParams.of(result.send_message.message, dialogId, replyToMsg, replyToTopMsg, webPage, !result.send_message.no_webpage, result.send_message.entities, result.send_message.reply_markup, params, notify, scheduleDate, null, false); + params2.quick_reply_shortcut = quick_reply_shortcut; + params2.quick_reply_shortcut_id = quick_reply_shortcut_id; + accountInstance.getSendMessagesHelper().sendMessage(params2); } } @@ -7634,7 +7805,7 @@ public static boolean shouldSendWebPAsSticker(String path, Uri uri) { } @UiThread - public static void prepareSendingMedia(AccountInstance accountInstance, ArrayList media, long dialogId, MessageObject replyToMsg, MessageObject replyToTopMsg, TL_stories.StoryItem storyItem, ChatActivity.ReplyQuote quote, boolean forceDocument, boolean groupMedia, MessageObject editingMessageObject, boolean notify, int scheduleDate, boolean updateStikcersOrder, InputContentInfoCompat inputContent) { + public static void prepareSendingMedia(AccountInstance accountInstance, ArrayList media, long dialogId, MessageObject replyToMsg, MessageObject replyToTopMsg, TL_stories.StoryItem storyItem, ChatActivity.ReplyQuote quote, boolean forceDocument, boolean groupMedia, MessageObject editingMessageObject, boolean notify, int scheduleDate, int mode, boolean updateStikcersOrder, InputContentInfoCompat inputContent, String quickReplyShortcut, int quickReplyShortcutId) { if (media.isEmpty()) { return; } @@ -7841,6 +8012,8 @@ public static void prepareSendingMedia(AccountInstance accountInstance, ArrayLis SendMessageParams sendMessageParams = SendMessageParams.of(documentFinal, null, pathFinal, dialogId, replyToMsg, replyToTopMsg, info.caption, info.entities, null, params, notify, scheduleDate, 0, parentFinal, null, false, info.hasMediaSpoilers); sendMessageParams.replyToStoryItem = storyItem; sendMessageParams.replyQuote = quote; + sendMessageParams.quick_reply_shortcut = quickReplyShortcut; + sendMessageParams.quick_reply_shortcut_id = quickReplyShortcutId; accountInstance.getSendMessagesHelper().sendMessage(sendMessageParams); } }); @@ -7915,6 +8088,8 @@ public static void prepareSendingMedia(AccountInstance accountInstance, ArrayLis SendMessageParams sendMessageParams = SendMessageParams.of(photoFinal, needDownloadHttpFinal ? info.searchImage.imageUrl : null, dialogId, replyToMsg, replyToTopMsg, info.caption, info.entities, null, params, notify, scheduleDate, info.ttl, parentFinal, false, info.hasMediaSpoilers); sendMessageParams.replyToStoryItem = storyItem; sendMessageParams.replyQuote = quote; + sendMessageParams.quick_reply_shortcut_id = quickReplyShortcutId; + sendMessageParams.quick_reply_shortcut = quickReplyShortcut; accountInstance.getSendMessagesHelper().sendMessage(sendMessageParams); } }); @@ -8092,6 +8267,8 @@ public static void prepareSendingMedia(AccountInstance accountInstance, ArrayLis SendMessageParams sendMessageParams = SendMessageParams.of(videoFinal, videoEditedInfo, finalPath, dialogId, replyToMsg, replyToTopMsg, info.caption, info.entities, null, params, notify, scheduleDate, info.ttl, parentFinal, null, false, info.hasMediaSpoilers); sendMessageParams.replyToStoryItem = storyItem; sendMessageParams.replyQuote = quote; + sendMessageParams.quick_reply_shortcut = quickReplyShortcut; + sendMessageParams.quick_reply_shortcut_id = quickReplyShortcutId; accountInstance.getSendMessagesHelper().sendMessage(sendMessageParams); } }); @@ -8292,6 +8469,8 @@ public static void prepareSendingMedia(AccountInstance accountInstance, ArrayLis SendMessageParams sendMessageParams = SendMessageParams.of(photoFinal, null, dialogId, replyToMsg, replyToTopMsg, info.caption, info.entities, null, params, notify, scheduleDate, info.ttl, parentFinal, updateStikcersOrder, info.hasMediaSpoilers); sendMessageParams.replyToStoryItem = storyItem; sendMessageParams.replyQuote = quote; + sendMessageParams.quick_reply_shortcut = quickReplyShortcut; + sendMessageParams.quick_reply_shortcut_id = quickReplyShortcutId; accountInstance.getSendMessagesHelper().sendMessage(sendMessageParams); } }); @@ -8328,7 +8507,7 @@ public static void prepareSendingMedia(AccountInstance accountInstance, ArrayLis mediaCount = 0; } mediaCount++; - int error = prepareSendingDocumentInternal(accountInstance, sendAsDocuments.get(a), sendAsDocumentsOriginal.get(a), sendAsDocumentsUri.get(a), extension, dialogId, replyToMsg, replyToTopMsg, storyItem, quote, sendAsDocumentsEntities.get(a), editingMessageObject, groupId2, mediaCount == 10 || a == documentsCount - 1, sendAsDocumentsCaptions.get(a), notify, scheduleDate, null, forceDocument); + int error = prepareSendingDocumentInternal(accountInstance, sendAsDocuments.get(a), sendAsDocumentsOriginal.get(a), sendAsDocumentsUri.get(a), extension, dialogId, replyToMsg, replyToTopMsg, storyItem, quote, sendAsDocumentsEntities.get(a), editingMessageObject, groupId2, mediaCount == 10 || a == documentsCount - 1, sendAsDocumentsCaptions.get(a), notify, scheduleDate, null, forceDocument, quickReplyShortcut, quickReplyShortcutId); handleError(error, accountInstance); } } @@ -8593,7 +8772,7 @@ private static VideoEditedInfo createCompressionSettings(String videoPath) { } @UiThread - public static void prepareSendingVideo(AccountInstance accountInstance, String videoPath, VideoEditedInfo info, long dialogId, MessageObject replyToMsg, MessageObject replyToTopMsg, TL_stories.StoryItem storyItem, ChatActivity.ReplyQuote quote, ArrayList entities, int ttl, MessageObject editingMessageObject, boolean notify, int scheduleDate, boolean forceDocument, boolean hasMediaSpoilers, CharSequence caption) { + public static void prepareSendingVideo(AccountInstance accountInstance, String videoPath, VideoEditedInfo info, long dialogId, MessageObject replyToMsg, MessageObject replyToTopMsg, TL_stories.StoryItem storyItem, ChatActivity.ReplyQuote quote, ArrayList entities, int ttl, MessageObject editingMessageObject, boolean notify, int scheduleDate, boolean forceDocument, boolean hasMediaSpoilers, CharSequence caption, String quickReplyShortcut, int quickReplyShortcutId) { if (videoPath == null || videoPath.length() == 0) { return; } @@ -8753,11 +8932,13 @@ public static void prepareSendingVideo(AccountInstance accountInstance, String v SendMessageParams sendMessageParams = SendMessageParams.of(videoFinal, videoEditedInfo, finalPath, dialogId, replyToMsg, replyToTopMsg, captionFinal, entities, null, params, notify, scheduleDate, ttl, parentFinal, null, false, hasMediaSpoilers); sendMessageParams.replyToStoryItem = storyItem; sendMessageParams.replyQuote = quote; + sendMessageParams.quick_reply_shortcut_id = quickReplyShortcutId; + sendMessageParams.quick_reply_shortcut = quickReplyShortcut; accountInstance.getSendMessagesHelper().sendMessage(sendMessageParams); } }); } else { - prepareSendingDocumentInternal(accountInstance, videoPath, videoPath, null, null, dialogId, replyToMsg, replyToTopMsg, storyItem, quote, entities, editingMessageObject, null, false, caption, notify, scheduleDate, null, forceDocument); + prepareSendingDocumentInternal(accountInstance, videoPath, videoPath, null, null, dialogId, replyToMsg, replyToTopMsg, storyItem, quote, entities, editingMessageObject, null, false, caption, notify, scheduleDate, null, forceDocument, quickReplyShortcut, quickReplyShortcutId); } }).start(); } @@ -8795,13 +8976,22 @@ public static class SendMessageParams { public TL_stories.StoryItem sendingStory; public ChatActivity.ReplyQuote replyQuote; public boolean invert_media; + public String quick_reply_shortcut; + public int quick_reply_shortcut_id; public static SendMessageParams of(String string, long dialogId) { return of(string, null, null, null, null, null, null, null, null, null, dialogId, null, null, null, null, true, null, null, null, null, false, 0, 0, null, null, false); } public static SendMessageParams of(MessageObject retryMessageObject) { - return of(null, null, null, null, null, null, null, null, null, null, retryMessageObject.getDialogId(), retryMessageObject.messageOwner.attachPath, null, null, null, true, retryMessageObject, null, retryMessageObject.messageOwner.reply_markup, retryMessageObject.messageOwner.params, !retryMessageObject.messageOwner.silent, retryMessageObject.scheduled ? retryMessageObject.messageOwner.date : 0, 0, null, null, false); + SendMessageParams params = of(null, null, null, null, null, null, null, null, null, null, retryMessageObject.getDialogId(), retryMessageObject.messageOwner.attachPath, null, null, null, true, retryMessageObject, null, retryMessageObject.messageOwner.reply_markup, retryMessageObject.messageOwner.params, !retryMessageObject.messageOwner.silent, retryMessageObject.scheduled ? retryMessageObject.messageOwner.date : 0, 0, null, null, false); + if (retryMessageObject.messageOwner != null) { + if (retryMessageObject.messageOwner.quick_reply_shortcut instanceof TLRPC.TL_inputQuickReplyShortcut) { + params.quick_reply_shortcut = ((TLRPC.TL_inputQuickReplyShortcut) retryMessageObject.messageOwner.quick_reply_shortcut).shortcut; + } + params.quick_reply_shortcut_id = retryMessageObject.getQuickReplyId(); + } + return params; } public static SendMessageParams of(TLRPC.User user, long peer, MessageObject replyToMsg, MessageObject replyToTopMsg, TLRPC.ReplyMarkup replyMarkup, HashMap params, boolean notify, int scheduleDate) { diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/SharedConfig.java b/TMessagesProj/src/main/java/org/telegram/messenger/SharedConfig.java index 876fad719e8..16a28cac404 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/SharedConfig.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/SharedConfig.java @@ -643,7 +643,7 @@ public static void loadConfig() { updateStickersOrderOnSend = preferences.getBoolean("updateStickersOrderOnSend", true); dayNightWallpaperSwitchHint = preferences.getInt("dayNightWallpaperSwitchHint", 0); bigCameraForRound = preferences.getBoolean("bigCameraForRound", false); - useCamera2 = preferences.getBoolean("useCamera2", false); + useCamera2 = preferences.getBoolean("useCamera2", BuildVars.DEBUG_VERSION); useSurfaceInStories = preferences.getBoolean("useSurfaceInStories", Build.VERSION.SDK_INT >= 30); payByInvoice = preferences.getBoolean("payByInvoice", false); photoViewerBlur = preferences.getBoolean("photoViewerBlur", true); diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/TopicsController.java b/TMessagesProj/src/main/java/org/telegram/messenger/TopicsController.java index 4155f19d094..b7585671544 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/TopicsController.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/TopicsController.java @@ -4,6 +4,7 @@ import android.graphics.drawable.Drawable; import android.text.TextPaint; import android.text.TextUtils; +import android.util.Log; import android.util.SparseArray; import androidx.collection.LongSparseArray; @@ -118,9 +119,9 @@ public void loadTopics(long chatId, boolean fromCache, int loadType) { topicsIsLoading.put(chatId, 0); processTopics(chatId, topics.topics, messagesMap, false, loadType, ((TLRPC.TL_messages_forumTopics) response).count); - getMessagesStorage().putMessages(topics.messages, false, true, false, 0, false, 0, 0); sortTopics(chatId); - getMessagesStorage().saveTopics(-chatId, topicsByChatId.get(chatId), true, true); + getMessagesStorage().saveTopics(-chatId, topicsByChatId.get(chatId), true, true, getConnectionsManager().getCurrentTime()); + getMessagesStorage().putMessages(topics.messages, false, true, false, 0, false, 0, 0); if (!topics.topics.isEmpty() && loadType == LOAD_TYPE_LOAD_NEXT) { TLRPC.TL_forumTopic lastTopic = topics.topics.get(topics.topics.size() - 1); @@ -193,6 +194,15 @@ public void processTopics(long chatId, ArrayList newTopics, topicsMap.put(newTopic.id, newTopic); topicsByTopMsgId.put(messageHash(newTopic.top_message, chatId), newTopic); changed = true; + } else if (!newTopic.isShort) { + TLRPC.TL_forumTopic oldTopic = topicsMap.get(newTopic.id); + if (oldTopic != null) { + if (oldTopic.closed != newTopic.closed) { + oldTopic.closed = newTopic.closed; + getMessagesStorage().updateTopicData(-chatId, newTopic, TOPIC_FLAG_CLOSE); + changed = true; + } + } } } } @@ -210,15 +220,15 @@ public void processTopics(long chatId, ArrayList newTopics, } if (deletedTopics != null && loadType == LOAD_TYPE_LOAD_UNKNOWN) { - for (int i = 0; i < deletedTopics.size(); i++) { - for (int j = 0; j < topics.size(); j++) { - if (topics.get(j).id == deletedTopics.get(i)) { - topics.remove(j); - break; - } - } - } - getMessagesStorage().removeTopics(chatId, deletedTopics); + for (int i = 0; i < deletedTopics.size(); i++) { + for (int j = 0; j < topics.size(); j++) { + if (topics.get(j).id == deletedTopics.get(i)) { + topics.remove(j); + break; + } + } + } + getMessagesStorage().removeTopics(chatId, deletedTopics); } if (topicsToReload != null && loadType != LOAD_TYPE_LOAD_UNKNOWN) { reloadTopics(chatId, topicsToReload, null); @@ -390,8 +400,8 @@ public void reloadTopics(long chatId, ArrayList topicsToRel getMessagesController().putChats(((TLRPC.TL_messages_forumTopics) response).chats, false); processTopics(chatId, topics.topics, messagesMap, false, LOAD_TYPE_LOAD_UNKNOWN, -1); + getMessagesStorage().saveTopics(-chatId, topicsByChatId.get(chatId), true, true, getConnectionsManager().getCurrentTime()); getMessagesStorage().putMessages(topics.messages, false, true, false, 0, false, 0, 0); - getMessagesStorage().saveTopics(-chatId, topicsByChatId.get(chatId), true, true); if (callback != null) { callback.run(); } @@ -495,7 +505,7 @@ public void onTopicCreated(long dialogId, TLRPC.TL_forumTopic forumTopic, boolea map.put(forumTopic.id, forumTopic); list.add(forumTopic); if (saveInDatabase) { - getMessagesStorage().saveTopics(dialogId, Collections.singletonList(forumTopic), false, true); + getMessagesStorage().saveTopics(dialogId, Collections.singletonList(forumTopic), false, true, getConnectionsManager().getCurrentTime()); } sortTopics(-dialogId, true); } @@ -651,11 +661,7 @@ public void toggleShowTopic(long chatId, int topicId, boolean show) { getMessagesStorage().updateTopicData(-chatId, topic, TOPIC_FLAG_PIN | TOPIC_FLAG_HIDE | TOPIC_FLAG_CLOSE); } - ConnectionsManager.getInstance(currentAccount).sendRequest(req, (res, err) -> { - if (err != null) { - - } - }); + ConnectionsManager.getInstance(currentAccount).sendRequest(req, null); } public void toggleViewForumAsMessages(long channelId, boolean enabled) { diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/Utilities.java b/TMessagesProj/src/main/java/org/telegram/messenger/Utilities.java index b4a8c9e4471..79b1243821a 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/Utilities.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/Utilities.java @@ -569,10 +569,18 @@ public static interface Callback3 { public static interface Callback4 { public void run(T arg, T2 arg2, T3 arg3, T4 arg4); } + + public static interface Callback4Return { + public ReturnType run(T arg, T2 arg2, T3 arg3, T4 arg4); + } public static interface Callback5 { public void run(T arg, T2 arg2, T3 arg3, T4 arg4, T5 arg5); } + public static interface Callback5Return { + public ReturnType run(T arg, T2 arg2, T3 arg3, T4 arg4, T5 arg5); + } + public static Value getOrDefault(HashMap map, Key key, Value defaultValue) { Value v = map.get(key); if (v == null) { diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/VideoEncodingService.java b/TMessagesProj/src/main/java/org/telegram/messenger/VideoEncodingService.java index b64d51bd2fa..6aca4d12694 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/VideoEncodingService.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/VideoEncodingService.java @@ -117,6 +117,7 @@ private void updateNotification() { } } + @Override public int onStartCommand(Intent intent, int flags, int startId) { if (isRunning()) { return Service.START_NOT_STICKY; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/browser/Browser.java b/TMessagesProj/src/main/java/org/telegram/messenger/browser/Browser.java index d9ce3ed6b3a..4ec2e51a955 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/browser/Browser.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/browser/Browser.java @@ -254,7 +254,7 @@ public static void openUrl(final Context context, Uri uri, final boolean allowCu if (tryTelegraph) { try { String host = AndroidUtilities.getHostAuthority(uri); - if (isTelegraphUrl(host, true) || "telegram.org".equalsIgnoreCase(host) && (uri.toString().toLowerCase().contains("telegram.org/faq") || uri.toString().toLowerCase().contains("telegram.org/privacy") || uri.toString().toLowerCase().contains("telegram.org/blog"))) { + if (UserConfig.getInstance(UserConfig.selectedAccount).getCurrentUser() != null && (isTelegraphUrl(host, true) || "telegram.org".equalsIgnoreCase(host) && (uri.toString().toLowerCase().contains("telegram.org/faq") || uri.toString().toLowerCase().contains("telegram.org/privacy") || uri.toString().toLowerCase().contains("telegram.org/blog")))) { final AlertDialog[] progressDialog = new AlertDialog[] { new AlertDialog(context, AlertDialog.ALERT_TYPE_SPINNER) }; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/camera/Camera2Session.java b/TMessagesProj/src/main/java/org/telegram/messenger/camera/Camera2Session.java index 6374e2d9aa1..395655f06dd 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/camera/Camera2Session.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/camera/Camera2Session.java @@ -24,6 +24,7 @@ import android.util.Size; import android.util.SizeF; import android.view.Surface; +import android.view.WindowManager; import androidx.annotation.NonNull; import androidx.annotation.RequiresApi; @@ -78,7 +79,7 @@ public class Camera2Session { private long lastTime; - public static Camera2Session create(boolean round, boolean front, int viewWidth, int viewHeight) { + public static Camera2Session create(boolean front, int viewWidth, int viewHeight) { final Context context = ApplicationLoader.applicationContext; final CameraManager cameraManager = (CameraManager) context.getSystemService(Context.CAMERA_SERVICE); @@ -97,12 +98,12 @@ public static Camera2Session create(boolean round, boolean front, int viewWidth, StreamConfigurationMap confMap = (StreamConfigurationMap) characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP); Size pixelSize = characteristics.get(CameraCharacteristics.SENSOR_INFO_PIXEL_ARRAY_SIZE); float cameraAspectRatio = pixelSize == null ? 0 : (float) pixelSize.getWidth() / pixelSize.getHeight(); - final Size targetAspectRatio = round ? new Size(1, 1) : new Size(9, 16); - final int targetWidth = round ? MessagesController.getInstance(UserConfig.selectedAccount).roundVideoSize : viewWidth; - final int targetHeight = round ? MessagesController.getInstance(UserConfig.selectedAccount).roundVideoSize : viewHeight; - if (bestAspectRatio <= 0 || Math.abs((float) targetAspectRatio.getWidth() / targetAspectRatio.getHeight() - bestAspectRatio) > Math.abs((float) targetAspectRatio.getWidth() / targetAspectRatio.getHeight() - cameraAspectRatio)) { + if ((viewWidth / (float) viewHeight >= 1f) != (cameraAspectRatio >= 1f)) { + cameraAspectRatio = 1f / cameraAspectRatio; + } + if (bestAspectRatio <= 0 || Math.abs((float) viewWidth / viewHeight - bestAspectRatio) > Math.abs((float) viewWidth / viewHeight - cameraAspectRatio)) { if (confMap != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { - Size size = chooseOptimalSize(confMap.getOutputSizes(SurfaceTexture.class), targetWidth, targetHeight, targetAspectRatio, false); + Size size = chooseOptimalSize(confMap.getOutputSizes(SurfaceTexture.class), viewWidth, viewHeight, false); if (size != null) { bestAspectRatio = cameraAspectRatio; cameraId = id; @@ -249,18 +250,93 @@ public boolean isInitiated() { } public int getDisplayOrientation() { - // TODO + try { + Context context = ApplicationLoader.applicationContext; + if (context == null) { + return 0; + } + int rotation = ((WindowManager) context.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay().getRotation(); + int degrees = 0; + switch (rotation) { + case Surface.ROTATION_0: + degrees = 0; + break; + case Surface.ROTATION_90: + degrees = 90; + break; + case Surface.ROTATION_180: + degrees = 180; + break; + case Surface.ROTATION_270: + degrees = 270; + break; + } + + Integer sensorOrientation = cameraCharacteristics.get(CameraCharacteristics.SENSOR_ORIENTATION); + int displayOrientation; + if (isFront) { + displayOrientation = (sensorOrientation + degrees) % 360; + displayOrientation = (360 - displayOrientation) % 360; // compensate the mirror + } else { // back-facing + displayOrientation = (sensorOrientation - degrees + 360) % 360; + } + return displayOrientation; + } catch (Exception e) { + FileLog.e(e); + } return 0; } - public int getWorldAngle() { - // TODO + private int getJpegOrientation() { + try { + Context context = ApplicationLoader.applicationContext; + if (context == null) { + return 0; + } + int rotation = ((WindowManager) context.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay().getRotation(); + int degrees = 0; + switch (rotation) { + case Surface.ROTATION_0: + degrees = 0; + break; + case Surface.ROTATION_90: + degrees = 90; + break; + case Surface.ROTATION_180: + degrees = 180; + break; + case Surface.ROTATION_270: + degrees = 270; + break; + } + + Integer sensorOrientation = cameraCharacteristics.get(CameraCharacteristics.SENSOR_ORIENTATION); + int jpegOrientation; + if (isFront) { + jpegOrientation = (sensorOrientation + degrees) % 360; + jpegOrientation = (360 - jpegOrientation) % 360; // compensate the mirror + } else { // back-facing + jpegOrientation = (sensorOrientation - degrees + 360) % 360; + } + return jpegOrientation; + } catch (Exception e) { + FileLog.e(e); + } return 0; } + public int getWorldAngle() { + int displayOrientation = getDisplayOrientation(); + int jpegOrientation = getJpegOrientation(); + int diffOrientation = jpegOrientation - displayOrientation; + if (diffOrientation < 0) { + diffOrientation += 360; + } + return diffOrientation; + } + public int getCurrentOrientation() { - // TODO - return 0; + return getJpegOrientation(); } private final Rect cropRegion = new Rect(); @@ -319,8 +395,8 @@ public void destroy(boolean async, Runnable afterCallback) { imageReader.close(); imageReader = null; } + thread.quitSafely(); AndroidUtilities.runOnUIThread(() -> { - thread.quitSafely(); try { thread.join(); } catch (Exception e) { @@ -424,6 +500,8 @@ public boolean takePicture(final File file, Utilities.Callback whenDone if (cameraDevice == null || captureSession == null) return false; try { CaptureRequest.Builder captureRequestBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE); + final int orientation = getJpegOrientation(); + captureRequestBuilder.set(CaptureRequest.JPEG_ORIENTATION, orientation); imageReader.setOnImageAvailableListener(new ImageReader.OnImageAvailableListener() { @Override public void onImageAvailable(ImageReader reader) { @@ -451,7 +529,7 @@ public void onImageAvailable(ImageReader reader) { AndroidUtilities.runOnUIThread(() -> { if (whenDone != null) { - whenDone.run(0); + whenDone.run(orientation); } }); } @@ -460,42 +538,7 @@ public void onImageAvailable(ImageReader reader) { captureRequestBuilder.set(CaptureRequest.CONTROL_SCENE_MODE, CameraMetadata.CONTROL_SCENE_MODE_BARCODE); } captureRequestBuilder.addTarget(imageReader.getSurface()); - captureSession.capture(captureRequestBuilder.build(), new CameraCaptureSession.CaptureCallback() { - @Override - public void onCaptureStarted(@NonNull CameraCaptureSession session, @NonNull CaptureRequest request, long timestamp, long frameNumber) { - super.onCaptureStarted(session, request, timestamp, frameNumber); - } - - @Override - public void onCaptureProgressed(@NonNull CameraCaptureSession session, @NonNull CaptureRequest request, @NonNull CaptureResult partialResult) { - super.onCaptureProgressed(session, request, partialResult); - } - - @Override - public void onCaptureCompleted(@NonNull CameraCaptureSession session, @NonNull CaptureRequest request, @NonNull TotalCaptureResult result) { - super.onCaptureCompleted(session, request, result); - } - - @Override - public void onCaptureFailed(@NonNull CameraCaptureSession session, @NonNull CaptureRequest request, @NonNull CaptureFailure failure) { - super.onCaptureFailed(session, request, failure); - } - - @Override - public void onCaptureSequenceCompleted(@NonNull CameraCaptureSession session, int sequenceId, long frameNumber) { - super.onCaptureSequenceCompleted(session, sequenceId, frameNumber); - } - - @Override - public void onCaptureSequenceAborted(@NonNull CameraCaptureSession session, int sequenceId) { - super.onCaptureSequenceAborted(session, sequenceId); - } - - @Override - public void onCaptureBufferLost(@NonNull CameraCaptureSession session, @NonNull CaptureRequest request, @NonNull Surface target, long frameNumber) { - super.onCaptureBufferLost(session, request, target, frameNumber); - } - }, null); + captureSession.capture(captureRequestBuilder.build(), new CameraCaptureSession.CaptureCallback() {}, null); return true; } catch (Exception e) { FileLog.e("Camera2Sessions takePicture error", e); @@ -504,11 +547,11 @@ public void onCaptureBufferLost(@NonNull CameraCaptureSession session, @NonNull } - public static Size chooseOptimalSize(Size[] choices, int width, int height, Size aspectRatio, boolean notBigger) { + public static Size chooseOptimalSize(Size[] choices, int width, int height, boolean notBigger) { List bigEnoughWithAspectRatio = new ArrayList<>(choices.length); List bigEnough = new ArrayList<>(choices.length); - int w = aspectRatio.getWidth(); - int h = aspectRatio.getHeight(); + int w = width; + int h = height; for (int a = 0; a < choices.length; a++) { Size option = choices[a]; if (notBigger && (option.getHeight() > height || option.getWidth() > width)) { diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/camera/CameraSessionWrapper.java b/TMessagesProj/src/main/java/org/telegram/messenger/camera/CameraSessionWrapper.java index ad1c71d383f..0a990f256d4 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/camera/CameraSessionWrapper.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/camera/CameraSessionWrapper.java @@ -93,7 +93,7 @@ public String getCurrentFlashMode() { // TODO return Camera.Parameters.FLASH_MODE_OFF; } else if (camera1Session != null) { - return camera1Session.getNextFlashMode(); + return camera1Session.getCurrentFlashMode(); } return null; } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/camera/CameraView.java b/TMessagesProj/src/main/java/org/telegram/messenger/camera/CameraView.java index f836368b923..8623a979ea4 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/camera/CameraView.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/camera/CameraView.java @@ -103,6 +103,7 @@ public class CameraView extends FrameLayout implements TextureView.SurfaceTextur public boolean WRITE_TO_FILE_IN_BACKGROUND = false; public boolean isStory; + private float scaleX, scaleY; private Size[] previewSize = new Size[2]; private Size[] pictureSize = new Size[2]; CameraInfo[] info = new CameraInfo[2]; @@ -120,7 +121,7 @@ public class CameraView extends FrameLayout implements TextureView.SurfaceTextur private int focusAreaSize; private Drawable thumbDrawable; - private final boolean useCamera2 = Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && SharedConfig.useCamera2; + private final boolean useCamera2 = false && Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && SharedConfig.useCamera2; private final CameraSessionWrapper[] cameraSession = new CameraSessionWrapper[2]; private CameraSessionWrapper cameraSessionRecording; @@ -202,6 +203,8 @@ public void startSwitchingAnimation() { flipHalfReached = false; flipping = true; flipAnimator = ValueAnimator.ofFloat(0, 1f); + textureView.setCameraDistance(textureView.getMeasuredHeight() * 4f); + blurredStubView.setCameraDistance(blurredStubView.getMeasuredHeight() * 4f); flipAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator valueAnimator) { @@ -1279,8 +1282,10 @@ private boolean initGL() { FileLog.e("gl initied"); } - float tX = 1.0f / 2.0f; - float tY = 1.0f / 2.0f; + updateScale(0); + + float tX = 1.0f / scaleX / 2.0f; + float tY = 1.0f / scaleY / 2.0f; float[] texData = { 0.5f - tX, 0.5f - tY, 0.5f + tX, 0.5f - tY, @@ -1307,7 +1312,6 @@ private boolean initGL() { cameraSurface[1] = new SurfaceTexture(cameraTexture[1][0]); cameraSurface[1].setOnFrameAvailableListener(this::updTex); - } if (initDual) { @@ -1670,6 +1674,21 @@ public void handleMessage(Message inputMessage) { } createCamera(cameraSurface[i], i); + updateScale(i); + + float tX = 1.0f / scaleX / 2.0f; + float tY = 1.0f / scaleY / 2.0f; + + float[] texData = { + 0.5f - tX, 0.5f - tY, + 0.5f + tX, 0.5f - tY, + 0.5f - tX, 0.5f + tY, + 0.5f + tX, 0.5f + tY + }; + + textureBuffer = ByteBuffer.allocateDirect(texData.length * 4).order(ByteOrder.nativeOrder()).asFloatBuffer(); + textureBuffer.put(texData).position(0); + if (i == 1) { dualAppeared = false; synchronized (layoutLock) { @@ -1798,6 +1817,33 @@ public void handleMessage(Message inputMessage) { } } + private void updateScale(int surfaceIndex) { + int width, height; + if (previewSize[surfaceIndex] != null) { + width = previewSize[surfaceIndex].getWidth(); + height = previewSize[surfaceIndex].getHeight(); + } else { + return; + } + + float scale = surfaceWidth / (float) Math.min(width, height); + + width *= scale; + height *= scale; + + if (width == height) { + scaleX = 1f; + scaleY = 1f; + } else if (width > height) { + scaleX = height / (float) surfaceWidth; + scaleY = 1.0f; + } else { + scaleX = 1.0f; + scaleY = width / (float) surfaceHeight; + } + FileLog.d("CameraView camera scaleX = " + scaleX + " scaleY = " + scaleY); + } + // private final float[] tempVertices = new float[6]; private void applyDualMatrix(Matrix matrix) { // tempVertices[0] = tempVertices[1] = 0; @@ -1944,9 +1990,10 @@ private void createCamera(final SurfaceTexture surfaceTexture, int i) { } if (useCamera2) { - Camera2Session session = Camera2Session.create(false, i == 0 ? isFrontface : !isFrontface, surfaceWidth, surfaceHeight); + Camera2Session session = Camera2Session.create(i == 0 ? isFrontface : !isFrontface, surfaceWidth, surfaceHeight); if (session == null) return; cameraSession[i] = CameraSessionWrapper.of(session); + previewSize[i] = new Size(session.getPreviewWidth(), session.getPreviewHeight()); cameraThread.setCurrentSession(cameraSession[i], i); session.whenDone(() -> { requestLayout(); @@ -2764,9 +2811,8 @@ private void prepareEncoder() { } GLES20.glBlendFunc(GLES20.GL_SRC_ALPHA, GLES20.GL_ONE_MINUS_SRC_ALPHA); - float tX = 1.0f / 2.0f; - float tY = 1.0f / 2.0f; - + float tX = 1.0f / scaleX / 2.0f; + float tY = 1.0f / scaleY / 2.0f; float[] texData = { 0.5f - tX, 0.5f - tY, 0.5f + tX, 0.5f - tY, @@ -2776,7 +2822,6 @@ private void prepareEncoder() { textureBuffer = ByteBuffer.allocateDirect(texData.length * 4).order(ByteOrder.nativeOrder()).asFloatBuffer(); textureBuffer.put(texData).position(0); - int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, RLottieDrawable.readRes(null, R.raw.camera_vert)); int fragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER, RLottieDrawable.readRes(null, R.raw.camera_frag)); if (vertexShader != 0 && fragmentShader != 0) { diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/video/VideoPlayerHolderBase.java b/TMessagesProj/src/main/java/org/telegram/messenger/video/VideoPlayerHolderBase.java index 3f8b016f6c7..b5421288819 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/video/VideoPlayerHolderBase.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/video/VideoPlayerHolderBase.java @@ -28,7 +28,7 @@ public class VideoPlayerHolderBase { public TLRPC.Document document; VideoPlayer videoPlayer; Runnable initRunnable; - volatile boolean released; + public volatile boolean released; public boolean firstFrameRendered; public float progress; @@ -100,6 +100,7 @@ public void preparePlayer(Uri uri, boolean audioDisabled, float speed) { } ensurePlayerCreated(audioDisabled); videoPlayer.setPlaybackSpeed(speed); + FileLog.d("videoplayerholderbase.preparePlayer(): preparePlayer new player as preload uri=" + uri); videoPlayer.preparePlayer(uri, "other", FileLoader.PRIORITY_LOW); videoPlayer.setPlayWhenReady(false); videoPlayer.setWorkerQueue(dispatchQueue); @@ -110,16 +111,19 @@ public void start(boolean paused, Uri uri, long position, boolean audioDisabled, startTime = System.currentTimeMillis(); this.audioDisabled = audioDisabled; this.paused = paused; + this.triesCount = 3; if (position > 0) { currentPosition = position; } dispatchQueue.postRunnable(initRunnable = () -> { if (released) { + FileLog.d("videoplayerholderbase returned from start: released"); return; } if (videoPlayer == null) { ensurePlayerCreated(audioDisabled); videoPlayer.setPlaybackSpeed(speed); + FileLog.d("videoplayerholderbase.start(): preparePlayer new player uri=" + uri); videoPlayer.preparePlayer(uri, "other"); videoPlayer.setWorkerQueue(dispatchQueue); if (!paused) { @@ -131,6 +135,7 @@ public void start(boolean paused, Uri uri, long position, boolean audioDisabled, videoPlayer.setPlayWhenReady(true); } } else { + FileLog.d("videoplayerholderbase.start(): player already exist"); if (!paused) { if (surfaceView != null) { videoPlayer.setSurfaceView(surfaceView); @@ -149,6 +154,8 @@ public void start(boolean paused, Uri uri, long position, boolean audioDisabled, }); } + private volatile int triesCount = 3; + private void ensurePlayerCreated(boolean audioDisabled) { if (videoPlayer != null) { videoPlayer.releasePlayer(true); @@ -176,6 +183,17 @@ public void onStateChanged(boolean playWhenReady, int playbackState) { @Override public void onError(VideoPlayer player, Exception e) { FileLog.e(e); + final long positionMs = getCurrentPosition(); + triesCount--; + if (triesCount > 0) { + dispatchQueue.postRunnable(initRunnable = () -> { + if (released) { + return; + } + videoPlayer.preparePlayer(uri, "other"); + videoPlayer.seekTo(positionMs); + }); + } } @Override @@ -348,6 +366,7 @@ public void setAudioEnabled(boolean enabled, boolean prepared) { return; } audioDisabled = disabled; + this.triesCount = 3; dispatchQueue.postRunnable(() -> { if (videoPlayer == null) { return; @@ -360,6 +379,7 @@ public void setAudioEnabled(boolean enabled, boolean prepared) { videoPlayer.releasePlayer(false); videoPlayer = null; ensurePlayerCreated(audioDisabled); + FileLog.d("videoplayerholderbase.setAudioEnabled(): repreparePlayer as audio track is enabled back uri=" + uri); videoPlayer.preparePlayer(uri, "other"); videoPlayer.setWorkerQueue(dispatchQueue); if (!prepared) { diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/voip/EncryptionKeyEmojifier.java b/TMessagesProj/src/main/java/org/telegram/messenger/voip/EncryptionKeyEmojifier.java index b0ed30a9cf3..54a2348832e 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/voip/EncryptionKeyEmojifier.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/voip/EncryptionKeyEmojifier.java @@ -10,7 +10,7 @@ public class EncryptionKeyEmojifier { "\uD83D\uDC69", "\uD83D\uDC74", "\uD83D\uDC75", "\uD83D\uDE3B", "\uD83D\uDE3D", "\uD83D\uDE40", "\uD83D\uDC7A", "\uD83D\uDE48", "\uD83D\uDE49", "\uD83D\uDE4A", "\uD83D\uDC80", "\uD83D\uDC7D", "\uD83D\uDCA9", "\uD83D\uDD25", "\uD83D\uDCA5", "\uD83D\uDCA4", "\uD83D\uDC42", "\uD83D\uDC40", "\uD83D\uDC43", "\uD83D\uDC45", "\uD83D\uDC44", "\uD83D\uDC4D", "\uD83D\uDC4E", "\uD83D\uDC4C", "\uD83D\uDC4A", "✌", "✋", "\uD83D\uDC50", "\uD83D\uDC46", "\uD83D\uDC47", "\uD83D\uDC49", - "\uD83D\uDC48", "\uD83D\uDE4F", "\uD83D\uDC4F", "\uD83D\uDCAA", "\uD83D\uDEB6", "\uD83C\uDFC3", "\uD83D\uDC83", "\uD83D\uDC6B", "\uD83D\uDC6A", "\uD83D\uDC6C", + "\uD83D\uDC48", "\uD83D\uDE4F", "\uD83D\uDC4F", "\uD83D\uDCAA", "\uD83D\uDEB6", "\uD83C\uDFC3", "\uD83D\uDC83", "\uD83D\uDC6B", "\uD83D\uDC68\u200D\uD83D\uDC69\u200D\uD83D\uDC66", "\uD83D\uDC6C", "\uD83D\uDC6D", "\uD83D\uDC85", "\uD83C\uDFA9", "\uD83D\uDC51", "\uD83D\uDC52", "\uD83D\uDC5F", "\uD83D\uDC5E", "\uD83D\uDC60", "\uD83D\uDC55", "\uD83D\uDC57", "\uD83D\uDC56", "\uD83D\uDC59", "\uD83D\uDC5C", "\uD83D\uDC53", "\uD83C\uDF80", "\uD83D\uDC84", "\uD83D\uDC9B", "\uD83D\uDC99", "\uD83D\uDC9C", "\uD83D\uDC9A", "\uD83D\uDC8D", "\uD83D\uDC8E", "\uD83D\uDC36", "\uD83D\uDC3A", "\uD83D\uDC31", "\uD83D\uDC2D", "\uD83D\uDC39", "\uD83D\uDC30", "\uD83D\uDC38", "\uD83D\uDC2F", diff --git a/TMessagesProj/src/main/java/org/telegram/tgnet/ConnectionsManager.java b/TMessagesProj/src/main/java/org/telegram/tgnet/ConnectionsManager.java index e2624740bcb..e1e43b15a9f 100644 --- a/TMessagesProj/src/main/java/org/telegram/tgnet/ConnectionsManager.java +++ b/TMessagesProj/src/main/java/org/telegram/tgnet/ConnectionsManager.java @@ -9,6 +9,8 @@ import android.os.SystemClock; import android.text.TextUtils; import android.util.Base64; +import android.util.LongSparseArray; +import android.util.SparseIntArray; import com.google.android.exoplayer2.util.Log; import com.google.firebase.remoteconfig.FirebaseRemoteConfig; @@ -52,6 +54,7 @@ import java.util.Objects; import java.util.TimeZone; import java.util.concurrent.BlockingQueue; +import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.Executor; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.ThreadFactory; @@ -83,6 +86,7 @@ public class ConnectionsManager extends BaseController { public final static int RequestFlagInvokeAfter = 64; public final static int RequestFlagNeedQuickAck = 128; public final static int RequestFlagDoNotWaitFloodWait = 1024; + public final static int RequestFlagListenAfterCancel = 2048; public final static int ConnectionStateConnecting = 1; public final static int ConnectionStateWaitingForNetwork = 2; @@ -296,37 +300,37 @@ public int sendRequest(TLObject object, RequestDelegate completionBlock, int fla return sendRequest(object, completionBlock, null, null, null, flags, DEFAULT_DATACENTER_ID, ConnectionTypeGeneric, true); } - public int sendRequest(TLObject object, RequestDelegate completionBlock, int flags, int connetionType) { - return sendRequest(object, completionBlock, null, null, null, flags, DEFAULT_DATACENTER_ID, connetionType, true); + public int sendRequest(TLObject object, RequestDelegate completionBlock, int flags, int connectionType) { + return sendRequest(object, completionBlock, null, null, null, flags, DEFAULT_DATACENTER_ID, connectionType, true); } - public int sendRequest(TLObject object, RequestDelegateTimestamp completionBlock, int flags, int connetionType, int datacenterId) { - return sendRequest(object, null, completionBlock, null, null, flags, datacenterId, connetionType, true); + public int sendRequest(TLObject object, RequestDelegateTimestamp completionBlock, int flags, int connectionType, int datacenterId) { + return sendRequest(object, null, completionBlock, null, null, flags, datacenterId, connectionType, true); } public int sendRequest(TLObject object, RequestDelegate completionBlock, QuickAckDelegate quickAckBlock, int flags) { return sendRequest(object, completionBlock, null, quickAckBlock, null, flags, DEFAULT_DATACENTER_ID, ConnectionTypeGeneric, true); } - public int sendRequest(final TLObject object, final RequestDelegate onComplete, final QuickAckDelegate onQuickAck, final WriteToSocketDelegate onWriteToSocket, final int flags, final int datacenterId, final int connetionType, final boolean immediate) { - return sendRequest(object, onComplete, null, onQuickAck, onWriteToSocket, flags, datacenterId, connetionType, immediate); + public int sendRequest(final TLObject object, final RequestDelegate onComplete, final QuickAckDelegate onQuickAck, final WriteToSocketDelegate onWriteToSocket, final int flags, final int datacenterId, final int connectionType, final boolean immediate) { + return sendRequest(object, onComplete, null, onQuickAck, onWriteToSocket, flags, datacenterId, connectionType, immediate); } - public int sendRequestSync(final TLObject object, final RequestDelegate onComplete, final QuickAckDelegate onQuickAck, final WriteToSocketDelegate onWriteToSocket, final int flags, final int datacenterId, final int connetionType, final boolean immediate) { + public int sendRequestSync(final TLObject object, final RequestDelegate onComplete, final QuickAckDelegate onQuickAck, final WriteToSocketDelegate onWriteToSocket, final int flags, final int datacenterId, final int connectionType, final boolean immediate) { final int requestToken = lastRequestToken.getAndIncrement(); - sendRequestInternal(object, onComplete, null, onQuickAck, onWriteToSocket, flags, datacenterId, connetionType, immediate, requestToken); + sendRequestInternal(object, onComplete, null, onQuickAck, onWriteToSocket, flags, datacenterId, connectionType, immediate, requestToken); return requestToken; } - public int sendRequest(final TLObject object, final RequestDelegate onComplete, final RequestDelegateTimestamp onCompleteTimestamp, final QuickAckDelegate onQuickAck, final WriteToSocketDelegate onWriteToSocket, final int flags, final int datacenterId, final int connetionType, final boolean immediate) { + public int sendRequest(final TLObject object, final RequestDelegate onComplete, final RequestDelegateTimestamp onCompleteTimestamp, final QuickAckDelegate onQuickAck, final WriteToSocketDelegate onWriteToSocket, final int flags, final int datacenterId, final int connectionType, final boolean immediate) { final int requestToken = lastRequestToken.getAndIncrement(); Utilities.stageQueue.postRunnable(() -> { - sendRequestInternal(object, onComplete, onCompleteTimestamp, onQuickAck, onWriteToSocket, flags, datacenterId, connetionType, immediate, requestToken); + sendRequestInternal(object, onComplete, onCompleteTimestamp, onQuickAck, onWriteToSocket, flags, datacenterId, connectionType, immediate, requestToken); }); return requestToken; } - private void sendRequestInternal(TLObject object, RequestDelegate onComplete, RequestDelegateTimestamp onCompleteTimestamp, QuickAckDelegate onQuickAck, WriteToSocketDelegate onWriteToSocket, int flags, int datacenterId, int connetionType, boolean immediate, int requestToken) { + private void sendRequestInternal(TLObject object, RequestDelegate onComplete, RequestDelegateTimestamp onCompleteTimestamp, QuickAckDelegate onQuickAck, WriteToSocketDelegate onWriteToSocket, int flags, int datacenterId, int connectionType, boolean immediate, int requestToken) { if (BuildVars.LOGS_ENABLED) { FileLog.d("send request " + object + " with token = " + requestToken); } @@ -340,7 +344,7 @@ private void sendRequestInternal(TLObject object, RequestDelegate onComplete, Re startRequestTime = System.currentTimeMillis(); } long finalStartRequestTime = startRequestTime; - native_sendRequest(currentAccount, buffer.address, (response, errorCode, errorText, networkType, timestamp, requestMsgId) -> { + listen(requestToken, (response, errorCode, errorText, networkType, timestamp, requestMsgId) -> { try { TLObject resp = null; TLRPC.TL_error error = null; @@ -370,7 +374,7 @@ private void sendRequestInternal(TLObject object, RequestDelegate onComplete, Re FileLog.d("Cleanup keys for " + currentAccount + " because of CONNECTION_NOT_INITED"); } cleanup(true); - sendRequest(object, onComplete, onCompleteTimestamp, onQuickAck, onWriteToSocket, flags, datacenterId, connetionType, immediate); + sendRequest(object, onComplete, onCompleteTimestamp, onQuickAck, onWriteToSocket, flags, datacenterId, connectionType, immediate); return; } if (resp != null) { @@ -395,14 +399,115 @@ private void sendRequestInternal(TLObject object, RequestDelegate onComplete, Re } catch (Exception e) { FileLog.e(e); } - }, onQuickAck, onWriteToSocket, flags, datacenterId, connetionType, immediate, requestToken); + }, onQuickAck, onWriteToSocket); + native_sendRequest(currentAccount, buffer.address, flags, datacenterId, connectionType, immediate, requestToken); } catch (Exception e) { FileLog.e(e); } } + private final ConcurrentHashMap requestCallbacks = new ConcurrentHashMap<>(); + private static class RequestCallbacks { + public RequestDelegateInternal onComplete; + public QuickAckDelegate onQuickAck; + public WriteToSocketDelegate onWriteToSocket; + public Runnable onCancelled; + public RequestCallbacks(RequestDelegateInternal onComplete, QuickAckDelegate onQuickAck, WriteToSocketDelegate onWriteToSocket) { + this.onComplete = onComplete; + this.onQuickAck = onQuickAck; + this.onWriteToSocket = onWriteToSocket; + } + } + + private void listen(int requestToken, RequestDelegateInternal onComplete, QuickAckDelegate onQuickAck, WriteToSocketDelegate onWriteToSocket) { + requestCallbacks.put(requestToken, new RequestCallbacks(onComplete, onQuickAck, onWriteToSocket)); + FileLog.d("{rc} listen(" + currentAccount + ", " + requestToken + "): " + requestCallbacks.size() + " requests' callbacks"); + } + + private void listenCancel(int requestToken, Runnable onCancelled) { + RequestCallbacks callbacks = requestCallbacks.get(requestToken); + if (callbacks != null) { + callbacks.onCancelled = onCancelled; + FileLog.d("{rc} listenCancel(" + currentAccount + ", " + requestToken + "): " + requestCallbacks.size() + " requests' callbacks"); + } else { + FileLog.d("{rc} listenCancel(" + currentAccount + ", " + requestToken + "): callback not found, " + requestCallbacks.size() + " requests' callbacks"); + } + } + + public static void onRequestClear(int currentAccount, int requestToken, boolean cancelled) { + ConnectionsManager connectionsManager = getInstance(currentAccount); + if (connectionsManager == null) return; + RequestCallbacks callbacks = connectionsManager.requestCallbacks.get(requestToken); + if (cancelled) { + if (callbacks != null) { + if (callbacks.onCancelled != null) { + callbacks.onCancelled.run(); + } + connectionsManager.requestCallbacks.remove(requestToken); + FileLog.d("{rc} onRequestClear(" + currentAccount + ", " + requestToken + ", " + cancelled + "): request to cancel is found " + connectionsManager.requestCallbacks.size() + " requests' callbacks"); + } else { + FileLog.d("{rc} onRequestClear(" + currentAccount + ", " + requestToken + ", " + cancelled + "): request to cancel is not found " + connectionsManager.requestCallbacks.size() + " requests' callbacks"); + } + } else if (callbacks != null) { + connectionsManager.requestCallbacks.remove(requestToken); + FileLog.d("{rc} onRequestClear(" + currentAccount + ", " + requestToken + ", " + cancelled + "): " + connectionsManager.requestCallbacks.size() + " requests' callbacks"); + } + } + + public static void onRequestComplete(int currentAccount, int requestToken, long response, int errorCode, String errorText, int networkType, long timestamp, long requestMsgId) { + ConnectionsManager connectionsManager = getInstance(currentAccount); + if (connectionsManager == null) return; + RequestCallbacks callbacks = connectionsManager.requestCallbacks.get(requestToken); + connectionsManager.requestCallbacks.remove(requestToken); + if (callbacks != null) { + if (callbacks.onComplete != null) { + callbacks.onComplete.run(response, errorCode, errorText, networkType, timestamp, requestMsgId); + } + FileLog.d("{rc} onRequestComplete(" + currentAccount + ", " + requestToken + "): found request " + requestToken + ", " + connectionsManager.requestCallbacks.size() + " requests' callbacks"); + } else { + FileLog.d("{rc} onRequestComplete(" + currentAccount + ", " + requestToken + "): not found request " + requestToken + "! " + connectionsManager.requestCallbacks.size() + " requests' callbacks"); + } + } + + public static void onRequestQuickAck(int currentAccount, int requestToken) { + ConnectionsManager connectionsManager = getInstance(currentAccount); + if (connectionsManager == null) return; + RequestCallbacks callbacks = connectionsManager.requestCallbacks.get(requestToken); + if (callbacks != null) { + if (callbacks.onQuickAck != null) { + callbacks.onQuickAck.run(); + } + FileLog.d("{rc} onRequestQuickAck(" + currentAccount + ", " + requestToken + "): found request " + requestToken + ", " + connectionsManager.requestCallbacks.size() + " requests' callbacks"); + } else { + FileLog.d("{rc} onRequestQuickAck(" + currentAccount + ", " + requestToken + "): not found request " + requestToken + "! " + connectionsManager.requestCallbacks.size() + " requests' callbacks"); + } + } + + public static void onRequestWriteToSocket(int currentAccount, int requestToken) { + ConnectionsManager connectionsManager = getInstance(currentAccount); + if (connectionsManager == null) return; + RequestCallbacks callbacks = connectionsManager.requestCallbacks.get(requestToken); + if (callbacks != null) { + if (callbacks.onWriteToSocket != null) { + callbacks.onWriteToSocket.run(); + } + FileLog.d("{rc} onRequestWriteToSocket(" + currentAccount + ", " + requestToken + "): found request " + requestToken + ", " + connectionsManager.requestCallbacks.size() + " requests' callbacks"); + } else { + FileLog.d("{rc} onRequestWriteToSocket(" + currentAccount + ", " + requestToken + "): not found request " + requestToken + "! " + connectionsManager.requestCallbacks.size() + " requests' callbacks"); + } + } + public void cancelRequest(int token, boolean notifyServer) { + cancelRequest(token, notifyServer, null); + } + + public void cancelRequest(int token, boolean notifyServer, Runnable onCancelled) { Utilities.stageQueue.postRunnable(() -> { + if (onCancelled != null) { + listenCancel(token, () -> { + Utilities.stageQueue.postRunnable(onCancelled); + }); + } native_cancelRequest(currentAccount, token, notifyServer); }); } @@ -798,7 +903,7 @@ public static void setProxySettings(boolean enabled, String address, int port, S public static native int native_getCurrentTime(int currentAccount); public static native int native_getCurrentDatacenterId(int currentAccount); public static native int native_getTimeDifference(int currentAccount); - public static native void native_sendRequest(int currentAccount, long object, RequestDelegateInternal onComplete, QuickAckDelegate onQuickAck, WriteToSocketDelegate onWriteToSocket, int flags, int datacenterId, int connetionType, boolean immediate, int requestToken); + public static native void native_sendRequest(int currentAccount, long object, int flags, int datacenterId, int connectionType, boolean immediate, int requestToken); public static native void native_cancelRequest(int currentAccount, int token, boolean notifyServer); public static native void native_cleanUp(int currentAccount, boolean resetKeys); public static native void native_cancelRequestsForGuid(int currentAccount, int guid); diff --git a/TMessagesProj/src/main/java/org/telegram/tgnet/TLRPC.java b/TMessagesProj/src/main/java/org/telegram/tgnet/TLRPC.java index 7e148191f67..f446d588eca 100644 --- a/TMessagesProj/src/main/java/org/telegram/tgnet/TLRPC.java +++ b/TMessagesProj/src/main/java/org/telegram/tgnet/TLRPC.java @@ -77,7 +77,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 = 175; + public static final int LAYER = 176; public static class TL_stats_megagroupStats extends TLObject { public static final int constructor = 0xef7ff916; @@ -9107,7 +9107,6 @@ public void serializeToStream(AbstractSerializedData stream) { public static class TL_messageMediaGeo extends MessageMedia { public static final int constructor = 0x56e0d474; - public void readParams(AbstractSerializedData stream, boolean exception) { geo = GeoPoint.TLdeserialize(stream, stream.readInt32(exception), exception); } @@ -23170,19 +23169,26 @@ public static abstract class DialogFilter extends TLObject { public ArrayList include_peers = new ArrayList<>(); public ArrayList exclude_peers = new ArrayList<>(); public boolean has_my_invites; + public int color; public static DialogFilter TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { DialogFilter result = null; switch (constructor) { - case 0xd64a04a8: - result = new TL_dialogFilterChatlist(); - break; case 0x363293ae: result = new TL_dialogFilterDefault(); break; - case 0x7438f7e8: + case TL_dialogFilter.constructor: result = new TL_dialogFilter(); break; + case TL_dialogFilter_layer175.constructor: + result = new TL_dialogFilter_layer175(); + break; + case TL_dialogFilterChatlist.constructor: + result = new TL_dialogFilterChatlist(); + break; + case TL_dialogFilterChatlist_layer175.constructor: + result = new TL_dialogFilterChatlist_layer175(); + break; } if (result == null && exception) { throw new RuntimeException(String.format("can't parse magic %x in DialogFilter", constructor)); @@ -23195,6 +23201,79 @@ public static DialogFilter TLdeserialize(AbstractSerializedData stream, int cons } public static class TL_dialogFilterChatlist extends DialogFilter { + public static final int constructor = 0x9fe28ea4; + + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + has_my_invites = (flags & 67108864) != 0; + id = stream.readInt32(exception); + title = stream.readString(exception); + if ((flags & 33554432) != 0) { + emoticon = stream.readString(exception); + } + if ((flags & 134217728) != 0) { + color = stream.readInt32(exception); + } + int magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + int count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + InputPeer object = InputPeer.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + pinned_peers.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++) { + InputPeer object = InputPeer.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + include_peers.add(object); + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + flags = has_my_invites ? (flags | 67108864) : (flags &~ 67108864); + stream.writeInt32(flags); + stream.writeInt32(id); + stream.writeString(title); + if ((flags & 33554432) != 0) { + stream.writeString(emoticon); + } + if ((flags & 134217728) != 0) { + stream.writeInt32(color); + } + stream.writeInt32(0x1cb5c415); + int count = pinned_peers.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + pinned_peers.get(a).serializeToStream(stream); + } + stream.writeInt32(0x1cb5c415); + count = include_peers.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + include_peers.get(a).serializeToStream(stream); + } + } + } + + public static class TL_dialogFilterChatlist_layer175 extends TL_dialogFilterChatlist { public static final int constructor = 0xd64a04a8; public void readParams(AbstractSerializedData stream, boolean exception) { @@ -23271,6 +23350,114 @@ public void serializeToStream(AbstractSerializedData stream) { } public static class TL_dialogFilter extends DialogFilter { + public static final int constructor = 0x5fb5523b; + + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + contacts = (flags & 1) != 0; + non_contacts = (flags & 2) != 0; + groups = (flags & 4) != 0; + broadcasts = (flags & 8) != 0; + bots = (flags & 16) != 0; + exclude_muted = (flags & 2048) != 0; + exclude_read = (flags & 4096) != 0; + exclude_archived = (flags & 8192) != 0; + id = stream.readInt32(exception); + title = stream.readString(exception); + if ((flags & 33554432) != 0) { + emoticon = stream.readString(exception); + } + if ((flags & 134217728) != 0) { + color = stream.readInt32(exception); + } + int magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + int count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + InputPeer object = InputPeer.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + pinned_peers.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++) { + InputPeer object = InputPeer.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + include_peers.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++) { + InputPeer object = InputPeer.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + exclude_peers.add(object); + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + flags = contacts ? (flags | 1) : (flags &~ 1); + flags = non_contacts ? (flags | 2) : (flags &~ 2); + flags = groups ? (flags | 4) : (flags &~ 4); + flags = broadcasts ? (flags | 8) : (flags &~ 8); + flags = bots ? (flags | 16) : (flags &~ 16); + flags = exclude_muted ? (flags | 2048) : (flags &~ 2048); + flags = exclude_read ? (flags | 4096) : (flags &~ 4096); + flags = exclude_archived ? (flags | 8192) : (flags &~ 8192); + stream.writeInt32(flags); + stream.writeInt32(id); + stream.writeString(title); + if ((flags & 33554432) != 0) { + stream.writeString(emoticon); + } + if ((flags & 134217728) != 0) { + stream.writeInt32(color); + } + stream.writeInt32(0x1cb5c415); + int count = pinned_peers.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + pinned_peers.get(a).serializeToStream(stream); + } + stream.writeInt32(0x1cb5c415); + count = include_peers.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + include_peers.get(a).serializeToStream(stream); + } + stream.writeInt32(0x1cb5c415); + count = exclude_peers.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + exclude_peers.get(a).serializeToStream(stream); + } + } + } + + public static class TL_dialogFilter_layer175 extends TL_dialogFilter { public static final int constructor = 0x7438f7e8; public void readParams(AbstractSerializedData stream, boolean exception) { @@ -34972,6 +35159,21 @@ public static Update TLdeserialize(AbstractSerializedData stream, int constructo case TL_updatePinnedSavedDialogs.constructor: result = new TL_updatePinnedSavedDialogs(); break; + case TL_updateQuickReplies.constructor: + result = new TL_updateQuickReplies(); + break; + case TL_updateNewQuickReply.constructor: + result = new TL_updateNewQuickReply(); + break; + case TL_updateDeleteQuickReply.constructor: + result = new TL_updateDeleteQuickReply(); + break; + case TL_updateQuickReplyMessage.constructor: + result = new TL_updateQuickReplyMessage(); + break; + case TL_updateDeleteQuickReplyMessages.constructor: + result = new TL_updateDeleteQuickReplyMessages(); + break; } if (result == null && ApplicationLoader.applicationLoaderInstance != null) { result = ApplicationLoader.applicationLoaderInstance.parseTLUpdate(constructor); @@ -52034,6 +52236,7 @@ public void serializeToStream(AbstractSerializedData stream) { public static abstract class UserFull extends TLObject { public int flags; + public int flags2; public boolean blocked; public boolean phone_calls_available; public boolean phone_calls_private; @@ -52068,6 +52271,10 @@ public static abstract class UserFull extends TLObject { public Photo fallback_photo; public WallPaper wallpaper; public TL_stories.PeerStories stories; + public TL_businessWorkHours business_work_hours; + public TL_businessLocation business_location; + public TL_businessGreetingMessage business_greeting_message; + public TL_businessAwayMessage business_away_message; public static UserFull TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { UserFull result = null; @@ -52075,6 +52282,9 @@ public static UserFull TLdeserialize(AbstractSerializedData stream, int construc case TL_userFull.constructor: result = new TL_userFull(); break; + case TL_userFull_layer175.constructor: + result = new TL_userFull_layer175(); + break; case 0x4fe1cc86: result = new TL_userFull_layer162(); break; @@ -52123,7 +52333,7 @@ public static UserFull TLdeserialize(AbstractSerializedData stream, int construc } public static class TL_userFull extends UserFull { - public static final int constructor = 0xb9b12c6c; + public static final int constructor = 0x22ff3e85; public void readParams(AbstractSerializedData stream, boolean exception) { flags = stream.readInt32(exception); @@ -52140,6 +52350,7 @@ public void readParams(AbstractSerializedData stream, boolean exception) { wallpaper_overridden = (flags & 268435456) != 0; contact_require_premium = (flags & 536870912) != 0; read_dates_private = (flags & 1073741824) != 0; + flags2 = stream.readInt32(exception); id = stream.readInt64(exception); if ((flags & 2) != 0) { about = stream.readString(exception); @@ -52203,6 +52414,18 @@ public void readParams(AbstractSerializedData stream, boolean exception) { if ((flags & 33554432) != 0) { stories = TL_stories.PeerStories.TLdeserialize(stream, stream.readInt32(exception), exception); } + if ((flags2 & 1) != 0) { + business_work_hours = TL_businessWorkHours.TLdeserialize(stream, stream.readInt32(exception), exception); + } + if ((flags2 & 2) != 0) { + business_location = TL_businessLocation.TLdeserialize(stream, stream.readInt32(exception), exception); + } + if ((flags2 & 4) != 0) { + business_greeting_message = TL_businessGreetingMessage.TLdeserialize(stream, stream.readInt32(exception), exception); + } + if ((flags2 & 8) != 0) { + business_away_message = TL_businessAwayMessage.TLdeserialize(stream, stream.readInt32(exception), exception); + } } public void serializeToStream(AbstractSerializedData stream) { @@ -52221,6 +52444,7 @@ public void serializeToStream(AbstractSerializedData stream) { flags = contact_require_premium ? (flags | 536870912) : (flags &~ 536870912); flags = read_dates_private ? (flags | 1073741824) : (flags &~ 1073741824); stream.writeInt32(flags); + stream.writeInt32(flags2); stream.writeInt64(id); if ((flags & 2) != 0) { stream.writeString(about); @@ -52275,11 +52499,23 @@ public void serializeToStream(AbstractSerializedData stream) { if ((flags & 33554432) != 0) { stories.serializeToStream(stream); } + if ((flags2 & 1) != 0) { + business_work_hours.serializeToStream(stream); + } + if ((flags2 & 2) != 0) { + business_location.serializeToStream(stream); + } + if ((flags2 & 4) != 0) { + business_greeting_message.serializeToStream(stream); + } + if ((flags2 & 8) != 0) { + business_away_message.serializeToStream(stream); + } } } - public static class TL_userFull_layer162 extends UserFull { - public static final int constructor = 0x4fe1cc86; + public static class TL_userFull_layer175 extends TL_userFull { + public static final int constructor = 0xb9b12c6c; public void readParams(AbstractSerializedData stream, boolean exception) { flags = stream.readInt32(exception); @@ -52293,6 +52529,9 @@ public void readParams(AbstractSerializedData stream, boolean exception) { translations_disabled = (flags & 8388608) != 0; stories_pinned_available = (flags & 67108864) != 0; blocked_my_stories_from = (flags & 134217728) != 0; + wallpaper_overridden = (flags & 268435456) != 0; + contact_require_premium = (flags & 536870912) != 0; + read_dates_private = (flags & 1073741824) != 0; id = stream.readInt64(exception); if ((flags & 2) != 0) { about = stream.readString(exception); @@ -52370,6 +52609,9 @@ public void serializeToStream(AbstractSerializedData stream) { flags = translations_disabled ? (flags | 8388608) : (flags &~ 8388608); flags = stories_pinned_available ? (flags | 67108864) : (flags &~ 67108864); flags = blocked_my_stories_from ? (flags | 134217728) : (flags &~ 134217728); + flags = wallpaper_overridden ? (flags | 268435456) : (flags &~ 268435456); + flags = contact_require_premium ? (flags | 536870912) : (flags &~ 536870912); + flags = read_dates_private ? (flags | 1073741824) : (flags &~ 1073741824); stream.writeInt32(flags); stream.writeInt64(id); if ((flags & 2) != 0) { @@ -52428,8 +52670,8 @@ public void serializeToStream(AbstractSerializedData stream) { } } - public static class TL_userFull_layer159 extends UserFull { - public static final int constructor = 0x93eadb53; + public static class TL_userFull_layer162 extends UserFull { + public static final int constructor = 0x4fe1cc86; public void readParams(AbstractSerializedData stream, boolean exception) { flags = stream.readInt32(exception); @@ -52441,6 +52683,8 @@ public void readParams(AbstractSerializedData stream, boolean exception) { video_calls_available = (flags & 8192) != 0; voice_messages_forbidden = (flags & 1048576) != 0; translations_disabled = (flags & 8388608) != 0; + stories_pinned_available = (flags & 67108864) != 0; + blocked_my_stories_from = (flags & 134217728) != 0; id = stream.readInt64(exception); if ((flags & 2) != 0) { about = stream.readString(exception); @@ -52501,6 +52745,9 @@ public void readParams(AbstractSerializedData stream, boolean exception) { if ((flags & 16777216) != 0) { wallpaper = WallPaper.TLdeserialize(stream, stream.readInt32(exception), exception); } + if ((flags & 33554432) != 0) { + stories = TL_stories.PeerStories.TLdeserialize(stream, stream.readInt32(exception), exception); + } } public void serializeToStream(AbstractSerializedData stream) { @@ -52513,6 +52760,8 @@ public void serializeToStream(AbstractSerializedData stream) { flags = video_calls_available ? (flags | 8192) : (flags &~ 8192); flags = voice_messages_forbidden ? (flags | 1048576) : (flags &~ 1048576); flags = translations_disabled ? (flags | 8388608) : (flags &~ 8388608); + flags = stories_pinned_available ? (flags | 67108864) : (flags &~ 67108864); + flags = blocked_my_stories_from ? (flags | 134217728) : (flags &~ 134217728); stream.writeInt32(flags); stream.writeInt64(id); if ((flags & 2) != 0) { @@ -52565,11 +52814,14 @@ public void serializeToStream(AbstractSerializedData stream) { if ((flags & 16777216) != 0) { wallpaper.serializeToStream(stream); } + if ((flags & 33554432) != 0) { + stories.serializeToStream(stream); + } } } - public static class TL_userFull_layer156 extends UserFull { - public static final int constructor = 0xf8d32aed; + public static class TL_userFull_layer159 extends UserFull { + public static final int constructor = 0x93eadb53; public void readParams(AbstractSerializedData stream, boolean exception) { flags = stream.readInt32(exception); @@ -52638,6 +52890,9 @@ public void readParams(AbstractSerializedData stream, boolean exception) { premium_gifts.add(object); } } + if ((flags & 16777216) != 0) { + wallpaper = WallPaper.TLdeserialize(stream, stream.readInt32(exception), exception); + } } public void serializeToStream(AbstractSerializedData stream) { @@ -52699,11 +52954,14 @@ public void serializeToStream(AbstractSerializedData stream) { premium_gifts.get(a).serializeToStream(stream); } } + if ((flags & 16777216) != 0) { + wallpaper.serializeToStream(stream); + } } } - public static class TL_userFull_layer150_rev2 extends UserFull { - public static final int constructor = 0xec6d41e3; + public static class TL_userFull_layer156 extends UserFull { + public static final int constructor = 0xf8d32aed; public void readParams(AbstractSerializedData stream, boolean exception) { flags = stream.readInt32(exception); @@ -52714,6 +52972,7 @@ public void readParams(AbstractSerializedData stream, boolean exception) { has_scheduled = (flags & 4096) != 0; video_calls_available = (flags & 8192) != 0; voice_messages_forbidden = (flags & 1048576) != 0; + translations_disabled = (flags & 8388608) != 0; id = stream.readInt64(exception); if ((flags & 2) != 0) { about = stream.readString(exception); @@ -52725,6 +52984,9 @@ public void readParams(AbstractSerializedData stream, boolean exception) { if ((flags & 4) != 0) { profile_photo = Photo.TLdeserialize(stream, stream.readInt32(exception), exception); } + if ((flags & 4194304) != 0) { + fallback_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); @@ -52779,6 +53041,7 @@ public void serializeToStream(AbstractSerializedData stream) { flags = has_scheduled ? (flags | 4096) : (flags &~ 4096); flags = video_calls_available ? (flags | 8192) : (flags &~ 8192); flags = voice_messages_forbidden ? (flags | 1048576) : (flags &~ 1048576); + flags = translations_disabled ? (flags | 8388608) : (flags &~ 8388608); stream.writeInt32(flags); stream.writeInt64(id); if ((flags & 2) != 0) { @@ -52791,6 +53054,9 @@ public void serializeToStream(AbstractSerializedData stream) { if ((flags & 4) != 0) { profile_photo.serializeToStream(stream); } + if ((flags & 4194304) != 0) { + fallback_photo.serializeToStream(stream); + } notify_settings.serializeToStream(stream); if ((flags & 8) != 0) { bot_info.serializeToStream(stream); @@ -52828,8 +53094,134 @@ public void serializeToStream(AbstractSerializedData stream) { } } - public static class TL_userFull_layer150 extends UserFull { - public static final int constructor = 0xc4b1fc3f; + public static class TL_userFull_layer150_rev2 extends UserFull { + public static final int constructor = 0xec6d41e3; + + 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; + voice_messages_forbidden = (flags & 1048576) != 0; + id = stream.readInt64(exception); + if ((flags & 2) != 0) { + about = stream.readString(exception); + } + settings = TL_peerSettings.TLdeserialize(stream, stream.readInt32(exception), exception); + if ((flags & 2097152) != 0) { + personal_photo = Photo.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); + } + if ((flags & 524288) != 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_premiumGiftOption object = TL_premiumGiftOption.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + premium_gifts.add(object); + } + } + } + + 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); + flags = voice_messages_forbidden ? (flags | 1048576) : (flags &~ 1048576); + stream.writeInt32(flags); + stream.writeInt64(id); + if ((flags & 2) != 0) { + stream.writeString(about); + } + settings.serializeToStream(stream); + if ((flags & 2097152) != 0) { + personal_photo.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); + } + if ((flags & 524288) != 0) { + stream.writeInt32(0x1cb5c415); + int count = premium_gifts.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + premium_gifts.get(a).serializeToStream(stream); + } + } + } + } + + public static class TL_userFull_layer150 extends UserFull { + public static final int constructor = 0xc4b1fc3f; public void readParams(AbstractSerializedData stream, boolean exception) { flags = stream.readInt32(exception); @@ -57797,7 +58189,7 @@ public void serializeToStream(AbstractSerializedData stream) { } public static class TL_messages_sendMessage extends TLObject { - public static final int constructor = 0x280d096f; + public static final int constructor = 0xdff8042c; public int flags; public boolean no_webpage; @@ -57815,6 +58207,7 @@ public static class TL_messages_sendMessage extends TLObject { public ArrayList entities = new ArrayList<>(); public int schedule_date; public InputPeer send_as; + public InputQuickReplyShortcut quick_reply_shortcut; public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { return Updates.TLdeserialize(stream, constructor, exception); @@ -57853,11 +58246,14 @@ public void serializeToStream(AbstractSerializedData stream) { if ((flags & 8192) != 0) { send_as.serializeToStream(stream); } + if ((flags & 131072) != 0) { + quick_reply_shortcut.serializeToStream(stream); + } } } public static class TL_messages_sendMedia extends TLObject { - public static final int constructor = 0x72ccc23d; + public static final int constructor = 0x7bd66041; public int flags; public boolean silent; @@ -57875,6 +58271,7 @@ public static class TL_messages_sendMedia extends TLObject { public ArrayList entities = new ArrayList<>(); public int schedule_date; public InputPeer send_as; + public InputQuickReplyShortcut quick_reply_shortcut; public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { return Updates.TLdeserialize(stream, constructor, exception); @@ -57913,11 +58310,14 @@ public void serializeToStream(AbstractSerializedData stream) { if ((flags & 8192) != 0) { send_as.serializeToStream(stream); } + if ((flags & 131072) != 0) { + quick_reply_shortcut.serializeToStream(stream); + } } } public static class TL_messages_forwardMessages extends TLObject { - public static final int constructor = 0xc661bbc4; + public static final int constructor = 0xd5039208; public int flags; public boolean silent; @@ -57933,6 +58333,7 @@ public static class TL_messages_forwardMessages extends TLObject { public int top_msg_id; public int schedule_date; public InputPeer send_as; + public InputQuickReplyShortcut quick_reply_shortcut; public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { return Updates.TLdeserialize(stream, constructor, exception); @@ -57970,6 +58371,9 @@ public void serializeToStream(AbstractSerializedData stream) { if ((flags & 8192) != 0) { send_as.serializeToStream(stream); } + if ((flags & 131072) != 0) { + quick_reply_shortcut.serializeToStream(stream); + } } } @@ -60153,7 +60557,7 @@ public void serializeToStream(AbstractSerializedData stream) { } public static class TL_messages_sendInlineBotResult extends TLObject { - public static final int constructor = 0xf7bc68ba; + public static final int constructor = 0x3ebee86a; public int flags; public boolean silent; @@ -60167,6 +60571,7 @@ public static class TL_messages_sendInlineBotResult extends TLObject { public String id; public int schedule_date; public InputPeer send_as; + public InputQuickReplyShortcut quick_reply_shortcut; public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { return Updates.TLdeserialize(stream, constructor, exception); @@ -60192,6 +60597,9 @@ public void serializeToStream(AbstractSerializedData stream) { if ((flags & 8192) != 0) { send_as.serializeToStream(stream); } + if ((flags & 131072) != 0) { + quick_reply_shortcut.serializeToStream(stream); + } } } @@ -60213,7 +60621,7 @@ public void serializeToStream(AbstractSerializedData stream) { } public static class TL_messages_editMessage extends TLObject { - public static final int constructor = 0x48f71778; + public static final int constructor = 0xdfd14005; public int flags; public boolean no_webpage; @@ -60225,6 +60633,7 @@ public static class TL_messages_editMessage extends TLObject { public ReplyMarkup reply_markup; public ArrayList entities = new ArrayList<>(); public int schedule_date; + public int quick_reply_shortcut_id; public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { return Updates.TLdeserialize(stream, constructor, exception); @@ -60257,6 +60666,9 @@ public void serializeToStream(AbstractSerializedData stream) { if ((flags & 32768) != 0) { stream.writeInt32(schedule_date); } + if ((flags & 131072) != 0) { + stream.writeInt32(quick_reply_shortcut_id); + } } } @@ -60889,7 +61301,7 @@ public void serializeToStream(AbstractSerializedData stream) { } public static class TL_messages_sendMultiMedia extends TLObject { - public static final int constructor = 0x456e8987; + public static final int constructor = 0xc964709; public int flags; public boolean silent; @@ -60903,6 +61315,7 @@ public static class TL_messages_sendMultiMedia extends TLObject { public ArrayList multi_media = new ArrayList<>(); public int schedule_date; public InputPeer send_as; + public InputQuickReplyShortcut quick_reply_shortcut; public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { return Updates.TLdeserialize(stream, constructor, exception); @@ -60933,6 +61346,9 @@ public void serializeToStream(AbstractSerializedData stream) { if ((flags & 8192) != 0) { send_as.serializeToStream(stream); } + if ((flags & 131072) != 0) { + quick_reply_shortcut.serializeToStream(stream); + } } } @@ -61799,21 +62215,76 @@ public void serializeToStream(AbstractSerializedData stream) { } } - public static class TL_messages_getDialogFilters extends TLObject { - public static final int constructor = 0xf19ed96d; + public static class TL_messages_dialogFilters extends TLObject { + public static final int constructor = 0x2ad93719; + public int flags; + public boolean tags_enabled; + public ArrayList filters = new ArrayList<>(); - public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { - Vector vector = new Vector(); - int size = stream.readInt32(exception); - for (int a = 0; a < size; a++) { + public static TL_messages_dialogFilters TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + if (TL_messages_dialogFilters.constructor != constructor) { + if (exception) { + throw new RuntimeException(String.format("can't parse magic %x in TL_messages_dialogFilters", constructor)); + } else { + return null; + } + } + TL_messages_dialogFilters result = new TL_messages_dialogFilters(); + result.readParams(stream, exception); + return result; + } + + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + tags_enabled = (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++) { DialogFilter object = DialogFilter.TLdeserialize(stream, stream.readInt32(exception), exception); if (object == null) { - return vector; + return; } - vector.objects.add(object); + filters.add(object); } - return vector; + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + flags = tags_enabled ? (flags | 1) : (flags & 1); + stream.writeInt32(flags); + stream.writeInt32(0x1cb5c415); + int count = filters.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + filters.get(a).serializeToStream(stream); + } + } + } + + public static class TL_messages_getDialogFilters extends TLObject { + public static final int constructor = 0xefd48c89; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + if (constructor == 0x1cb5c415) { + Vector vector = new Vector(); + int size = stream.readInt32(exception); + for (int a = 0; a < size; a++) { + DialogFilter object = DialogFilter.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return vector; + } + vector.objects.add(object); + } + return vector; + } + return TL_messages_dialogFilters.TLdeserialize(stream, constructor, exception); } public void serializeToStream(AbstractSerializedData stream) { @@ -65721,6 +66192,7 @@ public static class Message extends TLObject { public TL_messageReactions reactions; public ArrayList restriction_reason = new ArrayList<>(); public int ttl_period; + public int quick_reply_shortcut_id; public boolean noforwards; public boolean invert_media; public int send_state = 0; //custom @@ -65753,6 +66225,7 @@ public static class Message extends TLObject { public String translatedToLanguage; //custom public TL_textWithEntities translatedText; // custom public TL_stories.StoryItem replyStory; //custom + public InputQuickReplyShortcut quick_reply_shortcut; //custom public static Message TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { Message result = null; @@ -65841,6 +66314,9 @@ public static Message TLdeserialize(AbstractSerializedData stream, int construct case TL_message.constructor: result = new TL_message(); break; + case TL_message_layer175.constructor: + result = new TL_message_layer175(); + break; case TL_message_layer169.constructor: result = new TL_message_layer169(); break; @@ -66547,7 +67023,7 @@ public void serializeToStream(AbstractSerializedData stream) { } public static class TL_message extends Message { - public static final int constructor = 0x1e4c8a69; + public static final int constructor = 0xa66c7efc; public void readParams(AbstractSerializedData stream, boolean exception) { flags = stream.readInt32(exception); @@ -66654,6 +67130,9 @@ public void readParams(AbstractSerializedData stream, boolean exception) { if ((flags & 33554432) != 0) { ttl_period = stream.readInt32(exception); } + if ((flags & 1073741824) != 0) { + quick_reply_shortcut_id = stream.readInt32(exception); + } } public void serializeToStream(AbstractSerializedData stream) { @@ -66738,12 +67217,15 @@ public void serializeToStream(AbstractSerializedData stream) { if ((flags & 33554432) != 0) { stream.writeInt32(ttl_period); } + if ((flags & 1073741824) != 0) { + stream.writeInt32(quick_reply_shortcut_id); + } writeAttachPath(stream); } } - public static class TL_message_layer173 extends TL_message { - public static final int constructor = 0x76bec211; + public static class TL_message_layer175 extends TL_message { + public static final int constructor = 0x1e4c8a69; public void readParams(AbstractSerializedData stream, boolean exception) { flags = stream.readInt32(exception); @@ -66762,6 +67244,9 @@ public void readParams(AbstractSerializedData stream, boolean exception) { if ((flags & 256) != 0) { from_id = Peer.TLdeserialize(stream, stream.readInt32(exception), exception); } + if ((flags & 536870912) != 0) { + from_boosts_applied = stream.readInt32(exception); + } peer_id = Peer.TLdeserialize(stream, stream.readInt32(exception), exception); if ((flags & 268435456) != 0) { saved_peer_id = Peer.TLdeserialize(stream, stream.readInt32(exception), exception); @@ -66867,6 +67352,9 @@ public void serializeToStream(AbstractSerializedData stream) { if ((flags & 256) != 0) { from_id.serializeToStream(stream); } + if ((flags & 536870912) != 0) { + stream.writeInt32(from_boosts_applied); + } peer_id.serializeToStream(stream); if ((flags & 268435456) != 0) { saved_peer_id.serializeToStream(stream); @@ -66932,8 +67420,8 @@ public void serializeToStream(AbstractSerializedData stream) { } } - public static class TL_message_layer169 extends TL_message { - public static final int constructor = 0x38116ee0; + public static class TL_message_layer173 extends TL_message { + public static final int constructor = 0x76bec211; public void readParams(AbstractSerializedData stream, boolean exception) { flags = stream.readInt32(exception); @@ -66953,6 +67441,9 @@ public void readParams(AbstractSerializedData stream, boolean exception) { from_id = Peer.TLdeserialize(stream, stream.readInt32(exception), exception); } peer_id = Peer.TLdeserialize(stream, stream.readInt32(exception), exception); + if ((flags & 268435456) != 0) { + saved_peer_id = Peer.TLdeserialize(stream, stream.readInt32(exception), exception); + } if ((flags & 4) != 0) { fwd_from = MessageFwdHeader.TLdeserialize(stream, stream.readInt32(exception), exception); } @@ -67055,6 +67546,9 @@ public void serializeToStream(AbstractSerializedData stream) { from_id.serializeToStream(stream); } peer_id.serializeToStream(stream); + if ((flags & 268435456) != 0) { + saved_peer_id.serializeToStream(stream); + } if ((flags & 4) != 0) { fwd_from.serializeToStream(stream); } @@ -67116,9 +67610,8 @@ public void serializeToStream(AbstractSerializedData stream) { } } - public static class TL_message_layer135 extends TL_message { - public static final int constructor = 0x85d6cbe2; - + public static class TL_message_layer169 extends TL_message { + public static final int constructor = 0x38116ee0; public void readParams(AbstractSerializedData stream, boolean exception) { flags = stream.readInt32(exception); @@ -67132,6 +67625,7 @@ public void readParams(AbstractSerializedData stream, boolean exception) { edit_hide = (flags & 2097152) != 0; pinned = (flags & 16777216) != 0; noforwards = (flags & 67108864) != 0; + invert_media = (flags & 134217728) != 0; id = stream.readInt32(exception); if ((flags & 256) != 0) { from_id = Peer.TLdeserialize(stream, stream.readInt32(exception), exception); @@ -67195,6 +67689,9 @@ public void readParams(AbstractSerializedData stream, boolean exception) { if ((flags & 131072) != 0) { grouped_id = stream.readInt64(exception); } + if ((flags & 1048576) != 0) { + reactions = MessageReactions.TLdeserialize(stream, stream.readInt32(exception), exception); + } if ((flags & 4194304) != 0) { int magic = stream.readInt32(exception); if (magic != 0x1cb5c415) { @@ -67229,6 +67726,7 @@ public void serializeToStream(AbstractSerializedData stream) { flags = edit_hide ? (flags | 2097152) : (flags &~ 2097152); flags = pinned ? (flags | 16777216) : (flags &~ 16777216); flags = noforwards ? (flags | 67108864) : (flags &~ 67108864); + flags = invert_media ? (flags | 134217728) : (flags &~ 134217728); stream.writeInt32(flags); stream.writeInt32(id); if ((flags & 256) != 0) { @@ -67278,6 +67776,9 @@ public void serializeToStream(AbstractSerializedData stream) { if ((flags & 131072) != 0) { stream.writeInt64(grouped_id); } + if ((flags & 1048576) != 0) { + reactions.serializeToStream(stream); + } if ((flags & 4194304) != 0) { stream.writeInt32(0x1cb5c415); int count = restriction_reason.size(); @@ -67293,8 +67794,8 @@ public void serializeToStream(AbstractSerializedData stream) { } } - public static class TL_message_layer131 extends TL_message { - public static final int constructor = 0xbce383d2; + public static class TL_message_layer135 extends TL_message { + public static final int constructor = 0x85d6cbe2; public void readParams(AbstractSerializedData stream, boolean exception) { @@ -67308,6 +67809,7 @@ public void readParams(AbstractSerializedData stream, boolean exception) { legacy = (flags & 524288) != 0; edit_hide = (flags & 2097152) != 0; pinned = (flags & 16777216) != 0; + noforwards = (flags & 67108864) != 0; id = stream.readInt32(exception); if ((flags & 256) != 0) { from_id = Peer.TLdeserialize(stream, stream.readInt32(exception), exception); @@ -67317,7 +67819,7 @@ public void readParams(AbstractSerializedData stream, boolean exception) { fwd_from = MessageFwdHeader.TLdeserialize(stream, stream.readInt32(exception), exception); } if ((flags & 2048) != 0) { - via_bot_id = stream.readInt32(exception); + via_bot_id = stream.readInt64(exception); } if ((flags & 8) != 0) { reply_to = MessageReplyHeader.TLdeserialize(stream, stream.readInt32(exception), exception); @@ -67327,7 +67829,7 @@ public void readParams(AbstractSerializedData stream, boolean exception) { if ((flags & 512) != 0) { media = MessageMedia.TLdeserialize(stream, stream.readInt32(exception), exception); if (media != null) { - ttl = media.ttl_seconds; //custom + ttl = media.ttl_seconds; } if (media != null && !TextUtils.isEmpty(media.captionLegacy)) { message = media.captionLegacy; @@ -67404,6 +67906,7 @@ public void serializeToStream(AbstractSerializedData stream) { flags = legacy ? (flags | 524288) : (flags &~ 524288); flags = edit_hide ? (flags | 2097152) : (flags &~ 2097152); flags = pinned ? (flags | 16777216) : (flags &~ 16777216); + flags = noforwards ? (flags | 67108864) : (flags &~ 67108864); stream.writeInt32(flags); stream.writeInt32(id); if ((flags & 256) != 0) { @@ -67414,7 +67917,7 @@ public void serializeToStream(AbstractSerializedData stream) { fwd_from.serializeToStream(stream); } if ((flags & 2048) != 0) { - stream.writeInt32((int) via_bot_id); + stream.writeInt64(via_bot_id); } if ((flags & 8) != 0) { reply_to.serializeToStream(stream); @@ -67464,12 +67967,12 @@ public void serializeToStream(AbstractSerializedData stream) { if ((flags & 33554432) != 0) { stream.writeInt32(ttl_period); } - writeAttachPath(stream); //custom + writeAttachPath(stream); } } - public static class TL_message_layer123 extends TL_message { - public static final int constructor = 0x58ae39c9; + public static class TL_message_layer131 extends TL_message { + public static final int constructor = 0xbce383d2; public void readParams(AbstractSerializedData stream, boolean exception) { @@ -67563,6 +68066,9 @@ public void readParams(AbstractSerializedData stream, boolean exception) { restriction_reason.add(object); } } + if ((flags & 33554432) != 0) { + ttl_period = stream.readInt32(exception); + } } public void serializeToStream(AbstractSerializedData stream) { @@ -67633,12 +68139,15 @@ public void serializeToStream(AbstractSerializedData stream) { restriction_reason.get(a).serializeToStream(stream); } } - writeAttachPath(stream); + if ((flags & 33554432) != 0) { + stream.writeInt32(ttl_period); + } + writeAttachPath(stream); //custom } } - public static class TL_message_layer118 extends TL_message { - public static final int constructor = 0xf52e6b7f; + public static class TL_message_layer123 extends TL_message { + public static final int constructor = 0x58ae39c9; public void readParams(AbstractSerializedData stream, boolean exception) { @@ -67651,10 +68160,10 @@ public void readParams(AbstractSerializedData stream, boolean exception) { from_scheduled = (flags & 262144) != 0; legacy = (flags & 524288) != 0; edit_hide = (flags & 2097152) != 0; + pinned = (flags & 16777216) != 0; id = stream.readInt32(exception); if ((flags & 256) != 0) { - from_id = new TLRPC.TL_peerUser(); - from_id.user_id = stream.readInt32(exception); + from_id = Peer.TLdeserialize(stream, stream.readInt32(exception), exception); } peer_id = Peer.TLdeserialize(stream, stream.readInt32(exception), exception); if ((flags & 4) != 0) { @@ -67664,9 +68173,178 @@ public void readParams(AbstractSerializedData stream, boolean exception) { via_bot_id = stream.readInt32(exception); } if ((flags & 8) != 0) { - reply_to = new TLRPC.TL_messageReplyHeader(); - reply_to.flags |= 16; - reply_to.reply_to_msg_id = stream.readInt32(exception); + reply_to = MessageReplyHeader.TLdeserialize(stream, stream.readInt32(exception), exception); + } + date = stream.readInt32(exception); + message = stream.readString(exception); + if ((flags & 512) != 0) { + media = MessageMedia.TLdeserialize(stream, stream.readInt32(exception), exception); + if (media != null) { + ttl = media.ttl_seconds; //custom + } + if (media != null && !TextUtils.isEmpty(media.captionLegacy)) { + message = media.captionLegacy; + } + } + if ((flags & 64) != 0) { + reply_markup = ReplyMarkup.TLdeserialize(stream, stream.readInt32(exception), exception); + } + if ((flags & 128) != 0) { + int magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + int count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + MessageEntity object = MessageEntity.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + entities.add(object); + } + } + if ((flags & 1024) != 0) { + views = stream.readInt32(exception); + } + if ((flags & 1024) != 0) { + forwards = stream.readInt32(exception); + } + if ((flags & 8388608) != 0) { + replies = MessageReplies.TLdeserialize(stream, stream.readInt32(exception), exception); + } + if ((flags & 32768) != 0) { + edit_date = stream.readInt32(exception); + } + if ((flags & 65536) != 0) { + post_author = stream.readString(exception); + } + if ((flags & 131072) != 0) { + grouped_id = stream.readInt64(exception); + } + if ((flags & 4194304) != 0) { + int magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + int count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + TL_restrictionReason object = TL_restrictionReason.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + restriction_reason.add(object); + } + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + flags = out ? (flags | 2) : (flags &~ 2); + flags = mentioned ? (flags | 16) : (flags &~ 16); + flags = media_unread ? (flags | 32) : (flags &~ 32); + flags = silent ? (flags | 8192) : (flags &~ 8192); + flags = post ? (flags | 16384) : (flags &~ 16384); + flags = from_scheduled ? (flags | 262144) : (flags &~ 262144); + flags = legacy ? (flags | 524288) : (flags &~ 524288); + flags = edit_hide ? (flags | 2097152) : (flags &~ 2097152); + flags = pinned ? (flags | 16777216) : (flags &~ 16777216); + stream.writeInt32(flags); + stream.writeInt32(id); + if ((flags & 256) != 0) { + from_id.serializeToStream(stream); + } + peer_id.serializeToStream(stream); + if ((flags & 4) != 0) { + fwd_from.serializeToStream(stream); + } + if ((flags & 2048) != 0) { + stream.writeInt32((int) via_bot_id); + } + if ((flags & 8) != 0) { + reply_to.serializeToStream(stream); + } + stream.writeInt32(date); + stream.writeString(message); + if ((flags & 512) != 0) { + media.serializeToStream(stream); + } + if ((flags & 64) != 0) { + reply_markup.serializeToStream(stream); + } + if ((flags & 128) != 0) { + stream.writeInt32(0x1cb5c415); + int count = entities.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + entities.get(a).serializeToStream(stream); + } + } + if ((flags & 1024) != 0) { + stream.writeInt32(views); + } + if ((flags & 1024) != 0) { + stream.writeInt32(forwards); + } + if ((flags & 8388608) != 0) { + replies.serializeToStream(stream); + } + if ((flags & 32768) != 0) { + stream.writeInt32(edit_date); + } + if ((flags & 65536) != 0) { + stream.writeString(post_author); + } + if ((flags & 131072) != 0) { + stream.writeInt64(grouped_id); + } + if ((flags & 4194304) != 0) { + stream.writeInt32(0x1cb5c415); + int count = restriction_reason.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + restriction_reason.get(a).serializeToStream(stream); + } + } + writeAttachPath(stream); + } + } + + public static class TL_message_layer118 extends TL_message { + public static final int constructor = 0xf52e6b7f; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + out = (flags & 2) != 0; + mentioned = (flags & 16) != 0; + media_unread = (flags & 32) != 0; + silent = (flags & 8192) != 0; + post = (flags & 16384) != 0; + from_scheduled = (flags & 262144) != 0; + legacy = (flags & 524288) != 0; + edit_hide = (flags & 2097152) != 0; + id = stream.readInt32(exception); + if ((flags & 256) != 0) { + from_id = new TLRPC.TL_peerUser(); + from_id.user_id = stream.readInt32(exception); + } + peer_id = Peer.TLdeserialize(stream, stream.readInt32(exception), exception); + if ((flags & 4) != 0) { + fwd_from = MessageFwdHeader.TLdeserialize(stream, stream.readInt32(exception), exception); + } + if ((flags & 2048) != 0) { + via_bot_id = stream.readInt32(exception); + } + if ((flags & 8) != 0) { + reply_to = new TLRPC.TL_messageReplyHeader(); + reply_to.flags |= 16; + reply_to.reply_to_msg_id = stream.readInt32(exception); } date = stream.readInt32(exception); message = stream.readString(exception); @@ -73587,6 +74265,114 @@ public void serializeToStream(AbstractSerializedData stream) { } } } + + public static class TL_updateQuickReplies extends Update { + public static final int constructor = 0xf9470ab2; + + public ArrayList quick_replies = new ArrayList<>(); + + public void readParams(AbstractSerializedData stream, boolean exception) { + int magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + int count = stream.readInt32(exception); + for (int i = 0; i < count; ++i) { + quick_replies.add(TL_quickReply.TLdeserialize(stream, stream.readInt32(exception), exception)); + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(0x1cb5c415); + int count = quick_replies.size(); + stream.writeInt32(count); + for (int i = 0; i < count; ++i) { + quick_replies.get(i).serializeToStream(stream); + } + } + } + + public static class TL_updateNewQuickReply extends Update { + public static final int constructor = 0xf53da717; + + public TL_quickReply quick_reply; + + public void readParams(AbstractSerializedData stream, boolean exception) { + quick_reply = TL_quickReply.TLdeserialize(stream, stream.readInt32(exception), exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + quick_reply.serializeToStream(stream); + } + } + + public static class TL_updateDeleteQuickReply extends Update { + public static final int constructor = 0x53e6f1ec; + + public int shortcut_id; + + public void readParams(AbstractSerializedData stream, boolean exception) { + shortcut_id = stream.readInt32(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(shortcut_id); + } + } + + public static class TL_updateQuickReplyMessage extends Update { + public static final int constructor = 0x3e050d0f; + + public Message message; + + public void readParams(AbstractSerializedData stream, boolean exception) { + message = Message.TLdeserialize(stream, stream.readInt32(exception), exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + message.serializeToStream(stream); + } + } + + public static class TL_updateDeleteQuickReplyMessages extends Update { + public static final int constructor = 0x566fe7cd; + + public int shortcut_id; + public ArrayList messages = new ArrayList<>(); + + public void readParams(AbstractSerializedData stream, boolean exception) { + shortcut_id = stream.readInt32(exception); + int magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + int count = stream.readInt32(exception); + for (int i = 0; i < count; ++i) { + messages.add(stream.readInt32(exception)); + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(shortcut_id); + stream.writeInt32(0x1cb5c415); + int count = messages.size(); + stream.writeInt32(count); + for (int i = 0; i < count; ++i) { + stream.writeInt32(messages.get(i)); + } + } + } public static class TL_updateSavedDialogPinned extends Update { public static final int constructor = 0xaeaf9e74; @@ -75752,6 +76538,1188 @@ public void serializeToStream(AbstractSerializedData stream) { } } + public static class TL_businessWeeklyOpen extends TLObject { + public static final int constructor = 0x120b1ab9; + + public int start_minute; + public int end_minute; + + public static TL_businessWeeklyOpen TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + if (constructor != TL_businessWeeklyOpen.constructor) { + if (exception) { + throw new RuntimeException(String.format("can't parse magic %x in TL_businessWeeklyOpen", constructor)); + } + return null; + } + TL_businessWeeklyOpen result = new TL_businessWeeklyOpen(); + result.readParams(stream, exception); + return result; + } + + @Override + public void readParams(AbstractSerializedData stream, boolean exception) { + start_minute = stream.readInt32(exception); + end_minute = stream.readInt32(exception); + } + + @Override + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(start_minute); + stream.writeInt32(end_minute); + } + } + + public static class TL_businessWorkHours extends TLObject { + public static final int constructor = 0x8c92b098; + + public int flags; + public boolean open_now; + public String timezone_id; + public ArrayList weekly_open = new ArrayList<>(); + + public static TL_businessWorkHours TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + if (constructor != TL_businessWorkHours.constructor) { + if (exception) { + throw new RuntimeException(String.format("can't parse magic %x in TL_businessWorkHours", constructor)); + } + return null; + } + TL_businessWorkHours result = new TL_businessWorkHours(); + result.readParams(stream, exception); + return result; + } + + @Override + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + open_now = (flags & 1) != 0; + timezone_id = 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 i = 0; i < count; ++i) { + weekly_open.add(TL_businessWeeklyOpen.TLdeserialize(stream, stream.readInt32(exception), exception)); + } + } + + @Override + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + flags = open_now ? (flags | 1) : (flags &~ 1); + stream.writeInt32(flags); + stream.writeString(timezone_id); + stream.writeInt32(0x1cb5c415); + int count = weekly_open.size(); + stream.writeInt32(count); + for (int i = 0; i < count; ++i) { + weekly_open.get(i).serializeToStream(stream); + } + } + } + + public static class TL_businessLocation extends TLObject { + public static final int constructor = 0xac5c1af7; + + public int flags; + public GeoPoint geo_point; + public String address; + + public static TL_businessLocation TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + if (constructor != TL_businessLocation.constructor) { + if (exception) { + throw new RuntimeException(String.format("can't parse magic %x in TL_businessLocation", constructor)); + } + return null; + } + TL_businessLocation result = new TL_businessLocation(); + result.readParams(stream, exception); + return result; + } + + @Override + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + if ((flags & 1) != 0) { + geo_point = GeoPoint.TLdeserialize(stream, stream.readInt32(exception), exception); + } + address = stream.readString(exception); + } + + @Override + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(flags); + if ((flags & 1) != 0) { + geo_point.serializeToStream(stream); + } + stream.writeString(address); + } + } + + public static class TL_timezone extends TLObject { + public static final int constructor = 0xff9289f5; + + public String id; + public String name; + public int utc_offset; + + public static TL_timezone TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + if (constructor != TL_timezone.constructor) { + if (exception) { + throw new RuntimeException(String.format("can't parse magic %x in TL_timezone", constructor)); + } + return null; + } + TL_timezone result = new TL_timezone(); + result.readParams(stream, exception); + return result; + } + + @Override + public void readParams(AbstractSerializedData stream, boolean exception) { + id = stream.readString(exception); + name = stream.readString(exception); + utc_offset = stream.readInt32(exception); + } + + @Override + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeString(id); + stream.writeString(name); + stream.writeInt32(utc_offset); + } + } + + public static class help_timezonesList extends TLObject { + + public ArrayList timezones = new ArrayList<>(); + public int hash; + + public static help_timezonesList TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + help_timezonesList result = null; + switch (constructor) { + case TL_help_timezonesListNotModified.constructor: + result = new TL_help_timezonesListNotModified(); + break; + case TL_help_timezonesList.constructor: + result = new TL_help_timezonesList(); + break; + } + if (result == null && exception) { + throw new RuntimeException(String.format("can't parse magic %x in help_timezonesList", constructor)); + } + if (result != null) { + result.readParams(stream, exception); + } + return result; + } + } + + public static class TL_help_timezonesListNotModified extends help_timezonesList { + public static final int constructor = 0x970708cc; + + @Override + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } + + public static class TL_help_timezonesList extends help_timezonesList { + public static final int constructor = 0x7b74ed71; + + @Override + public void readParams(AbstractSerializedData stream, boolean exception) { + int magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + int count = stream.readInt32(exception); + for (int i = 0; i < count; ++i) { + timezones.add(TL_timezone.TLdeserialize(stream, stream.readInt32(exception), exception)); + } + } + + @Override + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(0x1cb5c415); + final int count = timezones.size(); + stream.writeInt32(count); + for (int i = 0; i < count; ++i) { + timezones.get(i).serializeToStream(stream); + } + stream.writeInt32(hash); + } + } + + public static class TL_help_getTimezonesList extends TLObject { + public static final int constructor = 0x49b30240; + + public int hash; + + @Override + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return help_timezonesList.TLdeserialize(stream, constructor, exception); + } + + @Override + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(hash); + } + } + + public static class TL_account_updateBusinessWorkHours extends TLObject { + public static final int constructor = 0x4b00e066; + + public int flags; + public TL_businessWorkHours business_work_hours; + + @Override + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return Bool.TLdeserialize(stream, constructor, exception); + } + + @Override + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(flags); + if ((flags & 1) != 0) { + business_work_hours.serializeToStream(stream); + } + } + } + + public static class TL_account_updateBusinessLocation extends TLObject { + public static final int constructor = 0x9e6b131a; + + public int flags; + public InputGeoPoint geo_point; + public String address; + + @Override + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return Bool.TLdeserialize(stream, constructor, exception); + } + + @Override + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(flags); + if ((flags & 2) != 0) { + geo_point.serializeToStream(stream); + } + if ((flags & 1) != 0) { + stream.writeString(address); + } + } + } + + public static class InputQuickReplyShortcut extends TLObject { + public static InputQuickReplyShortcut TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + InputQuickReplyShortcut result = null; + switch (constructor) { + case TL_inputQuickReplyShortcut.constructor: + result = new TL_inputQuickReplyShortcut(); + break; + case TL_inputQuickReplyShortcutId.constructor: + result = new TL_inputQuickReplyShortcutId(); + break; + } + if (result == null && exception) { + throw new RuntimeException(String.format("can't parse magic %x in InputQuickReplyShortcut", constructor)); + } + if (result != null) { + result.readParams(stream, exception); + } + return result; + } + } + + public static class TL_inputQuickReplyShortcut extends InputQuickReplyShortcut { + public static final int constructor = 0x24596d41; + + public String shortcut; + + @Override + public void readParams(AbstractSerializedData stream, boolean exception) { + shortcut = stream.readString(exception); + } + + @Override + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeString(shortcut); + } + } + + public static class TL_inputQuickReplyShortcutId extends InputQuickReplyShortcut { + public static final int constructor = 0x1190cf1; + + public int shortcut_id; + + @Override + public void readParams(AbstractSerializedData stream, boolean exception) { + shortcut_id = stream.readInt32(exception); + } + + @Override + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(shortcut_id); + } + } + + public static class TL_quickReply extends TLObject { + public static final int constructor = 0x697102b; + + public int shortcut_id; + public String shortcut; + public int top_message; + public int count; + + public static TL_quickReply TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + if (constructor != TL_quickReply.constructor) { + if (exception) { + throw new RuntimeException(String.format("can't parse magic %x in TL_messages_quickReply", constructor)); + } + return null; + } + TL_quickReply result = new TL_quickReply(); + result.readParams(stream, exception); + return result; + } + + @Override + public void readParams(AbstractSerializedData stream, boolean exception) { + shortcut_id = stream.readInt32(exception); + shortcut = stream.readString(exception); + top_message = stream.readInt32(exception); + count = stream.readInt32(exception); + } + + @Override + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(shortcut_id); + stream.writeString(shortcut); + stream.writeInt32(top_message); + stream.writeInt32(count); + } + } + + public static class messages_quickReplies extends TLObject { + public static messages_quickReplies TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + messages_quickReplies result = null; + switch (constructor) { + case TL_messages_quickReplies.constructor: + result = new TL_messages_quickReplies(); + break; + case TL_messages_quickRepliesNotModified.constructor: + result = new TL_messages_quickRepliesNotModified(); + break; + } + if (result == null && exception) { + throw new RuntimeException(String.format("can't parse magic %x in messages_quickReplies", constructor)); + } + if (result != null) { + result.readParams(stream, exception); + } + return result; + } + } + + public static class TL_messages_quickRepliesNotModified extends messages_quickReplies { + public static final int constructor = 0x5f91eb5b; + + @Override + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } + + public static class TL_messages_quickReplies extends messages_quickReplies { + public static final int constructor = 0xc68d6695; + + public ArrayList quick_replies = new ArrayList<>(); + public ArrayList messages = new ArrayList<>(); + public ArrayList chats = new ArrayList<>(); + public ArrayList users = new ArrayList<>(); + + @Override + public void readParams(AbstractSerializedData stream, boolean exception) { + int magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + int count = stream.readInt32(exception); + for (int i = 0; i < count; ++i) { + quick_replies.add(TL_quickReply.TLdeserialize(stream, stream.readInt32(exception), exception)); + } + magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + count = stream.readInt32(exception); + for (int i = 0; i < count; ++i) { + messages.add(Message.TLdeserialize(stream, stream.readInt32(exception), exception)); + } + magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + count = stream.readInt32(exception); + for (int i = 0; i < count; ++i) { + chats.add(Chat.TLdeserialize(stream, stream.readInt32(exception), exception)); + } + magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + count = stream.readInt32(exception); + for (int i = 0; i < count; ++i) { + users.add(User.TLdeserialize(stream, stream.readInt32(exception), exception)); + } + } + + @Override + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(0x1cb5c415); + int count = quick_replies.size(); + stream.writeInt32(count); + for (int i = 0; i < count; ++i) { + quick_replies.get(i).serializeToStream(stream); + } + stream.writeInt32(0x1cb5c415); + count = messages.size(); + stream.writeInt32(count); + for (int i = 0; i < count; ++i) { + messages.get(i).serializeToStream(stream); + } + stream.writeInt32(0x1cb5c415); + count = chats.size(); + stream.writeInt32(count); + for (int i = 0; i < count; ++i) { + chats.get(i).serializeToStream(stream); + } + stream.writeInt32(0x1cb5c415); + count = users.size(); + stream.writeInt32(count); + for (int i = 0; i < count; ++i) { + users.get(i).serializeToStream(stream); + } + } + } + + public static class TL_messages_getQuickReplies extends TLObject { + public static final int constructor = 0xd483f2a8; + + public long hash; + + @Override + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return messages_quickReplies.TLdeserialize(stream, constructor, exception); + } + + @Override + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt64(hash); + } + } + + public static class TL_messages_reorderQuickReplies extends TLObject { + public static final int constructor = 0x60331907; + + public ArrayList order = new ArrayList<>(); + + @Override + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return Bool.TLdeserialize(stream, constructor, exception); + } + + @Override + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(0x1cb5c415); + int count = order.size(); + stream.writeInt32(count); + for (int i = 0; i < count; ++i) { + stream.writeInt32(order.get(i)); + } + } + } + + public static class TL_messages_checkQuickReplyShortcut extends TLObject { + public static final int constructor = 0xf1d0fbd3; + + public String shortcut; + + @Override + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return Bool.TLdeserialize(stream, constructor, exception); + } + + @Override + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeString(shortcut); + } + } + + public static class TL_messages_editQuickReplyShortcut extends TLObject { + public static final int constructor = 0x5c003cef; + + public int shortcut_id; + public String shortcut; + + @Override + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return Bool.TLdeserialize(stream, constructor, exception); + } + + @Override + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(shortcut_id); + stream.writeString(shortcut); + } + } + + public static class TL_messages_getQuickReplyMessages extends TLObject { + public static final int constructor = 0x94a495c3; + + public int flags; + public int shortcut_id; + public ArrayList id = new ArrayList<>(); + public long hash; + + @Override + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return messages_Messages.TLdeserialize(stream, constructor, exception); + } + + @Override + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(flags); + stream.writeInt32(shortcut_id); + if ((flags & 1) != 0) { + stream.writeInt32(0x1cb5c415); + int count = id.size(); + stream.writeInt32(count); + for (int i = 0; i < count; ++i) { + stream.writeInt32(id.get(i)); + } + } + stream.writeInt64(hash); + } + } + + public static class TL_messages_sendQuickReplyMessages extends TLObject { + public static final int constructor = 0x33153ad4; + + public InputPeer peer; + public int shortcut_id; + + @Override + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return Updates.TLdeserialize(stream, constructor, exception); + } + + @Override + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + peer.serializeToStream(stream); + stream.writeInt32(shortcut_id); + } + } + + public static class TL_messages_deleteQuickReplyMessages extends TLObject { + public static final int constructor = 0xe105e910; + + public int shortcut_id; + public ArrayList id = new ArrayList<>(); + + @Override + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return Updates.TLdeserialize(stream, constructor, exception); + } + + @Override + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(shortcut_id); + stream.writeInt32(0x1cb5c415); + int count = id.size(); + stream.writeInt32(count); + for (int i = 0; i < count; ++i) { + stream.writeInt32(id.get(i)); + } + } + } + + public static class TL_messages_deleteQuickReplyShortcut extends TLObject { + public static final int constructor = 0x3cc04740; + + public int shortcut_id; + + @Override + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return Updates.TLdeserialize(stream, constructor, exception); + } + + @Override + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(shortcut_id); + } + } + + public static class BusinessAwayMessageSchedule extends TLObject { + public static BusinessAwayMessageSchedule TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + BusinessAwayMessageSchedule result = null; + switch (constructor) { + case TL_businessAwayMessageScheduleAlways.constructor: + result = new TL_businessAwayMessageScheduleAlways(); + break; + case TL_businessAwayMessageScheduleOutsideWorkHours.constructor: + result = new TL_businessAwayMessageScheduleOutsideWorkHours(); + break; + case TL_businessAwayMessageScheduleCustom.constructor: + result = new TL_businessAwayMessageScheduleCustom(); + break; + } + if (result == null && exception) { + throw new RuntimeException(String.format("can't parse magic %x in BusinessAwayMessageSchedule", constructor)); + } + if (result != null) { + result.readParams(stream, exception); + } + return result; + } + } + + public static class TL_businessAwayMessageScheduleAlways extends BusinessAwayMessageSchedule { + public static final int constructor = 0xc9b9e2b9; + + @Override + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } + + public static class TL_businessAwayMessageScheduleOutsideWorkHours extends BusinessAwayMessageSchedule { + public static final int constructor = 0xc3f2f501; + + @Override + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } + + public static class TL_businessAwayMessageScheduleCustom extends BusinessAwayMessageSchedule { + public static final int constructor = 0xcc4d9ecc; + + public int start_date; + public int end_date; + + @Override + public void readParams(AbstractSerializedData stream, boolean exception) { + start_date = stream.readInt32(exception); + end_date = stream.readInt32(exception); + } + + @Override + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(start_date); + stream.writeInt32(end_date); + } + } + + public static class TL_inputBusinessGreetingMessage extends TLObject { + public static final int constructor = 0x194cb3b; + + public int shortcut_id; + public TL_inputBusinessRecipients recipients; + public int no_activity_days; + + @Override + public void readParams(AbstractSerializedData stream, boolean exception) { + shortcut_id = stream.readInt32(exception); + recipients = TL_inputBusinessRecipients.TLdeserialize(stream, stream.readInt32(exception), exception); + no_activity_days = stream.readInt32(exception); + } + + @Override + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(shortcut_id); + recipients.serializeToStream(stream); + stream.writeInt32(no_activity_days); + } + } + + + public static class TL_businessGreetingMessage extends TLObject { + public static final int constructor = 0xe519abab; + + public int shortcut_id; + public TL_businessRecipients recipients; + public int no_activity_days; + + public static TL_businessGreetingMessage TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + if (constructor != TL_businessGreetingMessage.constructor) { + if (exception) { + throw new RuntimeException(String.format("can't parse magic %x in TL_businessGreetingMessage", constructor)); + } + return null; + } + TL_businessGreetingMessage result = new TL_businessGreetingMessage(); + result.readParams(stream, exception); + return result; + } + + @Override + public void readParams(AbstractSerializedData stream, boolean exception) { + shortcut_id = stream.readInt32(exception); + recipients = TL_businessRecipients.TLdeserialize(stream, stream.readInt32(exception), exception); + no_activity_days = stream.readInt32(exception); + } + + @Override + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(shortcut_id); + recipients.serializeToStream(stream); + stream.writeInt32(no_activity_days); + } + } + + public static class TL_inputBusinessAwayMessage extends TLObject { + public static final int constructor = 0x832175e0; + + public int flags; + public boolean offline_only; + public int shortcut_id; + public BusinessAwayMessageSchedule schedule; + public TL_inputBusinessRecipients recipients; + + @Override + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + offline_only = (flags & 1) != 0; + shortcut_id = stream.readInt32(exception); + schedule = BusinessAwayMessageSchedule.TLdeserialize(stream, stream.readInt32(exception), exception); + recipients = TL_inputBusinessRecipients.TLdeserialize(stream, stream.readInt32(exception), exception); + } + + @Override + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + flags = offline_only ? (flags | 1) : (flags & 1); + stream.writeInt32(flags); + stream.writeInt32(shortcut_id); + schedule.serializeToStream(stream); + recipients.serializeToStream(stream); + } + } + + public static class TL_businessAwayMessage extends TLObject { + public static final int constructor = 0xef156a5c; + + public int flags; + public boolean offline_only; + public int shortcut_id; + public BusinessAwayMessageSchedule schedule; + public TL_businessRecipients recipients; + + public static TL_businessAwayMessage TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + if (constructor != TL_businessAwayMessage.constructor) { + if (exception) { + throw new RuntimeException(String.format("can't parse magic %x in TL_businessAwayMessage", constructor)); + } + return null; + } + TL_businessAwayMessage result = new TL_businessAwayMessage(); + result.readParams(stream, exception); + return result; + } + + @Override + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + offline_only = (flags & 1) != 0; + shortcut_id = stream.readInt32(exception); + schedule = BusinessAwayMessageSchedule.TLdeserialize(stream, stream.readInt32(exception), exception); + recipients = TL_businessRecipients.TLdeserialize(stream, stream.readInt32(exception), exception); + } + + @Override + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + flags = offline_only ? (flags | 1) : (flags &~ 1); + stream.writeInt32(flags); + stream.writeInt32(shortcut_id); + schedule.serializeToStream(stream); + recipients.serializeToStream(stream); + } + } + + public static class TL_account_updateBusinessAwayMessage extends TLObject { + public static final int constructor = 0xa26a7fa5; + + public int flags; + public TL_inputBusinessAwayMessage message; + + @Override + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return Bool.TLdeserialize(stream, constructor, exception); + } + + @Override + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(flags); + if ((flags & 1) != 0) { + message.serializeToStream(stream); + } + } + } + + public static class TL_account_updateBusinessGreetingMessage extends TLObject { + public static final int constructor = 0x66cdafc4; + + public int flags; + public TL_inputBusinessGreetingMessage message; + + @Override + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return Bool.TLdeserialize(stream, constructor, exception); + } + + @Override + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(flags); + if ((flags & 1) != 0) { + message.serializeToStream(stream); + } + } + } + + public static class TL_inputBusinessRecipients extends TLObject { + public static final int constructor = 0x6f8b32aa; + + public int flags; + public boolean existing_chats; + public boolean new_chats; + public boolean contacts; + public boolean non_contacts; + public boolean exclude_selected; + public ArrayList users = new ArrayList<>(); + + public static TL_inputBusinessRecipients TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + if (constructor != TL_inputBusinessRecipients.constructor) { + if (exception) { + throw new RuntimeException(String.format("can't parse magic %x in TL_inputBusinessRecipients", constructor)); + } + return null; + } + TL_inputBusinessRecipients result = new TL_inputBusinessRecipients(); + result.readParams(stream, exception); + return result; + } + + @Override + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + existing_chats = (flags & 1) != 0; + new_chats = (flags & 2) != 0; + contacts = (flags & 4) != 0; + non_contacts = (flags & 8) != 0; + exclude_selected = (flags & 32) != 0; + if ((flags & 16) != 0) { + int magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + int count = stream.readInt32(exception); + for (int i = 0; i < count; ++i) { + users.add(InputUser.TLdeserialize(stream, stream.readInt32(exception), exception)); + } + } + } + + @Override + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + flags = existing_chats ? (flags | 1) : (flags &~ 1); + flags = new_chats ? (flags | 2) : (flags &~ 2); + flags = contacts ? (flags | 4) : (flags &~ 4); + flags = non_contacts ? (flags | 8) : (flags &~ 8); + flags = exclude_selected ? (flags | 32) : (flags &~ 32); + stream.writeInt32(flags); + if ((flags & 16) != 0) { + stream.writeInt32(0x1cb5c415); + final int count = users.size(); + stream.writeInt32(count); + for (int i = 0; i < count; ++i) { + users.get(i).serializeToStream(stream); + } + } + } + } + + public static class TL_businessRecipients extends TLObject { + public static final int constructor = 0x21108ff7; + + public int flags; + public boolean existing_chats; + public boolean new_chats; + public boolean contacts; + public boolean non_contacts; + public boolean exclude_selected; + public ArrayList users = new ArrayList<>(); + + public static TL_businessRecipients TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + if (constructor != TL_businessRecipients.constructor) { + if (exception) { + throw new RuntimeException(String.format("can't parse magic %x in TL_businessRecipients", constructor)); + } + return null; + } + TL_businessRecipients result = new TL_businessRecipients(); + result.readParams(stream, exception); + return result; + } + + @Override + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + existing_chats = (flags & 1) != 0; + new_chats = (flags & 2) != 0; + contacts = (flags & 4) != 0; + non_contacts = (flags & 8) != 0; + exclude_selected = (flags & 32) != 0; + if ((flags & 16) != 0) { + int magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + int count = stream.readInt32(exception); + for (int i = 0; i < count; ++i) { + users.add(stream.readInt64(exception)); + } + } + } + + @Override + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + flags = existing_chats ? (flags | 1) : (flags &~ 1); + flags = new_chats ? (flags | 2) : (flags &~ 2); + flags = contacts ? (flags | 4) : (flags &~ 4); + flags = non_contacts ? (flags | 8) : (flags &~ 8); + flags = exclude_selected ? (flags | 32) : (flags &~ 32); + stream.writeInt32(flags); + if ((flags & 16) != 0) { + stream.writeInt32(0x1cb5c415); + final int count = users.size(); + stream.writeInt32(count); + for (int i = 0; i < count; ++i) { + stream.writeInt64(users.get(i)); + } + } + } + } + + public static class TL_connectedBot extends TLObject { + public static int constructor = 0xe7e999e7; + + public int flags; + public boolean can_reply; + public long bot_id; + public TL_businessRecipients recipients; + + public static TL_connectedBot TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + if (constructor != TL_connectedBot.constructor) { + if (exception) { + throw new RuntimeException(String.format("can't parse magic %x in TL_connectedBot", constructor)); + } + return null; + } + TL_connectedBot result = new TL_connectedBot(); + result.readParams(stream, exception); + return result; + } + + @Override + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + can_reply = (flags & 1) != 0; + bot_id = stream.readInt64(exception); + recipients = TL_businessRecipients.TLdeserialize(stream, stream.readInt32(exception), exception); + } + + @Override + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + flags = can_reply ? (flags | 1) : (flags &~ 1); + stream.writeInt32(flags); + stream.writeInt64(bot_id); + recipients.serializeToStream(stream); + } + } + + public static class TL_account_connectedBots extends TLObject { + public static int constructor = 0x17d7f87b; + + public ArrayList connected_bots = new ArrayList<>(); + public ArrayList users = new ArrayList<>(); + + public static TL_account_connectedBots TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + if (constructor != TL_account_connectedBots.constructor) { + if (exception) { + throw new RuntimeException(String.format("can't parse magic %x in TL_account_connectedBots", constructor)); + } + return null; + } + TL_account_connectedBots result = new TL_account_connectedBots(); + result.readParams(stream, exception); + return result; + } + + @Override + public void readParams(AbstractSerializedData stream, boolean exception) { + int magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + int count = stream.readInt32(exception); + for (int i = 0; i < count; ++i) { + connected_bots.add(TL_connectedBot.TLdeserialize(stream, stream.readInt32(exception), exception)); + } + magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + count = stream.readInt32(exception); + for (int i = 0; i < count; ++i) { + users.add(User.TLdeserialize(stream, stream.readInt32(exception), exception)); + } + } + + @Override + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(0x1cb5c415); + int count = connected_bots.size(); + stream.writeInt32(count); + for (int i = 0; i < connected_bots.size(); ++i) { + connected_bots.get(i).serializeToStream(stream); + } + stream.writeInt32(0x1cb5c415); + count = users.size(); + stream.writeInt32(count); + for (int i = 0; i < users.size(); ++i) { + users.get(i).serializeToStream(stream); + } + } + } + + public static class TL_account_updateConnectedBot extends TLObject { + public static int constructor = 0x9c2d527d; + + public int flags; + public boolean can_reply; + public boolean deleted; + public InputUser bot; + public TL_inputBusinessRecipients recipients; + + @Override + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return Updates.TLdeserialize(stream, constructor, exception); + } + + @Override + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + flags = can_reply ? (flags | 1) : (flags &~ 1); + flags = deleted ? (flags | 2) : (flags &~ 2); + stream.writeInt32(flags); + bot.serializeToStream(stream); + recipients.serializeToStream(stream); + } + } + + public static class TL_account_getConnectedBots extends TLObject { + public static int constructor = 0x4ea4c80f; + + @Override + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return TL_account_connectedBots.TLdeserialize(stream, constructor, exception); + } + + @Override + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } + + public static class TL_messages_toggleDialogFilterTags extends TLObject { + public static final int constructor = 0xfd2dda49; + + public boolean enabled; + + @Override + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return Bool.TLdeserialize(stream, constructor, exception); + } + + @Override + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeBool(enabled); + } + } + public static class Vector extends TLObject { public static final int constructor = 0x1cb5c415; public ArrayList objects = new ArrayList<>(); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBar.java b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBar.java index 17585224cd9..fc86dea16e2 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBar.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBar.java @@ -91,7 +91,7 @@ public boolean canOpenMenu() { private String actionModeTag; private boolean ignoreLayoutRequest; protected boolean occupyStatusBar = Build.VERSION.SDK_INT >= 21; - private boolean actionModeVisible; + protected boolean actionModeVisible; private boolean addToContainer = true; private boolean clipContent; private boolean interceptTouches = true; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBarLayout.java b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBarLayout.java index a02dc2de3e6..7ca6957e93e 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBarLayout.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBarLayout.java @@ -222,7 +222,7 @@ protected void onLayout(boolean changed, int l, int t, int r, int b) { @Override public boolean dispatchTouchEvent(MotionEvent ev) { - processMenuButtonsTouch(ev); +// processMenuButtonsTouch(ev); boolean passivePreview = inPreviewMode && previewMenu == null; if ((passivePreview || transitionAnimationPreviewMode) && (ev.getActionMasked() == MotionEvent.ACTION_DOWN || ev.getActionMasked() == MotionEvent.ACTION_POINTER_DOWN)) { return false; 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 a0ea224680b..78ea5346604 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBarMenuSubItem.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBarMenuSubItem.java @@ -1,5 +1,7 @@ package org.telegram.ui.ActionBar; +import static org.telegram.messenger.AndroidUtilities.dp; + import android.content.Context; import android.graphics.PorterDuff; import android.graphics.PorterDuffColorFilter; @@ -68,7 +70,7 @@ public ActionBarMenuSubItem(Context context, int needCheck, boolean top, boolean selectorColor = getThemedColor(Theme.key_dialogButtonSelector); updateBackground(); - setPadding(AndroidUtilities.dp(18), 0, AndroidUtilities.dp(18), 0); + setPadding(dp(18), 0, dp(18), 0); imageView = new RLottieImageView(context); imageView.setScaleType(ImageView.ScaleType.CENTER); @@ -93,16 +95,16 @@ public ActionBarMenuSubItem(Context context, int needCheck, boolean top, boolean addView(checkView, LayoutHelper.createFrame(26, LayoutHelper.MATCH_PARENT, Gravity.CENTER_VERTICAL | (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT))); } else { addView(checkView, LayoutHelper.createFrame(26, LayoutHelper.MATCH_PARENT, Gravity.CENTER_VERTICAL | (LocaleController.isRTL ? Gravity.LEFT : Gravity.RIGHT))); - textView.setPadding(LocaleController.isRTL ? AndroidUtilities.dp(34) : 0, 0, LocaleController.isRTL ? 0 : AndroidUtilities.dp(34), 0); + textView.setPadding(LocaleController.isRTL ? dp(34) : 0, 0, LocaleController.isRTL ? 0 : dp(34), 0); } } } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - super.onMeasure(widthMeasureSpec, View.MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(itemHeight), View.MeasureSpec.EXACTLY)); + super.onMeasure(widthMeasureSpec, View.MeasureSpec.makeMeasureSpec(dp(itemHeight), View.MeasureSpec.EXACTLY)); if (expandIfMultiline && textView.getLayout().getLineCount() > 1) { - super.onMeasure(widthMeasureSpec, View.MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(itemHeight + 8), View.MeasureSpec.EXACTLY)); + super.onMeasure(widthMeasureSpec, View.MeasureSpec.makeMeasureSpec(dp(itemHeight + 8), View.MeasureSpec.EXACTLY)); } } @@ -144,12 +146,12 @@ public void setRightIcon(int icon) { } FrameLayout.LayoutParams layoutParams = (FrameLayout.LayoutParams) textView.getLayoutParams(); if (LocaleController.isRTL) { - layoutParams.leftMargin = rightIcon != null ? AndroidUtilities.dp(32) : 0; + layoutParams.leftMargin = rightIcon != null ? dp(32) : 0; } else { - layoutParams.rightMargin = rightIcon != null ? AndroidUtilities.dp(32) : 0; + layoutParams.rightMargin = rightIcon != null ? dp(32) : 0; } textView.setLayoutParams(layoutParams); - setPadding(AndroidUtilities.dp(LocaleController.isRTL ? 8 : 18), 0, AndroidUtilities.dp(LocaleController.isRTL ? 18 : 8), 0); + setPadding(dp(LocaleController.isRTL ? 8 : 18), 0, dp(LocaleController.isRTL ? 18 : 8), 0); rightIcon.setImageResource(icon); } @@ -183,7 +185,7 @@ public void setTextAndIcon(CharSequence text, int icon, Drawable iconDrawable) { imageView.setImageResource(icon); } imageView.setVisibility(VISIBLE); - textView.setPadding(LocaleController.isRTL ? 0 : AndroidUtilities.dp(43), 0, LocaleController.isRTL ? AndroidUtilities.dp(43) : 0, 0); + textView.setPadding(LocaleController.isRTL ? (checkView != null ? dp(34) : 0) : dp(43), 0, LocaleController.isRTL ? dp(43) : (checkView != null ? dp(34) : 0), 0); } else { imageView.setVisibility(INVISIBLE); textView.setPadding(0, 0, 0, 0); @@ -244,7 +246,7 @@ public void setSubtext(String text) { subtextView.setTextColor(getThemedColor(Theme.key_groupcreate_sectionText)); subtextView.setVisibility(GONE); subtextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 13); - subtextView.setPadding(LocaleController.isRTL ? 0 : AndroidUtilities.dp(43), 0, LocaleController.isRTL ? AndroidUtilities.dp(43) : 0, 0); + subtextView.setPadding(LocaleController.isRTL ? 0 : dp(43), 0, LocaleController.isRTL ? dp(43) : 0, 0); addView(subtextView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.CENTER_VERTICAL, 0, 10, 0, 0)); } boolean visible = !TextUtils.isEmpty(text); @@ -252,7 +254,7 @@ public void setSubtext(String text) { if (visible != oldVisible) { subtextView.setVisibility(visible ? VISIBLE : GONE); FrameLayout.LayoutParams layoutParams = (FrameLayout.LayoutParams) textView.getLayoutParams(); - layoutParams.bottomMargin = visible ? AndroidUtilities.dp(10) : 0; + layoutParams.bottomMargin = visible ? dp(10) : 0; textView.setLayoutParams(layoutParams); } subtextView.setText(text); 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 0592861fc12..c31bc97eac4 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/AlertDialog.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/AlertDialog.java @@ -65,6 +65,7 @@ import org.telegram.messenger.NotificationCenter; import org.telegram.messenger.R; import org.telegram.messenger.SharedConfig; +import org.telegram.messenger.Utilities; import org.telegram.ui.Components.AnimatedEmojiDrawable; import org.telegram.ui.Components.AnimatedFloat; import org.telegram.ui.Components.EffectsTextView; @@ -116,6 +117,7 @@ public class AlertDialog extends Dialog implements Drawable.Callback, Notificati private OnClickListener onClickListener; private OnDismissListener onDismissListener; + private Utilities.Callback overridenDissmissListener; private CharSequence[] items; private int[] itemIcons; @@ -1324,6 +1326,12 @@ public void dismissUnless(long minDuration) { @Override public void dismiss() { + if (overridenDissmissListener != null) { + Utilities.Callback listener = overridenDissmissListener; + overridenDissmissListener = null; + listener.run(this::dismiss); + return; + } NotificationCenter.getGlobalInstance().removeObserver(this, NotificationCenter.emojiLoaded); if (onDismissListener != null) { onDismissListener.onDismiss(this); @@ -1719,6 +1727,11 @@ public Builder setOnPreDismissListener(OnDismissListener onDismissListener) { return this; } + public Builder overrideDismissListener(Utilities.Callback overridenDissmissListener) { + alertDialog.overridenDissmissListener = overridenDissmissListener; + return this; + } + public Builder setBlurredBackground(boolean b) { alertDialog.blurredBackground = b; return this; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/BaseFragment.java b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/BaseFragment.java index 8888ee3b4f9..8474f5acf19 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/BaseFragment.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/BaseFragment.java @@ -62,7 +62,7 @@ public abstract class BaseFragment { - private boolean isFinished; + protected boolean isFinished; protected boolean finishing; protected Dialog visibleDialog; protected int currentAccount = UserConfig.selectedAccount; 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 9e3105c1f5f..8a4b06a9be7 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/BottomSheet.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/BottomSheet.java @@ -888,6 +888,7 @@ public static class BottomSheetCell extends FrameLayout { private final Theme.ResourcesProvider resourcesProvider; private TextView textView; private ImageView imageView; + private ImageView imageView2; int currentType; public BottomSheetCell(Context context, int type) { @@ -909,6 +910,11 @@ public BottomSheetCell(Context context, int type, Theme.ResourcesProvider resour imageView.setColorFilter(new PorterDuffColorFilter(getThemedColor(Theme.key_dialogIcon), PorterDuff.Mode.MULTIPLY)); addView(imageView, LayoutHelper.createFrame(56, 48, Gravity.CENTER_VERTICAL | (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT))); + imageView2 = new ImageView(context); + imageView2.setScaleType(ImageView.ScaleType.CENTER); + imageView2.setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_radioBackgroundChecked, resourcesProvider), PorterDuff.Mode.SRC_IN)); + addView(imageView2, LayoutHelper.createFrame(56, 48, Gravity.CENTER_VERTICAL | (LocaleController.isRTL ? Gravity.LEFT : Gravity.RIGHT))); + textView = new TextView(context); textView.setLines(1); textView.setSingleLine(true); @@ -985,6 +991,15 @@ public void setTextAndIcon(CharSequence text, int icon, Drawable drawable, boole } } + private boolean checked; + public void setChecked(boolean checked) { + imageView2.setImageResource((this.checked = checked) ? R.drawable.checkbig : 0); + } + + public boolean isChecked() { + return checked; + } + public TextView getTextView() { return textView; } 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 960e7915bb7..1d1925651ee 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/Theme.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/Theme.java @@ -389,7 +389,7 @@ public void setTop(int top, int backgroundWidth, int backgroundHeight, int heigh if (currentType != TYPE_PREVIEW) { motionBackground[num].setPostInvalidateParent(true); } - motionBackground[num].setRoundRadius(AndroidUtilities.dp(1)); + motionBackground[num].setRoundRadius(dp(1)); } motionBackground[num].setColors(color, gradientColor1, gradientColor2, gradientColor3, crosfadeFromBitmap); crosfadeFromBitmapShader.setLocalMatrix(matrix); @@ -409,7 +409,7 @@ public void setTop(int top, int backgroundWidth, int backgroundHeight, int heigh if (currentType != TYPE_PREVIEW) { motionBackground[num].setPostInvalidateParent(true); } - motionBackground[num].setRoundRadius(AndroidUtilities.dp(1)); + motionBackground[num].setRoundRadius(dp(1)); } motionBackground[num].setColors(color, gradientColor1, gradientColor2, gradientColor3); gradientShader = motionBackground[num].getBitmapShader(); @@ -483,7 +483,7 @@ public Drawable getBackgroundDrawable() { } else if (overrideRounding > 0) { newRad = 0; } else { - newRad = AndroidUtilities.dp(SharedConfig.bubbleRadius); + newRad = dp(SharedConfig.bubbleRadius); } int idx; if (isTopNear && isBottomNear) { @@ -606,7 +606,7 @@ public Drawable getShadowDrawable() { if (gradientShader == null && !isSelected && crossfadeFromDrawable == null) { return null; } - int newRad = AndroidUtilities.dp(SharedConfig.bubbleRadius); + int newRad = dp(SharedConfig.bubbleRadius); int idx; if (isTopNear && isBottomNear) { idx = 3; @@ -2863,7 +2863,7 @@ public int getAccentColor(int id) { public boolean createBackground(File file, String toPath) { try { - Bitmap bitmap = AndroidUtilities.getScaledBitmap(AndroidUtilities.dp(640), AndroidUtilities.dp(360), file.getAbsolutePath(), null, 0); + Bitmap bitmap = AndroidUtilities.getScaledBitmap(dp(640), dp(360), file.getAbsolutePath(), null, 0); if (bitmap != null && patternBgColor != 0) { Bitmap finalBitmap = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), bitmap.getConfig()); Canvas canvas = new Canvas(finalBitmap); @@ -3105,7 +3105,7 @@ public void run() { public static Paint avatar_backgroundPaint; public static Drawable listSelector; - public static Drawable[] avatarDrawables = new Drawable[20]; + public static Drawable[] avatarDrawables = new Drawable[22]; public static Drawable moveUpDrawable; @@ -3117,6 +3117,7 @@ public void run() { public static Paint dialogs_countGrayPaint; public static Paint dialogs_actionMessagePaint; public static Paint dialogs_reactionsCountPaint; + public static Paint dialogs_tagPaint; public static TextPaint[] dialogs_namePaint; public static TextPaint[] dialogs_nameEncryptedPaint; public static TextPaint dialogs_searchNamePaint; @@ -3130,6 +3131,7 @@ public void run() { public static TextPaint dialogs_archiveTextPaintSmall; public static TextPaint dialogs_onlinePaint; public static TextPaint dialogs_offlinePaint; + public static TextPaint dialogs_tagTextPaint; public static Drawable dialogs_checkDrawable; public static Drawable dialogs_playDrawable; public static Drawable dialogs_checkReadDrawable; @@ -3505,6 +3507,7 @@ public void run() { public static final int key_avatar_background2Cyan = colorsCount++; public static final int key_avatar_background2Blue = colorsCount++; public static final int key_avatar_background2Pink = colorsCount++; + public static final int key_avatar_backgroundGray = colorsCount++; public static final int key_avatar_backgroundInProfileBlue = colorsCount++; public static final int key_avatar_backgroundActionBarBlue = colorsCount++; @@ -5142,8 +5145,8 @@ public static Drawable getCurrentHolidayDrawable() { if (dialogs_holidayDrawable == null) { if (monthOfYear == 11 && dayOfMonth >= (BuildVars.DEBUG_PRIVATE_VERSION ? 29 : 31) && dayOfMonth <= 31 || monthOfYear == 0 && dayOfMonth == 1) { dialogs_holidayDrawable = ApplicationLoader.applicationContext.getResources().getDrawable(R.drawable.newyear); - dialogs_holidayDrawableOffsetX = -AndroidUtilities.dp(3); - dialogs_holidayDrawableOffsetY = -AndroidUtilities.dp(-7); + dialogs_holidayDrawableOffsetX = -dp(3); + dialogs_holidayDrawableOffsetY = -dp(-7); } } } @@ -5226,7 +5229,7 @@ public static CombinedDrawable createCircleDrawableWithIcon(int size, Drawable d paint.setColor(0xffffffff); if (stroke == 1) { paint.setStyle(Paint.Style.STROKE); - paint.setStrokeWidth(AndroidUtilities.dp(2)); + paint.setStrokeWidth(dp(2)); } else if (stroke == 2) { paint.setAlpha(0); } @@ -5386,7 +5389,7 @@ public static Drawable createSelectorDrawableFromDrawables(Drawable normal, Draw } public static Drawable getRoundRectSelectorDrawable(int color) { - return getRoundRectSelectorDrawable(AndroidUtilities.dp(3), color); + return getRoundRectSelectorDrawable(dp(3), color); } public static Drawable getRoundRectSelectorDrawable(int corners, int color) { @@ -5500,12 +5503,12 @@ public void draw(Canvas canvas) { rect = new RectF(); } rect.set(bounds); - float rad = radius <= 0 ? AndroidUtilities.dp(6) : radius; + float rad = radius <= 0 ? dp(6) : radius; canvas.drawRoundRect(rect, rad, rad, maskPaint); } else { int rad; if (maskType == RIPPLE_MASK_CIRCLE_20DP || maskType == 6) { - rad = radius <= 0 ? AndroidUtilities.dp(20) : radius; + rad = radius <= 0 ? dp(20) : radius; } else if (maskType == RIPPLE_MASK_CIRCLE_TO_BOUND_EDGE) { rad = (Math.max(bounds.width(), bounds.height()) / 2); } else { @@ -5542,7 +5545,7 @@ public int getOpacity() { RippleDrawable rippleDrawable = new RippleDrawable(colorStateList, null, maskDrawable); if (Build.VERSION.SDK_INT >= 23) { if (maskType == RIPPLE_MASK_CIRCLE_20DP) { - rippleDrawable.setRadius(radius <= 0 ? AndroidUtilities.dp(20) : radius); + rippleDrawable.setRadius(radius <= 0 ? dp(20) : radius); } else if (maskType == RIPPLE_MASK_CIRCLE_AUTO) { rippleDrawable.setRadius(RippleDrawable.RADIUS_AUTO); } @@ -5842,7 +5845,7 @@ public void draw(@NonNull Canvas canvas) { } else if (Math.abs(radius - RADIUS_OUT_BOUNDS) < 0.01f) { rad = (int) Math.ceil(Math.sqrt((bounds.left - bounds.centerX()) * (bounds.left - bounds.centerX()) + (bounds.top - bounds.centerY()) * (bounds.top - bounds.centerY()))); } else { - rad = AndroidUtilities.dp(radius); + rad = dp(radius); } canvas.drawCircle(bounds.centerX(), bounds.centerY(), rad, paint); } @@ -5905,27 +5908,27 @@ public static class RippleRadMaskDrawable extends Drawable { boolean invalidatePath = true; public RippleRadMaskDrawable(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); + radii[0] = radii[1] = radii[2] = radii[3] = dp(top); + radii[4] = radii[5] = radii[6] = radii[7] = dp(bottom); } public RippleRadMaskDrawable(float topLeft, float topRight, float bottomRight, float bottomLeft) { - radii[0] = radii[1] = AndroidUtilities.dp(topLeft); - radii[2] = radii[3] = AndroidUtilities.dp(topRight); - radii[4] = radii[5] = AndroidUtilities.dp(bottomRight); - radii[6] = radii[7] = AndroidUtilities.dp(bottomLeft); + radii[0] = radii[1] = dp(topLeft); + radii[2] = radii[3] = dp(topRight); + radii[4] = radii[5] = dp(bottomRight); + radii[6] = radii[7] = dp(bottomLeft); } 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); + radii[0] = radii[1] = radii[2] = radii[3] = dp(top); + radii[4] = radii[5] = radii[6] = radii[7] = dp(bottom); invalidatePath = true; invalidateSelf(); } public void setRadius(float topLeft, float topRight, float bottomRight, float bottomLeft) { - radii[0] = radii[1] = AndroidUtilities.dp(topLeft); - radii[2] = radii[3] = AndroidUtilities.dp(topRight); - radii[4] = radii[5] = AndroidUtilities.dp(bottomRight); - radii[6] = radii[7] = AndroidUtilities.dp(bottomLeft); + radii[0] = radii[1] = dp(topLeft); + radii[2] = radii[3] = dp(topRight); + radii[4] = radii[5] = dp(bottomRight); + radii[6] = radii[7] = dp(bottomLeft); invalidatePath = true; invalidateSelf(); } @@ -8118,7 +8121,7 @@ public static void createCommonResources(Context context) { checkboxSquare_checkPaint = new Paint(Paint.ANTI_ALIAS_FLAG); checkboxSquare_checkPaint.setStyle(Paint.Style.STROKE); - checkboxSquare_checkPaint.setStrokeWidth(AndroidUtilities.dp(2)); + checkboxSquare_checkPaint.setStrokeWidth(dp(2)); checkboxSquare_checkPaint.setStrokeCap(Paint.Cap.ROUND); checkboxSquare_eraserPaint = new Paint(Paint.ANTI_ALIAS_FLAG); checkboxSquare_eraserPaint.setColor(0); @@ -8150,6 +8153,8 @@ public static void createCommonResources(Context context) { avatarDrawables[17] = resources.getDrawable(R.drawable.large_repost_story); avatarDrawables[18] = resources.getDrawable(R.drawable.large_hidden); avatarDrawables[19] = resources.getDrawable(R.drawable.large_notes); + avatarDrawables[20] = resources.getDrawable(R.drawable.filled_folder_new); + avatarDrawables[21] = resources.getDrawable(R.drawable.filled_folder_existing); if (dialogs_archiveAvatarDrawable != null) { dialogs_archiveAvatarDrawable.setCallback(null); @@ -8170,21 +8175,21 @@ public static void createCommonResources(Context context) { if (dialogs_hidePsaDrawable != null) { dialogs_hidePsaDrawable.recycle(false); } - dialogs_archiveAvatarDrawable = new RLottieDrawable(R.raw.chats_archiveavatar, "chats_archiveavatar", AndroidUtilities.dp(36), AndroidUtilities.dp(36), false, null); - dialogs_archiveDrawable = new RLottieDrawable(R.raw.chats_archive, "chats_archive", AndroidUtilities.dp(36), AndroidUtilities.dp(36), false, null); - dialogs_unarchiveDrawable = new RLottieDrawable(R.raw.chats_unarchive, "chats_unarchive", AndroidUtilities.dp(AndroidUtilities.dp(36)), AndroidUtilities.dp(36), false, null); - dialogs_pinArchiveDrawable = new RLottieDrawable(R.raw.chats_hide, "chats_hide", AndroidUtilities.dp(36), AndroidUtilities.dp(36), false, null); - dialogs_unpinArchiveDrawable = new RLottieDrawable(R.raw.chats_unhide, "chats_unhide", AndroidUtilities.dp(36), AndroidUtilities.dp(36), false, null); - dialogs_hidePsaDrawable = new RLottieDrawable(R.raw.chat_audio_record_delete, "chats_psahide", AndroidUtilities.dp(30), AndroidUtilities.dp(30), false, null); + dialogs_archiveAvatarDrawable = new RLottieDrawable(R.raw.chats_archiveavatar, "chats_archiveavatar", dp(36), dp(36), false, null); + dialogs_archiveDrawable = new RLottieDrawable(R.raw.chats_archive, "chats_archive", dp(36), dp(36), false, null); + dialogs_unarchiveDrawable = new RLottieDrawable(R.raw.chats_unarchive, "chats_unarchive", dp(dp(36)), dp(36), false, null); + dialogs_pinArchiveDrawable = new RLottieDrawable(R.raw.chats_hide, "chats_hide", dp(36), dp(36), false, null); + dialogs_unpinArchiveDrawable = new RLottieDrawable(R.raw.chats_unhide, "chats_unhide", dp(36), dp(36), false, null); + dialogs_hidePsaDrawable = new RLottieDrawable(R.raw.chat_audio_record_delete, "chats_psahide", dp(30), dp(30), false, null); - dialogs_swipeMuteDrawable = new RLottieDrawable(R.raw.swipe_mute, "swipe_mute", AndroidUtilities.dp(36), AndroidUtilities.dp(36), false, null); - dialogs_swipeUnmuteDrawable = new RLottieDrawable(R.raw.swipe_unmute, "swipe_unmute", AndroidUtilities.dp(36), AndroidUtilities.dp(36), false, null); + dialogs_swipeMuteDrawable = new RLottieDrawable(R.raw.swipe_mute, "swipe_mute", dp(36), dp(36), false, null); + dialogs_swipeUnmuteDrawable = new RLottieDrawable(R.raw.swipe_unmute, "swipe_unmute", dp(36), dp(36), false, null); - dialogs_swipeReadDrawable = new RLottieDrawable(R.raw.swipe_read, "swipe_read", AndroidUtilities.dp(36), AndroidUtilities.dp(36), false, null); - dialogs_swipeUnreadDrawable = new RLottieDrawable(R.raw.swipe_unread, "swipe_unread", AndroidUtilities.dp(36), AndroidUtilities.dp(36), false, null); - dialogs_swipeDeleteDrawable = new RLottieDrawable(R.raw.swipe_delete, "swipe_delete", AndroidUtilities.dp(36), AndroidUtilities.dp(36), false, null); - dialogs_swipeUnpinDrawable = new RLottieDrawable(R.raw.swipe_unpin, "swipe_unpin", AndroidUtilities.dp(36), AndroidUtilities.dp(36), false, null); - dialogs_swipePinDrawable = new RLottieDrawable(R.raw.swipe_pin, "swipe_pin", AndroidUtilities.dp(36), AndroidUtilities.dp(36), false, null); + dialogs_swipeReadDrawable = new RLottieDrawable(R.raw.swipe_read, "swipe_read", dp(36), dp(36), false, null); + dialogs_swipeUnreadDrawable = new RLottieDrawable(R.raw.swipe_unread, "swipe_unread", dp(36), dp(36), false, null); + dialogs_swipeDeleteDrawable = new RLottieDrawable(R.raw.swipe_delete, "swipe_delete", dp(36), dp(36), false, null); + dialogs_swipeUnpinDrawable = new RLottieDrawable(R.raw.swipe_unpin, "swipe_unpin", dp(36), dp(36), false, null); + dialogs_swipePinDrawable = new RLottieDrawable(R.raw.swipe_pin, "swipe_pin", dp(36), dp(36), false, null); applyCommonTheme(); } @@ -8252,13 +8257,14 @@ public static void applyCommonTheme() { public static void createCommonDialogResources(Context context) { if (dialogs_countTextPaint == null) { dialogs_countTextPaint = new TextPaint(TextPaint.ANTI_ALIAS_FLAG); - dialogs_countTextPaint.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); + dialogs_countTextPaint.setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)); dialogs_countPaint = new Paint(Paint.ANTI_ALIAS_FLAG); dialogs_reactionsCountPaint = new Paint(Paint.ANTI_ALIAS_FLAG); dialogs_onlineCirclePaint = new Paint(Paint.ANTI_ALIAS_FLAG); + dialogs_tagPaint = new Paint(Paint.ANTI_ALIAS_FLAG); } - dialogs_countTextPaint.setTextSize(AndroidUtilities.dp(13)); + dialogs_countTextPaint.setTextSize(dp(13)); } public static void createDialogsResources(Context context) { @@ -8273,25 +8279,27 @@ public static void createDialogsResources(Context context) { dialogs_messagePrintingPaint = new TextPaint[2]; for (int a = 0; a < 2; a++) { dialogs_namePaint[a] = new TextPaint(TextPaint.ANTI_ALIAS_FLAG); - dialogs_namePaint[a].setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); + dialogs_namePaint[a].setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)); dialogs_nameEncryptedPaint[a] = new TextPaint(TextPaint.ANTI_ALIAS_FLAG); - dialogs_nameEncryptedPaint[a].setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); + dialogs_nameEncryptedPaint[a].setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)); dialogs_messagePaint[a] = new TextPaint(TextPaint.ANTI_ALIAS_FLAG); dialogs_messagePrintingPaint[a] = new TextPaint(TextPaint.ANTI_ALIAS_FLAG); } dialogs_searchNamePaint = new TextPaint(TextPaint.ANTI_ALIAS_FLAG); - dialogs_searchNamePaint.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); + dialogs_searchNamePaint.setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)); dialogs_searchNameEncryptedPaint = new TextPaint(TextPaint.ANTI_ALIAS_FLAG); - dialogs_searchNameEncryptedPaint.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); + dialogs_searchNameEncryptedPaint.setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)); dialogs_messageNamePaint = new TextPaint(TextPaint.ANTI_ALIAS_FLAG); - dialogs_messageNamePaint.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); + dialogs_messageNamePaint.setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)); dialogs_timePaint = new TextPaint(TextPaint.ANTI_ALIAS_FLAG); dialogs_archiveTextPaint = new TextPaint(TextPaint.ANTI_ALIAS_FLAG); - dialogs_archiveTextPaint.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); + dialogs_archiveTextPaint.setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)); dialogs_archiveTextPaintSmall = new TextPaint(TextPaint.ANTI_ALIAS_FLAG); - dialogs_archiveTextPaintSmall.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); + dialogs_archiveTextPaintSmall.setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)); dialogs_onlinePaint = new TextPaint(TextPaint.ANTI_ALIAS_FLAG); dialogs_offlinePaint = new TextPaint(TextPaint.ANTI_ALIAS_FLAG); + dialogs_tagTextPaint = new TextPaint(TextPaint.ANTI_ALIAS_FLAG); + dialogs_tagTextPaint.setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)); dialogs_tabletSeletedPaint = new Paint(); dialogs_pinnedPaint = new Paint(Paint.ANTI_ALIAS_FLAG); @@ -8323,33 +8331,34 @@ public static void createDialogsResources(Context context) { RectF rect = new RectF(); chat_updatePath[0] = new Path(); chat_updatePath[2] = new Path(); - float cx = AndroidUtilities.dp(12); - float cy = AndroidUtilities.dp(12); - rect.set(cx - AndroidUtilities.dp(5), cy - AndroidUtilities.dp(5), cx + AndroidUtilities.dp(5), cy + AndroidUtilities.dp(5)); + float cx = dp(12); + float cy = dp(12); + rect.set(cx - dp(5), cy - dp(5), cx + dp(5), cy + dp(5)); chat_updatePath[2].arcTo(rect, -160, -110, true); chat_updatePath[2].arcTo(rect, 20, -110, true); - chat_updatePath[0].moveTo(cx, cy + AndroidUtilities.dp(5 + 3)); - chat_updatePath[0].lineTo(cx, cy + AndroidUtilities.dp(5 - 3)); - chat_updatePath[0].lineTo(cx + AndroidUtilities.dp(3), cy + AndroidUtilities.dp(5)); + chat_updatePath[0].moveTo(cx, cy + dp(5 + 3)); + chat_updatePath[0].lineTo(cx, cy + dp(5 - 3)); + chat_updatePath[0].lineTo(cx + dp(3), cy + dp(5)); chat_updatePath[0].close(); - chat_updatePath[0].moveTo(cx, cy - AndroidUtilities.dp(5 + 3)); - chat_updatePath[0].lineTo(cx, cy - AndroidUtilities.dp(5 - 3)); - chat_updatePath[0].lineTo(cx - AndroidUtilities.dp(3), cy - AndroidUtilities.dp(5)); + chat_updatePath[0].moveTo(cx, cy - dp(5 + 3)); + chat_updatePath[0].lineTo(cx, cy - dp(5 - 3)); + chat_updatePath[0].lineTo(cx - dp(3), cy - dp(5)); chat_updatePath[0].close(); applyDialogsTheme(); } - dialogs_messageNamePaint.setTextSize(AndroidUtilities.dp(14)); - dialogs_timePaint.setTextSize(AndroidUtilities.dp(13)); - dialogs_archiveTextPaint.setTextSize(AndroidUtilities.dp(13)); - dialogs_archiveTextPaintSmall.setTextSize(AndroidUtilities.dp(11)); - dialogs_onlinePaint.setTextSize(AndroidUtilities.dp(15)); - dialogs_offlinePaint.setTextSize(AndroidUtilities.dp(15)); - dialogs_searchNamePaint.setTextSize(AndroidUtilities.dp(16)); - dialogs_searchNameEncryptedPaint.setTextSize(AndroidUtilities.dp(16)); + dialogs_messageNamePaint.setTextSize(dp(14)); + dialogs_timePaint.setTextSize(dp(13)); + dialogs_archiveTextPaint.setTextSize(dp(13)); + dialogs_archiveTextPaintSmall.setTextSize(dp(11)); + dialogs_onlinePaint.setTextSize(dp(15)); + dialogs_offlinePaint.setTextSize(dp(15)); + dialogs_tagTextPaint.setTextSize(dp(10)); + dialogs_searchNamePaint.setTextSize(dp(16)); + dialogs_searchNameEncryptedPaint.setTextSize(dp(16)); } public static void applyDialogsTheme() { @@ -8455,25 +8464,25 @@ public static void createCommonMessageResources() { final float[] emojiSizePercents = new float[] {.68f, .46f, .34f, .28f, .22f, .19f}; for (int i = 0; i < chat_msgTextPaintEmoji.length; ++i) { chat_msgTextPaintEmoji[i] = new TextPaint(Paint.ANTI_ALIAS_FLAG); - chat_msgTextPaintEmoji[i].setTextSize(AndroidUtilities.dp(emojiSizePercents[i] * 120f)); - } - chat_msgTextPaintOneEmoji.setTextSize(AndroidUtilities.dp(28 + 18)); - chat_msgTextPaintTwoEmoji.setTextSize(AndroidUtilities.dp(24 + 14)); - chat_msgTextPaintThreeEmoji.setTextSize(AndroidUtilities.dp(20 + 10)); - chat_msgTextPaint.setTextSize(AndroidUtilities.dp(SharedConfig.fontSize)); - chat_msgGameTextPaint.setTextSize(AndroidUtilities.dp(14)); - chat_msgBotButtonPaint.setTextSize(AndroidUtilities.dp(15)); + chat_msgTextPaintEmoji[i].setTextSize(dp(emojiSizePercents[i] * 120f)); + } + chat_msgTextPaintOneEmoji.setTextSize(dp(28 + 18)); + chat_msgTextPaintTwoEmoji.setTextSize(dp(24 + 14)); + chat_msgTextPaintThreeEmoji.setTextSize(dp(20 + 10)); + chat_msgTextPaint.setTextSize(dp(SharedConfig.fontSize)); + chat_msgGameTextPaint.setTextSize(dp(14)); + chat_msgBotButtonPaint.setTextSize(dp(15)); float smallerDp = (2 * SharedConfig.fontSize + 10) / 3f; // 6f + SharedConfig.fontSize / 2f; - chat_namePaint.setTextSize(AndroidUtilities.dp(smallerDp)); - chat_replyNamePaint.setTextSize(AndroidUtilities.dp(smallerDp)); - chat_replyTextPaint.setTextSize(AndroidUtilities.dp(smallerDp)); - chat_quoteTextPaint.setTextSize(AndroidUtilities.dp(smallerDp - 1)); - chat_topicTextPaint.setTextSize(AndroidUtilities.dp(smallerDp - 1)); - chat_forwardNamePaint.setTextSize(AndroidUtilities.dp(smallerDp)); - chat_adminPaint.setTextSize(AndroidUtilities.dp(smallerDp - 1)); - chat_msgTextCodePaint.setTextSize(AndroidUtilities.dp(Math.max(Math.min(10, SharedConfig.fontSize - 1), SharedConfig.fontSize - 2))); - chat_msgTextCode2Paint.setTextSize(AndroidUtilities.dp(Math.max(Math.min(10, SharedConfig.fontSize - 2), SharedConfig.fontSize - 3))); - chat_msgTextCode3Paint.setTextSize(AndroidUtilities.dp(Math.max(Math.min(10, SharedConfig.fontSize - 2), SharedConfig.fontSize - 5))); + chat_namePaint.setTextSize(dp(smallerDp)); + chat_replyNamePaint.setTextSize(dp(smallerDp)); + chat_replyTextPaint.setTextSize(dp(smallerDp)); + chat_quoteTextPaint.setTextSize(dp(smallerDp - 1)); + chat_topicTextPaint.setTextSize(dp(smallerDp - 1)); + chat_forwardNamePaint.setTextSize(dp(smallerDp)); + chat_adminPaint.setTextSize(dp(smallerDp - 1)); + chat_msgTextCodePaint.setTextSize(dp(Math.max(Math.min(10, SharedConfig.fontSize - 1), SharedConfig.fontSize - 2))); + chat_msgTextCode2Paint.setTextSize(dp(Math.max(Math.min(10, SharedConfig.fontSize - 2), SharedConfig.fontSize - 3))); + chat_msgTextCode3Paint.setTextSize(dp(Math.max(Math.min(10, SharedConfig.fontSize - 2), SharedConfig.fontSize - 5))); } } @@ -8483,17 +8492,17 @@ public static void createCommonChatResources() { if (chat_infoPaint == null) { chat_infoPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG); chat_infoBoldPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG); - chat_infoBoldPaint.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); + chat_infoBoldPaint.setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)); chat_stickerCommentCountPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG); - chat_stickerCommentCountPaint.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); + chat_stickerCommentCountPaint.setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)); chat_docNamePaint = new TextPaint(Paint.ANTI_ALIAS_FLAG); - chat_docNamePaint.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); + chat_docNamePaint.setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)); chat_docBackPaint = new Paint(Paint.ANTI_ALIAS_FLAG); chat_deleteProgressPaint = new Paint(Paint.ANTI_ALIAS_FLAG); chat_deleteProgressPaint.setStyle(Paint.Style.STROKE); chat_deleteProgressPaint.setStrokeCap(Paint.Cap.ROUND); chat_locationTitlePaint = new TextPaint(Paint.ANTI_ALIAS_FLAG); - chat_locationTitlePaint.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); + chat_locationTitlePaint.setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)); chat_locationAddressPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG); chat_urlPaint = new Paint(); chat_urlPaint.setPathEffect(LinkPath.getRoundedEffect()); @@ -8510,32 +8519,32 @@ public static void createCommonChatResources() { chat_radialProgress2Paint.setStyle(Paint.Style.STROKE); chat_audioTimePaint = new TextPaint(TextPaint.ANTI_ALIAS_FLAG); chat_livePaint = new TextPaint(Paint.ANTI_ALIAS_FLAG); - chat_livePaint.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); + chat_livePaint.setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)); chat_audioTitlePaint = new TextPaint(Paint.ANTI_ALIAS_FLAG); - chat_audioTitlePaint.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); + chat_audioTitlePaint.setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)); chat_audioPerformerPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG); chat_botButtonPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG); - chat_botButtonPaint.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); + chat_botButtonPaint.setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)); chat_contactNamePaint = new TextPaint(Paint.ANTI_ALIAS_FLAG); - chat_contactNamePaint.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); + chat_contactNamePaint.setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)); chat_contactPhonePaint = new TextPaint(Paint.ANTI_ALIAS_FLAG); chat_durationPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG); chat_gamePaint = new TextPaint(Paint.ANTI_ALIAS_FLAG); - chat_gamePaint.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); + chat_gamePaint.setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)); chat_shipmentPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG); chat_timePaint = new TextPaint(TextPaint.ANTI_ALIAS_FLAG); chat_adminPaint = new TextPaint(TextPaint.ANTI_ALIAS_FLAG); chat_namePaint = new TextPaint(TextPaint.ANTI_ALIAS_FLAG); - chat_namePaint.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); + chat_namePaint.setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)); chat_forwardNamePaint = new TextPaint(TextPaint.ANTI_ALIAS_FLAG); chat_replyNamePaint = new TextPaint(TextPaint.ANTI_ALIAS_FLAG); - chat_replyNamePaint.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); + chat_replyNamePaint.setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)); chat_replyTextPaint = new TextPaint(TextPaint.ANTI_ALIAS_FLAG); chat_topicTextPaint = new TextPaint(TextPaint.ANTI_ALIAS_FLAG); - chat_topicTextPaint.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); + chat_topicTextPaint.setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)); chat_commentTextPaint = new TextPaint(TextPaint.ANTI_ALIAS_FLAG); chat_instantViewPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG); - chat_instantViewPaint.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); + chat_instantViewPaint.setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)); chat_instantViewRectPaint = new Paint(Paint.ANTI_ALIAS_FLAG); chat_instantViewRectPaint.setStyle(Paint.Style.STROKE); chat_instantViewRectPaint.setStrokeCap(Paint.Cap.ROUND); @@ -8551,14 +8560,14 @@ public static void createCommonChatResources() { chat_statusRecordPaint.setStrokeCap(Paint.Cap.ROUND); chat_actionTextPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG); chat_actionTextPaint2 = new TextPaint(Paint.ANTI_ALIAS_FLAG); - chat_actionTextPaint.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); + chat_actionTextPaint.setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)); chat_unlockExtendedMediaTextPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG); chat_unlockExtendedMediaTextPaint.setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)); chat_actionBackgroundGradientDarkenPaint = new Paint(Paint.ANTI_ALIAS_FLAG); chat_actionBackgroundGradientDarkenPaint.setColor(0x15000000); chat_timeBackgroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG); chat_contextResult_titleTextPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG); - chat_contextResult_titleTextPaint.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); + chat_contextResult_titleTextPaint.setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)); chat_contextResult_descriptionTextPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG); chat_composeBackgroundPaint = new Paint(); chat_radialProgressPausedPaint = new Paint(Paint.ANTI_ALIAS_FLAG); @@ -8688,12 +8697,12 @@ public static void createChatResources(Context context, boolean fontsOnly) { chat_contextResult_shadowUnderSwitchDrawable = resources.getDrawable(R.drawable.header_shadow).mutate(); - chat_attachButtonDrawables[0] = new RLottieDrawable(R.raw.attach_gallery, "attach_gallery", AndroidUtilities.dp(26), AndroidUtilities.dp(26)); - chat_attachButtonDrawables[1] = new RLottieDrawable(R.raw.attach_music, "attach_music", AndroidUtilities.dp(26), AndroidUtilities.dp(26)); - chat_attachButtonDrawables[2] = new RLottieDrawable(R.raw.attach_file, "attach_file", AndroidUtilities.dp(26), AndroidUtilities.dp(26)); - chat_attachButtonDrawables[3] = new RLottieDrawable(R.raw.attach_contact, "attach_contact", AndroidUtilities.dp(26), AndroidUtilities.dp(26)); - chat_attachButtonDrawables[4] = new RLottieDrawable(R.raw.attach_location, "attach_location", AndroidUtilities.dp(26), AndroidUtilities.dp(26)); - chat_attachButtonDrawables[5] = new RLottieDrawable(R.raw.attach_poll, "attach_poll", AndroidUtilities.dp(26), AndroidUtilities.dp(26)); + chat_attachButtonDrawables[0] = new RLottieDrawable(R.raw.attach_gallery, "attach_gallery", dp(26), dp(26)); + chat_attachButtonDrawables[1] = new RLottieDrawable(R.raw.attach_music, "attach_music", dp(26), dp(26)); + chat_attachButtonDrawables[2] = new RLottieDrawable(R.raw.attach_file, "attach_file", dp(26), dp(26)); + chat_attachButtonDrawables[3] = new RLottieDrawable(R.raw.attach_contact, "attach_contact", dp(26), dp(26)); + chat_attachButtonDrawables[4] = new RLottieDrawable(R.raw.attach_location, "attach_location", dp(26), dp(26)); + chat_attachButtonDrawables[5] = new RLottieDrawable(R.raw.attach_poll, "attach_poll", dp(26), dp(26)); chat_attachEmptyDrawable = resources.getDrawable(R.drawable.nophotos3); chat_shareIconDrawable = resources.getDrawable(R.drawable.filled_button_share).mutate(); @@ -8701,45 +8710,45 @@ public static void createChatResources(Context context, boolean fontsOnly) { chat_closeIconDrawable = resources.getDrawable(R.drawable.msg_voiceclose).mutate(); chat_goIconDrawable = resources.getDrawable(R.drawable.filled_open_message); - int rad = AndroidUtilities.dp(2); + int rad = dp(2); RectF rect = new RectF(); chat_filePath[0] = new Path(); - chat_filePath[0].moveTo(AndroidUtilities.dp(7), AndroidUtilities.dp(3)); - chat_filePath[0].lineTo(AndroidUtilities.dp(14), AndroidUtilities.dp(3)); - chat_filePath[0].lineTo(AndroidUtilities.dp(21), AndroidUtilities.dp(10)); - chat_filePath[0].lineTo(AndroidUtilities.dp(21), AndroidUtilities.dp(20)); - rect.set(AndroidUtilities.dp(21) - rad * 2, AndroidUtilities.dp(19) - rad, AndroidUtilities.dp(21), AndroidUtilities.dp(19) + rad); + chat_filePath[0].moveTo(dp(7), dp(3)); + chat_filePath[0].lineTo(dp(14), dp(3)); + chat_filePath[0].lineTo(dp(21), dp(10)); + chat_filePath[0].lineTo(dp(21), dp(20)); + rect.set(dp(21) - rad * 2, dp(19) - rad, dp(21), dp(19) + rad); chat_filePath[0].arcTo(rect, 0, 90, false); - chat_filePath[0].lineTo(AndroidUtilities.dp(6), AndroidUtilities.dp(21)); - rect.set(AndroidUtilities.dp(5), AndroidUtilities.dp(19) - rad, AndroidUtilities.dp(5) + rad * 2, AndroidUtilities.dp(19) + rad); + chat_filePath[0].lineTo(dp(6), dp(21)); + rect.set(dp(5), dp(19) - rad, dp(5) + rad * 2, dp(19) + rad); chat_filePath[0].arcTo(rect, 90, 90, false); - chat_filePath[0].lineTo(AndroidUtilities.dp(5), AndroidUtilities.dp(4)); - rect.set(AndroidUtilities.dp(5), AndroidUtilities.dp(3), AndroidUtilities.dp(5) + rad * 2, AndroidUtilities.dp(3) + rad * 2); + chat_filePath[0].lineTo(dp(5), dp(4)); + rect.set(dp(5), dp(3), dp(5) + rad * 2, dp(3) + rad * 2); chat_filePath[0].arcTo(rect, 180, 90, false); chat_filePath[0].close(); chat_filePath[1] = new Path(); - chat_filePath[1].moveTo(AndroidUtilities.dp(14), AndroidUtilities.dp(5)); - chat_filePath[1].lineTo(AndroidUtilities.dp(19), AndroidUtilities.dp(10)); - chat_filePath[1].lineTo(AndroidUtilities.dp(14), AndroidUtilities.dp(10)); + chat_filePath[1].moveTo(dp(14), dp(5)); + chat_filePath[1].lineTo(dp(19), dp(10)); + chat_filePath[1].lineTo(dp(14), dp(10)); chat_filePath[1].close(); chat_flameIcon = resources.getDrawable(R.drawable.filled_fire).mutate(); chat_gifIcon = resources.getDrawable(R.drawable.msg_round_gif_m).mutate(); - chat_fileStatesDrawable[0][0] = createCircleDrawableWithIcon(AndroidUtilities.dp(44), R.drawable.msg_round_play_m); - chat_fileStatesDrawable[0][1] = createCircleDrawableWithIcon(AndroidUtilities.dp(44), R.drawable.msg_round_play_m); - chat_fileStatesDrawable[1][0] = createCircleDrawableWithIcon(AndroidUtilities.dp(44), R.drawable.msg_round_pause_m); - chat_fileStatesDrawable[1][1] = createCircleDrawableWithIcon(AndroidUtilities.dp(44), R.drawable.msg_round_pause_m); - chat_fileStatesDrawable[2][0] = createCircleDrawableWithIcon(AndroidUtilities.dp(44), R.drawable.msg_round_load_m); - chat_fileStatesDrawable[2][1] = createCircleDrawableWithIcon(AndroidUtilities.dp(44), R.drawable.msg_round_load_m); - chat_fileStatesDrawable[3][0] = createCircleDrawableWithIcon(AndroidUtilities.dp(44), R.drawable.msg_round_file_s); - chat_fileStatesDrawable[3][1] = createCircleDrawableWithIcon(AndroidUtilities.dp(44), R.drawable.msg_round_file_s); - chat_fileStatesDrawable[4][0] = createCircleDrawableWithIcon(AndroidUtilities.dp(44), R.drawable.msg_round_cancel_m); - chat_fileStatesDrawable[4][1] = createCircleDrawableWithIcon(AndroidUtilities.dp(44), R.drawable.msg_round_cancel_m); + chat_fileStatesDrawable[0][0] = createCircleDrawableWithIcon(dp(44), R.drawable.msg_round_play_m); + chat_fileStatesDrawable[0][1] = createCircleDrawableWithIcon(dp(44), R.drawable.msg_round_play_m); + chat_fileStatesDrawable[1][0] = createCircleDrawableWithIcon(dp(44), R.drawable.msg_round_pause_m); + chat_fileStatesDrawable[1][1] = createCircleDrawableWithIcon(dp(44), R.drawable.msg_round_pause_m); + chat_fileStatesDrawable[2][0] = createCircleDrawableWithIcon(dp(44), R.drawable.msg_round_load_m); + chat_fileStatesDrawable[2][1] = createCircleDrawableWithIcon(dp(44), R.drawable.msg_round_load_m); + chat_fileStatesDrawable[3][0] = createCircleDrawableWithIcon(dp(44), R.drawable.msg_round_file_s); + chat_fileStatesDrawable[3][1] = createCircleDrawableWithIcon(dp(44), R.drawable.msg_round_file_s); + chat_fileStatesDrawable[4][0] = createCircleDrawableWithIcon(dp(44), R.drawable.msg_round_cancel_m); + chat_fileStatesDrawable[4][1] = createCircleDrawableWithIcon(dp(44), R.drawable.msg_round_cancel_m); - chat_contactDrawable[0] = createCircleDrawableWithIcon(AndroidUtilities.dp(44), R.drawable.msg_contact); - chat_contactDrawable[1] = createCircleDrawableWithIcon(AndroidUtilities.dp(44), R.drawable.msg_contact); + chat_contactDrawable[0] = createCircleDrawableWithIcon(dp(44), R.drawable.msg_contact); + chat_contactDrawable[1] = createCircleDrawableWithIcon(dp(44), R.drawable.msg_contact); chat_locationDrawable[0] = resources.getDrawable(R.drawable.msg_location).mutate(); chat_locationDrawable[1] = resources.getDrawable(R.drawable.msg_location).mutate(); @@ -8804,43 +8813,43 @@ public static void createChatResources(Context context, boolean fontsOnly) { } if (!fontsOnly && chat_infoPaint != null) { - chat_infoPaint.setTextSize(AndroidUtilities.dp(12)); - chat_infoBoldPaint.setTextSize(AndroidUtilities.dp(12)); - chat_stickerCommentCountPaint.setTextSize(AndroidUtilities.dp(11)); - chat_docNamePaint.setTextSize(AndroidUtilities.dp(15)); - chat_locationTitlePaint.setTextSize(AndroidUtilities.dp(15)); - chat_locationAddressPaint.setTextSize(AndroidUtilities.dp(13)); - chat_audioTimePaint.setTextSize(AndroidUtilities.dp(12)); - chat_livePaint.setTextSize(AndroidUtilities.dp(12)); - chat_audioTitlePaint.setTextSize(AndroidUtilities.dp(16)); - chat_audioPerformerPaint.setTextSize(AndroidUtilities.dp(15)); - chat_botButtonPaint.setTextSize(AndroidUtilities.dp(15)); - chat_contactNamePaint.setTextSize(AndroidUtilities.dp(15)); - chat_contactPhonePaint.setTextSize(AndroidUtilities.dp(13)); - chat_durationPaint.setTextSize(AndroidUtilities.dp(12)); + chat_infoPaint.setTextSize(dp(12)); + chat_infoBoldPaint.setTextSize(dp(12)); + chat_stickerCommentCountPaint.setTextSize(dp(11)); + chat_docNamePaint.setTextSize(dp(15)); + chat_locationTitlePaint.setTextSize(dp(15)); + chat_locationAddressPaint.setTextSize(dp(13)); + chat_audioTimePaint.setTextSize(dp(12)); + chat_livePaint.setTextSize(dp(12)); + chat_audioTitlePaint.setTextSize(dp(16)); + chat_audioPerformerPaint.setTextSize(dp(15)); + chat_botButtonPaint.setTextSize(dp(15)); + chat_contactNamePaint.setTextSize(dp(15)); + chat_contactPhonePaint.setTextSize(dp(13)); + chat_durationPaint.setTextSize(dp(12)); float smallerDp = (2 * SharedConfig.fontSize + 10) / 3f; // 6f + SharedConfig.fontSize / 2f; - chat_namePaint.setTextSize(AndroidUtilities.dp(smallerDp)); - chat_replyNamePaint.setTextSize(AndroidUtilities.dp(smallerDp)); - chat_replyTextPaint.setTextSize(AndroidUtilities.dp(smallerDp)); - chat_topicTextPaint.setTextSize(AndroidUtilities.dp(smallerDp - 1)); - chat_forwardNamePaint.setTextSize(AndroidUtilities.dp(smallerDp)); - chat_adminPaint.setTextSize(AndroidUtilities.dp(smallerDp - 1)); + chat_namePaint.setTextSize(dp(smallerDp)); + chat_replyNamePaint.setTextSize(dp(smallerDp)); + chat_replyTextPaint.setTextSize(dp(smallerDp)); + chat_topicTextPaint.setTextSize(dp(smallerDp - 1)); + chat_forwardNamePaint.setTextSize(dp(smallerDp)); + chat_adminPaint.setTextSize(dp(smallerDp - 1)); float timeDp = 2 * (SharedConfig.fontSize - 16) / 3f + 12; - chat_timePaint.setTextSize(AndroidUtilities.dp(12)); - chat_gamePaint.setTextSize(AndroidUtilities.dp(13)); - chat_shipmentPaint.setTextSize(AndroidUtilities.dp(13)); - chat_instantViewPaint.setTextSize(AndroidUtilities.dp(13)); - chat_instantViewRectPaint.setStrokeWidth(AndroidUtilities.dp(1)); - chat_pollTimerPaint.setStrokeWidth(AndroidUtilities.dp(1.1f)); - chat_actionTextPaint.setTextSize(AndroidUtilities.dp(Math.max(16, SharedConfig.fontSize) - 2)); - chat_actionTextPaint2.setTextSize(AndroidUtilities.dp(Math.max(16, SharedConfig.fontSize) - 2)); - chat_unlockExtendedMediaTextPaint.setTextSize(AndroidUtilities.dp(Math.max(16, SharedConfig.fontSize))); - chat_contextResult_titleTextPaint.setTextSize(AndroidUtilities.dp(15)); - chat_contextResult_descriptionTextPaint.setTextSize(AndroidUtilities.dp(13)); - chat_radialProgressPaint.setStrokeWidth(AndroidUtilities.dp(3)); - chat_radialProgress2Paint.setStrokeWidth(AndroidUtilities.dp(2)); - chat_commentTextPaint.setTextSize(AndroidUtilities.dp(14)); - chat_commentTextPaint.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); + chat_timePaint.setTextSize(dp(12)); + chat_gamePaint.setTextSize(dp(13)); + chat_shipmentPaint.setTextSize(dp(13)); + chat_instantViewPaint.setTextSize(dp(13)); + chat_instantViewRectPaint.setStrokeWidth(dp(1)); + chat_pollTimerPaint.setStrokeWidth(dp(1.1f)); + chat_actionTextPaint.setTextSize(dp(Math.max(16, SharedConfig.fontSize) - 2)); + chat_actionTextPaint2.setTextSize(dp(Math.max(16, SharedConfig.fontSize) - 2)); + chat_unlockExtendedMediaTextPaint.setTextSize(dp(Math.max(16, SharedConfig.fontSize))); + chat_contextResult_titleTextPaint.setTextSize(dp(15)); + chat_contextResult_descriptionTextPaint.setTextSize(dp(13)); + chat_radialProgressPaint.setStrokeWidth(dp(3)); + chat_radialProgress2Paint.setStrokeWidth(dp(2)); + chat_commentTextPaint.setTextSize(dp(14)); + chat_commentTextPaint.setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)); } } @@ -9317,7 +9326,7 @@ public static void createProfileResources(Context context) { applyProfileTheme(); } - profile_aboutTextPaint.setTextSize(AndroidUtilities.dp(16)); + profile_aboutTextPaint.setTextSize(dp(16)); } private static ColorFilter currentShareColorFilter; @@ -9886,9 +9895,9 @@ public static BackgroundDrawableSettings createBackgroundDrawable( if (wallpaperFile != null) { if (wallpaperDocument != null) { File f = FileLoader.getInstance(UserConfig.selectedAccount).getPathToAttach(wallpaperDocument, true); - patternBitmap = SvgHelper.getBitmap(f, AndroidUtilities.dp(360), AndroidUtilities.dp(640), false); + patternBitmap = SvgHelper.getBitmap(f, dp(360), dp(640), false); } else { - patternBitmap = SvgHelper.getBitmap(R.raw.default_pattern, AndroidUtilities.dp(360), AndroidUtilities.dp(640), Color.WHITE); + patternBitmap = SvgHelper.getBitmap(R.raw.default_pattern, dp(360), dp(640), Color.WHITE); } if (patternBitmap != null) { FileOutputStream stream = null; @@ -10203,7 +10212,7 @@ public void onSizeReady(int width, int height) { opts.inJustDecodeBounds = true; float photoW = opts.outWidth; float photoH = opts.outHeight; - int maxWidth = AndroidUtilities.dp(100); + int maxWidth = dp(100); while (photoW > maxWidth || photoH > maxWidth) { scaleFactor *= 2; photoW /= 2; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ThemeColors.java b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ThemeColors.java index 25e14d08b63..060f898919d 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ThemeColors.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ThemeColors.java @@ -149,6 +149,7 @@ public static int[] createDefaultColors() { defaultColors[key_avatar_backgroundCyan] = 0xff5BCBE3; defaultColors[key_avatar_backgroundBlue] = 0xff5CAFFA; defaultColors[key_avatar_backgroundPink] = 0xffFF8AAC; + defaultColors[key_avatar_backgroundGray] = 0xffA1ABB5; defaultColors[key_avatar_background2Red] = 0xffD45246; defaultColors[key_avatar_background2Orange] = 0xffF68136; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Adapters/BaseLocationAdapter.java b/TMessagesProj/src/main/java/org/telegram/ui/Adapters/BaseLocationAdapter.java index 9d2835a5f11..912a5afb922 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Adapters/BaseLocationAdapter.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Adapters/BaseLocationAdapter.java @@ -37,9 +37,11 @@ public abstract class BaseLocationAdapter extends RecyclerListView.SelectionAdapter { public final boolean stories; + public final boolean biz; - public BaseLocationAdapter(boolean stories) { + public BaseLocationAdapter(boolean stories, boolean biz) { this.stories = stories; + this.biz = biz; } public interface BaseLocationAdapterDelegate { @@ -101,7 +103,7 @@ private void searchBotUser() { searchingUser = true; TLRPC.TL_contacts_resolveUsername req = new TLRPC.TL_contacts_resolveUsername(); req.username = stories ? - MessagesController.getInstance(currentAccount).venueSearchBot : // MessagesController.getInstance(currentAccount).storyVenueSearchBot : + MessagesController.getInstance(currentAccount).storyVenueSearchBot : MessagesController.getInstance(currentAccount).venueSearchBot; ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> { if (response != null) { @@ -169,7 +171,7 @@ public void searchPlacesWithQuery(final String query, final Location coordinate, TLObject object = MessagesController.getInstance(currentAccount).getUserOrChat( stories ? - MessagesController.getInstance(currentAccount).venueSearchBot : // MessagesController.getInstance(currentAccount).storyVenueSearchBot : + MessagesController.getInstance(currentAccount).storyVenueSearchBot : MessagesController.getInstance(currentAccount).venueSearchBot ); if (!(object instanceof TLRPC.User)) { @@ -198,13 +200,14 @@ public void searchPlacesWithQuery(final String query, final Location coordinate, req.peer = MessagesController.getInstance(currentAccount).getInputPeer(dialogId); } - if (!TextUtils.isEmpty(query) && stories) { + if (!TextUtils.isEmpty(query) && (stories || biz)) { searchingLocations = true; final Locale locale = LocaleController.getInstance().getCurrentLocale(); final String finalQuery = query; Utilities.globalQueue.postRunnable(() -> { final ArrayList locations = new ArrayList<>(); try { + final int maxCount = biz ? 10 : 5; Geocoder geocoder = new Geocoder(ApplicationLoader.applicationContext, locale); List
addresses = geocoder.getFromLocationName(finalQuery, 5); HashSet countries = new HashSet<>(); @@ -289,52 +292,74 @@ public void searchPlacesWithQuery(final String query, final Location coordinate, countryBuilder.append(arg); } - if (countryBuilder.length() > 0 && !countries.contains(countryBuilder.toString())) { - TLRPC.TL_messageMediaVenue countryLocation = new TLRPC.TL_messageMediaVenue(); - countryLocation.geo = new TLRPC.TL_geoPoint(); - countryLocation.geo.lat = lat; - countryLocation.geo._long = _long; - countryLocation.query_id = -1; - countryLocation.title = countryBuilder.toString(); - countryLocation.icon = "https://ss3.4sqi.net/img/categories_v2/building/government_capitolbuilding_64.png"; - countryLocation.emoji = LocationController.countryCodeToEmoji(address.getCountryCode()); - countries.add(countryLocation.title); - countryLocation.address = LocaleController.getString("Country", R.string.Country); - locations.add(countryLocation); - if (locations.size() >= 5) { - break; + if (biz) { + StringBuilder addressBuilder = new StringBuilder(); + try { + arg = address.getAddressLine(0); + if (!TextUtils.isEmpty(arg)) { + addressBuilder.append(arg); + } + } catch (Exception ignore) { + } + if (addressBuilder.length() > 0) { + TLRPC.TL_messageMediaVenue streetLocation = new TLRPC.TL_messageMediaVenue(); + streetLocation.geo = new TLRPC.TL_geoPoint(); + streetLocation.geo.lat = lat; + streetLocation.geo._long = _long; + streetLocation.query_id = -1; + streetLocation.title = addressBuilder.toString(); + streetLocation.icon = "pin"; + streetLocation.address = LocaleController.getString(R.string.PassportAddress); + locations.add(streetLocation); + } + } else { + if (streetBuilder != null && streetBuilder.length() > 0) { + TLRPC.TL_messageMediaVenue streetLocation = new TLRPC.TL_messageMediaVenue(); + streetLocation.geo = new TLRPC.TL_geoPoint(); + streetLocation.geo.lat = lat; + streetLocation.geo._long = _long; + streetLocation.query_id = -1; + streetLocation.title = streetBuilder.toString(); + streetLocation.icon = "pin"; + streetLocation.address = onlyCity ? LocaleController.getString("PassportCity", R.string.PassportCity) : LocaleController.getString("PassportStreet1", R.string.PassportStreet1); + locations.add(streetLocation); + if (locations.size() >= maxCount) { + break; + } } - } - if (!onlyCountry && !cities.contains(cityBuilder.toString())) { - TLRPC.TL_messageMediaVenue cityLocation = new TLRPC.TL_messageMediaVenue(); - cityLocation.geo = new TLRPC.TL_geoPoint(); - cityLocation.geo.lat = lat; - cityLocation.geo._long = _long; - cityLocation.query_id = -1; - cityLocation.title = cityBuilder.toString(); - cityLocation.icon = "https://ss3.4sqi.net/img/categories_v2/travel/hotel_64.png"; - cityLocation.emoji = LocationController.countryCodeToEmoji(address.getCountryCode()); - cities.add(cityLocation.title); - cityLocation.address = LocaleController.getString("PassportCity", R.string.PassportCity); - locations.add(cityLocation); - if (locations.size() >= 5) { - break; + if (!onlyCountry && !cities.contains(cityBuilder.toString())) { + TLRPC.TL_messageMediaVenue cityLocation = new TLRPC.TL_messageMediaVenue(); + cityLocation.geo = new TLRPC.TL_geoPoint(); + cityLocation.geo.lat = lat; + cityLocation.geo._long = _long; + cityLocation.query_id = -1; + cityLocation.title = cityBuilder.toString(); + cityLocation.icon = "https://ss3.4sqi.net/img/categories_v2/travel/hotel_64.png"; + cityLocation.emoji = LocationController.countryCodeToEmoji(address.getCountryCode()); + cities.add(cityLocation.title); + cityLocation.address = LocaleController.getString("PassportCity", R.string.PassportCity); + locations.add(cityLocation); + if (locations.size() >= maxCount) { + break; + } } - } - if (streetBuilder != null && streetBuilder.length() > 0) { - TLRPC.TL_messageMediaVenue streetLocation = new TLRPC.TL_messageMediaVenue(); - streetLocation.geo = new TLRPC.TL_geoPoint(); - streetLocation.geo.lat = lat; - streetLocation.geo._long = _long; - streetLocation.query_id = -1; - streetLocation.title = streetBuilder.toString(); - streetLocation.icon = "pin"; - streetLocation.address = onlyCity ? LocaleController.getString("PassportCity", R.string.PassportCity) : LocaleController.getString("PassportStreet1", R.string.PassportStreet1); - locations.add(streetLocation); - if (locations.size() >= 5) { - break; + if (countryBuilder.length() > 0 && !countries.contains(countryBuilder.toString())) { + TLRPC.TL_messageMediaVenue countryLocation = new TLRPC.TL_messageMediaVenue(); + countryLocation.geo = new TLRPC.TL_geoPoint(); + countryLocation.geo.lat = lat; + countryLocation.geo._long = _long; + countryLocation.query_id = -1; + countryLocation.title = countryBuilder.toString(); + countryLocation.icon = "https://ss3.4sqi.net/img/categories_v2/building/government_capitolbuilding_64.png"; + countryLocation.emoji = LocationController.countryCodeToEmoji(address.getCountryCode()); + countries.add(countryLocation.title); + countryLocation.address = LocaleController.getString("Country", R.string.Country); + locations.add(countryLocation); + if (locations.size() >= maxCount) { + break; + } } } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Adapters/ContactsAdapter.java b/TMessagesProj/src/main/java/org/telegram/ui/Adapters/ContactsAdapter.java index 99b86cf910e..737236d64fa 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Adapters/ContactsAdapter.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Adapters/ContactsAdapter.java @@ -59,7 +59,7 @@ public class ContactsAdapter extends RecyclerListView.SectionsAdapter { private int onlyUsers; private boolean needPhonebook; private LongSparseArray ignoreUsers; - private LongSparseArray checkedMap; + private LongSparseArray selectedContacts; private ArrayList onlineContacts; private boolean scrolling; private boolean isAdmin; @@ -74,11 +74,12 @@ public class ContactsAdapter extends RecyclerListView.SectionsAdapter { DialogStoriesCell dialogStoriesCell; BaseFragment fragment; - public ContactsAdapter(Context context, BaseFragment fragment, int onlyUsersType, boolean showPhoneBook, LongSparseArray usersToIgnore, int flags, boolean gps) { + public ContactsAdapter(Context context, BaseFragment fragment, int onlyUsersType, boolean showPhoneBook, LongSparseArray usersToIgnore, LongSparseArray selectedContacts, int flags, boolean gps) { mContext = context; onlyUsers = onlyUsersType; needPhonebook = showPhoneBook; ignoreUsers = usersToIgnore; + this.selectedContacts = selectedContacts; isAdmin = flags != 0; isChannel = flags == 2; hasGps = gps; @@ -175,10 +176,6 @@ public void sortOnlineContacts() { } } - public void setCheckedMap(LongSparseArray map) { - checkedMap = map; - } - public void setIsScrolling(boolean value) { scrolling = value; } @@ -558,9 +555,7 @@ public void onBindViewHolder(int section, int position, RecyclerView.ViewHolder } TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(arr.get(position).user_id); userCell.setData(user, null, null, 0); - if (checkedMap != null) { - userCell.setChecked(checkedMap.indexOfKey(user.id) >= 0, !scrolling); - } + userCell.setChecked(selectedContacts.indexOfKey(user.id) >= 0, false); if (ignoreUsers != null) { if (ignoreUsers.indexOfKey(user.id) >= 0) { userCell.setAlpha(0.5f); 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 00f2078bd4b..8a0dc23a7f9 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Adapters/DrawerLayoutAdapter.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Adapters/DrawerLayoutAdapter.java @@ -416,6 +416,7 @@ public static class Item { public int id; TLRPC.TL_attachMenuBot bot; View.OnClickListener listener; + public boolean error; public Item(int id, CharSequence text, int icon) { this.icon = icon; @@ -434,11 +435,17 @@ public void bind(DrawerActionCell actionCell) { } else { actionCell.setTextAndIcon(id, text, icon); } + actionCell.setError(error); } public Item onClick(View.OnClickListener listener) { this.listener = listener; return this; } + + public Item withError() { + this.error = true; + return this; + } } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Adapters/LocationActivityAdapter.java b/TMessagesProj/src/main/java/org/telegram/ui/Adapters/LocationActivityAdapter.java index 90af25e5345..daff53ebae1 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Adapters/LocationActivityAdapter.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Adapters/LocationActivityAdapter.java @@ -52,6 +52,7 @@ public class LocationActivityAdapter extends BaseLocationAdapter implements Loca private SendLocationCell sendLocationCell; private Location gpsLocation; private Location customLocation; + private String overrideAddressName; private String addressName; private Location previousFetchedLocation; private int locationType; @@ -69,8 +70,13 @@ public class LocationActivityAdapter extends BaseLocationAdapter implements Loca public boolean animated = true; public TLRPC.TL_messageMediaVenue city, street; - public LocationActivityAdapter(Context context, int type, long did, boolean emptyView, Theme.ResourcesProvider resourcesProvider, boolean stories) { - super(stories); + public void setAddressNameOverride(String address) { + overrideAddressName = address; + updateCell(); + } + + public LocationActivityAdapter(Context context, int type, long did, boolean emptyView, Theme.ResourcesProvider resourcesProvider, boolean stories, boolean biz) { + super(stories, biz); mContext = context; locationType = type; @@ -171,9 +177,24 @@ public void setChatLocation(TLRPC.TL_channelLocation location) { private void updateCell() { if (sendLocationCell != null) { - if (locationType == LocationActivity.LOCATION_TYPE_GROUP || customLocation != null) { + if (locationType == ChatAttachAlertLocationLayout.LOCATION_TYPE_BIZ) { String address = ""; - if (!TextUtils.isEmpty(addressName)) { + if (!TextUtils.isEmpty(overrideAddressName)) { + address = overrideAddressName; + } else if (!TextUtils.isEmpty(addressName)) { + address = addressName; + } else if (fetchingLocation) { + address = LocaleController.getString("Loading", R.string.Loading); + } else { + address = LocaleController.getString(R.string.UnknownLocation); + } + sendLocationCell.setText(LocaleController.getString(R.string.SetThisLocation), address); + sendLocationCell.setHasLocation(true); + } else if (locationType == LocationActivity.LOCATION_TYPE_GROUP || customLocation != null) { + String address = ""; + if (!TextUtils.isEmpty(overrideAddressName)) { + address = overrideAddressName; + } else if (!TextUtils.isEmpty(addressName)) { address = addressName; } else if (customLocation == null && gpsLocation == null || fetchingLocation) { address = LocaleController.getString("Loading", R.string.Loading); @@ -192,7 +213,7 @@ private void updateCell() { sendLocationCell.setHasLocation(true); } else { if (gpsLocation != null) { - sendLocationCell.setText(LocaleController.getString("SendLocation", R.string.SendLocation), LocaleController.formatString("AccurateTo", R.string.AccurateTo, LocaleController.formatPluralString("Meters", (int) gpsLocation.getAccuracy()))); + sendLocationCell.setText(LocaleController.getString(R.string.SendLocation), LocaleController.formatString(R.string.AccurateTo, LocaleController.formatPluralString("Meters", (int) gpsLocation.getAccuracy()))); sendLocationCell.setHasLocation(true); } else { sendLocationCell.setText(LocaleController.getString("SendLocation", R.string.SendLocation), myLocationDenied ? "" : LocaleController.getString("Loading", R.string.Loading)); @@ -202,7 +223,7 @@ private void updateCell() { } } - private String getAddressName() { + public String getAddressName() { return addressName; } @@ -210,9 +231,13 @@ private String getAddressName() { public void onLocationAddressAvailable(String address, String displayAddress, TLRPC.TL_messageMediaVenue city, TLRPC.TL_messageMediaVenue street, Location location) { fetchingLocation = false; previousFetchedLocation = location; - addressName = address; + if (locationType == ChatAttachAlertLocationLayout.LOCATION_TYPE_BIZ) { + addressName = displayAddress; + } else { + addressName = address; + } - if (locationType == ChatAttachAlertLocationLayout.LOCATION_TYPE_STORY && askingForMyLocation) { + if ((locationType == ChatAttachAlertLocationLayout.LOCATION_TYPE_STORY) && askingForMyLocation) { this.city = null; this.street = null; } @@ -241,7 +266,19 @@ protected void onDirectionClick() { } public void fetchLocationAddress() { - if (locationType == LocationActivity.LOCATION_TYPE_GROUP) { + if (locationType == ChatAttachAlertLocationLayout.LOCATION_TYPE_BIZ) { + Location location; + if (customLocation != null) { + location = customLocation; + } else if (gpsLocation != null) { + location = gpsLocation; + } else { + return; + } + fetchingLocation = true; + updateCell(); + LocationController.fetchLocationAddress(location, biz ? LocationController.TYPE_BIZ : 0, this); + } else if (locationType == LocationActivity.LOCATION_TYPE_GROUP) { Location location; if (customLocation != null) { location = customLocation; @@ -280,6 +317,8 @@ public int getItemCount() { return 2; } else if (locationType == LocationActivity.LOCATION_TYPE_GROUP) { return 2; + } else if (biz) { + return 2; } else if (currentMessageObject != null) { return 2 + (currentLiveLocations.isEmpty() ? 1 : currentLiveLocations.size() + 3); } else if (locationType == 2) { @@ -351,7 +390,7 @@ public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType break; } case VIEW_TYPE_SHARING: - view = new SharingLiveLocationCell(mContext, true, locationType == LocationActivity.LOCATION_TYPE_GROUP || locationType == LocationActivity.LOCATION_TYPE_GROUP_VIEW ? 16 : 54, resourcesProvider); + view = new SharingLiveLocationCell(mContext, true, locationType == LocationActivity.LOCATION_TYPE_GROUP || locationType == LocationActivity.LOCATION_TYPE_GROUP_VIEW || locationType == 3 ? 16 : 54, resourcesProvider); break; case VIEW_TYPE_DIRECTION: { LocationDirectionCell cell = new LocationDirectionCell(mContext, resourcesProvider); @@ -425,7 +464,7 @@ public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { if (locationType == 0) { position -= 4; - } else if (locationType == ChatAttachAlertLocationLayout.LOCATION_TYPE_STORY) { + } else if (locationType == ChatAttachAlertLocationLayout.LOCATION_TYPE_STORY || locationType == ChatAttachAlertLocationLayout.LOCATION_TYPE_BIZ) { position -= 4; if (this.street != null) { position--; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Adapters/LocationActivitySearchAdapter.java b/TMessagesProj/src/main/java/org/telegram/ui/Adapters/LocationActivitySearchAdapter.java index fcf362dfa43..2ca06cdb605 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Adapters/LocationActivitySearchAdapter.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Adapters/LocationActivitySearchAdapter.java @@ -39,8 +39,8 @@ public void setMyLocationDenied(boolean myLocationDenied) { } private FlickerLoadingView globalGradientView; - public LocationActivitySearchAdapter(Context context, Theme.ResourcesProvider resourcesProvider, boolean stories) { - super(stories); + public LocationActivitySearchAdapter(Context context, Theme.ResourcesProvider resourcesProvider, boolean stories, boolean biz) { + super(stories, biz); mContext = context; this.resourcesProvider = resourcesProvider; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Adapters/MentionsAdapter.java b/TMessagesProj/src/main/java/org/telegram/ui/Adapters/MentionsAdapter.java index d7919c427c1..5a6909ce523 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Adapters/MentionsAdapter.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Adapters/MentionsAdapter.java @@ -48,6 +48,8 @@ import org.telegram.tgnet.TLRPC; import org.telegram.ui.ActionBar.AlertDialog; import org.telegram.ui.ActionBar.Theme; +import org.telegram.ui.Business.QuickRepliesActivity; +import org.telegram.ui.Business.QuickRepliesController; import org.telegram.ui.Cells.BotSwitchCell; import org.telegram.ui.Cells.ContextLinkCell; import org.telegram.ui.Cells.MentionCell; @@ -92,6 +94,8 @@ public interface MentionsAdapterDelegate { private ArrayList searchResultHashtags; private ArrayList searchResultCommands; private ArrayList searchResultCommandsHelp; + private String quickRepliesQuery; + private ArrayList quickReplies; private ArrayList searchResultSuggestions; private String[] lastSearchKeyboardLanguage; private ArrayList searchResultCommandsUsers; @@ -389,6 +393,9 @@ public void notifyDataSetChanged() { } private boolean itemsEqual(Object a, Object b) { + if (a instanceof QuickRepliesController.QuickReply) { + return false; + } if (a == b) { return true; } @@ -795,6 +802,7 @@ private void searchForContextBotResults(final boolean cache, final TLRPC.User us searchResultUsernames = null; searchResultUsernamesMap = null; searchResultCommands = null; + quickReplies = null; searchResultSuggestions = null; searchResultCommandsHelp = null; searchResultCommandsUsers = null; @@ -1304,6 +1312,7 @@ public int compare(TLObject lhs, TLObject rhs) { }); searchResultHashtags = null; stickers = null; + quickReplies = null; searchResultCommands = null; searchResultCommandsHelp = null; searchResultCommandsUsers = null; @@ -1393,6 +1402,7 @@ public void run() { stickers = null; searchResultUsernames = null; searchResultUsernamesMap = null; + quickReplies = null; searchResultCommands = null; searchResultCommandsHelp = null; searchResultCommandsUsers = null; @@ -1417,6 +1427,21 @@ public void run() { } } } + if (parentFragment != null && !DialogObject.isEncryptedDialog(dialog_id) && parentFragment.getChatMode() == 0 && parentFragment.getCurrentUser() != null && !parentFragment.getCurrentUser().bot && !UserObject.isReplyUser(parentFragment.getCurrentUser()) && !UserObject.isService(parentFragment.getCurrentUser().id)) { + QuickRepliesController quickRepliesController = QuickRepliesController.getInstance(currentAccount); + quickRepliesController.load(); + quickRepliesQuery = command; + quickReplies = new ArrayList(); + for (int i = 0; i < quickRepliesController.replies.size(); i++) { + QuickRepliesController.QuickReply reply = quickRepliesController.replies.get(i); + if (!reply.isSpecial() && reply.name.startsWith(command)) { + quickReplies.add(reply); + } + } + } else { + quickRepliesQuery = null; + quickReplies = null; + } searchResultHashtags = null; stickers = null; searchResultUsernames = null; @@ -1428,7 +1453,7 @@ public void run() { contextMedia = false; searchResultBotContext = null; notifyDataSetChanged(); - delegate.needChangePanelVisibility(!newResult.isEmpty()); + delegate.needChangePanelVisibility(!newResult.isEmpty() || quickReplies != null && !quickReplies.isEmpty()); } else if (foundType == 3) { String[] newLanguage = AndroidUtilities.getCurrentKeyboardLanguage(); if (!Arrays.equals(newLanguage, lastSearchKeyboardLanguage)) { @@ -1442,6 +1467,7 @@ public void run() { searchResultUsernames = null; searchResultUsernamesMap = null; searchResultCommands = null; + quickReplies = null; searchResultCommandsHelp = null; searchResultCommandsUsers = null; notifyDataSetChanged(); @@ -1453,6 +1479,7 @@ public void run() { searchResultUsernamesMap = null; searchResultSuggestions = null; searchResultCommands = null; + quickReplies = null; searchResultCommandsHelp = null; searchResultCommandsUsers = null; } @@ -1533,8 +1560,8 @@ public int getItemCountInternal() { return searchResultUsernames.size(); } else if (searchResultHashtags != null) { return searchResultHashtags.size(); - } else if (searchResultCommands != null) { - return searchResultCommands.size(); + } else if (searchResultCommands != null || quickReplies != null) { + return (quickReplies == null ? 0 : quickReplies.size()) + (searchResultCommands == null ? 0 : searchResultCommands.size()); } else if (searchResultSuggestions != null) { return searchResultSuggestions.size(); } @@ -1563,6 +1590,9 @@ public void clear(boolean safe) { if (searchResultCommands != null) { searchResultCommands.clear(); } + if (quickReplies != null) { + quickReplies.clear(); + } if (searchResultSuggestions != null) { searchResultSuggestions.clear(); } @@ -1580,6 +1610,8 @@ public int getItemViewType(int position) { return 2; } return 1; + } else if (quickReplies != null && position >= 0 && position < quickReplies.size()) { + return 5; } else { return 0; } @@ -1636,18 +1668,27 @@ public Object getItem(int i) { return null; } return searchResultSuggestions.get(i); - } else if (searchResultCommands != null) { - if (i < 0 || i >= searchResultCommands.size()) { - return null; + } else if (quickReplies != null || searchResultCommands != null) { + if (quickReplies != null) { + if (i >= 0 && i < quickReplies.size()) { + return quickReplies.get(i); + } else if (quickReplies != null) { + i -= quickReplies.size(); + } } - if (searchResultCommandsUsers != null && (botsCount != 1 || info instanceof TLRPC.TL_channelFull)) { - if (searchResultCommandsUsers.get(i) != null) { - return String.format("%s@%s", searchResultCommands.get(i), searchResultCommandsUsers.get(i) != null ? searchResultCommandsUsers.get(i).username : ""); - } else { - return String.format("%s", searchResultCommands.get(i)); + if (searchResultCommands != null) { + if (i < 0 || i >= searchResultCommands.size()) { + return null; } + if (searchResultCommandsUsers != null && (botsCount != 1 || info instanceof TLRPC.TL_channelFull)) { + if (searchResultCommandsUsers.get(i) != null) { + return String.format("%s@%s", searchResultCommands.get(i), searchResultCommandsUsers.get(i) != null ? searchResultCommandsUsers.get(i).username : ""); + } else { + return String.format("%s", searchResultCommands.get(i)); + } + } + return searchResultCommands.get(i); } - return searchResultCommands.get(i); } return null; } @@ -1703,6 +1744,9 @@ public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType textView.setTextColor(getThemedColor(Theme.key_windowBackgroundWhiteGrayText2)); view = textView; break; + case 5: + view = new QuickRepliesActivity.QuickReplyView(mContext, false, resourcesProvider); + break; case 4: default: view = new StickerCell(mContext, resourcesProvider); @@ -1731,6 +1775,11 @@ public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { textView.setText(LocaleController.formatString("AttachInlineRestricted", R.string.AttachInlineRestricted, LocaleController.formatDateForBan(chat.banned_rights.until_date))); } } + } else if (type == 5) { + QuickRepliesActivity.QuickReplyView cell = (QuickRepliesActivity.QuickReplyView) holder.itemView; + if (quickReplies != null && position >= 0 && position < quickReplies.size()) { + cell.set(quickReplies.get(position), quickRepliesQuery, USE_DIVIDERS && (position + 1) < getItemCount()); + } } else if (searchResultBotContext != null) { boolean hasTop = searchResultBotContextSwitch != null || searchResultBotWebViewSwitch != null; if (holder.getItemViewType() == 2) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Adapters/SearchAdapter.java b/TMessagesProj/src/main/java/org/telegram/ui/Adapters/SearchAdapter.java index 30c592cb9ae..fab75be4136 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Adapters/SearchAdapter.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Adapters/SearchAdapter.java @@ -50,7 +50,7 @@ public class SearchAdapter extends RecyclerListView.SelectionAdapter { private ArrayList searchResult = new ArrayList<>(); private ArrayList searchResultNames = new ArrayList<>(); private SearchAdapterHelper searchAdapterHelper; - private LongSparseArray checkedMap; + private LongSparseArray selectedUsers; private Timer searchTimer; private boolean allowUsernameSearch; private boolean useUserCell; @@ -67,9 +67,10 @@ public class SearchAdapter extends RecyclerListView.SelectionAdapter { private ArrayList unregistredContacts = new ArrayList<>(); - public SearchAdapter(Context context, LongSparseArray arg1, boolean usernameSearch, boolean mutual, boolean chats, boolean bots, boolean self, boolean phones, int searchChannelId) { + public SearchAdapter(Context context, LongSparseArray arg1, LongSparseArray selected, boolean usernameSearch, boolean mutual, boolean chats, boolean bots, boolean self, boolean phones, int searchChannelId) { mContext = context; ignoreUsers = arg1; + selectedUsers = selected; onlyMutual = mutual; allowUsernameSearch = usernameSearch; allowChats = chats; @@ -94,10 +95,6 @@ public LongSparseArray getExcludeUsers() { }); } - public void setCheckedMap(LongSparseArray map) { - checkedMap = map; - } - public void setUseUserCell(boolean value) { useUserCell = value; } @@ -334,9 +331,6 @@ public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType case 0: if (useUserCell) { view = new UserCell(mContext, 1, 1, false); - if (checkedMap != null) { - ((UserCell) view).setChecked(false, false); - } } else { view = new ProfileSearchCell(mContext); } @@ -412,9 +406,7 @@ public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { if (useUserCell) { UserCell userCell = (UserCell) holder.itemView; userCell.setData(object, name, username, 0); - if (checkedMap != null) { - userCell.setChecked(checkedMap.indexOfKey(id) >= 0, false); - } + userCell.setChecked(selectedUsers.indexOfKey(id) >= 0, false); } else { ProfileSearchCell profileSearchCell = (ProfileSearchCell) holder.itemView; if (self) { @@ -422,6 +414,7 @@ public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { } profileSearchCell.setData(object, null, name, username, false, self); profileSearchCell.useSeparator = (position != getItemCount() - 1 && position != searchResult.size() - 1); + profileSearchCell.setChecked(selectedUsers.indexOfKey(id) >= 0, false); /*if (ignoreUsers != null) { if (ignoreUsers.containsKey(id)) { profileSearchCell.drawAlpha = 0.5f; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Business/AwayMessagesActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/Business/AwayMessagesActivity.java new file mode 100644 index 00000000000..bab0d43875e --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Business/AwayMessagesActivity.java @@ -0,0 +1,402 @@ +package org.telegram.ui.Business; + +import static org.telegram.messenger.LocaleController.getString; + +import android.content.Context; +import android.graphics.PorterDuff; +import android.graphics.PorterDuffColorFilter; +import android.graphics.drawable.Drawable; +import android.os.Bundle; +import android.view.View; +import android.widget.FrameLayout; + +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.BotWebViewVibrationEffect; +import org.telegram.messenger.LocaleController; +import org.telegram.messenger.NotificationCenter; +import org.telegram.messenger.R; +import org.telegram.tgnet.ConnectionsManager; +import org.telegram.tgnet.TLRPC; +import org.telegram.ui.ActionBar.ActionBar; +import org.telegram.ui.ActionBar.ActionBarMenuItem; +import org.telegram.ui.ActionBar.AlertDialog; +import org.telegram.ui.ActionBar.BaseFragment; +import org.telegram.ui.ActionBar.Theme; +import org.telegram.ui.Cells.TextCell; +import org.telegram.ui.Cells.TextCheckCell; +import org.telegram.ui.ChatActivity; +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.LayoutHelper; +import org.telegram.ui.Components.UItem; +import org.telegram.ui.Components.UniversalAdapter; +import org.telegram.ui.Components.UniversalRecyclerView; + +import java.util.ArrayList; + +public class AwayMessagesActivity extends BaseFragment implements NotificationCenter.NotificationCenterDelegate { + + private static final int done_button = 1; + private CrossfadeDrawable doneButtonDrawable; + private ActionBarMenuItem doneButton; + + private UniversalRecyclerView listView; + private BusinessRecipientsHelper recipientsHelper; + + @Override + public View createView(Context context) { + actionBar.setBackButtonImage(R.drawable.ic_ab_back); + actionBar.setAllowOverlayTitle(true); + actionBar.setTitle(getString(R.string.BusinessAway)); + actionBar.setActionBarMenuOnItemClick(new ActionBar.ActionBarMenuOnItemClick() { + @Override + public void onItemClick(int id) { + if (id == -1) { + if (onBackPressed()) { + finishFragment(); + } + } else if (id == done_button) { + processDone(); + } + } + }); + + Drawable checkmark = context.getResources().getDrawable(R.drawable.ic_ab_done).mutate(); + checkmark.setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_actionBarDefaultIcon), PorterDuff.Mode.MULTIPLY)); + doneButtonDrawable = new CrossfadeDrawable(checkmark, new CircularProgressDrawable(Theme.getColor(Theme.key_actionBarDefaultIcon))); + doneButton = actionBar.createMenu().addItemWithWidth(done_button, doneButtonDrawable, AndroidUtilities.dp(56), LocaleController.getString("Done", R.string.Done)); + checkDone(false); + + FrameLayout contentView = new FrameLayout(context); + contentView.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundGray)); + + recipientsHelper = new BusinessRecipientsHelper(this, () -> { + listView.adapter.update(true); + checkDone(true); + }); + recipientsHelper.setExclude(exclude); + if (recipientsHelper != null) { + recipientsHelper.setValue(currentValue == null ? null : currentValue.recipients); + } + + listView = new UniversalRecyclerView(context, currentAccount, this::fillItems, this::onClick, null, getResourceProvider()); + contentView.addView(listView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); + setValue(); + + return fragmentView = contentView; + } + + private boolean hasHours; + private boolean valueSet; + private void setValue() { + if (valueSet) return; + + final long selfId = getUserConfig().getClientUserId(); + TLRPC.UserFull userFull = getMessagesController().getUserFull(selfId); + if (userFull == null) { + getMessagesController().loadUserInfo(getUserConfig().getCurrentUser(), true, getClassGuid()); + return; + } + + currentValue = userFull.business_away_message; + hasHours = userFull.business_work_hours != null; + + enabled = currentValue != null; + exclude = currentValue != null ? currentValue.recipients.exclude_selected : true; + offline_only = currentValue != null ? currentValue.offline_only : true; + if (recipientsHelper != null) { + recipientsHelper.setValue(currentValue == null ? null : currentValue.recipients); + } + if (currentValue != null && currentValue.schedule instanceof TLRPC.TL_businessAwayMessageScheduleCustom) { + schedule = currentValueScheduleType = SCHEDULE_CUSTOM; + scheduleCustomStart = currentScheduleCustomStart = ((TLRPC.TL_businessAwayMessageScheduleCustom) currentValue.schedule).start_date; + scheduleCustomEnd =currentScheduleCustomEnd = ((TLRPC.TL_businessAwayMessageScheduleCustom) currentValue.schedule).end_date; + } else { + scheduleCustomStart = getConnectionsManager().getCurrentTime(); + scheduleCustomEnd = getConnectionsManager().getCurrentTime() + 60 * 60 * 24; + if (currentValue != null && currentValue.schedule instanceof TLRPC.TL_businessAwayMessageScheduleAlways) { + schedule = currentValueScheduleType = SCHEDULE_ALWAYS; + } else if (currentValue != null && currentValue.schedule instanceof TLRPC.TL_businessAwayMessageScheduleOutsideWorkHours) { + schedule = currentValueScheduleType = SCHEDULE_OUTSIDE_HOURS; + } else { + schedule = currentValueScheduleType = SCHEDULE_ALWAYS; + } + } + + if (listView != null && listView.adapter != null) { + listView.adapter.update(true); + } + checkDone(true); + valueSet = true; + } + + public boolean hasChanges() { + if (!valueSet) return false; + if (enabled != (currentValue != null)) return true; + if (enabled && currentValue != null) { + if (currentValue.recipients.exclude_selected != exclude) { + return true; + } + if (recipientsHelper != null && recipientsHelper.hasChanges()) { + return true; + } + if (currentValueScheduleType != schedule) { + return true; + } + if (currentValue.offline_only != offline_only) { + return true; + } + if (schedule == SCHEDULE_CUSTOM) { + if (currentScheduleCustomStart != scheduleCustomStart || currentScheduleCustomEnd != scheduleCustomEnd) { + return true; + } + } + } + return false; + } + + private void checkDone(boolean animated) { + if (doneButton == null) return; + final boolean hasChanges = hasChanges(); + doneButton.setEnabled(hasChanges); + if (animated) { + doneButton.animate().alpha(hasChanges ? 1.0f : 0.0f).scaleX(hasChanges ? 1.0f : 0.0f).scaleY(hasChanges ? 1.0f : 0.0f).setDuration(180).start(); + } else { + doneButton.setAlpha(hasChanges ? 1.0f : 0.0f); + doneButton.setScaleX(hasChanges ? 1.0f : 0.0f); + doneButton.setScaleY(hasChanges ? 1.0f : 0.0f); + } + } + + private int shiftDp = -4; + private void processDone() { + if (doneButtonDrawable.getProgress() > 0f) return; + + if (!hasChanges()) { + finishFragment(); + return; + } + + QuickRepliesController.QuickReply reply = QuickRepliesController.getInstance(currentAccount).findReply(QuickRepliesController.AWAY); + if (enabled && reply == null) { + BotWebViewVibrationEffect.APP_ERROR.vibrate(); + AndroidUtilities.shakeViewSpring(listView.findViewByItemId(BUTTON_CREATE), shiftDp = -shiftDp); + listView.smoothScrollToPosition(listView.findPositionByItemId(BUTTON_CREATE)); + return; + } + + if (enabled && !recipientsHelper.validate(listView)) { + return; + } + + doneButtonDrawable.animateToProgress(1f); + TLRPC.UserFull userFull = getMessagesController().getUserFull(getUserConfig().getClientUserId()); + TLRPC.TL_account_updateBusinessAwayMessage req = new TLRPC.TL_account_updateBusinessAwayMessage(); + if (enabled) { + req.message = new TLRPC.TL_inputBusinessAwayMessage(); + req.message.offline_only = offline_only; + req.message.shortcut_id = reply.id; + req.message.recipients = recipientsHelper.getInputValue(); + if (schedule == SCHEDULE_ALWAYS) { + req.message.schedule = new TLRPC.TL_businessAwayMessageScheduleAlways(); + } else if (schedule == SCHEDULE_OUTSIDE_HOURS) { + req.message.schedule = new TLRPC.TL_businessAwayMessageScheduleOutsideWorkHours(); + } else if (schedule == SCHEDULE_CUSTOM) { + TLRPC.TL_businessAwayMessageScheduleCustom custom = new TLRPC.TL_businessAwayMessageScheduleCustom(); + custom.start_date = scheduleCustomStart; + custom.end_date = scheduleCustomEnd; + req.message.schedule = custom; + } + req.flags |= 1; + + if (userFull != null) { + userFull.flags2 |= 8; + userFull.business_away_message = new TLRPC.TL_businessAwayMessage(); + userFull.business_away_message.offline_only = offline_only; + userFull.business_away_message.shortcut_id = reply.id; + userFull.business_away_message.recipients = recipientsHelper.getValue(); + userFull.business_away_message.schedule = req.message.schedule; + } + } else { + if (userFull != null) { + userFull.flags2 &=~ 8; + userFull.business_away_message = null; + } + } + + getConnectionsManager().sendRequest(req, (res, err) -> AndroidUtilities.runOnUIThread(() -> { + if (err != null) { + doneButtonDrawable.animateToProgress(0f); + BulletinFactory.showError(err); + } else if (res instanceof TLRPC.TL_boolFalse) { + doneButtonDrawable.animateToProgress(0f); + BulletinFactory.of(this).createErrorBulletin(LocaleController.getString(R.string.UnknownError)).show(); + } else { + finishFragment(); + } + })); + getMessagesStorage().updateUserInfo(userFull, false); + } + + @Override + public boolean onBackPressed() { + if (hasChanges()) { + if (!enabled) { + processDone(); + return false; + } + AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); + builder.setTitle(LocaleController.getString(R.string.UnsavedChanges)); + builder.setMessage(LocaleController.getString(R.string.BusinessAwayUnsavedChanges)); + builder.setPositiveButton(LocaleController.getString("ApplyTheme", R.string.ApplyTheme), (dialogInterface, i) -> processDone()); + builder.setNegativeButton(LocaleController.getString("PassportDiscard", R.string.PassportDiscard), (dialog, which) -> finishFragment()); + showDialog(builder.create()); + return false; + } + return super.onBackPressed(); + } + + public TLRPC.TL_businessAwayMessage currentValue; + public int currentValueScheduleType; + + public boolean enabled; + public boolean exclude; + public boolean offline_only; + public int schedule; + + private int currentScheduleCustomStart, currentScheduleCustomEnd; + public int scheduleCustomStart, scheduleCustomEnd; + + private final static int BUTTON_ENABLE = 1; + private final static int BUTTON_CREATE = 2; + private final static int RADIO_SCHEDULE_ALWAYS = 3; + private final static int RADIO_SCHEDULE_OUTSIDE_HOURS = 4; + private final static int RADIO_SCHEDULE_CUSTOM = 5; + private static final int RADIO_PRIVATE_CHATS = 6; + private static final int RADIO_ALL_CHATS = 7; + private static final int BUTTON_SCHEDULE_CUSTOM_START = 8; + private static final int BUTTON_SCHEDULE_CUSTOM_END = 9; + private static final int BUTTON_ONLY_OFFLINE = 10; + + private static final int SCHEDULE_ALWAYS = 0; + private static final int SCHEDULE_OUTSIDE_HOURS = 1; + private static final int SCHEDULE_CUSTOM = 2; + + private void fillItems(ArrayList items, UniversalAdapter adapter) { + items.add(UItem.asTopView(getString(R.string.BusinessAwayInfo), "RestrictedEmoji", "💤")); + items.add(UItem.asCheck(BUTTON_ENABLE, getString(R.string.BusinessAwaySend)).setChecked(enabled)); + items.add(UItem.asShadow(null)); + if (enabled) { + QuickRepliesController.QuickReply reply = QuickRepliesController.getInstance(currentAccount).findReply(QuickRepliesController.AWAY); + if (reply != null) { + items.add(UItem.asLargeQuickReply(reply)); + } else { + items.add(UItem.asButton(BUTTON_CREATE, R.drawable.msg2_chats_add, getString(R.string.BusinessAwayCreate)).accent()); + } + items.add(UItem.asShadow(null)); + items.add(UItem.asHeader(getString(R.string.BusinessAwaySchedule))); + items.add(UItem.asRadio(RADIO_SCHEDULE_ALWAYS, getString(R.string.BusinessAwayScheduleAlways)).setChecked(schedule == SCHEDULE_ALWAYS)); + if (hasHours) { + items.add(UItem.asRadio(RADIO_SCHEDULE_OUTSIDE_HOURS, getString(R.string.BusinessAwayScheduleOutsideHours)).setChecked(schedule == SCHEDULE_OUTSIDE_HOURS)); + } + items.add(UItem.asRadio(RADIO_SCHEDULE_CUSTOM, getString(R.string.BusinessAwayScheduleCustom)).setChecked(schedule == SCHEDULE_CUSTOM)); + if (schedule == SCHEDULE_CUSTOM) { + items.add(UItem.asShadow(null)); + items.add(UItem.asHeader(getString(R.string.BusinessAwaySchedule))); + items.add(UItem.asButton(BUTTON_SCHEDULE_CUSTOM_START, getString(R.string.BusinessAwayScheduleCustomStart), LocaleController.formatShortDateTime(scheduleCustomStart))); + items.add(UItem.asButton(BUTTON_SCHEDULE_CUSTOM_END, getString(R.string.BusinessAwayScheduleCustomEnd), LocaleController.formatShortDateTime(scheduleCustomEnd))); + } + items.add(UItem.asShadow(null)); + items.add(UItem.asCheck(BUTTON_ONLY_OFFLINE, LocaleController.getString(R.string.BusinessAwayOnlyOffline)).setChecked(offline_only)); + items.add(UItem.asShadow(LocaleController.getString(R.string.BusinessAwayOnlyOfflineInfo))); + items.add(UItem.asHeader(getString(R.string.BusinessRecipients))); + items.add(UItem.asRadio(RADIO_PRIVATE_CHATS, getString(R.string.BusinessChatsAllPrivateExcept)).setChecked(exclude)); + items.add(UItem.asRadio(RADIO_ALL_CHATS, getString(R.string.BusinessChatsOnlySelected)).setChecked(!exclude)); + items.add(UItem.asShadow(null)); + recipientsHelper.fillItems(items); + items.add(UItem.asShadow(null)); + } + } + + private void onClick(UItem item, View view, int position, float x, float y) { + if (recipientsHelper.onClick(item)) { + return; + } + if (item.id == BUTTON_CREATE || item.viewType == UniversalAdapter.VIEW_TYPE_LARGE_QUICK_REPLY) { + Bundle args = new Bundle(); + args.putLong("user_id", getUserConfig().getClientUserId()); + args.putInt("chatMode", ChatActivity.MODE_QUICK_REPLIES); + args.putString("quick_reply", QuickRepliesController.AWAY); + presentFragment(new ChatActivity(args)); + } else if (item.id == BUTTON_ENABLE) { + enabled = !enabled; + listView.adapter.update(true); + checkDone(true); + } else if (item.id == RADIO_PRIVATE_CHATS) { + recipientsHelper.setExclude(exclude = true); + listView.adapter.update(true); + checkDone(true); + } else if (item.id == RADIO_ALL_CHATS) { + recipientsHelper.setExclude(exclude = false); + listView.adapter.update(true); + checkDone(true); + } else if (item.id == RADIO_SCHEDULE_ALWAYS) { + schedule = SCHEDULE_ALWAYS; + listView.adapter.update(true); + checkDone(true); + } else if (item.id == RADIO_SCHEDULE_OUTSIDE_HOURS) { + schedule = SCHEDULE_OUTSIDE_HOURS; + listView.adapter.update(true); + checkDone(true); + } else if (item.id == RADIO_SCHEDULE_CUSTOM) { + schedule = SCHEDULE_CUSTOM; + listView.adapter.update(true); + checkDone(true); + } else if (item.id == BUTTON_SCHEDULE_CUSTOM_START) { + AlertsCreator.createDatePickerDialog(getContext(), getString(R.string.BusinessAwayScheduleCustomStartTitle), getString(R.string.BusinessAwayScheduleCustomSetButton), scheduleCustomStart, (notify, date) -> { + ((TextCell) view).setValue(LocaleController.formatShortDateTime(scheduleCustomStart = date), true); + checkDone(true); + }); + } else if (item.id == BUTTON_SCHEDULE_CUSTOM_END) { + AlertsCreator.createDatePickerDialog(getContext(), getString(R.string.BusinessAwayScheduleCustomEndTitle), getString(R.string.BusinessAwayScheduleCustomSetButton), scheduleCustomEnd, (notify, date) -> { + ((TextCell) view).setValue(LocaleController.formatShortDateTime(scheduleCustomEnd = date), true); + checkDone(true); + }); + } else if (item.id == BUTTON_ONLY_OFFLINE) { + offline_only = !offline_only; + ((TextCheckCell) view).setChecked(offline_only); + checkDone(true); + } + } + + @Override + public void didReceivedNotification(int id, int account, Object... args) { + if (id == NotificationCenter.quickRepliesUpdated) { + if (listView != null && listView.adapter != null) { + listView.adapter.update(true); + } + checkDone(true); + } else if (id == NotificationCenter.userInfoDidLoad) { + setValue(); + } + } + + @Override + public boolean onFragmentCreate() { + getNotificationCenter().addObserver(this, NotificationCenter.quickRepliesUpdated); + getNotificationCenter().addObserver(this, NotificationCenter.userInfoDidLoad); + QuickRepliesController.getInstance(currentAccount).load(); + setValue(); + return super.onFragmentCreate(); + } + + @Override + public void onFragmentDestroy() { + getNotificationCenter().removeObserver(this, NotificationCenter.quickRepliesUpdated); + getNotificationCenter().removeObserver(this, NotificationCenter.userInfoDidLoad); + super.onFragmentDestroy(); + } + +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Business/BusinessChatEmptyView.java b/TMessagesProj/src/main/java/org/telegram/ui/Business/BusinessChatEmptyView.java new file mode 100644 index 00000000000..516453192d9 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Business/BusinessChatEmptyView.java @@ -0,0 +1,158 @@ +package org.telegram.ui.Business; + +import static org.telegram.messenger.AndroidUtilities.dp; + +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.graphics.Path; +import android.graphics.PorterDuff; +import android.graphics.PorterDuffColorFilter; +import android.text.Layout; +import android.util.TypedValue; +import android.view.Gravity; +import android.view.MotionEvent; +import android.view.View; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.TextView; + +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.ContactsController; +import org.telegram.messenger.DocumentObject; +import org.telegram.messenger.FileLoader; +import org.telegram.messenger.ImageLocation; +import org.telegram.messenger.LocaleController; +import org.telegram.messenger.MediaDataController; +import org.telegram.messenger.MessageObject; +import org.telegram.messenger.MessagesController; +import org.telegram.messenger.R; +import org.telegram.messenger.SvgHelper; +import org.telegram.messenger.UserConfig; +import org.telegram.messenger.UserObject; +import org.telegram.tgnet.ConnectionsManager; +import org.telegram.tgnet.TLRPC; +import org.telegram.ui.ActionBar.BaseFragment; +import org.telegram.ui.ActionBar.BottomSheet; +import org.telegram.ui.ActionBar.SimpleTextView; +import org.telegram.ui.ActionBar.Theme; +import org.telegram.ui.ChatActivity; +import org.telegram.ui.Components.LayoutHelper; +import org.telegram.ui.Components.Premium.PremiumButtonView; +import org.telegram.ui.Components.Premium.StarParticlesView; +import org.telegram.ui.Components.RLottieImageView; +import org.telegram.ui.LaunchActivity; +import org.telegram.ui.PremiumPreviewFragment; +import org.telegram.ui.Stories.recorder.ButtonWithCounterView; +import org.telegram.ui.Stories.recorder.HintView2; + +import java.util.Locale; + +public class BusinessChatEmptyView extends LinearLayout { + + private TextView titleView; + private TextView descriptionView, descriptionView2; + + public RLottieImageView imageView; + private final Theme.ResourcesProvider resourcesProvider; + + private class DotTextView extends TextView { + public DotTextView(Context context) { + super(context); + } + + @Override + protected void dispatchDraw(Canvas canvas) { + if (getPaddingLeft() > 0) { + canvas.drawCircle((getPaddingLeft() - dp(2.5f)) / 2f, dp(10), dp(2.5f), getPaint()); + } + super.dispatchDraw(canvas); + } + } + + public BusinessChatEmptyView(Context context, int chatMode, long type, long topic_id, String quickReplyName, Theme.ResourcesProvider resourcesProvider) { + super(context); + setOrientation(VERTICAL); + this.resourcesProvider = resourcesProvider; + + titleView = new TextView(context); + titleView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); + titleView.setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)); + titleView.setTextAlignment(TEXT_ALIGNMENT_CENTER); + titleView.setGravity(Gravity.CENTER); + + descriptionView = new DotTextView(context); + descriptionView.setTextAlignment(TEXT_ALIGNMENT_CENTER); + descriptionView.setGravity(Gravity.CENTER); + descriptionView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 13); + descriptionView.setGravity(Gravity.CENTER_HORIZONTAL); + + imageView = new RLottieImageView(context); + imageView.setScaleType(ImageView.ScaleType.CENTER); + imageView.setColorFilter(new PorterDuffColorFilter(Color.WHITE, PorterDuff.Mode.SRC_IN)); +// imageView.setAnimation(R.raw.large_message_lock, 80, 80); +// imageView.setOnClickListener(v -> { +// imageView.setProgress(0); +// imageView.playAnimation(); +// }); +// imageView.playAnimation(); + + int descriptionViewMargin = 12; + descriptionView.setMaxWidth(dp(160)); + if (QuickRepliesController.GREETING.equalsIgnoreCase(quickReplyName)) { + imageView.setImageResource(R.drawable.large_greeting); + titleView.setText(LocaleController.getString(R.string.BusinessGreetingIntroTitle)); + descriptionViewMargin = 22; + descriptionView.setText(LocaleController.getString(R.string.BusinessGreetingIntro)); + descriptionView.setMaxWidth(Math.min(dp(160), HintView2.cutInFancyHalf(descriptionView.getText(), descriptionView.getPaint()))); + } else if (QuickRepliesController.AWAY.equalsIgnoreCase(quickReplyName)) { + imageView.setImageResource(R.drawable.large_away); + titleView.setText(LocaleController.getString(R.string.BusinessAwayIntroTitle)); + descriptionViewMargin = 22; + descriptionView.setText(LocaleController.getString(R.string.BusinessAwayIntro)); + descriptionView.setMaxWidth(Math.min(dp(160), HintView2.cutInFancyHalf(descriptionView.getText(), descriptionView.getPaint()))); + } else if (chatMode == ChatActivity.MODE_QUICK_REPLIES) { + imageView.setImageResource(R.drawable.large_quickreplies); + + QuickRepliesController.QuickReply reply = QuickRepliesController.getInstance(UserConfig.selectedAccount).findReply(topic_id); + String replyName = reply == null ? quickReplyName : reply.name; + + titleView.setText(LocaleController.getString(R.string.BusinessRepliesIntroTitle)); + descriptionView.setMaxWidth(dp(208)); + descriptionView.setTextAlignment(TEXT_ALIGNMENT_TEXT_START); + descriptionView.setGravity(Gravity.LEFT); + descriptionView.setText(AndroidUtilities.replaceTags(LocaleController.formatString(R.string.BusinessRepliesIntro1, replyName))); + descriptionView.setPadding(dp(28), 0, 0, 0); + + descriptionView2 = new DotTextView(context); + descriptionView2.setMaxWidth(dp(208)); + descriptionView2.setTextAlignment(TEXT_ALIGNMENT_TEXT_START); + descriptionView2.setGravity(Gravity.LEFT); + descriptionView2.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 13); + descriptionView2.setText(AndroidUtilities.replaceTags(LocaleController.getString(R.string.BusinessRepliesIntro2))); + descriptionView2.setPadding(dp(28), 0, 0, 0); + } + + addView(imageView, LayoutHelper.createLinear(78, 78, Gravity.CENTER_HORIZONTAL | Gravity.TOP, 20, 17, 20, 9)); + addView(titleView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_HORIZONTAL | Gravity.TOP, 20, 0, 20, 9)); + addView(descriptionView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_HORIZONTAL | Gravity.TOP, descriptionViewMargin, 0, descriptionViewMargin, descriptionView2 != null ? 9 : 19)); + if (descriptionView2 != null) { + addView(descriptionView2, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_HORIZONTAL | Gravity.TOP, 12, 0, 12, 19)); + } + + updateColors(); + } + + private void updateColors() { + titleView.setTextColor(getThemedColor(Theme.key_chat_serviceText)); + descriptionView.setTextColor(getThemedColor(Theme.key_chat_serviceText)); + if (descriptionView2 != null) { + descriptionView2.setTextColor(getThemedColor(Theme.key_chat_serviceText)); + } + } + + private int getThemedColor(int key) { + return Theme.getColor(key, resourcesProvider); + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Business/BusinessChatbotController.java b/TMessagesProj/src/main/java/org/telegram/ui/Business/BusinessChatbotController.java new file mode 100644 index 00000000000..20f031bfe45 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Business/BusinessChatbotController.java @@ -0,0 +1,79 @@ +package org.telegram.ui.Business; + +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.MessagesController; +import org.telegram.messenger.UserConfig; +import org.telegram.messenger.Utilities; +import org.telegram.tgnet.ConnectionsManager; +import org.telegram.tgnet.TLRPC; + +import java.util.ArrayList; + +public class BusinessChatbotController { + + private static volatile BusinessChatbotController[] Instance = new BusinessChatbotController[UserConfig.MAX_ACCOUNT_COUNT]; + private static final Object[] lockObjects = new Object[UserConfig.MAX_ACCOUNT_COUNT]; + static { + for (int i = 0; i < UserConfig.MAX_ACCOUNT_COUNT; i++) { + lockObjects[i] = new Object(); + } + } + public static BusinessChatbotController getInstance(int num) { + BusinessChatbotController localInstance = Instance[num]; + if (localInstance == null) { + synchronized (lockObjects[num]) { + localInstance = Instance[num]; + if (localInstance == null) { + Instance[num] = localInstance = new BusinessChatbotController(num); + } + } + } + return localInstance; + } + + private final int currentAccount; + private BusinessChatbotController(int account) { + this.currentAccount = account; + } + + private long lastTime; + private TLRPC.TL_account_connectedBots value; + private ArrayList> callbacks = new ArrayList<>(); + private boolean loading, loaded; + + public void load(Utilities.Callback callback) { + callbacks.add(callback); + if (loading) return; + if (System.currentTimeMillis() - lastTime > 1000 * 60 || !loaded) { + loading = true; + ConnectionsManager.getInstance(currentAccount).sendRequest(new TLRPC.TL_account_getConnectedBots(), (res, err) -> AndroidUtilities.runOnUIThread(() -> { + loading = false; + value = res instanceof TLRPC.TL_account_connectedBots ? (TLRPC.TL_account_connectedBots) res : null; + if (value != null) { + MessagesController.getInstance(currentAccount).putUsers(value.users, false); + } + lastTime = System.currentTimeMillis(); + loaded = true; + + for (int i = 0; i < callbacks.size(); ++i) { + if (callbacks.get(i) != null) { + callbacks.get(i).run(value); + } + } + callbacks.clear(); + })); + } else if (loaded) { + for (int i = 0; i < callbacks.size(); ++i) { + if (callbacks.get(i) != null) { + callbacks.get(i).run(value); + } + } + callbacks.clear(); + } + } + + public void invalidate() { + loaded = false; + load(null); + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Business/BusinessRecipientsHelper.java b/TMessagesProj/src/main/java/org/telegram/ui/Business/BusinessRecipientsHelper.java new file mode 100644 index 00000000000..13534bd1eb4 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Business/BusinessRecipientsHelper.java @@ -0,0 +1,309 @@ +package org.telegram.ui.Business; + +import static org.telegram.messenger.LocaleController.formatString; +import static org.telegram.messenger.LocaleController.getString; + +import android.text.TextUtils; + +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.BotWebViewVibrationEffect; +import org.telegram.messenger.FileLog; +import org.telegram.messenger.LocaleController; +import org.telegram.messenger.MessagesController; +import org.telegram.messenger.R; +import org.telegram.messenger.UserConfig; +import org.telegram.tgnet.TLRPC; +import org.telegram.ui.ActionBar.AlertDialog; +import org.telegram.ui.ActionBar.BaseFragment; +import org.telegram.ui.Components.UItem; +import org.telegram.ui.Components.UniversalAdapter; +import org.telegram.ui.Components.UniversalRecyclerView; +import org.telegram.ui.UsersSelectActivity; + +import java.util.ArrayList; + +public class BusinessRecipientsHelper { + + public final BaseFragment fragment; + public final Runnable update; + public BusinessRecipientsHelper(BaseFragment fragment, Runnable update) { + this.fragment = fragment; + this.update = update; + } + + public int includeFlags, excludeFlags; + public boolean exclude; + public final ArrayList alwaysShow = new ArrayList<>(); + public final ArrayList neverShow = new ArrayList<>(); + + public boolean includeExpanded, excludeExpanded; + + public static final int BUTTON_ADD_INCLUDED = 101; + public static final int BUTTON_EXPAND_INCLUDED = 102; + public static final int BUTTON_ADD_EXCLUDED = 103; + public static final int BUTTON_EXPAND_EXCLUDED = 104; + + public int getFlags() { + return exclude ? excludeFlags : includeFlags; + } + + + private TLRPC.TL_businessRecipients currentValue; + public boolean hasChanges() { + if (currentValue == null) return true; + if (currentValue.exclude_selected != exclude) return true; + if ((currentValue.flags &~ (32 | 16)) != getFlags()) return true; + ArrayList array = exclude ? neverShow : alwaysShow; + if (array.size() != currentValue.users.size()) return true; + for (int i = 0; i < array.size(); ++i) { + if (!currentValue.users.contains(array.get(i))) { + return true; + } + } + return false; + } + + public void setValue(TLRPC.TL_businessRecipients recipients) { + currentValue = recipients; + if (currentValue == null) { + exclude = true; + excludeFlags = 0; + includeFlags = 0; + alwaysShow.clear(); + neverShow.clear(); + } else { + exclude = currentValue.exclude_selected; + if (exclude) { + includeFlags = 0; + excludeFlags = currentValue.flags &~ (32 | 16); + alwaysShow.clear(); + neverShow.addAll(currentValue.users); + } else { + includeFlags = currentValue.flags &~ (32 | 16); + excludeFlags = 0; + alwaysShow.addAll(currentValue.users); + neverShow.clear(); + } + } + } + + public TLRPC.TL_businessRecipients getValue() { + TLRPC.TL_businessRecipients value = new TLRPC.TL_businessRecipients(); + final int flags = getFlags(); + value.flags = flags &~ (32 | 16); + value.existing_chats = (flags & PRIVATE_FLAG_EXISTING_CHATS) != 0; + value.new_chats = (flags & PRIVATE_FLAG_NEW_CHATS) != 0; + value.contacts = (flags & PRIVATE_FLAG_CONTACTS) != 0; + value.non_contacts = (flags & PRIVATE_FLAG_NON_CONTACTS) != 0; + value.exclude_selected = exclude; + ArrayList array = exclude ? neverShow : alwaysShow; + if (!array.isEmpty()) { + final int currentAccount = UserConfig.selectedAccount; + MessagesController controller = MessagesController.getInstance(currentAccount); + + value.flags |= 16; + for (int i = 0; i < array.size(); ++i) { + TLRPC.InputUser inputUser = controller.getInputUser(array.get(i)); + if (inputUser == null) { + FileLog.e("businessRecipientsHelper: user not found " + array.get(i)); + } else { + value.users.add(array.get(i)); + } + } + } + return value; + } + + public TLRPC.TL_inputBusinessRecipients getInputValue() { + TLRPC.TL_inputBusinessRecipients value = new TLRPC.TL_inputBusinessRecipients(); + final int flags = getFlags(); + value.flags = flags &~ (32 | 16); + value.existing_chats = (flags & PRIVATE_FLAG_EXISTING_CHATS) != 0; + value.new_chats = (flags & PRIVATE_FLAG_NEW_CHATS) != 0; + value.contacts = (flags & PRIVATE_FLAG_CONTACTS) != 0; + value.non_contacts = (flags & PRIVATE_FLAG_NON_CONTACTS) != 0; + value.exclude_selected = exclude; + ArrayList array = exclude ? neverShow : alwaysShow; + if (!array.isEmpty()) { + final int currentAccount = UserConfig.selectedAccount; + MessagesController controller = MessagesController.getInstance(currentAccount); + + value.flags |= 16; + for (int i = 0; i < array.size(); ++i) { + TLRPC.InputUser inputUser = controller.getInputUser(array.get(i)); + if (inputUser == null) { + FileLog.e("businessRecipientsHelper: user not found " + array.get(i)); + } else { + value.users.add(inputUser); + } + } + } + return value; + } + + private int shiftDp = -4; + public boolean validate(UniversalRecyclerView listView) { + if (!exclude && alwaysShow.isEmpty() && includeFlags == 0) { + BotWebViewVibrationEffect.APP_ERROR.vibrate(); + AndroidUtilities.shakeViewSpring(listView.findViewByItemId(BUTTON_ADD_INCLUDED), shiftDp = -shiftDp); + listView.smoothScrollToPosition(listView.findPositionByItemId(BUTTON_ADD_INCLUDED)); + return false; + } + return true; + } + + public void setExclude(boolean value) { + exclude = value; + } + + public void fillItems(ArrayList items) { + final int flags = getFlags(); + if (!exclude) { + items.add(UItem.asHeader(getString(R.string.BusinessChatsIncluded))); + items.add(UItem.asButton(BUTTON_ADD_INCLUDED, R.drawable.msg2_chats_add, getString(R.string.BusinessChatsIncludedAdd)).accent()); + if ((flags & PRIVATE_FLAG_EXISTING_CHATS) != 0) { + items.add(UItem.asFilterChat(true, LocaleController.getString(R.string.FilterExistingChats), "existing_chats", PRIVATE_FLAG_EXISTING_CHATS)); + } + if ((flags & PRIVATE_FLAG_NEW_CHATS) != 0) { + items.add(UItem.asFilterChat(true, LocaleController.getString(R.string.FilterNewChats), "new_chats", PRIVATE_FLAG_NEW_CHATS)); + } + if ((flags & PRIVATE_FLAG_CONTACTS) != 0) { + items.add(UItem.asFilterChat(true, LocaleController.getString(R.string.FilterContacts), "contacts", PRIVATE_FLAG_CONTACTS)); + } + if ((flags & PRIVATE_FLAG_NON_CONTACTS) != 0) { + items.add(UItem.asFilterChat(true, LocaleController.getString(R.string.FilterNonContacts), "non_contacts", PRIVATE_FLAG_NON_CONTACTS)); + } + if (!alwaysShow.isEmpty()) { + int count = includeExpanded || alwaysShow.size() < 8 ? alwaysShow.size() : Math.min(5, alwaysShow.size()); + for (int i = 0; i < count; ++i) { + items.add(UItem.asFilterChat(true, alwaysShow.get(i))); + } + if (count != alwaysShow.size()) { + items.add(UItem.asButton(BUTTON_EXPAND_INCLUDED, R.drawable.arrow_more, LocaleController.formatPluralString("FilterShowMoreChats", alwaysShow.size() - 5)).accent()); + } + } + } else { + items.add(UItem.asHeader(getString(R.string.BusinessChatsExcluded))); + items.add(UItem.asButton(BUTTON_ADD_EXCLUDED, R.drawable.msg2_chats_add, getString(R.string.BusinessChatsExcludedAdd)).accent()); + if ((flags & PRIVATE_FLAG_EXISTING_CHATS) != 0) { + items.add(UItem.asFilterChat(false, getString(R.string.FilterExistingChats), "existing_chats", PRIVATE_FLAG_EXISTING_CHATS)); + } + if ((flags & PRIVATE_FLAG_NEW_CHATS) != 0) { + items.add(UItem.asFilterChat(false, getString(R.string.FilterNewChats), "new_chats", PRIVATE_FLAG_NEW_CHATS)); + } + if ((flags & PRIVATE_FLAG_CONTACTS) != 0) { + items.add(UItem.asFilterChat(false, getString(R.string.FilterContacts), "contacts", PRIVATE_FLAG_CONTACTS)); + } + if ((flags & PRIVATE_FLAG_NON_CONTACTS) != 0) { + items.add(UItem.asFilterChat(false, getString(R.string.FilterNonContacts), "non_contacts", PRIVATE_FLAG_NON_CONTACTS)); + } + if (!neverShow.isEmpty()) { + int count = excludeExpanded || neverShow.size() < 8 ? neverShow.size() : Math.min(5, neverShow.size()); + for (int i = 0; i < count; ++i) { + items.add(UItem.asFilterChat(false, neverShow.get(i))); + } + if (count != neverShow.size()) { + items.add(UItem.asButton(BUTTON_EXPAND_EXCLUDED, R.drawable.arrow_more, LocaleController.formatPluralString("FilterShowMoreChats", neverShow.size() - 5)).accent()); + } + } + } + } + + public boolean onClick(UItem item) { + if (item.id == BUTTON_ADD_INCLUDED || item.id == BUTTON_ADD_EXCLUDED) { + selectChatsFor(item.id == BUTTON_ADD_INCLUDED); + return true; + } else if (item.id == BUTTON_EXPAND_INCLUDED) { + includeExpanded = true; + update.run(); + return true; + } else if (item.id == BUTTON_EXPAND_EXCLUDED) { + excludeExpanded = true; + update.run(); + return true; + } else if (item.viewType == UniversalAdapter.VIEW_TYPE_FILTER_CHAT) { + if (fragment == null) return false; + final int flag = item.chatType == null ? 0 : getFlag(item.chatType); + final String name = flag == 0 ? fragment.getMessagesController().getPeerName(item.dialogId) : getFlagName(flag); + fragment.showDialog( + new AlertDialog.Builder(fragment.getContext(), fragment.getResourceProvider()) + .setTitle(getString(exclude ? R.string.BusinessRecipientsRemoveExcludeTitle : R.string.BusinessRecipientsRemoveIncludeTitle)) + .setMessage(formatString(exclude ? R.string.BusinessRecipientsRemoveExcludeMessage : R.string.BusinessRecipientsRemoveIncludeMessage, name)) + .setPositiveButton(getString(R.string.Remove), (di, w) -> { + if (flag != 0) { + if (exclude) { + excludeFlags &=~ flag; + } else { + includeFlags &=~ flag; + } + } else { + (exclude ? neverShow : alwaysShow).remove(item.dialogId); + } + update.run(); + }) + .setNegativeButton(getString(R.string.Cancel), null) + .create() + ); + return true; + } + return false; + } + + private int getFlag(String chatType) { + switch (chatType) { + case "existing_chats": return PRIVATE_FLAG_EXISTING_CHATS; + case "new_chats": return PRIVATE_FLAG_NEW_CHATS; + case "contacts": return PRIVATE_FLAG_CONTACTS; + case "non_contacts": return PRIVATE_FLAG_NON_CONTACTS; + } + return 0; + } + + private String getFlagName(int flag) { + switch (flag) { + case PRIVATE_FLAG_EXISTING_CHATS: return getString(R.string.FilterExistingChats); + case PRIVATE_FLAG_NEW_CHATS: return getString(R.string.FilterNewChats); + case PRIVATE_FLAG_CONTACTS: return getString(R.string.FilterContacts); + default: + case PRIVATE_FLAG_NON_CONTACTS: return getString(R.string.FilterNonContacts); + } + } + + public static final int PRIVATE_FLAG_EXISTING_CHATS = 1; + public static final int PRIVATE_FLAG_NEW_CHATS = 2; + public static final int PRIVATE_FLAG_CONTACTS = 4; + public static final int PRIVATE_FLAG_NON_CONTACTS = 8; + + private boolean doNotExcludeNewChats; + public void doNotExcludeNewChats() { + doNotExcludeNewChats = true; + } + + private void selectChatsFor(boolean include) { + ArrayList arrayList = include ? alwaysShow : neverShow; + UsersSelectActivity fragment = new UsersSelectActivity(include, arrayList, getFlags()).asPrivateChats(); + fragment.noChatTypes = false; + fragment.allowSelf = false; + fragment.doNotNewChats = !include && doNotExcludeNewChats; + fragment.setDelegate((ids, flags) -> { + if (include) { + includeFlags = flags; + alwaysShow.clear(); + alwaysShow.addAll(ids); + for (int a = 0; a < alwaysShow.size(); a++) { + neverShow.remove(alwaysShow.get(a)); + } + } else { + excludeFlags = flags; + neverShow.clear(); + neverShow.addAll(ids); + for (int a = 0; a < neverShow.size(); a++) { + alwaysShow.remove(neverShow.get(a)); + } + } + update.run(); + }); + this.fragment.presentFragment(fragment); + } + +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Business/ChatAttachAlertQuickRepliesLayout.java b/TMessagesProj/src/main/java/org/telegram/ui/Business/ChatAttachAlertQuickRepliesLayout.java new file mode 100644 index 00000000000..0bbf27258b5 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Business/ChatAttachAlertQuickRepliesLayout.java @@ -0,0 +1,883 @@ +package org.telegram.ui.Business; + +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.animation.AnimatorSet; +import android.animation.ObjectAnimator; +import android.content.Context; +import android.graphics.Canvas; +import android.net.Uri; +import android.os.Build; +import android.text.TextUtils; +import android.view.Gravity; +import android.view.MotionEvent; +import android.view.View; +import android.view.ViewGroup; +import android.widget.FrameLayout; + +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.LinearSmoothScroller; +import androidx.recyclerview.widget.RecyclerView; + +import org.telegram.PhoneFormat.PhoneFormat; +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.Emoji; +import org.telegram.messenger.LocaleController; +import org.telegram.messenger.MessagesController; +import org.telegram.messenger.NotificationCenter; +import org.telegram.messenger.R; +import org.telegram.messenger.UserConfig; +import org.telegram.messenger.UserObject; +import org.telegram.messenger.Utilities; +import org.telegram.messenger.support.LongSparseIntArray; +import org.telegram.tgnet.ConnectionsManager; +import org.telegram.tgnet.TLRPC; +import org.telegram.ui.ActionBar.AlertDialog; +import org.telegram.ui.ActionBar.SimpleTextView; +import org.telegram.ui.ActionBar.Theme; +import org.telegram.ui.ActionBar.ThemeDescription; +import org.telegram.ui.Components.ChatActivityInterface; +import org.telegram.ui.Components.ChatAttachAlert; +import org.telegram.ui.Components.EditTextBoldCursor; +import org.telegram.ui.Components.RecyclerListView; +import org.telegram.ui.Components.FillLastLinearLayoutManager; +import org.telegram.ui.Components.EmptyTextProgressView; +import org.telegram.ui.Components.SearchField; +import org.telegram.ui.Components.BackupImageView; +import org.telegram.ui.Components.LayoutHelper; +import org.telegram.ui.Components.CheckBox2; +import org.telegram.ui.Components.AvatarDrawable; +import org.telegram.ui.Components.PhonebookShareAlert; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Locale; +import java.util.Objects; + +public class ChatAttachAlertQuickRepliesLayout extends ChatAttachAlert.AttachAlertLayout implements NotificationCenter.NotificationCenterDelegate { + + private FrameLayout frameLayout; + private RecyclerListView listView; + private FillLastLinearLayoutManager layoutManager; + private HashSet selectedReplies = new HashSet<>(); + private ShareAdapter listAdapter; + private ShareSearchAdapter searchAdapter; + private EmptyTextProgressView emptyView; + private View shadow; + private AnimatorSet shadowAnimation; + private SearchField searchField; + + private boolean ignoreLayout; + + public static class UserCell extends FrameLayout { + + private final Theme.ResourcesProvider resourcesProvider; + private BackupImageView avatarImageView; + private SimpleTextView nameTextView; + private SimpleTextView statusTextView; + private CheckBox2 checkBox; + + private AvatarDrawable avatarDrawable; + private TLRPC.User currentUser; + private int currentId; + + private CharSequence currentName; + private CharSequence currentStatus; + private TLRPC.User formattedPhoneNumberUser; + private CharSequence formattedPhoneNumber; + + private String lastName; + private int lastStatus; + private TLRPC.FileLocation lastAvatar; + + private int currentAccount = UserConfig.selectedAccount; + + private boolean needDivider; + + public UserCell(Context context, Theme.ResourcesProvider resourcesProvider) { + super(context); + this.resourcesProvider = resourcesProvider; + + avatarDrawable = new AvatarDrawable(resourcesProvider); + + avatarImageView = new BackupImageView(context); + avatarImageView.setRoundRadius(AndroidUtilities.dp(23)); + addView(avatarImageView, LayoutHelper.createFrame(46, 46, (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.TOP, LocaleController.isRTL ? 0 : 14, 9, LocaleController.isRTL ? 14 : 0, 0)); + + nameTextView = new SimpleTextView(context) { + @Override + public boolean setText(CharSequence value, boolean force) { + value = Emoji.replaceEmoji(value, getPaint().getFontMetricsInt(), AndroidUtilities.dp(14), false); + return super.setText(value, force); + } + }; + NotificationCenter.listenEmojiLoading(nameTextView); + nameTextView.setTextColor(getThemedColor(Theme.key_dialogTextBlack)); + nameTextView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); + nameTextView.setTextSize(16); + nameTextView.setGravity((LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.TOP); + addView(nameTextView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 20, (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.TOP, LocaleController.isRTL ? 28 : 72, 12, LocaleController.isRTL ? 72 : 28, 0)); + + statusTextView = new SimpleTextView(context); + statusTextView.setTextSize(13); + statusTextView.setTextColor(getThemedColor(Theme.key_dialogTextGray2)); + statusTextView.setGravity((LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.TOP); + addView(statusTextView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 20, (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.TOP, LocaleController.isRTL ? 28 : 72, 36, LocaleController.isRTL ? 72 : 28, 0)); + + checkBox = new CheckBox2(context, 21, resourcesProvider); + checkBox.setColor(-1, Theme.key_windowBackgroundWhite, Theme.key_checkboxCheck); + checkBox.setDrawUnchecked(false); + checkBox.setDrawBackgroundAsArc(3); + addView(checkBox, LayoutHelper.createFrame(24, 24, (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.TOP, LocaleController.isRTL ? 0 : 44, 37, LocaleController.isRTL ? 44 : 0, 0)); + } + + public void setCurrentId(int id) { + currentId = id; + } + + public void setData(TLRPC.User user, CharSequence name, CharSequence status, boolean divider) { + if (user == null && name == null && status == null) { + currentStatus = null; + currentName = null; + nameTextView.setText(""); + statusTextView.setText(""); + avatarImageView.setImageDrawable(null); + return; + } + currentStatus = status; + currentName = name; + currentUser = user; + needDivider = divider; + setWillNotDraw(!needDivider); + update(0); + } + + public interface CharSequenceCallback { + CharSequence run(); + } + + public void setData(TLRPC.User user, CharSequence name, CharSequenceCallback status, boolean divider) { + setData(user, name, (CharSequence) null, divider); + Utilities.globalQueue.postRunnable(() -> { + final CharSequence newCurrentStatus = status.run(); + AndroidUtilities.runOnUIThread(() -> { + setStatus(newCurrentStatus); + }); + }); + } + + public void setChecked(boolean checked, boolean animated) { + if (checkBox.getVisibility() != VISIBLE) { + checkBox.setVisibility(VISIBLE); + } + checkBox.setChecked(checked, animated); + } + + public void setStatus(CharSequence status) { + currentStatus = status; + if (currentStatus != null) { + statusTextView.setText(currentStatus); + } else if (currentUser != null) { + if (TextUtils.isEmpty(currentUser.phone)) { + statusTextView.setText(LocaleController.getString("NumberUnknown", R.string.NumberUnknown)); + } else { + if (formattedPhoneNumberUser != currentUser && formattedPhoneNumber != null) { + statusTextView.setText(formattedPhoneNumber); + } else { + statusTextView.setText(""); + Utilities.globalQueue.postRunnable(() -> { + if (currentUser != null) { + formattedPhoneNumber = PhoneFormat.getInstance().format("+" + currentUser.phone); + formattedPhoneNumberUser = currentUser; + AndroidUtilities.runOnUIThread(() -> statusTextView.setText(formattedPhoneNumber)); + } + }); + } + } + } + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure( + MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.EXACTLY), + MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(64) + (needDivider ? 1 : 0), MeasureSpec.EXACTLY) + ); + } + + public void update(int mask) { + TLRPC.FileLocation photo = null; + String newName = null; + if (currentUser != null && currentUser.photo != null) { + photo = currentUser.photo.photo_small; + } + + if (mask != 0) { + boolean continueUpdate = false; + if ((mask & MessagesController.UPDATE_MASK_AVATAR) != 0) { + if (lastAvatar != null && photo == null || lastAvatar == null && photo != null || lastAvatar != null && photo != null && (lastAvatar.volume_id != photo.volume_id || lastAvatar.local_id != photo.local_id)) { + continueUpdate = true; + } + } + if (currentUser != null && !continueUpdate && (mask & MessagesController.UPDATE_MASK_STATUS) != 0) { + int newStatus = 0; + if (currentUser.status != null) { + newStatus = currentUser.status.expires; + } + if (newStatus != lastStatus) { + continueUpdate = true; + } + } + if (!continueUpdate && currentName == null && lastName != null && (mask & MessagesController.UPDATE_MASK_NAME) != 0) { + if (currentUser != null) { + newName = UserObject.getUserName(currentUser); + } + if (!newName.equals(lastName)) { + continueUpdate = true; + } + } + if (!continueUpdate) { + return; + } + } + + if (currentUser != null) { + avatarDrawable.setInfo(currentAccount, currentUser); + if (currentUser.status != null) { + lastStatus = currentUser.status.expires; + } else { + lastStatus = 0; + } + } else if (currentName != null) { + avatarDrawable.setInfo(currentId, currentName.toString(), null); + } else { + avatarDrawable.setInfo(currentId, "#", null); + } + + if (currentName != null) { + lastName = null; + nameTextView.setText(currentName); + } else { + if (currentUser != null) { + lastName = newName == null ? UserObject.getUserName(currentUser) : newName; + } else { + lastName = ""; + } + nameTextView.setText(lastName); + } + + setStatus(currentStatus); + + lastAvatar = photo; + if (currentUser != null) { + avatarImageView.setForUserOrChat(currentUser, avatarDrawable); + } else { + avatarImageView.setImageDrawable(avatarDrawable); + } + } + + @Override + public boolean hasOverlappingRendering() { + return false; + } + + @Override + protected void onDraw(Canvas canvas) { + if (needDivider) { + canvas.drawLine(LocaleController.isRTL ? 0 : AndroidUtilities.dp(70), getMeasuredHeight() - 1, getMeasuredWidth() - (LocaleController.isRTL ? AndroidUtilities.dp(70) : 0), getMeasuredHeight() - 1, Theme.dividerPaint); + } + } + + protected int getThemedColor(int key) { + return Theme.getColor(key, resourcesProvider); + } + } + + public ChatAttachAlertQuickRepliesLayout(ChatAttachAlert alert, Context context, Theme.ResourcesProvider resourcesProvider) { + super(alert, context, resourcesProvider); + + searchAdapter = new ShareSearchAdapter(context); + + frameLayout = new FrameLayout(context); + frameLayout.setBackgroundColor(getThemedColor(Theme.key_dialogBackground)); + + searchField = new SearchField(context, false, resourcesProvider) { + @Override + public void onTextChange(String text) { + if (text.length() != 0) { + if (emptyView != null) { + emptyView.setText(LocaleController.getString("NoResult", R.string.NoResult)); + } + } else { + if (listView.getAdapter() != listAdapter) { + int top = getCurrentTop(); + emptyView.showTextView(); + listView.setAdapter(listAdapter); + listAdapter.notifyDataSetChanged(); + if (top > 0) { + layoutManager.scrollToPositionWithOffset(0, -top); + } + } + } + if (searchAdapter != null) { + searchAdapter.search(text); + } + } + + @Override + public boolean onInterceptTouchEvent(MotionEvent ev) { + parentAlert.makeFocusable(getSearchEditText(), true); + return super.onInterceptTouchEvent(ev); + } + + @Override + public void processTouchEvent(MotionEvent event) { + MotionEvent e = MotionEvent.obtain(event); + e.setLocation(e.getRawX(), e.getRawY() - parentAlert.getSheetContainer().getTranslationY() - AndroidUtilities.dp(58)); + listView.dispatchTouchEvent(e); + e.recycle(); + } + + @Override + protected void onFieldTouchUp(EditTextBoldCursor editText) { + parentAlert.makeFocusable(editText, true); + } + }; + searchField.setHint(LocaleController.getString(R.string.BusinessRepliesSearch)); + frameLayout.addView(searchField, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.TOP | Gravity.LEFT)); + + emptyView = new EmptyTextProgressView(context, null, resourcesProvider); + emptyView.showTextView(); + addView(emptyView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.TOP | Gravity.LEFT, 0, 52, 0, 0)); + + listView = new RecyclerListView(context, resourcesProvider) { + @Override + protected boolean allowSelectChildAtPosition(float x, float y) { + return y >= parentAlert.scrollOffsetY[0] + AndroidUtilities.dp(30) + (Build.VERSION.SDK_INT >= 21 && !parentAlert.inBubbleMode ? AndroidUtilities.statusBarHeight : 0); + } + + @Override + public void onScrolled(int dx, int dy) { + super.onScrolled(dx, dy); +// if (searchField != null) { +// AndroidUtilities.hideKeyboard(searchField.getSearchEditText()); +// } + } + }; + NotificationCenter.getInstance(UserConfig.selectedAccount).listen(listView, NotificationCenter.emojiLoaded, args -> { + AndroidUtilities.forEachViews(listView, view -> { + if (view instanceof QuickRepliesActivity.QuickReplyView) { + ((QuickRepliesActivity.QuickReplyView) view).invalidateEmojis(); + } + }); + }); + listView.setClipToPadding(false); + listView.setLayoutManager(layoutManager = new FillLastLinearLayoutManager(getContext(), LinearLayoutManager.VERTICAL, false, AndroidUtilities.dp(9), listView) { + @Override + public void smoothScrollToPosition(RecyclerView recyclerView, RecyclerView.State state, int position) { + LinearSmoothScroller linearSmoothScroller = new LinearSmoothScroller(recyclerView.getContext()) { + @Override + public int calculateDyToMakeVisible(View view, int snapPreference) { + int dy = super.calculateDyToMakeVisible(view, snapPreference); + dy -= (listView.getPaddingTop() - AndroidUtilities.dp(8)); + return dy; + } + + @Override + protected int calculateTimeForDeceleration(int dx) { + return super.calculateTimeForDeceleration(dx) * 2; + } + }; + linearSmoothScroller.setTargetPosition(position); + startSmoothScroll(linearSmoothScroller); + } + }); + layoutManager.setBind(false); + listView.setHorizontalScrollBarEnabled(false); + listView.setVerticalScrollBarEnabled(false); + listView.setClipToPadding(false); + listView.setPadding(0, 0, 0, AndroidUtilities.dp(48)); + addView(listView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.TOP | Gravity.LEFT, 0, 0, 0, 0)); + listView.setAdapter(listAdapter = new ShareAdapter(context)); + listView.setGlowColor(getThemedColor(Theme.key_dialogScrollGlow)); + listView.setOnItemClickListener((view, position) -> { + Object object; + if (listView.getAdapter() == searchAdapter) { + object = searchAdapter.getItem(position); + } else { + int section = listAdapter.getSectionForPosition(position); + int row = listAdapter.getPositionInSectionForPosition(position); + if (row < 0 || section < 0) { + return; + } + object = listAdapter.getItem(section, row); + } + if (object instanceof QuickRepliesController.QuickReply) { + final int currentAccount = UserConfig.selectedAccount; + TLRPC.TL_messages_sendQuickReplyMessages req = new TLRPC.TL_messages_sendQuickReplyMessages(); + long dialogId; + if (parentAlert.baseFragment instanceof ChatActivityInterface) { + dialogId = ((ChatActivityInterface) parentAlert.baseFragment).getDialogId(); + } else return; + req.peer = MessagesController.getInstance(currentAccount).getInputPeer(dialogId); + if (req.peer == null) return; + req.shortcut_id = ((QuickRepliesController.QuickReply) object).id; + ConnectionsManager.getInstance(currentAccount).sendRequest(req, null); + parentAlert.dismiss(); + } + }); + listView.setOnScrollListener(new RecyclerView.OnScrollListener() { + @Override + public void onScrolled(RecyclerView recyclerView, int dx, int dy) { + parentAlert.updateLayout(ChatAttachAlertQuickRepliesLayout.this, true, dy); + updateEmptyViewPosition(); + } + }); + + FrameLayout.LayoutParams frameLayoutParams = new FrameLayout.LayoutParams(LayoutHelper.MATCH_PARENT, AndroidUtilities.getShadowHeight(), Gravity.TOP | Gravity.LEFT); + frameLayoutParams.topMargin = AndroidUtilities.dp(58); + shadow = new View(context); + shadow.setBackgroundColor(getThemedColor(Theme.key_dialogShadowLine)); + shadow.setAlpha(0.0f); + shadow.setTag(1); + addView(shadow, frameLayoutParams); + + addView(frameLayout, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 58, Gravity.LEFT | Gravity.TOP)); + + updateEmptyView(); + } + + @Override + public int getSelectedItemsCount() { + return 0; + } + + private void showErrorBox(String error) { + new AlertDialog.Builder(getContext(), resourcesProvider).setTitle(LocaleController.getString("AppName", R.string.AppName)).setMessage(error).setPositiveButton(LocaleController.getString("OK", R.string.OK), null).show(); + } + + @Override + public void sendSelectedItems(boolean notify, int scheduleDate) { + + } + + @Override + public void scrollToTop() { + listView.smoothScrollToPosition(0); + } + + @Override + public int getCurrentItemTop() { + if (listView.getChildCount() <= 0) { + return Integer.MAX_VALUE; + } + View child = listView.getChildAt(0); + RecyclerListView.Holder holder = (RecyclerListView.Holder) listView.findContainingViewHolder(child); + int top = child.getTop() - AndroidUtilities.dp(8); + int newOffset = top > 0 && holder != null && holder.getAdapterPosition() == 0 ? top : 0; + if (top >= 0 && holder != null && holder.getAdapterPosition() == 0) { + newOffset = top; + runShadowAnimation(false); + } else { + runShadowAnimation(true); + } + frameLayout.setTranslationY(newOffset); + return newOffset + AndroidUtilities.dp(12); + } + + @Override + public int getFirstOffset() { + return getListTopPadding() + AndroidUtilities.dp(4); + } + + @Override + public void setTranslationY(float translationY) { + super.setTranslationY(translationY); + parentAlert.getSheetContainer().invalidate(); + } + + @Override + public int getListTopPadding() { + return listView.getPaddingTop(); + } + + @Override + public void onPreMeasure(int availableWidth, int availableHeight) { + int padding; + if (parentAlert.sizeNotifierFrameLayout.measureKeyboardHeight() > AndroidUtilities.dp(20)) { + padding = AndroidUtilities.dp(8); + parentAlert.setAllowNestedScroll(false); + } else { + if (!AndroidUtilities.isTablet() && AndroidUtilities.displaySize.x > AndroidUtilities.displaySize.y) { + padding = (int) (availableHeight / 3.5f); + } else { + padding = (availableHeight / 5 * 2); + } + parentAlert.setAllowNestedScroll(true); + } + if (listView.getPaddingTop() != padding) { + ignoreLayout = true; + listView.setPadding(0, padding, 0, AndroidUtilities.dp(48)); + ignoreLayout = false; + } + } + + @Override + public void requestLayout() { + if (ignoreLayout) { + return; + } + super.requestLayout(); + } + + private void runShadowAnimation(final boolean show) { + if (show && shadow.getTag() != null || !show && shadow.getTag() == null) { + shadow.setTag(show ? null : 1); + if (show) { + shadow.setVisibility(View.VISIBLE); + } + if (shadowAnimation != null) { + shadowAnimation.cancel(); + } + shadowAnimation = new AnimatorSet(); + shadowAnimation.playTogether(ObjectAnimator.ofFloat(shadow, View.ALPHA, show ? 1.0f : 0.0f)); + shadowAnimation.setDuration(150); + shadowAnimation.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + if (shadowAnimation != null && shadowAnimation.equals(animation)) { + if (!show) { + shadow.setVisibility(View.INVISIBLE); + } + shadowAnimation = null; + } + } + + @Override + public void onAnimationCancel(Animator animation) { + if (shadowAnimation != null && shadowAnimation.equals(animation)) { + shadowAnimation = null; + } + } + }); + shadowAnimation.start(); + } + } + + private int getCurrentTop() { + if (listView.getChildCount() != 0) { + View child = listView.getChildAt(0); + RecyclerListView.Holder holder = (RecyclerListView.Holder) listView.findContainingViewHolder(child); + if (holder != null) { + return listView.getPaddingTop() - (holder.getAdapterPosition() == 0 && child.getTop() >= 0 ? child.getTop() : 0); + } + } + return -1000; + } + + @Override + public void didReceivedNotification(int id, int account, Object... args) { + } + + @Override + public void onDestroy() { + + } + + @Override + public void onShow(ChatAttachAlert.AttachAlertLayout previousLayout) { + layoutManager.scrollToPositionWithOffset(0, 0); + } + + @Override + protected void onLayout(boolean changed, int left, int top, int right, int bottom) { + super.onLayout(changed, left, top, right, bottom); + updateEmptyViewPosition(); + } + + private void updateEmptyViewPosition() { + if (emptyView.getVisibility() != VISIBLE) { + return; + } + View child = listView.getChildAt(0); + if (child == null) { + return; + } + emptyView.setTranslationY((emptyView.getMeasuredHeight() - getMeasuredHeight() + child.getTop()) / 2); + } + + private void updateEmptyView() { + boolean visible = listView.getAdapter().getItemCount() == 2; + emptyView.setVisibility(visible ? VISIBLE : GONE); + updateEmptyViewPosition(); + } + + public class ShareAdapter extends RecyclerListView.SectionsAdapter { + + private ArrayList replies = new ArrayList<>(); + private int currentAccount = UserConfig.selectedAccount; + private Context mContext; + + public ShareAdapter(Context context) { + mContext = context; + replies.addAll(QuickRepliesController.getInstance(currentAccount).getFilteredReplies()); + } + + public Object getItem(int section, int position) { + if (section == 0) { + return null; + } + section--; + if (position < 0 || position >= replies.size()) return null; + return replies.get(position); + } + + @Override + public boolean isEnabled(RecyclerView.ViewHolder holder, int section, int row) { + if (section == 0 || section == getSectionCount() - 1) { + return false; + } + section--; + return row < replies.size(); + } + + @Override + public int getSectionCount() { + return 3; + } + + @Override + public int getCountForSection(int section) { + if (section == 0 || section == getSectionCount() - 1) { + return 1; + } + section--; + return replies.size(); + } + + @Override + public View getSectionHeaderView(int section, View view) { + return null; + } + + @Override + public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { + View view; + switch (viewType) { + case 0: { + view = new QuickRepliesActivity.QuickReplyView(mContext, false, resourcesProvider); + break; + } + case 1: { + view = new View(mContext); + view.setLayoutParams(new RecyclerView.LayoutParams(RecyclerView.LayoutParams.MATCH_PARENT, AndroidUtilities.dp(56))); + break; + } + case 2: + default: { + view = new View(mContext); + break; + } + } + return new RecyclerListView.Holder(view); + } + + @Override + public void onBindViewHolder(int section, int position, RecyclerView.ViewHolder holder) { + if (holder.getItemViewType() == 0) { + QuickRepliesActivity.QuickReplyView cell = (QuickRepliesActivity.QuickReplyView) holder.itemView; + Object object = getItem(section, position); + boolean divider = section != getSectionCount() - 2 || position != getCountForSection(section) - 1; + if (object instanceof QuickRepliesController.QuickReply) { + cell.set((QuickRepliesController.QuickReply) object, null, divider); + cell.setChecked(selectedReplies.contains(((QuickRepliesController.QuickReply) object).id), false); + } + } + } + + @Override + public int getItemViewType(int section, int position) { + if (section == 0) { + return 1; + } else if (section == getSectionCount() - 1) { + return 2; + } + return 0; + } + + @Override + public String getLetter(int position) { + return null; + } + + @Override + public void getPositionForScrollProgress(RecyclerListView listView, float progress, int[] position) { + position[0] = 0; + position[1] = 0; + } + + @Override + public void notifyDataSetChanged() { + replies.clear(); + replies.addAll(QuickRepliesController.getInstance(currentAccount).getFilteredReplies()); + super.notifyDataSetChanged(); + updateEmptyView(); + } + } + + public class ShareSearchAdapter extends RecyclerListView.SelectionAdapter { + + private Context mContext; + private ArrayList searchResult = new ArrayList<>(); + private Runnable searchRunnable; + private int lastSearchId; + public String lastQuery; + + public ShareSearchAdapter(Context context) { + mContext = context; + } + + public void search(final String query) { + if (searchRunnable != null) { + Utilities.searchQueue.cancelRunnable(searchRunnable); + searchRunnable = null; + } + searchResult.clear(); + lastQuery = query; + if (query != null) { + String q = AndroidUtilities.translitSafe(query); + if (q.startsWith("/")) q = q.substring(1); + QuickRepliesController controller = QuickRepliesController.getInstance(UserConfig.selectedAccount); + for (int i = 0; i < controller.replies.size(); ++i) { + QuickRepliesController.QuickReply reply = controller.replies.get(i); + if (reply.isSpecial()) continue; + String rq = AndroidUtilities.translitSafe(reply.name); + if (rq.startsWith(q) || rq.contains(" " + q)) { + searchResult.add(reply); + } + } + } + if (listView.getAdapter() != searchAdapter) { + listView.setAdapter(searchAdapter); + } + notifyDataSetChanged(); + } + + @Override + public int getItemCount() { + return searchResult.size() + 2; + } + + public Object getItem(int position) { + position--; + if (position < 0 || position >= searchResult.size()) { + return null; + } + return searchResult.get(position); + } + + @Override + public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { + View view; + switch (viewType) { + case 0: + view = new QuickRepliesActivity.QuickReplyView(mContext, false, resourcesProvider); + break; + case 1: + view = new View(mContext); + view.setLayoutParams(new RecyclerView.LayoutParams(RecyclerView.LayoutParams.MATCH_PARENT, AndroidUtilities.dp(56))); + break; + case 2: + default: + view = new View(mContext); + break; + } + return new RecyclerListView.Holder(view); + } + + @Override + public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { + if (holder.getItemViewType() == 0) { + QuickRepliesActivity.QuickReplyView cell = (QuickRepliesActivity.QuickReplyView) holder.itemView; + boolean divider = position != getItemCount() - 2; + Object object = getItem(position); + if (object instanceof QuickRepliesController.QuickReply) { + cell.set((QuickRepliesController.QuickReply) object, lastQuery, divider); + cell.setChecked(selectedReplies.contains(((QuickRepliesController.QuickReply) object).id), false); + } + } + } + + @Override + public boolean isEnabled(RecyclerView.ViewHolder holder) { + return holder.getItemViewType() == 0; + } + + @Override + public int getItemViewType(int position) { + if (position == 0) { + return 1; + } else if (position == getItemCount() - 1) { + return 2; + } + return 0; + } + + @Override + public void notifyDataSetChanged() { + super.notifyDataSetChanged(); + updateEmptyView(); + } + } + + @Override + public ArrayList getThemeDescriptions() { + + ThemeDescription.ThemeDescriptionDelegate cellDelegate = () -> { + if (listView != null) { + int count = listView.getChildCount(); + for (int a = 0; a < count; a++) { + View child = listView.getChildAt(a); + if (child instanceof UserCell) { + ((UserCell) child).update(0); + } + } + } + }; + + ArrayList themeDescriptions = new ArrayList<>(); + + themeDescriptions.add(new ThemeDescription(frameLayout, ThemeDescription.FLAG_BACKGROUND, null, null, null, null, Theme.key_dialogBackground)); + + themeDescriptions.add(new ThemeDescription(shadow, ThemeDescription.FLAG_BACKGROUND, null, null, null, null, Theme.key_dialogShadowLine)); + + themeDescriptions.add(new ThemeDescription(searchField.getSearchBackground(), ThemeDescription.FLAG_BACKGROUNDFILTER, null, null, null, null, Theme.key_dialogSearchBackground)); + themeDescriptions.add(new ThemeDescription(searchField, ThemeDescription.FLAG_IMAGECOLOR, new Class[]{SearchField.class}, new String[]{"searchIconImageView"}, null, null, null, Theme.key_dialogSearchIcon)); + themeDescriptions.add(new ThemeDescription(searchField, ThemeDescription.FLAG_IMAGECOLOR, new Class[]{SearchField.class}, new String[]{"clearSearchImageView"}, null, null, null, Theme.key_dialogSearchIcon)); + themeDescriptions.add(new ThemeDescription(searchField.getSearchEditText(), ThemeDescription.FLAG_TEXTCOLOR, null, null, null, null, Theme.key_dialogSearchText)); + themeDescriptions.add(new ThemeDescription(searchField.getSearchEditText(), ThemeDescription.FLAG_HINTTEXTCOLOR, null, null, null, null, Theme.key_dialogSearchHint)); + themeDescriptions.add(new ThemeDescription(searchField.getSearchEditText(), ThemeDescription.FLAG_CURSORCOLOR, null, null, null, null, Theme.key_featuredStickers_addedIcon)); + + themeDescriptions.add(new ThemeDescription(emptyView, ThemeDescription.FLAG_TEXTCOLOR, null, null, null, null, Theme.key_emptyListPlaceholder)); + themeDescriptions.add(new ThemeDescription(emptyView, ThemeDescription.FLAG_PROGRESSBAR, null, null, null, null, Theme.key_progressCircle)); + + themeDescriptions.add(new ThemeDescription(listView, ThemeDescription.FLAG_LISTGLOWCOLOR, null, null, null, null, Theme.key_dialogScrollGlow)); + + themeDescriptions.add(new ThemeDescription(listView, ThemeDescription.FLAG_SELECTOR, null, null, null, null, Theme.key_listSelector)); + themeDescriptions.add(new ThemeDescription(listView, 0, new Class[]{View.class}, Theme.dividerPaint, null, null, Theme.key_divider)); + + themeDescriptions.add(new ThemeDescription(listView, 0, new Class[]{UserCell.class}, new String[]{"nameTextView"}, null, null, null, Theme.key_dialogTextGray2)); + themeDescriptions.add(new ThemeDescription(listView, 0, new Class[]{UserCell.class}, new String[]{"statusTextView"}, null, null, cellDelegate, Theme.key_dialogTextGray2)); + themeDescriptions.add(new ThemeDescription(listView, 0, new Class[]{UserCell.class}, null, Theme.avatarDrawables, null, Theme.key_avatar_text)); + themeDescriptions.add(new ThemeDescription(null, 0, null, null, null, cellDelegate, Theme.key_avatar_backgroundRed)); + themeDescriptions.add(new ThemeDescription(null, 0, null, null, null, cellDelegate, Theme.key_avatar_backgroundOrange)); + themeDescriptions.add(new ThemeDescription(null, 0, null, null, null, cellDelegate, Theme.key_avatar_backgroundViolet)); + themeDescriptions.add(new ThemeDescription(null, 0, null, null, null, cellDelegate, Theme.key_avatar_backgroundGreen)); + themeDescriptions.add(new ThemeDescription(null, 0, null, null, null, cellDelegate, Theme.key_avatar_backgroundCyan)); + 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)); + + return themeDescriptions; + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Business/ChatbotsActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/Business/ChatbotsActivity.java new file mode 100644 index 00000000000..db2409d8819 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Business/ChatbotsActivity.java @@ -0,0 +1,478 @@ +package org.telegram.ui.Business; + +import static org.telegram.messenger.AndroidUtilities.dp; +import static org.telegram.messenger.LocaleController.getString; + +import android.content.Context; +import android.graphics.PorterDuff; +import android.graphics.PorterDuffColorFilter; +import android.graphics.drawable.Drawable; +import android.media.Image; +import android.text.Editable; +import android.text.InputType; +import android.text.SpannableString; +import android.text.SpannableStringBuilder; +import android.text.Spanned; +import android.text.SpannedString; +import android.text.TextUtils; +import android.text.TextWatcher; +import android.util.LongSparseArray; +import android.util.TypedValue; +import android.view.Gravity; +import android.view.View; +import android.view.inputmethod.EditorInfo; +import android.widget.FrameLayout; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.TextView; + +import org.checkerframework.checker.guieffect.qual.UI; +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.BotWebViewVibrationEffect; +import org.telegram.messenger.LocaleController; +import org.telegram.messenger.MessagesController; +import org.telegram.messenger.R; +import org.telegram.messenger.UserObject; +import org.telegram.messenger.browser.Browser; +import org.telegram.tgnet.TLObject; +import org.telegram.tgnet.TLRPC; +import org.telegram.ui.ActionBar.ActionBar; +import org.telegram.ui.ActionBar.ActionBarMenuItem; +import org.telegram.ui.ActionBar.AlertDialog; +import org.telegram.ui.ActionBar.BaseFragment; +import org.telegram.ui.ActionBar.Theme; +import org.telegram.ui.Adapters.SearchAdapterHelper; +import org.telegram.ui.Cells.DialogRadioCell; +import org.telegram.ui.Cells.RadioCell; +import org.telegram.ui.Cells.TextCheckCell; +import org.telegram.ui.ChangeUsernameActivity; +import org.telegram.ui.Components.Bulletin; +import org.telegram.ui.Components.BulletinFactory; +import org.telegram.ui.Components.CircularProgressDrawable; +import org.telegram.ui.Components.ColoredImageSpan; +import org.telegram.ui.Components.CrossfadeDrawable; +import org.telegram.ui.Components.CubicBezierInterpolator; +import org.telegram.ui.Components.EditTextBoldCursor; +import org.telegram.ui.Components.LayoutHelper; +import org.telegram.ui.Components.UItem; +import org.telegram.ui.Components.UniversalAdapter; +import org.telegram.ui.Components.UniversalRecyclerView; +import org.telegram.ui.LaunchActivity; + +import java.util.ArrayList; + +public class ChatbotsActivity extends BaseFragment { + + private static final int done_button = 1; + private CrossfadeDrawable doneButtonDrawable; + private ActionBarMenuItem doneButton; + + private UniversalRecyclerView listView; + + private SpannableStringBuilder introText; + + private SearchAdapterHelper searchHelper; + + private FrameLayout editTextContainer; + private EditTextBoldCursor editText; + private View editTextDivider; + + private FrameLayout emptyView; + private TextView emptyViewText; + private ImageView emptyViewLoading; + + private BusinessRecipientsHelper recipientsHelper; + + @Override + public View createView(Context context) { + actionBar.setBackButtonImage(R.drawable.ic_ab_back); + actionBar.setAllowOverlayTitle(true); + actionBar.setTitle(getString(R.string.BusinessBots)); + actionBar.setActionBarMenuOnItemClick(new ActionBar.ActionBarMenuOnItemClick() { + @Override + public void onItemClick(int id) { + if (id == -1) { + if (onBackPressed()) { + finishFragment(); + } + } else if (id == done_button) { + processDone(); + } + } + }); + + Drawable checkmark = context.getResources().getDrawable(R.drawable.ic_ab_done).mutate(); + checkmark.setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_actionBarDefaultIcon), PorterDuff.Mode.MULTIPLY)); + doneButtonDrawable = new CrossfadeDrawable(checkmark, new CircularProgressDrawable(Theme.getColor(Theme.key_actionBarDefaultIcon))); + doneButton = actionBar.createMenu().addItemWithWidth(done_button, doneButtonDrawable, AndroidUtilities.dp(56), LocaleController.getString("Done", R.string.Done)); + checkDone(false); + + FrameLayout contentView = new FrameLayout(context); + contentView.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundGray)); + + LinearLayout content = new LinearLayout(getContext()); + content.setOrientation(LinearLayout.HORIZONTAL); + editText = new EditTextBoldCursor(getContext()); + editText.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 17); + editText.setHintTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteHintText)); + editText.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlackText)); + editText.setBackgroundDrawable(null); + editText.setMaxLines(1); + editText.setLines(1); + editText.setPadding(0, 0, 0, 0); + editText.setSingleLine(true); + editText.setGravity((LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.TOP); + editText.setInputType(InputType.TYPE_TEXT_FLAG_CAP_SENTENCES | InputType.TYPE_TEXT_FLAG_MULTI_LINE | InputType.TYPE_TEXT_FLAG_AUTO_CORRECT); + editText.setImeOptions(EditorInfo.IME_ACTION_DONE); + editText.setHint(getString(R.string.BusinessBotLink)); + editText.setCursorColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlackText)); + editText.setCursorSize(dp(19)); + editText.setCursorWidth(1.5f); + editText.setOnEditorActionListener((textView, i, keyEvent) -> { + if (i == EditorInfo.IME_ACTION_DONE) { + scheduledLoading = false; + AndroidUtilities.cancelRunOnUIThread(search); + if (TextUtils.isEmpty(editText.getText())) { + lastQuery = null; + searchHelper.clear(); + listView.adapter.update(true); + } else { + AndroidUtilities.runOnUIThread(search); + } + updateSearchLoading(); + return true; + } + return false; + }); + editText.addTextChangedListener(new TextWatcher() { + @Override + public void beforeTextChanged(CharSequence charSequence, int i, int i2, int i3) { + + } + + @Override + public void onTextChanged(CharSequence charSequence, int i, int i2, int i3) { + + } + + @Override + public void afterTextChanged(Editable editable) { + scheduleSearch(); + } + }); + editTextContainer = new FrameLayout(context); + editTextContainer.addView(editText, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.TOP, 21, 15, 21, 15)); + editTextContainer.setBackgroundColor(getThemedColor(Theme.key_windowBackgroundWhite)); + editTextDivider = new View(context); + editTextDivider.setBackgroundColor(getThemedColor(Theme.key_divider)); + editTextContainer.addView(editTextDivider, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 1f / AndroidUtilities.density, Gravity.BOTTOM | Gravity.FILL_HORIZONTAL, (LocaleController.isRTL ? 0 : 21), 0, (LocaleController.isRTL ? 21 : 0), 0)); + + emptyView = new FrameLayout(context) { + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(dp(58), MeasureSpec.EXACTLY)); + } + }; + emptyView.setBackgroundColor(getThemedColor(Theme.key_windowBackgroundWhite)); + + emptyViewText = new TextView(context); + emptyViewText.setText(getString(R.string.BusinessBotNotFound)); + emptyViewText.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); + emptyViewText.setTextColor(getThemedColor(Theme.key_windowBackgroundWhiteGrayText2)); + emptyView.addView(emptyViewText, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER)); + + emptyViewLoading = new ImageView(context); + CircularProgressDrawable progressDrawable = new CircularProgressDrawable(getThemedColor(Theme.key_windowBackgroundWhiteGrayText2)) { + @Override + public int getIntrinsicWidth() { + return (int) (size + thickness * 2); + } + @Override + public int getIntrinsicHeight() { + return (int) (size + thickness * 2); + } + }; + emptyViewLoading.setImageDrawable(progressDrawable); + emptyView.addView(emptyViewLoading, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER)); + emptyViewLoading.setAlpha(0f); + emptyViewLoading.setTranslationY(dp(8)); + + introText = AndroidUtilities.replaceSingleTag(getString(R.string.BusinessBotsInfo), () -> { + Browser.openUrl(getContext(), LocaleController.getString(R.string.BusinessBotsInfoLink)); + }); + int arrowIndex = introText.toString().indexOf(">"); + if (arrowIndex >= 0) { + ColoredImageSpan span = new ColoredImageSpan(R.drawable.arrow_newchat); + span.setColorKey(Theme.key_chat_messageLinkIn); + introText.setSpan(span, arrowIndex, arrowIndex + 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + } + + searchHelper = new SearchAdapterHelper(true); + searchHelper.setDelegate(new SearchAdapterHelper.SearchAdapterHelperDelegate() { + @Override + public void onDataSetChanged(int searchId) { + AndroidUtilities.runOnUIThread(() -> { + listView.adapter.update(true); + updateSearchLoading(); + }); + } + }); + + recipientsHelper = new BusinessRecipientsHelper(this, () -> { + listView.adapter.update(true); + checkDone(true); + }); + recipientsHelper.setValue(currentBot == null ? null : currentBot.recipients); + + listView = new UniversalRecyclerView(context, currentAccount, this::fillItems, this::onClick, null, getResourceProvider()); + contentView.addView(listView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); + + return fragmentView = contentView; + } + + private boolean wasLoading; + private void updateSearchLoading() { + if (wasLoading != (searchHelper.isSearchInProgress() || scheduledLoading || foundBots.size() > 0)) { + final boolean loading = wasLoading = searchHelper.isSearchInProgress() || scheduledLoading || foundBots.size() > 0; + emptyViewText.animate().alpha(loading ? 0f : 1f).translationY(loading ? -dp(8) : 0).setDuration(320).setInterpolator(CubicBezierInterpolator.EASE_OUT_QUINT).start(); + emptyViewLoading.animate().alpha(loading ? 1f : 0f).translationY(loading ? 0 : dp(8)).setDuration(320).setInterpolator(CubicBezierInterpolator.EASE_OUT_QUINT).start(); + } + } + + private boolean scheduledLoading; + private void scheduleSearch() { + scheduledLoading = false; + AndroidUtilities.cancelRunOnUIThread(search); + if (TextUtils.isEmpty(editText.getText())) { + lastQuery = null; + searchHelper.clear(); + } else { + scheduledLoading = true; + AndroidUtilities.runOnUIThread(search, 800); + } + listView.adapter.update(true); + updateSearchLoading(); + } + private String lastQuery; + private int searchId = 0; + private Runnable search = () -> { + final String query = editText.getText().toString(); + if (lastQuery != null && TextUtils.equals(lastQuery, query)) + return; + scheduledLoading = false; + if (TextUtils.isEmpty(query)) { + lastQuery = null; + searchHelper.clear(); + listView.adapter.update(true); + } else { + searchHelper.queryServerSearch(lastQuery = query, true, false, true, false, false, 0, false, 0, searchId++, 0); + } + }; + + public TLRPC.TL_account_connectedBots currentValue; + public TLRPC.TL_connectedBot currentBot; + + public boolean exclude; + public boolean allowReply = true; + + private TLRPC.User selectedBot = null; + private LongSparseArray foundBots = new LongSparseArray<>(); + + private static final int RADIO_EXCLUDE = -1; + private static final int RADIO_INCLUDE = -2; + private static final int CHECK_PERMISSIONS_REPLY = -5; + private static final int BUTTON_DELETE = -6; + + private void fillItems(ArrayList items, UniversalAdapter adapter) { + items.add(UItem.asTopView(introText, "RestrictedEmoji", "🤖")); + + if (selectedBot != null) { + items.add(UItem.asAddChat(selectedBot.id).setChecked(true).setCloseIcon(this::clear)); + } else { + adapter.whiteSectionStart(); + boolean needDivider = false; + items.add(UItem.asCustom(editTextContainer)); + foundBots.clear(); + for (int i = 0; i < searchHelper.getLocalServerSearch().size(); ++i) { + TLObject obj = searchHelper.getLocalServerSearch().get(i); + if (!(obj instanceof TLRPC.User)) continue; + TLRPC.User user = (TLRPC.User) obj; + if (!user.bot) continue; + items.add(UItem.asAddChat(user.id)); + foundBots.put(user.id, user); + needDivider = true; + } + for (int i = 0; i < searchHelper.getGlobalSearch().size(); ++i) { + TLObject obj = searchHelper.getGlobalSearch().get(i); + if (!(obj instanceof TLRPC.User)) continue; + TLRPC.User user = (TLRPC.User) obj; + if (!user.bot) continue; + items.add(UItem.asAddChat(user.id)); + foundBots.put(user.id, user); + needDivider = true; + } + if (foundBots.size() <= 0 && (!TextUtils.isEmpty(editText.getText().toString()) || searchHelper.isSearchInProgress() || scheduledLoading)) { + items.add(UItem.asCustom(emptyView)); + needDivider = true; + } + editTextDivider.setVisibility(needDivider ? View.VISIBLE : View.GONE); + adapter.whiteSectionEnd(); + } + items.add(UItem.asShadow(getString(R.string.BusinessBotLinkInfo))); + items.add(UItem.asHeader(getString(R.string.BusinessBotChats))); + items.add(UItem.asRadio(RADIO_EXCLUDE, getString(R.string.BusinessChatsAllPrivateExcept)).setChecked(exclude)); + items.add(UItem.asRadio(RADIO_INCLUDE, getString(R.string.BusinessChatsOnlySelected)).setChecked(!exclude)); + items.add(UItem.asShadow(null)); + recipientsHelper.fillItems(items); + items.add(UItem.asShadow(getString(R.string.BusinessBotChatsInfo))); + items.add(UItem.asHeader(getString(R.string.BusinessBotPermissions))); + items.add(UItem.asCheck(CHECK_PERMISSIONS_REPLY, getString(R.string.BusinessBotPermissionsReply)).setChecked(allowReply)); + items.add(UItem.asShadow(getString(R.string.BusinessBotPermissionsInfo))); + items.add(UItem.asShadow(null)); + } + + private void onClick(UItem item, View view, int position, float x, float y) { + if (recipientsHelper.onClick(item)) { + return; + } + if (item.id == RADIO_EXCLUDE) { + recipientsHelper.setExclude(exclude = true); + listView.adapter.update(true); + checkDone(true); + } else if (item.id == RADIO_INCLUDE) { + recipientsHelper.setExclude(exclude = false); + listView.adapter.update(true); + checkDone(true); + } else if (item.id == CHECK_PERMISSIONS_REPLY) { + ((TextCheckCell) view).setChecked(allowReply = !allowReply); + checkDone(true); + } else if (item.id == BUTTON_DELETE) { + selectedBot = null; + listView.adapter.update(true); + checkDone(true); + } else if (item.viewType == UniversalAdapter.VIEW_TYPE_USER_ADD) { + selectedBot = foundBots.get(item.dialogId); + AndroidUtilities.hideKeyboard(editText); + listView.adapter.update(true); + checkDone(true); + } + } + + private void clear() { + selectedBot = null; + listView.adapter.update(true); + checkDone(true); + } + + private void processDone() { + if (doneButtonDrawable.getProgress() > 0f) return; + + if (!hasChanges()) { + finishFragment(); + return; + } + + if (!recipientsHelper.validate(listView)) { + return; + } + + TLRPC.TL_account_updateConnectedBot req = new TLRPC.TL_account_updateConnectedBot(); + if (selectedBot == null) { + req.deleted = true; + req.bot = new TLRPC.TL_inputUserEmpty(); + req.recipients = new TLRPC.TL_inputBusinessRecipients(); + } else { + req.can_reply = allowReply; + req.bot = getMessagesController().getInputUser(selectedBot); + req.recipients = recipientsHelper.getInputValue(); + + if (currentBot != null) { + currentBot.can_reply = allowReply; + currentBot.bot_id = selectedBot.id; + currentBot.recipients = recipientsHelper.getValue(); + } + } + + getConnectionsManager().sendRequest(req, (res, err) -> AndroidUtilities.runOnUIThread(() -> { + if (res instanceof TLRPC.Updates) { + getMessagesController().processUpdates((TLRPC.Updates) res, false); + } + if (err != null) { + doneButtonDrawable.animateToProgress(0f); + BulletinFactory.showError(err); + } else { + BusinessChatbotController.getInstance(currentAccount).invalidate(); + finishFragment(); + } + })); + } + + private boolean loading; + private boolean valueSet; + private void setValue() { + if (loading || valueSet) return; + loading = true; + BusinessChatbotController.getInstance(currentAccount).load(bots -> { + currentValue = bots; + currentBot = currentValue == null || currentValue.connected_bots.isEmpty() ? null : currentValue.connected_bots.get(0); + selectedBot = currentBot == null ? null : getMessagesController().getUser(currentBot.bot_id); + allowReply = currentBot != null ? currentBot.can_reply : true; + exclude = currentBot != null ? currentBot.recipients.exclude_selected : true; + if (recipientsHelper != null) { + recipientsHelper.setValue(currentBot == null ? null : currentBot.recipients); + } + if (listView != null && listView.adapter != null) { + listView.adapter.update(true); + } + checkDone(true); + valueSet = true; + }); + } + + public boolean hasChanges() { + if (!valueSet) return false; + if ((selectedBot != null) != (currentBot != null)) return true; + if (selectedBot != null) { + if (allowReply != currentBot.can_reply) { + return true; + } + if (recipientsHelper != null && recipientsHelper.hasChanges()) { + return true; + } + } + return false; + } + + @Override + public boolean onBackPressed() { + if (hasChanges()) { + AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); + builder.setTitle(LocaleController.getString(R.string.UnsavedChanges)); + builder.setMessage(LocaleController.getString(R.string.BusinessBotUnsavedChanges)); + builder.setPositiveButton(LocaleController.getString("ApplyTheme", R.string.ApplyTheme), (dialogInterface, i) -> processDone()); + builder.setNegativeButton(LocaleController.getString("PassportDiscard", R.string.PassportDiscard), (dialog, which) -> finishFragment()); + showDialog(builder.create()); + return false; + } + return super.onBackPressed(); + } + + private void checkDone(boolean animated) { + if (doneButton == null) return; + final boolean hasChanges = hasChanges(); + doneButton.setEnabled(hasChanges); + if (animated) { + doneButton.animate().alpha(hasChanges ? 1.0f : 0.0f).scaleX(hasChanges ? 1.0f : 0.0f).scaleY(hasChanges ? 1.0f : 0.0f).setDuration(180).start(); + } else { + doneButton.setAlpha(hasChanges ? 1.0f : 0.0f); + doneButton.setScaleX(hasChanges ? 1.0f : 0.0f); + doneButton.setScaleY(hasChanges ? 1.0f : 0.0f); + } + } + + @Override + public boolean onFragmentCreate() { + setValue(); + return super.onFragmentCreate(); + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Business/GreetMessagesActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/Business/GreetMessagesActivity.java new file mode 100644 index 00000000000..db5e2c845c9 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Business/GreetMessagesActivity.java @@ -0,0 +1,333 @@ +package org.telegram.ui.Business; + +import static org.telegram.messenger.LocaleController.getString; + +import android.content.Context; +import android.graphics.PorterDuff; +import android.graphics.PorterDuffColorFilter; +import android.graphics.drawable.Drawable; +import android.os.Bundle; +import android.text.TextUtils; +import android.view.View; +import android.widget.FrameLayout; + +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.BotWebViewVibrationEffect; +import org.telegram.messenger.LocaleController; +import org.telegram.messenger.NotificationCenter; +import org.telegram.messenger.R; +import org.telegram.tgnet.TLRPC; +import org.telegram.ui.ActionBar.ActionBar; +import org.telegram.ui.ActionBar.ActionBarMenuItem; +import org.telegram.ui.ActionBar.AlertDialog; +import org.telegram.ui.ActionBar.BaseFragment; +import org.telegram.ui.ActionBar.Theme; +import org.telegram.ui.ChatActivity; +import org.telegram.ui.Components.BulletinFactory; +import org.telegram.ui.Components.CircularProgressDrawable; +import org.telegram.ui.Components.CrossfadeDrawable; +import org.telegram.ui.Components.LayoutHelper; +import org.telegram.ui.Components.UItem; +import org.telegram.ui.Components.UniversalAdapter; +import org.telegram.ui.Components.UniversalRecyclerView; + +import java.util.ArrayList; + +public class GreetMessagesActivity extends BaseFragment implements NotificationCenter.NotificationCenterDelegate { + + private static final int done_button = 1; + private CrossfadeDrawable doneButtonDrawable; + private ActionBarMenuItem doneButton; + + private UniversalRecyclerView listView; + private BusinessRecipientsHelper recipientsHelper; + + private final int[] daysOfInactivity = new int[] { 7, 14, 21, 28 }; + private final String[] daysOfInactivityTexts; + + public GreetMessagesActivity() { + daysOfInactivityTexts = new String[daysOfInactivity.length]; + for (int i = 0; i < daysOfInactivity.length; ++i) { + daysOfInactivityTexts[i] = LocaleController.formatPluralString("DaysSchedule", daysOfInactivity[i]); + } + } + + public static void preloadSticker(int currentAccount) { + + } + + @Override + public View createView(Context context) { + actionBar.setBackButtonImage(R.drawable.ic_ab_back); + actionBar.setAllowOverlayTitle(true); + actionBar.setTitle(getString(R.string.BusinessGreet)); + actionBar.setActionBarMenuOnItemClick(new ActionBar.ActionBarMenuOnItemClick() { + @Override + public void onItemClick(int id) { + if (id == -1) { + if (onBackPressed()) { + finishFragment(); + } + } else if (id == done_button) { + processDone(); + } + } + }); + + Drawable checkmark = context.getResources().getDrawable(R.drawable.ic_ab_done).mutate(); + checkmark.setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_actionBarDefaultIcon), PorterDuff.Mode.MULTIPLY)); + doneButtonDrawable = new CrossfadeDrawable(checkmark, new CircularProgressDrawable(Theme.getColor(Theme.key_actionBarDefaultIcon))); + doneButton = actionBar.createMenu().addItemWithWidth(done_button, doneButtonDrawable, AndroidUtilities.dp(56), LocaleController.getString("Done", R.string.Done)); + checkDone(false); + + FrameLayout contentView = new FrameLayout(context); + contentView.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundGray)); + + recipientsHelper = new BusinessRecipientsHelper(this, () -> { + listView.adapter.update(true); + checkDone(true); + }); + recipientsHelper.doNotExcludeNewChats(); + recipientsHelper.setValue(currentValue == null ? null : currentValue.recipients); + + listView = new UniversalRecyclerView(context, currentAccount, this::fillItems, this::onClick, null, getResourceProvider()); + contentView.addView(listView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); + setValue(); + + return fragmentView = contentView; + } + + private boolean valueSet; + private void setValue() { + if (valueSet) return; + + final long selfId = getUserConfig().getClientUserId(); + TLRPC.UserFull userFull = getMessagesController().getUserFull(selfId); + if (userFull == null) { + getMessagesController().loadUserInfo(getUserConfig().getCurrentUser(), true, getClassGuid()); + return; + } + + currentValue = userFull.business_greeting_message; + + enabled = currentValue != null; + inactivityDays = currentValue != null ? currentValue.no_activity_days : 7; + exclude = currentValue != null ? currentValue.recipients.exclude_selected : true; + if (recipientsHelper != null) { + recipientsHelper.setValue(currentValue == null ? null : currentValue.recipients); + } + + if (listView != null && listView.adapter != null) { + listView.adapter.update(true); + } + checkDone(true); + valueSet = true; + } + + public boolean hasChanges() { + if (!valueSet) return false; + if (enabled != (currentValue != null)) return true; + if (enabled && currentValue != null) { + if (currentValue.no_activity_days != inactivityDays) { + return true; + } + if (currentValue.recipients.exclude_selected != exclude) { + return true; + } + if (recipientsHelper != null && recipientsHelper.hasChanges()) { + return true; + } + } + return false; + } + + private void checkDone(boolean animated) { + if (doneButton == null) return; + final boolean hasChanges = hasChanges(); + doneButton.setEnabled(hasChanges); + if (animated) { + doneButton.animate().alpha(hasChanges ? 1.0f : 0.0f).scaleX(hasChanges ? 1.0f : 0.0f).scaleY(hasChanges ? 1.0f : 0.0f).setDuration(180).start(); + } else { + doneButton.setAlpha(hasChanges ? 1.0f : 0.0f); + doneButton.setScaleX(hasChanges ? 1.0f : 0.0f); + doneButton.setScaleY(hasChanges ? 1.0f : 0.0f); + } + } + + private int shiftDp = -4; + private void processDone() { + if (doneButtonDrawable.getProgress() > 0f) return; + + if (!hasChanges()) { + finishFragment(); + return; + } + + QuickRepliesController.QuickReply reply = QuickRepliesController.getInstance(currentAccount).findReply(QuickRepliesController.GREETING); + if (enabled && reply == null) { + BotWebViewVibrationEffect.APP_ERROR.vibrate(); + AndroidUtilities.shakeViewSpring(listView.findViewByItemId(BUTTON_CREATE), shiftDp = -shiftDp); + return; + } + + if (enabled && !recipientsHelper.validate(listView)) { + return; + } + + doneButtonDrawable.animateToProgress(1f); + TLRPC.UserFull userFull = getMessagesController().getUserFull(getUserConfig().getClientUserId()); + TLRPC.TL_account_updateBusinessGreetingMessage req = new TLRPC.TL_account_updateBusinessGreetingMessage(); + if (enabled) { + req.message = new TLRPC.TL_inputBusinessGreetingMessage(); + req.message.shortcut_id = reply.id; + req.message.recipients = recipientsHelper.getInputValue(); + req.message.no_activity_days = inactivityDays; + req.flags |= 1; + + if (userFull != null) { + userFull.flags2 |= 4; + userFull.business_greeting_message = new TLRPC.TL_businessGreetingMessage(); + userFull.business_greeting_message.shortcut_id = reply.id; + userFull.business_greeting_message.recipients = recipientsHelper.getValue(); + userFull.business_greeting_message.no_activity_days = inactivityDays; + } + } else { + if (userFull != null) { + userFull.flags2 &=~ 4; + userFull.business_greeting_message = null; + } + } + + getConnectionsManager().sendRequest(req, (res, err) -> AndroidUtilities.runOnUIThread(() -> { + if (err != null) { + doneButtonDrawable.animateToProgress(0f); + BulletinFactory.showError(err); + } else if (res instanceof TLRPC.TL_boolFalse) { + doneButtonDrawable.animateToProgress(0f); + BulletinFactory.of(this).createErrorBulletin(LocaleController.getString(R.string.UnknownError)).show(); + } else { + finishFragment(); + } + })); + getMessagesStorage().updateUserInfo(userFull, false); + } + + @Override + public boolean onBackPressed() { + if (hasChanges()) { + if (!enabled) { + processDone(); + return false; + } + AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); + builder.setTitle(LocaleController.getString(R.string.UnsavedChanges)); + builder.setMessage(LocaleController.getString(R.string.BusinessGreetUnsavedChanges)); + builder.setPositiveButton(LocaleController.getString("ApplyTheme", R.string.ApplyTheme), (dialogInterface, i) -> processDone()); + builder.setNegativeButton(LocaleController.getString("PassportDiscard", R.string.PassportDiscard), (dialog, which) -> finishFragment()); + showDialog(builder.create()); + return false; + } + return super.onBackPressed(); + } + + + public TLRPC.TL_businessGreetingMessage currentValue; + + public boolean enabled; + public boolean exclude; + public int inactivityDays = 7; + + private final static int BUTTON_ENABLE = 1; + private final static int BUTTON_CREATE = 2; + private static final int RADIO_PRIVATE_CHATS = 3; + private static final int RADIO_ALL_CHATS = 4; + + private void fillItems(ArrayList items, UniversalAdapter adapter) { + items.add(UItem.asTopView(getString(R.string.BusinessGreetInfo), "RestrictedEmoji", "👋")); + items.add(UItem.asCheck(BUTTON_ENABLE, getString(R.string.BusinessGreetSend)).setChecked(enabled)); + items.add(UItem.asShadow(null)); + if (enabled) { + QuickRepliesController.QuickReply reply = QuickRepliesController.getInstance(currentAccount).findReply(QuickRepliesController.GREETING); + if (reply != null) { + items.add(UItem.asLargeQuickReply(reply)); + } else { + items.add(UItem.asButton(BUTTON_CREATE, R.drawable.msg2_chats_add, getString(R.string.BusinessGreetCreate)).accent()); + } + items.add(UItem.asShadow(null)); + items.add(UItem.asHeader(getString(R.string.BusinessRecipients))); + items.add(UItem.asRadio(RADIO_PRIVATE_CHATS, getString(R.string.BusinessChatsAllPrivateExcept)).setChecked(exclude)); + items.add(UItem.asRadio(RADIO_ALL_CHATS, getString(R.string.BusinessChatsOnlySelected)).setChecked(!exclude)); + items.add(UItem.asShadow(null)); + recipientsHelper.fillItems(items); + items.add(UItem.asShadow(getString(R.string.BusinessGreetRecipientsInfo))); + items.add(UItem.asHeader(getString(R.string.BusinessGreetPeriod))); + int daysIndex = -1; + for (int i = 0; i < daysOfInactivity.length; ++i) { + if (daysOfInactivity[i] == inactivityDays) { + daysIndex = i; + break; + } + } + items.add(UItem.asSlideView(daysOfInactivityTexts, daysIndex, this::chooseInactivity)); + items.add(UItem.asShadow(getString(R.string.BusinessGreetPeriodInfo))); + } + } + + private void chooseInactivity(int index) { + inactivityDays = daysOfInactivity[index]; + checkDone(true); + } + + private void onClick(UItem item, View view, int position, float x, float y) { + if (recipientsHelper.onClick(item)) { + return; + } + if (item.id == BUTTON_CREATE || item.viewType == UniversalAdapter.VIEW_TYPE_LARGE_QUICK_REPLY) { + Bundle args = new Bundle(); + args.putLong("user_id", getUserConfig().getClientUserId()); + args.putInt("chatMode", ChatActivity.MODE_QUICK_REPLIES); + args.putString("quick_reply", QuickRepliesController.GREETING); + presentFragment(new ChatActivity(args)); + } else if (item.id == BUTTON_ENABLE) { + enabled = !enabled; + listView.adapter.update(true); + checkDone(true); + } else if (item.id == RADIO_PRIVATE_CHATS) { + recipientsHelper.setExclude(exclude = true); + listView.adapter.update(true); + checkDone(true); + } else if (item.id == RADIO_ALL_CHATS) { + recipientsHelper.setExclude(exclude = false); + listView.adapter.update(true); + checkDone(true); + } + } + + @Override + public void didReceivedNotification(int id, int account, Object... args) { + if (id == NotificationCenter.quickRepliesUpdated) { + if (listView != null && listView.adapter != null) { + listView.adapter.update(true); + } + checkDone(true); + } else if (id == NotificationCenter.userInfoDidLoad) { + setValue(); + } + } + + @Override + public boolean onFragmentCreate() { + getNotificationCenter().addObserver(this, NotificationCenter.quickRepliesUpdated); + getNotificationCenter().addObserver(this, NotificationCenter.userInfoDidLoad); + QuickRepliesController.getInstance(currentAccount).load(); + setValue(); + return super.onFragmentCreate(); + } + + @Override + public void onFragmentDestroy() { + getNotificationCenter().removeObserver(this, NotificationCenter.quickRepliesUpdated); + getNotificationCenter().removeObserver(this, NotificationCenter.userInfoDidLoad); + super.onFragmentDestroy(); + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Business/LocationActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/Business/LocationActivity.java new file mode 100644 index 00000000000..e287f5179df --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Business/LocationActivity.java @@ -0,0 +1,571 @@ +package org.telegram.ui.Business; + +import static org.telegram.messenger.AndroidUtilities.dp; +import static org.telegram.messenger.LocaleController.getString; + +import android.app.Activity; +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.PorterDuff; +import android.graphics.PorterDuffColorFilter; +import android.graphics.drawable.Drawable; +import android.location.Address; +import android.location.Geocoder; +import android.text.Editable; +import android.text.InputFilter; +import android.text.InputType; +import android.text.Spanned; +import android.text.TextUtils; +import android.text.TextWatcher; +import android.util.TypedValue; +import android.view.Gravity; +import android.view.MotionEvent; +import android.view.View; +import android.view.inputmethod.EditorInfo; +import android.widget.FrameLayout; +import android.widget.LinearLayout; + +import androidx.annotation.NonNull; + +import org.checkerframework.checker.units.qual.A; +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.ApplicationLoader; +import org.telegram.messenger.BotWebViewVibrationEffect; +import org.telegram.messenger.DocumentObject; +import org.telegram.messenger.FileLog; +import org.telegram.messenger.ImageReceiver; +import org.telegram.messenger.LocaleController; +import org.telegram.messenger.NotificationCenter; +import org.telegram.messenger.R; +import org.telegram.messenger.SvgHelper; +import org.telegram.messenger.UserConfig; +import org.telegram.messenger.Utilities; +import org.telegram.tgnet.TLRPC; +import org.telegram.tgnet.tl.TL_stories; +import org.telegram.ui.ActionBar.ActionBar; +import org.telegram.ui.ActionBar.ActionBarMenuItem; +import org.telegram.ui.ActionBar.AlertDialog; +import org.telegram.ui.ActionBar.BaseFragment; +import org.telegram.ui.ActionBar.Theme; +import org.telegram.ui.ChatActivity; +import org.telegram.ui.Components.AnimatedColor; +import org.telegram.ui.Components.AnimatedTextView; +import org.telegram.ui.Components.AvatarDrawable; +import org.telegram.ui.Components.BackupImageView; +import org.telegram.ui.Components.BulletinFactory; +import org.telegram.ui.Components.ChatAttachAlert; +import org.telegram.ui.Components.ChatAttachAlertLocationLayout; +import org.telegram.ui.Components.CircularProgressDrawable; +import org.telegram.ui.Components.ClipRoundedDrawable; +import org.telegram.ui.Components.CrossfadeDrawable; +import org.telegram.ui.Components.CubicBezierInterpolator; +import org.telegram.ui.Components.EditTextBoldCursor; +import org.telegram.ui.Components.LayoutHelper; +import org.telegram.ui.Components.LoadingDrawable; +import org.telegram.ui.Components.Paint.Views.LocationView; +import org.telegram.ui.Components.UItem; +import org.telegram.ui.Components.UniversalAdapter; +import org.telegram.ui.Components.UniversalRecyclerView; +import org.telegram.ui.Stories.recorder.PaintView; + +import java.util.ArrayList; +import java.util.List; + +public class LocationActivity extends BaseFragment implements NotificationCenter.NotificationCenterDelegate { + + private UniversalRecyclerView listView; + + private static final int done_button = 1; + private CrossfadeDrawable doneButtonDrawable; + private ActionBarMenuItem doneButton; + + private boolean ignoreEditText; + private FrameLayout editTextContainer; + private EditTextBoldCursor editText; + + private FrameLayout mapPreviewContainer; + private View mapMarker; + private ClipRoundedDrawable mapLoadingDrawable; + private BackupImageView mapPreview; + + final int MAX_NAME_LENGTH = 96; + @Override + public View createView(Context context) { + actionBar.setBackButtonImage(R.drawable.ic_ab_back); + actionBar.setAllowOverlayTitle(true); + actionBar.setTitle(getString(R.string.BusinessLocation)); + actionBar.setActionBarMenuOnItemClick(new ActionBar.ActionBarMenuOnItemClick() { + @Override + public void onItemClick(int id) { + if (id == -1) { + if (onBackPressed()) { + finishFragment(); + } + } else if (id == done_button) { + processDone(); + } + } + }); + + Drawable checkmark = context.getResources().getDrawable(R.drawable.ic_ab_done).mutate(); + checkmark.setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_actionBarDefaultIcon), PorterDuff.Mode.MULTIPLY)); + doneButtonDrawable = new CrossfadeDrawable(checkmark, new CircularProgressDrawable(Theme.getColor(Theme.key_actionBarDefaultIcon))); + doneButton = actionBar.createMenu().addItemWithWidth(done_button, doneButtonDrawable, AndroidUtilities.dp(56), LocaleController.getString("Done", R.string.Done)); + checkDone(false); + + FrameLayout contentView = new FrameLayout(context); + contentView.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundGray)); + + LinearLayout content = new LinearLayout(getContext()); + content.setOrientation(LinearLayout.HORIZONTAL); + editText = new EditTextBoldCursor(getContext()) { + AnimatedColor limitColor = new AnimatedColor(this); + private int limitCount; + AnimatedTextView.AnimatedTextDrawable limit = new AnimatedTextView.AnimatedTextDrawable(false, true, true); { + limit.setAnimationProperties(.2f, 0, 160, CubicBezierInterpolator.EASE_OUT_QUINT); + limit.setTextSize(dp(15.33f)); + limit.setCallback(this); + limit.setGravity(Gravity.RIGHT); + } + @Override + protected boolean verifyDrawable(@NonNull Drawable who) { + return who == limit || super.verifyDrawable(who); + } + @Override + protected void onTextChanged(CharSequence text, int start, int lengthBefore, int lengthAfter) { + super.onTextChanged(text, start, lengthBefore, lengthAfter); + + if (limit != null) { + limitCount = MAX_NAME_LENGTH - text.length(); + limit.cancelAnimation(); + limit.setText(limitCount > 12 ? "" : "" + limitCount); + } + } + @Override + protected void dispatchDraw(Canvas canvas) { + super.dispatchDraw(canvas); + limit.setTextColor(limitColor.set(Theme.getColor(limitCount < 0 ? Theme.key_text_RedRegular : Theme.key_dialogSearchHint, getResourceProvider()))); + limit.setBounds(getScrollX(), 0, getScrollX() + getWidth(), getHeight()); + limit.draw(canvas); + } + }; + editText.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 17); + editText.setHintTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteHintText)); + editText.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlackText)); + editText.setBackgroundDrawable(null); + editText.setMaxLines(5); + editText.setSingleLine(false); + editText.setPadding(0, 0, dp(42), 0); + editText.setGravity((LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.TOP); + editText.setInputType(InputType.TYPE_TEXT_FLAG_CAP_SENTENCES | InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_FLAG_MULTI_LINE | InputType.TYPE_TEXT_FLAG_AUTO_CORRECT); + editText.setHint(getString(R.string.BusinessLocationAddress)); + editText.setCursorColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlackText)); + editText.setCursorSize(dp(19)); + editText.setCursorWidth(1.5f); + editText.addTextChangedListener(new TextWatcher() { + @Override + public void beforeTextChanged(CharSequence charSequence, int i, int i2, int i3) {} + @Override + public void onTextChanged(CharSequence charSequence, int i, int i2, int i3) {} + @Override + public void afterTextChanged(Editable editable) { + if (!ignoreEditText) { + mapAddress = false; + address = editable.toString(); + checkDone(true); + } + } + }); + editText.setFilters(new InputFilter[] { + new InputFilter() { + @Override + public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) { + if (source != null) { + String s = source.toString(); + if (s.contains("\n")) { + return s.replaceAll("\n", ""); + } + } + return null; + } + } + }); + editTextContainer = new FrameLayout(context); + editTextContainer.addView(editText, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.TOP, 21, 15, 21, 15)); + editTextContainer.setBackgroundColor(getThemedColor(Theme.key_windowBackgroundWhite)); + if (editText != null) { + editText.setText(address); + editText.setSelection(editText.getText().length()); + } + +// mapLoadingDrawable = new LoadingDrawable(resourceProvider); +// mapLoadingDrawable.setColors( +// Theme.multAlpha(getThemedColor(Theme.key_windowBackgroundWhiteBlackText), .025f), +// Theme.multAlpha(getThemedColor(Theme.key_windowBackgroundWhiteBlackText), Theme.isCurrentThemeDark() ? .25f : .12f) +// ); + mapPreview = new BackupImageView(context) { + @Override + protected ImageReceiver createImageReciever() { + return new ImageReceiver(this) { + @Override + protected boolean setImageBitmapByKey(Drawable drawable, String key, int type, boolean memCache, int guid) { + if (drawable != null && type != TYPE_THUMB) { + mapMarker.animate().alpha(1f).translationY(0).setInterpolator(CubicBezierInterpolator.EASE_OUT_BACK).setDuration(250).start(); + } + return super.setImageBitmapByKey(drawable, key, type, memCache, guid); + } + }; + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(dp(240), MeasureSpec.EXACTLY)); + } + @Override + protected boolean verifyDrawable(@NonNull Drawable who) { + return who == mapLoadingDrawable || super.verifyDrawable(who); + } + }; + SvgHelper.SvgDrawable svgThumb = DocumentObject.getSvgThumb(R.raw.map_placeholder, Theme.key_chat_outLocationIcon, .2f); + svgThumb.setColorKey(Theme.key_windowBackgroundWhiteBlackText, getResourceProvider()); + svgThumb.setAspectCenter(true); + svgThumb.setParent(mapPreview.getImageReceiver()); + mapLoadingDrawable = new ClipRoundedDrawable(svgThumb); + mapLoadingDrawable.setCallback(mapPreview); + mapPreview.setBackgroundColor(getThemedColor(Theme.key_windowBackgroundWhite)); + + mapMarker = new View(context) { + final Drawable pin = getContext().getResources().getDrawable(R.drawable.map_pin_photo).mutate(); + final AvatarDrawable avatarDrawable = new AvatarDrawable(); + final ImageReceiver avatarImage = new ImageReceiver(this); + { + avatarDrawable.setInfo(getUserConfig().getCurrentUser()); + avatarImage.setForUserOrChat(getUserConfig().getCurrentUser(), avatarDrawable); + } + @Override + protected void dispatchDraw(Canvas canvas) { + pin.setBounds(0, 0, dp(62), dp(85)); + pin.draw(canvas); + avatarImage.setRoundRadius(dp(62)); + avatarImage.setImageCoords(dp(6), dp(6), dp(50), dp(50)); + avatarImage.draw(canvas); + } + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(MeasureSpec.makeMeasureSpec(dp(62), MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(dp(85), MeasureSpec.EXACTLY)); + } + }; + + mapPreviewContainer = new FrameLayout(context); + mapPreviewContainer.addView(mapPreview, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); + mapPreviewContainer.addView(mapMarker, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER, 0, -31, 0, 0)); + updateMapPreview(); + + listView = new UniversalRecyclerView(context, currentAccount, this::fillItems, this::onClick, null, getResourceProvider()); + contentView.addView(listView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); + + setValue(); + + return fragmentView = contentView; + } + + @Override + public boolean onFragmentCreate() { + getNotificationCenter().addObserver(this, NotificationCenter.userInfoDidLoad); + return super.onFragmentCreate(); + } + + @Override + public void onFragmentDestroy() { + getNotificationCenter().removeObserver(this, NotificationCenter.userInfoDidLoad); + super.onFragmentDestroy(); + } + + @Override + public void didReceivedNotification(int id, int account, Object... args) { + if (id == NotificationCenter.userInfoDidLoad) { + setValue(); + } + } + + private boolean valueSet; + private void setValue() { + if (valueSet) return; + + final long selfId = getUserConfig().getClientUserId(); + TLRPC.UserFull userFull = getMessagesController().getUserFull(selfId); + if (userFull == null) { + getMessagesController().loadUserInfo(getUserConfig().getCurrentUser(), true, getClassGuid()); + return; + } + + currentLocation = userFull.business_location; + if (currentLocation != null) { + geo = currentLocation.geo_point; + address = currentLocation.address; + } else { + geo = null; + address = ""; + } + + if (editText != null) { + editText.setText(address); + editText.setSelection(editText.getText().length()); + } + updateMapPreview(); + if (listView != null && listView.adapter != null) { + listView.adapter.update(true); + } + valueSet = true; + } + + private void updateMapPreview() { + if (mapMarker == null || mapPreview == null) return; + if (geo != null) { + mapMarker.setAlpha(0f); + mapMarker.setTranslationY(-dp(12)); + final int w = (int) ((mapPreview.getMeasuredWidth() <= 0 ? AndroidUtilities.displaySize.x : mapPreview.getMeasuredWidth()) / AndroidUtilities.density); + final int h = 240; + String url = AndroidUtilities.formapMapUrl(currentAccount, geo.lat, geo._long, w, h, false, 15, -1); + mapPreview.setImage(url, w + "_" + h, mapLoadingDrawable); + } else { + mapPreview.setImageBitmap(null); + } + } + + private TLRPC.TL_businessLocation currentLocation; + private TLRPC.GeoPoint geo; + private String address; + private boolean mapAddress; + + public boolean hasChanges() { + if ((geo != null || !TextUtils.isEmpty(address)) != (currentLocation != null)) { + return true; + } + if ((geo != null || !TextUtils.isEmpty(address)) != (currentLocation != null && !(currentLocation.geo_point instanceof TLRPC.TL_geoPointEmpty))) { + return true; + } + if (!TextUtils.equals(address, currentLocation != null ? currentLocation.address : "")) { + return true; + } + if ((geo != null) != (currentLocation != null && currentLocation.geo_point != null)) { + return true; + } + if (geo != null && (currentLocation == null || currentLocation.geo_point == null || !(currentLocation.geo_point instanceof TLRPC.TL_geoPointEmpty) && (geo.lat != currentLocation.geo_point.lat || geo._long != currentLocation.geo_point._long))) { + return true; + } + return false; + } + + private void checkDone(boolean animated) { + if (doneButton == null) return; + final boolean hasChanges = hasChanges(); + doneButton.setEnabled(hasChanges); + if (animated) { + doneButton.animate().alpha(hasChanges ? 1.0f : 0.0f).scaleX(hasChanges ? 1.0f : 0.0f).scaleY(hasChanges ? 1.0f : 0.0f).setDuration(180).start(); + } else { + doneButton.setAlpha(hasChanges ? 1.0f : 0.0f); + doneButton.setScaleX(hasChanges ? 1.0f : 0.0f); + doneButton.setScaleY(hasChanges ? 1.0f : 0.0f); + } + if (listView != null && listView.adapter != null && clearVisible != (currentLocation != null && (geo != null || !TextUtils.isEmpty(address)))) { + listView.adapter.update(true); + } + } + + private int shiftDp = -4; + private void processDone() { + if (doneButtonDrawable.getProgress() > 0f) return; + + final boolean empty = geo == null && TextUtils.isEmpty(address); + if (!empty) { + if (!hasChanges()) { + finishFragment(); + return; + } + + final String address = this.address == null ? "" : this.address.trim(); + if (TextUtils.isEmpty(address) || address.length() > MAX_NAME_LENGTH) { + BotWebViewVibrationEffect.APP_ERROR.vibrate(); + AndroidUtilities.shakeViewSpring(editText, shiftDp = -shiftDp); + return; + } + } + + doneButtonDrawable.animateToProgress(1f); + TLRPC.UserFull userFull = getMessagesController().getUserFull(getUserConfig().getClientUserId()); + TLRPC.TL_account_updateBusinessLocation req = new TLRPC.TL_account_updateBusinessLocation(); + if (!empty) { + if (geo != null) { + req.flags |= 2; + req.geo_point = new TLRPC.TL_inputGeoPoint(); + req.geo_point.lat = geo.lat; + req.geo_point._long = geo._long; + } + req.flags |= 1; + req.address = address; + + if (userFull != null) { + userFull.flags2 |= 2; + userFull.business_location = new TLRPC.TL_businessLocation(); + userFull.business_location.address = address; + if (geo != null) { + userFull.business_location.flags |= 1; + userFull.business_location.geo_point = new TLRPC.TL_geoPoint(); + userFull.business_location.geo_point.lat = geo.lat; + userFull.business_location.geo_point._long = geo._long; + } + } + } else { + if (userFull != null) { + userFull.flags2 &=~ 2; + userFull.business_location = null; + } + } + + getConnectionsManager().sendRequest(req, (res, err) -> AndroidUtilities.runOnUIThread(() -> { + if (err != null) { + doneButtonDrawable.animateToProgress(0f); + BulletinFactory.showError(err); + } else if (res instanceof TLRPC.TL_boolFalse) { + doneButtonDrawable.animateToProgress(0f); + BulletinFactory.of(this).createErrorBulletin(LocaleController.getString(R.string.UnknownError)).show(); + } else { + finishFragment(); + } + })); + getMessagesStorage().updateUserInfo(userFull, false); + } + + @Override + public boolean onBackPressed() { + final boolean empty = geo == null && TextUtils.isEmpty(address); + if (hasChanges() && !empty) { + AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); + builder.setTitle(LocaleController.getString(R.string.UnsavedChanges)); + builder.setMessage(LocaleController.getString(R.string.BusinessLocationUnsavedChanges)); + builder.setPositiveButton(LocaleController.getString("ApplyTheme", R.string.ApplyTheme), (dialogInterface, i) -> processDone()); + builder.setNegativeButton(LocaleController.getString("PassportDiscard", R.string.PassportDiscard), (dialog, which) -> finishFragment()); + showDialog(builder.create()); + return false; + } + return super.onBackPressed(); + } + + @Override + public boolean isSwipeBackEnabled(MotionEvent event) { + return !hasChanges(); + } + + private boolean clearVisible; + private final int BUTTON_MAP = 1; + private final int BUTTON_CLEAR = 2; + + private void fillItems(ArrayList items, UniversalAdapter adapter) { + items.add(UItem.asTopView(getString(R.string.BusinessLocationInfo), R.raw.biz_map)); + items.add(UItem.asCustom(editTextContainer)); + items.add(UItem.asShadow(null)); + items.add(UItem.asCheck(BUTTON_MAP, getString(R.string.BusinessLocationMap)).setChecked(geo != null)); + if (geo != null) { + items.add(UItem.asCustom(mapPreviewContainer)); + } + items.add(UItem.asShadow(null)); + if (clearVisible = (currentLocation != null && (geo != null || !TextUtils.isEmpty(address)))) { + items.add(UItem.asButton(BUTTON_CLEAR, LocaleController.getString(R.string.BusinessLocationClear)).red()); + items.add(UItem.asShadow(null)); + } + checkDone(true); + } + + private void onClick(UItem item, View view, int position, float x, float y) { + if (item.id == BUTTON_MAP || item.view == mapPreviewContainer) { + if (geo == null || item.view == mapPreviewContainer) { + showLocationAlert(); + } else { + geo = null; + listView.adapter.update(true); + } + } else if (item.id == BUTTON_CLEAR) { + AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); + builder.setTitle(LocaleController.getString(R.string.BusinessLocationClearTitle)); + builder.setMessage(LocaleController.getString(R.string.BusinessLocationClearMessage)); + builder.setPositiveButton(LocaleController.getString(R.string.Remove), (di, w) -> { + doneButtonDrawable.animateToProgress(1f); + TLRPC.UserFull userFull = getMessagesController().getUserFull(getUserConfig().getClientUserId()); + TLRPC.TL_account_updateBusinessLocation req = new TLRPC.TL_account_updateBusinessLocation(); + if (userFull != null) { + userFull.business_location = null; + userFull.flags2 &=~ 2; + } + getConnectionsManager().sendRequest(req, (res, err) -> AndroidUtilities.runOnUIThread(() -> { + doneButtonDrawable.animateToProgress(0f); + if (err != null) { + BulletinFactory.showError(err); + } else if (res instanceof TLRPC.TL_boolFalse) { + BulletinFactory.of(this).createErrorBulletin(LocaleController.getString(R.string.UnknownError)).show(); + } else { + finishFragment(); + } + })); + }); + builder.setNegativeButton(LocaleController.getString(R.string.Cancel), null); + showDialog(builder.create()); + } + } + + private void showLocationAlert() { + org.telegram.ui.LocationActivity fragment = new org.telegram.ui.LocationActivity(ChatAttachAlertLocationLayout.LOCATION_TYPE_BIZ); + if (geo != null) { + TLRPC.TL_channelLocation initialLocation = new TLRPC.TL_channelLocation(); + initialLocation.address = address; + initialLocation.geo_point = geo; + fragment.setInitialLocation(initialLocation); + } + fragment.setDelegate((location, live, notify, scheduleDate) -> { + geo = location.geo; + if (TextUtils.isEmpty(address) && !TextUtils.isEmpty(fragment.getAddressName()) || mapAddress) { + mapAddress = true; + address = fragment.getAddressName(); + if (address == null) address = ""; + if (editText != null) { + ignoreEditText = true; + editText.setText(address); + editText.setSelection(editText.getText().length()); + ignoreEditText = false; + } + } + updateMapPreview(); + listView.adapter.update(true); + checkDone(true); + }); + if (geo == null && !TextUtils.isEmpty(address)) { + AlertDialog progressDialog = new AlertDialog(getContext(), AlertDialog.ALERT_TYPE_SPINNER); + progressDialog.setCanCancel(false); + progressDialog.showDelayed(200); + Utilities.searchQueue.postRunnable(() -> { + try { + Geocoder geocoder = new Geocoder(getContext(), LocaleController.getInstance().getCurrentLocale()); + List
addresses = geocoder.getFromLocationName(address, 1); + if (!addresses.isEmpty()) { + Address geoAddress = addresses.get(0); + TLRPC.TL_channelLocation initialLocation = new TLRPC.TL_channelLocation(); + initialLocation.address = address; + initialLocation.geo_point = new TLRPC.TL_geoPoint(); + initialLocation.geo_point.lat = geoAddress.getLatitude(); + initialLocation.geo_point._long = geoAddress.getLongitude(); + fragment.setInitialLocation(initialLocation); + } + } catch (Exception e) { + FileLog.e(e); + } + AndroidUtilities.runOnUIThread(() -> { + progressDialog.dismiss(); + presentFragment(fragment); + }); + }); + } else { + presentFragment(fragment); + } + } + +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Business/OpeningHoursActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/Business/OpeningHoursActivity.java new file mode 100644 index 00000000000..2234e20f8ef --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Business/OpeningHoursActivity.java @@ -0,0 +1,605 @@ +package org.telegram.ui.Business; + +import static org.telegram.messenger.AndroidUtilities.dp; +import static org.telegram.messenger.LocaleController.getString; + +import android.content.Context; +import android.graphics.PorterDuff; +import android.graphics.PorterDuffColorFilter; +import android.graphics.drawable.Drawable; +import android.text.TextUtils; +import android.view.View; +import android.widget.FrameLayout; + +import androidx.annotation.NonNull; + +import org.checkerframework.checker.units.qual.A; +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.BotWebViewVibrationEffect; +import org.telegram.messenger.LocaleController; +import org.telegram.messenger.MessagesController; +import org.telegram.messenger.NotificationCenter; +import org.telegram.messenger.R; +import org.telegram.messenger.Utilities; +import org.telegram.tgnet.AbstractSerializedData; +import org.telegram.tgnet.TLObject; +import org.telegram.tgnet.TLRPC; +import org.telegram.ui.ActionBar.ActionBar; +import org.telegram.ui.ActionBar.ActionBarMenuItem; +import org.telegram.ui.ActionBar.AlertDialog; +import org.telegram.ui.ActionBar.BaseFragment; +import org.telegram.ui.ActionBar.BottomSheet; +import org.telegram.ui.ActionBar.Theme; +import org.telegram.ui.Cells.NotificationsCheckCell; +import org.telegram.ui.Cells.TextCell; +import org.telegram.ui.Cells.TextCheckCell; +import org.telegram.ui.Components.AlertsCreator; +import org.telegram.ui.Components.BottomSheetWithRecyclerListView; +import org.telegram.ui.Components.BulletinFactory; +import org.telegram.ui.Components.CircularProgressDrawable; +import org.telegram.ui.Components.CrossfadeDrawable; +import org.telegram.ui.Components.LayoutHelper; +import org.telegram.ui.Components.RecyclerListView; +import org.telegram.ui.Components.UItem; +import org.telegram.ui.Components.UniversalAdapter; +import org.telegram.ui.Components.UniversalRecyclerView; + +import java.time.DayOfWeek; +import java.time.ZoneId; +import java.time.format.TextStyle; +import java.util.ArrayList; +import java.util.Calendar; +import java.util.Collections; +import java.util.TimeZone; + +public class OpeningHoursActivity extends BaseFragment implements NotificationCenter.NotificationCenterDelegate { + + public static final int PERIODS_COUNT_LIMIT = 28; + + private UniversalRecyclerView listView; + + private static final int done_button = 1; + private CrossfadeDrawable doneButtonDrawable; + private ActionBarMenuItem doneButton; + + @Override + public View createView(Context context) { + actionBar.setBackButtonImage(R.drawable.ic_ab_back); + actionBar.setAllowOverlayTitle(true); + actionBar.setTitle(getString(R.string.BusinessHours)); + actionBar.setActionBarMenuOnItemClick(new ActionBar.ActionBarMenuOnItemClick() { + @Override + public void onItemClick(int id) { + if (id == -1) { + if (onBackPressed()) { + finishFragment(); + } + } else if (id == done_button) { + processDone(); + } + } + }); + + Drawable checkmark = context.getResources().getDrawable(R.drawable.ic_ab_done).mutate(); + checkmark.setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_actionBarDefaultIcon), PorterDuff.Mode.MULTIPLY)); + doneButtonDrawable = new CrossfadeDrawable(checkmark, new CircularProgressDrawable(Theme.getColor(Theme.key_actionBarDefaultIcon))); + doneButton = actionBar.createMenu().addItemWithWidth(done_button, doneButtonDrawable, AndroidUtilities.dp(56), LocaleController.getString("Done", R.string.Done)); + checkDone(false); + + FrameLayout contentView = new FrameLayout(context); + contentView.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundGray)); + + listView = new UniversalRecyclerView(context, currentAccount, this::fillItems, this::onClick, null, getResourceProvider()); + contentView.addView(listView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); + + setValue(); + + return fragmentView = contentView; + } + + public boolean hasChanges() { + if ((currentValue != null) != enabled) { + return true; + } + if (!TextUtils.equals(currentTimezoneId, timezoneId)) { + return true; + } + if (currentValue != null && enabled) { + if (value == null) return true; + for (int i = 0; i < currentValue.length; ++i) { + if (currentValue[i].size() != value[i].size()) + return true; + for (int j = 0; j < value[i].size(); ++j) { + Period a = currentValue[i].get(j); + Period b = value[i].get(j); + if (a.start != b.start || a.end != b.end) { + return true; + } + } + } + } + return false; + } + + private void checkDone(boolean animated) { + if (doneButton == null) return; + final boolean hasChanges = hasChanges(); + doneButton.setEnabled(hasChanges); + if (animated) { + doneButton.animate().alpha(hasChanges ? 1.0f : 0.0f).scaleX(hasChanges ? 1.0f : 0.0f).scaleY(hasChanges ? 1.0f : 0.0f).setDuration(180).start(); + } else { + doneButton.setAlpha(hasChanges ? 1.0f : 0.0f); + doneButton.setScaleX(hasChanges ? 1.0f : 0.0f); + doneButton.setScaleY(hasChanges ? 1.0f : 0.0f); + } + } + + @Override + public boolean onFragmentCreate() { + TimezonesController.getInstance(currentAccount).load(); + timezoneId = TimezonesController.getInstance(currentAccount).getSystemTimezoneId(); + getNotificationCenter().addObserver(this, NotificationCenter.userInfoDidLoad); + return super.onFragmentCreate(); + } + + @Override + public void onFragmentDestroy() { + getNotificationCenter().removeObserver(this, NotificationCenter.userInfoDidLoad); + super.onFragmentDestroy(); + processDone(); + } + + @Override + public void didReceivedNotification(int id, int account, Object... args) { + if (id == NotificationCenter.userInfoDidLoad) { + setValue(); + } else if (id == NotificationCenter.timezonesUpdated) { + if (currentValue == null) { + timezoneId = TimezonesController.getInstance(currentAccount).getSystemTimezoneId(); + } + if (listView != null && listView.adapter != null) { + listView.adapter.update(true); + } + } + } + + private boolean valueSet; + private void setValue() { + if (valueSet) return; + + final long selfId = getUserConfig().getClientUserId(); + TLRPC.UserFull userFull = getMessagesController().getUserFull(selfId); + if (userFull == null) { + getMessagesController().loadUserInfo(getUserConfig().getCurrentUser(), true, getClassGuid()); + return; + } + + if (enabled = userFull.business_work_hours != null) { + currentTimezoneId = timezoneId = userFull.business_work_hours.timezone_id; + currentValue = getDaysHours(userFull.business_work_hours.weekly_open); + value = getDaysHours(userFull.business_work_hours.weekly_open); + } else { + currentTimezoneId = timezoneId = TimezonesController.getInstance(currentAccount).getSystemTimezoneId(); + currentValue = null; + value = new ArrayList[7]; + for (int i = 0; i < value.length; ++i) { + value[i] = new ArrayList<>(); + } + } + + if (listView != null && listView.adapter != null) { + listView.adapter.update(true); + } + checkDone(false); + + valueSet = true; + } + + public static ArrayList adaptWeeklyOpen(ArrayList hours, int utc_offset) { + ArrayList array = new ArrayList<>(hours); + +// // join together weeklies +// Collections.sort(array, (a, b) -> a.start_minute - b.start_minute); +// for (int i = 0; i < array.size() - 1; ++i) { +// if (i + 1 >= array.size()) continue; +// TLRPC.TL_businessWeeklyOpen weekly = array.get(i); +// TLRPC.TL_businessWeeklyOpen nextWeekly = array.get(i + 1); +// if (weekly.end_minute + 1 >= nextWeekly.start_minute) { +// TLRPC.TL_businessWeeklyOpen newWeekly = new TLRPC.TL_businessWeeklyOpen(); +// newWeekly.start_minute = weekly.start_minute; +// newWeekly.end_minute = nextWeekly.end_minute; +// array.set(i, newWeekly); +// array.remove(i + 1); +// i--; +// } +// } + + ArrayList array2 = new ArrayList<>(array.size()); + for (int i = 0; i < array.size(); ++i) { + TLRPC.TL_businessWeeklyOpen weekly = array.get(i); + TLRPC.TL_businessWeeklyOpen newWeekly = new TLRPC.TL_businessWeeklyOpen(); + + if (utc_offset != 0) { + int start = weekly.start_minute % (24 * 60); + int end = start + (weekly.end_minute - weekly.start_minute); + if (start == 0 && (end == 24 * 60 || end == 24 * 60 - 1)) { + newWeekly.start_minute = weekly.start_minute; + newWeekly.end_minute = weekly.end_minute; + array2.add(newWeekly); + continue; + } + } + + newWeekly.start_minute = weekly.start_minute + utc_offset; + newWeekly.end_minute = weekly.end_minute + utc_offset; + array2.add(newWeekly); + + if (newWeekly.start_minute < 0) { + if (newWeekly.end_minute < 0) { + newWeekly.start_minute += 24 * 7 * 60; + newWeekly.end_minute += 24 * 7 * 60; + } else { + newWeekly.start_minute = 0; + + newWeekly = new TLRPC.TL_businessWeeklyOpen(); + newWeekly.start_minute = 24 * 7 * 60 + weekly.start_minute + utc_offset; + newWeekly.end_minute = (24 * 7 * 60 - 1); + array2.add(newWeekly); + } + } else if (newWeekly.end_minute > 24 * 7 * 60) { + if (newWeekly.start_minute > 24 * 7 * 60) { + newWeekly.start_minute -= 24 * 7 * 60; + newWeekly.end_minute -= 24 * 7 * 60; + } else { + newWeekly.end_minute = 24 * 7 * 60 - 1; + + newWeekly = new TLRPC.TL_businessWeeklyOpen(); + newWeekly.start_minute = 0; + newWeekly.end_minute = weekly.end_minute + utc_offset - (24 * 7 * 60 - 1); + array2.add(newWeekly); + } + } + } + + Collections.sort(array2, (a, b) -> a.start_minute - b.start_minute); + return array2; + } + + public static ArrayList[] getDaysHours(ArrayList hours) { + ArrayList[] days = new ArrayList[7]; + for (int i = 0; i < days.length; ++i) { + days[i] = new ArrayList<>(); + } + for (int i = 0; i < hours.size(); ++i) { + TLRPC.TL_businessWeeklyOpen period = hours.get(i); + int day = (int) (period.start_minute / (24 * 60)) % 7; + int start = period.start_minute % (24 * 60); + int end = start + (period.end_minute - period.start_minute); + days[day].add(new Period(start, end)); + } + for (int i = 0; i < 7; ++i) { + int start = (24 * 60) * i; + int end = (24 * 60) * (i + 1); + + int m = start; + for (int j = 0; j < hours.size(); ++j) { + TLRPC.TL_businessWeeklyOpen period = hours.get(j); + if (period.start_minute <= m && period.end_minute >= m) { + m = period.end_minute + 1; + } + } + + boolean isFull = m >= end; + if (isFull) { + int prevDay = (7 + i - 1) % 7; + if (!days[prevDay].isEmpty() && days[prevDay].get(days[prevDay].size() - 1).end >= 24 * 60) { + days[prevDay].get(days[prevDay].size() - 1).end = 24 * 60 - 1; + } + days[i].clear(); + days[i].add(new Period(0, 24 * 60 - 1)); + } else { + int nextDay = (i + 1) % 7; + if (!days[i].isEmpty() && !days[nextDay].isEmpty()) { + Period todayLast = days[i].get(days[i].size() - 1); + Period tomorrowFirst = days[nextDay].get(0); + if (todayLast.end > 24 * 60 && todayLast.end - 24 * 60 + 1 == tomorrowFirst.start) { + todayLast.end = 24 * 60 - 1; + tomorrowFirst.start = 0; + } + } + } + } + return days; + } + + public static ArrayList fromDaysHours(ArrayList[] days) { + ArrayList hours = new ArrayList<>(); + if (days != null) { + for (int i = 0; i < days.length; ++i) { + if (days[i] != null) { + for (int j = 0; j < days[i].size(); ++j) { + Period period = days[i].get(j); + TLRPC.TL_businessWeeklyOpen weekly = new TLRPC.TL_businessWeeklyOpen(); + weekly.start_minute = i * (24 * 60) + period.start; + weekly.end_minute = i * (24 * 60) + period.end; + hours.add(weekly); + } + } + } + } + return hours; + } + + private void processDone() { + if (doneButtonDrawable.getProgress() > 0f) return; + + if (!hasChanges()) { + finishFragment(); + return; + } + + doneButtonDrawable.animateToProgress(1f); + TLRPC.UserFull userFull = getMessagesController().getUserFull(getUserConfig().getClientUserId()); + TLRPC.TL_account_updateBusinessWorkHours req = new TLRPC.TL_account_updateBusinessWorkHours(); + ArrayList periods = fromDaysHours(value); + if (enabled && !periods.isEmpty()) { + TLRPC.TL_businessWorkHours business_work_hours = new TLRPC.TL_businessWorkHours(); + business_work_hours.timezone_id = timezoneId; + business_work_hours.weekly_open.addAll(periods); + + req.flags |= 1; + req.business_work_hours = business_work_hours; + + if (userFull != null) { + userFull.flags2 |= 1; + userFull.business_work_hours = business_work_hours; + } + } else { + if (userFull != null) { + userFull.flags2 &=~ 1; + userFull.business_work_hours = null; + } + } + + getConnectionsManager().sendRequest(req, (res, err) -> AndroidUtilities.runOnUIThread(() -> { + if (err != null) { + doneButtonDrawable.animateToProgress(0f); + BulletinFactory.showError(err); + } else if (res instanceof TLRPC.TL_boolFalse) { + if (getContext() == null) return; + doneButtonDrawable.animateToProgress(0f); + BulletinFactory.of(this).createErrorBulletin(LocaleController.getString(R.string.UnknownError)).show(); + } else { + if (!isFinished && !finishing) + finishFragment(); + } + })); + getMessagesStorage().updateUserInfo(userFull, false); + } + + public boolean enabled; + public ArrayList[] currentValue = null; + public ArrayList[] value = new ArrayList[] { + new ArrayList<>(), + new ArrayList<>(), + new ArrayList<>(), + new ArrayList<>(), + new ArrayList<>(), + new ArrayList<>(), + new ArrayList<>() + }; + public String currentTimezoneId; + public String timezoneId; + + public static class Period { + // from 0 to 2 * 24 * 60 + public int start; + public int end; + + public Period(int start, int end) { + this.start = start; + this.end = end; + } + + @NonNull + @Override + public String toString() { + return timeToString(start) + " - " + timeToString(end); + } + + public static String timeToString(int time) { + return timeToString(time, true); + } + + public static String timeToString(int time, boolean includeNextDay) { +// if (time == 24 * 60) +// time = 24 * 60 - 1; + int min = time % 60; + int hours = (time - min) / 60 % 24; + Calendar rightNow = Calendar.getInstance(); + rightNow.set(0, 0, 0, hours, min); + String str = LocaleController.getInstance().formatterConstDay.format(rightNow.getTime()); + if (time > 24 * 60 && includeNextDay) { + return LocaleController.formatString(R.string.BusinessHoursNextDay, str); + } + return str; + } + } + + public static boolean isFull(ArrayList periods) { + if (periods == null || periods.isEmpty()) return false; + int lastTime = 0; + for (int i = 0; i < periods.size(); ++i) { + Period p = periods.get(i); + if (lastTime < p.start) { + return false; + } + lastTime = p.end; + } + return lastTime == 24 * 60 - 1 || lastTime == 24 * 60; + } + + private String getPeriodsValue(ArrayList periods) { + if (periods.isEmpty()) { + return getString(R.string.BusinessHoursDayClosed); + } else if (isFull(periods)) { + return getString(R.string.BusinessHoursDayFullOpened); + } else { + String value = ""; + for (int j = 0; j < periods.size(); ++j) { + Period p = periods.get(j); + if (j > 0) { + value += "\n"; + } + value += Period.timeToString(p.start) + " - " + Period.timeToString(p.end); + } + return value; + } + } + + private int maxPeriodsFor(int day) { + int usedCount = 0; + for (int i = 0; i < 7; ++i) { + if (value[i] == null) continue; + // at least one is needed in case we want to turn on 24 hours + usedCount += Math.max(1, value[i].size()); + } + return PERIODS_COUNT_LIMIT - usedCount; + } + + public static final int BUTTON_SHOW = -1; + public static final int BUTTON_TIMEZONE = -2; + + private void fillItems(ArrayList items, UniversalAdapter adapter) { + items.add(UItem.asTopView(getString(R.string.BusinessHoursInfo), R.raw.biz_clock)); + items.add(UItem.asCheck(BUTTON_SHOW, getString(R.string.BusinessHoursShow)).setChecked(enabled)); + items.add(UItem.asShadow(-100, null)); + if (enabled) { + items.add(UItem.asHeader(getString(R.string.BusinessHours))); + for (int i = 0; i < value.length; ++i) { + if (value[i] == null) { + value[i] = new ArrayList<>(); + } + String day = DayOfWeek.values()[i].getDisplayName(TextStyle.FULL, LocaleController.getInstance().getCurrentLocale()); + day = day.substring(0, 1).toUpperCase() + day.substring(1); + items.add(UItem.asButtonCheck(i, day, getPeriodsValue(value[i])).setChecked(!value[i].isEmpty())); + } + items.add(UItem.asShadow(-101, null)); + items.add(UItem.asButton(BUTTON_TIMEZONE, getString(R.string.BusinessHoursTimezone), TimezonesController.getInstance(currentAccount).getTimezoneName(timezoneId, false))); + items.add(UItem.asShadow(-102, null)); + } + } + + private void onClick(UItem item, View view, int position, float x, float y) { + if (item.id == BUTTON_SHOW) { + enabled = !enabled; + ((TextCheckCell) view).setChecked(enabled); + listView.adapter.update(true); + checkDone(true); + } else if (item.id == BUTTON_TIMEZONE) { + presentFragment(new TimezoneSelector().setValue(timezoneId).whenSelected(id -> { + ((TextCell) view).setValue(TimezonesController.getInstance(currentAccount).getTimezoneName(timezoneId = id, false), true); + checkDone(true); + })); + } else if (item.viewType == UniversalAdapter.VIEW_TYPE_TEXT_CHECK && item.id >= 0 && item.id < value.length) { + final boolean checkClick = LocaleController.isRTL ? x <= dp(76) : x >= view.getMeasuredWidth() - dp(76); + if (checkClick) { + if (value[item.id].isEmpty()) { + ((NotificationsCheckCell) view).setChecked(true); + value[item.id].add(new Period(0, 24 * 60 - 1)); + adaptPrevDay(item.id); + } else { + value[item.id].clear(); + ((NotificationsCheckCell) view).setChecked(false); + } + ((NotificationsCheckCell) view).setValue(getPeriodsValue(value[item.id])); + checkDone(true); + } else { + int prevDay = (7 + item.id - 1) % 7; + int prevDayMaxTime = 0; + for (int i = 0; i < value[prevDay].size(); ++i) { + if (value[prevDay].get(i).end > prevDayMaxTime) { + prevDayMaxTime = value[prevDay].get(i).end; + } + } + int min = Math.max(0, prevDayMaxTime + 1 - 24 * 60); + int nextDay = (item.id + 1) % 7; + int nextDayMinTime = 24 * 60; + for (int i = 0; i < value[nextDay].size(); ++i) { + if (value[nextDay].get(i).start < nextDayMinTime) { + nextDayMinTime = value[nextDay].get(i).start; + } + } + int max = 24 * 60 + nextDayMinTime - 1; + presentFragment(new OpeningHoursDayActivity(item.text, value[item.id], min, max, maxPeriodsFor(item.id)).onApplied(() -> { + listView.adapter.update(true); + checkDone(true); + }).onDone(() -> { + adaptPrevDay(item.id); + })); + } + } + } + + private void adaptPrevDay(int id) { + Period thisDayLastPeriod = value[id].isEmpty() ? null : value[id].get(value[id].size() - 1); + if (thisDayLastPeriod == null) + return; + int prevDay = (7 + id - 1) % 7; + Period prevDayLastPeriod = value[prevDay].isEmpty() ? null : value[prevDay].get(value[prevDay].size() - 1); + if (prevDayLastPeriod != null && prevDayLastPeriod.end > 24 * 60 - 1) { + prevDayLastPeriod.end = 24 * 60 - 1; + if (prevDayLastPeriod.start >= prevDayLastPeriod.end) { + value[prevDay].remove(prevDayLastPeriod); + } + View child = listView.findViewByItemId(prevDay); + if (child instanceof NotificationsCheckCell) { + ((NotificationsCheckCell) child).setValue(getPeriodsValue(value[prevDay])); + } else { + listView.adapter.update(true); + } + } + } + +// private class TimezonesBottomSheet extends BottomSheetWithRecyclerListView { +// private String currentTimezoneId; +// private Utilities.Callback whenSelectedTimezone; +// public TimezonesBottomSheet(BaseFragment fragment, String timezoneId, Utilities.Callback whenSelected) { +// super(fragment, false, false); +// currentTimezoneId = timezoneId; +// whenSelectedTimezone = whenSelected; +// listView.setOnItemClickListener((view, position) -> { +// position -= 2; +// TimezonesController timezonesController = TimezonesController.getInstance(currentAccount); +// ArrayList timezones = timezonesController.getTimezones(); +// if (position >= 0 && position < timezones.size()) { +// if (whenSelectedTimezone != null) { +// whenSelectedTimezone.run(timezones.get(position).id); +// } +// dismiss(); +// } +// }); +// } +// +// @Override +// protected CharSequence getTitle() { +// return getString(R.string.BusinessHoursTimezonePicker); +// } +// +// @Override +// protected RecyclerListView.SelectionAdapter createAdapter() { +// return new UniversalAdapter(getContext(), currentAccount, this::fillItems, getResourceProvider()); +// } +// +// private void fillItems(ArrayList items, UniversalAdapter adapter) { +// items.add(UItem.asHeader(getString(R.string.BusinessHoursTimezonePicker))); +// +// TimezonesController timezonesController = TimezonesController.getInstance(currentAccount); +// ArrayList timezones = timezonesController.getTimezones(); +// for (int i = 0; i < timezones.size(); ++i) { +// items.add(UItem.asCheck(i, timezonesController.getTimezoneName(timezones.get(i), true)).setChecked(TextUtils.equals(currentTimezoneId, timezones.get(i).id))); +// } +// } +// } + +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Business/OpeningHoursDayActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/Business/OpeningHoursDayActivity.java new file mode 100644 index 00000000000..cd931540322 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Business/OpeningHoursDayActivity.java @@ -0,0 +1,220 @@ +package org.telegram.ui.Business; + +import static org.telegram.messenger.AndroidUtilities.dp; +import static org.telegram.messenger.LocaleController.getString; + +import android.content.Context; +import android.view.View; +import android.widget.FrameLayout; + +import androidx.recyclerview.widget.LinearLayoutManager; + +import org.checkerframework.checker.guieffect.qual.UI; +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.LocaleController; +import org.telegram.messenger.R; +import org.telegram.messenger.Utilities; +import org.telegram.ui.ActionBar.ActionBar; +import org.telegram.ui.ActionBar.BaseFragment; +import org.telegram.ui.ActionBar.Theme; +import org.telegram.ui.Cells.NotificationsCheckCell; +import org.telegram.ui.Cells.TextCell; +import org.telegram.ui.Cells.TextCheckCell; +import org.telegram.ui.Components.AlertsCreator; +import org.telegram.ui.Components.LayoutHelper; +import org.telegram.ui.Components.RecyclerListView; +import org.telegram.ui.Components.UItem; +import org.telegram.ui.Components.UniversalAdapter; +import org.telegram.ui.Components.UniversalRecyclerView; + +import java.time.DayOfWeek; +import java.time.format.TextStyle; +import java.util.ArrayList; +import java.util.Locale; + +public class OpeningHoursDayActivity extends BaseFragment { + + private final CharSequence title; + private final ArrayList periods; + private final int min; + private final int max; + private final int maxPeriodsCount; + + public OpeningHoursDayActivity(CharSequence text, ArrayList periods, int min, int max, int maxPeriodsCount) { + super(); + this.title = text; + this.periods = periods; + this.min = min; + this.max = max; + this.maxPeriodsCount = maxPeriodsCount; + enabled = !periods.isEmpty(); + } + + private Runnable whenApplied; + public OpeningHoursDayActivity onApplied(Runnable whenApplied) { + this.whenApplied = whenApplied; + return this; + } + + public Runnable whenDone; + public OpeningHoursDayActivity onDone(Runnable whenDone) { + this.whenDone = whenDone; + return this; + } + + @Override + public void onBecomeFullyHidden() { + if (this.whenDone != null) { + this.whenDone.run(); + } + super.onBecomeFullyHidden(); + } + + private UniversalRecyclerView listView; + + @Override + public View createView(Context context) { + actionBar.setBackButtonImage(R.drawable.ic_ab_back); + actionBar.setAllowOverlayTitle(true); + actionBar.setTitle(title); + actionBar.setActionBarMenuOnItemClick(new ActionBar.ActionBarMenuOnItemClick() { + @Override + public void onItemClick(int id) { + if (id == -1) { + finishFragment(); + } + } + }); + + FrameLayout contentView = new FrameLayout(context); + contentView.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundGray)); + + listView = new UniversalRecyclerView(context, currentAccount, this::fillItems, this::onClick, null, getResourceProvider()); + contentView.addView(listView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); + + return fragmentView = contentView; + } + + public boolean enabled; + + public static final int BUTTON_ENABLE = -1; + public static final int BUTTON_ADD = -2; + + private boolean is24() { + return periods.size() == 1 && periods.get(0).start == 0 && periods.get(0).end == 24 * 60 - 1; + } + + private void fillItems(ArrayList items, UniversalAdapter adapter) { + items.add(UItem.asRippleCheck(BUTTON_ENABLE, getString(R.string.BusinessHoursDayOpen)).setChecked(enabled)); + items.add(UItem.asShadow(null)); + if (enabled) { + for (int i = 0; i < periods.size(); ++i) { + if (i > 0) { + items.add(UItem.asShadow(null)); + } + OpeningHoursActivity.Period period = periods.get(i); + if (is24()) { + continue; + } + items.add(UItem.asButton(3 * i, getString(R.string.BusinessHoursDayOpenHour), OpeningHoursActivity.Period.timeToString(period.start))); + items.add(UItem.asButton(3 * i + 1, getString(R.string.BusinessHoursDayCloseHour), OpeningHoursActivity.Period.timeToString(period.end))); + items.add(UItem.asButton(3 * i + 2, getString(R.string.Remove)).red()); + } + if (showAddButton()) { + items.add(UItem.asShadow(null)); + items.add(UItem.asButton(BUTTON_ADD, R.drawable.menu_premium_clock_add, getString(R.string.BusinessHoursDayAdd)).accent()); + } + items.add(UItem.asShadow(getString(R.string.BusinessHoursDayInfo))); + } + } + + private boolean showAddButton() { + if (periods.size() >= maxPeriodsCount) { + return false; + } + return periods.isEmpty() || is24() || periods.get(periods.size() - 1).end < max - 2; + } + + private void onClick(UItem item, View view, int position, float x, float y) { + if (item.id == BUTTON_ENABLE) { + enabled = !enabled; + periods.clear(); + if (enabled) { + periods.add(new OpeningHoursActivity.Period(0, 24 * 60 - 1)); + } + ((TextCheckCell) view).setChecked(item.checked = enabled); + ((TextCheckCell) view).setBackgroundColorAnimated(enabled, Theme.getColor(enabled ? Theme.key_windowBackgroundChecked : Theme.key_windowBackgroundUnchecked)); + listView.adapter.update(true); + if (whenApplied != null) { + whenApplied.run(); + } + } else if (item.id == BUTTON_ADD) { + if (periods.isEmpty() || is24()) { + if (is24()) { + periods.clear(); + } + int start = Utilities.clamp(8 * 60, max - 1, min); + int end = Utilities.clamp(20 * 60, max, start + 1); + periods.add(new OpeningHoursActivity.Period(start, end)); + } else { + int lastEnd = periods.get(periods.size() - 1).end; + int start = Utilities.clamp(lastEnd + 30, max - 1, min); + int end = Utilities.clamp((lastEnd + 26 * 60) / 2, max, start + 1); + periods.add(new OpeningHoursActivity.Period(start, end)); + } + if (whenApplied != null) { + whenApplied.run(); + } + listView.adapter.update(true); + } else if (item.viewType == UniversalAdapter.VIEW_TYPE_TEXT) { + int index = item.id / 3; + if (index < 0 || index >= periods.size()) return; + OpeningHoursActivity.Period prevPeriod = index - 1 >= 0 ? periods.get(index - 1) : null; + OpeningHoursActivity.Period period = periods.get(index); + OpeningHoursActivity.Period nextPeriod = index + 1 < periods.size() ? periods.get(index + 1) : null; + if (item.id % 3 == 0) { + AlertsCreator.createTimePickerDialog(getContext(), LocaleController.getString(R.string.BusinessHoursDayOpenHourPicker), period.start, prevPeriod == null ? min : prevPeriod.end + 1, period.end - 1, time -> { + final boolean wasAddButtonShown = showAddButton(); + ((TextCell) view).setValue(OpeningHoursActivity.Period.timeToString(period.start = time), true); + if (wasAddButtonShown != showAddButton()) { + listView.adapter.update(true); + } + if (whenApplied != null) { + whenApplied.run(); + } + }); + } else if (item.id % 3 == 1) { + AlertsCreator.createTimePickerDialog(getContext(), LocaleController.getString(R.string.BusinessHoursDayCloseHourPicker), period.end, period.start + 1, nextPeriod == null ? max : nextPeriod.start - 1, time -> { + final boolean wasAddButtonShown = showAddButton(); + ((TextCell) view).setValue(OpeningHoursActivity.Period.timeToString(period.end = time), true); + if (wasAddButtonShown != showAddButton()) { + listView.adapter.update(true); + } + if (whenApplied != null) { + whenApplied.run(); + } + }); + } else if (item.id % 3 == 2) { + periods.remove(index); + if (periods.isEmpty()) { // turn into 24h + periods.add(new OpeningHoursActivity.Period(0, 24 * 60 - 1)); + } + listView.adapter.update(true); + if (whenApplied != null) { + whenApplied.run(); + } + } + } + } + + @Override + public void onFragmentDestroy() { + super.onFragmentDestroy(); + if (!enabled && !periods.isEmpty()) { + periods.clear(); + if (whenApplied != null) { + whenApplied.run(); + } + } + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Business/ProfileHoursCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Business/ProfileHoursCell.java new file mode 100644 index 00000000000..6355aeed23b --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Business/ProfileHoursCell.java @@ -0,0 +1,361 @@ +package org.telegram.ui.Business; + +import static org.telegram.messenger.AndroidUtilities.dp; +import static org.telegram.messenger.AndroidUtilities.dpf2; +import static org.telegram.messenger.LocaleController.formatPluralString; +import static org.telegram.messenger.LocaleController.formatString; +import static org.telegram.messenger.LocaleController.getString; + +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.PorterDuff; +import android.graphics.PorterDuffColorFilter; +import android.text.StaticLayout; +import android.util.TypedValue; +import android.view.Gravity; +import android.view.MotionEvent; +import android.view.View; +import android.view.ViewGroup; +import android.widget.FrameLayout; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.TextView; + +import com.google.android.exoplayer2.source.dash.manifest.Period; + +import org.checkerframework.checker.units.qual.A; +import org.telegram.messenger.LocaleController; +import org.telegram.messenger.R; +import org.telegram.messenger.UserConfig; +import org.telegram.tgnet.TLRPC; +import org.telegram.ui.ActionBar.Theme; +import org.telegram.ui.Components.AnimatedTextView; +import org.telegram.ui.Components.ClickableAnimatedTextView; +import org.telegram.ui.Components.CubicBezierInterpolator; +import org.telegram.ui.Components.LayoutHelper; + +import java.time.DayOfWeek; +import java.time.Instant; +import java.time.ZoneId; +import java.time.format.TextStyle; +import java.util.ArrayList; +import java.util.Calendar; +import java.util.Map; +import java.util.TimeZone; + +public class ProfileHoursCell extends LinearLayout { + + private final Theme.ResourcesProvider resourcesProvider; + + private TextView textView; + private TextView labelTimeText[] = new TextView[2]; + private ImageView arrowView; + private FrameLayout todayTimeContainer; + private final ViewGroup[] lines = new ViewGroup[7]; + private final TextView[] labelText = new TextView[7]; + private final TextView[][] timeText = new TextView[7][]; + private ClickableAnimatedTextView switchText; + private FrameLayout todayTimeTextContainer; + private LinearLayout todayTimeTextContainer2; + private int todayLinesCount = 1; + private int todayLinesHeight = 0; + + public ProfileHoursCell(Context context, Theme.ResourcesProvider resourcesProvider) { + super(context); + this.resourcesProvider = resourcesProvider; + + setOrientation(VERTICAL); + setClipChildren(false); + + for (int i = 0; i < 7; ++i) { + if (i == 0) { + FrameLayout line = new FrameLayout(context) { + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(Math.max(MeasureSpec.getSize(heightMeasureSpec), dp(60)), MeasureSpec.getMode(heightMeasureSpec))); + } + }; + line.setMinimumHeight(dp(60)); + + textView = new TextView(context); + textView.setGravity(LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT); + textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16); + line.addView(textView, LayoutHelper.createFrameRelatively(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.TOP | Gravity.START, 0, 9.33f, 0, 0)); + + labelText[i] = new TextView(context); + labelText[i].setGravity(LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT); + labelText[i].setTextSize(TypedValue.COMPLEX_UNIT_DIP, 13); + labelText[i].setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteGrayText2, resourcesProvider)); + line.addView(labelText[i], LayoutHelper.createFrameRelatively(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.START | Gravity.TOP, 0, 33, 0, 10)); + + todayTimeTextContainer2 = new LinearLayout(context); + todayTimeTextContainer2.setOrientation(VERTICAL); + + todayTimeTextContainer = new FrameLayout(context); + timeText[i] = new TextView[2]; + for (int a = 0; a < 2; ++a) { + timeText[i][a] = new TextView(context); + timeText[i][a].setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); + timeText[i][a].setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteGrayText2, resourcesProvider)); + timeText[i][a].setGravity(LocaleController.isRTL ? Gravity.LEFT : Gravity.RIGHT); + todayTimeTextContainer.addView(timeText[i][a], LayoutHelper.createFrameRelatively(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.FILL, 0, 0, 20, 0)); + } + + for (int a = 0; a < 2; ++a) { + labelTimeText[a] = new TextView(context); + labelTimeText[a].setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); + labelTimeText[a].setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteGrayText2, resourcesProvider)); + labelTimeText[a].setGravity(LocaleController.isRTL ? Gravity.LEFT : Gravity.RIGHT); + todayTimeTextContainer.addView(labelTimeText[a], LayoutHelper.createFrameRelatively(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.FILL, 0, 0, 20, 0)); + } + + arrowView = new ImageView(context); + arrowView.setScaleType(ImageView.ScaleType.CENTER); + arrowView.setScaleX(0.6f); + arrowView.setScaleY(0.6f); + arrowView.setImageResource(R.drawable.arrow_more); + arrowView.setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_windowBackgroundWhiteGrayText2, resourcesProvider), PorterDuff.Mode.SRC_IN)); + todayTimeTextContainer.addView(arrowView, LayoutHelper.createFrameRelatively(20, 20, Gravity.CENTER_VERTICAL | Gravity.END)); + + todayTimeTextContainer2.addView(todayTimeTextContainer, LayoutHelper.createLinearRelatively(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.FILL)); + switchText = new ClickableAnimatedTextView(context); + switchText.getDrawable().updateAll = true; + switchText.setTextSize(dp(13)); + switchText.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlueText2, resourcesProvider)); + switchText.setPadding(dp(6), 0, dp(6), 0); + switchText.setGravity(LocaleController.isRTL ? Gravity.LEFT : Gravity.RIGHT); + switchText.setBackground(Theme.createSimpleSelectorRoundRectDrawable(dp(8), Theme.multAlpha(Theme.getColor(Theme.key_windowBackgroundWhiteBlueText2, resourcesProvider), .10f), Theme.multAlpha(Theme.getColor(Theme.key_windowBackgroundWhiteBlueText2, resourcesProvider), .22f))); + switchText.getDrawable().setScaleProperty(.6f); + switchText.setVisibility(View.GONE); + todayTimeTextContainer2.addView(switchText, LayoutHelper.createLinearRelatively(LayoutHelper.MATCH_PARENT, 17, Gravity.END, 0, 4, 20 - 2, 0)); + + todayTimeContainer = new FrameLayout(context); + todayTimeContainer.addView(todayTimeTextContainer2, LayoutHelper.createFrameRelatively(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.END | Gravity.BOTTOM, 0, 0, 0, 0)); + line.addView(todayTimeContainer, LayoutHelper.createFrameRelatively(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.END | Gravity.BOTTOM, 0, 0, 0, 12)); + + addView(lines[i] = line, LayoutHelper.createFrameRelatively(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.TOP | Gravity.LEFT, 22, 0, 33 - 20, 0)); + } else { + LinearLayout line = new LinearLayout(context); + line.setOrientation(HORIZONTAL); + + labelText[i] = new TextView(context); + labelText[i].setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); + labelText[i].setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlackText, resourcesProvider)); + labelText[i].setGravity(LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT); + + FrameLayout timeTextContainer = new FrameLayout(context); + timeText[i] = new TextView[2]; + for (int a = 0; a < 2; ++a) { + timeText[i][a] = new TextView(context); + timeText[i][a].setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); + timeText[i][a].setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteGrayText2, resourcesProvider)); + timeText[i][a].setGravity(LocaleController.isRTL ? Gravity.LEFT : Gravity.RIGHT); + timeTextContainer.addView(timeText[i][a], LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.FILL)); + } + + if (LocaleController.isRTL) { + line.addView(timeTextContainer, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.MATCH_PARENT, Gravity.LEFT | Gravity.TOP)); + line.addView(labelText[i], LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.RIGHT | Gravity.TOP)); + } else { + line.addView(labelText[i], LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.MATCH_PARENT, Gravity.LEFT | Gravity.TOP)); + line.addView(timeTextContainer, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.RIGHT | Gravity.TOP)); + } + + addView(lines[i] = line, LayoutHelper.createLinearRelatively(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.TOP | Gravity.LEFT, 22, i == 1 ? 1f : 11.66f, 33, i == 6 ? 16.66f : 0)); + } + } + + setWillNotDraw(false); + } + + public void setOnTimezoneSwitchClick(View.OnClickListener onClickListener) { + if (switchText != null) { + switchText.setOnClickListener(onClickListener); + } + } + + private boolean firstAfterAttach = true; + private boolean needDivider; + private boolean expanded; + public void set(TLRPC.TL_businessWorkHours value, boolean expanded, boolean showInMyTimezone, boolean divider) { + this.expanded = expanded; + this.needDivider = divider; + + if (value == null) return; + + TimezonesController timezonesController = TimezonesController.getInstance(UserConfig.selectedAccount); + TLRPC.TL_timezone timezone = timezonesController.findTimezone(value.timezone_id); + + Calendar calendar = Calendar.getInstance(); + int currentUtcOffset = calendar.getTimeZone().getRawOffset() / 1000; + int valueUtcOffset = timezone == null ? 0 : timezone.utc_offset; + int utcOffset = (currentUtcOffset - valueUtcOffset) / 60; + switchText.setVisibility(utcOffset != 0 ? View.VISIBLE : View.GONE); + if (utcOffset == 0) showInMyTimezone = false; + + invalidate(); + + if (firstAfterAttach) { + labelTimeText[0].setAlpha(!expanded && !showInMyTimezone ? 1f : 0f); + labelTimeText[1].setAlpha(!expanded && showInMyTimezone ? 1f : 0f); + arrowView.setRotation(expanded ? 180 : 0); + } else { + labelTimeText[0].animate().alpha(!expanded && !showInMyTimezone ? 1f : 0f).setDuration(320).setInterpolator(CubicBezierInterpolator.EASE_OUT_QUINT).start(); + labelTimeText[1].animate().alpha(!expanded && showInMyTimezone ? 1f : 0f).setDuration(320).setInterpolator(CubicBezierInterpolator.EASE_OUT_QUINT).start(); + timeText[0][0].animate().alpha(expanded ? 1f : 0f).setDuration(320).setInterpolator(CubicBezierInterpolator.EASE_OUT_QUINT).start(); + timeText[0][1].animate().alpha(expanded ? 1f : 0f).setDuration(320).setInterpolator(CubicBezierInterpolator.EASE_OUT_QUINT).start(); + arrowView.animate().rotation(expanded ? 180 : 0).setDuration(320).setInterpolator(CubicBezierInterpolator.EASE_OUT_QUINT).start(); + } + for (int i = 0; i < timeText.length; ++i) { + for (int a = 0; a < timeText[i].length; ++a) { + float alpha = ((i == 0 ? expanded : true) && (a == 1) == showInMyTimezone) ? 1f : 0f; + if (firstAfterAttach) { + timeText[i][a].setAlpha(alpha); + } else { + timeText[i][a].animate().alpha(alpha).setDuration(320).setInterpolator(CubicBezierInterpolator.EASE_OUT_QUINT).start(); + } + } + } + if (switchText != null) { + switchText.setText(getString(showInMyTimezone ? R.string.BusinessHoursProfileSwitchMy : R.string.BusinessHoursProfileSwitchLocal), !LocaleController.isRTL && !firstAfterAttach); + } + firstAfterAttach = false; + + ArrayList weekly_open = new ArrayList<>(value.weekly_open); + ArrayList[] localDays = OpeningHoursActivity.getDaysHours(weekly_open); + + int nowWeekday = (7 + calendar.get(Calendar.DAY_OF_WEEK) - 2) % 7; + int nowHours = calendar.get(Calendar.HOUR_OF_DAY); + int nowMinutes = calendar.get(Calendar.MINUTE); + + ArrayList adapted_weekly_open = OpeningHoursActivity.adaptWeeklyOpen(value.weekly_open, utcOffset); + boolean open_now = false; + int nowPeriodTime = nowMinutes + nowHours * 60 + nowWeekday * (24 * 60); + for (int i = 0; i < adapted_weekly_open.size(); ++i) { + TLRPC.TL_businessWeeklyOpen weeklyPeriod = adapted_weekly_open.get(i); + if ( + nowPeriodTime >= weeklyPeriod.start_minute && nowPeriodTime <= weeklyPeriod.end_minute || + nowPeriodTime + (7 * 24 * 60) >= weeklyPeriod.start_minute && nowPeriodTime + (7 * 24 * 60) <= weeklyPeriod.end_minute || + nowPeriodTime - (7 * 24 * 60) >= weeklyPeriod.start_minute && nowPeriodTime - (7 * 24 * 60) <= weeklyPeriod.end_minute + ) { + open_now = true; + break; + } + } + ArrayList[] myDays = OpeningHoursActivity.getDaysHours(adapted_weekly_open); + + textView.setText(getString(open_now ? R.string.BusinessHoursProfileNowOpen : R.string.BusinessHoursProfileNowClosed)); + textView.setTextColor(Theme.getColor(open_now ? Theme.key_avatar_nameInMessageGreen : Theme.key_text_RedRegular, resourcesProvider)); + + int lastTodayLinesHeight = todayLinesHeight; + int lastTodayLinesCount = todayLinesCount; + todayLinesCount = 1; + todayLinesHeight = 0; + for (int a = 0; a < 2; ++a) { + ArrayList[] days = a == 0 ? localDays : myDays; + for (int i = 0; i < 7; ++i) { + int weekday = (nowWeekday + i) % 7; + if (i == 0) { + labelText[i].setText(getString(R.string.BusinessHoursProfile)); + } else { + String dayName = DayOfWeek.values()[weekday].getDisplayName(TextStyle.FULL, LocaleController.getInstance().getCurrentLocale()); + dayName = dayName.substring(0, 1).toUpperCase() + dayName.substring(1); + labelText[i].setText(dayName); + + timeText[i][0].setVisibility(expanded ? View.VISIBLE : View.INVISIBLE); + timeText[i][1].setVisibility(expanded ? View.VISIBLE : View.INVISIBLE); + labelText[i].setVisibility(expanded ? View.VISIBLE : View.INVISIBLE); + } + for (int k = 0; k < (i == 0 ? 2 : 1); ++k) { + TextView textView = k == 0 ? timeText[i][a] : labelTimeText[a]; + if (i == 0 && !open_now && k == 1) { + int opensPeriodTime = -1; + for (int j = 0; j < weekly_open.size(); ++j) { + TLRPC.TL_businessWeeklyOpen weekly = weekly_open.get(j); + if (nowPeriodTime < weekly.start_minute) { + opensPeriodTime = weekly.start_minute; + break; + } + } + if (opensPeriodTime == -1 && !weekly_open.isEmpty()) { + opensPeriodTime = weekly_open.get(0).start_minute; + } + if (opensPeriodTime == -1) { + textView.setText(getString(R.string.BusinessHoursProfileClose)); + } else { + int diff = opensPeriodTime < nowPeriodTime ? opensPeriodTime + (7 * 24 * 60 - nowPeriodTime) : opensPeriodTime - nowPeriodTime; + if (diff < 60) { + textView.setText(formatPluralString("BusinessHoursProfileOpensInMinutes", diff)); + } else if (diff < 24 * 60) { + textView.setText(formatPluralString("BusinessHoursProfileOpensInHours", (int) Math.ceil(diff / 60f))); + } else { + textView.setText(formatPluralString("BusinessHoursProfileOpensInDays", (int) Math.ceil(diff / 60f / 24f))); + } + } + } else { + if (days[weekday].isEmpty()) { + textView.setText(getString(R.string.BusinessHoursProfileClose)); + } else if (OpeningHoursActivity.isFull(days[weekday])) { + textView.setText(getString(R.string.BusinessHoursProfileOpen)); + } else { + StringBuilder sb = new StringBuilder(); + for (int j = 0; j < days[weekday].size(); ++j) { + if (j > 0) sb.append("\n"); + sb.append(days[weekday].get(j)); + } + int linesCount = days[weekday].size(); + textView.setText(sb); + if (i == 0) { + todayLinesCount = Math.max(todayLinesCount, linesCount); + todayLinesHeight = Math.max(todayLinesHeight, textView.getLineHeight() * linesCount); + } + } + } + } + } + } + + FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) todayTimeContainer.getLayoutParams(); + lp.topMargin = dp(todayLinesCount > 2 || switchText.getVisibility() == View.VISIBLE ? 6 : 12); + lp.bottomMargin = dp(todayLinesCount > 2 || switchText.getVisibility() == View.VISIBLE ? 6 : 12); + lp.gravity = (todayLinesCount > 2 || switchText.getVisibility() == View.VISIBLE ? Gravity.CENTER_VERTICAL : Gravity.BOTTOM) | (LocaleController.isRTL ? Gravity.LEFT : Gravity.RIGHT); + if (lastTodayLinesCount != todayLinesCount || lastTodayLinesHeight != todayLinesHeight) { + requestLayout(); + } + } + + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + + if (needDivider) { + Paint dividerPaint = Theme.getThemePaint(Theme.key_paint_divider, resourcesProvider); + if (dividerPaint == null) dividerPaint = Theme.dividerPaint; + canvas.drawRect(dp(LocaleController.isRTL ? 0 : 21.33f), getMeasuredHeight() - 1, getWidth() - dp(LocaleController.isRTL ? 21.33f : 0), getMeasuredHeight(), dividerPaint); + } + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure( + MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.EXACTLY), + expanded ? heightMeasureSpec : MeasureSpec.makeMeasureSpec(Math.max(dp(60), todayLinesCount > 2 || switchText.getVisibility() == View.VISIBLE ? todayLinesHeight + dp(12 + 3) + dp(switchText.getVisibility() == View.VISIBLE ? 21 : 0) : 0) + (needDivider ? 1 : 0), MeasureSpec.EXACTLY) + ); + } + + @Override + public boolean onTouchEvent(MotionEvent event) { + if (switchText != null && switchText.getVisibility() == View.VISIBLE) { + final float x = event.getX() - lines[0].getX() - todayTimeContainer.getX() - todayTimeTextContainer.getX() - switchText.getX(); + final float y = event.getY() - lines[0].getY() - todayTimeContainer.getY() - todayTimeTextContainer.getY() - switchText.getY(); + return switchText.getClickBounds().contains((int) x, (int) y); + } + return super.onTouchEvent(event); + } + + @Override + public boolean dispatchTouchEvent(MotionEvent ev) { + return super.dispatchTouchEvent(ev); + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Business/ProfileLocationCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Business/ProfileLocationCell.java new file mode 100644 index 00000000000..9980cc9cc84 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Business/ProfileLocationCell.java @@ -0,0 +1,138 @@ +package org.telegram.ui.Business; + +import static org.telegram.messenger.AndroidUtilities.dp; + +import android.app.Activity; +import android.content.Context; +import android.content.Intent; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.drawable.Drawable; +import android.net.Uri; +import android.text.TextUtils; +import android.util.TypedValue; +import android.view.Gravity; +import android.widget.FrameLayout; +import android.widget.LinearLayout; +import android.widget.TextView; + +import androidx.annotation.NonNull; + +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.BuildVars; +import org.telegram.messenger.FileLog; +import org.telegram.messenger.ImageReceiver; +import org.telegram.messenger.LocaleController; +import org.telegram.messenger.R; +import org.telegram.messenger.UserConfig; +import org.telegram.tgnet.TLRPC; +import org.telegram.ui.ActionBar.Theme; +import org.telegram.ui.Components.AvatarDrawable; +import org.telegram.ui.Components.LayoutHelper; +import org.telegram.ui.Components.LoadingDrawable; + +import java.util.Locale; + +public class ProfileLocationCell extends LinearLayout { + + private final Theme.ResourcesProvider resourcesProvider; + private final LoadingDrawable thumbDrawable; + private final ImageReceiver imageReceiver = new ImageReceiver(this); + + private final TextView textView1, textView2; + + public ProfileLocationCell(Context context, Theme.ResourcesProvider resourcesProvider) { + super(context); + this.resourcesProvider = resourcesProvider; + + setOrientation(VERTICAL); + + thumbDrawable = new LoadingDrawable(); + final int color = Theme.getColor(Theme.key_windowBackgroundWhiteBlackText, resourcesProvider); + thumbDrawable.setColors( + Theme.multAlpha(color, .05f), + Theme.multAlpha(color, .15f), + Theme.multAlpha(color, .1f), + Theme.multAlpha(color, .3f) + ); + thumbDrawable.strokePaint.setStrokeWidth(dp(1)); + + imageReceiver.setRoundRadius(dp(4)); + + textView1 = new TextView(context); + textView1.setGravity(LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT); + textView1.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlackText, resourcesProvider)); + textView1.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16); + addView(textView1, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.FILL_HORIZONTAL | Gravity.TOP, LocaleController.isRTL ? 70 : 22, 10, LocaleController.isRTL ? 22 : 70, 4)); + + textView2 = new TextView(context); + textView2.setGravity(LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT); + textView2.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteGrayText2, resourcesProvider)); + textView2.setText(LocaleController.getString(R.string.BusinessProfileLocation)); + textView2.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 13); + addView(textView2, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.FILL_HORIZONTAL | Gravity.TOP, LocaleController.isRTL ? 70 : 22, 0, LocaleController.isRTL ? 22 : 70, 8)); + + setWillNotDraw(false); + } + + @Override + protected boolean verifyDrawable(@NonNull Drawable who) { + return who == thumbDrawable || super.verifyDrawable(who); + } + + private boolean needDivider; + public void set(TLRPC.TL_businessLocation value, boolean divider) { + if (value != null) { + textView1.setText(value.address); + if (value.geo_point != null) { + imageReceiver.setImage(AndroidUtilities.formapMapUrl(UserConfig.selectedAccount, value.geo_point.lat, value.geo_point._long, dp(44), dp(44), false, 15, -1), "44_44", thumbDrawable, null, 0); + } else { + imageReceiver.setImageBitmap((Drawable) null); + } + } + + needDivider = divider; + setPadding(0, 0, 0, needDivider ? 1 : 0); + invalidate(); + } + + @Override + protected void onDraw(Canvas canvas) { + imageReceiver.setImageCoords( + LocaleController.isRTL ? dp(16) : getWidth() - dp(44 + 16), + dp(8), + dp(44), dp(44) + ); + imageReceiver.draw(canvas); + + super.onDraw(canvas); + + if (needDivider) { + Paint dividerPaint = Theme.getThemePaint(Theme.key_paint_divider, resourcesProvider); + if (dividerPaint == null) dividerPaint = Theme.dividerPaint; + canvas.drawRect(dp(LocaleController.isRTL ? 0 : 21.33f), getMeasuredHeight() - 1, getWidth() - dp(LocaleController.isRTL ? 21.33f : 0), getMeasuredHeight(), dividerPaint); + } + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.EXACTLY), heightMeasureSpec); + } + + public static void openLocation(Activity activity, TLRPC.TL_businessLocation location) { + if (activity == null || location == null) return; + if (location.geo_point != null && !(location.geo_point instanceof TLRPC.TL_geoPointEmpty)) { + try { + String uri = String.format(Locale.ENGLISH, "geo:%f,%f", location.geo_point.lat, location.geo_point._long); + if (!TextUtils.isEmpty(location.address)) { + uri += "?q=" + location.address; + } + Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(uri)); + activity.startActivity(intent); + } catch (Exception e) { + FileLog.e(e); + } + } + } + +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Business/QuickRepliesActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/Business/QuickRepliesActivity.java new file mode 100644 index 00000000000..d23a23d54ac --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Business/QuickRepliesActivity.java @@ -0,0 +1,855 @@ +package org.telegram.ui.Business; + +import static org.telegram.messenger.AndroidUtilities.dp; +import static org.telegram.messenger.AndroidUtilities.dpf2; +import static org.telegram.messenger.LocaleController.formatPluralString; +import static org.telegram.messenger.LocaleController.formatString; +import static org.telegram.messenger.LocaleController.getString; + +import android.animation.ValueAnimator; +import android.app.Activity; +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.Path; +import android.graphics.PorterDuff; +import android.graphics.PorterDuffColorFilter; +import android.graphics.drawable.Drawable; +import android.os.Bundle; +import android.text.Editable; +import android.text.InputFilter; +import android.text.InputType; +import android.text.SpannableString; +import android.text.SpannableStringBuilder; +import android.text.Spanned; +import android.text.TextUtils; +import android.text.TextWatcher; +import android.text.style.ForegroundColorSpan; +import android.text.style.ReplacementSpan; +import android.util.TypedValue; +import android.view.Gravity; +import android.view.KeyEvent; +import android.view.View; +import android.view.inputmethod.EditorInfo; +import android.widget.FrameLayout; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.Emoji; +import org.telegram.messenger.FileLoader; +import org.telegram.messenger.ImageLoader; +import org.telegram.messenger.ImageLocation; +import org.telegram.messenger.ImageReceiver; +import org.telegram.messenger.LocaleController; +import org.telegram.messenger.MediaDataController; +import org.telegram.messenger.MessageObject; +import org.telegram.messenger.MessagesController; +import org.telegram.messenger.NotificationCenter; +import org.telegram.messenger.R; +import org.telegram.messenger.UserConfig; +import org.telegram.messenger.Utilities; +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.AlertDialog; +import org.telegram.ui.ActionBar.AlertDialogDecor; +import org.telegram.ui.ActionBar.BackDrawable; +import org.telegram.ui.ActionBar.BaseFragment; +import org.telegram.ui.ActionBar.Theme; +import org.telegram.ui.ChatActivity; +import org.telegram.ui.Components.AnimatedColor; +import org.telegram.ui.Components.AnimatedTextView; +import org.telegram.ui.Components.AvatarDrawable; +import org.telegram.ui.Components.CheckBox2; +import org.telegram.ui.Components.CubicBezierInterpolator; +import org.telegram.ui.Components.EditTextBoldCursor; +import org.telegram.ui.Components.ForegroundColorSpanThemable; +import org.telegram.ui.Components.LayoutHelper; +import org.telegram.ui.Components.NumberTextView; +import org.telegram.ui.Components.SizeNotifierFrameLayout; +import org.telegram.ui.Components.Text; +import org.telegram.ui.Components.TypefaceSpan; +import org.telegram.ui.Components.UItem; +import org.telegram.ui.Components.UniversalAdapter; +import org.telegram.ui.Components.UniversalRecyclerView; +import org.telegram.ui.Components.spoilers.SpoilersTextView; +import org.telegram.ui.LaunchActivity; + +import java.util.ArrayList; + +public class QuickRepliesActivity extends BaseFragment implements NotificationCenter.NotificationCenterDelegate { + + private UniversalRecyclerView listView; + + public final ArrayList selected = new ArrayList<>(); + + private NumberTextView countText; + private ActionBarMenuItem editItem; + private ActionBarMenuItem deleteItem; + + @Override + public View createView(Context context) { + actionBar.setBackButtonDrawable(new BackDrawable(false)); + actionBar.setAllowOverlayTitle(true); + actionBar.setTitle(getString(R.string.BusinessReplies)); + actionBar.setActionBarMenuOnItemClick(new ActionBar.ActionBarMenuOnItemClick() { + @Override + public void onItemClick(int id) { + if (id == -1) { + if (selected.isEmpty()) { + finishFragment(); + } else { + clearSelection(); + } + } else if (id == 1) { + if (selected.size() != 1) return; +// selected.get(0); + final int replyId = selected.get(0); + QuickRepliesController.QuickReply quickReply = QuickRepliesController.getInstance(currentAccount).findReply(replyId); + if (quickReply == null) return; + openRenameReplyAlert(getContext(), currentAccount, null, quickReply, resourceProvider, false, name -> { + clearSelection(); + QuickRepliesController.getInstance(currentAccount).renameReply(replyId, name); + }); + } else if (id == 2) { + showDialog( + new AlertDialog.Builder(getContext(), getResourceProvider()) + .setTitle(formatPluralString("BusinessRepliesDeleteTitle", selected.size())) + .setMessage(formatPluralString("BusinessRepliesDeleteMessage", selected.size())) + .setPositiveButton(getString(R.string.Remove), (di, w) -> { + QuickRepliesController.getInstance(currentAccount).deleteReplies(selected); + clearSelection(); + }) + .setNegativeButton(getString(R.string.Cancel), null) + .create() + ); + } + } + }); + + ActionBarMenu actionModeMenu = actionBar.createActionMode(); + countText = new NumberTextView(getContext()); + countText.setTextSize(18); + countText.setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)); + countText.setTextColor(Theme.getColor(Theme.key_actionBarActionModeDefaultIcon)); + actionModeMenu.addView(countText, LayoutHelper.createLinear(0, LayoutHelper.MATCH_PARENT, 1.0f, 72, 0, 0, 0)); + countText.setOnTouchListener((v, event) -> true); + editItem = actionModeMenu.addItem(1, R.drawable.msg_edit); + editItem.setContentDescription(LocaleController.getString(R.string.Edit)); + deleteItem = actionModeMenu.addItem(2, R.drawable.msg_delete); + deleteItem.setContentDescription(LocaleController.getString(R.string.Delete)); + + FrameLayout contentView = new SizeNotifierFrameLayout(context) { + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure( + MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.EXACTLY), + MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(heightMeasureSpec), MeasureSpec.EXACTLY) + ); + } + }; + contentView.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundGray)); + + listView = new UniversalRecyclerView(context, currentAccount, this::fillItems, this::onClick, this::onLongClick, getResourceProvider()); + listView.listenReorder(this::whenReordered); + contentView.addView(listView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); + + return fragmentView = contentView; + } + + private final static int BUTTON_ADD = 1; + private int repliesOrderId; + + private void fillItems(ArrayList items, UniversalAdapter adapter) { + items.add(UItem.asTopView(getString(R.string.BusinessRepliesInfo), "RestrictedEmoji", "📝")); + adapter.whiteSectionStart(); + if (QuickRepliesController.getInstance(currentAccount).canAddNew()) { + items.add(UItem.asButton(BUTTON_ADD, R.drawable.msg_viewintopic, getString(R.string.BusinessRepliesAdd)).accent()); + } +// for (QuickRepliesController.QuickReply reply : QuickRepliesController.getInstance(currentAccount).localReplies) { +// items.add(UItem.asQuickReply(reply).setChecked(false)); +// } + repliesOrderId = adapter.reorderSectionStart(); + for (QuickRepliesController.QuickReply reply : QuickRepliesController.getInstance(currentAccount).replies) { + items.add(UItem.asQuickReply(reply).setChecked(selected.contains(reply.id))); + } + adapter.reorderSectionEnd(); + adapter.whiteSectionEnd(); + items.add(UItem.asShadow(getString(R.string.BusinessRepliesAddInfo))); + } + + private void whenReordered(int id, ArrayList items) { + if (id == repliesOrderId) { + for (int i = 0; i < items.size(); ++i) { + if (items.get(i).object instanceof QuickRepliesController.QuickReply) { + QuickRepliesController.QuickReply quickReply = ((QuickRepliesController.QuickReply) items.get(i).object); + quickReply.order = i; + } + } + QuickRepliesController.getInstance(currentAccount).reorder(); + } + } + + private void onClick(UItem item, View view, int position, float x, float y) { + if (item.id == BUTTON_ADD) { + openRenameReplyAlert(getContext(), currentAccount, null, null, getResourceProvider(), false, name -> { + Bundle args = new Bundle(); + args.putInt("chatMode", ChatActivity.MODE_QUICK_REPLIES); + args.putLong("user_id", getUserConfig().getClientUserId()); + args.putString("quick_reply", name); + ChatActivity chatActivity = new ChatActivity(args); + chatActivity.forceEmptyHistory(); + presentFragment(chatActivity); + }); + } else if (item.viewType == UniversalAdapter.VIEW_TYPE_QUICK_REPLY && item.object instanceof QuickRepliesController.QuickReply) { + if (!selected.isEmpty()) { + updateSelect(item, view); + return; + } + QuickRepliesController.QuickReply reply = (QuickRepliesController.QuickReply) item.object; + if (reply.local) { + return; + } + Bundle args = new Bundle(); + args.putInt("chatMode", ChatActivity.MODE_QUICK_REPLIES); + args.putLong("user_id", getUserConfig().getClientUserId()); + args.putString("quick_reply", reply.name); + ChatActivity chatActivity = new ChatActivity(args); + chatActivity.setQuickReplyId(reply.id); + presentFragment(chatActivity); + } + } + + private void updateSelect(UItem item, View view) { + QuickRepliesController.QuickReply quickReply = (QuickRepliesController.QuickReply) item.object; + QuickReplyView cell = (QuickReplyView) view; + if (selected.contains(quickReply.id)) { + selected.remove((Integer) quickReply.id); + } else { + selected.add(quickReply.id); + } + listView.allowReorder(!selected.isEmpty()); + cell.setChecked(item.checked = selected.contains(quickReply.id), true); + if (actionBar.isActionModeShowed() == selected.isEmpty()) { + if (selected.isEmpty()) { + actionBar.hideActionMode(); + } else { + actionBar.showActionMode(); + } + } + countText.setNumber(Math.max(1, selected.size()), true); + updateEditItem(); + } + + private boolean shownEditItem = true; + private void updateEditItem() { + boolean show = selected.size() == 1; + if (show) { + QuickRepliesController.QuickReply reply = QuickRepliesController.getInstance(currentAccount).findReply(selected.get(0)); + show = reply != null && !reply.isSpecial(); + } + if (shownEditItem != show) { + shownEditItem = show; + editItem.animate().alpha(shownEditItem ? 1f : 0f).scaleX(shownEditItem ? 1f : .7f).scaleY(shownEditItem ? 1f : .7f).setInterpolator(CubicBezierInterpolator.EASE_OUT_QUINT).setDuration(340).start(); + } + } + + private void clearSelection() { + selected.clear(); + AndroidUtilities.forEachViews(listView, view -> { + if (view instanceof QuickReplyView) { + ((QuickReplyView) view).setChecked(false, true); + } + }); + actionBar.hideActionMode(); + listView.allowReorder(false); + } + + private boolean onLongClick(UItem item, View view, int position, float x, float y) { + if (item.viewType == UniversalAdapter.VIEW_TYPE_QUICK_REPLY) { + if (item.object instanceof QuickRepliesController.QuickReply && ((QuickRepliesController.QuickReply) item.object).local) { + return false; + } + updateSelect(item, view); + return true; + } + return false; + } + + private static AlertDialog currentDialog; + public static void openRenameReplyAlert(Context context, int currentAccount, String currentName, QuickRepliesController.QuickReply currentReply, Theme.ResourcesProvider resourcesProvider, boolean forceNotAdaptive, Utilities.Callback whenDone) { + BaseFragment fragment = LaunchActivity.getLastFragment(); + Activity activity = AndroidUtilities.findActivity(context); + View currentFocus = activity != null ? activity.getCurrentFocus() : null; + final boolean isKeyboardVisible = fragment != null && fragment.getFragmentView() instanceof SizeNotifierFrameLayout && ((SizeNotifierFrameLayout) fragment.getFragmentView()).measureKeyboardHeight() > dp(20); + final boolean adaptive = isKeyboardVisible && !forceNotAdaptive; + AlertDialog[] dialog = new AlertDialog[1]; + AlertDialog.Builder builder; + if (adaptive) { + builder = new AlertDialogDecor.Builder(context, resourcesProvider); + } else { + builder = new AlertDialog.Builder(context, resourcesProvider); + } + builder.setTitle(getString(currentReply == null && currentName == null ? R.string.BusinessRepliesNewTitle : R.string.BusinessRepliesEditTitle)); + + final int MAX_NAME_LENGTH = 32; + EditTextBoldCursor editText = new EditTextBoldCursor(context) { + AnimatedColor limitColor = new AnimatedColor(this); + private int limitCount; + AnimatedTextView.AnimatedTextDrawable limit = new AnimatedTextView.AnimatedTextDrawable(false, true, true); { + limit.setAnimationProperties(.2f, 0, 160, CubicBezierInterpolator.EASE_OUT_QUINT); + limit.setTextSize(dp(15.33f)); + limit.setCallback(this); + limit.setGravity(Gravity.RIGHT); + } + + @Override + protected boolean verifyDrawable(@NonNull Drawable who) { + return who == limit || super.verifyDrawable(who); + } + + @Override + protected void onTextChanged(CharSequence text, int start, int lengthBefore, int lengthAfter) { + super.onTextChanged(text, start, lengthBefore, lengthAfter); + + if (limit != null) { + limitCount = MAX_NAME_LENGTH - text.length(); + limit.cancelAnimation(); + limit.setText(limitCount > 4 ? "" : "" + limitCount); + } + } + + @Override + protected void dispatchDraw(Canvas canvas) { + super.dispatchDraw(canvas); + + limit.setTextColor(limitColor.set(Theme.getColor(limitCount < 0 ? Theme.key_text_RedRegular : Theme.key_dialogSearchHint, resourcesProvider))); + limit.setBounds(getScrollX(), 0, getScrollX() + getWidth(), getHeight()); + limit.draw(canvas); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(36), MeasureSpec.EXACTLY)); + } + }; + MediaDataController.getInstance(currentAccount).fetchNewEmojiKeywords(AndroidUtilities.getCurrentKeyboardLanguage(), true); + editText.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 18); + editText.setText(currentReply == null ? (currentName == null ? "" : currentName) : currentReply.name); + editText.setTextColor(Theme.getColor(Theme.key_dialogTextBlack, resourcesProvider)); + editText.setHintColor(Theme.getColor(Theme.key_groupcreate_hintText, resourcesProvider)); + editText.setHintText(LocaleController.getString(R.string.BusinessRepliesNamePlaceholder)); + editText.setSingleLine(true); + editText.setFocusable(true); + editText.setLineColors(Theme.getColor(Theme.key_windowBackgroundWhiteInputField, resourcesProvider), Theme.getColor(Theme.key_windowBackgroundWhiteInputFieldActivated, resourcesProvider), Theme.getColor(Theme.key_text_RedRegular, resourcesProvider)); + editText.setImeOptions(EditorInfo.IME_ACTION_DONE); + editText.setBackgroundDrawable(null); + editText.setPadding(0, 0, dp(42), 0); + editText.setFilters(new InputFilter[]{ + new InputFilter() { + @Override + public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) { + return String.valueOf(source).replaceAll("[^\\d_\\p{L}\\x{200c}\\x{00b7}\\x{0d80}-\\x{0dff}]", ""); + } + } + }); + + LinearLayout container = new LinearLayout(context); + container.setOrientation(LinearLayout.VERTICAL); + + FrameLayout textContainer = new FrameLayout(context); + + final TextView textView = new TextView(context); + textView.setTextColor(Theme.getColor(Theme.key_dialogTextBlack, resourcesProvider)); + textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16); + textView.setText(LocaleController.getString(currentReply == null && currentName == null ? R.string.BusinessRepliesNewMessage : R.string.BusinessRepliesEditMessage)); + textContainer.addView(textView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.LEFT | Gravity.BOTTOM)); + + final TextView errorTextView = new TextView(context); + errorTextView.setTextColor(Theme.getColor(Theme.key_text_RedBold, resourcesProvider)); + errorTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16); + errorTextView.setText(LocaleController.getString(R.string.BusinessRepliesNameBusy)); + errorTextView.setAlpha(0f); + textContainer.addView(errorTextView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.LEFT | Gravity.BOTTOM)); + ValueAnimator[] errorAnimator = new ValueAnimator[1]; + final Runnable[] hideError = new Runnable[1]; + Utilities.Callback updateError = show -> { + AndroidUtilities.cancelRunOnUIThread(hideError[0]); + if (errorAnimator[0] != null) { + errorAnimator[0].cancel(); + } + errorAnimator[0] = ValueAnimator.ofFloat(errorTextView.getAlpha(), show ? 1f : 0f); + errorAnimator[0].addUpdateListener(anm -> { + errorTextView.setAlpha((float) anm.getAnimatedValue()); + textView.setAlpha(1f - (float) anm.getAnimatedValue()); + }); + errorAnimator[0].setDuration(320); + errorAnimator[0].setInterpolator(CubicBezierInterpolator.EASE_OUT_QUINT); + errorAnimator[0].start(); + if (show) { + AndroidUtilities.runOnUIThread(hideError[0], 320 + 5000); + } + }; + hideError[0] = () -> updateError.run(false); + editText.addTextChangedListener(new TextWatcher() { + @Override + public void beforeTextChanged(CharSequence s, int start, int count, int after) {} + @Override + public void onTextChanged(CharSequence s, int start, int before, int count) {} + @Override + public void afterTextChanged(Editable s) { + if (errorTextView.getAlpha() > 0f) { + AndroidUtilities.cancelRunOnUIThread(hideError[0]); + AndroidUtilities.runOnUIThread(hideError[0]); + } + } + }); + + container.addView(textContainer, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, 24, 5, 24, 12)); + + container.addView(editText, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, 24, 0, 24, 10)); + builder.setView(container); + builder.setWidth(dp(292)); + + editText.setOnEditorActionListener(new TextView.OnEditorActionListener() { + @Override + public boolean onEditorAction(TextView v, int actionId, KeyEvent event) { + if (actionId == EditorInfo.IME_ACTION_DONE) { + String text = editText.getText().toString(); + if (text.length() <= 0 || text.length() > MAX_NAME_LENGTH) { + AndroidUtilities.shakeView(editText); + return true; + } + if (QuickRepliesController.getInstance(currentAccount).isNameBusy(text, currentReply == null ? -1 : currentReply.id)) { + AndroidUtilities.shakeView(editText); + errorTextView.setText(LocaleController.getString(R.string.BusinessRepliesNameBusy)); + updateError.run(true); + return true; + } + if (whenDone != null) { + whenDone.run(text); + } + if (dialog[0] != null) { + dialog[0].dismiss(); + } + if (dialog[0] == currentDialog) { + currentDialog = null; + } + if (currentFocus != null) { + currentFocus.requestFocus(); + } + return true; + } + return false; + } + }); + builder.setPositiveButton(LocaleController.getString(R.string.Done), (dialogInterface, i) -> { + String text = editText.getText().toString(); + if (text.length() <= 0 || text.length() > MAX_NAME_LENGTH) { + AndroidUtilities.shakeView(editText); + updateError.run(false); + return; + } + if (QuickRepliesController.getInstance(currentAccount).isNameBusy(text, currentReply == null ? -1 : currentReply.id)) { + AndroidUtilities.shakeView(editText); + errorTextView.setText(LocaleController.getString(R.string.BusinessRepliesNameBusy)); + updateError.run(true); + return; + } + if (whenDone != null) { + whenDone.run(text); + } + dialogInterface.dismiss(); + }); + builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), (dialogInterface, i) -> { + dialogInterface.dismiss(); + }); + if (adaptive) { + dialog[0] = currentDialog = builder.create(); + currentDialog.setOnDismissListener(d -> { + currentDialog = null; + if (currentFocus != null) { + currentFocus.requestFocus(); + } + }); + currentDialog.setOnShowListener(d -> { + editText.requestFocus(); + AndroidUtilities.showKeyboard(editText); + }); + currentDialog.showDelayed(250); + } else { + builder.overrideDismissListener(dismiss -> { + AndroidUtilities.hideKeyboard(editText); + AndroidUtilities.runOnUIThread(dismiss, 80); + }); + dialog[0] = builder.create(); + dialog[0].setOnDismissListener(d -> { + AndroidUtilities.hideKeyboard(editText); + }); + dialog[0].setOnShowListener(d -> { + editText.requestFocus(); + AndroidUtilities.showKeyboard(editText); + }); + dialog[0].show(); + } + dialog[0].setDismissDialogByButtons(false); + editText.setSelection(editText.getText().length()); + } + + @Override + public boolean onFragmentCreate() { + getNotificationCenter().addObserver(this, NotificationCenter.quickRepliesUpdated); + QuickRepliesController.getInstance(currentAccount).load(); + return super.onFragmentCreate(); + } + + @Override + public void onFragmentDestroy() { + getNotificationCenter().removeObserver(this, NotificationCenter.quickRepliesUpdated); + super.onFragmentDestroy(); + } + + @Override + public void didReceivedNotification(int id, int account, Object... args) { + if (id == NotificationCenter.quickRepliesUpdated) { + if (listView != null && listView.adapter != null) { + listView.adapter.update(true); + } + } + } + + private static class MoreSpan extends ReplacementSpan { + private final Paint backgroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + private final Text text; + public MoreSpan(int count) { + text = new Text(formatPluralString("BusinessRepliesMore", count), 9.33f, AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)); + } + public static CharSequence of(int count, int[] width) { + SpannableString ss = new SpannableString("+"); + MoreSpan span = new MoreSpan(count); + width[0] = span.getSize(); + ss.setSpan(span, 0, ss.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + return ss; + } + + public int getSize() { + return (int) (this.text.getCurrentWidth() + dp(10)); + } + + @Override + public int getSize(@NonNull Paint paint, CharSequence text, int start, int end, @Nullable Paint.FontMetricsInt fm) { + return getSize(); + } + + @Override + public void draw(@NonNull Canvas canvas, CharSequence text, int start, int end, float x, int top, int y, int bottom, @NonNull Paint paint) { + final float h = dpf2(14.66f), cy = (top + bottom) / 2f; + AndroidUtilities.rectTmp.set(x, cy - h / 2f, x + getSize(), cy + h / 2f); + backgroundPaint.setColor(Theme.multAlpha(Theme.getColor(Theme.key_windowBackgroundWhiteGrayText2), .15f)); + canvas.drawRoundRect(AndroidUtilities.rectTmp, dp(4), dp(4), backgroundPaint); + this.text.draw(canvas, x + dp(5), (top + bottom) / 2f, Theme.getColor(Theme.key_windowBackgroundWhiteGrayText2), Utilities.clamp(2 * paint.getAlpha() / 255f, 1, 0)); + } + } + + public static class QuickReplyView extends FrameLayout { + + private final AvatarDrawable avatarDrawable = new AvatarDrawable(); + private final ImageReceiver imageReceiver = new ImageReceiver(this); + + private final TextView textView; + private final CheckBox2 checkBox; + private final ImageView orderView; + + private final Theme.ResourcesProvider resourcesProvider; + private boolean local; + + public QuickReplyView(Context context, boolean reorderable, Theme.ResourcesProvider resourcesProvider) { + super(context); + + this.resourcesProvider = resourcesProvider; + setWillNotDraw(false); + + int rightpadding = reorderable ? 42 : 16; + + textView = new SpoilersTextView(context); + textView.setLines(2); + textView.setEllipsize(TextUtils.TruncateAt.END); + textView.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteGrayText2, resourcesProvider)); + textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); + addView(textView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.FILL_HORIZONTAL, LocaleController.isRTL ? rightpadding : 64, 7, LocaleController.isRTL ? 64 : rightpadding, 0)); + + if (reorderable) { + orderView = new ImageView(context); + orderView.setScaleType(ImageView.ScaleType.CENTER); + orderView.setImageResource(R.drawable.list_reorder); + orderView.setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_stickers_menu), PorterDuff.Mode.MULTIPLY)); + orderView.setAlpha(0f); + addView(orderView, LayoutHelper.createFrame(50, 50, Gravity.FILL_VERTICAL | (LocaleController.isRTL ? Gravity.LEFT : Gravity.RIGHT))); + } else { + orderView = null; + } + + checkBox = new CheckBox2(getContext(), 21, resourcesProvider); + checkBox.setColor(-1, Theme.key_windowBackgroundWhite, Theme.key_checkboxCheck); + checkBox.setDrawUnchecked(false); + checkBox.setDrawBackgroundAsArc(3); + addView(checkBox, LayoutHelper.createFrameRelatively(24, 24, Gravity.START | Gravity.TOP, 27 + 6, 19 + 6, 0, 0)); + } + + public void invalidateEmojis() { + textView.invalidate(); + } + + public void setChecked(boolean checked, boolean animated) { + checkBox.setChecked(checked, animated); + } + + public void setReorder(boolean reorder) { + orderView.animate().alpha(reorder && !local ? 1f : 0f).start(); + } + + private int[] spanWidth = new int[1]; + private boolean needDivider; + public void set(QuickRepliesController.QuickReply quickReply, String highlight, boolean divider) { + local = quickReply != null ? quickReply.local : false; + SpannableStringBuilder ssb = new SpannableStringBuilder(); + if (highlight != null && highlight.length() > 0 && !highlight.startsWith("/")) { + highlight = "/" + highlight; + } + ssb.append("/").append(quickReply.name); + ssb.setSpan(new TypefaceSpan(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)), 0, ssb.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + ssb.setSpan(new ForegroundColorSpan(Theme.getColor(Theme.key_windowBackgroundWhiteBlackText, resourcesProvider)), 0, ssb.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + if (highlight != null) { + ssb.setSpan(new ForegroundColorSpan(Theme.getColor(Theme.key_windowBackgroundWhiteBlueText2, resourcesProvider)), 0, Math.min(highlight.length() <= 0 ? 1 : highlight.length(), ssb.length()), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + } + if (quickReply.topMessage != null) { + ssb.append(" "); + CharSequence messageText = quickReply.topMessage.caption; + if (TextUtils.isEmpty(messageText)) { + messageText = quickReply.topMessage.messageText; + } + CharSequence text = new SpannableStringBuilder(messageText); + text = Emoji.replaceEmoji(text, textView.getPaint().getFontMetricsInt(), false); + if (quickReply.topMessage.messageOwner != null) { + MessageObject.replaceAnimatedEmoji(text, quickReply.topMessage.messageOwner.entities, textView.getPaint().getFontMetricsInt()); + } + ssb.append(text); + } + if (quickReply.getMessagesCount() > 1) { + ssb.append(" "); + + int lineWidth = AndroidUtilities.displaySize.x - dp(64 + 16); + CharSequence more = MoreSpan.of(quickReply.getMessagesCount() - 1, spanWidth); + ssb = new SpannableStringBuilder(TextUtils.ellipsize(ssb, textView.getPaint(), 1.5f * lineWidth - spanWidth[0], TextUtils.TruncateAt.END)); + if (ssb.length() > 0 && ssb.charAt(ssb.length() - 1) == '\u2026') { + ssb.append(" "); + } + ssb.append(more); + } + textView.setText(ssb); + + final int currentAccount = UserConfig.selectedAccount; + TLRPC.MessageMedia media = MessageObject.getMedia(quickReply.topMessage); + if (media != null && media.photo != null) { + TLRPC.PhotoSize currentPhotoObject = FileLoader.getClosestPhotoSizeWithSize(media.photo.sizes, dp(36), true, null, true); + imageReceiver.setImage(ImageLocation.getForObject(currentPhotoObject, media.photo), "36_36", quickReply.topMessage.strippedThumb, currentPhotoObject == null ? 0 : currentPhotoObject.size, null, quickReply.topMessage, 0); + imageReceiver.setRoundRadius(dp(4)); + } else if (media != null && media.document != null && (quickReply.topMessage.isVideo() || quickReply.topMessage.isSticker())) { + ImageLocation location = null; + long size; + String filter = "36_36"; + TLRPC.PhotoSize currentPhotoObject = FileLoader.getClosestPhotoSizeWithSize(media.document.thumbs, dp(36), true, null, true); + if (currentPhotoObject == null) { + location = ImageLocation.getForDocument(media.document); + size = media.document.size; + filter = ImageLoader.AUTOPLAY_FILTER; + } else { + location = ImageLocation.getForObject(currentPhotoObject, media.document); + size = currentPhotoObject.size; + } + imageReceiver.setImage(location, filter, quickReply.topMessage.strippedThumb, size, null, quickReply.topMessage, 0); + imageReceiver.setRoundRadius(dp(4)); + } else if (media != null && media.webpage != null && media.webpage.photo != null) { + TLRPC.PhotoSize currentPhotoObject = FileLoader.getClosestPhotoSizeWithSize(media.webpage.photo.sizes, dp(36), true, null, true); + imageReceiver.setImage(ImageLocation.getForObject(currentPhotoObject, media.webpage.photo), "36_36", quickReply.topMessage.strippedThumb, currentPhotoObject == null ? 0 : currentPhotoObject.size, null, media.webpage, 0); + imageReceiver.setRoundRadius(dp(4)); + } else { + avatarDrawable.setInfo(UserConfig.getInstance(currentAccount).getCurrentUser()); + imageReceiver.setForUserOrChat(UserConfig.getInstance(currentAccount).getCurrentUser(), avatarDrawable); + imageReceiver.setRoundRadius(dp(36)); + } + + needDivider = divider; + invalidate(); + } + + @Override + protected void onDraw(Canvas canvas) { + imageReceiver.setImageCoords( + LocaleController.isRTL ? getMeasuredWidth() - dp(15 + 36) : dp(15), + dp(7), + dp(36), dp(36) + ); + imageReceiver.draw(canvas); + super.onDraw(canvas); + if (needDivider) { + Paint dividerPaint = Theme.getThemePaint(Theme.key_paint_divider, resourcesProvider); + if (dividerPaint == null) dividerPaint = Theme.dividerPaint; + canvas.drawRect(dp(LocaleController.isRTL ? 0 : 64), getMeasuredHeight() - 1, getWidth() - dp(LocaleController.isRTL ? 64 : 0), getMeasuredHeight(), dividerPaint); + } + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure( + MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.EXACTLY), + MeasureSpec.makeMeasureSpec(dp(50) + (needDivider ? 1 : 0), MeasureSpec.EXACTLY) + ); + } + } + + public static class LargeQuickReplyView extends FrameLayout { + + private final AvatarDrawable avatarDrawable = new AvatarDrawable(); + private final ImageReceiver imageReceiver = new ImageReceiver(this); + + private final TextView titleView; + private final TextView textView; + private final CheckBox2 checkBox; + + private final Path arrowPath = new Path(); + private final Paint arrowPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + + private final Theme.ResourcesProvider resourcesProvider; + public LargeQuickReplyView(Context context, Theme.ResourcesProvider resourcesProvider) { + super(context); + + this.resourcesProvider = resourcesProvider; + setWillNotDraw(false); + + titleView = new TextView(context); + titleView.setSingleLine(); + titleView.setEllipsize(TextUtils.TruncateAt.END); + titleView.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlackText, resourcesProvider)); + titleView.setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)); + titleView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16); + addView(titleView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.FILL_HORIZONTAL, LocaleController.isRTL ? 40 : 78, 10.33f, LocaleController.isRTL ? 78 : 40, 0)); + + textView = new TextView(context); + textView.setLines(2); + textView.setEllipsize(TextUtils.TruncateAt.END); + textView.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteGrayText2, resourcesProvider)); + textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 15); + addView(textView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.FILL_HORIZONTAL, LocaleController.isRTL ? 40 : 78, 32, LocaleController.isRTL ? 78 : 40, 0)); + + checkBox = new CheckBox2(getContext(), 21, resourcesProvider); + checkBox.setColor(-1, Theme.key_windowBackgroundWhite, Theme.key_checkboxCheck); + checkBox.setDrawUnchecked(false); + checkBox.setDrawBackgroundAsArc(3); + addView(checkBox, LayoutHelper.createFrameRelatively(24, 24, Gravity.START | Gravity.TOP, 27 + 6, 19 + 6, 0, 0)); + } + + public void invalidateEmojis() { + textView.invalidate(); + } + + public void setChecked(boolean checked, boolean animated) { + checkBox.setChecked(checked, animated); + } + + private int[] spanWidth = new int[1]; + private boolean needDivider; + public void set(QuickRepliesController.QuickReply quickReply, boolean divider) { + final int currentAccount = UserConfig.selectedAccount; + + titleView.setText(MessagesController.getInstance(currentAccount).getPeerName(UserConfig.getInstance(currentAccount).getClientUserId())); + + SpannableStringBuilder ssb = new SpannableStringBuilder(); + if (quickReply.topMessage != null) { + ssb.append(Emoji.replaceEmoji(quickReply.topMessage.messageText, textView.getPaint().getFontMetricsInt(), false)); + } + if (quickReply.getMessagesCount() > 1) { + ssb.append(" "); + + int lineWidth = AndroidUtilities.displaySize.x - dp(64 + 16); + CharSequence more = MoreSpan.of(quickReply.getMessagesCount() - 1, spanWidth); + ssb = new SpannableStringBuilder(TextUtils.ellipsize(ssb, textView.getPaint(), 1.5f * lineWidth - spanWidth[0], TextUtils.TruncateAt.END)); + if (ssb.length() > 0 && ssb.charAt(ssb.length() - 1) == '\u2026') { + ssb.append(" "); + } + ssb.append(more); + } + textView.setText(ssb); + + TLRPC.MessageMedia media = MessageObject.getMedia(quickReply.topMessage); + if (media != null && media.photo != null) { + TLRPC.PhotoSize currentPhotoObject = FileLoader.getClosestPhotoSizeWithSize(media.photo.sizes, dp(36), true, null, true); + imageReceiver.setImage(ImageLocation.getForObject(currentPhotoObject, media.photo), "36_36", quickReply.topMessage.strippedThumb, currentPhotoObject == null ? 0 : currentPhotoObject.size, null, quickReply.topMessage, 0); + imageReceiver.setRoundRadius(dp(6)); + } else if (media != null && media.document != null) { + ImageLocation location = null; + long size; + String filter = "36_36"; + TLRPC.PhotoSize currentPhotoObject = FileLoader.getClosestPhotoSizeWithSize(media.document.thumbs, dp(36), true, null, true); + if (currentPhotoObject == null) { + location = ImageLocation.getForDocument(media.document); + size = media.document.size; + filter = ImageLoader.AUTOPLAY_FILTER; + } else { + location = ImageLocation.getForObject(currentPhotoObject, media.document); + size = currentPhotoObject.size; + } + imageReceiver.setImage(location, filter, quickReply.topMessage.strippedThumb, size, null, quickReply.topMessage, 0); + imageReceiver.setRoundRadius(dp(6)); + } else { + avatarDrawable.setInfo(UserConfig.getInstance(currentAccount).getCurrentUser()); + imageReceiver.setForUserOrChat(UserConfig.getInstance(currentAccount).getCurrentUser(), avatarDrawable); + imageReceiver.setRoundRadius(dp(56)); + } + + needDivider = divider; + invalidate(); + } + + @Override + protected void onDraw(Canvas canvas) { + imageReceiver.setImageCoords( + LocaleController.isRTL ? getMeasuredWidth() - dp(9 + 56) : dp(9), + dp(11.33f), + dp(56), dp(56) + ); + imageReceiver.draw(canvas); + super.onDraw(canvas); + canvas.drawPath(arrowPath, arrowPaint); + if (needDivider) { + Paint dividerPaint = Theme.getThemePaint(Theme.key_paint_divider, resourcesProvider); + if (dividerPaint == null) dividerPaint = Theme.dividerPaint; + canvas.drawRect(dp(LocaleController.isRTL ? 0 : 78), getMeasuredHeight() - 1, getWidth() - dp(LocaleController.isRTL ? 78 : 0), getMeasuredHeight(), dividerPaint); + } + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure( + MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.EXACTLY), + MeasureSpec.makeMeasureSpec(dp(78) + (needDivider ? 1 : 0), MeasureSpec.EXACTLY) + ); + arrowPaint.setStyle(Paint.Style.STROKE); + arrowPaint.setStrokeCap(Paint.Cap.ROUND); + arrowPaint.setStrokeJoin(Paint.Join.ROUND); + arrowPaint.setStrokeWidth(dpf2(1.66f)); + arrowPaint.setColor(Theme.multAlpha(Theme.getColor(Theme.key_windowBackgroundWhiteGrayText2, resourcesProvider), .85f)); + arrowPath.rewind(); + final float cy = getMeasuredHeight() / 2f, cx = LocaleController.isRTL ? dpf2(24.33f + 5.33f) : getMeasuredWidth() - dpf2(24.33f); + arrowPath.moveTo(cx, cy - dpf2(5.66f)); + arrowPath.lineTo(cx + (LocaleController.isRTL ? -1 : 1) * dpf2(5.33f), cy); + arrowPath.lineTo(cx, cy + dpf2(5.66f)); + } + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Business/QuickRepliesController.java b/TMessagesProj/src/main/java/org/telegram/ui/Business/QuickRepliesController.java new file mode 100644 index 00000000000..cefd2c29190 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Business/QuickRepliesController.java @@ -0,0 +1,768 @@ +package org.telegram.ui.Business; + +import android.text.TextUtils; + +import org.telegram.SQLite.SQLiteCursor; +import org.telegram.SQLite.SQLiteDatabase; +import org.telegram.SQLite.SQLitePreparedStatement; +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.DownloadController; +import org.telegram.messenger.FileLog; +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.UserConfig; +import org.telegram.messenger.Utilities; +import org.telegram.tgnet.ConnectionsManager; +import org.telegram.tgnet.NativeByteBuffer; +import org.telegram.tgnet.TLRPC; +import org.telegram.ui.ChatActivity; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashSet; + +public class QuickRepliesController { + + public static final String GREETING = "hello"; + public static final String AWAY = "away"; + public static boolean isSpecial(String name) { + return GREETING.equalsIgnoreCase(name) || AWAY.equalsIgnoreCase(name); + } + + private static volatile QuickRepliesController[] Instance = new QuickRepliesController[UserConfig.MAX_ACCOUNT_COUNT]; + private static final Object[] lockObjects = new Object[UserConfig.MAX_ACCOUNT_COUNT]; + static { + for (int i = 0; i < UserConfig.MAX_ACCOUNT_COUNT; i++) { + lockObjects[i] = new Object(); + } + } + public static QuickRepliesController getInstance(int num) { + QuickRepliesController localInstance = Instance[num]; + if (localInstance == null) { + synchronized (lockObjects[num]) { + localInstance = Instance[num]; + if (localInstance == null) { + Instance[num] = localInstance = new QuickRepliesController(num); + } + } + } + return localInstance; + } + + public final int currentAccount; + private QuickRepliesController(int currentAccount) { + this.currentAccount = currentAccount; + } + + public class QuickReply { + public int id; + public String name; + public int order; + public int topMessageId; + public MessageObject topMessage; + public int messagesCount; + public boolean local; + public HashSet localIds = new HashSet<>(); + public int getTopMessageId() { + if (topMessage != null) return topMessage.getId(); + return topMessageId; + } + public int getMessagesCount() { + if (local) return localIds.size(); + return messagesCount; + } + public boolean isSpecial() { + return QuickRepliesController.isSpecial(name); + } + } + + public boolean canAddNew() { + boolean containsGreeting = false; + boolean containsAway = false; + for (int i = 0; i < replies.size(); ++i) { + containsGreeting = containsGreeting || GREETING.equalsIgnoreCase(replies.get(i).name); + containsAway = containsAway || AWAY.equalsIgnoreCase(replies.get(i).name); + if (containsGreeting && containsAway) break; + } + final int currentCount = replies.size() + (containsGreeting ? 0 : 1) + (containsAway ? 0 : 1); + return currentCount < MessagesController.getInstance(currentAccount).quickRepliesLimit; + } + + public final ArrayList replies = new ArrayList<>(); + public final ArrayList localReplies = new ArrayList<>(); + + private ArrayList filtered = new ArrayList<>(); + public ArrayList getFilteredReplies() { + filtered.clear(); + for (int i = 0; i < replies.size(); ++i) { + if (!replies.get(i).isSpecial()) { + filtered.add(replies.get(i)); + } + } + return filtered; + } + + private boolean loading; + private boolean loaded; + public void load() { +// if (!UserConfig.getInstance(currentAccount).isPremium()) return; + load(true, null); + } + private void load(boolean cache) { + load(cache, null); + } + private void load(boolean cache, Runnable whenLoaded) { + if (loading || loaded) return; + loading = true; + if (cache) { + MessagesStorage storage = MessagesStorage.getInstance(currentAccount); + final long selfId = UserConfig.getInstance(currentAccount).getClientUserId(); + storage.getStorageQueue().postRunnable(() -> { + final ArrayList result = new ArrayList<>(); + final ArrayList users = new ArrayList<>(); + final ArrayList chats = new ArrayList<>(); + + SQLiteCursor cursor = null; + try { + SQLiteDatabase db = storage.getDatabase(); + cursor = db.queryFinalized("SELECT topic_id, name, order_value, count FROM business_replies ORDER BY order_value ASC"); + while (cursor.next()) { + QuickReply reply = new QuickReply(); + reply.id = cursor.intValue(0); + reply.name = cursor.stringValue(1); + reply.order = cursor.intValue(2); + reply.messagesCount = cursor.intValue(3); + result.add(reply); + } + cursor.dispose(); + + ArrayList usersToLoad = new ArrayList<>(); + ArrayList chatsToLoad = new ArrayList<>(); + + for (int i = 0; i < result.size(); ++i) { + QuickReply reply = result.get(i); + cursor = db.queryFinalized("SELECT data, send_state, mid, date, topic_id, ttl FROM quick_replies_messages WHERE topic_id = ? ORDER BY mid ASC", reply.id); + if (cursor.next()) { + NativeByteBuffer data = cursor.byteBufferValue(0); + if (data != null) { + TLRPC.Message message = TLRPC.Message.TLdeserialize(data, data.readInt32(false), false); + message.send_state = cursor.intValue(1); + message.readAttachPath(data, selfId); + data.reuse(); + message.id = cursor.intValue(2); + message.date = cursor.intValue(3); + message.flags |= 1073741824; + message.quick_reply_shortcut_id = cursor.intValue(4); + message.ttl = cursor.intValue(5); + MessagesStorage.addUsersAndChatsFromMessage(message, usersToLoad, chatsToLoad, null); + + reply.topMessage = new MessageObject(currentAccount, message, false, true); + reply.topMessageId = message.id; + reply.topMessage.generateThumbs(false); + reply.topMessage.applyQuickReply(reply.name, reply.id); + } + } + cursor.dispose(); + } + + if (!chatsToLoad.isEmpty()) { + storage.getChatsInternal(TextUtils.join(",", chatsToLoad), chats); + } + if (!usersToLoad.isEmpty()) { + storage.getUsersInternal(TextUtils.join(",", usersToLoad), users); + } + + } catch (Exception e) { + FileLog.e(e); + } finally { + if (cursor != null) { + cursor.dispose(); + } + } + + AndroidUtilities.runOnUIThread(() -> { + loading = false; + MessagesController.getInstance(currentAccount).putUsers(users, false); + MessagesController.getInstance(currentAccount).putChats(chats, false); + replies.clear(); + replies.addAll(result); + if (whenLoaded != null) { + whenLoaded.run(); + } else { + load(false); + } + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.quickRepliesUpdated); + }); + }); + } else { + TLRPC.TL_messages_getQuickReplies req = new TLRPC.TL_messages_getQuickReplies(); + req.hash = 0; + for (int i = 0; i < replies.size(); ++i) { + QuickReply reply = replies.get(i); + + req.hash = MediaDataController.calcHash(req.hash, reply.id); + req.hash = MediaDataController.calcHash(req.hash, reply.name == null ? 0 : Long.parseUnsignedLong(Utilities.MD5(reply.name).substring(0, 16), 16)); + req.hash = MediaDataController.calcHash(req.hash, reply.topMessage == null ? 0 : reply.topMessage.getId()); + if (reply.topMessage != null && reply.topMessage.messageOwner != null && (reply.topMessage.messageOwner.flags & TLRPC.MESSAGE_FLAG_EDITED) != 0) { + req.hash = MediaDataController.calcHash(req.hash, reply.topMessage.messageOwner.edit_date); + } else { + req.hash = MediaDataController.calcHash(req.hash, 0); + } + } + ConnectionsManager.getInstance(currentAccount).sendRequest(req, ((res, err) -> AndroidUtilities.runOnUIThread(() -> { + ArrayList result = null; + if (res instanceof TLRPC.TL_messages_quickReplies) { + TLRPC.TL_messages_quickReplies quickReplies = (TLRPC.TL_messages_quickReplies) res; + MessagesController.getInstance(currentAccount).putUsers(quickReplies.users, false); + MessagesController.getInstance(currentAccount).putChats(quickReplies.chats, false); + MessagesStorage.getInstance(currentAccount).putUsersAndChats(quickReplies.users, quickReplies.chats, true, true); + + result = new ArrayList<>(); + for (int i = 0; i < quickReplies.quick_replies.size(); ++i) { + TLRPC.TL_quickReply tlreply = quickReplies.quick_replies.get(i); + QuickReply quickReply = new QuickReply(); + quickReply.id = tlreply.shortcut_id; + quickReply.name = tlreply.shortcut; + quickReply.messagesCount = tlreply.count; + quickReply.topMessageId = tlreply.top_message; + quickReply.order = i; + + TLRPC.Message message = null; + for (int j = 0; j < quickReplies.messages.size(); ++j) { + TLRPC.Message m = quickReplies.messages.get(j); + if (m.id == tlreply.top_message) { + message = m; + break; + } + } + + if (message != null) { + quickReply.topMessage = new MessageObject(currentAccount, message, false, true); + quickReply.topMessage.generateThumbs(false); + quickReply.topMessage.applyQuickReply(tlreply.shortcut, tlreply.shortcut_id); + } + + result.add(quickReply); + } + } else if (res instanceof TLRPC.TL_messages_quickRepliesNotModified) { + + } + loading = false; + if (result != null) { + replies.clear(); + replies.addAll(result); + } + loaded = true; + saveToCache(); + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.quickRepliesUpdated); + }))); + } + } + + private void ensureLoaded(Runnable done) { + if (loaded) { + done.run(); + } else { + load(true, done); + } + } + + private void saveToCache() { + MessagesStorage storage = MessagesStorage.getInstance(currentAccount); + storage.getStorageQueue().postRunnable(() -> { + SQLitePreparedStatement state = null; + try { + SQLiteDatabase db = storage.getDatabase(); + db.executeFast("DELETE FROM business_replies").stepThis().dispose(); + state = db.executeFast("REPLACE INTO business_replies VALUES(?, ?, ?, ?)"); + for (int i = 0; i < replies.size(); ++i) { + QuickReply quickReply = replies.get(i); + state.requery(); + state.bindInteger(1, quickReply.id); + state.bindString(2, quickReply.name); + state.bindInteger(3, quickReply.order); + state.bindInteger(4, quickReply.messagesCount); + state.step(); + } + } catch (Exception e) { + FileLog.e(e); + } finally { + if (state != null) { + state.dispose(); + } + } + }); + } + + private void updateOrder() { + for (int i = 0; i < replies.size(); ++i) { + replies.get(i).order = i; + } + } + + private void addReply(QuickReply reply) { + MessagesStorage storage = MessagesStorage.getInstance(currentAccount); + storage.getStorageQueue().postRunnable(() -> { + SQLitePreparedStatement state = null; + try { + SQLiteDatabase db = storage.getDatabase(); + state = db.executeFast("REPLACE INTO business_replies VALUES(?, ?, ?, ?);"); + state.requery(); + state.bindInteger(1, reply.id); + state.bindString(2, reply.name); + state.bindInteger(3, reply.order); + state.bindInteger(4, reply.messagesCount); + state.step(); + } catch (Exception e) { + FileLog.e(e); + } finally { + if (state != null) { + state.dispose(); + } + } + }); + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.quickRepliesUpdated); + } + + public QuickReply findReply(long topicId) { + for (QuickReply reply : replies) { + if (reply.id == topicId) { + return reply; + } + } + return null; + } + + public QuickReply findReply(String name) { + for (QuickReply reply : replies) { + if (TextUtils.equals(name, reply.name)) { + return reply; + } + } + return null; + } + + public QuickReply findLocalReply(long topicId) { + for (QuickReply reply : localReplies) { + if (reply.id == topicId) { + return reply; + } + } + return null; + } + + public QuickReply findLocalReply(String name) { + for (QuickReply reply : localReplies) { + if (TextUtils.equals(name, reply.name)) { + return reply; + } + } + return null; + } + + public boolean isNameBusy(String name, int exceptId) { + QuickReply reply = findReply(name); + return reply != null && reply.id != exceptId; + } + + public long getTopicId(String quick_shortcut) { + QuickReply reply = findReply(quick_shortcut); + if (reply != null) return reply.id; + return 0; + } + + public void removeReply(long topicId) { + QuickReply reply = null; + for (int i = 0; i < replies.size(); ++i) { + if (replies.get(i).id == topicId) { + reply = replies.remove(i); + break; + } + } + if (reply == null) { + return; + } + deleteLocalReply(reply.name); + + MessagesStorage storage = MessagesStorage.getInstance(currentAccount); + storage.getStorageQueue().postRunnable(() -> { + try { + SQLiteDatabase db = storage.getDatabase(); + db.executeFast("DELETE FROM business_replies WHERE topic_id = " + topicId).stepThis().dispose(); + db.executeFast("DELETE FROM quick_replies_messages WHERE topic_id = " + topicId).stepThis().dispose(); + } catch (Exception e) { + FileLog.e(e); + } + }); + + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.quickRepliesUpdated); + } + + public void reorder() { + ArrayList oldOrder = new ArrayList<>(); + for (int i = 0; i < replies.size(); ++i) { + oldOrder.add(replies.get(i).id); + } + Collections.sort(replies, (a, b) -> a.order - b.order); + boolean orderUpdated = false; + for (int i = 0; i < replies.size(); ++i) { + if (replies.get(i).id != oldOrder.get(i)) { + orderUpdated = true; + break; + } + } + if (orderUpdated) { + TLRPC.TL_messages_reorderQuickReplies req = new TLRPC.TL_messages_reorderQuickReplies(); + for (int i = 0; i < replies.size(); ++i) { + req.order.add(replies.get(i).id); + } + ConnectionsManager.getInstance(currentAccount).sendRequest(req, (res, err) -> AndroidUtilities.runOnUIThread(() -> { + + })); + saveToCache(); + } + } + + public void renameReply(int topicId, String name) { + QuickReply reply = findReply(topicId); + if (reply == null) return; + final String oldName = reply.name; + reply.name = name; + TLRPC.TL_messages_editQuickReplyShortcut req = new TLRPC.TL_messages_editQuickReplyShortcut(); + req.shortcut_id = topicId; + req.shortcut = name; + ConnectionsManager.getInstance(currentAccount).sendRequest(req, (res, err) -> AndroidUtilities.runOnUIThread(() -> { + + })); + saveToCache(); + + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.quickRepliesUpdated); + } + + public void deleteReplies(ArrayList ids) { + for (int i = 0; i < ids.size(); ++i) { + if (findReply(ids.get(i)) == null) { + ids.remove(i); + i--; + } + } + if (ids.isEmpty()) return; + final ArrayList finalIds = ids; + for (int i = 0; i < ids.size(); ++i) { + QuickReply reply = findReply(ids.get(i)); + replies.remove(reply); + deleteLocalReply(reply.name); + + TLRPC.TL_messages_deleteQuickReplyShortcut req = new TLRPC.TL_messages_deleteQuickReplyShortcut(); + req.shortcut_id = reply.id; + ConnectionsManager.getInstance(currentAccount).sendRequest(req, (res, err) -> AndroidUtilities.runOnUIThread(() -> { + + })); + + if (GREETING.equals(reply.name)) { + ConnectionsManager.getInstance(currentAccount).sendRequest(new TLRPC.TL_account_updateBusinessGreetingMessage(), null); + TLRPC.UserFull userInfo = MessagesController.getInstance(currentAccount).getUserFull(UserConfig.getInstance(currentAccount).getClientUserId()); + if (userInfo != null) { + userInfo.flags2 &=~ 4; + userInfo.business_greeting_message = null; + MessagesStorage.getInstance(currentAccount).updateUserInfo(userInfo, true); + } + } else if (AWAY.equals(reply.name)) { + ConnectionsManager.getInstance(currentAccount).sendRequest(new TLRPC.TL_account_updateBusinessAwayMessage(), null); + TLRPC.UserFull userInfo = MessagesController.getInstance(currentAccount).getUserFull(UserConfig.getInstance(currentAccount).getClientUserId()); + if (userInfo != null) { + userInfo.flags2 &=~ 8; + userInfo.business_away_message = null; + MessagesStorage.getInstance(currentAccount).updateUserInfo(userInfo, true); + } + } + } + saveToCache(); + final MessagesStorage storage = MessagesStorage.getInstance(currentAccount); + storage.getStorageQueue().postRunnable(() -> { + try { + storage.getDatabase().executeFast(String.format("DELETE FROM quick_replies_messages WHERE topic_id IN (%s)", TextUtils.join(", ", finalIds))).stepThis().dispose(); + } catch (Exception e) { + FileLog.e(e); + } + }); + + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.quickRepliesUpdated); + } + + private void updateTopMessage(QuickReply reply) { + if (reply == null) return; + final long selfId = UserConfig.getInstance(currentAccount).getClientUserId(); + final MessagesStorage storage = MessagesStorage.getInstance(currentAccount); + storage.getStorageQueue().postRunnable(() -> { + SQLiteCursor cursor = null; + try { + ArrayList usersToLoad = new ArrayList<>(); + ArrayList chatsToLoad = new ArrayList<>(); + + MessageObject messageObject = null; + cursor = storage.getDatabase().queryFinalized("SELECT data, send_state, mid, date, topic_id, ttl FROM quick_replies_messages WHERE topic_id = ? ORDER BY mid ASC", reply.id); + if (cursor.next()) { + NativeByteBuffer data = cursor.byteBufferValue(0); + if (data != null) { + TLRPC.Message message = TLRPC.Message.TLdeserialize(data, data.readInt32(false), false); + message.send_state = cursor.intValue(1); + message.readAttachPath(data, selfId); + data.reuse(); + message.id = cursor.intValue(2); + message.date = cursor.intValue(3); + message.flags |= 1073741824; + message.quick_reply_shortcut_id = cursor.intValue(4); + message.ttl = cursor.intValue(5); + MessagesStorage.addUsersAndChatsFromMessage(message, usersToLoad, chatsToLoad, null); + + messageObject = new MessageObject(currentAccount, message, false, true); + } + } + cursor.dispose(); + + final ArrayList users = new ArrayList<>(); + final ArrayList chats = new ArrayList<>(); + if (!chatsToLoad.isEmpty()) { + storage.getChatsInternal(TextUtils.join(",", chatsToLoad), chats); + } + if (!usersToLoad.isEmpty()) { + storage.getUsersInternal(TextUtils.join(",", usersToLoad), users); + } + final MessageObject finalMessageObject = messageObject; + AndroidUtilities.runOnUIThread(() -> { + MessagesController.getInstance(currentAccount).putUsers(users, false); + MessagesController.getInstance(currentAccount).putChats(chats, false); + reply.topMessage = finalMessageObject; + if (reply.topMessage != null) { + reply.topMessage.applyQuickReply(reply.name, reply.id); + } + saveToCache(); + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.quickRepliesUpdated); + }); + } catch (Exception e) { + FileLog.e(e); + } finally { + if (cursor != null) { + cursor.dispose(); + } + } + }); + // TODO + } + + public boolean processUpdate(TLRPC.Update update, String quick_reply_shortcut, int quick_reply_shortcut_id) { + if (update instanceof TLRPC.TL_updateQuickReplyMessage) { + TLRPC.Message message = ((TLRPC.TL_updateQuickReplyMessage) update).message; + ensureLoaded(() -> { + if ((message.flags & 1073741824) != 0) { + QuickReply reply = findReply(message.quick_reply_shortcut_id); + if (reply == null) { + QuickReply newReply = new QuickReply(); + newReply.id = message.quick_reply_shortcut_id; + newReply.topMessageId = message.id; + newReply.topMessage = new MessageObject(currentAccount, message, false, true); + newReply.topMessage.generateThumbs(false); + if (quick_reply_shortcut != null) { + newReply.name = quick_reply_shortcut; + deleteLocalReply(newReply.name); + } + newReply.topMessage.applyQuickReply(quick_reply_shortcut, quick_reply_shortcut_id); + newReply.messagesCount = 1; + replies.add(0, newReply); + updateOrder(); + addReply(newReply); + } else if (reply.topMessageId == message.id) { + reply.topMessageId = message.id; + reply.topMessage = new MessageObject(currentAccount, message, false, true); + reply.topMessage.generateThumbs(false); + saveToCache(); + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.quickRepliesUpdated); + } else if ((message.flags & TLRPC.MESSAGE_FLAG_EDITED) == 0) { + reply.messagesCount++; + saveToCache(); + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.quickRepliesUpdated); + } + } + + if (quick_reply_shortcut == null && quick_reply_shortcut_id == 0) { + ArrayList array = new ArrayList<>(); + array.add(message); + MessagesStorage.getInstance(currentAccount).putMessages(array, true, true, false, DownloadController.getInstance(currentAccount).getAutodownloadMask(), ChatActivity.MODE_QUICK_REPLIES, message.quick_reply_shortcut_id); + final long selfId = UserConfig.getInstance(currentAccount).getClientUserId(); + + ArrayList msgObjs = new ArrayList<>(); + msgObjs.add(new MessageObject(currentAccount, message, true, true)); + MessagesController.getInstance(currentAccount).updateInterfaceWithMessages(selfId, msgObjs, ChatActivity.MODE_QUICK_REPLIES); + } + }); + return true; + } else if (update instanceof TLRPC.TL_updateQuickReplies) { + ensureLoaded(() -> { + ArrayList quick_replies = ((TLRPC.TL_updateQuickReplies) update).quick_replies; + ArrayList oldReplies = new ArrayList<>(replies); + replies.clear(); + for (int i = 0; i < quick_replies.size(); ++i) { + TLRPC.TL_quickReply tlreply = quick_replies.get(i); + QuickReply quickReply = null; + for (int j = 0; j < oldReplies.size(); ++j) { + if (oldReplies.get(j).id == tlreply.shortcut_id) { + quickReply = oldReplies.get(j); + break; + } + } + if (quickReply == null) { + quickReply = new QuickReply(); + } + quickReply.id = tlreply.shortcut_id; + quickReply.name = tlreply.shortcut; + quickReply.messagesCount = tlreply.count; + quickReply.order = i; + quickReply.topMessageId = tlreply.top_message; + if (quickReply.topMessage != null && quickReply.topMessage.getId() != tlreply.top_message) { + quickReply.topMessage = null; + } + replies.add(quickReply); + deleteLocalReply(quickReply.name); + } + saveToCache(); + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.quickRepliesUpdated); + }); + return true; + } else if (update instanceof TLRPC.TL_updateNewQuickReply) { + ensureLoaded(() -> { + TLRPC.TL_quickReply tlreply = ((TLRPC.TL_updateNewQuickReply) update).quick_reply; + QuickRepliesController.QuickReply reply = findReply(tlreply.shortcut_id); + if (reply != null) { + reply.name = tlreply.shortcut; + reply.messagesCount = tlreply.count; + reply.topMessageId = tlreply.top_message; + if (reply.topMessage != null && reply.topMessage.getId() != tlreply.top_message) { + reply.topMessage = null; + updateTopMessage(reply); + return; + } + } else { + QuickReply quickReply = new QuickReply(); + quickReply.id = tlreply.shortcut_id; + quickReply.name = tlreply.shortcut; + quickReply.messagesCount = tlreply.count; + quickReply.topMessageId = tlreply.top_message; + updateOrder(); + replies.add(0, quickReply); + deleteLocalReply(quickReply.name); + } + saveToCache(); + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.quickRepliesUpdated); + }); + return true; + } else if (update instanceof TLRPC.TL_updateDeleteQuickReply) { + ensureLoaded(() -> { + int id = ((TLRPC.TL_updateDeleteQuickReply) update).shortcut_id; + QuickReply reply = findReply(id); + if (reply != null) { + replies.remove(reply); + deleteLocalReply(reply.name); + final int topicId = reply.id; + MessagesStorage storage = MessagesStorage.getInstance(currentAccount); + storage.getStorageQueue().postRunnable(() -> { + try { + SQLiteDatabase db = storage.getDatabase(); + db.executeFast("DELETE FROM business_replies WHERE topic_id = " + topicId).stepThis().dispose(); + db.executeFast("DELETE FROM quick_replies_messages WHERE topic_id = " + topicId).stepThis().dispose(); + } catch (Exception e) { + FileLog.e(e); + } + }); + saveToCache(); + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.quickRepliesUpdated); + } + }); + return true; + } else if (update instanceof TLRPC.TL_updateDeleteQuickReplyMessages) { + ensureLoaded(() -> { + TLRPC.TL_updateDeleteQuickReplyMessages upd = (TLRPC.TL_updateDeleteQuickReplyMessages) update; + int id = upd.shortcut_id; + QuickReply quickReply = findReply(id); + if (quickReply != null) { + quickReply.messagesCount -= upd.messages.size(); + if (quickReply.messagesCount <= 0) { + replies.remove(quickReply); + } + if (upd.messages.contains(quickReply.getTopMessageId()) || quickReply.topMessage == null) { + quickReply.topMessage = null; + updateTopMessage(quickReply); + } else { + saveToCache(); + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.quickRepliesUpdated); + } + } + }); + return true; + } + return false; + } + + public void checkLocalMessages(ArrayList messages) { + for (MessageObject message : messages) { + if (!message.isSending()) continue; + QuickReply reply = findReply(message.getQuickReplyId()); + if (reply != null) continue; + if (message.getQuickReplyName() == null) continue; + reply = findReply(message.getQuickReplyName()); + if (reply != null) continue; + + reply = findLocalReply(message.getQuickReplyName()); + if (reply == null) { + reply = new QuickReply(); + reply.local = true; + reply.name = message.getQuickReplyName(); + reply.id = -1; + reply.topMessage = message; + reply.topMessageId = message.getId(); + localReplies.add(reply); + } + reply.localIds.add(message.getId()); + + AndroidUtilities.runOnUIThread(() -> { + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.quickRepliesUpdated); + }); + } + } + + public void deleteLocalReply(String name) { + QuickReply reply = findLocalReply(name); + if (reply != null) { + localReplies.remove(reply); + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.quickRepliesUpdated); + } + } + + public void deleteLocalMessages(ArrayList messages) { + for (int id : messages) { + deleteLocalMessage(id); + } + } + + public void deleteLocalMessage(int messageId) { + for (int i = 0; i < localReplies.size(); ++i) { + QuickReply reply = localReplies.get(i); + if (reply.localIds.contains(messageId)) { + reply.localIds.remove((Integer) messageId); + if (reply.getMessagesCount() <= 0) { + localReplies.remove(reply); + } + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.quickRepliesUpdated); + break; + } + } + } + + public boolean hasReplies() { + return !replies.isEmpty(); + } + +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Business/TimezoneSelector.java b/TMessagesProj/src/main/java/org/telegram/ui/Business/TimezoneSelector.java new file mode 100644 index 00000000000..99858a16099 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Business/TimezoneSelector.java @@ -0,0 +1,220 @@ +package org.telegram.ui.Business; + +import static org.telegram.messenger.AndroidUtilities.dp; +import static org.telegram.messenger.LocaleController.formatString; +import static org.telegram.messenger.LocaleController.getString; + +import android.content.Context; +import android.text.TextUtils; +import android.util.TypedValue; +import android.view.Gravity; +import android.view.View; +import android.view.ViewGroup; +import android.widget.EditText; +import android.widget.FrameLayout; +import android.widget.LinearLayout; +import android.widget.TextView; + +import androidx.recyclerview.widget.RecyclerView; + +import org.telegram.messenger.AndroidUtilities; +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.Utilities; +import org.telegram.tgnet.TLRPC; +import org.telegram.ui.ActionBar.ActionBar; +import org.telegram.ui.ActionBar.ActionBarMenuItem; +import org.telegram.ui.ActionBar.BaseFragment; +import org.telegram.ui.ActionBar.Theme; +import org.telegram.ui.Cells.TextCheckCell; +import org.telegram.ui.Components.BackupImageView; +import org.telegram.ui.Components.LayoutHelper; +import org.telegram.ui.Components.StickerEmptyView; +import org.telegram.ui.Components.UItem; +import org.telegram.ui.Components.UniversalAdapter; +import org.telegram.ui.Components.UniversalRecyclerView; + +import java.util.ArrayList; + +public class TimezoneSelector extends BaseFragment implements NotificationCenter.NotificationCenterDelegate { + + private ActionBarMenuItem searchItem; + private UniversalRecyclerView listView; + private LinearLayout emptyView; + + private final static int search = 1; + + @Override + public View createView(Context context) { + actionBar.setBackButtonImage(R.drawable.ic_ab_back); + actionBar.setAllowOverlayTitle(true); + actionBar.setTitle(getString(R.string.TimezoneTitle)); + actionBar.setActionBarMenuOnItemClick(new ActionBar.ActionBarMenuOnItemClick() { + @Override + public void onItemClick(int id) { + if (id == -1) { + finishFragment(); + } + } + }); + + searchItem = actionBar.createMenu().addItem(search, R.drawable.ic_ab_search).setIsSearchField(true).setActionBarMenuItemSearchListener(new ActionBarMenuItem.ActionBarMenuItemSearchListener() { + @Override + public void onSearchExpand() { + searching = true; + listView.adapter.update(true); + listView.scrollToPosition(0); + } + + @Override + public void onSearchCollapse() { + searching = false; + query = null; + listView.adapter.update(true); + listView.scrollToPosition(0); + } + + @Override + public void onTextChanged(EditText editText) { + query = editText.getText().toString(); + listView.adapter.update(true); + listView.scrollToPosition(0); + } + }); + searchItem.setSearchFieldHint(LocaleController.getString(R.string.Search)); + + FrameLayout contentView = new FrameLayout(context); + contentView.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundGray)); + + listView = new UniversalRecyclerView(context, currentAccount, this::fillItems, this::onClick, null, getResourceProvider()); + contentView.addView(listView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); + + listView.setOnScrollListener(new RecyclerView.OnScrollListener() { + @Override + public void onScrollStateChanged(RecyclerView recyclerView, int newState) { + if (newState == RecyclerView.SCROLL_STATE_DRAGGING) { + AndroidUtilities.hideKeyboard(getParentActivity().getCurrentFocus()); + } + } + }); + + emptyView = new LinearLayout(context); + emptyView.setOrientation(LinearLayout.VERTICAL); + emptyView.setMinimumHeight(dp(500)); + BackupImageView emptyImageView = new BackupImageView(context); + emptyImageView.getImageReceiver().setAllowLoadingOnAttachedOnly(false); + MediaDataController.getInstance(currentAccount).setPlaceholderImage(emptyImageView, "RestrictedEmoji", "\uD83C\uDF16", "130_130"); + emptyView.addView(emptyImageView, LayoutHelper.createLinear(130, 130, Gravity.TOP | Gravity.CENTER_HORIZONTAL, 0, 42, 0, 12)); + TextView emptyTextView = new TextView(context); + emptyTextView.setText(getString(R.string.TimezoneNotFound)); + emptyTextView.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteGrayText, resourceProvider)); + emptyTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 15); + emptyView.addView(emptyTextView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.TOP | Gravity.CENTER_HORIZONTAL, 0, 0, 0, 0)); + + return fragmentView = contentView; + } + + public TimezoneSelector setValue(String timezoneKey) { + currentTimezone = timezoneKey; + return this; + } + + @Override + public boolean onFragmentCreate() { + systemTimezone = TimezonesController.getInstance(currentAccount).getSystemTimezoneId(); + useSystem = TextUtils.equals(systemTimezone, currentTimezone); + getNotificationCenter().addObserver(this, NotificationCenter.timezonesUpdated); + return super.onFragmentCreate(); + } + + private Utilities.Callback whenTimezoneSelected; + public TimezoneSelector whenSelected(Utilities.Callback selected) { + whenTimezoneSelected = selected; + return this; + } + + private boolean searching; + private String query; + + private String systemTimezone; + private boolean useSystem; + private String currentTimezone; + + private static final int BUTTON_DETECT = -1; + + private void fillItems(ArrayList items, UniversalAdapter adapter) { + final boolean filter = searching && !TextUtils.isEmpty(query); + final TimezonesController controller = TimezonesController.getInstance(currentAccount); + if (!filter) { + items.add(UItem.asRippleCheck(BUTTON_DETECT, getString(R.string.TimezoneDetectAutomatically)).setChecked(useSystem)); + items.add(UItem.asShadow(formatString(R.string.TimezoneDetectAutomaticallyInfo, controller.getTimezoneName(currentTimezone, true)))); + items.add(UItem.asHeader(getString(R.string.TimezoneHeader))); + } + boolean empty = true; + for (int i = 0; i < controller.getTimezones().size(); ++i) { + TLRPC.TL_timezone timezone = controller.getTimezones().get(i); + if (filter) { + String timezoneQuery = AndroidUtilities.translitSafe(timezone.name).toLowerCase().replace("/", " "); + String q = AndroidUtilities.translitSafe(query).toLowerCase(); + if (!(timezoneQuery.contains(" " + q) || timezoneQuery.startsWith(q))) { + continue; + } + } + items.add(UItem.asRadio(i, controller.getTimezoneName(timezone, false), controller.getTimezoneOffsetName(timezone)).setChecked(TextUtils.equals(timezone.id, currentTimezone)).setEnabled(!useSystem || filter)); + empty = false; + } + if (empty) { + items.add(UItem.asCustom(emptyView)); + } else { + items.add(UItem.asShadow(null)); + } + } + + private void onClick(UItem item, View view, int position, float x, float y) { + if (item.id == BUTTON_DETECT) { + useSystem = !useSystem; + if (useSystem) { + currentTimezone = systemTimezone; + if (whenTimezoneSelected != null) { + whenTimezoneSelected.run(currentTimezone); + } + } + ((TextCheckCell) view).setChecked(useSystem); + listView.adapter.update(true); + } else { + if (!view.isEnabled()) return; + final TimezonesController controller = TimezonesController.getInstance(currentAccount); + if (item.id < 0 || item.id >= controller.getTimezones().size()) { + return; + } + TLRPC.TL_timezone timezone = controller.getTimezones().get(item.id); + useSystem = false; + currentTimezone = timezone.id; + if (whenTimezoneSelected != null) { + whenTimezoneSelected.run(currentTimezone); + } + if (searching) { + actionBar.closeSearchField(true); + } + listView.adapter.update(true); + } + } + + @Override + public void didReceivedNotification(int id, int account, Object... args) { + if (id == NotificationCenter.timezonesUpdated) { + if (listView != null && listView.adapter != null) { + listView.adapter.update(true); + } + } + } + + @Override + public void onFragmentDestroy() { + getNotificationCenter().removeObserver(this, NotificationCenter.timezonesUpdated); + super.onFragmentDestroy(); + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Business/TimezonesController.java b/TMessagesProj/src/main/java/org/telegram/ui/Business/TimezonesController.java new file mode 100644 index 00000000000..a9af03682ea --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Business/TimezonesController.java @@ -0,0 +1,182 @@ +package org.telegram.ui.Business; + +import android.content.SharedPreferences; +import android.text.TextUtils; + +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.LocaleController; +import org.telegram.messenger.MessagesController; +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 org.telegram.tgnet.tl.TL_stories; + +import java.nio.ByteBuffer; +import java.time.Instant; +import java.time.ZoneId; +import java.time.format.TextStyle; +import java.util.ArrayList; + +public class TimezonesController { + + private static volatile TimezonesController[] Instance = new TimezonesController[UserConfig.MAX_ACCOUNT_COUNT]; + private static final Object[] lockObjects = new Object[UserConfig.MAX_ACCOUNT_COUNT]; + static { + for (int i = 0; i < UserConfig.MAX_ACCOUNT_COUNT; i++) { + lockObjects[i] = new Object(); + } + } + public static TimezonesController getInstance(int num) { + TimezonesController localInstance = Instance[num]; + if (localInstance == null) { + synchronized (lockObjects[num]) { + localInstance = Instance[num]; + if (localInstance == null) { + Instance[num] = localInstance = new TimezonesController(num); + } + } + } + return localInstance; + } + + public final int currentAccount; + private TimezonesController(int currentAccount) { + this.currentAccount = currentAccount; + } + + private boolean loading, loaded; + private final ArrayList timezones = new ArrayList<>(); + + public ArrayList getTimezones() { + load(); + return timezones; + } + + public void load() { + if (loading || loaded) return; + loading = true; + + SharedPreferences prefs = MessagesController.getInstance(currentAccount).getMainSettings(); + String value = prefs.getString("timezones", null); + TLRPC.help_timezonesList list = null; + if (value != null) { + SerializedData serializedData = new SerializedData(Utilities.hexToBytes(value)); + list = TLRPC.help_timezonesList.TLdeserialize(serializedData, serializedData.readInt32(false), false); + } + + timezones.clear(); + if (list != null) { + timezones.addAll(list.timezones); + } + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.timezonesUpdated); + + TLRPC.TL_help_getTimezonesList req = new TLRPC.TL_help_getTimezonesList(); + req.hash = list == null ? 0 : list.hash; + ConnectionsManager.getInstance(currentAccount).sendRequest(req, (res, err) -> AndroidUtilities.runOnUIThread(() -> { + if (res instanceof TLRPC.TL_help_timezonesList) { + timezones.clear(); + timezones.addAll(((TLRPC.TL_help_timezonesList) res).timezones); + SerializedData data = new SerializedData(res.getObjectSize()); + res.serializeToStream(data); + prefs.edit().putString("timezones", Utilities.bytesToHex(data.toByteArray())).apply(); + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.timezonesUpdated); + } + loaded = true; + loading = false; + })); + } + + public String getSystemTimezoneId() { + String systemDefaultId = null; + ZoneId zone = ZoneId.systemDefault(); + if (zone != null) { + systemDefaultId = zone.getId(); + } + + if (loading || !loaded) { + load(); + return systemDefaultId; + } + + for (int i = 0; i < timezones.size(); ++i) { + TLRPC.TL_timezone timezone = timezones.get(i); + if (TextUtils.equals(timezone.id, systemDefaultId)) { + return systemDefaultId; + } + } + + int systemUtcOffset = 0; + if (zone != null) { + systemUtcOffset = zone.getRules().getOffset(Instant.now()).getTotalSeconds(); + } + for (int i = 0; i < timezones.size(); ++i) { + TLRPC.TL_timezone timezone = timezones.get(i); + if (systemUtcOffset == timezone.utc_offset) { + return timezone.id; + } + } + + if (!timezones.isEmpty()) { + return timezones.get(0).id; + } + + return systemDefaultId; + } + + public TLRPC.TL_timezone findTimezone(String id) { + if (id == null) return null; + load(); + for (int i = 0; i < timezones.size(); ++i) { + TLRPC.TL_timezone timezone = timezones.get(i); + if (TextUtils.equals(timezone.id, id)) { + return timezone; + } + } + return null; + } + + public String getTimezoneName(TLRPC.TL_timezone timezone, boolean withOffset) { + if (timezone == null) return null; + if (withOffset) { + return timezone.name + ", " + getTimezoneOffsetName(timezone); + } + return timezone.name; + } + + public String getTimezoneOffsetName(TLRPC.TL_timezone timezone) { + String offset = "GMT"; + if (timezone.utc_offset != 0) { + offset += (timezone.utc_offset < 0 ? "-" : "+"); + int val = Math.abs(timezone.utc_offset) / 60; + int hr = (int) (val / 60); + int min = val % 60; + offset += (hr < 10 ? "0" : "") + hr; + offset += ":"; + offset += (min < 10 ? "0" : "") + min; + } + return offset; + } + + public String getTimezoneName(String id, boolean withOffset) { + TLRPC.TL_timezone timezone = findTimezone(id); + if (timezone != null) { + return getTimezoneName(timezone, withOffset); + } + + ZoneId timeZone = ZoneId.of(id); + if (timeZone == null) return ""; + String offset = null; + if (withOffset) { + offset = timeZone.getRules().getOffset(Instant.now()).getDisplayName(TextStyle.FULL, LocaleController.getInstance().getCurrentLocale()); + if (offset.length() == 1 && offset.charAt(0) == 'Z') { + offset = "GMT"; + } else { + offset = "GMT" + offset; + } + } + return timeZone.getId().replace("/", ", ").replace("_", " ") + (offset != null ? ", " + offset : ""); + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/CacheControlActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/CacheControlActivity.java index aadf792bc85..72706854f87 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/CacheControlActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/CacheControlActivity.java @@ -874,6 +874,7 @@ public static int countDirJava(String fileName, int docType) { File dir = new File(fileName); if (dir.exists()) { File[] entries = dir.listFiles(); + if (entries == null) return count; for (int i = 0; i < entries.length; ++i) { File entry = entries[i]; String name = entry.getName(); @@ -917,6 +918,7 @@ public static void cleanDirJava(String fileName, int docType, int[] p, Utilities File dir = new File(fileName); if (dir.exists()) { File[] entries = dir.listFiles(); + if (entries == null) return; for (int i = 0; i < entries.length; ++i) { File entry = entries[i]; String name = entry.getName(); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/CallLogActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/CallLogActivity.java index 46a3d945b9e..0d49fbdc838 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/CallLogActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/CallLogActivity.java @@ -615,7 +615,7 @@ private void showDeleteAlert(boolean all) { otherItem.setVisibility(View.GONE); listViewAdapter.notifyDataSetChanged(); } else { - getMessagesController().deleteMessages(new ArrayList<>(selectedIds), null, null, 0, checks[0], false); + getMessagesController().deleteMessages(new ArrayList<>(selectedIds), null, null, 0, 0, checks[0], 0); } hideActionMode(false); }); 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 cdc82f3be7d..063a5eaf12a 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/AboutLinkCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/AboutLinkCell.java @@ -252,6 +252,8 @@ protected boolean drawChild(Canvas canvas, View child, long drawingTime) { private Paint backgroundPaint = new Paint(); @Override public void draw(Canvas canvas) { + super.draw(canvas); + View parent = (View) getParent(); float alpha = parent == null ? 1f : (float) Math.pow(parent.getAlpha(), 2f); @@ -276,8 +278,6 @@ public void draw(Canvas canvas) { } container.draw(canvas); - - super.draw(canvas); } final float SPACE = AndroidUtilities.dp(3f); @@ -682,7 +682,7 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { private StaticLayout makeTextLayout(CharSequence string, int width) { if (Build.VERSION.SDK_INT >= 24) { - return StaticLayout.Builder.obtain(string, 0, string.length(), Theme.profile_aboutTextPaint, width) + return StaticLayout.Builder.obtain(string, 0, string.length(), Theme.profile_aboutTextPaint, Math.max(1, width)) .setBreakStrategy(StaticLayout.BREAK_STRATEGY_SIMPLE) .setHyphenationFrequency(StaticLayout.HYPHENATION_FREQUENCY_NONE) .setAlignment(LocaleController.isRTL ? StaticLayoutEx.ALIGN_RIGHT() : StaticLayoutEx.ALIGN_LEFT()) 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 1798e37bcc1..28e8c68e84e 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatMessageCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatMessageCell.java @@ -5414,7 +5414,9 @@ private void setMessageContent(MessageObject messageObject, MessageObject.Groupe } measureTime(messageObject); int timeMore = timeWidth + AndroidUtilities.dp(6); - if (messageObject.isOutOwner()) { + if (messageObject.isQuickReply() && !messageObject.isSendError()) { + timeMore -= dp(3); + } else if (messageObject.isOutOwner()) { timeMore += AndroidUtilities.dp(20.5f); } timeMore += getExtraTimeX(); @@ -6902,7 +6904,9 @@ private void setMessageContent(MessageObject messageObject, MessageObject.Groupe backgroundWidth = reactionsLayoutInBubble.width; } int timeMore = timeWidth + AndroidUtilities.dp(6); - if (messageObject.isOutOwner()) { + if (messageObject.isQuickReply() && !messageObject.isSendError()) { + timeMore -= dp(3); + } else if (messageObject.isOutOwner()) { timeMore += AndroidUtilities.dp(20.5f); } timeMore += getExtraTimeX(); @@ -9384,6 +9388,7 @@ private void updateWaveform() { } useTranscribeButton = ( currentMessageObject != null && + !currentMessageObject.isQuickReply() && !currentMessageObject.isRepostPreview && (!currentMessageObject.isOutOwner() || currentMessageObject.isSent()) && ( @@ -9781,18 +9786,22 @@ private void highlight(int start, int end, ArrayList= block.charactersOffset + length) { for (int a = c + 1; a < textLayoutBlocks.size(); a++) { MessageObject.TextLayoutBlock nextBlock = textLayoutBlocks.get(a); length = nextBlock.charactersEnd - nextBlock.charactersOffset; path = obtainNewUrlPath(); + path.setUseCornerPathImplementation(true); y += nextBlock.padTop; path.setCurrentLayout(nextBlock.textLayout, 0, y); y += nextBlock.height + nextBlock.padBottom; nextBlock.textLayout.getSelectionPath(0, end - nextBlock.charactersOffset, path); + path.closeRects(); if (end < block.charactersOffset + length - 1) { break; } @@ -13133,7 +13142,7 @@ public void updateCaptionLayout() { } private boolean textIsSelectionMode() { - if (getCurrentMessagesGroup() != null) { + if (getCurrentMessagesGroup() != null || delegate == null) { return false; } return delegate.getTextSelectionHelper() != null && delegate.getTextSelectionHelper().isSelected(currentMessageObject); @@ -14322,7 +14331,7 @@ private void measureTime(MessageObject messageObject) { } } } - if (currentMessageObject.isSponsored()) { + if (currentMessageObject.isSponsored() || currentMessageObject.isQuickReply()) { timeString = ""; } else if (currentMessageObject.scheduled && currentMessageObject.messageOwner.date == 0x7FFFFFFE) { timeString = ""; @@ -14331,9 +14340,9 @@ private void measureTime(MessageObject messageObject) { } else if (edited) { timeString = LocaleController.getString("EditedMessage", R.string.EditedMessage) + " " + LocaleController.getInstance().formatterDay.format((long) (messageObject.messageOwner.date) * 1000); } else if (currentMessageObject.isSaved && currentMessageObject.messageOwner.fwd_from != null && (currentMessageObject.messageOwner.fwd_from.date != 0 || currentMessageObject.messageOwner.fwd_from.saved_date != 0)) { - int date = currentMessageObject.messageOwner.fwd_from.date; + int date = currentMessageObject.messageOwner.fwd_from.saved_date; if (date == 0) { - date = currentMessageObject.messageOwner.fwd_from.saved_date; + date = currentMessageObject.messageOwner.fwd_from.date; } timeString = LocaleController.formatSeenDate(date); } else { @@ -14492,6 +14501,9 @@ private void updateCurrentUserAndChat() { } } else if (fwd_from != null && fwd_from.from_id instanceof TLRPC.TL_peerUser && (fwd_from.imported || currentMessageObject.getDialogId() == currentUserId)) { currentUser = messagesController.getUser(fwd_from.from_id.user_id); + } else if (fwd_from != null && !TextUtils.isEmpty(fwd_from.saved_from_name) && (fwd_from.imported || currentMessageObject.getDialogId() == currentUserId)) { + currentUser = new TLRPC.TL_user(); + currentUser.first_name = fwd_from.saved_from_name; } else if (fwd_from != null && !TextUtils.isEmpty(fwd_from.from_name) && (fwd_from.imported || currentMessageObject.getDialogId() == currentUserId)) { currentUser = new TLRPC.TL_user(); currentUser.first_name = fwd_from.from_name; @@ -14645,6 +14657,7 @@ private void setMessageObjectInternal(MessageObject messageObject) { nameOffsetX = nameLayout.getLineLeft(0); } else { nameWidth = nameLayoutWidth = 0; + nameOffsetX = 0; } if (currentNameStatus != null) { nameWidth += AndroidUtilities.dp(4 + 12 + 4); @@ -14681,6 +14694,7 @@ private void setMessageObjectInternal(MessageObject messageObject) { currentNameString = null; nameLayout = null; nameWidth = 0; + nameOffsetX = 0; } currentForwardUser = null; @@ -14831,7 +14845,7 @@ protected void onClick() { topicButton = null; } - if ((!messageObject.isGiveawayResults() && (!isThreadChat || isSavedChat || messageObject.getReplyTopMsgId(isForum) != 0 || isForumGeneral) && messageObject.hasValidReplyMessageObject() || messageObject.messageOwner.fwd_from != null && messageObject.isDice() || (messageObject.messageOwner.reply_to != null && (messageObject.messageOwner.reply_to.story_id != 0 || !TextUtils.isEmpty(messageObject.messageOwner.reply_to.quote_text) || messageObject.messageOwner.reply_to.reply_from != null))) && !messageObject.isRepostPreview) { + if ((!messageObject.isGiveawayResults() && (!isThreadChat || messageObject.isQuickReply() || isSavedChat || messageObject.getReplyTopMsgId(isForum) != 0 || isForumGeneral) && messageObject.hasValidReplyMessageObject() || messageObject.messageOwner.fwd_from != null && messageObject.isDice() || (messageObject.messageOwner.reply_to != null && (messageObject.messageOwner.reply_to.story_id != 0 || !TextUtils.isEmpty(messageObject.messageOwner.reply_to.quote_text) || messageObject.messageOwner.reply_to.reply_from != null))) && !messageObject.isRepostPreview) { if (currentPosition == null || currentPosition.minY == 0) { if (!messageObject.isAnyKindOfSticker() && messageObject.type != MessageObject.TYPE_ROUND_VIDEO || messageObject.type == MessageObject.TYPE_EMOJIS) { namesOffset += AndroidUtilities.dp(20) + (Theme.chat_replyTextPaint.getTextSize() + Theme.chat_replyNamePaint.getTextSize()); @@ -14881,7 +14895,7 @@ protected void onClick() { stringFinalText = StoriesUtilities.createReplyStoryString(); maxWidth -= AndroidUtilities.dp(16) + (textPaint.getTextSize() + Theme.chat_replyNamePaint.getTextSize()); } - } else if ((!isThreadChat || isSavedChat || messageObject.getReplyTopMsgId(isForum) != 0 || isForumGeneral) && messageObject.hasValidReplyMessageObject() || hasReplyQuote || messageObject.messageOwner.reply_to != null && messageObject.messageOwner.reply_to.reply_from != null) { + } else if ((!isThreadChat || messageObject.isQuickReply() || isSavedChat || messageObject.getReplyTopMsgId(isForum) != 0 || isForumGeneral) && messageObject.hasValidReplyMessageObject() || hasReplyQuote || messageObject.messageOwner.reply_to != null && messageObject.messageOwner.reply_to.reply_from != null) { lastReplyMessage = messageObject.replyMessageObject == null ? null : messageObject.replyMessageObject.messageOwner; int cacheType = 1; int size = 0; @@ -15199,7 +15213,7 @@ protected void onClick() { FileLog.e(e); } } - } else if (!isThreadChat && messageObject.getReplyMsgId() != 0 && !messageObject.isGiveawayResults() && !messageObject.isRepostPreview) { + } else if ((!isThreadChat || messageObject.isQuickReply()) && messageObject.getReplyMsgId() != 0 && !messageObject.isGiveawayResults() && !messageObject.isRepostPreview) { if (!(messageObject.replyMessageObject != null && (messageObject.replyMessageObject.messageOwner instanceof TLRPC.TL_messageEmpty || messageObject.replyMessageObject.messageOwner != null && messageObject.replyMessageObject.messageOwner.action instanceof TLRPC.TL_messageActionTopicCreate)) && (delegate == null || delegate.doNotShowLoadingReply(messageObject))) { if (!messageObject.isAnyKindOfSticker() && messageObject.type != MessageObject.TYPE_ROUND_VIDEO) { namesOffset += AndroidUtilities.dp(14 + 4) + (Theme.chat_replyTextPaint.getTextSize() + Theme.chat_replyNamePaint.getTextSize()); @@ -15661,7 +15675,7 @@ protected void onDraw(Canvas canvas) { if ((!autoPlayingMedia || !MediaController.getInstance().isPlayingMessageAndReadyToDraw(currentMessageObject) || isRoundVideo) && !transitionParams.animateBackgroundBoundsInner && !(currentMessageObject != null && currentMessageObject.preview)) { drawOverlays(canvas); } - if ((drawTime || !mediaBackground) && !forceNotDrawTime && !transitionParams.animateBackgroundBoundsInner && !(enterTransitionInProgress && !currentMessageObject.isVoice())) { + if ((drawTime || !mediaBackground) && !forceNotDrawTime && !transitionParams.animateBackgroundBoundsInner && !(enterTransitionInProgress && !currentMessageObject.isVoice()) && (!currentMessageObject.isQuickReply() || currentMessageObject.isSendError())) { drawTime(canvas, 1f, false); } @@ -16908,9 +16922,9 @@ public void drawNamesLayout(Canvas canvas, float alpha) { Theme.setSelectorDrawableColor(nameLayoutSelector, nameLayoutSelectorColor = selectorColor, true); } nameLayoutSelector.setBounds( - (int) (nx - dp(4)), + (int) (nx + nameOffsetX - dp(4)), (int) (nameY - dp(1.33f)), - (int) (nx + (viaNameWidth > 0 ? viaNameWidth - dp(4 + 28) : nameLayoutWidth) + dp(4)), + (int) (nx + nameOffsetX + (viaNameWidth > 0 ? viaNameWidth - dp(4 + 28) : nameLayoutWidth) + dp(4)), (int) (nameY + nameLayout.getHeight() + dp(1.33f)) ); nameLayoutSelector.setAlpha((int) (0xFF * nameAlpha)); @@ -16923,11 +16937,15 @@ public void drawNamesLayout(Canvas canvas, float alpha) { } else if (nameStatusSelectorColor != selectorColor) { Theme.setSelectorDrawableColor(nameStatusSelector, nameStatusSelectorColor = selectorColor, true); } + boolean isStarDrawable = currentNameStatus instanceof Drawable; + //star has smaller size than other emoji + float starVerticalOffset = isStarDrawable ? 1.5f : 0f; + float starHorizontalOffset = isStarDrawable ? -5 : 0; nameStatusSelector.setBounds( - (int) (nx + (viaNameWidth > 0 ? viaNameWidth - dp(4 + 28) : nameLayoutWidth)), - (int) (nameY - dp(1.33f + 2)), - (int) (nx + (viaNameWidth > 0 ? viaNameWidth - dp(4 + 28) : nameLayoutWidth) + dp(4 + 12 + 4 + 4)), - (int) (nameY + nameLayout.getHeight() + dp(1.33f + 2)) + (int) (nx + nameOffsetX + (viaNameWidth > 0 ? viaNameWidth - dp(4 + 28) : nameLayoutWidth)), + (int) (nameY - dp(1.33f + 2 - starVerticalOffset)), + (int) (nx + nameOffsetX + (viaNameWidth > 0 ? viaNameWidth - dp(4 + 28) : nameLayoutWidth) + dp(4 + 12 + 4 + 4 + starHorizontalOffset)), + (int) (nameY + nameLayout.getHeight() + dp(1.33f + 2 - starVerticalOffset)) ); nameStatusSelector.setAlpha((int) (0xFF * nameAlpha)); nameStatusSelector.draw(canvas); @@ -18390,30 +18408,32 @@ private void drawTimeInternal(Canvas canvas, float alpha, boolean fromParent, fl float timeHeight = Math.max(AndroidUtilities.dp(17), Theme.chat_timePaint.getTextSize() + AndroidUtilities.dp(5)); rect.set(x1, y1, x1 + timeWidth + AndroidUtilities.dp((bigRadius ? 12 : 8) + (currentMessageObject.isOutOwner() ? 20 + (currentMessageObject.type == MessageObject.TYPE_EMOJIS ? 4 : 0) : 0)), y1 + timeHeight); - if (currentMessageObject.hasMediaSpoilers() && currentMessageObject.type != MessageObject.TYPE_ROUND_VIDEO) { - rectPath.rewind(); - rectPath.addRoundRect(rect, r, r, Path.Direction.CW); - canvas.save(); - canvas.clipPath(rectPath); - ImageReceiver imageReceiver = currentMessageObject.needDrawBluredPreview() ? photoImage : blurredPhotoImage; - float wasAlpha = imageReceiver.getAlpha(); - imageReceiver.setAlpha(.5f * wasAlpha); - imageReceiver.draw(canvas); - imageReceiver.setAlpha(wasAlpha); - canvas.restore(); - Paint dimPaint = getThemedPaint(Theme.key_paint_chatTimeBackground); - int oldAlpha2 = dimPaint.getAlpha(); - dimPaint.setAlpha((int) (oldAlpha2 * controlsAlpha * .4f)); - canvas.drawRoundRect(rect, r, r, dimPaint); - dimPaint.setAlpha(oldAlpha2); - } else { - applyServiceShaderMatrix(); - canvas.drawRoundRect(rect, r, r, paint); - if (paint == getThemedPaint(Theme.key_paint_chatActionBackground) && hasGradientService()) { - int oldAlpha2 = Theme.chat_actionBackgroundGradientDarkenPaint.getAlpha(); - Theme.chat_actionBackgroundGradientDarkenPaint.setAlpha((int) (oldAlpha2 * timeAlpha * alpha)); - canvas.drawRoundRect(rect, r, r, Theme.chat_actionBackgroundGradientDarkenPaint); - Theme.chat_actionBackgroundGradientDarkenPaint.setAlpha(oldAlpha2); + if (!currentMessageObject.isQuickReply()) { + if (currentMessageObject.hasMediaSpoilers() && currentMessageObject.type != MessageObject.TYPE_ROUND_VIDEO) { + rectPath.rewind(); + rectPath.addRoundRect(rect, r, r, Path.Direction.CW); + canvas.save(); + canvas.clipPath(rectPath); + ImageReceiver imageReceiver = currentMessageObject.needDrawBluredPreview() ? photoImage : blurredPhotoImage; + float wasAlpha = imageReceiver.getAlpha(); + imageReceiver.setAlpha(.5f * wasAlpha); + imageReceiver.draw(canvas); + imageReceiver.setAlpha(wasAlpha); + canvas.restore(); + Paint dimPaint = getThemedPaint(Theme.key_paint_chatTimeBackground); + int oldAlpha2 = dimPaint.getAlpha(); + dimPaint.setAlpha((int) (oldAlpha2 * controlsAlpha * .4f)); + canvas.drawRoundRect(rect, r, r, dimPaint); + dimPaint.setAlpha(oldAlpha2); + } else { + applyServiceShaderMatrix(); + canvas.drawRoundRect(rect, r, r, paint); + if (paint == getThemedPaint(Theme.key_paint_chatActionBackground) && hasGradientService()) { + int oldAlpha2 = Theme.chat_actionBackgroundGradientDarkenPaint.getAlpha(); + Theme.chat_actionBackgroundGradientDarkenPaint.setAlpha((int) (oldAlpha2 * timeAlpha * alpha)); + canvas.drawRoundRect(rect, r, r, Theme.chat_actionBackgroundGradientDarkenPaint); + Theme.chat_actionBackgroundGradientDarkenPaint.setAlpha(oldAlpha2); + } } } paint.setAlpha(oldAlpha); @@ -22267,6 +22287,11 @@ public int createStatusDrawableParams() { drawClock = false; drawError = false; } + if (currentMessageObject.isQuickReply()) { + drawCheck1 = false; + drawCheck2 = false; + drawClock = false; + } return (drawCheck1 ? 1 : 0) | (drawCheck2 ? 2 : 0) | (drawClock ? 4 : 0) | (drawError ? 8 : 0); } else { boolean drawClock = currentMessageObject.isSending() || currentMessageObject.isEditing(); @@ -22306,7 +22331,7 @@ private ColorMatrixColorFilter getFancyBlurFilter() { } public int getNameStatusX() { - return (int) (nameX + (viaNameWidth > 0 ? viaNameWidth - dp(4 + 28) : nameLayoutWidth) + dp(2) + dp(4 + 12 + 4) / 2); + return (int) (nameX + nameOffsetX + (viaNameWidth > 0 ? viaNameWidth - dp(4 + 28) : nameLayoutWidth) + dp(2) + dp(4 + 12 + 4) / 2); } public int getNameStatusY() { 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 478109bd159..52051631af8 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/DialogCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/DialogCell.java @@ -91,6 +91,7 @@ import org.telegram.ui.Components.CheckBox2; import org.telegram.ui.Components.ColoredImageSpan; import org.telegram.ui.Components.CubicBezierInterpolator; +import org.telegram.ui.Components.DialogCellTags; import org.telegram.ui.Components.EmptyStubSpan; import org.telegram.ui.Components.ForegroundColorSpanThemable; import org.telegram.ui.Components.Forum.ForumBubbleDrawable; @@ -141,6 +142,8 @@ public class DialogCell extends BaseCell implements StoriesListPlaceProvider.Ava public int messagePaddingStart = 72; public int heightDefault = 72; public int heightThreeLines = 78; + public int addHeightForTags = 3; + public int addForumHeightForTags = 11; public TLRPC.TL_forumTopic forumTopic; public boolean useFromUserAsAvatar; private boolean isTopic; @@ -172,6 +175,7 @@ public class DialogCell extends BaseCell implements StoriesListPlaceProvider.Ava SharedResources sharedResources; public boolean isSavedDialog; public boolean isSavedDialogCell; + public DialogCellTags tags; public final StoriesUtilities.AvatarStoryParams storyParams = new StoriesUtilities.AvatarStoryParams(false) { @Override @@ -456,6 +460,7 @@ public boolean isBlocked() { private int checkDrawTop; private int halfCheckDrawLeft; + private int tagsLeft, tagsRight; private int messageTop; private int messageLeft; private int buttonLeft; @@ -574,17 +579,17 @@ public DialogCell(DialogsActivity fragment, Context context, boolean needCheck, this.resourcesProvider = resourcesProvider; parentFragment = fragment; Theme.createDialogsResources(context); - avatarImage.setRoundRadius(AndroidUtilities.dp(28)); + avatarImage.setRoundRadius(dp(28)); for (int i = 0; i < thumbImage.length; ++i) { thumbImage[i] = new ImageReceiver(this); thumbImage[i].ignoreNotifications = true; - thumbImage[i].setRoundRadius(AndroidUtilities.dp(2)); + thumbImage[i].setRoundRadius(dp(2)); thumbImage[i].setAllowLoadingOnAttachedOnly(true); } useForceThreeLines = forceThreeLines; currentAccount = account; - emojiStatus = new AnimatedEmojiDrawable.SwapAnimatedEmojiDrawable(this, AndroidUtilities.dp(22)); + emojiStatus = new AnimatedEmojiDrawable.SwapAnimatedEmojiDrawable(this, dp(22)); avatarImage.setAllowLoadingOnAttachedOnly(true); } @@ -611,6 +616,9 @@ public void setDialog(TLRPC.Dialog dialog, int type, int folder) { } dialogsType = type; showPremiumBlocked(dialogsType == DialogsActivity.DIALOGS_TYPE_FORWARD); + if (tags == null) { + tags = new DialogCellTags(); + } folderId = folder; messageId = 0; if (update(0, false)) { @@ -787,12 +795,12 @@ public void resetPinnedArchiveState() { protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { if (checkBox != null) { checkBox.measure( - MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(24), MeasureSpec.EXACTLY), - MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(24), MeasureSpec.EXACTLY) + MeasureSpec.makeMeasureSpec(dp(24), MeasureSpec.EXACTLY), + MeasureSpec.makeMeasureSpec(dp(24), MeasureSpec.EXACTLY) ); } if (isTopic) { - setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec), AndroidUtilities.dp(useForceThreeLines || SharedConfig.useThreeLinesLayout ? heightThreeLines : heightDefault) + (useSeparator ? 1 : 0)); + setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec), dp((useForceThreeLines || SharedConfig.useThreeLinesLayout ? heightThreeLines : heightDefault) + (hasTags() && (!(useForceThreeLines || SharedConfig.useThreeLinesLayout) || isForumCell()) ? (isForumCell() ? addForumHeightForTags : addHeightForTags) : 0)) + (useSeparator ? 1 : 0)); checkTwoLinesForName(); } @@ -802,20 +810,38 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { } private int computeHeight() { + int height; if (isForumCell() && !isTransitionSupport && !collapsed) { - return AndroidUtilities.dp(useForceThreeLines || SharedConfig.useThreeLinesLayout ? 86 : 91 + (useSeparator ? 1 : 0)); + height = dp(useForceThreeLines || SharedConfig.useThreeLinesLayout ? 86 : 91); + if (useSeparator) { + height += 1; + } + if (hasTags()) { + height += dp(addForumHeightForTags); + } } else { - return getCollapsedHeight(); + height = getCollapsedHeight(); } + return height; } private int getCollapsedHeight() { - return AndroidUtilities.dp(useForceThreeLines || SharedConfig.useThreeLinesLayout ? heightThreeLines : heightDefault) + (useSeparator ? 1 : 0) + (twoLinesForName ? AndroidUtilities.dp(20) : 0); + int height = dp(useForceThreeLines || SharedConfig.useThreeLinesLayout ? heightThreeLines : heightDefault); + if (useSeparator) { + height += 1; + } + if (twoLinesForName) { + height += dp(20); + } + if (hasTags() && (!(useForceThreeLines || SharedConfig.useThreeLinesLayout) || isForumCell())) { + height += dp(isForumCell() ? addForumHeightForTags : addHeightForTags); + } + return height; } private void checkTwoLinesForName() { twoLinesForName = false; - if (isTopic) { + if (isTopic && !hasTags()) { buildLayout(); if (nameIsEllipsized) { twoLinesForName = true; @@ -831,14 +857,14 @@ protected void onLayout(boolean changed, int left, int top, int right, int botto return; } if (checkBox != null) { - int paddingStart = AndroidUtilities.dp(messagePaddingStart - (useForceThreeLines || SharedConfig.useThreeLinesLayout ? 29 : 27)); + int paddingStart = dp(messagePaddingStart - (useForceThreeLines || SharedConfig.useThreeLinesLayout ? 29 : 27)); int x, y; if (inPreviewMode) { - x = AndroidUtilities.dp(8);//LocaleController.isRTL ? (right - left) - paddingStart : paddingStart; + x = dp(8);//LocaleController.isRTL ? (right - left) - paddingStart : paddingStart; y = (getMeasuredHeight() - checkBox.getMeasuredHeight()) >> 1; } else { x = LocaleController.isRTL ? (right - left) - paddingStart : paddingStart; - y = AndroidUtilities.dp(chekBoxPaddingTop + (useForceThreeLines || SharedConfig.useThreeLinesLayout ? 6 : 0)); + y = dp(chekBoxPaddingTop + (useForceThreeLines || SharedConfig.useThreeLinesLayout ? 6 : 0)); } checkBox.layout(x, y, x + checkBox.getMeasuredWidth(), y + checkBox.getMeasuredHeight()); } @@ -935,7 +961,15 @@ private CharSequence formatArchivedDialogNames() { } builder.append(LocaleController.formatPluralString("Stories", totalCount)); } - return Emoji.replaceEmoji(builder, Theme.dialogs_messagePaint[paintIndex].getFontMetricsInt(), AndroidUtilities.dp(17), false); + return Emoji.replaceEmoji(builder, Theme.dialogs_messagePaint[paintIndex].getFontMetricsInt(), dp(17), false); + } + + public boolean hasTags() { + return tags != null && !tags.isEmpty(); + } + + public boolean separateMessageNameLine() { + return (useForceThreeLines || SharedConfig.useThreeLinesLayout) && !hasTags(); } int thumbSize; @@ -952,24 +986,24 @@ public void buildLayout() { } if (useForceThreeLines || SharedConfig.useThreeLinesLayout) { - Theme.dialogs_namePaint[0].setTextSize(AndroidUtilities.dp(17)); - Theme.dialogs_nameEncryptedPaint[0].setTextSize(AndroidUtilities.dp(17)); - Theme.dialogs_messagePaint[0].setTextSize(AndroidUtilities.dp(16)); - Theme.dialogs_messagePrintingPaint[0].setTextSize(AndroidUtilities.dp(16)); + Theme.dialogs_namePaint[0].setTextSize(dp(17)); + Theme.dialogs_nameEncryptedPaint[0].setTextSize(dp(17)); + Theme.dialogs_messagePaint[0].setTextSize(dp(16)); + Theme.dialogs_messagePrintingPaint[0].setTextSize(dp(16)); - Theme.dialogs_namePaint[1].setTextSize(AndroidUtilities.dp(16)); - Theme.dialogs_nameEncryptedPaint[1].setTextSize(AndroidUtilities.dp(16)); - Theme.dialogs_messagePaint[1].setTextSize(AndroidUtilities.dp(15)); - Theme.dialogs_messagePrintingPaint[1].setTextSize(AndroidUtilities.dp(15)); + Theme.dialogs_namePaint[1].setTextSize(dp(16)); + Theme.dialogs_nameEncryptedPaint[1].setTextSize(dp(16)); + Theme.dialogs_messagePaint[1].setTextSize(dp(15)); + Theme.dialogs_messagePrintingPaint[1].setTextSize(dp(15)); Theme.dialogs_messagePaint[1].setColor(Theme.dialogs_messagePaint[1].linkColor = Theme.getColor(Theme.key_chats_message_threeLines, resourcesProvider)); paintIndex = 1; thumbSize = 18; } else { - Theme.dialogs_namePaint[0].setTextSize(AndroidUtilities.dp(17)); - Theme.dialogs_nameEncryptedPaint[0].setTextSize(AndroidUtilities.dp(17)); - Theme.dialogs_messagePaint[0].setTextSize(AndroidUtilities.dp(16)); - Theme.dialogs_messagePrintingPaint[0].setTextSize(AndroidUtilities.dp(16)); + Theme.dialogs_namePaint[0].setTextSize(dp(17)); + Theme.dialogs_nameEncryptedPaint[0].setTextSize(dp(17)); + Theme.dialogs_messagePaint[0].setTextSize(dp(16)); + Theme.dialogs_messagePrintingPaint[0].setTextSize(dp(16)); Theme.dialogs_messagePaint[0].setColor(Theme.dialogs_messagePaint[0].linkColor = Theme.getColor(Theme.key_chats_message, resourcesProvider)); paintIndex = 0; @@ -1012,7 +1046,7 @@ public void buildLayout() { int messageFormatType; if (Build.VERSION.SDK_INT >= 18) { - if ((!useForceThreeLines && !SharedConfig.useThreeLinesLayout || currentDialogFolderId != 0) || isForumCell()) { + if ((!useForceThreeLines && !SharedConfig.useThreeLinesLayout || currentDialogFolderId != 0) || isForumCell() || hasTags()) { //1 - "%2$s: \u2068%1$s\u2069"; messageFormatType = 1; hasNameInMessage = true; @@ -1022,7 +1056,7 @@ public void buildLayout() { hasNameInMessage = false; } } else { - if ((!useForceThreeLines && !SharedConfig.useThreeLinesLayout || currentDialogFolderId != 0) || isForumCell()) { + if ((!useForceThreeLines && !SharedConfig.useThreeLinesLayout || currentDialogFolderId != 0) || isForumCell() || hasTags()) { //3 - "%2$s: %1$s"; messageFormatType = 3; hasNameInMessage = true; @@ -1051,37 +1085,37 @@ public void buildLayout() { if (customDialog.type == 2) { drawNameLock = true; if (useForceThreeLines || SharedConfig.useThreeLinesLayout) { - nameLockTop = AndroidUtilities.dp(12.5f); + nameLockTop = dp(12.5f); if (!LocaleController.isRTL) { - nameLockLeft = AndroidUtilities.dp(messagePaddingStart + 6); - nameLeft = AndroidUtilities.dp(messagePaddingStart + 10) + Theme.dialogs_lockDrawable.getIntrinsicWidth(); + nameLockLeft = dp(messagePaddingStart + 6); + nameLeft = dp(messagePaddingStart + 10) + Theme.dialogs_lockDrawable.getIntrinsicWidth(); } else { - nameLockLeft = getMeasuredWidth() - AndroidUtilities.dp(messagePaddingStart + 6) - Theme.dialogs_lockDrawable.getIntrinsicWidth(); - nameLeft = AndroidUtilities.dp(22); + nameLockLeft = getMeasuredWidth() - dp(messagePaddingStart + 6) - Theme.dialogs_lockDrawable.getIntrinsicWidth(); + nameLeft = dp(22); } } else { - nameLockTop = AndroidUtilities.dp(16.5f); + nameLockTop = dp(16.5f); if (!LocaleController.isRTL) { - nameLockLeft = AndroidUtilities.dp(messagePaddingStart + 4); - nameLeft = AndroidUtilities.dp(messagePaddingStart + 8) + Theme.dialogs_lockDrawable.getIntrinsicWidth(); + nameLockLeft = dp(messagePaddingStart + 4); + nameLeft = dp(messagePaddingStart + 8) + Theme.dialogs_lockDrawable.getIntrinsicWidth(); } else { - nameLockLeft = getMeasuredWidth() - AndroidUtilities.dp(messagePaddingStart + 4) - Theme.dialogs_lockDrawable.getIntrinsicWidth(); - nameLeft = AndroidUtilities.dp(18); + nameLockLeft = getMeasuredWidth() - dp(messagePaddingStart + 4) - Theme.dialogs_lockDrawable.getIntrinsicWidth(); + nameLeft = dp(18); } } } else { drawVerified = !forbidVerified && customDialog.verified; if (useForceThreeLines || SharedConfig.useThreeLinesLayout) { if (!LocaleController.isRTL) { - nameLeft = AndroidUtilities.dp(messagePaddingStart + 6); + nameLeft = dp(messagePaddingStart + 6); } else { - nameLeft = AndroidUtilities.dp(22); + nameLeft = dp(22); } } else { if (!LocaleController.isRTL) { - nameLeft = AndroidUtilities.dp(messagePaddingStart + 4); + nameLeft = dp(messagePaddingStart + 4); } else { - nameLeft = AndroidUtilities.dp(18); + nameLeft = dp(18); } } } @@ -1105,7 +1139,7 @@ public void buildLayout() { stringBuilder = formatInternal(messageFormatType, mess.replace('\n', ' '), messageNameString); } } - messageString = Emoji.replaceEmoji(stringBuilder, Theme.dialogs_messagePaint[paintIndex].getFontMetricsInt(), AndroidUtilities.dp(20), false); + messageString = Emoji.replaceEmoji(stringBuilder, Theme.dialogs_messagePaint[paintIndex].getFontMetricsInt(), dp(20), false); } else { messageString = customDialog.message; if (customDialog.isMedia) { @@ -1145,15 +1179,15 @@ public void buildLayout() { } else { if (useForceThreeLines || SharedConfig.useThreeLinesLayout) { if (!LocaleController.isRTL) { - nameLeft = AndroidUtilities.dp(messagePaddingStart + 6); + nameLeft = dp(messagePaddingStart + 6); } else { - nameLeft = AndroidUtilities.dp(22); + nameLeft = dp(22); } } else { if (!LocaleController.isRTL) { - nameLeft = AndroidUtilities.dp(messagePaddingStart + 4); + nameLeft = dp(messagePaddingStart + 4); } else { - nameLeft = AndroidUtilities.dp(18); + nameLeft = dp(18); } } @@ -1161,22 +1195,22 @@ public void buildLayout() { if (currentDialogFolderId == 0) { drawNameLock = true; if (useForceThreeLines || SharedConfig.useThreeLinesLayout) { - nameLockTop = AndroidUtilities.dp(12.5f); + nameLockTop = dp(12.5f); if (!LocaleController.isRTL) { - nameLockLeft = AndroidUtilities.dp(messagePaddingStart + 6); - nameLeft = AndroidUtilities.dp(messagePaddingStart + 10) + Theme.dialogs_lockDrawable.getIntrinsicWidth(); + nameLockLeft = dp(messagePaddingStart + 6); + nameLeft = dp(messagePaddingStart + 10) + Theme.dialogs_lockDrawable.getIntrinsicWidth(); } else { - nameLockLeft = getMeasuredWidth() - AndroidUtilities.dp(messagePaddingStart + 6) - Theme.dialogs_lockDrawable.getIntrinsicWidth(); - nameLeft = AndroidUtilities.dp(22); + nameLockLeft = getMeasuredWidth() - dp(messagePaddingStart + 6) - Theme.dialogs_lockDrawable.getIntrinsicWidth(); + nameLeft = dp(22); } } else { - nameLockTop = AndroidUtilities.dp(16.5f); + nameLockTop = dp(16.5f); if (!LocaleController.isRTL) { - nameLockLeft = AndroidUtilities.dp(messagePaddingStart + 4); - nameLeft = AndroidUtilities.dp(messagePaddingStart + 8) + Theme.dialogs_lockDrawable.getIntrinsicWidth(); + nameLockLeft = dp(messagePaddingStart + 4); + nameLeft = dp(messagePaddingStart + 8) + Theme.dialogs_lockDrawable.getIntrinsicWidth(); } else { - nameLockLeft = getMeasuredWidth() - AndroidUtilities.dp(messagePaddingStart + 4) - Theme.dialogs_lockDrawable.getIntrinsicWidth(); - nameLeft = AndroidUtilities.dp(18); + nameLockLeft = getMeasuredWidth() - dp(messagePaddingStart + 4) - Theme.dialogs_lockDrawable.getIntrinsicWidth(); + nameLeft = dp(18); } } } @@ -1271,7 +1305,7 @@ public void buildLayout() { StatusDrawable statusDrawable = Theme.getChatStatusDrawable(printingStringType); int startPadding = 0; if (statusDrawable != null) { - startPadding = statusDrawable.getIntrinsicWidth() + AndroidUtilities.dp(3); + startPadding = statusDrawable.getIntrinsicWidth() + dp(3); } SpannableStringBuilder spannableStringBuilder = new SpannableStringBuilder(); @@ -1295,7 +1329,7 @@ public void buildLayout() { checkMessage = false; messageNameString = LocaleController.getString("Draft", R.string.Draft); if (draftMessage != null && TextUtils.isEmpty(draftMessage.message)) { - if (useForceThreeLines || SharedConfig.useThreeLinesLayout) { + if ((useForceThreeLines || SharedConfig.useThreeLinesLayout) && !hasTags()) { messageString = ""; } else { SpannableStringBuilder stringBuilder = SpannableStringBuilder.valueOf(messageNameString); @@ -1325,10 +1359,10 @@ public void buildLayout() { } SpannableStringBuilder stringBuilder = formatInternal(messageFormatType, AndroidUtilities.replaceNewLines(messSpan), messageNameString); - if (!useForceThreeLines && !SharedConfig.useThreeLinesLayout) { + if (!useForceThreeLines && !SharedConfig.useThreeLinesLayout || hasTags()) { stringBuilder.setSpan(new ForegroundColorSpanThemable(Theme.key_chats_draft, resourcesProvider), 0, messageNameString.length() + 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); } - messageString = Emoji.replaceEmoji(stringBuilder, Theme.dialogs_messagePaint[paintIndex].getFontMetricsInt(), AndroidUtilities.dp(20), false); + messageString = Emoji.replaceEmoji(stringBuilder, Theme.dialogs_messagePaint[paintIndex].getFontMetricsInt(), dp(20), false); } } else { if (clearingDialog) { @@ -1478,7 +1512,7 @@ public void buildLayout() { FileLog.e(e); } } - messageString = Emoji.replaceEmoji(stringBuilder, Theme.dialogs_messagePaint[paintIndex].getFontMetricsInt(), AndroidUtilities.dp(20), false); + messageString = Emoji.replaceEmoji(stringBuilder, Theme.dialogs_messagePaint[paintIndex].getFontMetricsInt(), dp(20), false); if (message.hasHighlightedWords()) { CharSequence messageH = AndroidUtilities.highlightText(messageString, message.highlightedWords, resourcesProvider); if (messageH != null) { @@ -1493,10 +1527,10 @@ public void buildLayout() { SpannableStringBuilder builder = (SpannableStringBuilder) messageString; if (thumbInsertIndex >= builder.length()) { builder.append(" "); - builder.setSpan(new FixedWidthSpan(AndroidUtilities.dp(thumbsCount * (thumbSize + 2) - 2 + 5)), builder.length() - 1, builder.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + builder.setSpan(new FixedWidthSpan(dp(thumbsCount * (thumbSize + 2) - 2 + 5)), builder.length() - 1, builder.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); } else { builder.insert(thumbInsertIndex, " "); - builder.setSpan(new FixedWidthSpan(AndroidUtilities.dp(thumbsCount * (thumbSize + 2) - 2 + 5)), thumbInsertIndex, thumbInsertIndex + 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + builder.setSpan(new FixedWidthSpan(dp(thumbsCount * (thumbSize + 2) - 2 + 5)), thumbInsertIndex, thumbInsertIndex + 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); } } } else { @@ -1542,7 +1576,7 @@ public void buildLayout() { } if (message.hasHighlightedWords() && !TextUtils.isEmpty(message.messageOwner.message)) { CharSequence text = message.messageTrimmedToHighlight; - int w = getMeasuredWidth() - AndroidUtilities.dp(messagePaddingStart + 23 + 24); + int w = getMeasuredWidth() - dp(messagePaddingStart + 23 + 24); if (hasNameInMessage) { if (!TextUtils.isEmpty(messageNameString)) { w -= currentMessagePaint.measureText(messageNameString.toString()); @@ -1613,7 +1647,7 @@ public void buildLayout() { if (message.messageTrimmedToHighlight != null) { messageString = message.messageTrimmedToHighlight; } - int w = getMeasuredWidth() - AndroidUtilities.dp(messagePaddingStart + 23 ); + int w = getMeasuredWidth() - dp(messagePaddingStart + 23 ); messageString = AndroidUtilities.ellipsizeCenterEnd(messageString, message.highlightedWords.get(0), w, currentMessagePaint, 130); } else { SpannableStringBuilder stringBuilder = new SpannableStringBuilder(msgText); @@ -1644,7 +1678,7 @@ public void buildLayout() { if (message.messageTrimmedToHighlight != null) { messageString = message.messageTrimmedToHighlight; } - int w = getMeasuredWidth() - AndroidUtilities.dp(messagePaddingStart + 23 + (thumbSize + 2) * thumbsCount - 2 + 5); + int w = getMeasuredWidth() - dp(messagePaddingStart + 23 + (thumbSize + 2) * thumbsCount - 2 + 5); messageString = AndroidUtilities.ellipsizeCenterEnd(messageString, message.highlightedWords.get(0), w, currentMessagePaint, 130).toString(); } else { if (messageString.length() > 150) { @@ -1658,8 +1692,8 @@ public void buildLayout() { checkMessage = false; SpannableStringBuilder builder = (SpannableStringBuilder) messageString; builder.insert(0, " "); - builder.setSpan(new FixedWidthSpan(AndroidUtilities.dp((thumbSize + 2) * thumbsCount - 2 + 5)), 0, 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); - Emoji.replaceEmoji(builder, Theme.dialogs_messagePaint[paintIndex].getFontMetricsInt(), AndroidUtilities.dp(17), false); + builder.setSpan(new FixedWidthSpan(dp((thumbSize + 2) * thumbsCount - 2 + 5)), 0, 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + Emoji.replaceEmoji(builder, Theme.dialogs_messagePaint[paintIndex].getFontMetricsInt(), dp(17), false); if (message.hasHighlightedWords()) { CharSequence s = AndroidUtilities.highlightText(builder, message.highlightedWords, resourcesProvider); if (s != null) { @@ -1849,9 +1883,9 @@ public void buildLayout() { timeWidth = (int) Math.ceil(Theme.dialogs_timePaint.measureText(timeString)); timeLayout = new StaticLayout(timeString, Theme.dialogs_timePaint, timeWidth, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); if (!LocaleController.isRTL) { - timeLeft = getMeasuredWidth() - AndroidUtilities.dp(15) - timeWidth; + timeLeft = getMeasuredWidth() - dp(15) - timeWidth; } else { - timeLeft = AndroidUtilities.dp(15); + timeLeft = dp(15); } } else { timeWidth = 0; @@ -1862,88 +1896,88 @@ public void buildLayout() { int timeLeftOffset = 0; if (drawLock2()) { if (LocaleController.isRTL) { - lock2Left = timeLeft + timeWidth + AndroidUtilities.dp(4); + lock2Left = timeLeft + timeWidth + dp(4); } else { - lock2Left = timeLeft - Theme.dialogs_lock2Drawable.getIntrinsicWidth() - AndroidUtilities.dp(4); + lock2Left = timeLeft - Theme.dialogs_lock2Drawable.getIntrinsicWidth() - dp(4); } - timeLeftOffset += Theme.dialogs_lock2Drawable.getIntrinsicWidth() + AndroidUtilities.dp(4); + timeLeftOffset += Theme.dialogs_lock2Drawable.getIntrinsicWidth() + dp(4); timeWidth += timeLeftOffset; } if (!LocaleController.isRTL) { - nameWidth = getMeasuredWidth() - nameLeft - AndroidUtilities.dp(14 + 8) - timeWidth; + nameWidth = getMeasuredWidth() - nameLeft - dp(14 + 8) - timeWidth; } else { - nameWidth = getMeasuredWidth() - nameLeft - AndroidUtilities.dp(messagePaddingStart + 5 + 8) - timeWidth; + nameWidth = getMeasuredWidth() - nameLeft - dp(messagePaddingStart + 5 + 8) - timeWidth; nameLeft += timeWidth; } if (drawNameLock) { - nameWidth -= AndroidUtilities.dp(LocaleController.isRTL ? 8 : 4) + Theme.dialogs_lockDrawable.getIntrinsicWidth(); + nameWidth -= dp(LocaleController.isRTL ? 8 : 4) + Theme.dialogs_lockDrawable.getIntrinsicWidth(); } if (drawClock) { - int w = Theme.dialogs_clockDrawable.getIntrinsicWidth() + AndroidUtilities.dp(5); + int w = Theme.dialogs_clockDrawable.getIntrinsicWidth() + dp(5); nameWidth -= w; if (!LocaleController.isRTL) { clockDrawLeft = timeLeft - timeLeftOffset - w; } else { - clockDrawLeft = timeLeft + timeWidth + AndroidUtilities.dp(5); + clockDrawLeft = timeLeft + timeWidth + dp(5); nameLeft += w; } } else if (drawCheck2) { - int w = Theme.dialogs_checkDrawable.getIntrinsicWidth() + AndroidUtilities.dp(5); + int w = Theme.dialogs_checkDrawable.getIntrinsicWidth() + dp(5); nameWidth -= w; if (drawCheck1) { - nameWidth -= Theme.dialogs_halfCheckDrawable.getIntrinsicWidth() - AndroidUtilities.dp(8); + nameWidth -= Theme.dialogs_halfCheckDrawable.getIntrinsicWidth() - dp(8); if (!LocaleController.isRTL) { halfCheckDrawLeft = timeLeft - timeLeftOffset - w; - checkDrawLeft = halfCheckDrawLeft - AndroidUtilities.dp(5.5f); + checkDrawLeft = halfCheckDrawLeft - dp(5.5f); } else { - checkDrawLeft = timeLeft + timeWidth + AndroidUtilities.dp(5); - halfCheckDrawLeft = checkDrawLeft + AndroidUtilities.dp(5.5f); - nameLeft += w + Theme.dialogs_halfCheckDrawable.getIntrinsicWidth() - AndroidUtilities.dp(8); + checkDrawLeft = timeLeft + timeWidth + dp(5); + halfCheckDrawLeft = checkDrawLeft + dp(5.5f); + nameLeft += w + Theme.dialogs_halfCheckDrawable.getIntrinsicWidth() - dp(8); } } else { if (!LocaleController.isRTL) { checkDrawLeft1 = timeLeft - timeLeftOffset - w; } else { - checkDrawLeft1 = timeLeft + timeWidth + AndroidUtilities.dp(5); + checkDrawLeft1 = timeLeft + timeWidth + dp(5); nameLeft += w; } } } if (drawPremium && emojiStatus.getDrawable() != null) { - int w = AndroidUtilities.dp(6 + 24 + 6); + int w = dp(6 + 24 + 6); nameWidth -= w; if (LocaleController.isRTL) { nameLeft += w; } } else if ((dialogMuted || drawUnmute) && !drawVerified && drawScam == 0) { - int w = AndroidUtilities.dp(6) + Theme.dialogs_muteDrawable.getIntrinsicWidth(); + int w = dp(6) + Theme.dialogs_muteDrawable.getIntrinsicWidth(); nameWidth -= w; if (LocaleController.isRTL) { nameLeft += w; } } else if (drawVerified) { - int w = AndroidUtilities.dp(6) + Theme.dialogs_verifiedDrawable.getIntrinsicWidth(); + int w = dp(6) + Theme.dialogs_verifiedDrawable.getIntrinsicWidth(); nameWidth -= w; if (LocaleController.isRTL) { nameLeft += w; } } else if (drawPremium) { - int w = AndroidUtilities.dp(6 + 24 + 6); + int w = dp(6 + 24 + 6); nameWidth -= w; if (LocaleController.isRTL) { nameLeft += w; } } else if (drawScam != 0) { - int w = AndroidUtilities.dp(6) + (drawScam == 1 ? Theme.dialogs_scamDrawable : Theme.dialogs_fakeDrawable).getIntrinsicWidth(); + int w = dp(6) + (drawScam == 1 ? Theme.dialogs_scamDrawable : Theme.dialogs_fakeDrawable).getIntrinsicWidth(); nameWidth -= w; if (LocaleController.isRTL) { nameLeft += w; } } try { - int ellipsizeWidth = nameWidth - AndroidUtilities.dp(12); + int ellipsizeWidth = nameWidth - dp(12); if (ellipsizeWidth < 0) { ellipsizeWidth = 0; } @@ -1953,13 +1987,13 @@ public void buildLayout() { CharSequence nameStringFinal = nameString; if (nameLayoutEllipsizeByGradient) { nameLayoutFits = nameStringFinal.length() == TextUtils.ellipsize(nameStringFinal, Theme.dialogs_namePaint[paintIndex], ellipsizeWidth, TextUtils.TruncateAt.END).length(); - ellipsizeWidth += AndroidUtilities.dp(48); + ellipsizeWidth += dp(48); } nameIsEllipsized = Theme.dialogs_namePaint[paintIndex].measureText(nameStringFinal.toString()) > ellipsizeWidth; if (!twoLinesForName) { nameStringFinal = TextUtils.ellipsize(nameStringFinal, Theme.dialogs_namePaint[paintIndex], ellipsizeWidth, TextUtils.TruncateAt.END); } - nameStringFinal = Emoji.replaceEmoji(nameStringFinal, Theme.dialogs_namePaint[paintIndex].getFontMetricsInt(), AndroidUtilities.dp(20), false); + nameStringFinal = Emoji.replaceEmoji(nameStringFinal, Theme.dialogs_namePaint[paintIndex].getFontMetricsInt(), dp(20), false); if (message != null && message.hasHighlightedWords()) { CharSequence s = AndroidUtilities.highlightText(nameStringFinal, message.highlightedWords, resourcesProvider); if (s != null) { @@ -1971,7 +2005,7 @@ public void buildLayout() { } else { nameLayout = new StaticLayout(nameStringFinal, Theme.dialogs_namePaint[paintIndex], Math.max(ellipsizeWidth, nameWidth), Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); } - nameLayoutTranslateX = nameLayoutEllipsizeByGradient && nameLayout.isRtlCharAt(0) ? -AndroidUtilities.dp(36) : 0; + nameLayoutTranslateX = nameLayoutEllipsizeByGradient && nameLayout.isRtlCharAt(0) ? -dp(36) : 0; nameLayoutEllipsizeLeft = nameLayout.isRtlCharAt(0); } catch (Exception e) { FileLog.e(e); @@ -1985,69 +2019,80 @@ public void buildLayout() { int avatarTop; int thumbLeft; if (useForceThreeLines || SharedConfig.useThreeLinesLayout) { - avatarTop = AndroidUtilities.dp(11); - messageNameTop = AndroidUtilities.dp(32); - timeTop = AndroidUtilities.dp(13); - errorTop = AndroidUtilities.dp(43); - pinTop = AndroidUtilities.dp(43); - countTop = AndroidUtilities.dp(43); - checkDrawTop = AndroidUtilities.dp(13); - messageWidth = getMeasuredWidth() - AndroidUtilities.dp(messagePaddingStart + 21); + avatarTop = dp(11); + messageNameTop = dp(32); + timeTop = dp(13); + errorTop = dp(43); + pinTop = dp(43); + countTop = dp(43); + checkDrawTop = dp(13); + messageWidth = getMeasuredWidth() - dp(messagePaddingStart + 21); if (LocaleController.isRTL) { - buttonLeft = typingLeft = messageLeft = messageNameLeft = AndroidUtilities.dp(16); - avatarLeft = getMeasuredWidth() - AndroidUtilities.dp(66); - thumbLeft = avatarLeft - AndroidUtilities.dp(13 + 18); + buttonLeft = typingLeft = messageLeft = messageNameLeft = dp(16); + avatarLeft = getMeasuredWidth() - dp(66); + thumbLeft = avatarLeft - dp(13 + 18); } else { - buttonLeft = typingLeft = messageLeft = messageNameLeft = AndroidUtilities.dp(messagePaddingStart + 6); - avatarLeft = AndroidUtilities.dp(10); - thumbLeft = avatarLeft + AndroidUtilities.dp(56 + 13); + buttonLeft = typingLeft = messageLeft = messageNameLeft = dp(messagePaddingStart + 6); + avatarLeft = dp(10); + thumbLeft = avatarLeft + dp(56 + 13); } - storyParams.originalAvatarRect.set(avatarLeft, avatarTop, avatarLeft + AndroidUtilities.dp(56), avatarTop + AndroidUtilities.dp(56)); + storyParams.originalAvatarRect.set(avatarLeft, avatarTop, avatarLeft + dp(56), avatarTop + dp(56)); for (int i = 0; i < thumbImage.length; ++i) { - thumbImage[i].setImageCoords(thumbLeft + (thumbSize + 2) * i, avatarTop + AndroidUtilities.dp(31) + (twoLinesForName ? AndroidUtilities.dp(20) : 0), AndroidUtilities.dp(18), AndroidUtilities.dp(18)); + thumbImage[i].setImageCoords(thumbLeft + (thumbSize + 2) * i, avatarTop + dp(31) + (twoLinesForName ? dp(20) : 0) - (!(useForceThreeLines || SharedConfig.useThreeLinesLayout) && tags != null && !tags.isEmpty() ? dp(9) : 0), dp(18), dp(18)); } } else { - avatarTop = AndroidUtilities.dp(9); - messageNameTop = AndroidUtilities.dp(31); - timeTop = AndroidUtilities.dp(16); - errorTop = AndroidUtilities.dp(39); - pinTop = AndroidUtilities.dp(39); - countTop = isTopic ? AndroidUtilities.dp(36) : AndroidUtilities.dp(39); - checkDrawTop = AndroidUtilities.dp(17); - messageWidth = getMeasuredWidth() - AndroidUtilities.dp(messagePaddingStart + 23 - (LocaleController.isRTL ? 0 : 12)); + avatarTop = dp(9); + messageNameTop = dp(31); + timeTop = dp(16); + errorTop = dp(39); + pinTop = dp(39); + countTop = isTopic ? dp(36) : dp(39); + checkDrawTop = dp(17); + messageWidth = getMeasuredWidth() - dp(messagePaddingStart + 23 - (LocaleController.isRTL ? 0 : 12)); if (LocaleController.isRTL) { - buttonLeft = typingLeft = messageLeft = messageNameLeft = AndroidUtilities.dp(22); - avatarLeft = getMeasuredWidth() - AndroidUtilities.dp(64); - thumbLeft = avatarLeft - AndroidUtilities.dp(11 + (thumbsCount * (thumbSize + 2) - 2)); + buttonLeft = typingLeft = messageLeft = messageNameLeft = dp(22); + avatarLeft = getMeasuredWidth() - dp(64); + thumbLeft = avatarLeft - dp(11 + (thumbsCount * (thumbSize + 2) - 2)); } else { - buttonLeft = typingLeft = messageLeft = messageNameLeft = AndroidUtilities.dp(messagePaddingStart + 4); - avatarLeft = AndroidUtilities.dp(10); - thumbLeft = avatarLeft + AndroidUtilities.dp(56 + 11); + buttonLeft = typingLeft = messageLeft = messageNameLeft = dp(messagePaddingStart + 4); + avatarLeft = dp(10); + thumbLeft = avatarLeft + dp(56 + 11); } - storyParams.originalAvatarRect.set(avatarLeft, avatarTop, avatarLeft + AndroidUtilities.dp(54), avatarTop + AndroidUtilities.dp(54)); + storyParams.originalAvatarRect.set(avatarLeft, avatarTop, avatarLeft + dp(54), avatarTop + dp(54)); for (int i = 0; i < thumbImage.length; ++i) { - thumbImage[i].setImageCoords(thumbLeft + (thumbSize + 2) * i, avatarTop + AndroidUtilities.dp(30) + (twoLinesForName ? AndroidUtilities.dp(20) : 0), AndroidUtilities.dp(thumbSize), AndroidUtilities.dp(thumbSize)); + thumbImage[i].setImageCoords(thumbLeft + (thumbSize + 2) * i, avatarTop + dp(30) + (twoLinesForName ? dp(20) : 0) - (!(useForceThreeLines || SharedConfig.useThreeLinesLayout) && tags != null && !tags.isEmpty() ? dp(9) : 0), dp(thumbSize), dp(thumbSize)); } } + if (LocaleController.isRTL) { + tagsRight = getMeasuredWidth() - dp(messagePaddingStart); + tagsLeft = dp(64); + } else { + tagsLeft = messageLeft; + tagsRight = getMeasuredWidth() - dp(64); + } if (twoLinesForName) { - messageNameTop += AndroidUtilities.dp(20); + messageNameTop += dp(20); + } + if ((!(useForceThreeLines || SharedConfig.useThreeLinesLayout) || isForumCell()) && tags != null && !tags.isEmpty()) { + timeTop -= dp(6); + checkDrawTop -= dp(6); } if (getIsPinned()) { if (!LocaleController.isRTL) { - pinLeft = getMeasuredWidth() - Theme.dialogs_pinnedDrawable.getIntrinsicWidth() - AndroidUtilities.dp(14); + pinLeft = getMeasuredWidth() - Theme.dialogs_pinnedDrawable.getIntrinsicWidth() - dp(14); } else { - pinLeft = AndroidUtilities.dp(14); + pinLeft = dp(14); } } if (drawError) { - int w = AndroidUtilities.dp(23 + 8); + int w = dp(23 + 8); messageWidth -= w; if (!LocaleController.isRTL) { - errorLeft = getMeasuredWidth() - AndroidUtilities.dp(23 + 11); + errorLeft = getMeasuredWidth() - dp(23 + 11); } else { - errorLeft = AndroidUtilities.dp(11); + errorLeft = dp(11); messageLeft += w; typingLeft += w; buttonLeft += w; @@ -2055,14 +2100,14 @@ public void buildLayout() { } } else if (countString != null || mentionString != null || drawReactionMention) { if (countString != null) { - countWidth = Math.max(AndroidUtilities.dp(12), (int) Math.ceil(Theme.dialogs_countTextPaint.measureText(countString))); + countWidth = Math.max(dp(12), (int) Math.ceil(Theme.dialogs_countTextPaint.measureText(countString))); countLayout = new StaticLayout(countString, Theme.dialogs_countTextPaint, countWidth, Layout.Alignment.ALIGN_CENTER, 1.0f, 0.0f, false); - int w = countWidth + AndroidUtilities.dp(18); + int w = countWidth + dp(18); messageWidth -= w; if (!LocaleController.isRTL) { - countLeft = getMeasuredWidth() - countWidth - AndroidUtilities.dp(20); + countLeft = getMeasuredWidth() - countWidth - dp(20); } else { - countLeft = AndroidUtilities.dp(20); + countLeft = dp(20); messageLeft += w; typingLeft += w; buttonLeft += w; @@ -2074,17 +2119,17 @@ public void buildLayout() { } if (mentionString != null) { if (currentDialogFolderId != 0) { - mentionWidth = Math.max(AndroidUtilities.dp(12), (int) Math.ceil(Theme.dialogs_countTextPaint.measureText(mentionString))); + mentionWidth = Math.max(dp(12), (int) Math.ceil(Theme.dialogs_countTextPaint.measureText(mentionString))); mentionLayout = new StaticLayout(mentionString, Theme.dialogs_countTextPaint, mentionWidth, Layout.Alignment.ALIGN_CENTER, 1.0f, 0.0f, false); } else { - mentionWidth = AndroidUtilities.dp(12); + mentionWidth = dp(12); } - int w = mentionWidth + AndroidUtilities.dp(18); + int w = mentionWidth + dp(18); messageWidth -= w; if (!LocaleController.isRTL) { - mentionLeft = getMeasuredWidth() - mentionWidth - AndroidUtilities.dp(20) - (countWidth != 0 ? countWidth + AndroidUtilities.dp(18) : 0); + mentionLeft = getMeasuredWidth() - mentionWidth - dp(20) - (countWidth != 0 ? countWidth + dp(18) : 0); } else { - mentionLeft = AndroidUtilities.dp(20) + (countWidth != 0 ? countWidth + AndroidUtilities.dp(18) : 0); + mentionLeft = dp(20) + (countWidth != 0 ? countWidth + dp(18) : 0); messageLeft += w; typingLeft += w; buttonLeft += w; @@ -2095,23 +2140,23 @@ public void buildLayout() { mentionWidth = 0; } if (drawReactionMention) { - int w = AndroidUtilities.dp(24); + int w = dp(24); messageWidth -= w; if (!LocaleController.isRTL) { - reactionMentionLeft = getMeasuredWidth() - AndroidUtilities.dp(32); + reactionMentionLeft = getMeasuredWidth() - dp(32); if (drawMention) { - reactionMentionLeft -= (mentionWidth != 0 ? (mentionWidth + AndroidUtilities.dp(18)) : 0); + reactionMentionLeft -= (mentionWidth != 0 ? (mentionWidth + dp(18)) : 0); } if (drawCount) { - reactionMentionLeft -= (countWidth != 0 ? countWidth + AndroidUtilities.dp(18) : 0); + reactionMentionLeft -= (countWidth != 0 ? countWidth + dp(18) : 0); } } else { - reactionMentionLeft = AndroidUtilities.dp(20); + reactionMentionLeft = dp(20); if (drawMention) { - reactionMentionLeft += (mentionWidth != 0 ? (mentionWidth + AndroidUtilities.dp(18)) : 0); + reactionMentionLeft += (mentionWidth != 0 ? (mentionWidth + dp(18)) : 0); } if (drawCount) { - reactionMentionLeft += (countWidth != 0 ? (countWidth + AndroidUtilities.dp(18)) : 0); + reactionMentionLeft += (countWidth != 0 ? (countWidth + dp(18)) : 0); } messageLeft += w; typingLeft += w; @@ -2121,7 +2166,7 @@ public void buildLayout() { } } else { if (getIsPinned()) { - int w = Theme.dialogs_pinnedDrawable.getIntrinsicWidth() + AndroidUtilities.dp(8); + int w = Theme.dialogs_pinnedDrawable.getIntrinsicWidth() + dp(8); messageWidth -= w; if (LocaleController.isRTL) { messageLeft += w; @@ -2142,12 +2187,12 @@ public void buildLayout() { if (mess.length() > 150) { mess = mess.subSequence(0, 150); } - if (!useForceThreeLines && !SharedConfig.useThreeLinesLayout || messageNameString != null) { + if (!useForceThreeLines && !SharedConfig.useThreeLinesLayout || hasTags() || messageNameString != null) { mess = AndroidUtilities.replaceNewLines(mess); } else { mess = AndroidUtilities.replaceTwoNewLinesToOne(mess); } - messageString = Emoji.replaceEmoji(mess, Theme.dialogs_messagePaint[paintIndex].getFontMetricsInt(), AndroidUtilities.dp(17), false); + messageString = Emoji.replaceEmoji(mess, Theme.dialogs_messagePaint[paintIndex].getFontMetricsInt(), dp(17), false); if (message != null) { CharSequence s = AndroidUtilities.highlightText(messageString, message.highlightedWords, resourcesProvider); if (s != null) { @@ -2155,18 +2200,17 @@ public void buildLayout() { } } } - messageWidth = Math.max(AndroidUtilities.dp(12), messageWidth); - buttonTop = useForceThreeLines || SharedConfig.useThreeLinesLayout ? AndroidUtilities.dp(58) : AndroidUtilities.dp(62); + messageWidth = Math.max(dp(12), messageWidth); + buttonTop = dp(useForceThreeLines || SharedConfig.useThreeLinesLayout ? 58 : 62); + if ((!(useForceThreeLines || SharedConfig.useThreeLinesLayout) || isForumCell()) && hasTags()) { + buttonTop -= dp(isForumCell() ? 10 : 12); + } if (isForumCell()) { - if (useForceThreeLines || SharedConfig.useThreeLinesLayout) { - messageTop = AndroidUtilities.dp(34); - } else { - messageTop = AndroidUtilities.dp(39); - } + messageTop = dp(useForceThreeLines || SharedConfig.useThreeLinesLayout ? 34 : 39); for (int i = 0; i < thumbImage.length; ++i) { thumbImage[i].setImageY(buttonTop); } - } else if ((useForceThreeLines || SharedConfig.useThreeLinesLayout) && messageNameString != null && (currentDialogFolderId == 0 || currentDialogFolderDialogsCount == 1)) { + } else if ((useForceThreeLines || SharedConfig.useThreeLinesLayout) && !hasTags() && messageNameString != null && (currentDialogFolderId == 0 || currentDialogFolderDialogsCount == 1)) { try { if (message != null && message.hasHighlightedWords()) { CharSequence s = AndroidUtilities.highlightText(messageNameString, message.highlightedWords, resourcesProvider); @@ -2178,26 +2222,26 @@ public void buildLayout() { } catch (Exception e) { FileLog.e(e); } - messageTop = AndroidUtilities.dp(32 + 19); - int yoff = nameIsEllipsized && isTopic ? AndroidUtilities.dp(20) : 0; + messageTop = dp(32 + 19); + int yoff = nameIsEllipsized && isTopic ? dp(20) : 0; for (int i = 0; i < thumbImage.length; ++i) { - thumbImage[i].setImageY(avatarTop + yoff + AndroidUtilities.dp(40)); + thumbImage[i].setImageY(avatarTop + yoff + dp(40)); } } else { messageNameLayout = null; if (useForceThreeLines || SharedConfig.useThreeLinesLayout) { - messageTop = AndroidUtilities.dp(32); - int yoff = nameIsEllipsized && isTopic ? AndroidUtilities.dp(20) : 0; + messageTop = dp(32); + int yoff = nameIsEllipsized && isTopic ? dp(20) : 0; for (int i = 0; i < thumbImage.length; ++i) { - thumbImage[i].setImageY(avatarTop + yoff + AndroidUtilities.dp(21)); + thumbImage[i].setImageY(avatarTop + yoff + dp(21)); } } else { - messageTop = AndroidUtilities.dp(39); + messageTop = dp(39); } } if (twoLinesForName) { - messageTop += AndroidUtilities.dp(20); + messageTop += dp(20); } animatedEmojiStack2 = AnimatedEmojiSpan.update(AnimatedEmojiDrawable.CACHE_TYPE_MESSAGES, this, animatedEmojiStack2, messageNameLayout); @@ -2205,9 +2249,9 @@ public void buildLayout() { try { buttonCreated = false; if (!TextUtils.isEmpty(buttonString)) { - buttonString = Emoji.replaceEmoji(buttonString, currentMessagePaint.getFontMetricsInt(), AndroidUtilities.dp(17), false); - CharSequence buttonStringFinal = TextUtils.ellipsize(buttonString, currentMessagePaint, messageWidth - AndroidUtilities.dp(26), TextUtils.TruncateAt.END); - buttonLayout = new StaticLayout(buttonStringFinal, currentMessagePaint, messageWidth - AndroidUtilities.dp(20), Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); + buttonString = Emoji.replaceEmoji(buttonString, currentMessagePaint.getFontMetricsInt(), dp(17), false); + CharSequence buttonStringFinal = TextUtils.ellipsize(buttonString, currentMessagePaint, messageWidth - dp(26), TextUtils.TruncateAt.END); + buttonLayout = new StaticLayout(buttonStringFinal, currentMessagePaint, messageWidth - dp(20), Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); spoilersPool2.addAll(spoilers2); spoilers2.clear(); SpoilerEffect.addSpoilers(this, buttonLayout, spoilersPool2, spoilers2); @@ -2221,10 +2265,10 @@ public void buildLayout() { try { if (!TextUtils.isEmpty(typingString)) { - if (useForceThreeLines || SharedConfig.useThreeLinesLayout) { - typingLayout = StaticLayoutEx.createStaticLayout(typingString, Theme.dialogs_messagePrintingPaint[paintIndex], messageWidth, Layout.Alignment.ALIGN_NORMAL, 1.0f, AndroidUtilities.dp(1), false, TextUtils.TruncateAt.END, messageWidth, typingString != null ? 1 : 2); + if ((useForceThreeLines || SharedConfig.useThreeLinesLayout) && !hasTags()) { + typingLayout = StaticLayoutEx.createStaticLayout(typingString, Theme.dialogs_messagePrintingPaint[paintIndex], messageWidth, Layout.Alignment.ALIGN_NORMAL, 1.0f, dp(1), false, TextUtils.TruncateAt.END, messageWidth, typingString != null ? 1 : 2); } else { - typingString = TextUtils.ellipsize(typingString, currentMessagePaint, messageWidth - AndroidUtilities.dp(12), TextUtils.TruncateAt.END); + typingString = TextUtils.ellipsize(typingString, currentMessagePaint, messageWidth - dp(12), TextUtils.TruncateAt.END); typingLayout = new StaticLayout(typingString, Theme.dialogs_messagePrintingPaint[paintIndex], messageWidth, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); } } @@ -2243,31 +2287,31 @@ public void buildLayout() { } } } - if ((useForceThreeLines || SharedConfig.useThreeLinesLayout) && currentDialogFolderId != 0 && currentDialogFolderDialogsCount > 1) { + if ((useForceThreeLines || SharedConfig.useThreeLinesLayout) && !hasTags() && currentDialogFolderId != 0 && currentDialogFolderDialogsCount > 1) { messageStringFinal = messageNameString; messageNameString = null; currentMessagePaint = Theme.dialogs_messagePaint[paintIndex]; - } else if (!useForceThreeLines && !SharedConfig.useThreeLinesLayout || messageNameString != null) { + } else if (!useForceThreeLines && !SharedConfig.useThreeLinesLayout || hasTags() || messageNameString != null) { if (!isForumCell() && messageString instanceof Spanned && ((Spanned) messageString).getSpans(0, messageString.length(), FixedWidthSpan.class).length <= 0) { - messageStringFinal = TextUtils.ellipsize(messageString, currentMessagePaint, messageWidth - AndroidUtilities.dp(12 + (thumbsCount * (thumbSize + 2) - 2) + 5), TextUtils.TruncateAt.END); + messageStringFinal = TextUtils.ellipsize(messageString, currentMessagePaint, messageWidth - dp(12 + (thumbsCount * (thumbSize + 2) - 2) + 5), TextUtils.TruncateAt.END); } else { - messageStringFinal = TextUtils.ellipsize(messageString, currentMessagePaint, messageWidth - AndroidUtilities.dp(12), TextUtils.TruncateAt.END); + messageStringFinal = TextUtils.ellipsize(messageString, currentMessagePaint, messageWidth - dp(12), TextUtils.TruncateAt.END); } } else { messageStringFinal = messageString; } Layout.Alignment align = isForum && LocaleController.isRTL ? Layout.Alignment.ALIGN_OPPOSITE : Layout.Alignment.ALIGN_NORMAL; - if (useForceThreeLines || SharedConfig.useThreeLinesLayout) { + if ((useForceThreeLines || SharedConfig.useThreeLinesLayout) && !hasTags()) { if (thumbsCount > 0 && messageNameString != null) { - messageWidth += AndroidUtilities.dp(5); + messageWidth += dp(5); } - messageLayout = StaticLayoutEx.createStaticLayout(messageStringFinal, currentMessagePaint, messageWidth, align, 1.0f, AndroidUtilities.dp(1), false, TextUtils.TruncateAt.END, messageWidth, messageNameString != null ? 1 : 2); + messageLayout = StaticLayoutEx.createStaticLayout(messageStringFinal, currentMessagePaint, messageWidth, align, 1.0f, dp(1), false, TextUtils.TruncateAt.END, messageWidth, messageNameString != null ? 1 : 2); } else { if (thumbsCount > 0) { - messageWidth += AndroidUtilities.dp((thumbsCount * (thumbSize + 2) - 2) + 5); + messageWidth += dp((thumbsCount * (thumbSize + 2) - 2) + 5); if (LocaleController.isRTL && !isForumCell()) { - messageLeft -= AndroidUtilities.dp((thumbsCount * (thumbSize + 2) - 2) + 5); + messageLeft -= dp((thumbsCount * (thumbSize + 2) - 2) + 5); } } messageLayout = new StaticLayout(messageStringFinal, currentMessagePaint, messageWidth, align, 1.0f, 0.0f, false); @@ -2287,20 +2331,20 @@ public void buildLayout() { if (nameLayout != null && nameLayout.getLineCount() > 0) { left = nameLayout.getLineLeft(0); widthpx = Math.ceil(nameLayout.getLineWidth(0)); - nameLeft += AndroidUtilities.dp(12); + nameLeft += dp(12); if (nameLayoutEllipsizeByGradient) { widthpx = Math.min(nameWidth, widthpx); } if ((dialogMuted || drawUnmute) && !drawVerified && drawScam == 0) { - nameMuteLeft = (int) (nameLeft + (nameWidth - widthpx) - AndroidUtilities.dp(6) - Theme.dialogs_muteDrawable.getIntrinsicWidth()); + nameMuteLeft = (int) (nameLeft + (nameWidth - widthpx) - dp(6) - Theme.dialogs_muteDrawable.getIntrinsicWidth()); } else if (drawVerified) { - nameMuteLeft = (int) (nameLeft + (nameWidth - widthpx) - AndroidUtilities.dp(6) - Theme.dialogs_verifiedDrawable.getIntrinsicWidth()); + nameMuteLeft = (int) (nameLeft + (nameWidth - widthpx) - dp(6) - Theme.dialogs_verifiedDrawable.getIntrinsicWidth()); } else if (drawPremium) { - nameMuteLeft = (int) (nameLeft + (nameWidth - widthpx - left) - AndroidUtilities.dp(24)); + nameMuteLeft = (int) (nameLeft + (nameWidth - widthpx - left) - dp(24)); } else if (drawScam != 0) { - nameMuteLeft = (int) (nameLeft + (nameWidth - widthpx) - AndroidUtilities.dp(6) - (drawScam == 1 ? Theme.dialogs_scamDrawable : Theme.dialogs_fakeDrawable).getIntrinsicWidth()); + nameMuteLeft = (int) (nameLeft + (nameWidth - widthpx) - dp(6) - (drawScam == 1 ? Theme.dialogs_scamDrawable : Theme.dialogs_fakeDrawable).getIntrinsicWidth()); } else { - nameMuteLeft = (int) (nameLeft + (nameWidth - widthpx) - AndroidUtilities.dp(6) - Theme.dialogs_muteDrawable.getIntrinsicWidth()); + nameMuteLeft = (int) (nameLeft + (nameWidth - widthpx) - dp(6) - Theme.dialogs_muteDrawable.getIntrinsicWidth()); } if (left == 0) { if (widthpx < nameWidth) { @@ -2375,15 +2419,15 @@ public void buildLayout() { widthpx = Math.ceil(nameLayout.getLineWidth(0)); if (nameLayoutEllipsizeByGradient) { widthpx = Math.min(nameWidth, widthpx); -// widthpx -= AndroidUtilities.dp(36); -// left += AndroidUtilities.dp(36); +// widthpx -= dp(36); +// left += dp(36); } if (widthpx < nameWidth) { nameLeft -= (nameWidth - widthpx); } } if ((dialogMuted || true) || drawUnmute || drawVerified || drawPremium || drawScam != 0) { - nameMuteLeft = (int) (nameLeft + left + AndroidUtilities.dp(6)); + nameMuteLeft = (int) (nameLeft + left + dp(6)); } } if (messageLayout != null) { @@ -2432,7 +2476,7 @@ public void buildLayout() { if (x1 < x2) { statusDrawableLeft = (int) (typingLeft + x1); } else { - statusDrawableLeft = (int) (typingLeft + x2 + AndroidUtilities.dp(3)); + statusDrawableLeft = (int) (typingLeft + x2 + dp(3)); } } updateThumbsPosition(); @@ -2482,10 +2526,10 @@ private void updateThumbsPosition() { float x2 = layout.getPrimaryHorizontal(spanOffset + 1); int offset = (int) Math.ceil(Math.min(x1, x2)); if (offset != 0 && !drawForwardIcon) { - offset += AndroidUtilities.dp(3); + offset += dp(3); } for (int i = 0; i < thumbsCount; ++i) { - thumbImage[i].setImageX(left + offset + AndroidUtilities.dp((thumbSize + 2) * i)); + thumbImage[i].setImageX(left + offset + dp((thumbSize + 2) * i)); thumbImageSeen[i] = true; } } else { @@ -2504,7 +2548,7 @@ private CharSequence applyThumbs(CharSequence string) { if (thumbsCount > 0) { SpannableStringBuilder builder = SpannableStringBuilder.valueOf(string); builder.insert(0, " "); - builder.setSpan(new FixedWidthSpan(AndroidUtilities.dp((thumbSize + 2) * thumbsCount - 2 + 5)), 0, 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + builder.setSpan(new FixedWidthSpan(dp((thumbSize + 2) * thumbsCount - 2 + 5)), 0, 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); return builder; } return string; @@ -2573,7 +2617,7 @@ private void drawCheckStatus(Canvas canvas, boolean drawClock, boolean drawCheck if (moveCheck) { canvas.restore(); canvas.save(); - canvas.translate(AndroidUtilities.dp(4) * (1f - alpha), 0); + canvas.translate(dp(4) * (1f - alpha), 0); } setDrawableBounds(Theme.dialogs_checkReadDrawable, checkDrawLeft, checkDrawTop); Theme.dialogs_checkReadDrawable.draw(canvas); @@ -2605,9 +2649,9 @@ private void drawCheckStatus(Canvas canvas, boolean drawClock, boolean drawCheck public boolean isPointInsideAvatar(float x, float y) { if (!LocaleController.isRTL) { - return x >= 0 && x < AndroidUtilities.dp(60); + return x >= 0 && x < dp(60); } else { - return x >= getMeasuredWidth() - AndroidUtilities.dp(60) && x < getMeasuredWidth(); + return x >= getMeasuredWidth() - dp(60) && x < getMeasuredWidth(); } } @@ -2707,7 +2751,7 @@ public boolean update(int mask, boolean animated) { for (int i = 0; i < thumbImage.length; ++i) { thumbImage[i].setImageBitmap((BitmapDrawable) null); } - avatarImage.setRoundRadius(AndroidUtilities.dp(28)); + avatarImage.setRoundRadius(dp(28)); drawUnmute = false; } else { int oldUnreadCount = unreadCount; @@ -2776,6 +2820,17 @@ public boolean update(int mask, boolean animated) { drawPin = false; } + if (tags != null) { + final boolean tagsWereEmpty = tags.isEmpty(); + if (tags.update(currentAccount, dialogsType, currentDialogId)) { + if (tagsWereEmpty != tags.isEmpty()) { + rebuildLayout = true; + requestLayout = true; + } + invalidate = true; + } + } + if (mask != 0) { boolean continueUpdate = false; if (user != null && !MessagesController.isSupportUser(user) && !user.bot && (mask & MessagesController.UPDATE_MASK_STATUS) != 0) { @@ -3032,7 +3087,7 @@ public void onAnimationEnd(Animator animation) { } } - int countOldWidth = Math.max(AndroidUtilities.dp(12), (int) Math.ceil(Theme.dialogs_countTextPaint.measureText(oldStr))); + int countOldWidth = Math.max(dp(12), (int) Math.ceil(Theme.dialogs_countTextPaint.measureText(oldStr))); countOldLayout = new StaticLayout(oldSpannableStr, Theme.dialogs_countTextPaint, countOldWidth, Layout.Alignment.ALIGN_CENTER, 1.0f, 0.0f, false); countAnimationStableLayout = new StaticLayout(stableStr, Theme.dialogs_countTextPaint, countOldWidth, Layout.Alignment.ALIGN_CENTER, 1.0f, 0.0f, false); countAnimationInLayout = new StaticLayout(newSpannableStr, Theme.dialogs_countTextPaint, countOldWidth, Layout.Alignment.ALIGN_CENTER, 1.0f, 0.0f, false); @@ -3260,7 +3315,7 @@ protected void onDraw(Canvas canvas) { lastDrawSwipeMessageStringId = swipeMessageStringId; } - if (!translationAnimationStarted && Math.abs(translationX) > AndroidUtilities.dp(43)) { + if (!translationAnimationStarted && Math.abs(translationX) > dp(43)) { translationAnimationStarted = true; translationDrawable.setProgress(0.0f); translationDrawable.setCallback(this); @@ -3270,7 +3325,7 @@ protected void onDraw(Canvas canvas) { float tx = getMeasuredWidth() + translationX; if (currentRevealProgress < 1.0f) { Theme.dialogs_pinnedPaint.setColor(backgroundColor); - canvas.drawRect(tx - AndroidUtilities.dp(8), 0, getMeasuredWidth(), getMeasuredHeight(), Theme.dialogs_pinnedPaint); + canvas.drawRect(tx - dp(8), 0, getMeasuredWidth(), getMeasuredHeight(), Theme.dialogs_pinnedPaint); if (currentRevealProgress == 0) { if (Theme.dialogs_archiveDrawableRecolored) { Theme.dialogs_archiveDrawable.setLayerColor("Arrow.**", Theme.getNonAnimatedColor(Theme.key_chats_archiveBackground)); @@ -3286,14 +3341,14 @@ protected void onDraw(Canvas canvas) { } } } - int drawableX = getMeasuredWidth() - AndroidUtilities.dp(43) - translationDrawable.getIntrinsicWidth() / 2; - int drawableY = (getMeasuredHeight() - AndroidUtilities.dp(54)) / 2; + int drawableX = getMeasuredWidth() - dp(43) - translationDrawable.getIntrinsicWidth() / 2; + int drawableY = (getMeasuredHeight() - dp(54)) / 2; int drawableCx = drawableX + translationDrawable.getIntrinsicWidth() / 2; int drawableCy = drawableY + translationDrawable.getIntrinsicHeight() / 2; if (currentRevealProgress > 0.0f) { canvas.save(); - canvas.clipRect(tx - AndroidUtilities.dp(8), 0, getMeasuredWidth(), getMeasuredHeight()); + canvas.clipRect(tx - dp(8), 0, getMeasuredWidth(), getMeasuredHeight()); Theme.dialogs_pinnedPaint.setColor(revealBackgroundColor); float rad = (float) Math.sqrt(drawableCx * drawableCx + (drawableCy - getMeasuredHeight()) * (drawableCy - getMeasuredHeight())); @@ -3331,17 +3386,17 @@ protected void onDraw(Canvas canvas) { if (swipeMessageTextId != swipeMessageStringId || swipeMessageWidth != getMeasuredWidth()) { swipeMessageTextId = swipeMessageStringId; swipeMessageWidth = getMeasuredWidth(); - swipeMessageTextLayout = new StaticLayout(swipeMessage, Theme.dialogs_archiveTextPaint, Math.min(AndroidUtilities.dp(80), width), Layout.Alignment.ALIGN_CENTER, 1.0f, 0.0f, false); + swipeMessageTextLayout = new StaticLayout(swipeMessage, Theme.dialogs_archiveTextPaint, Math.min(dp(80), width), Layout.Alignment.ALIGN_CENTER, 1.0f, 0.0f, false); if (swipeMessageTextLayout.getLineCount() > 1) { - swipeMessageTextLayout = new StaticLayout(swipeMessage, Theme.dialogs_archiveTextPaintSmall, Math.min(AndroidUtilities.dp(82), width), Layout.Alignment.ALIGN_CENTER, 1.0f, 0.0f, false); + swipeMessageTextLayout = new StaticLayout(swipeMessage, Theme.dialogs_archiveTextPaintSmall, Math.min(dp(82), width), Layout.Alignment.ALIGN_CENTER, 1.0f, 0.0f, false); } } if (swipeMessageTextLayout != null) { canvas.save(); - float yOffset = swipeMessageTextLayout.getLineCount() > 1 ? -AndroidUtilities.dp(4) : 0; - canvas.translate(getMeasuredWidth() - AndroidUtilities.dp(43) - swipeMessageTextLayout.getWidth() / 2f, drawableY + AndroidUtilities.dp(54 - 16) + yOffset); + float yOffset = swipeMessageTextLayout.getLineCount() > 1 ? -dp(4) : 0; + canvas.translate(getMeasuredWidth() - dp(43) - swipeMessageTextLayout.getWidth() / 2f, drawableY + dp(54 - 16) + yOffset); swipeMessageTextLayout.draw(canvas); canvas.restore(); } @@ -3359,7 +3414,7 @@ protected void onDraw(Canvas canvas) { canvas.translate(translationX, 0); } - float cornersRadius = AndroidUtilities.dp(8) * cornerProgress; + float cornersRadius = dp(8) * cornerProgress; if (isSelected) { rect.set(0, 0, getMeasuredWidth(), AndroidUtilities.lerp(getMeasuredHeight(), getCollapsedHeight(), rightFragmentOpenedProgress)); rect.offset(0, -translateY + collapseOffset); @@ -3391,19 +3446,19 @@ protected void onDraw(Canvas canvas) { if (rightFragmentOpenedProgress != 0) { float startAnimationProgress = Utilities.clamp(rightFragmentOpenedProgress / 0.4f, 1f, 0); if (SharedConfig.getDevicePerformanceClass() >= SharedConfig.PERFORMANCE_CLASS_HIGH) { - restoreToCount = canvas.saveLayerAlpha(AndroidUtilities.dp(RightSlidingDialogContainer.getRightPaddingSize() + 1) - AndroidUtilities.dp(8) * (1f - startAnimationProgress), 0, getMeasuredWidth(), getMeasuredHeight(), (int) (255 * (1f - rightFragmentOpenedProgress)), Canvas.ALL_SAVE_FLAG); + restoreToCount = canvas.saveLayerAlpha(dp(RightSlidingDialogContainer.getRightPaddingSize() + 1) - dp(8) * (1f - startAnimationProgress), 0, getMeasuredWidth(), getMeasuredHeight(), (int) (255 * (1f - rightFragmentOpenedProgress)), Canvas.ALL_SAVE_FLAG); } else { restoreToCount = canvas.save(); - canvas.clipRect(AndroidUtilities.dp(RightSlidingDialogContainer.getRightPaddingSize() + 1) - AndroidUtilities.dp(8) * (1f - startAnimationProgress), 0, getMeasuredWidth(), getMeasuredHeight()); + canvas.clipRect(dp(RightSlidingDialogContainer.getRightPaddingSize() + 1) - dp(8) * (1f - startAnimationProgress), 0, getMeasuredWidth(), getMeasuredHeight()); } - canvas.translate(-(getMeasuredWidth() - AndroidUtilities.dp(74)) * 0.7f * rightFragmentOpenedProgress, 0); + canvas.translate(-(getMeasuredWidth() - dp(74)) * 0.7f * rightFragmentOpenedProgress, 0); } if (translationX != 0 || cornerProgress != 0.0f) { canvas.save(); Theme.dialogs_pinnedPaint.setColor(Theme.getColor(Theme.key_windowBackgroundWhite, resourcesProvider)); - rect.set(getMeasuredWidth() - AndroidUtilities.dp(64), 0, getMeasuredWidth(), getMeasuredHeight()); + rect.set(getMeasuredWidth() - dp(64), 0, getMeasuredWidth(), getMeasuredHeight()); rect.offset(0, -translateY); canvas.drawRoundRect(rect, cornersRadius, cornersRadius, Theme.dialogs_pinnedPaint); @@ -3445,15 +3500,19 @@ protected void onDraw(Canvas canvas) { Theme.dialogs_lockDrawable.draw(canvas); } + int nameTop = dp(useForceThreeLines || SharedConfig.useThreeLinesLayout ? 10 : 13); + if ((!(useForceThreeLines || SharedConfig.useThreeLinesLayout) || isForumCell()) && hasTags()) { + nameTop -= dp(isForumCell() ? 8 : 9); + } if (nameLayout != null) { if (nameLayoutEllipsizeByGradient && !nameLayoutFits) { if (nameLayoutEllipsizeLeft && fadePaint == null) { fadePaint = new Paint(); - fadePaint.setShader(new LinearGradient(0, 0, AndroidUtilities.dp(24), 0, new int[]{0xffffffff, 0}, new float[]{0f, 1f}, Shader.TileMode.CLAMP)); + fadePaint.setShader(new LinearGradient(0, 0, dp(24), 0, new int[]{0xffffffff, 0}, new float[]{0f, 1f}, Shader.TileMode.CLAMP)); fadePaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT)); } else if (fadePaintBack == null) { fadePaintBack = new Paint(); - fadePaintBack.setShader(new LinearGradient(0, 0, AndroidUtilities.dp(24), 0, new int[]{0, 0xffffffff}, new float[]{0f, 1f}, Shader.TileMode.CLAMP)); + fadePaintBack.setShader(new LinearGradient(0, 0, dp(24), 0, new int[]{0, 0xffffffff}, new float[]{0f, 1f}, Shader.TileMode.CLAMP)); fadePaintBack.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT)); } canvas.saveLayerAlpha(0, 0, getMeasuredWidth(), getMeasuredHeight(), 255, Canvas.ALL_SAVE_FLAG); @@ -3467,7 +3526,7 @@ protected void onDraw(Canvas canvas) { Theme.dialogs_namePaint[paintIndex].setColor(Theme.dialogs_namePaint[paintIndex].linkColor = Theme.getColor(Theme.key_chats_name, resourcesProvider)); } canvas.save(); - canvas.translate(nameLeft + nameLayoutTranslateX, AndroidUtilities.dp(useForceThreeLines || SharedConfig.useThreeLinesLayout ? 10 : 13)); + canvas.translate(nameLeft + nameLayoutTranslateX, nameTop); SpoilerEffect.layoutDrawMaybe(nameLayout, canvas); AnimatedEmojiSpan.drawAnimatedEmojis(canvas, nameLayout, animatedEmojiStackName, -.075f, null, 0, 0, 0, 1f, getAdaptiveEmojiColorFilter(0, nameLayout.getPaint().getColor())); canvas.restore(); @@ -3475,10 +3534,10 @@ protected void onDraw(Canvas canvas) { canvas.save(); if (nameLayoutEllipsizeLeft) { canvas.translate(nameLeft, 0); - canvas.drawRect(0, 0, AndroidUtilities.dp(24), getMeasuredHeight(), fadePaint); + canvas.drawRect(0, 0, dp(24), getMeasuredHeight(), fadePaint); } else { - canvas.translate(nameLeft + nameWidth - AndroidUtilities.dp(24), 0); - canvas.drawRect(0, 0, AndroidUtilities.dp(24), getMeasuredHeight(), fadePaintBack); + canvas.translate(nameLeft + nameWidth - dp(24), 0); + canvas.drawRect(0, 0, dp(24), getMeasuredHeight(), fadePaintBack); } canvas.restore(); canvas.restore(); @@ -3532,12 +3591,15 @@ protected void onDraw(Canvas canvas) { Theme.dialogs_messagePaint[paintIndex].setColor(Theme.dialogs_messagePaint[paintIndex].linkColor = Theme.getColor(Theme.key_chats_message, resourcesProvider)); } float top; - float typingAnimationOffset = AndroidUtilities.dp(14); + float typingAnimationOffset = dp(14); if (updateHelper.typingOutToTop) { top = messageTop - typingAnimationOffset * updateHelper.typingProgres; } else { top = messageTop + typingAnimationOffset * updateHelper.typingProgres; } + if ((!(useForceThreeLines || SharedConfig.useThreeLinesLayout) || isForumCell()) && hasTags()) { + top -= dp(isForumCell() ? 10 : 11); + } if (updateHelper.typingProgres != 1f) { canvas.save(); canvas.translate(messageLeft, top); @@ -3573,6 +3635,9 @@ protected void onDraw(Canvas canvas) { } else { top = messageTop - typingAnimationOffset * (1f - updateHelper.typingProgres); } + if ((!(useForceThreeLines || SharedConfig.useThreeLinesLayout) || isForumCell()) && hasTags()) { + top -= dp(isForumCell() ? 10 : 11); + } canvas.translate(typingLeft, top); if (typingLayout != null && updateHelper.typingProgres > 0) { int oldAlpha = typingLayout.getPaint().getAlpha(); @@ -3594,10 +3659,13 @@ protected void onDraw(Canvas canvas) { } else { top = messageTop - typingAnimationOffset * (1f - updateHelper.typingProgres); } + if ((!(useForceThreeLines || SharedConfig.useThreeLinesLayout) || isForumCell()) && hasTags()) { + top -= dp(isForumCell() ? 10 : 11); + } if (type == 1 || type == 4) { - canvas.translate(statusDrawableLeft, top + (type == 1 ? AndroidUtilities.dp(1) : 0)); + canvas.translate(statusDrawableLeft, top + (type == 1 ? dp(1) : 0)); } else { - canvas.translate(statusDrawableLeft, top + (AndroidUtilities.dp(18) - statusDrawable.getIntrinsicHeight()) / 2f); + canvas.translate(statusDrawableLeft, top + (dp(18) - statusDrawable.getIntrinsicHeight()) / 2f); } statusDrawable.draw(canvas); invalidate(); @@ -3625,27 +3693,31 @@ protected void onDraw(Canvas canvas) { }); } - if (lastTopicMessageUnread && topMessageTopicEndIndex != topMessageTopicStartIndex && (dialogsType == DialogsActivity.DIALOGS_TYPE_DEFAULT || dialogsType == DialogsActivity.DIALOGS_TYPE_7 || dialogsType == DialogsActivity.DIALOGS_TYPE_8)) { + if (lastTopicMessageUnread && topMessageTopicEndIndex != topMessageTopicStartIndex && (dialogsType == DialogsActivity.DIALOGS_TYPE_DEFAULT || dialogsType == DialogsActivity.DIALOGS_TYPE_FOLDER1 || dialogsType == DialogsActivity.DIALOGS_TYPE_FOLDER2)) { canvasButton.setColor(ColorUtils.setAlphaComponent(currentMessagePaint.getColor(), Theme.isCurrentThemeDark() ? 36 : 26)); if (!buttonCreated) { canvasButton.rewind(); if (topMessageTopicEndIndex != topMessageTopicStartIndex && topMessageTopicEndIndex > 0) { - AndroidUtilities.rectTmp.set(messageLeft + AndroidUtilities.dp(2) + messageLayout.getPrimaryHorizontal(0), messageTop, messageLeft + messageLayout.getPrimaryHorizontal(Math.min(messageLayout.getText().length(), topMessageTopicEndIndex)) - AndroidUtilities.dp(3), buttonTop - AndroidUtilities.dp(4)); - AndroidUtilities.rectTmp.inset(-AndroidUtilities.dp(8), -AndroidUtilities.dp(4)); + float top = messageTop; + if ((!(useForceThreeLines || SharedConfig.useThreeLinesLayout) || isForumCell()) && hasTags()) { + top -= dp(isForumCell() ? 10 : 11); + } + AndroidUtilities.rectTmp.set(messageLeft + dp(2) + messageLayout.getPrimaryHorizontal(0), top, messageLeft + messageLayout.getPrimaryHorizontal(Math.min(messageLayout.getText().length(), topMessageTopicEndIndex)) - dp(3), buttonTop - dp(4)); + AndroidUtilities.rectTmp.inset(-dp(8), -dp(4)); if (AndroidUtilities.rectTmp.right > AndroidUtilities.rectTmp.left) { canvasButton.addRect(AndroidUtilities.rectTmp); } } float buttonLayoutLeft = buttonLayout.getLineLeft(0); - AndroidUtilities.rectTmp.set(buttonLeft + buttonLayoutLeft + AndroidUtilities.dp(2), buttonTop + AndroidUtilities.dp(2), buttonLeft + buttonLayoutLeft + buttonLayout.getLineWidth(0) + AndroidUtilities.dp(12), buttonTop + buttonLayout.getHeight()); - AndroidUtilities.rectTmp.inset(-AndroidUtilities.dp(8), -AndroidUtilities.dp(3)); + AndroidUtilities.rectTmp.set(buttonLeft + buttonLayoutLeft + dp(2), buttonTop + dp(2), buttonLeft + buttonLayoutLeft + buttonLayout.getLineWidth(0) + dp(12), buttonTop + buttonLayout.getHeight()); + AndroidUtilities.rectTmp.inset(-dp(8), -dp(3)); canvasButton.addRect(AndroidUtilities.rectTmp); } canvasButton.draw(canvas); Theme.dialogs_forum_arrowDrawable.setAlpha(125); - setDrawableBounds(Theme.dialogs_forum_arrowDrawable, AndroidUtilities.rectTmp.right - AndroidUtilities.dp(18), AndroidUtilities.rectTmp.top + (AndroidUtilities.rectTmp.height() - Theme.dialogs_forum_arrowDrawable.getIntrinsicHeight()) / 2f); + setDrawableBounds(Theme.dialogs_forum_arrowDrawable, AndroidUtilities.rectTmp.right - dp(18), AndroidUtilities.rectTmp.top + (AndroidUtilities.rectTmp.height() - Theme.dialogs_forum_arrowDrawable.getIntrinsicHeight()) / 2f); Theme.dialogs_forum_arrowDrawable.draw(canvas); } @@ -3720,8 +3792,11 @@ protected void onDraw(Canvas canvas) { invalidate(); } } - float muteX = nameMuteLeft - AndroidUtilities.dp(useForceThreeLines || SharedConfig.useThreeLinesLayout ? 0 : 1); - float muteY = AndroidUtilities.dp(SharedConfig.useThreeLinesLayout ? 13.5f : 17.5f); + float muteX = nameMuteLeft - dp(useForceThreeLines || SharedConfig.useThreeLinesLayout ? 0 : 1); + float muteY = dp(SharedConfig.useThreeLinesLayout ? 13.5f : 17.5f); + if ((!(useForceThreeLines || SharedConfig.useThreeLinesLayout) || isForumCell()) && hasTags()) { + muteY -= dp(isForumCell() ? 8 : 9); + } setDrawableBounds(Theme.dialogs_muteDrawable, muteX, muteY); setDrawableBounds(Theme.dialogs_unmuteDrawable, muteX, muteY); if (dialogMutedProgress != 1f) { @@ -3746,27 +3821,39 @@ protected void onDraw(Canvas canvas) { } } else if (drawVerified) { - setDrawableBounds(Theme.dialogs_verifiedDrawable, nameMuteLeft - AndroidUtilities.dp(1), AndroidUtilities.dp(useForceThreeLines || SharedConfig.useThreeLinesLayout ? 13.5f : 16.5f)); - setDrawableBounds(Theme.dialogs_verifiedCheckDrawable, nameMuteLeft - AndroidUtilities.dp(1), AndroidUtilities.dp(useForceThreeLines || SharedConfig.useThreeLinesLayout ? 13.5f : 16.5f)); + float y = dp(useForceThreeLines || SharedConfig.useThreeLinesLayout ? 13.5f : 16.5f); + if ((!(useForceThreeLines || SharedConfig.useThreeLinesLayout) || isForumCell()) && hasTags()) { + y -= dp(9); + } + setDrawableBounds(Theme.dialogs_verifiedDrawable, nameMuteLeft - dp(1), y); + setDrawableBounds(Theme.dialogs_verifiedCheckDrawable, nameMuteLeft - dp(1), y); Theme.dialogs_verifiedDrawable.draw(canvas); Theme.dialogs_verifiedCheckDrawable.draw(canvas); } else if (drawPremium) { + int y = dp(useForceThreeLines || SharedConfig.useThreeLinesLayout ? 12.5f : 15.5f); + if ((!(useForceThreeLines || SharedConfig.useThreeLinesLayout) || isForumCell()) && hasTags()) { + y -= dp(9); + } if (emojiStatus != null) { emojiStatus.setBounds( - nameMuteLeft - AndroidUtilities.dp(2), - AndroidUtilities.dp(useForceThreeLines || SharedConfig.useThreeLinesLayout ? 12.5f : 15.5f) - AndroidUtilities.dp(4), - nameMuteLeft + AndroidUtilities.dp(20), - AndroidUtilities.dp(useForceThreeLines || SharedConfig.useThreeLinesLayout ? 12.5f : 15.5f) - AndroidUtilities.dp(4) + AndroidUtilities.dp(22) + nameMuteLeft - dp(2), + y - dp(4), + nameMuteLeft + dp(20), + y - dp(4) + dp(22) ); emojiStatus.setColor(Theme.getColor(Theme.key_chats_verifiedBackground, resourcesProvider)); emojiStatus.draw(canvas); } else { Drawable premiumDrawable = PremiumGradient.getInstance().premiumStarDrawableMini; - setDrawableBounds(premiumDrawable, nameMuteLeft - AndroidUtilities.dp(1), AndroidUtilities.dp(useForceThreeLines || SharedConfig.useThreeLinesLayout ? 12.5f : 15.5f)); + setDrawableBounds(premiumDrawable, nameMuteLeft - dp(1), dp(useForceThreeLines || SharedConfig.useThreeLinesLayout ? 12.5f : 15.5f)); premiumDrawable.draw(canvas); } } else if (drawScam != 0) { - setDrawableBounds((drawScam == 1 ? Theme.dialogs_scamDrawable : Theme.dialogs_fakeDrawable), nameMuteLeft, AndroidUtilities.dp(useForceThreeLines || SharedConfig.useThreeLinesLayout ? 12 : 15)); + int y = dp(useForceThreeLines || SharedConfig.useThreeLinesLayout ? 12 : 15); + if ((!(useForceThreeLines || SharedConfig.useThreeLinesLayout) || isForumCell()) && hasTags()) { + y -= dp(9); + } + setDrawableBounds((drawScam == 1 ? Theme.dialogs_scamDrawable : Theme.dialogs_fakeDrawable), nameMuteLeft, y); (drawScam == 1 ? Theme.dialogs_scamDrawable : Theme.dialogs_fakeDrawable).draw(canvas); } @@ -3777,9 +3864,9 @@ protected void onDraw(Canvas canvas) { } if (drawError) { Theme.dialogs_errorDrawable.setAlpha((int) ((1.0f - reorderIconProgress) * 255)); - rect.set(errorLeft, errorTop, errorLeft + AndroidUtilities.dp(23), errorTop + AndroidUtilities.dp(23)); + rect.set(errorLeft, errorTop, errorLeft + dp(23), errorTop + dp(23)); 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)); + setDrawableBounds(Theme.dialogs_errorDrawable, errorLeft + dp(5.5f), errorTop + dp(5)); Theme.dialogs_errorDrawable.draw(canvas); } else if ((drawCount || drawMention) && drawCount2 || countChangeProgress != 1f || drawReactionMention || reactionsMentionsChangeProgress != 1f) { boolean drawCounterMuted; @@ -3792,21 +3879,21 @@ protected void onDraw(Canvas canvas) { if (drawMention) { Theme.dialogs_countPaint.setAlpha((int) ((1.0f - reorderIconProgress) * 255)); - int x = mentionLeft - AndroidUtilities.dp(5.5f); - rect.set(x, countTop, x + mentionWidth + AndroidUtilities.dp(11), countTop + AndroidUtilities.dp(23)); + int x = mentionLeft - dp(5.5f); + rect.set(x, countTop, x + mentionWidth + dp(11), countTop + dp(23)); Paint paint = drawCounterMuted && folderId != 0 ? Theme.dialogs_countGrayPaint : Theme.dialogs_countPaint; canvas.drawRoundRect(rect, 11.5f * AndroidUtilities.density, 11.5f * AndroidUtilities.density, paint); if (mentionLayout != null) { Theme.dialogs_countTextPaint.setAlpha((int) ((1.0f - reorderIconProgress) * 255)); canvas.save(); - canvas.translate(mentionLeft, countTop + AndroidUtilities.dp(4)); + canvas.translate(mentionLeft, countTop + dp(4)); mentionLayout.draw(canvas); canvas.restore(); } else { Theme.dialogs_mentionDrawable.setAlpha((int) ((1.0f - reorderIconProgress) * 255)); - setDrawableBounds(Theme.dialogs_mentionDrawable, mentionLeft - AndroidUtilities.dp(2), countTop + AndroidUtilities.dp(3.2f), AndroidUtilities.dp(16), AndroidUtilities.dp(16)); + setDrawableBounds(Theme.dialogs_mentionDrawable, mentionLeft - dp(2), countTop + dp(3.2f), dp(16), dp(16)); Theme.dialogs_mentionDrawable.draw(canvas); } } @@ -3815,8 +3902,8 @@ protected void onDraw(Canvas canvas) { Theme.dialogs_reactionsCountPaint.setAlpha((int) ((1.0f - reorderIconProgress) * 255)); - int x = reactionMentionLeft - AndroidUtilities.dp(5.5f); - rect.set(x, countTop, x + AndroidUtilities.dp(23), countTop + AndroidUtilities.dp(23)); + int x = reactionMentionLeft - dp(5.5f); + rect.set(x, countTop, x + dp(23), countTop + dp(23)); Paint paint = Theme.dialogs_reactionsCountPaint; canvas.save(); @@ -3826,7 +3913,7 @@ protected void onDraw(Canvas canvas) { } canvas.drawRoundRect(rect, 11.5f * AndroidUtilities.density, 11.5f * AndroidUtilities.density, paint); Theme.dialogs_reactionsMentionDrawable.setAlpha((int) ((1.0f - reorderIconProgress) * 255)); - setDrawableBounds(Theme.dialogs_reactionsMentionDrawable, reactionMentionLeft - AndroidUtilities.dp(2), countTop + AndroidUtilities.dp(3.8f), AndroidUtilities.dp(16), AndroidUtilities.dp(16)); + setDrawableBounds(Theme.dialogs_reactionsMentionDrawable, reactionMentionLeft - dp(2), countTop + dp(3.8f), dp(16), dp(16)); Theme.dialogs_reactionsMentionDrawable.draw(canvas); canvas.restore(); } @@ -3843,9 +3930,9 @@ protected void onDraw(Canvas canvas) { canvas.saveLayerAlpha(0, 0, getWidth(), getHeight(), (int) (255 * alpha), Canvas.ALL_SAVE_FLAG); float top; if (updateHelper.typingOutToTop) { - top = -AndroidUtilities.dp(14) * updateHelper.typingProgres; + top = -dp(14) * updateHelper.typingProgres; } else { - top = AndroidUtilities.dp(14) * updateHelper.typingProgres; + top = dp(14) * updateHelper.typingProgres; } canvas.translate(0, top); } @@ -3855,7 +3942,7 @@ protected void onDraw(Canvas canvas) { } if (thumbBackgroundPaint == null) { thumbBackgroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG); - thumbBackgroundPaint.setShadowLayer(AndroidUtilities.dp(1.34f), 0, AndroidUtilities.dp(0.34f), 0x18000000); + thumbBackgroundPaint.setShadowLayer(dp(1.34f), 0, dp(0.34f), 0x18000000); thumbBackgroundPaint.setColor(0x00000000); } AndroidUtilities.rectTmp.set( @@ -3903,6 +3990,13 @@ protected void onDraw(Canvas canvas) { } } + if (tags != null && !tags.isEmpty()) { + canvas.save(); + canvas.translate(tagsLeft, getMeasuredHeight() - dp(21.66f) - (useSeparator ? 1 : 0)); + tags.draw(canvas, tagsRight - tagsLeft); + canvas.restore(); + } + if (restoreToCount != -1) { canvas.restoreToCount(restoreToCount); } @@ -3936,9 +4030,9 @@ protected void onDraw(Canvas canvas) { } else { drawCounterMuted = chat != null && chat.forum && forumTopic == null ? !hasUnmutedTopics : dialogMuted; } - int countLeftLocal = (int) (storyParams.originalAvatarRect.left + storyParams.originalAvatarRect.width() - countWidth - AndroidUtilities.dp(5f)); - int countLeftOld = (int) (storyParams.originalAvatarRect.left + storyParams.originalAvatarRect.width() - countWidthOld - AndroidUtilities.dp(5f)); - int countTop = (int) (avatarImage.getImageY() + storyParams.originalAvatarRect.height() - AndroidUtilities.dp(22)); + int countLeftLocal = (int) (storyParams.originalAvatarRect.left + storyParams.originalAvatarRect.width() - countWidth - dp(5f)); + int countLeftOld = (int) (storyParams.originalAvatarRect.left + storyParams.originalAvatarRect.width() - countWidthOld - dp(5f)); + int countTop = (int) (avatarImage.getImageY() + storyParams.originalAvatarRect.height() - dp(22)); drawCounter(canvas, drawCounterMuted, countTop, countLeftLocal, countLeftOld, rightFragmentOpenedProgress, true); } @@ -3962,7 +4056,7 @@ protected void onDraw(Canvas canvas) { if (fullSeparator || currentDialogFolderId != 0 && archiveHidden && !fullSeparator2 || fullSeparator2 && !archiveHidden) { left = 0; } else { - left = AndroidUtilities.dp(messagePaddingStart); + left = dp(messagePaddingStart); } if (rightFragmentOpenedProgress != 1) { @@ -4122,15 +4216,15 @@ public boolean drawAvatarOverlays(Canvas canvas) { timerPaint2 = new Paint(Paint.ANTI_ALIAS_FLAG); timerPaint2.setColor(0x32000000); } - int top = (int) (avatarImage.getImageY2() - AndroidUtilities.dp(9)); + int top = (int) (avatarImage.getImageY2() - dp(9)); int left; if (LocaleController.isRTL) { - left = (int) (storyParams.originalAvatarRect.left + AndroidUtilities.dp(9)); + left = (int) (storyParams.originalAvatarRect.left + dp(9)); } else { - left = (int) (storyParams.originalAvatarRect.right - AndroidUtilities.dp(9)); + left = (int) (storyParams.originalAvatarRect.right - dp(9)); } timerDrawable.setBounds( - 0, 0, AndroidUtilities.dp(22), AndroidUtilities.dp(22) + 0, 0, dp(22), dp(22) ); timerDrawable.setTime(ttlPeriod); @@ -4169,18 +4263,18 @@ public boolean drawAvatarOverlays(Canvas canvas) { boolean isOnline = isOnline(); wasDrawnOnline = isOnline; if (isOnline || onlineProgress != 0) { - int top = (int) (storyParams.originalAvatarRect.bottom - AndroidUtilities.dp(useForceThreeLines || SharedConfig.useThreeLinesLayout ? 6 : 8)); + int top = (int) (storyParams.originalAvatarRect.bottom - dp(useForceThreeLines || SharedConfig.useThreeLinesLayout ? 6 : 8)); int left; if (LocaleController.isRTL) { - left = (int) (storyParams.originalAvatarRect.left + AndroidUtilities.dp(useForceThreeLines || SharedConfig.useThreeLinesLayout ? 10 : 6)); + left = (int) (storyParams.originalAvatarRect.left + dp(useForceThreeLines || SharedConfig.useThreeLinesLayout ? 10 : 6)); } else { - left = (int) (storyParams.originalAvatarRect.right - AndroidUtilities.dp(useForceThreeLines || SharedConfig.useThreeLinesLayout ? 10 : 6)); + left = (int) (storyParams.originalAvatarRect.right - dp(useForceThreeLines || SharedConfig.useThreeLinesLayout ? 10 : 6)); } Theme.dialogs_onlineCirclePaint.setColor(Theme.getColor(Theme.key_windowBackgroundWhite, resourcesProvider)); - canvas.drawCircle(left, top, AndroidUtilities.dp(7) * onlineProgress, Theme.dialogs_onlineCirclePaint); + canvas.drawCircle(left, top, dp(7) * onlineProgress, Theme.dialogs_onlineCirclePaint); Theme.dialogs_onlineCirclePaint.setColor(Theme.getColor(Theme.key_chats_onlineCircle, resourcesProvider)); - canvas.drawCircle(left, top, AndroidUtilities.dp(5) * onlineProgress, Theme.dialogs_onlineCirclePaint); + canvas.drawCircle(left, top, dp(5) * onlineProgress, Theme.dialogs_onlineCirclePaint); if (isOnline) { if (onlineProgress < 1.0f) { onlineProgress += 16f / 150.0f; @@ -4203,12 +4297,12 @@ public boolean drawAvatarOverlays(Canvas canvas) { hasCall = chat.call_active && chat.call_not_empty; if ((hasCall || chatCallProgress != 0) && rightFragmentOpenedProgress < 1f) { float checkProgress = checkBox != null && checkBox.isChecked() ? 1.0f - checkBox.getProgress() : 1.0f; - int top = (int) (storyParams.originalAvatarRect.bottom - AndroidUtilities.dp(useForceThreeLines || SharedConfig.useThreeLinesLayout ? 6 : 8)); + int top = (int) (storyParams.originalAvatarRect.bottom - dp(useForceThreeLines || SharedConfig.useThreeLinesLayout ? 6 : 8)); int left; if (LocaleController.isRTL) { - left = (int) (storyParams.originalAvatarRect.left + AndroidUtilities.dp(useForceThreeLines || SharedConfig.useThreeLinesLayout ? 10 : 6)); + left = (int) (storyParams.originalAvatarRect.left + dp(useForceThreeLines || SharedConfig.useThreeLinesLayout ? 10 : 6)); } else { - left = (int) (storyParams.originalAvatarRect.right - AndroidUtilities.dp(useForceThreeLines || SharedConfig.useThreeLinesLayout ? 10 : 6)); + left = (int) (storyParams.originalAvatarRect.right - dp(useForceThreeLines || SharedConfig.useThreeLinesLayout ? 10 : 6)); } if (rightFragmentOpenedProgress != 0) { @@ -4217,9 +4311,9 @@ public boolean drawAvatarOverlays(Canvas canvas) { canvas.scale(scale, scale, left, top); } Theme.dialogs_onlineCirclePaint.setColor(Theme.getColor(Theme.key_windowBackgroundWhite, resourcesProvider)); - canvas.drawCircle(left, top, AndroidUtilities.dp(11) * chatCallProgress * checkProgress, Theme.dialogs_onlineCirclePaint); + canvas.drawCircle(left, top, dp(11) * chatCallProgress * checkProgress, Theme.dialogs_onlineCirclePaint); Theme.dialogs_onlineCirclePaint.setColor(Theme.getColor(Theme.key_chats_onlineCircle, resourcesProvider)); - canvas.drawCircle(left, top, AndroidUtilities.dp(9) * chatCallProgress * checkProgress, Theme.dialogs_onlineCirclePaint); + canvas.drawCircle(left, top, dp(9) * chatCallProgress * checkProgress, Theme.dialogs_onlineCirclePaint); Theme.dialogs_onlineCirclePaint.setColor(Theme.getColor(Theme.key_windowBackgroundWhite, resourcesProvider)); float size1; @@ -4228,43 +4322,43 @@ public boolean drawAvatarOverlays(Canvas canvas) { innerProgress = 0.65f; } if (progressStage == 0) { - size1 = AndroidUtilities.dp(1) + AndroidUtilities.dp(4) * innerProgress; - size2 = AndroidUtilities.dp(3) - AndroidUtilities.dp(2) * innerProgress; + size1 = dp(1) + dp(4) * innerProgress; + size2 = dp(3) - dp(2) * innerProgress; } else if (progressStage == 1) { - size1 = AndroidUtilities.dp(5) - AndroidUtilities.dp(4) * innerProgress; - size2 = AndroidUtilities.dp(1) + AndroidUtilities.dp(4) * innerProgress; + size1 = dp(5) - dp(4) * innerProgress; + size2 = dp(1) + dp(4) * innerProgress; } else if (progressStage == 2) { - size1 = AndroidUtilities.dp(1) + AndroidUtilities.dp(2) * innerProgress; - size2 = AndroidUtilities.dp(5) - AndroidUtilities.dp(4) * innerProgress; + size1 = dp(1) + dp(2) * innerProgress; + size2 = dp(5) - dp(4) * innerProgress; } else if (progressStage == 3) { - size1 = AndroidUtilities.dp(3) - AndroidUtilities.dp(2) * innerProgress; - size2 = AndroidUtilities.dp(1) + AndroidUtilities.dp(2) * innerProgress; + size1 = dp(3) - dp(2) * innerProgress; + size2 = dp(1) + dp(2) * innerProgress; } else if (progressStage == 4) { - size1 = AndroidUtilities.dp(1) + AndroidUtilities.dp(4) * innerProgress; - size2 = AndroidUtilities.dp(3) - AndroidUtilities.dp(2) * innerProgress; + size1 = dp(1) + dp(4) * innerProgress; + size2 = dp(3) - dp(2) * innerProgress; } else if (progressStage == 5) { - size1 = AndroidUtilities.dp(5) - AndroidUtilities.dp(4) * innerProgress; - size2 = AndroidUtilities.dp(1) + AndroidUtilities.dp(4) * innerProgress; + size1 = dp(5) - dp(4) * innerProgress; + size2 = dp(1) + dp(4) * innerProgress; } else if (progressStage == 6) { - size1 = AndroidUtilities.dp(1) + AndroidUtilities.dp(4) * innerProgress; - size2 = AndroidUtilities.dp(5) - AndroidUtilities.dp(4) * innerProgress; + size1 = dp(1) + dp(4) * innerProgress; + size2 = dp(5) - dp(4) * innerProgress; } else { - size1 = AndroidUtilities.dp(5) - AndroidUtilities.dp(4) * innerProgress; - size2 = AndroidUtilities.dp(1) + AndroidUtilities.dp(2) * innerProgress; + size1 = dp(5) - dp(4) * innerProgress; + size2 = dp(1) + dp(2) * innerProgress; } if (chatCallProgress < 1.0f || checkProgress < 1.0f) { canvas.save(); canvas.scale(chatCallProgress * checkProgress, chatCallProgress * checkProgress, left, top); } - rect.set(left - AndroidUtilities.dp(1), top - size1, left + AndroidUtilities.dp(1), top + size1); - canvas.drawRoundRect(rect, AndroidUtilities.dp(1), AndroidUtilities.dp(1), Theme.dialogs_onlineCirclePaint); + rect.set(left - dp(1), top - size1, left + dp(1), top + size1); + canvas.drawRoundRect(rect, dp(1), dp(1), Theme.dialogs_onlineCirclePaint); - rect.set(left - AndroidUtilities.dp(5), top - size2, left - AndroidUtilities.dp(3), top + size2); - canvas.drawRoundRect(rect, AndroidUtilities.dp(1), AndroidUtilities.dp(1), Theme.dialogs_onlineCirclePaint); + rect.set(left - dp(5), top - size2, left - dp(3), top + size2); + canvas.drawRoundRect(rect, dp(1), dp(1), Theme.dialogs_onlineCirclePaint); - rect.set(left + AndroidUtilities.dp(3), top - size2, left + AndroidUtilities.dp(5), top + size2); - canvas.drawRoundRect(rect, AndroidUtilities.dp(1), AndroidUtilities.dp(1), Theme.dialogs_onlineCirclePaint); + rect.set(left + dp(3), top - size2, left + dp(5), top + size2); + canvas.drawRoundRect(rect, dp(1), dp(1), Theme.dialogs_onlineCirclePaint); if (chatCallProgress < 1.0f || checkProgress < 1.0f) { canvas.restore(); } @@ -4331,7 +4425,7 @@ private void drawCounter(Canvas canvas, boolean drawCounterMuted, int countTop, if (counterPaintOutline == null) { counterPaintOutline = new Paint(); counterPaintOutline.setStyle(Paint.Style.STROKE); - counterPaintOutline.setStrokeWidth(AndroidUtilities.dp(2)); + counterPaintOutline.setStrokeWidth(dp(2)); counterPaintOutline.setStrokeJoin(Paint.Join.ROUND); counterPaintOutline.setStrokeCap(Paint.Cap.ROUND); } @@ -4361,8 +4455,8 @@ private void drawCounter(Canvas canvas, boolean drawCounterMuted, int countTop, paint.setAlpha((int) ((1.0f - reorderIconProgress) * fillPaintAlpha)); Theme.dialogs_countTextPaint.setAlpha((int) ((1.0f - reorderIconProgress) * 255)); - int x = countLeftLocal - AndroidUtilities.dp(5.5f); - rect.set(x, countTop, x + countWidth + AndroidUtilities.dp(11), countTop + AndroidUtilities.dp(23)); + int x = countLeftLocal - dp(5.5f); + rect.set(x, countTop, x + countWidth + dp(11), countTop + dp(23)); int restoreToCount = canvas.save(); if (globalScale != 1f) { @@ -4390,21 +4484,21 @@ private void drawCounter(Canvas canvas, boolean drawCounterMuted, int countTop, if (counterPath == null) { counterPath = new Path(); } - BubbleCounterPath.addBubbleRect(counterPath, counterPathRect, AndroidUtilities.dp(11.5f)); + BubbleCounterPath.addBubbleRect(counterPath, counterPathRect, dp(11.5f)); } canvas.drawPath(counterPath, paint); if (outline) { canvas.drawPath(counterPath, counterPaintOutline); } } else { - canvas.drawRoundRect(rect, AndroidUtilities.dp(11.5f), AndroidUtilities.dp(11.5f), paint); + canvas.drawRoundRect(rect, dp(11.5f), dp(11.5f), paint); if (outline) { - canvas.drawRoundRect(rect, AndroidUtilities.dp(11.5f), AndroidUtilities.dp(11.5f), counterPaintOutline); + canvas.drawRoundRect(rect, dp(11.5f), dp(11.5f), counterPaintOutline); } } if (drawLayout != null) { canvas.save(); - canvas.translate(countLeftLocal, countTop + AndroidUtilities.dp(4)); + canvas.translate(countLeftLocal, countTop + dp(4)); drawLayout.draw(canvas); canvas.restore(); } @@ -4420,8 +4514,8 @@ private void drawCounter(Canvas canvas, boolean drawCounterMuted, int countTop, } float countLeft = countLeftLocal * progressHalf + countLeftOld * (1f - progressHalf); - float x = countLeft - AndroidUtilities.dp(5.5f); - rect.set(x, countTop, x + (countWidth * progressHalf) + (countWidthOld * (1f - progressHalf)) + AndroidUtilities.dp(11), countTop + AndroidUtilities.dp(23)); + float x = countLeft - dp(5.5f); + rect.set(x, countTop, x + (countWidth * progressHalf) + (countWidthOld * (1f - progressHalf)) + dp(11), countTop + dp(23)); float scale = 1f; if (progressFinal <= 0.5f) { @@ -4442,21 +4536,21 @@ private void drawCounter(Canvas canvas, boolean drawCounterMuted, int countTop, if (counterPath == null) { counterPath = new Path(); } - BubbleCounterPath.addBubbleRect(counterPath, counterPathRect, AndroidUtilities.dp(11.5f)); + BubbleCounterPath.addBubbleRect(counterPath, counterPathRect, dp(11.5f)); } canvas.drawPath(counterPath, paint); if (outline) { canvas.drawPath(counterPath, counterPaintOutline); } } else { - canvas.drawRoundRect(rect, AndroidUtilities.dp(11.5f), AndroidUtilities.dp(11.5f), paint); + canvas.drawRoundRect(rect, dp(11.5f), dp(11.5f), paint); if (outline) { - canvas.drawRoundRect(rect, AndroidUtilities.dp(11.5f), AndroidUtilities.dp(11.5f), counterPaintOutline); + canvas.drawRoundRect(rect, dp(11.5f), dp(11.5f), counterPaintOutline); } } if (countAnimationStableLayout != null) { canvas.save(); - canvas.translate(countLeft, countTop + AndroidUtilities.dp(4)); + canvas.translate(countLeft, countTop + dp(4)); countAnimationStableLayout.draw(canvas); canvas.restore(); } @@ -4465,12 +4559,12 @@ private void drawCounter(Canvas canvas, boolean drawCounterMuted, int countTop, Theme.dialogs_countTextPaint.setAlpha((int) (textAlpha * progressHalf)); if (countAnimationInLayout != null) { canvas.save(); - canvas.translate(countLeft, (countAnimationIncrement ? AndroidUtilities.dp(13) : -AndroidUtilities.dp(13)) * (1f - progressHalf) + countTop + AndroidUtilities.dp(4)); + canvas.translate(countLeft, (countAnimationIncrement ? dp(13) : -dp(13)) * (1f - progressHalf) + countTop + dp(4)); countAnimationInLayout.draw(canvas); canvas.restore(); } else if (countLayout != null) { canvas.save(); - canvas.translate(countLeft, (countAnimationIncrement ? AndroidUtilities.dp(13) : -AndroidUtilities.dp(13)) * (1f - progressHalf) + countTop + AndroidUtilities.dp(4)); + canvas.translate(countLeft, (countAnimationIncrement ? dp(13) : -dp(13)) * (1f - progressHalf) + countTop + dp(4)); countLayout.draw(canvas); canvas.restore(); } @@ -4478,7 +4572,7 @@ private void drawCounter(Canvas canvas, boolean drawCounterMuted, int countTop, if (countOldLayout != null) { Theme.dialogs_countTextPaint.setAlpha((int) (textAlpha * (1f - progressHalf))); canvas.save(); - canvas.translate(countLeft, (countAnimationIncrement ? -AndroidUtilities.dp(13) : AndroidUtilities.dp(13)) * progressHalf + countTop + AndroidUtilities.dp(4)); + canvas.translate(countLeft, (countAnimationIncrement ? -dp(13) : dp(13)) * progressHalf + countTop + dp(4)); countOldLayout.draw(canvas); canvas.restore(); } @@ -4523,8 +4617,8 @@ public void onAnimationEnd(Animator animation) { public void startOutAnimation() { if (archivedChatsDrawable != null) { if (isTopic) { - archivedChatsDrawable.outCy = AndroidUtilities.dp(10 + 14); - archivedChatsDrawable.outCx = AndroidUtilities.dp(10 + 14); + archivedChatsDrawable.outCy = dp(10 + 14); + archivedChatsDrawable.outCx = dp(10 + 14); archivedChatsDrawable.outRadius = 0; archivedChatsDrawable.outImageSize = 0; } else { @@ -4816,7 +4910,7 @@ private void setThumb(int index, MessageObject message) { int size = message.type == MessageObject.TYPE_PHOTO && selectedThumb != null ? selectedThumb.size : 0; String filter = message.hasMediaSpoilers() ? "5_5_b" : "20_20"; thumbImage[index].setImage(ImageLocation.getForObject(selectedThumb, photoThumbsObject), filter, ImageLocation.getForObject(smallThumb, photoThumbsObject), filter, size, null, message, 0); - thumbImage[index].setRoundRadius(message.isRoundVideo() ? AndroidUtilities.dp(18) : AndroidUtilities.dp(2)); + thumbImage[index].setRoundRadius(message.isRoundVideo() ? dp(18) : dp(2)); needEmoji = false; } } @@ -4938,7 +5032,7 @@ public SpannableStringBuilder getMessageStringFormatted(int messageFormatType, S } if (message.hasHighlightedWords() && !TextUtils.isEmpty(message.messageOwner.message)) { CharSequence text = message.messageTrimmedToHighlight; - int w = getMeasuredWidth() - AndroidUtilities.dp(messagePaddingStart + 23 + 24); + int w = getMeasuredWidth() - dp(messagePaddingStart + 23 + 24); if (hasNameInMessage) { if (!TextUtils.isEmpty(messageNameString)) { w -= currentMessagePaint.measureText(messageNameString.toString()); @@ -5022,7 +5116,7 @@ public SpannableStringBuilder getMessageStringFormatted(int messageFormatType, S if (message.messageTrimmedToHighlight != null) { mess = message.messageTrimmedToHighlight; } - int w = getMeasuredWidth() - AndroidUtilities.dp(messagePaddingStart + 23 + 10); + int w = getMeasuredWidth() - dp(messagePaddingStart + 23 + 10); if (hasNameInMessage) { if (!TextUtils.isEmpty(messageNameString)) { w -= currentMessagePaint.measureText(messageNameString.toString()); @@ -5078,7 +5172,7 @@ public boolean onTouchEvent(MotionEvent event) { return true; } if (delegate == null || delegate.canClickButtonInside()) { - if (lastTopicMessageUnread && canvasButton != null && buttonLayout != null && dialogsType == DialogsActivity.DIALOGS_TYPE_DEFAULT && canvasButton.checkTouchEvent(event)) { + if (lastTopicMessageUnread && canvasButton != null && buttonLayout != null && (dialogsType == DialogsActivity.DIALOGS_TYPE_DEFAULT || dialogsType == DialogsActivity.DIALOGS_TYPE_FOLDER1 || dialogsType == DialogsActivity.DIALOGS_TYPE_FOLDER2) && canvasButton.checkTouchEvent(event)) { return true; } } @@ -5342,7 +5436,7 @@ private void formatTopicsNames(int currentAccount, MessageObject message, TLRPC. } if (lastTopicMessageUnread) { spannableStringBuilder.append(" "); - spannableStringBuilder.setSpan(new DialogCell.FixedWidthSpan(AndroidUtilities.dp(3)), spannableStringBuilder.length() - 1, spannableStringBuilder.length(), 0); + spannableStringBuilder.setSpan(new DialogCell.FixedWidthSpan(dp(3)), spannableStringBuilder.length() - 1, spannableStringBuilder.length(), 0); hasDivider = true; } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/DialogRadioCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/DialogRadioCell.java index c7da323eb63..61b9bc41453 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/DialogRadioCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/DialogRadioCell.java @@ -8,6 +8,8 @@ package org.telegram.ui.Cells; +import static org.telegram.messenger.AndroidUtilities.dp; + import android.animation.Animator; import android.animation.ObjectAnimator; import android.content.Context; @@ -15,6 +17,7 @@ import android.text.TextUtils; import android.util.TypedValue; import android.view.Gravity; +import android.view.View; import android.widget.FrameLayout; import android.widget.TextView; @@ -28,7 +31,10 @@ public class DialogRadioCell extends FrameLayout { + public int itemId; + private TextView textView; + private TextView valueTextView; private RadioButton radioButton; private boolean needDivider; @@ -53,8 +59,23 @@ public DialogRadioCell(Context context, boolean dialog) { textView.setGravity((LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.CENTER_VERTICAL); addView(textView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.TOP, LocaleController.isRTL ? 23 : 61, 0, LocaleController.isRTL ? 61 : 23, 0)); + valueTextView = new TextView(context); + if (dialog) { + valueTextView.setTextColor(Theme.getColor(Theme.key_dialogTextBlue2)); + } else { + valueTextView.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteValueText)); + } + valueTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16); + valueTextView.setLines(1); + valueTextView.setMaxLines(1); + valueTextView.setSingleLine(true); + valueTextView.setEllipsize(TextUtils.TruncateAt.END); + valueTextView.setGravity((LocaleController.isRTL ? Gravity.LEFT : Gravity.RIGHT) | Gravity.CENTER_VERTICAL); + valueTextView.setVisibility(View.GONE); + addView(valueTextView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.MATCH_PARENT, (LocaleController.isRTL ? Gravity.LEFT : Gravity.RIGHT) | Gravity.TOP, 23, 0, 23, 0)); + radioButton = new RadioButton(context); - radioButton.setSize(AndroidUtilities.dp(20)); + radioButton.setSize(dp(20)); if (dialog) { radioButton.setColor(Theme.getColor(Theme.key_dialogRadioBackground), Theme.getColor(Theme.key_dialogRadioBackgroundChecked)); } else { @@ -65,10 +86,14 @@ public DialogRadioCell(Context context, boolean dialog) { @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec), AndroidUtilities.dp(50) + (needDivider ? 1 : 0)); + setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec), dp(50) + (needDivider ? 1 : 0)); - int availableWidth = getMeasuredWidth() - getPaddingLeft() - getPaddingRight() - AndroidUtilities.dp(34); - radioButton.measure(MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(22), MeasureSpec.AT_MOST), MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(22), MeasureSpec.EXACTLY)); + int availableWidth = getMeasuredWidth() - getPaddingLeft() - getPaddingRight() - dp(61 + 23 + (valueTextView.getVisibility() == View.VISIBLE ? 12 : 0)); + radioButton.measure(MeasureSpec.makeMeasureSpec(dp(22), MeasureSpec.AT_MOST), MeasureSpec.makeMeasureSpec(dp(22), MeasureSpec.EXACTLY)); + if (valueTextView.getVisibility() == View.VISIBLE) { + valueTextView.measure(MeasureSpec.makeMeasureSpec(availableWidth, MeasureSpec.AT_MOST), MeasureSpec.makeMeasureSpec(getMeasuredHeight(), MeasureSpec.EXACTLY)); + availableWidth -= valueTextView.getMeasuredWidth() + dp(12); + } textView.measure(MeasureSpec.makeMeasureSpec(availableWidth, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(getMeasuredHeight(), MeasureSpec.EXACTLY)); } @@ -76,7 +101,17 @@ public void setTextColor(int color) { textView.setTextColor(color); } - public void setText(String text, boolean checked, boolean divider) { + public void setText(CharSequence text, boolean checked, boolean divider) { + valueTextView.setVisibility(View.GONE); + textView.setText(text); + radioButton.setChecked(checked, false); + needDivider = divider; + setWillNotDraw(!divider); + } + + public void setTextAndValue(CharSequence text, CharSequence value, boolean checked, boolean divider) { + valueTextView.setVisibility(View.VISIBLE); + valueTextView.setText(value); textView.setText(text); radioButton.setChecked(checked, false); needDivider = divider; @@ -91,12 +126,27 @@ public void setChecked(boolean checked, boolean animated) { radioButton.setChecked(checked, animated); } - public void setEnabled(boolean value, ArrayList animators) { + public void setEnabled(boolean value, boolean animated) { + super.setEnabled(value); + if (animated) { + textView.animate().alpha(value ? 1.0f : 0.5f).start(); + valueTextView.animate().alpha(value ? 1.0f : 0.5f).start(); + radioButton.animate().alpha(value ? 1.0f : 0.5f).start(); + } else { + textView.setAlpha(value ? 1.0f : 0.5f); + valueTextView.setAlpha(value ? 1.0f : 0.5f); + radioButton.setAlpha(value ? 1.0f : 0.5f); + } + } + + public void setEnabled(boolean value, ArrayList animators) { if (animators != null) { animators.add(ObjectAnimator.ofFloat(textView, "alpha", value ? 1.0f : 0.5f)); + animators.add(ObjectAnimator.ofFloat(valueTextView, "alpha", value ? 1.0f : 0.5f)); animators.add(ObjectAnimator.ofFloat(radioButton, "alpha", value ? 1.0f : 0.5f)); } else { textView.setAlpha(value ? 1.0f : 0.5f); + valueTextView.setAlpha(value ? 1.0f : 0.5f); radioButton.setAlpha(value ? 1.0f : 0.5f); } } @@ -104,7 +154,7 @@ public void setEnabled(boolean value, ArrayList animators) { @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); + canvas.drawLine(dp(LocaleController.isRTL ? 0 : 60), getHeight() - 1, getMeasuredWidth() - dp(LocaleController.isRTL ? 60 : 0), getHeight() - 1, Theme.dividerPaint); } } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/DrawerActionCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/DrawerActionCell.java index d1f96e747f6..e3c1169f2b7 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/DrawerActionCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/DrawerActionCell.java @@ -49,6 +49,7 @@ public class DrawerActionCell extends FrameLayout { private TextView textView; private int currentId; private RectF rect = new RectF(); + private boolean currentError; public DrawerActionCell(Context context) { super(context); @@ -71,23 +72,26 @@ public DrawerActionCell(Context context) { protected void onDraw(Canvas canvas) { super.onDraw(canvas); - if (currentId == 8) { + boolean redError = currentError; + boolean error = currentError; + if (!error && currentId == 8) { Set suggestions = MessagesController.getInstance(UserConfig.selectedAccount).pendingSuggestions; - if (suggestions.contains("VALIDATE_PHONE_NUMBER") || suggestions.contains("VALIDATE_PASSWORD")) { - int countTop = AndroidUtilities.dp(12.5f); - int countWidth = AndroidUtilities.dp(9); - int countLeft = getMeasuredWidth() - countWidth - AndroidUtilities.dp(25); - - int x = countLeft - AndroidUtilities.dp(5.5f); - rect.set(x, countTop, x + countWidth + AndroidUtilities.dp(14), countTop + AndroidUtilities.dp(23)); - Theme.chat_docBackPaint.setColor(Theme.getColor(Theme.key_chats_archiveBackground)); - canvas.drawRoundRect(rect, 11.5f * AndroidUtilities.density, 11.5f * AndroidUtilities.density, Theme.chat_docBackPaint); - - int w = Theme.dialogs_errorDrawable.getIntrinsicWidth(); - int h = Theme.dialogs_errorDrawable.getIntrinsicHeight(); - Theme.dialogs_errorDrawable.setBounds((int) (rect.centerX() - w / 2), (int) (rect.centerY() - h / 2), (int) (rect.centerX() + w / 2), (int) (rect.centerY() + h / 2)); - Theme.dialogs_errorDrawable.draw(canvas); - } + error = suggestions.contains("VALIDATE_PHONE_NUMBER") || suggestions.contains("VALIDATE_PASSWORD"); + } + if (error) { + int countTop = AndroidUtilities.dp(12.5f); + int countWidth = AndroidUtilities.dp(9); + int countLeft = getMeasuredWidth() - countWidth - AndroidUtilities.dp(25); + + int x = countLeft - AndroidUtilities.dp(5.5f); + rect.set(x, countTop, x + countWidth + AndroidUtilities.dp(14), countTop + AndroidUtilities.dp(23)); + Theme.chat_docBackPaint.setColor(Theme.getColor(redError ? Theme.key_text_RedBold : Theme.key_chats_archiveBackground)); + canvas.drawRoundRect(rect, 11.5f * AndroidUtilities.density, 11.5f * AndroidUtilities.density, Theme.chat_docBackPaint); + + int w = Theme.dialogs_errorDrawable.getIntrinsicWidth(); + int h = Theme.dialogs_errorDrawable.getIntrinsicHeight(); + Theme.dialogs_errorDrawable.setBounds((int) (rect.centerX() - w / 2), (int) (rect.centerY() - h / 2), (int) (rect.centerX() + w / 2), (int) (rect.centerY() + h / 2)); + Theme.dialogs_errorDrawable.draw(canvas); } } @@ -112,6 +116,11 @@ public void setTextAndIcon(int id, String text, int resId) { } } + public void setError(boolean error) { + currentError = error; + invalidate(); + } + public void setTextAndIcon(int id, CharSequence text, int resId) { currentId = id; try { 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 33f62feffdd..0fe2edfd45f 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/DrawerProfileCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/DrawerProfileCell.java @@ -33,6 +33,7 @@ import android.widget.TextView; import androidx.annotation.NonNull; +import androidx.appcompat.app.AppCompatDelegate; import org.telegram.PhoneFormat.PhoneFormat; import org.telegram.messenger.AndroidUtilities; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/GroupCreateUserCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/GroupCreateUserCell.java index d3736c61773..81b91d121bf 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/GroupCreateUserCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/GroupCreateUserCell.java @@ -279,9 +279,15 @@ public void update(int mask) { case "non_contacts": avatarDrawable.setAvatarType(AvatarDrawable.AVATAR_TYPE_FILTER_NON_CONTACTS); break; + case "existing_chats": + avatarDrawable.setAvatarType(AvatarDrawable.AVATAR_TYPE_EXISTING_CHATS); + break; case "groups": avatarDrawable.setAvatarType(AvatarDrawable.AVATAR_TYPE_FILTER_GROUPS); break; + case "new_chats": + avatarDrawable.setAvatarType(AvatarDrawable.AVATAR_TYPE_NEW_CHATS); + break; case "channels": avatarDrawable.setAvatarType(AvatarDrawable.AVATAR_TYPE_FILTER_CHANNELS); break; 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 5e9c367bbc3..009fd0257d3 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/HeaderCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/HeaderCell.java @@ -32,6 +32,9 @@ public class HeaderCell extends FrameLayout { + protected int padding; + protected int bottomMargin; + private TextView textView; private SimpleTextView textView2; private int height = 40; @@ -64,10 +67,12 @@ public HeaderCell(Context context, int textColorKey, int padding, int topMargin, public HeaderCell(Context context, int textColorKey, int padding, int topMargin, int bottomMargin, boolean text2, Theme.ResourcesProvider resourcesProvider) { super(context); this.resourcesProvider = resourcesProvider; + this.padding = padding; + this.bottomMargin = bottomMargin; textView = new TextView(getContext()); textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 15); - textView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); + textView.setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)); textView.setEllipsize(TextUtils.TruncateAt.END); textView.setGravity((LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.CENTER_VERTICAL); textView.setMinHeight(AndroidUtilities.dp(height - topMargin)); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/InviteUserCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/InviteUserCell.java index 2ac0b085242..fb6950778f9 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/InviteUserCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/InviteUserCell.java @@ -90,7 +90,8 @@ public void update(int mask) { } String newName = null; - avatarDrawable.setInfo(currentContact.contact_id, currentContact.first_name, currentContact.last_name); + avatarDrawable.setInfo(currentContact.contact_id, currentContact.first_name, currentContact.last_name, null, null, null, true); + if (currentName != null) { nameTextView.setText(currentName, true); 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 01797c4ddba..4de63242844 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/NotificationsCheckCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/NotificationsCheckCell.java @@ -117,19 +117,19 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { } } - public void setTextAndValueAndCheck(String text, CharSequence value, boolean checked, boolean divider) { + public void setTextAndValueAndCheck(CharSequence text, CharSequence value, boolean checked, boolean divider) { setTextAndValueAndCheck(text, value, checked, 0, false, divider); } - public void setTextAndValueAndCheck(String text, CharSequence value, boolean checked, int iconType, boolean divider) { + public void setTextAndValueAndCheck(CharSequence text, CharSequence value, boolean checked, int iconType, boolean divider) { setTextAndValueAndCheck(text, value, checked, iconType, false, divider); } - public void setTextAndValueAndCheck(String text, CharSequence value, boolean checked, int iconType, boolean multiline, boolean divider) { + public void setTextAndValueAndCheck(CharSequence text, CharSequence value, boolean checked, int iconType, boolean multiline, boolean divider) { setTextAndValueAndIconAndCheck(text, value, 0, checked, iconType, multiline, divider); } - public void setTextAndValueAndIconAndCheck(String text, CharSequence value, int iconResId, boolean checked, int iconType, boolean multiline, boolean divider) { + public void setTextAndValueAndIconAndCheck(CharSequence text, CharSequence value, int iconResId, boolean checked, int iconType, boolean multiline, boolean divider) { textView.setText(text); valueTextView.setText(value); if (imageView != null) { @@ -139,6 +139,11 @@ public void setTextAndValueAndIconAndCheck(String text, CharSequence value, int checkBox.setChecked(checked, iconType, animationsEnabled); valueTextView.setVisibility(VISIBLE); needDivider = divider; + setMultiline(multiline); + checkBox.setContentDescription(text); + } + + public void setMultiline(boolean multiline) { isMultiline = multiline; if (multiline) { valueTextView.setLines(0); @@ -153,7 +158,10 @@ public void setTextAndValueAndIconAndCheck(String text, CharSequence value, int valueTextView.setEllipsize(TextUtils.TruncateAt.END); valueTextView.setPadding(0, 0, 0, 0); } - checkBox.setContentDescription(text); + } + + public void setValue(CharSequence value) { + valueTextView.setText(value); } public void setDrawLine(boolean value) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/RadioCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/RadioCell.java index 70f5b0c5cd3..11dfa01a073 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/RadioCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/RadioCell.java @@ -93,7 +93,7 @@ public void setTextColor(int color) { textView.setTextColor(color); } - public void setText(String text, boolean checked, boolean divider) { + public void setText(CharSequence text, boolean checked, boolean divider) { textView.setText(text); radioButton.setChecked(checked, false); needDivider = divider; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/SharingLiveLocationCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/SharingLiveLocationCell.java index 81ef27e448c..bb74a15586c 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/SharingLiveLocationCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/SharingLiveLocationCell.java @@ -8,6 +8,8 @@ package org.telegram.ui.Cells; +import static org.telegram.messenger.AndroidUtilities.dp; + import android.content.Context; import android.graphics.Canvas; import android.graphics.PorterDuff; @@ -17,11 +19,15 @@ import android.location.Address; import android.location.Geocoder; import android.location.Location; +import android.text.Layout; import android.text.SpannableString; import android.text.Spanned; +import android.text.StaticLayout; import android.text.TextUtils; +import android.util.TypedValue; import android.view.Gravity; import android.widget.FrameLayout; +import android.widget.TextView; import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.ApplicationLoader; @@ -56,9 +62,12 @@ public class SharingLiveLocationCell extends FrameLayout { private BackupImageView avatarImageView; private SimpleTextView nameTextView; - private SimpleTextView distanceTextView; + private int distanceTextViewHeight; + private TextView distanceTextView; + private boolean distanceTextViewSingle; private AvatarDrawable avatarDrawable; + private int padding; private RectF rect = new RectF(); private LocationController.SharingLocationInfo currentInfo; @@ -79,9 +88,10 @@ public void run() { public SharingLiveLocationCell(Context context, boolean distance, int padding, Theme.ResourcesProvider resourcesProvider) { super(context); this.resourcesProvider = resourcesProvider; + this.padding = padding; avatarImageView = new BackupImageView(context); - avatarImageView.setRoundRadius(AndroidUtilities.dp(21)); + avatarImageView.setRoundRadius(dp(21)); avatarDrawable = new AvatarDrawable(); @@ -97,12 +107,14 @@ public SharingLiveLocationCell(Context context, boolean distance, int padding, T addView(avatarImageView, LayoutHelper.createFrame(42, 42, Gravity.TOP | (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT), LocaleController.isRTL ? 0 : 15, 12, LocaleController.isRTL ? 15 : 0, 0)); addView(nameTextView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 20, Gravity.TOP | (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT), LocaleController.isRTL ? padding : 73, 12, LocaleController.isRTL ? 73 : 16, 0)); - distanceTextView = new SimpleTextView(context); - distanceTextView.setTextSize(14); + distanceTextView = new TextView(context); + distanceTextView.setSingleLine(); + distanceTextViewSingle = true; + distanceTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); distanceTextView.setTextColor(getThemedColor(Theme.key_windowBackgroundWhiteGrayText3)); distanceTextView.setGravity(LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT); - addView(distanceTextView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 20, Gravity.TOP | (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT), LocaleController.isRTL ? padding : 73, 37, LocaleController.isRTL ? 73 : padding, 0)); + addView(distanceTextView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.TOP | (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT), LocaleController.isRTL ? padding : 73, 37, LocaleController.isRTL ? 73 : padding, 0)); } else { addView(avatarImageView, LayoutHelper.createFrame(42, 42, Gravity.TOP | (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT), LocaleController.isRTL ? 0 : 15, 6, LocaleController.isRTL ? 15 : 0, 0)); addView(nameTextView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.TOP | (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT), LocaleController.isRTL ? padding : 74, 17, LocaleController.isRTL ? 74 : padding, 0)); @@ -113,7 +125,10 @@ public SharingLiveLocationCell(Context context, boolean distance, int padding, T @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - super.onMeasure(MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(distanceTextView != null ? 66 : 54), MeasureSpec.EXACTLY)); + super.onMeasure( + MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.EXACTLY), + MeasureSpec.makeMeasureSpec(dp(distanceTextView != null ? 66 : 54) + (distanceTextView != null && !distanceTextViewSingle ? -dp(20) + distanceTextViewHeight : 0), MeasureSpec.EXACTLY) + ); } @Override @@ -152,6 +167,7 @@ public void setDialog(long dialogId, TLRPC.TL_channelLocation chatLocation) { location.setLatitude(chatLocation.geo_point.lat); location.setLongitude(chatLocation.geo_point._long); + distanceTextView.setSingleLine(distanceTextViewSingle = true); distanceTextView.setText(address); } @@ -216,6 +232,27 @@ private CharSequence getName(double lat, double _long) { public void setDialog(MessageObject messageObject, Location userLocation, boolean userLocationDenied) { + if (messageObject != null && messageObject.messageOwner != null && messageObject.messageOwner.local_id == -1) { + Drawable drawable = getResources().getDrawable(R.drawable.pin); + drawable.setColorFilter(new PorterDuffColorFilter(getThemedColor(Theme.key_location_sendLocationIcon), PorterDuff.Mode.MULTIPLY)); + int color = getThemedColor(Theme.key_location_placeLocationBackground); + Drawable circle = Theme.createSimpleSelectorCircleDrawable(dp(42), color, color); + CombinedDrawable combinedDrawable = new CombinedDrawable(circle, drawable); + combinedDrawable.setCustomSize(dp(42), dp(42)); + combinedDrawable.setIconSize(dp(24), dp(24)); + avatarImageView.setImageDrawable(combinedDrawable); + + nameTextView.setText(Emoji.replaceEmoji(MessagesController.getInstance(currentAccount).getPeerName(DialogObject.getPeerDialogId(messageObject.messageOwner.peer_id)), nameTextView.getPaint().getFontMetricsInt(), false)); + distanceTextView.setSingleLine(distanceTextViewSingle = false); + String text = messageObject.messageOwner.media.address; + distanceTextViewHeight = new StaticLayout(text, distanceTextView.getPaint(), AndroidUtilities.displaySize.x - dp(padding + 73), Layout.Alignment.ALIGN_NORMAL, 1f, 0f, false).getHeight(); + distanceTextView.setText(text); + requestLayout(); + + return; + } else { + distanceTextView.setSingleLine(distanceTextViewSingle = true); + } long fromId = messageObject.getFromChatId(); if (messageObject.isForwarded()) { fromId = MessageObject.getPeerId(messageObject.messageOwner.fwd_from.from_id); @@ -257,7 +294,7 @@ public void setDialog(MessageObject messageObject, Location userLocation, boolea if (TextUtils.isEmpty(name)) { if (loadingString == null) { loadingString = new SpannableString("dkaraush has been here"); - loadingString.setSpan(new LoadingSpan(nameTextView, AndroidUtilities.dp(100), 0, resourcesProvider), 0, loadingString.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + loadingString.setSpan(new LoadingSpan(nameTextView, dp(100), 0, resourcesProvider), 0, loadingString.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); } name = loadingString; } @@ -269,10 +306,10 @@ public void setDialog(MessageObject messageObject, Location userLocation, boolea Drawable drawable = getResources().getDrawable(R.drawable.pin); drawable.setColorFilter(new PorterDuffColorFilter(getThemedColor(Theme.key_location_sendLocationIcon), PorterDuff.Mode.MULTIPLY)); int color = getThemedColor(Theme.key_location_placeLocationBackground); - Drawable circle = Theme.createSimpleSelectorCircleDrawable(AndroidUtilities.dp(42), color, color); + Drawable circle = Theme.createSimpleSelectorCircleDrawable(dp(42), color, color); CombinedDrawable combinedDrawable = new CombinedDrawable(circle, drawable); - combinedDrawable.setCustomSize(AndroidUtilities.dp(42), AndroidUtilities.dp(42)); - combinedDrawable.setIconSize(AndroidUtilities.dp(24), AndroidUtilities.dp(24)); + combinedDrawable.setCustomSize(dp(42), dp(42)); + combinedDrawable.setIconSize(dp(24), dp(24)); avatarImageView.setImageDrawable(combinedDrawable); } nameTextView.setText(name); @@ -368,9 +405,9 @@ protected void onDraw(Canvas canvas) { } float progress = Math.abs(stopTime - currentTime) / (float) period; if (LocaleController.isRTL) { - rect.set(AndroidUtilities.dp(13), AndroidUtilities.dp(distanceTextView != null ? 18 : 12), AndroidUtilities.dp(43), AndroidUtilities.dp(distanceTextView != null ? 48 : 42)); + rect.set(dp(13), dp(distanceTextView != null ? 18 : 12), dp(43), dp(distanceTextView != null ? 48 : 42)); } else { - rect.set(getMeasuredWidth() - AndroidUtilities.dp(43), AndroidUtilities.dp(distanceTextView != null ? 18 : 12), getMeasuredWidth() - AndroidUtilities.dp(13), AndroidUtilities.dp(distanceTextView != null ? 48 : 42)); + rect.set(getMeasuredWidth() - dp(43), dp(distanceTextView != null ? 18 : 12), getMeasuredWidth() - dp(13), dp(distanceTextView != null ? 48 : 42)); } int color; @@ -388,7 +425,7 @@ protected void onDraw(Canvas canvas) { float size = Theme.chat_livePaint.measureText(text); - canvas.drawText(text, rect.centerX() - size / 2, AndroidUtilities.dp(distanceTextView != null ? 37 : 31), Theme.chat_livePaint); + canvas.drawText(text, rect.centerX() - size / 2, dp(distanceTextView != null ? 37 : 31), Theme.chat_livePaint); } private int getThemedColor(int key) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/TextCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/TextCell.java index 0534ebc7eae..19eeca4c942 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/TextCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/TextCell.java @@ -95,7 +95,7 @@ public TextCell(Context context, int left, boolean dialog, boolean needCheck, Th subtitleView.setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_NO); addView(subtitleView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.MATCH_PARENT)); - valueTextView = new AnimatedTextView(context, false, false, true); + valueTextView = new AnimatedTextView(context, false, true, true); valueTextView.setTextColor(Theme.getColor(dialog ? Theme.key_dialogTextBlue2 : Theme.key_windowBackgroundWhiteValueText, resourcesProvider)); valueTextView.setPadding(0, dp(18), 0, dp(18)); valueTextView.setTextSize(dp(16)); @@ -338,7 +338,7 @@ public void setTextAndColorfulIcon(CharSequence text, int resId, int color, bool } public void setTextAndIcon(String text, Drawable drawable, boolean divider) { - offsetFromImage = 68; + offsetFromImage = 71; imageLeft = 18; textView.setText(text); textView.setRightDrawable(null); @@ -365,11 +365,11 @@ public void setImageLeft(int imageLeft) { this.imageLeft = imageLeft; } - public void setTextAndValue(String text, String value, boolean divider) { + public void setTextAndValue(CharSequence text, CharSequence value, boolean divider) { setTextAndValue(text, value, false, divider); } - public void setTextAndValue(String text, String value, boolean animated, boolean divider) { + public void setTextAndValue(CharSequence text, CharSequence value, boolean animated, boolean divider) { imageLeft = 21; offsetFromImage = getOffsetFromImage(false); textView.setText(text); @@ -387,7 +387,7 @@ public void setTextAndValue(String text, String value, boolean animated, boolean } public void setValue(String value, boolean animated) { - valueTextView.setText(TextUtils.ellipsize(valueText = value, valueTextView.getPaint(), AndroidUtilities.displaySize.x / 2.5f, TextUtils.TruncateAt.END), animated); + valueTextView.setText(value == null ? "" : TextUtils.ellipsize(valueText = value, valueTextView.getPaint(), AndroidUtilities.displaySize.x / 2.5f, TextUtils.TruncateAt.END), animated); } public void setTextAndValueAndColorfulIcon(String text, CharSequence value, boolean animated, int resId, int color, boolean divider) { @@ -395,7 +395,7 @@ public void setTextAndValueAndColorfulIcon(String text, CharSequence value, bool offsetFromImage = getOffsetFromImage(false); textView.setText(text); textView.setRightDrawable(null); - valueTextView.setText(TextUtils.ellipsize(valueText = value, valueTextView.getPaint(), AndroidUtilities.displaySize.x / 2.5f, TextUtils.TruncateAt.END), animated); + valueTextView.setText(value == null ? "" : TextUtils.ellipsize(valueText = value, valueTextView.getPaint(), AndroidUtilities.displaySize.x / 2.5f, TextUtils.TruncateAt.END), animated); valueTextView.setVisibility(VISIBLE); valueSpoilersTextView.setVisibility(GONE); setColorfulIcon(color, resId); @@ -445,16 +445,16 @@ public void setTextAndSpoilersValueAndColorfulIcon(String text, CharSequence val } } - public void setTextAndValueAndIcon(String text, String value, int resId, boolean divider) { + public void setTextAndValueAndIcon(CharSequence text, CharSequence value, int resId, boolean divider) { setTextAndValueAndIcon(text, value, false, resId, divider); } - public void setTextAndValueAndIcon(CharSequence text, String value, boolean animated, int resId, boolean divider) { + public void setTextAndValueAndIcon(CharSequence text, CharSequence value, boolean animated, int resId, boolean divider) { imageLeft = 21; offsetFromImage = getOffsetFromImage(false); textView.setText(text); textView.setRightDrawable(null); - valueTextView.setText(TextUtils.ellipsize(valueText = value, valueTextView.getPaint(), AndroidUtilities.displaySize.x / 2.5f, TextUtils.TruncateAt.END), animated); + valueTextView.setText(value == null ? "" : TextUtils.ellipsize(valueText = value, valueTextView.getPaint(), AndroidUtilities.displaySize.x / 2.5f, TextUtils.TruncateAt.END), animated); valueTextView.setVisibility(VISIBLE); valueSpoilersTextView.setVisibility(GONE); valueImageView.setVisibility(GONE); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/TextCheckCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/TextCheckCell.java index a248222404e..e44c07a729c 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/TextCheckCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/TextCheckCell.java @@ -45,6 +45,8 @@ public class TextCheckCell extends FrameLayout { private boolean isAnimatingToThumbInsteadOfTouch; + public int itemId; + private TextView textView; private TextView valueTextView; private Switch checkBox; @@ -301,9 +303,11 @@ public boolean isChecked() { @Override public void setBackgroundColor(int color) { - clearAnimation(); - animatedColorBackground = 0; - super.setBackgroundColor(color); + if (animatedColorBackground != color) { + clearAnimation(); + animatedColorBackground = 0; + super.setBackgroundColor(color); + } } public void setBackgroundColorAnimated(boolean checked, int color) { @@ -325,8 +329,8 @@ public void setBackgroundColorAnimated(boolean checked, int color) { animator.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { - setBackgroundColor(animatedColorBackground); animatedColorBackground = 0; + setBackgroundColor(color); invalidate(); } }); 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 73cf4d61a40..10c9f0c0166 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/TextCheckCell2.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/TextCheckCell2.java @@ -152,7 +152,7 @@ public void setTextAndCheck(String text, boolean checked, boolean divider, boole setWillNotDraw(!divider); } - public void setTextAndValueAndCheck(String text, String value, boolean checked, boolean multiline, boolean divider) { + public void setTextAndValueAndCheck(CharSequence text, CharSequence value, boolean checked, boolean multiline, boolean divider) { textView.setText(text); valueTextView.setText(value); checkBox.setChecked(checked, false); 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 959f6dc6211..106f2a4b645 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/TextSelectionHelper.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/TextSelectionHelper.java @@ -20,8 +20,6 @@ import android.text.SpannableStringBuilder; import android.text.Spanned; import android.text.StaticLayout; -import android.text.TextUtils; -import android.util.Log; import android.util.SparseArray; import android.util.SparseIntArray; import android.util.TypedValue; @@ -60,6 +58,7 @@ import org.telegram.ui.ActionBar.Theme; import org.telegram.ui.ArticleViewer; import org.telegram.ui.Components.AnimatedEmojiSpan; +import org.telegram.ui.Components.CornerPath; import org.telegram.ui.Components.LayoutHelper; import org.telegram.ui.Components.RecyclerListView; import org.telegram.ui.RestrictedLanguagesSelectActivity; @@ -89,7 +88,7 @@ public abstract class TextSelectionHelper 0) { + TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(id); + if (user != null) { + String status; + if (user.bot) { + status = LocaleController.getString("Bot", R.string.Bot); + } else if (user.contact) { + status = LocaleController.getString("FilterContact", R.string.FilterContact); + } else { + status = LocaleController.getString("FilterNonContact", R.string.FilterNonContact); + } + setData(user, null, status, 0, divider); + } + } else { + TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(-id); + if (chat != null) { + String status; + if (chat.participants_count != 0) { + if (ChatObject.isChannelAndNotMegaGroup(chat)) { + status = LocaleController.formatPluralStringComma("Subscribers", chat.participants_count); + } else { + status = LocaleController.formatPluralStringComma("Members", chat.participants_count); + } + } else if (!ChatObject.isPublic(chat)) { + if (ChatObject.isChannel(chat) && !chat.megagroup) { + status = LocaleController.getString("ChannelPrivate", R.string.ChannelPrivate); + } else { + status = LocaleController.getString("MegaPrivate", R.string.MegaPrivate); + } + } else { + if (ChatObject.isChannel(chat) && !chat.megagroup) { + status = LocaleController.getString("ChannelPublic", R.string.ChannelPublic); + } else { + status = LocaleController.getString("MegaPublic", R.string.MegaPublic); + } + } + setData(chat, null, status, 0, divider); + } + } + } + + public void setCloseIcon(Runnable onClick) { + if (onClick == null) { + if (closeView != null) { + removeView(closeView); + closeView = null; + } + } else { + if (closeView == null) { + closeView = new ImageView(getContext()); + closeView.setScaleType(ImageView.ScaleType.CENTER); + ScaleStateListAnimator.apply(closeView); + closeView.setImageResource(R.drawable.ic_close_white); + closeView.setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_windowBackgroundWhiteGrayText3, resourcesProvider), PorterDuff.Mode.SRC_IN)); + closeView.setBackground(Theme.createSelectorDrawable(Theme.getColor(Theme.key_listSelector, resourcesProvider), Theme.RIPPLE_MASK_CIRCLE_AUTO)); + addView(closeView, LayoutHelper.createFrame(30, 30, (LocaleController.isRTL ? Gravity.LEFT : Gravity.RIGHT) | Gravity.CENTER_VERTICAL, LocaleController.isRTL ? 14 : 0, 0, LocaleController.isRTL ? 0 : 14, 0)); + } + closeView.setOnClickListener(v -> onClick.run()); + } + } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ChannelColorActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ChannelColorActivity.java index 47fb2d03748..5483884e145 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ChannelColorActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ChannelColorActivity.java @@ -143,11 +143,7 @@ public int minLevelRequired() { lvl = Math.max(lvl, getEmojiStatusLevelMin()); } if (!ChatThemeController.wallpaperEquals(currentWallpaper, selectedWallpaper)) { - if (!TextUtils.isEmpty(ChatThemeController.getWallpaperEmoticon(selectedWallpaper))) { - lvl = Math.max(lvl, getWallpaperLevelMin()); - } else { - lvl = Math.max(lvl, getCustomWallpaperLevelMin()); - } + lvl = Math.max(lvl, getWallpaperLevelMin()); } return lvl; } @@ -316,6 +312,10 @@ protected void createListView() { listView = new RecyclerListView(getContext(), resourceProvider); } + protected void openBoostDialog(int type) { + + } + @Override public View createView(Context context) { TLRPC.Chat chat = getMessagesController().getChat(-dialogId); @@ -389,10 +389,7 @@ public void onItemClick(int id) { if (position == packEmojiRow) { final int requiredLvl = getEmojiStickersLevelMin(); if (boostsStatus != null && boostsStatus.level < requiredLvl) { - LimitReachedBottomSheet limitReachedBottomSheet = new LimitReachedBottomSheet(this, getContext(), TYPE_BOOSTS_FOR_CUSTOM_EMOJI_PACK, currentAccount, getResourceProvider()); - limitReachedBottomSheet.setBoostsStats(boostsStatus, true); - limitReachedBottomSheet.setDialogId(dialogId); - showDialog(limitReachedBottomSheet); + openBoostDialog(TYPE_BOOSTS_FOR_CUSTOM_EMOJI_PACK); return; } GroupStickersActivity fragment = new GroupStickersActivity(-dialogId, true); @@ -1336,7 +1333,7 @@ public void setColor(int colorId, boolean animated) { addView(title, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.BOTTOM,72,0,0,16)); infoLayout = new LinearLayout(context); infoLayout.setOrientation(LinearLayout.HORIZONTAL); - infoLayout.setBackground(Theme.createSelectorWithBackgroundDrawable(Theme.multAlpha(Color.BLACK, 0.15f), Theme.multAlpha(Color.BLACK, 0.35f))); + infoLayout.setBackground(Theme.createSelectorWithBackgroundDrawable(Theme.multAlpha(Color.BLACK, 0.065f), Color.BLACK)); infoLayout.setGravity(Gravity.CENTER); infoLayout.setPadding(dp(4), dp(4), dp(4), dp(4)); textInfo1 = new TextView(context); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ChatActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ChatActivity.java index 6222492fe7b..61cfb7626cd 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ChatActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ChatActivity.java @@ -86,6 +86,7 @@ import android.view.ViewConfiguration; import android.view.ViewGroup; import android.view.ViewOutlineProvider; +import android.view.ViewPropertyAnimator; import android.view.ViewTreeObserver; import android.view.WindowManager; import android.view.accessibility.AccessibilityEvent; @@ -192,6 +193,9 @@ import org.telegram.ui.ActionBar.ThemeDescription; import org.telegram.ui.Adapters.FiltersView; import org.telegram.ui.Adapters.MessagesSearchAdapter; +import org.telegram.ui.Business.BusinessChatEmptyView; +import org.telegram.ui.Business.QuickRepliesActivity; +import org.telegram.ui.Business.QuickRepliesController; import org.telegram.ui.Cells.BotHelpCell; import org.telegram.ui.Cells.BotSwitchCell; import org.telegram.ui.Cells.ChatActionCell; @@ -333,6 +337,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not @Nullable private FrameLayout emptyViewContainer; private ChatGreetingsView greetingsViewContainer; + private BusinessChatEmptyView businessEmptyView; public ChatActivityFragmentView contentView; private ChatBigEmptyView bigEmptyView; private ArrayList actionModeViews = new ArrayList<>(); @@ -514,7 +519,9 @@ public ArrayList getFilteredMessages() { public static final int MODE_SCHEDULED = 1; public static final int MODE_PINNED = 2; public static final int MODE_SAVED = 3; + public static final int MODE_QUICK_REPLIES = 5; + public String quickReplyShortcut; private int chatMode; private int scheduledMessagesCount = -1; @@ -788,6 +795,7 @@ public int getColor(int key) { private MessageObject botReplyButtons; private int botsCount; private boolean hasBotsCommands; + private boolean hasQuickReplies; private boolean hasBotWebView; private long chatEnterTime; private long chatLeaveTime; @@ -989,7 +997,8 @@ public void run() { NotificationCenter.pinnedInfoDidLoad, NotificationCenter.didSetNewWallpapper, NotificationCenter.savedMessagesDialogsUpdate, - NotificationCenter.didApplyNewTheme + NotificationCenter.didApplyNewTheme, + NotificationCenter.messageReceivedByServer }; private final DialogInterface.OnCancelListener postponedScrollCancelListener = dialog -> { @@ -1108,7 +1117,11 @@ public void showHeaderItem(boolean show) { } public long getTopicId() { - return isTopic || chatMode == MODE_SAVED ? threadMessageId : 0L; + return isTopic || chatMode == MODE_SAVED || chatMode == MODE_QUICK_REPLIES ? threadMessageId : 0L; + } + + public int getQuickReplyId() { + return chatMode == MODE_QUICK_REPLIES ? (int) threadMessageId : 0; } public long getSavedDialogId() { @@ -1334,6 +1347,7 @@ public void sendButtonPressed(int index, VideoEditedInfo videoEditedInfo, boolea private final static int translate = 62; private final static int scheduled = 63; + private final static int edit_quick_reply = 64; private final static int id_chat_compose_panel = 1000; @@ -1493,6 +1507,10 @@ public void onItemClick(View view, int position, float x, float y) { presentFragment(calendarActivity); return; } + if (view instanceof ChatActionCell && ((ChatActionCell) view).getMessageObject() != null && ((ChatActionCell) view).getMessageObject().messageOwner.action instanceof TLRPC.TL_messageActionBoostApply) { + getNotificationCenter().postNotificationName(NotificationCenter.openBoostForUsersDialog, dialog_id); + return; + } if (view instanceof ChatActionCell && ((ChatActionCell) view).getMessageObject() != null && ((ChatActionCell) view).getMessageObject().messageOwner.action instanceof TLRPC.TL_messageActionSetSameChatWallPaper) { int messageId = ((ChatActionCell) view).getMessageObject().getReplyMsgId(); AndroidUtilities.runOnUIThread(() -> { @@ -1529,6 +1547,7 @@ public void onItemClick(View view, int position, float x, float y) { @Override public boolean hasDoubleTap(View view, int position) { + if (chatMode == MODE_QUICK_REPLIES) return false; String reactionStringSetting = getMediaDataController().getDoubleTapReaction(); TLRPC.TL_availableReaction reaction = getMediaDataController().getReactionsMap().get(reactionStringSetting); if (reaction == null && (reactionStringSetting == null || !reactionStringSetting.startsWith("animated_"))) { @@ -1547,7 +1566,7 @@ public boolean hasDoubleTap(View view, int position) { @Override public void onDoubleTap(View view, int position, float x, float y) { - if (!(view instanceof ChatMessageCell) || getParentActivity() == null || isSecretChat() || isInScheduleMode() || isInPreviewMode()) { + if (!(view instanceof ChatMessageCell) || getParentActivity() == null || isSecretChat() || isInScheduleMode() || isInPreviewMode() || chatMode == MODE_QUICK_REPLIES) { return; } ChatMessageCell cell = (ChatMessageCell) view; @@ -1867,6 +1886,7 @@ public void onTextSpansChanged(CharSequence text) { @Override public void needSendTyping() { + if (chatMode == MODE_QUICK_REPLIES) return; getMessagesController().sendTyping(dialog_id, threadMessageId, 0, classGuid); } @@ -2197,6 +2217,7 @@ public boolean onFragmentCreate() { dialogFolderId = arguments.getInt("dialog_folder_id", 0); dialogFilterId = arguments.getInt("dialog_filter_id", 0); chatMode = arguments.getInt("chatMode", 0); + quickReplyShortcut = arguments.getString("quick_reply", null); voiceChatHash = arguments.getString("voicechat", null); livestream = !TextUtils.isEmpty(arguments.getString("livestream", null)); attachMenuBotToOpen = arguments.getString("attach_bot", null); @@ -2222,6 +2243,12 @@ public boolean onFragmentCreate() { scrollToTopOnResume = arguments.getBoolean("scrollToTopOnResume", false); needRemovePreviousSameChatActivity = arguments.getBoolean("need_remove_previous_same_chat_activity", true); justCreatedChat = arguments.getBoolean("just_created_chat", false); + if (quickReplyShortcut != null) { + QuickRepliesController.QuickReply quickReply = QuickRepliesController.getInstance(currentAccount).findReply(quickReplyShortcut); + if (quickReply != null) { + setQuickReplyId(quickReply.id); + } + } if (chatId != 0) { currentChat = getMessagesController().getChat(chatId); @@ -2287,6 +2314,11 @@ public boolean onFragmentCreate() { botUser = null; premiumInvoiceBot = false; } + hasQuickReplies = false; + if (currentUser != null && chatMode == 0 && !currentUser.bot) { + QuickRepliesController.getInstance(currentAccount).load(); +// hasQuickReplies = QuickRepliesController.getInstance(currentAccount).hasReplies(); + } } else if (encId != 0) { currentEncryptedChat = getMessagesController().getEncryptedChat(encId); final MessagesStorage messagesStorage = getMessagesStorage(); @@ -2443,6 +2475,8 @@ public boolean onFragmentCreate() { getNotificationCenter().addObserver(this, NotificationCenter.channelRecommendationsLoaded); getNotificationCenter().addObserver(this, NotificationCenter.updateTranscriptionLock); getNotificationCenter().addObserver(this, NotificationCenter.savedMessagesDialogsUpdate); + getNotificationCenter().addObserver(this, NotificationCenter.quickRepliesDeleted); + getNotificationCenter().addObserver(this, NotificationCenter.quickRepliesUpdated); if (actionBarSearchTags != null) { actionBarSearchTags.attach(); } @@ -2824,6 +2858,8 @@ public void onFragmentDestroy() { getNotificationCenter().removeObserver(this, NotificationCenter.channelRecommendationsLoaded); getNotificationCenter().removeObserver(this, NotificationCenter.updateTranscriptionLock); getNotificationCenter().removeObserver(this, NotificationCenter.savedMessagesDialogsUpdate); + getNotificationCenter().removeObserver(this, NotificationCenter.quickRepliesDeleted); + getNotificationCenter().removeObserver(this, NotificationCenter.quickRepliesUpdated); if (actionBarSearchTags != null) { actionBarSearchTags.detach(); } @@ -3061,6 +3097,10 @@ public void onItemClick(final int id) { if (actionBar.isActionModeShowed()) { clearSelectionMode(); } else { + if (chatMode == MODE_QUICK_REPLIES && (messages.isEmpty() || threadMessageId == 0)) { + showQuickRepliesRemoveAlert(); + return; + } if (!checkRecordLocked(true)) { finishFragment(); } @@ -3196,7 +3236,7 @@ public void run(boolean revoke) { toggleMute(false); } else if (id == add_shortcut) { try { - getMediaDataController().installShortcut(currentUser.id); + getMediaDataController().installShortcut(currentUser.id, MediaDataController.SHORTCUT_TYPE_USER_OR_CHAT); } catch (Exception e) { FileLog.e(e); } @@ -3236,6 +3276,15 @@ public void run(boolean revoke) { hideActionMode(); updatePinnedMessageView(true); updateVisibleRows(); + } else if (id == edit_quick_reply) { + QuickRepliesController.QuickReply currentQuickReply = QuickRepliesController.getInstance(currentAccount).findReply(getQuickReplyId()); + QuickRepliesActivity.openRenameReplyAlert(getContext(), currentAccount, quickReplyShortcut, currentQuickReply, getResourceProvider(), false, name -> { + if (currentQuickReply != null) { + QuickRepliesController.getInstance(currentAccount).renameReply(currentQuickReply.id, name); + } + quickReplyShortcut = name; + avatarContainer.setTitle(name); + }); } else if (id == chat_menu_attach) { ActionBarMenuSubItem attach = new ActionBarMenuSubItem(context, false, true, true, getResourceProvider()); attach.setTextAndIcon(LocaleController.getString(R.string.AttachMenu), R.drawable.input_attach); @@ -3389,7 +3438,7 @@ protected void openSearch() { }; avatarContainer.allowShorterStatus = true; avatarContainer.premiumIconHiddable = true; - avatarContainer.allowDrawStories = dialog_id < 0; + avatarContainer.allowDrawStories = dialog_id < 0 && !isTopic; avatarContainer.setClipChildren(false); AndroidUtilities.updateViewVisibilityAnimated(avatarContainer, true, 1f, false); updateTopicTitleIcon(); @@ -3466,6 +3515,10 @@ protected void openSearch() { ActionBarMenu menu = actionBar.createMenu(); + if (chatMode == MODE_QUICK_REPLIES && !QuickRepliesController.isSpecial(quickReplyShortcut)) { + menu.addItem(edit_quick_reply, R.drawable.group_edit).setContentDescription(LocaleController.getString(R.string.Edit)); + } + if (currentEncryptedChat == null && (chatMode == 0 || chatMode == MODE_SAVED) && reportType < 0) { searchIconItem = menu.addItem(search, isSupportedTags() ? R.drawable.navbar_search_tag : R.drawable.ic_ab_search); searchIconItem.setContentDescription(LocaleController.getString("Search", R.string.Search)); @@ -3613,9 +3666,9 @@ public void toggleMute() { if (searchItem != null) { headerItem.lazilyAddSubItem(search, R.drawable.msg_search, LocaleController.getString(R.string.Search)); } - if (ChatObject.isGroupAndSupportBoost(currentChat) && (getUserConfig().isPremium() || ChatObject.isBoosted(chatInfo) || ChatObject.hasAdminRights(currentChat))) { + if (ChatObject.isBoostSupported(currentChat) && (getUserConfig().isPremium() || ChatObject.isBoosted(chatInfo) || ChatObject.hasAdminRights(currentChat))) { RLottieDrawable drawable = new RLottieDrawable(R.raw.boosts, "" + R.raw.boosts, dp(24), dp(24)); - headerItem.lazilyAddSubItem(boost_group, drawable, TextCell.applyNewSpan(LocaleController.getString("BoostingBoostGroupMenu", R.string.BoostingBoostGroupMenu))); + headerItem.lazilyAddSubItem(boost_group, drawable, TextCell.applyNewSpan(LocaleController.getString(ChatObject.isChannelAndNotMegaGroup(currentChat) ? R.string.BoostingBoostChannelMenu : R.string.BoostingBoostGroupMenu))); } translateItem = headerItem.lazilyAddSubItem(translate, R.drawable.msg_translate, LocaleController.getString("TranslateMessage", R.string.TranslateMessage)); updateTranslateItemVisibility(); @@ -4115,12 +4168,18 @@ private void processTouchEvent(MotionEvent e) { slidingView = (ChatMessageCell) view; MessageObject message = slidingView.getMessageObject(); boolean allowReplyOnOpenTopic = canSendMessageToTopic(message); - if (chatMode != 0 && (chatMode != MODE_SAVED || threadMessageId != getUserConfig().getClientUserId()) || threadMessageObjects != null && threadMessageObjects.contains(message) || + if ( + chatMode != 0 && chatMode != MODE_QUICK_REPLIES && (chatMode != MODE_SAVED || threadMessageId != getUserConfig().getClientUserId()) || + threadMessageObjects != null && threadMessageObjects.contains(message) || getMessageType(message) == 1 && (message.getDialogId() == mergeDialogId || message.needDrawBluredPreview()) || currentEncryptedChat == null && message.getId() < 0 || bottomOverlayChat != null && bottomOverlayChat.getVisibility() == View.VISIBLE && !(bottomOverlayChatWaitsReply && allowReplyOnOpenTopic || message.wasJustSent) || - currentChat != null && (ChatObject.isNotInChat(currentChat) && !isThreadChat() || ChatObject.isChannel(currentChat) && !ChatObject.canPost(currentChat) && !currentChat.megagroup || !ChatObject.canSendMessages(currentChat) || (ChatObject.isForum(currentChat) && !allowReplyOnOpenTopic)) || - textSelectionHelper.isInSelectionMode()) { + currentChat != null && (ChatObject.isNotInChat(currentChat) && !isThreadChat() || + ChatObject.isChannel(currentChat) && !ChatObject.canPost(currentChat) && !currentChat.megagroup || + !ChatObject.canSendMessages(currentChat) || + (ChatObject.isForum(currentChat) && !allowReplyOnOpenTopic)) || + textSelectionHelper.isInSelectionMode() + ) { slidingView.setSlidingOffset(0); slidingView = null; return; @@ -6269,7 +6328,19 @@ public long getDialogId() { Object object = mentionContainer.getAdapter().getItem(position); int start = mentionContainer.getAdapter().getResultStartPosition(); int len = mentionContainer.getAdapter().getResultLength(); - if (object instanceof TLRPC.TL_document) { + if (object instanceof QuickRepliesController.QuickReply) { + if (!getUserConfig().isPremium()) { + showDialog(new PremiumFeatureBottomSheet(this, getContext(), currentAccount, true, PremiumPreviewFragment.PREMIUM_FEATURE_BUSINESS_QUICK_REPLIES, false, null)); + return; + } + TLRPC.TL_messages_sendQuickReplyMessages req = new TLRPC.TL_messages_sendQuickReplyMessages(); + req.peer = getMessagesController().getInputPeer(dialog_id); + req.shortcut_id = ((QuickRepliesController.QuickReply) object).id; + getConnectionsManager().sendRequest(req, null); + if (chatActivityEnterView != null) { + chatActivityEnterView.setFieldText(null); + } + } else if (object instanceof TLRPC.TL_document) { if (chatMode == 0 && checkSlowMode(view)) { return; } @@ -6281,9 +6352,9 @@ public long getDialogId() { Object parent = mentionContainer.getAdapter().getItemParent(position); String query = MessageObject.findAnimatedEmojiEmoticon(document); if (chatMode == MODE_SCHEDULED) { - AlertsCreator.createScheduleDatePickerDialog(getParentActivity(), dialog_id, (notify, scheduleDate) -> SendMessagesHelper.getInstance(currentAccount).sendSticker(document, query, dialog_id, replyingMessageObject, getThreadMessage(), null, replyingQuote, null, notify, scheduleDate, false, parent), themeDelegate); + AlertsCreator.createScheduleDatePickerDialog(getParentActivity(), dialog_id, (notify, scheduleDate) -> SendMessagesHelper.getInstance(currentAccount).sendSticker(document, query, dialog_id, replyingMessageObject, getThreadMessage(), null, replyingQuote, null, notify, scheduleDate, false, parent, quickReplyShortcut, getQuickReplyId()), themeDelegate); } else { - getSendMessagesHelper().sendSticker(document, query, dialog_id, replyingMessageObject, getThreadMessage(), null, replyingQuote, sendAnimationData, true, 0, false, parent); + getSendMessagesHelper().sendSticker(document, query, dialog_id, replyingMessageObject, getThreadMessage(), null, replyingQuote, sendAnimationData, true, 0, false, parent, quickReplyShortcut, getQuickReplyId()); } hideFieldPanel(false); chatActivityEnterView.addStickerToRecent(document); @@ -6324,7 +6395,10 @@ public long getDialogId() { if (checkSlowMode(view)) { return; } - getSendMessagesHelper().sendMessage(SendMessagesHelper.SendMessageParams.of((String) object, dialog_id, replyingMessageObject, getThreadMessage(), null, false, null, null, null, true, 0, null, false)); + SendMessagesHelper.SendMessageParams params = SendMessagesHelper.SendMessageParams.of((String) object, dialog_id, replyingMessageObject, getThreadMessage(), null, false, null, null, null, true, 0, null, false); + params.quick_reply_shortcut = quickReplyShortcut; + params.quick_reply_shortcut_id = getQuickReplyId(); + getSendMessagesHelper().sendMessage(params); chatActivityEnterView.setFieldText(""); hideFieldPanel(false); } @@ -6855,7 +6929,7 @@ protected void onLineCountChanged(int oldLineCount, int newLineCount) { chatActivityEnterView.setChatInfo(chatInfo); } chatActivityEnterView.setId(id_chat_compose_panel); - chatActivityEnterView.setBotsCount(botsCount, hasBotsCommands, false); + chatActivityEnterView.setBotsCount(botsCount, hasBotsCommands, hasQuickReplies, false); chatActivityEnterView.updateBotWebView(false); chatActivityEnterView.setMinimumHeight(AndroidUtilities.dp(51)); chatActivityEnterView.setAllowStickersAndGifs(true, true, currentEncryptedChat == null || AndroidUtilities.getPeerLayerVersion(currentEncryptedChat.layer) >= 46); @@ -6934,7 +7008,7 @@ public void setVisibility(int visibility) { } else if (messagePreviewParams != null) { forbidForwardingWithDismiss = false; if (fieldPanelShown == 2) { - if (DialogObject.isEncryptedDialog(dialog_id) || messagePreviewParams.hasSecretMessages) { + if (DialogObject.isEncryptedDialog(dialog_id) || messagePreviewParams.hasSecretMessages || chatMode == MODE_QUICK_REPLIES) { if (replyingMessageObject != null) { scrollToMessageId(replyingMessageObject.getId(), 0, true, 0, true, 0); } @@ -7928,7 +8002,11 @@ private void putFilteredDate(int index, MessageObject baseMsg) { private void createHint2MessageObject() { if (hint2MessageObject != null) return; TLRPC.Message dateMsg = new TLRPC.TL_message(); - dateMsg.message = LocaleController.getString(R.string.SavedMessagesProfileHint); + if (chatMode == MODE_SAVED) { + dateMsg.message = LocaleController.getString(R.string.SavedMessagesProfileHint); + } else { + dateMsg.message = LocaleController.getString(R.string.BusinessRepliesHint); + } dateMsg.id = 0; hint2MessageObject = new MessageObject(currentAccount, dateMsg, false, false); hint2MessageObject.type = 10; @@ -8993,7 +9071,9 @@ private void checkEditTextItemMenu() { ActionBarMenuItem item = editTextItem.createView(); item.addSubItem(text_spoiler, LocaleController.getString("Spoiler", R.string.Spoiler)); - item.addSubItem(text_quote, LocaleController.getString("Quote", R.string.Quote)); + if (chatMode == 0) { + item.addSubItem(text_quote, LocaleController.getString("Quote", R.string.Quote)); + } SpannableStringBuilder stringBuilder = new SpannableStringBuilder(LocaleController.getString("Bold", R.string.Bold)); stringBuilder.setSpan(new TypefaceSpan(AndroidUtilities.getTypeface("fonts/rmedium.ttf")), 0, stringBuilder.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); item.addSubItem(text_bold, stringBuilder); @@ -10593,7 +10673,7 @@ private void sendBotInlineResult(TLRPC.BotInlineResult result, boolean notify, i params.put("query_id", "" + result.query_id); params.put("bot", "" + uid); params.put("bot_name", mentionContainer.getAdapter().getContextBotName()); - SendMessagesHelper.prepareSendingBotContextResult(this, getAccountInstance(), result, params, dialog_id, replyingMessageObject, getThreadMessage(), null, replyingQuote, notify, scheduleDate); + SendMessagesHelper.prepareSendingBotContextResult(this, getAccountInstance(), result, params, dialog_id, replyingMessageObject, getThreadMessage(), null, replyingQuote, notify, scheduleDate, quickReplyShortcut, getQuickReplyId()); chatActivityEnterView.setFieldText(""); hideFieldPanel(false); getMediaDataController().increaseInlineRaiting(uid); @@ -10797,7 +10877,7 @@ public void didPressedButton(int button, boolean arg, boolean notify, int schedu fillEditingMediaWithCaption(photos.get(0).caption, photos.get(0).entities); updateStickersOrder = photos.get(0).updateStickersOrder; } - SendMessagesHelper.prepareSendingMedia(getAccountInstance(), photos, dialog_id, replyingMessageObject, getThreadMessage(), null, replyingQuote, button == 4 || forceDocument, arg, editingMessageObject, notify, scheduleDate, updateStickersOrder, null); + SendMessagesHelper.prepareSendingMedia(getAccountInstance(), photos, dialog_id, replyingMessageObject, getThreadMessage(), null, replyingQuote, button == 4 || forceDocument, arg, editingMessageObject, notify, scheduleDate, chatMode, updateStickersOrder, null, quickReplyShortcut, getQuickReplyId()); } afterMessageSend(); chatActivityEnterView.setFieldText(""); @@ -11090,7 +11170,10 @@ public void shareMyContact(int type, MessageObject messageObject) { getMessagesController().processUpdates((TLRPC.Updates) response, false); }); } else { - SendMessagesHelper.getInstance(currentAccount).sendMessage(SendMessagesHelper.SendMessageParams.of(getUserConfig().getCurrentUser(), dialog_id, messageObject, getThreadMessage(), null, null, true, 0)); + SendMessagesHelper.SendMessageParams params = SendMessagesHelper.SendMessageParams.of(getUserConfig().getCurrentUser(), dialog_id, messageObject, getThreadMessage(), null, null, true, 0); + params.quick_reply_shortcut_id = getQuickReplyId(); + params.quick_reply_shortcut = quickReplyShortcut; + SendMessagesHelper.getInstance(currentAccount).sendMessage(params); if (chatMode == 0) { moveScrollToLastMessage(false); } @@ -11640,7 +11723,7 @@ private void openAttachMenu() { } private void showFloatingDateView(boolean scroll) { - if (floatingDateView == null) { + if (floatingDateView == null || chatMode == MODE_QUICK_REPLIES) { return; } if (floatingDateView.getTag() == null) { @@ -11907,7 +11990,10 @@ public void openPollCreate(Boolean quiz) { PollCreateActivity pollCreateActivity = new PollCreateActivity(ChatActivity.this, quiz); pollCreateActivity.setDelegate((poll, params, notify, scheduleDate) -> { if (checkSlowModeAlert()) { - getSendMessagesHelper().sendMessage(SendMessagesHelper.SendMessageParams.of(poll, dialog_id, replyingMessageObject, getThreadMessage(), null, params, notify, scheduleDate)); + SendMessagesHelper.SendMessageParams params2 = SendMessagesHelper.SendMessageParams.of(poll, dialog_id, replyingMessageObject, getThreadMessage(), null, params, notify, scheduleDate); + params2.quick_reply_shortcut = quickReplyShortcut; + params2.quick_reply_shortcut_id = getQuickReplyId(); + getSendMessagesHelper().sendMessage(params2); afterMessageSend(); } }); @@ -11919,11 +12005,14 @@ public void didSelectFiles(ArrayList files, String caption, ArrayList files, String caption, ArrayList photos, boolean notify, int scheduleDate) { fillEditingMediaWithCaption(photos.get(0).caption, photos.get(0).entities); - SendMessagesHelper.prepareSendingMedia(getAccountInstance(), photos, dialog_id, replyingMessageObject, getThreadMessage(), null, replyingQuote, true, false, editingMessageObject, notify, scheduleDate, photos.get(0).updateStickersOrder, null); + SendMessagesHelper.prepareSendingMedia(getAccountInstance(), photos, dialog_id, replyingMessageObject, getThreadMessage(), null, replyingQuote, true, false, editingMessageObject, notify, scheduleDate, chatMode, photos.get(0).updateStickersOrder, null, quickReplyShortcut, getQuickReplyId()); afterMessageSend(); if (scheduleDate != 0) { if (scheduledMessagesCount == -1) { @@ -11958,12 +12047,15 @@ public void didSelectSearchPhotos(ArrayList } } if (!hasNoGifs && !TextUtils.isEmpty(photos.get(0).caption)) { - SendMessagesHelper.getInstance(currentAccount).sendMessage(SendMessagesHelper.SendMessageParams.of(photos.get(0).caption, dialog_id, replyingMessageObject, getThreadMessage(), null, false, photos.get(0).entities, null, null, notify, scheduleDate, null, false)); + SendMessagesHelper.SendMessageParams params = SendMessagesHelper.SendMessageParams.of(photos.get(0).caption, dialog_id, replyingMessageObject, getThreadMessage(), null, false, photos.get(0).entities, null, null, notify, scheduleDate, null, false); + params.quick_reply_shortcut = quickReplyShortcut; + params.quick_reply_shortcut_id = getQuickReplyId(); + SendMessagesHelper.getInstance(currentAccount).sendMessage(params); } for (int a = 0; a < photos.size(); a++) { SendMessagesHelper.SendingMediaInfo info = photos.get(a); if (info.inlineResult != null && info.videoEditedInfo == null) { - SendMessagesHelper.prepareSendingBotContextResult(this, getAccountInstance(), info.inlineResult, info.params, dialog_id, replyingMessageObject, getThreadMessage(), null, replyingQuote, notify, scheduleDate); + SendMessagesHelper.prepareSendingBotContextResult(this, getAccountInstance(), info.inlineResult, info.params, dialog_id, replyingMessageObject, getThreadMessage(), null, replyingQuote, notify, scheduleDate, quickReplyShortcut, getQuickReplyId()); photos.remove(a); a--; } @@ -11972,7 +12064,7 @@ public void didSelectSearchPhotos(ArrayList return; } fillEditingMediaWithCaption(photos.get(0).caption, photos.get(0).entities); - SendMessagesHelper.prepareSendingMedia(getAccountInstance(), photos, dialog_id, replyingMessageObject, getThreadMessage(), null, replyingQuote, false, true, editingMessageObject, notify, scheduleDate, photos.get(0).updateStickersOrder, null); + SendMessagesHelper.prepareSendingMedia(getAccountInstance(), photos, dialog_id, replyingMessageObject, getThreadMessage(), null, replyingQuote, false, true, editingMessageObject, notify, scheduleDate, chatMode, photos.get(0).updateStickersOrder, null, quickReplyShortcut, getQuickReplyId()); afterMessageSend(); if (scheduleDate != 0) { if (scheduledMessagesCount == -1) { @@ -12748,7 +12840,7 @@ public void showFieldPanel(boolean show, MessageObject messageObjectToReply, Mes replyIconImageView.setImageResource(R.drawable.filled_reply_quote); nameText = AndroidUtilities.replaceCharSequence("%s", LocaleController.getString(R.string.ReplyToQuote), name == null ? "" : name); } else { - if (messagePreviewParams == null || messagePreviewParams.hasSecretMessages) { + if (messagePreviewParams == null || messagePreviewParams.hasSecretMessages || chatMode == MODE_QUICK_REPLIES) { replyIconImageView.setImageResource(R.drawable.ic_ab_reply); } else { replyIconImageView.setImageResource(R.drawable.filled_reply_settings); @@ -13822,6 +13914,9 @@ public void updateMessagesVisiblePart(boolean inLayout) { } else { floatingDateViewOffset = 0; } + if (chatMode == MODE_QUICK_REPLIES) { + showFloatingView = false; + } if (showFloatingView) { if (floatingDateAnimation != null) { floatingDateAnimation.cancel(); @@ -16687,7 +16782,15 @@ public void updateTitle(boolean animated) { if (avatarContainer == null) { return; } - if (chatMode == MODE_SAVED) { + if (chatMode == MODE_QUICK_REPLIES) { + if (QuickRepliesController.GREETING.equalsIgnoreCase(quickReplyShortcut)) { + avatarContainer.setTitle(LocaleController.getString(R.string.BusinessGreet)); + } else if (QuickRepliesController.AWAY.equalsIgnoreCase(quickReplyShortcut)) { + avatarContainer.setTitle(LocaleController.getString(R.string.BusinessAway)); + } else { + avatarContainer.setTitle(quickReplyShortcut); + } + } else if (chatMode == MODE_SAVED) { long dialogId = threadMessageId; TLRPC.User user = null; TLRPC.Chat chat = null; @@ -16893,7 +16996,7 @@ public boolean canCaptureMorePhotos() { }, this); } else { fillEditingMediaWithCaption(caption, null); - SendMessagesHelper.prepareSendingVideo(getAccountInstance(), videoPath, null, dialog_id, replyingMessageObject, getThreadMessage(), null, replyingQuote, null, 0, editingMessageObject, true, 0, false, false, null); + SendMessagesHelper.prepareSendingVideo(getAccountInstance(), videoPath, null, dialog_id, replyingMessageObject, getThreadMessage(), null, replyingQuote, null, 0, editingMessageObject, true, 0, false, false, null, quickReplyShortcut, getQuickReplyId()); afterMessageSend(); } } @@ -17004,7 +17107,7 @@ private void sendPhotosGroup(ArrayList entries, bool entry.reset(); } fillEditingMediaWithCaption(photos.get(0).caption, photos.get(0).entities); - SendMessagesHelper.prepareSendingMedia(getAccountInstance(), photos, dialog_id, replyingMessageObject, getThreadMessage(), null, replyingQuote, forceDocument, true, null, notify, scheduleDate, photos.get(0).updateStickersOrder, null); + SendMessagesHelper.prepareSendingMedia(getAccountInstance(), photos, dialog_id, replyingMessageObject, getThreadMessage(), null, replyingQuote, forceDocument, true, null, notify, scheduleDate, chatMode, photos.get(0).updateStickersOrder, null, quickReplyShortcut, getQuickReplyId()); afterMessageSend(); if (chatActivityEnterView != null) { chatActivityEnterView.setFieldText(""); @@ -17224,9 +17327,9 @@ private void sendUriAsDocument(Uri uri) { } fillEditingMediaWithCaption(null, null); if (sendAsUri) { - SendMessagesHelper.prepareSendingDocument(getAccountInstance(), null, null, uri, null, null, dialog_id, replyingMessageObject, getThreadMessage(), null, replyingQuote, editingMessageObject, true, 0, null); + SendMessagesHelper.prepareSendingDocument(getAccountInstance(), null, null, uri, null, null, dialog_id, replyingMessageObject, getThreadMessage(), null, replyingQuote, editingMessageObject, true, 0, null, quickReplyShortcut, getQuickReplyId()); } else { - SendMessagesHelper.prepareSendingDocument(getAccountInstance(), tempPath, originalPath, null, null, null, dialog_id, replyingMessageObject, getThreadMessage(), null, replyingQuote, editingMessageObject, true, 0, null); + SendMessagesHelper.prepareSendingDocument(getAccountInstance(), tempPath, originalPath, null, null, null, dialog_id, replyingMessageObject, getThreadMessage(), null, replyingQuote, editingMessageObject, true, 0, null, quickReplyShortcut, getQuickReplyId()); } hideFieldPanel(false); } @@ -17265,11 +17368,11 @@ public void onActivityResultFragment(int requestCode, int resultCode, Intent dat if (editingMessageObject == null && chatMode == MODE_SCHEDULED) { AlertsCreator.createScheduleDatePickerDialog(getParentActivity(), dialog_id, (notify, scheduleDate) -> { fillEditingMediaWithCaption(null, null); - SendMessagesHelper.prepareSendingPhoto(getAccountInstance(), null, uri, dialog_id, replyingMessageObject, getThreadMessage(), replyingQuote, null, null, null, null, 0, editingMessageObject, notify, scheduleDate); + SendMessagesHelper.prepareSendingPhoto(getAccountInstance(), null, uri, dialog_id, replyingMessageObject, getThreadMessage(), replyingQuote, null, null, null, null, 0, editingMessageObject, notify, scheduleDate, chatMode, quickReplyShortcut, getQuickReplyId()); }, themeDelegate); } else { fillEditingMediaWithCaption(null, null); - SendMessagesHelper.prepareSendingPhoto(getAccountInstance(), null, uri, dialog_id, replyingMessageObject, getThreadMessage(), replyingQuote, null, null, null, null, 0, editingMessageObject, true, 0); + SendMessagesHelper.prepareSendingPhoto(getAccountInstance(), null, uri, dialog_id, replyingMessageObject, getThreadMessage(), replyingQuote, null, null, null, null, 0, editingMessageObject, true, 0, chatMode, quickReplyShortcut, getQuickReplyId()); } } afterMessageSend(); @@ -17457,7 +17560,7 @@ public void didReceivedNotification(int id, int account, final Object... args) { return; } if (chatMode != mode && (chatMode != MODE_SAVED || getSavedDialogId() == getUserConfig().getClientUserId())) { - if (chatMode != MODE_SCHEDULED) { + if (chatMode != MODE_SCHEDULED && chatMode != MODE_QUICK_REPLIES) { if (isTopic) { ForumUtilities.filterMessagesByTopic(threadMessageId, messArr); } @@ -17662,7 +17765,7 @@ public void didReceivedNotification(int id, int account, final Object... args) { minMessageId[0] = 0; checkDispatchHideSkeletons(true); } - if (chatMode == MODE_SCHEDULED) { + if (chatMode == MODE_SCHEDULED || chatMode == MODE_QUICK_REPLIES) { endReached[0] = cacheEndReached[0] = true; forwardEndReached[0] = forwardEndReached[0] = true; } @@ -17798,8 +17901,8 @@ public void didReceivedNotification(int id, int account, final Object... args) { if (load_type == 1) { Collections.reverse(messArr); } - if (currentEncryptedChat == null) { - getMediaDataController().loadReplyMessagesForMessages(messArr, dialog_id, chatMode == MODE_SCHEDULED, 0, null, classGuid); + if (currentEncryptedChat == null && chatMode != MODE_QUICK_REPLIES) { + getMediaDataController().loadReplyMessagesForMessages(messArr, dialog_id, chatMode, 0, null, classGuid); } int approximateHeightSum = 0; if (!chatWasReset && (load_type == 2 || load_type == 1) && messArr.isEmpty() && !isCache) { @@ -17911,7 +18014,7 @@ public void didReceivedNotification(int id, int account, final Object... args) { continue; } - if (needAnimateToMessage != null && needAnimateToMessage.getId() == messageId && messageId < 0 && chatMode != MODE_SCHEDULED) { + if (needAnimateToMessage != null && needAnimateToMessage.getId() == messageId && messageId < 0 && chatMode != MODE_SCHEDULED && (chatMode != MODE_QUICK_REPLIES || messages.size() + 1 < getMessagesController().quickReplyMessagesLimit)) { obj = needAnimateToMessage; animatingMessageObjects.add(obj); needAnimateToMessage = null; @@ -17924,45 +18027,47 @@ public void didReceivedNotification(int id, int account, final Object... args) { messagesDict[loadIndex].put(messageId, obj); ArrayList dayArray = messagesByDays.get(obj.dateKey); + final boolean addDateObjects = chatMode != MODE_QUICK_REPLIES; if (dayArray == null) { dayArray = new ArrayList<>(); messagesByDays.put(obj.dateKey, dayArray); messagesByDaysSorted.put(obj.dateKeyInt, dayArray); - TLRPC.Message dateMsg = new TLRPC.TL_message(); - if (chatMode == MODE_SCHEDULED) { - if (obj.messageOwner.date == 0x7ffffffe) { - dateMsg.message = LocaleController.getString("MessageScheduledUntilOnline", R.string.MessageScheduledUntilOnline); + if (addDateObjects) { + TLRPC.Message dateMsg = new TLRPC.TL_message(); + if (chatMode == MODE_SCHEDULED) { + if (obj.messageOwner.date == 0x7ffffffe) { + dateMsg.message = LocaleController.getString("MessageScheduledUntilOnline", R.string.MessageScheduledUntilOnline); + } else { + dateMsg.message = LocaleController.formatString("MessageScheduledOn", R.string.MessageScheduledOn, LocaleController.formatDateChat(obj.messageOwner.date, true)); + } + } else { + dateMsg.message = LocaleController.formatDateChat(obj.messageOwner.date); + } + dateMsg.id = 0; + Calendar calendar = Calendar.getInstance(); + calendar.setTimeInMillis(((long) obj.messageOwner.date) * 1000); + calendar.set(Calendar.HOUR_OF_DAY, 0); + calendar.set(Calendar.MINUTE, 0); + calendar.set(Calendar.SECOND, 0); + calendar.set(Calendar.MILLISECOND, 0); + + if (chatMode == MODE_SCHEDULED && obj.messageOwner.date == 0x7ffffffe) { + dateMsg.date = 0x7ffffffe; + } else { + dateMsg.date = (int) (calendar.getTimeInMillis() / 1000); + } + MessageObject dateObj = new MessageObject(currentAccount, dateMsg, false, false); + dateObj.type = MessageObject.TYPE_DATE; + dateObj.contentType = 1; + dateObj.isDateObject = true; + dateObj.stableId = getStableIdForDateObject(obj.dateKeyInt); + if (load_type == 1) { + messages.add(0, dateObj); } else { - dateMsg.message = LocaleController.formatString("MessageScheduledOn", R.string.MessageScheduledOn, LocaleController.formatDateChat(obj.messageOwner.date, true)); + messages.add(dateObj); } - } else { - dateMsg.message = LocaleController.formatDateChat(obj.messageOwner.date); - } - dateMsg.id = 0; - Calendar calendar = Calendar.getInstance(); - calendar.setTimeInMillis(((long) obj.messageOwner.date) * 1000); - calendar.set(Calendar.HOUR_OF_DAY, 0); - calendar.set(Calendar.MINUTE, 0); - calendar.set(Calendar.SECOND, 0); - calendar.set(Calendar.MILLISECOND, 0); - - if (chatMode == MODE_SCHEDULED && obj.messageOwner.date == 0x7ffffffe) { - dateMsg.date = 0x7ffffffe; - } else { - dateMsg.date = (int) (calendar.getTimeInMillis() / 1000); - } - - MessageObject dateObj = new MessageObject(currentAccount, dateMsg, false, false); - dateObj.type = MessageObject.TYPE_DATE; - dateObj.contentType = 1; - dateObj.isDateObject = true; - dateObj.stableId = getStableIdForDateObject(obj.dateKeyInt); - if (load_type == 1) { - messages.add(0, dateObj); - } else { - messages.add(dateObj); + newRowsCount++; } - newRowsCount++; } else { if (!moveCurrentDateObject && !messages.isEmpty() && messages.get(messages.size() - 1).isDateObject) { messages.get(messages.size() - 1).stableId = lastStableId++; @@ -17978,7 +18083,7 @@ public void didReceivedNotification(int id, int account, final Object... args) { if (load_type == MessagesController.LOAD_FORWARD) { previous = messages.get(0); } else { - previous = messages.get(messages.size() - (reversed ? 1 : 2)); + previous = messages.get(messages.size() - (reversed || !addDateObjects ? 1 : 2)); } if (previous.getGroupIdForUse() == obj.getGroupIdForUse()) { if (previous.localGroupId != 0) { @@ -17986,7 +18091,7 @@ public void didReceivedNotification(int id, int account, final Object... args) { groupedMessages = groupedMessagesMap.get(previous.localGroupId); } } else { - if (reversed) { + if (reversed || !addDateObjects) { previous = messages.get(messages.size() - 2); if (previous.getGroupIdForUse() == obj.getGroupIdForUse()) { if (previous.localGroupId != 0) { @@ -18043,8 +18148,10 @@ public void didReceivedNotification(int id, int account, final Object... args) { if (load_type == 1) { messages.add(0, obj); } else { - messages.get(messages.size() - 1).stableId = lastStableId++; - if (reversed) { + if (!messages.isEmpty()) { + messages.get(messages.size() - 1).stableId = lastStableId++; + } + if (reversed || !addDateObjects) { messages.add(obj); } else { messages.add(messages.size() - 1, obj); @@ -18070,7 +18177,7 @@ public void didReceivedNotification(int id, int account, final Object... args) { prevObj = null; } } - if (load_type == 2 && messageId != 0 && messageId == first_unread_id && chatMode != MODE_SAVED) { + if (load_type == 2 && messageId != 0 && messageId == first_unread_id && chatMode != MODE_SAVED && chatMode != MODE_QUICK_REPLIES) { if ((approximateHeightSum > AndroidUtilities.displaySize.y / 2 || isThreadChat()) || !forwardEndReached[0]) { if (!isThreadChat() || threadMaxInboxReadId != 0) { TLRPC.Message dateMsg = new TLRPC.TL_message(); @@ -18109,7 +18216,7 @@ public void didReceivedNotification(int id, int account, final Object... args) { } if (load_type != 2 && unreadMessageObject == null && createUnreadMessageAfterId != 0 && (currentEncryptedChat == null && (!obj.isOut() || obj.messageOwner.from_scheduled) && messageId >= createUnreadMessageAfterId || currentEncryptedChat != null && (!obj.isOut() || obj.messageOwner.from_scheduled) && messageId <= createUnreadMessageAfterId) && - (load_type == 1 || prevObj != null || prevObj == null && createUnreadLoading && a == messArr.size() - 1) && chatMode != MODE_SAVED) { + (load_type == 1 || prevObj != null || prevObj == null && createUnreadLoading && a == messArr.size() - 1) && chatMode != MODE_SAVED && chatMode != MODE_QUICK_REPLIES) { TLRPC.Message dateMsg = new TLRPC.TL_message(); dateMsg.message = ""; dateMsg.id = 0; @@ -18507,6 +18614,9 @@ public void didReceivedNotification(int id, int account, final Object... args) { checkNewMessagesOnQuoteEdit(true); invalidatePremiumBlocked(); + if (chatMode == MODE_QUICK_REPLIES) { + updateBottomOverlay(); + } if (fakePostponedScroll) { setFilterMessages(false, true, true); } @@ -18631,8 +18741,9 @@ public void didReceivedNotification(int id, int account, final Object... args) { if (isInsideContainer) return; if (did == dialog_id) { boolean scheduled = (Boolean) args[2]; - if (scheduled != (chatMode == MODE_SCHEDULED)) { - if (chatMode != MODE_SCHEDULED && !isPaused && messagePreviewParams == null) { + int mode = (Integer) args[3]; + if (mode != chatMode) { + if (chatMode != MODE_SCHEDULED && mode == MODE_SCHEDULED && !isPaused && messagePreviewParams == null) { if (!arr.isEmpty() && arr.get(0).getId() < 0) { openScheduledMessages(); } @@ -18902,6 +19013,11 @@ public void didReceivedNotification(int id, int account, final Object... args) { long channelId = (Long) args[1]; boolean sent = args.length > 3 && (boolean) args[3]; processDeletedMessages(markAsDeletedMessages, channelId, sent); + } else if (id == NotificationCenter.quickRepliesDeleted) { + if (chatMode != MODE_QUICK_REPLIES) return; + if ((Long) args[1] != getQuickReplyId()) return; + ArrayList markAsDeletedMessages = (ArrayList) args[0]; + processDeletedMessages(markAsDeletedMessages, 0, false); } else if (id == NotificationCenter.messageReceivedByServer) { Boolean scheduled = (Boolean) args[6]; if (scheduled != (chatMode == MODE_SCHEDULED)) { @@ -18945,6 +19061,12 @@ public void didReceivedNotification(int id, int account, final Object... args) { return; } TLRPC.Message newMsgObj = (TLRPC.Message) args[2]; + if (MessageObject.isQuickReply(newMsgObj) && chatMode == MODE_QUICK_REPLIES) { + if (threadMessageId == 0) { + threadMessageId = MessageObject.getQuickReplyId(newMsgObj); + } else if (threadMessageId != MessageObject.getQuickReplyId(newMsgObj)) + return; + } Long grouped_id; if (args.length >= 4) { grouped_id = (Long) args[4]; @@ -18998,8 +19120,8 @@ public void didReceivedNotification(int id, int account, final Object... args) { addToPolls(obj, null); ArrayList messArr = new ArrayList<>(); messArr.add(obj); - if (currentEncryptedChat == null) { - getMediaDataController().loadReplyMessagesForMessages(messArr, dialog_id, chatMode == MODE_SCHEDULED, 0, null, classGuid); + if (currentEncryptedChat == null && chatMode != MODE_QUICK_REPLIES) { + getMediaDataController().loadReplyMessagesForMessages(messArr, dialog_id, chatMode, 0, null, classGuid); } if (chatAdapter != null) { chatAdapter.updateRowWithMessageObject(obj, false, false); @@ -19054,6 +19176,11 @@ public void didReceivedNotification(int id, int account, final Object... args) { } dismissCurrentDialog(); updateSecretStatus(); + AndroidUtilities.runOnUIThread(() -> { + String title = LocaleController.getString(R.string.BoostingRemoveRestrictionsSuccessTitle); + String subTitle = LocaleController.getString(R.string.BoostingRemoveRestrictionsSuccessSubTitle); + BulletinFactory.of(ChatActivity.this).createSimpleBulletin(R.raw.chats_infotip, title, subTitle).show(); + }, 350); } else if (id == NotificationCenter.chatInfoDidLoad) { TLRPC.ChatFull chatFull = (TLRPC.ChatFull) args[0]; if (currentChat != null && chatFull.id == currentChat.id) { @@ -19157,7 +19284,6 @@ public void didReceivedNotification(int id, int account, final Object... args) { } else if (chatInfo instanceof TLRPC.TL_channelFull) { hasBotsCommands = false; botInfo.clear(); - botsCount = 0; URLSpanBotCommand.enabled = !chatInfo.bot_info.isEmpty() && currentChat != null && currentChat.megagroup; botsCount = chatInfo.bot_info.size(); for (int a = 0; a < chatInfo.bot_info.size(); a++) { @@ -19180,7 +19306,7 @@ public void didReceivedNotification(int id, int account, final Object... args) { } } if (chatActivityEnterView != null) { - chatActivityEnterView.setBotsCount(botsCount, hasBotsCommands, true); + chatActivityEnterView.setBotsCount(botsCount, hasBotsCommands, hasQuickReplies, true); } if (mentionContainer != null && mentionContainer.getAdapter() != null) { mentionContainer.getAdapter().setBotsCount(botsCount); @@ -19884,7 +20010,7 @@ public void didReceivedNotification(int id, int account, final Object... args) { } boolean updated = false; if (arrayList != null) { - getMediaDataController().loadReplyMessagesForMessages(arrayList, dialog_id, false, 0, null, classGuid); + getMediaDataController().loadReplyMessagesForMessages(arrayList, dialog_id, 0, 0, null, classGuid); } for (int a = 0, N = ids.size(); a < N; a++) { Integer mid = ids.get(a); @@ -19980,7 +20106,7 @@ public void didReceivedNotification(int id, int account, final Object... args) { } loadingPinnedMessages.remove(message.getId()); } - getMediaDataController().loadReplyMessagesForMessages(arrayList, dialog_id, false, 0, null, classGuid); + getMediaDataController().loadReplyMessagesForMessages(arrayList, dialog_id, 0, 0, null, classGuid); updateMessagesVisiblePart(false); } else { pinnedMessageIds.clear(); @@ -20103,7 +20229,7 @@ public void didReceivedNotification(int id, int account, final Object... args) { } } if (chatActivityEnterView != null) { - chatActivityEnterView.setBotsCount(botsCount, hasBotsCommands, true); + chatActivityEnterView.setBotsCount(botsCount, hasBotsCommands, hasQuickReplies, true); TLRPC.User bot = getMessagesController().getUser(info.user_id); hasBotWebView = bot != null && bot.bot_menu_webview; chatActivityEnterView.updateBotWebView(true); @@ -20155,9 +20281,6 @@ public void didReceivedNotification(int id, int account, final Object... args) { setFilterMessages(false); updateVisibleRows(); } - if (searchItem != null) { - searchItem.setShowSearchProgress(false); - } onSearchLoadingUpdate(false); } else if (searchingReaction != null) { if (chatAdapter.isFiltered) { @@ -20166,6 +20289,9 @@ public void didReceivedNotification(int id, int account, final Object... args) { setFilterMessages(true); } } + if (searchItem != null) { + searchItem.setShowSearchProgress(false); + } if (messagesSearchAdapter != null) { messagesSearchAdapter.notifyDataSetChanged(); } @@ -20176,7 +20302,7 @@ public void didReceivedNotification(int id, int account, final Object... args) { } else if (id == NotificationCenter.chatSearchResultsLoading) { if (classGuid == (Integer) args[0]) { if (searchItem != null) { - searchItem.setShowSearchProgress(true); + searchItem.setShowSearchProgress(!TextUtils.isEmpty(searchingQuery) || searchingReaction != null); } onSearchLoadingUpdate(true); if (messagesSearchAdapter != null) { @@ -20374,7 +20500,7 @@ public void didReceivedNotification(int id, int account, final Object... args) { totalPinnedMessagesCount = (Integer) args[3]; pinnedEndReached = (Boolean) args[4]; - getMediaDataController().loadReplyMessagesForMessages(new ArrayList<>(pinnedMessageObjects.values()), dialog_id, false, 0, null, classGuid); + getMediaDataController().loadReplyMessagesForMessages(new ArrayList<>(pinnedMessageObjects.values()), dialog_id, 0, 0, null, classGuid); if (!inMenuMode && !loadingPinnedMessagesList && totalPinnedMessagesCount == 0 && !pinnedEndReached) { getMediaDataController().loadPinnedMessages(dialog_id, 0, fallbackId); @@ -20809,6 +20935,11 @@ public void didReceivedNotification(int id, int account, final Object... args) { if (chatMode == MODE_SAVED && !isInsideContainer && getUserConfig().getClientUserId() != getSavedDialogId() && !getMessagesController().getSavedMessagesController().containsDialog(getSavedDialogId())) { finishFragment(); } + } else if (id == NotificationCenter.quickRepliesUpdated) { +// hasQuickReplies = currentUser != null && chatMode == 0 && !currentUser.bot && QuickRepliesController.getInstance(currentAccount).hasReplies(); +// if (chatActivityEnterView != null) { +// chatActivityEnterView.setBotsCount(botsCount, hasBotsCommands, hasQuickReplies, true); +// } } } @@ -21537,7 +21668,7 @@ private void processNewMessages(ArrayList arr) { } } - if (chatMode == MODE_SCHEDULED && !arr.isEmpty()) { + if ((chatMode == MODE_SCHEDULED || chatMode == MODE_QUICK_REPLIES) && !arr.isEmpty()) { replaceMessageObjects(arr, 0, true); } @@ -21555,7 +21686,11 @@ private void processNewMessages(ArrayList arr) { if (obj.isOut()) { rotateMotionBackgroundDrawable(); } - if (chatMode == MODE_SAVED) { + if (chatMode == MODE_QUICK_REPLIES) { + if (!(obj.getQuickReplyId() == getQuickReplyId() || TextUtils.equals(obj.getQuickReplyName(), quickReplyShortcut) || obj.messageOwner != null && obj.messageOwner.quick_reply_shortcut_id == threadMessageId)) { + continue; + } + } else if (chatMode == MODE_SAVED) { if (MessageObject.getSavedDialogId(getUserConfig().getClientUserId(), obj.messageOwner) != threadMessageId) { continue; } @@ -21661,7 +21796,11 @@ private void processNewMessages(ArrayList arr) { if (obj.scheduled != (chatMode == MODE_SCHEDULED)) { continue; } - if (chatMode == MODE_SAVED) { + if (chatMode == MODE_QUICK_REPLIES) { + if (!(obj.getQuickReplyId() == getQuickReplyId() || TextUtils.equals(obj.getQuickReplyName(), quickReplyShortcut) || obj.messageOwner != null && obj.messageOwner.quick_reply_shortcut_id == threadMessageId)) { + continue; + } + } else if (chatMode == MODE_SAVED) { if (MessageObject.getSavedDialogId(getUserConfig().getClientUserId(), obj.messageOwner) != threadMessageId) { continue; } @@ -21732,7 +21871,7 @@ private void processNewMessages(ArrayList arr) { } } addToPolls(obj, null); - if (a == 0 && obj.shouldAnimateSending() && chatMode != MODE_SCHEDULED) { + if (a == 0 && obj.shouldAnimateSending() && chatMode != MODE_SCHEDULED && (chatMode != MODE_QUICK_REPLIES || messages.size() + 1 < getMessagesController().quickReplyMessagesLimit)) { animatingMessageObjects.add(obj); } @@ -21763,7 +21902,7 @@ private void processNewMessages(ArrayList arr) { } if (placeToPaste == -1) { - if (!obj.scheduled && obj.messageOwner.id < 0 || messages.isEmpty()) { + if (!obj.scheduled && obj.messageOwner.id < 0 || obj.isQuickReply() || messages.isEmpty()) { placeToPaste = 0; } else { int size = messages.size(); @@ -21886,35 +22025,37 @@ private void processNewMessages(ArrayList arr) { dayArray = new ArrayList<>(); messagesByDays.put(obj.dateKey, dayArray); messagesByDaysSorted.put(obj.dateKeyInt, dayArray); - TLRPC.Message dateMsg = new TLRPC.TL_message(); - if (chatMode == MODE_SCHEDULED) { - if (obj.messageOwner.date == 0x7ffffffe) { - dateMsg.message = LocaleController.getString("MessageScheduledUntilOnline", R.string.MessageScheduledUntilOnline); + if (chatMode != MODE_QUICK_REPLIES) { + TLRPC.Message dateMsg = new TLRPC.TL_message(); + if (chatMode == MODE_SCHEDULED) { + if (obj.messageOwner.date == 0x7ffffffe) { + dateMsg.message = LocaleController.getString("MessageScheduledUntilOnline", R.string.MessageScheduledUntilOnline); + } else { + dateMsg.message = LocaleController.formatString("MessageScheduledOn", R.string.MessageScheduledOn, LocaleController.formatDateChat(obj.messageOwner.date, true)); + } } else { - dateMsg.message = LocaleController.formatString("MessageScheduledOn", R.string.MessageScheduledOn, LocaleController.formatDateChat(obj.messageOwner.date, true)); + dateMsg.message = LocaleController.formatDateChat(obj.messageOwner.date); + } + dateMsg.id = 0; + Calendar calendar = Calendar.getInstance(); + calendar.setTimeInMillis(((long) obj.messageOwner.date) * 1000); + calendar.set(Calendar.HOUR_OF_DAY, 0); + calendar.set(Calendar.MINUTE, 0); + calendar.set(Calendar.SECOND, 0); + calendar.set(Calendar.MILLISECOND, 0); + dateMsg.date = (int) (calendar.getTimeInMillis() / 1000); + MessageObject dateObj = new MessageObject(currentAccount, dateMsg, false, false); + dateObj.type = 10; + dateObj.contentType = 1; + dateObj.isDateObject = true; + dateObj.stableId = getStableIdForDateObject(obj.dateKeyInt); + messages.add(placeToPaste, dateObj); + if (chatAdapter != null) { + chatAdapter.notifyItemInserted(placeToPaste); } - } else { - dateMsg.message = LocaleController.formatDateChat(obj.messageOwner.date); - } - dateMsg.id = 0; - Calendar calendar = Calendar.getInstance(); - calendar.setTimeInMillis(((long) obj.messageOwner.date) * 1000); - calendar.set(Calendar.HOUR_OF_DAY, 0); - calendar.set(Calendar.MINUTE, 0); - calendar.set(Calendar.SECOND, 0); - calendar.set(Calendar.MILLISECOND, 0); - dateMsg.date = (int) (calendar.getTimeInMillis() / 1000); - MessageObject dateObj = new MessageObject(currentAccount, dateMsg, false, false); - dateObj.type = 10; - dateObj.contentType = 1; - dateObj.isDateObject = true; - dateObj.stableId = getStableIdForDateObject(obj.dateKeyInt); - messages.add(placeToPaste, dateObj); - if (chatAdapter != null) { - chatAdapter.notifyItemInserted(placeToPaste); } } - if (!(obj.messageOwner.action instanceof TLRPC.TL_messageActionGeoProximityReached) && (!obj.isOut() || obj.messageOwner.from_scheduled) && chatMode != MODE_SAVED) { + if (chatMode != MODE_QUICK_REPLIES && !(obj.messageOwner.action instanceof TLRPC.TL_messageActionGeoProximityReached) && (!obj.isOut() || obj.messageOwner.from_scheduled) && chatMode != MODE_SAVED) { if (paused && placeToPaste == 0) { if (!scrollToTopUnReadOnResume && unreadMessageObject != null) { removeMessageObject(unreadMessageObject); @@ -22082,6 +22223,9 @@ private void processNewMessages(ArrayList arr) { } } } + if (chatMode == MODE_QUICK_REPLIES) { + updateBottomOverlay(); + } if (!messages.isEmpty() && botUser != null && botUser.length() == 0) { botUser = null; updateBottomOverlay(); @@ -22418,6 +22562,7 @@ private void processDeletedMessages(ArrayList markAsDeletedMessages, lo } } if (chatAdapter != null) { + int prevHintRow = chatAdapter.hintRow; int prevLoadingUpRow = chatAdapter.loadingUpRow; int prevLoadingDownRow = chatAdapter.loadingDownRow; for (int a = 0, N = removedIndexes.size(); a < N; a++) { @@ -22434,11 +22579,17 @@ private void processDeletedMessages(ArrayList markAsDeletedMessages, lo if (prevLoadingDownRow >= 0) { chatAdapter.notifyItemRemoved(0); } + if (prevHintRow >= 0) { + chatAdapter.notifyItemRemoved(0); + } } else { chatAdapter.notifyItemRangeChanged(chatAdapter.messagesStartRow, chatAdapter.getMessages().size()); } } updateVisibleRows(); + if (chatMode == MODE_QUICK_REPLIES) { + updateBottomOverlay(); + } } else if (threadMessageId == 0) { first_unread_id = 0; last_message_id = 0; @@ -22454,6 +22605,10 @@ private void processDeletedMessages(ArrayList markAsDeletedMessages, lo if (savedMessagesTagHint != null && savedMessagesTagHint.shown()) { savedMessagesTagHint.hide(); } + + if (chatMode == MODE_QUICK_REPLIES && messages != null && messages.isEmpty()) { + threadMessageId = 0; + } } private void replaceMessageObjects(ArrayList messageObjects, int loadIndex, boolean remove) { @@ -23352,6 +23507,15 @@ private void updateBottomOverlay() { ChatGreetingsView.showPremiumSheet(getContext(), currentAccount, dialog_id, themeDelegate); })); showBottomOverlayProgress(false, false); + } else if (chatMode == MODE_QUICK_REPLIES && messages.size() >= getMessagesController().quickReplyMessagesLimit) { + bottomOverlayLinks = true; + bottomOverlayChatText.setVisibility(View.GONE); + bottomOverlayLinksText.setVisibility(View.VISIBLE); + bottomOverlayLinksText.setText(AndroidUtilities.replaceTags(LocaleController.formatPluralString("BusinessRepliesLimit", getMessagesController().quickReplyMessagesLimit))); + showBottomOverlayProgress(false, false); + if (chatActivityEnterView != null) { + chatActivityEnterView.hidePopup(false); + } } else if (chatMode == MODE_SAVED && getSavedDialogId() != getUserConfig().getClientUserId()) { if (getSavedDialogId() == UserObject.ANONYMOUS) { forceNoBottom = true; @@ -23512,12 +23676,11 @@ private void updateBottomOverlay() { searchContainer.setVisibility(View.VISIBLE); searchContainer.setAlpha(0f); } - searchContainer.animate().alpha(1f).setDuration(150).setListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator animation) { - super.onAnimationEnd(animation); - } - }).start(); + ViewPropertyAnimator anim = searchContainer.animate().alpha(1f).setDuration(220).setInterpolator(CubicBezierInterpolator.EASE_OUT_QUINT); + if (isInsideContainer) { + anim.translationY(0); + } + anim.start(); if (searchExpandAnimator != null) { searchExpandAnimator.removeAllListeners(); @@ -23562,7 +23725,11 @@ public void onAnimationEnd(Animator animation) { if (searchContainer != null) { searchContainer.animate().setListener(null).cancel(); if (searchContainer.getVisibility() == View.VISIBLE) { - searchContainer.animate().alpha(0).setDuration(150).setListener(new AnimatorListenerAdapter() { + ViewPropertyAnimator anim = searchContainer.animate().setDuration(220).setInterpolator(CubicBezierInterpolator.EASE_OUT_QUINT); + if (isInsideContainer) { + anim.translationY(dp(searchContainerHeight)); + } + anim.setListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { super.onAnimationEnd(animation); @@ -25950,7 +26117,7 @@ private void createDeleteMessagesAlert(final MessageObject finalSelectedObject, 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, chatMode == MODE_SAVED, loadParticipant, () -> { + AlertsCreator.createDeleteMessagesAlert(this, currentUser, currentChat, currentEncryptedChat, chatInfo, mergeDialogId, finalSelectedObject, selectedMessagesIds, finalSelectedGroup, (int) getTopicId(), chatMode, loadParticipant, () -> { hideActionMode(); updatePinnedMessageView(true); }, hideDimAfter ? () -> dimBehindView(false) : null, themeDelegate); @@ -26150,7 +26317,7 @@ private boolean createMenu(View v, boolean single, boolean listView, float x, fl boolean allowChatActions = true; boolean allowPin; - if (chatMode == MODE_SAVED) { + if (chatMode == MODE_SAVED || chatMode == MODE_QUICK_REPLIES) { allowPin = false; } else if (chatMode == MODE_SCHEDULED || (isThreadChat() && !isTopic)) { allowPin = false; @@ -26581,7 +26748,7 @@ public void setAutoDeleteHistory(int time, int action) { icons.add(R.drawable.msg_unfave); } } - if (!selectedObject.isSponsored() && chatMode != MODE_SCHEDULED && (!selectedObject.needDrawBluredPreview() || selectedObject.hasExtendedMediaPreview()) && + if (!selectedObject.isSponsored() && chatMode != MODE_QUICK_REPLIES && chatMode != MODE_SCHEDULED && (!selectedObject.needDrawBluredPreview() || selectedObject.hasExtendedMediaPreview()) && !selectedObject.isLiveLocation() && selectedObject.type != MessageObject.TYPE_PHONE_CALL && !noforwards && selectedObject.type != MessageObject.TYPE_GIFT_PREMIUM && selectedObject.type != MessageObject.TYPE_GIFT_PREMIUM_CHANNEL && selectedObject.type != MessageObject.TYPE_SUGGEST_PHOTO && !selectedObject.isWallpaperAction() && !message.isExpiredStory() && message.type != MessageObject.TYPE_STORY_MENTION) { @@ -26746,10 +26913,10 @@ public void setAutoDeleteHistory(int time, int action) { if (chatInfo == null) { isReactionsAvailable = true; } else { - isReactionsAvailable = !isSecretChat() && !isInScheduleMode() && message.isReactionsAvailable() && (chatInfo != null && !(chatInfo.available_reactions instanceof TLRPC.TL_chatReactionsNone)) && !availableReacts.isEmpty(); + isReactionsAvailable = !isSecretChat() && chatMode != MODE_QUICK_REPLIES && !isInScheduleMode() && message.isReactionsAvailable() && (chatInfo != null && !(chatInfo.available_reactions instanceof TLRPC.TL_chatReactionsNone)) && !availableReacts.isEmpty(); } } else { - isReactionsAvailable = !message.isSecretMedia() && !isSecretChat() && !isInScheduleMode() && message.isReactionsAvailable() && (chatInfo != null && !(chatInfo.available_reactions instanceof TLRPC.TL_chatReactionsNone) || (chatInfo == null && !ChatObject.isChannel(currentChat)) || currentUser != null) && !availableReacts.isEmpty(); + isReactionsAvailable = !message.isSecretMedia() && chatMode != MODE_QUICK_REPLIES && !isSecretChat() && !isInScheduleMode() && message.isReactionsAvailable() && (chatInfo != null && !(chatInfo.available_reactions instanceof TLRPC.TL_chatReactionsNone) || (chatInfo == null && !ChatObject.isChannel(currentChat)) || currentUser != null) && !availableReacts.isEmpty(); } boolean showMessageSeen = !isReactionsViewAvailable && !isInScheduleMode() && currentChat != null && message.isOutOwner() && message.isSent() && !message.isEditing() && !message.isSending() && !message.isSendError() && !message.isContentUnread() && !message.isUnread() && (ConnectionsManager.getInstance(currentAccount).getCurrentTime() - message.messageOwner.date < getMessagesController().chatReadMarkExpirePeriod) && (ChatObject.isMegagroup(currentChat) || !ChatObject.isChannel(currentChat)) && chatInfo != null && chatInfo.participants_count <= getMessagesController().chatReadMarkSizeThreshold && !(message.messageOwner.action instanceof TLRPC.TL_messageActionChatJoinedByRequest) && (v instanceof ChatMessageCell); boolean showPrivateMessageSeen = !isReactionsViewAvailable && currentChat == null && currentEncryptedChat == null && (currentUser != null && !UserObject.isUserSelf(currentUser) && !UserObject.isReplyUser(currentUser) && !UserObject.isAnonymous(currentUser) && !currentUser.bot && !UserObject.isService(currentUser.id)) && (userInfo == null || !userInfo.read_dates_private) && !isInScheduleMode() && message.isOutOwner() && message.isSent() && !message.isEditing() && !message.isSending() && !message.isSendError() && !message.isContentUnread() && !message.isUnread() && (ConnectionsManager.getInstance(currentAccount).getCurrentTime() - message.messageOwner.date < getMessagesController().pmReadDateExpirePeriod) && !(message.messageOwner.action instanceof TLRPC.TL_messageActionChatJoinedByRequest) && (v instanceof ChatMessageCell); @@ -27934,14 +28101,18 @@ private void createEmptyView(boolean recreate) { emptyView.setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)); emptyView.setPadding(AndroidUtilities.dp(10), AndroidUtilities.dp(2), AndroidUtilities.dp(10), AndroidUtilities.dp(3)); emptyViewContainer.addView(emptyView, new FrameLayout.LayoutParams(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER)); + } else if (chatMode == MODE_QUICK_REPLIES) { + businessEmptyView = new BusinessChatEmptyView(getContext(), chatMode, dialog_id, threadMessageId, quickReplyShortcut, getResourceProvider()); + businessEmptyView.setBackground(Theme.createServiceDrawable(AndroidUtilities.dp(16), businessEmptyView, contentView, getThemedPaint(Theme.key_paint_chatActionBackground))); + emptyViewContainer.addView(businessEmptyView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER)); } else if ((distance >= 0 || preloadedGreetingsSticker != null) && currentUser != null && !userBlocked || userInfo != null && userInfo.contact_require_premium && !getUserConfig().isPremium()) { greetingsViewContainer = new ChatGreetingsView(getContext(), currentUser, distance, currentAccount, preloadedGreetingsSticker, themeDelegate); greetingsViewContainer.setPremiumLock(userInfo != null && userInfo.contact_require_premium && !getUserConfig().isPremium(), dialog_id); greetingsViewContainer.setListener((sticker) -> { animatingDocuments.put(sticker, 0); - SendMessagesHelper.getInstance(currentAccount).sendSticker(sticker, null, dialog_id, null, null, null, replyingQuote, null, true, 0, false, null); + SendMessagesHelper.getInstance(currentAccount).sendSticker(sticker, null, dialog_id, null, null, null, replyingQuote, null, true, 0, false, null, quickReplyShortcut, getQuickReplyId()); }); - greetingsViewContainer.setBackground(Theme.createServiceDrawable(AndroidUtilities.dp(10), greetingsViewContainer, contentView, getThemedPaint(Theme.key_paint_chatActionBackground))); + greetingsViewContainer.setBackground(Theme.createServiceDrawable(AndroidUtilities.dp(16), greetingsViewContainer, contentView, getThemedPaint(Theme.key_paint_chatActionBackground))); emptyViewContainer.addView(greetingsViewContainer, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER)); } else if (currentEncryptedChat == null) { if (isTopic && chatMode == 0) { @@ -27973,7 +28144,7 @@ private void createEmptyView(boolean recreate) { greetingsViewContainer.setPremiumLock(userInfo != null && userInfo.contact_require_premium && !getUserConfig().isPremium(), dialog_id); greetingsViewContainer.setListener((sticker) -> { animatingDocuments.put(sticker, 0); - SendMessagesHelper.getInstance(currentAccount).sendSticker(sticker, null, dialog_id, null, null, null, replyingQuote, null, true, 0, false, null); + SendMessagesHelper.getInstance(currentAccount).sendSticker(sticker, null, dialog_id, null, null, null, replyingQuote, null, true, 0, false, null, quickReplyShortcut, getQuickReplyId()); }); greetingsViewContainer.setBackground(Theme.createServiceDrawable(AndroidUtilities.dp(16), greetingsViewContainer, contentView, getThemedPaint(Theme.key_paint_chatActionBackground))); emptyViewContainer.addView(greetingsViewContainer, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER)); @@ -28230,7 +28401,7 @@ private void startEditingMessageObject(MessageObject messageObject) { updatePinnedMessageView(true); updateVisibleRows(); - if (!messageObject.scheduled) { + if (!messageObject.scheduled && !messageObject.isQuickReply()) { TLRPC.TL_messages_getMessageEditData req = new TLRPC.TL_messages_getMessageEditData(); req.peer = getMessagesController().getInputPeer(dialog_id); req.id = messageObject.getId(); @@ -28242,7 +28413,7 @@ private void startEditingMessageObject(MessageObject messageObject) { } AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity(), themeDelegate); builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); - builder.setMessage(LocaleController.getString("EditMessageError", R.string.EditMessageError)); + builder.setMessage(LocaleController.getString(R.string.EditMessageError)); builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), null); showDialog(builder.create()); @@ -29157,7 +29328,10 @@ public boolean didSelectDialogs(DialogsActivity fragment, ArrayList { + finishFragment(); + }) + .setNegativeButton(LocaleController.getString(R.string.Cancel), null) + .create() + ); + } public void clearSelectionMode() { clearSelectionMode(false); @@ -29371,6 +29562,14 @@ public void setSavedDialog(long savedDialogId) { threadMessageId = savedDialogId; } + private MessageObject quickReplyMessage; + public void setQuickReplyId(long topicId) { + threadMessageId = topicId; + TLRPC.TL_message message = new TLRPC.TL_message(); + message.id = (int) topicId; + quickReplyMessage = new MessageObject(currentAccount, message, false, false); + } + public void setThreadMessages(ArrayList messageObjects, TLRPC.Chat originalChat, int originalMessage, int maxInboxReadId, int maxOutboxReadId, TLRPC.TL_forumTopic forumTopic) { this.forumTopic = forumTopic; threadMessageObjects = messageObjects; @@ -29622,7 +29821,10 @@ public void openSearchWithText(String text) { @Override public void didSelectLocation(TLRPC.MessageMedia location, int locationType, boolean notify, int scheduleDate) { - getSendMessagesHelper().sendMessage(SendMessagesHelper.SendMessageParams.of(location, dialog_id, replyingMessageObject, getThreadMessage(), null, null, notify, scheduleDate)); + SendMessagesHelper.SendMessageParams params = SendMessagesHelper.SendMessageParams.of(location, dialog_id, replyingMessageObject, getThreadMessage(), null, null, notify, scheduleDate); + params.quick_reply_shortcut = quickReplyShortcut; + params.quick_reply_shortcut_id = getQuickReplyId(); + getSendMessagesHelper().sendMessage(params); if (chatMode == 0) { moveScrollToLastMessage(false); } @@ -29643,6 +29845,7 @@ public boolean isSecretChat() { } public boolean canScheduleMessage() { + if (chatMode == MODE_QUICK_REPLIES) return false; if (getMessagesController().isForum(getDialogId()) && !isTopic) { return false; } @@ -29712,21 +29915,45 @@ public TLRPC.UserFull getCurrentUserInfo() { public void sendAudio(ArrayList audios, CharSequence caption, boolean notify, int scheduleDate) { if (checkSlowModeAlert()) { fillEditingMediaWithCaption(caption, null); - SendMessagesHelper.prepareSendingAudioDocuments(getAccountInstance(), audios, caption != null ? caption : null, dialog_id, replyingMessageObject, getThreadMessage(), null, notify, scheduleDate, editingMessageObject); + SendMessagesHelper.prepareSendingAudioDocuments(getAccountInstance(), audios, caption != null ? caption : null, dialog_id, replyingMessageObject, getThreadMessage(), null, notify, scheduleDate, editingMessageObject, quickReplyShortcut, getQuickReplyId()); afterMessageSend(); } } public void sendContact(TLRPC.User user, boolean notify, int scheduleDate) { if (checkSlowModeAlert()) { - getSendMessagesHelper().sendMessage(SendMessagesHelper.SendMessageParams.of(user, dialog_id, replyingMessageObject, getThreadMessage(), null, null, notify, scheduleDate)); + SendMessagesHelper.SendMessageParams params = SendMessagesHelper.SendMessageParams.of(user, dialog_id, replyingMessageObject, getThreadMessage(), null, null, notify, scheduleDate); + params.quick_reply_shortcut = quickReplyShortcut; + params.quick_reply_shortcut_id = getQuickReplyId(); + getSendMessagesHelper().sendMessage(params); + afterMessageSend(); + } + } + + public void sendContacts(ArrayList users, String caption, boolean notify, int scheduleDate) { + if (checkSlowModeAlert()) { + if (!TextUtils.isEmpty(caption)) { + SendMessagesHelper.SendMessageParams params = SendMessagesHelper.SendMessageParams.of(caption, dialog_id, null, null, null, true, null, null, null, true, 0, null, false); + params.quick_reply_shortcut = quickReplyShortcut; + params.quick_reply_shortcut_id = getQuickReplyId(); + SendMessagesHelper.getInstance(currentAccount).sendMessage(params); + } + for (TLRPC.User user : users) { + SendMessagesHelper.SendMessageParams params = SendMessagesHelper.SendMessageParams.of(user, dialog_id, null, null, null, null, notify, scheduleDate); + params.quick_reply_shortcut = quickReplyShortcut; + params.quick_reply_shortcut_id = getQuickReplyId(); + getSendMessagesHelper().sendMessage(params); + } afterMessageSend(); } } public void sendPoll(TLRPC.TL_messageMediaPoll poll, HashMap params, boolean notify, int scheduleDate) { if (checkSlowModeAlert()) { - getSendMessagesHelper().sendMessage(SendMessagesHelper.SendMessageParams.of(poll, dialog_id, replyingMessageObject, getThreadMessage(), null, params, notify, scheduleDate)); + SendMessagesHelper.SendMessageParams params2 = SendMessagesHelper.SendMessageParams.of(poll, dialog_id, replyingMessageObject, getThreadMessage(), null, params, notify, scheduleDate); + params2.quick_reply_shortcut = quickReplyShortcut; + params2.quick_reply_shortcut_id = getQuickReplyId(); + getSendMessagesHelper().sendMessage(params2); afterMessageSend(); } } @@ -29744,15 +29971,15 @@ public void sendMedia(MediaController.PhotoEntry photoEntry, VideoEditedInfo vid fillEditingMediaWithCaption(photoEntry.caption, photoEntry.entities); if (photoEntry.isVideo) { if (videoEditedInfo != null) { - SendMessagesHelper.prepareSendingVideo(getAccountInstance(), photoEntry.path, videoEditedInfo, dialog_id, replyingMessageObject, getThreadMessage(), null, replyingQuote, photoEntry.entities, photoEntry.ttl, editingMessageObject, notify, scheduleDate, forceDocument, photoEntry.hasSpoiler, photoEntry.caption); + SendMessagesHelper.prepareSendingVideo(getAccountInstance(), photoEntry.path, videoEditedInfo, dialog_id, replyingMessageObject, getThreadMessage(), null, replyingQuote, photoEntry.entities, photoEntry.ttl, editingMessageObject, notify, scheduleDate, forceDocument, photoEntry.hasSpoiler, photoEntry.caption, quickReplyShortcut, getQuickReplyId()); } else { - SendMessagesHelper.prepareSendingVideo(getAccountInstance(), photoEntry.path, null, dialog_id, replyingMessageObject, getThreadMessage(), null, replyingQuote, photoEntry.entities, photoEntry.ttl, editingMessageObject, notify, scheduleDate, forceDocument, photoEntry.hasSpoiler, photoEntry.caption); + SendMessagesHelper.prepareSendingVideo(getAccountInstance(), photoEntry.path, null, dialog_id, replyingMessageObject, getThreadMessage(), null, replyingQuote, photoEntry.entities, photoEntry.ttl, editingMessageObject, notify, scheduleDate, forceDocument, photoEntry.hasSpoiler, photoEntry.caption, quickReplyShortcut, getQuickReplyId()); } } else { if (photoEntry.imagePath != null) { - SendMessagesHelper.prepareSendingPhoto(getAccountInstance(), photoEntry.imagePath, photoEntry.thumbPath, null, dialog_id, replyingMessageObject, getThreadMessage(), null, replyingQuote, photoEntry.entities, photoEntry.stickers, null, photoEntry.ttl, editingMessageObject, videoEditedInfo, notify, scheduleDate, forceDocument, photoEntry.caption); + SendMessagesHelper.prepareSendingPhoto(getAccountInstance(), photoEntry.imagePath, photoEntry.thumbPath, null, dialog_id, replyingMessageObject, getThreadMessage(), null, replyingQuote, photoEntry.entities, photoEntry.stickers, null, photoEntry.ttl, editingMessageObject, videoEditedInfo, notify, scheduleDate, 0, forceDocument, photoEntry.caption, quickReplyShortcut, getQuickReplyId()); } else if (photoEntry.path != null) { - SendMessagesHelper.prepareSendingPhoto(getAccountInstance(), photoEntry.path, photoEntry.thumbPath, null, dialog_id, replyingMessageObject, getThreadMessage(), null, replyingQuote, photoEntry.entities, photoEntry.stickers, null, photoEntry.ttl, editingMessageObject, videoEditedInfo, notify, scheduleDate, forceDocument, photoEntry.caption); + SendMessagesHelper.prepareSendingPhoto(getAccountInstance(), photoEntry.path, photoEntry.thumbPath, null, dialog_id, replyingMessageObject, getThreadMessage(), null, replyingQuote, photoEntry.entities, photoEntry.stickers, null, photoEntry.ttl, editingMessageObject, videoEditedInfo, notify, scheduleDate, 0, forceDocument, photoEntry.caption, quickReplyShortcut, getQuickReplyId()); } } afterMessageSend(); @@ -29802,7 +30029,10 @@ public void sendAnimatedEmoji(TLRPC.Document emoji, boolean notify, int schedule entity.offset = 0; entity.length = message.length(); entities.add(entity); - SendMessagesHelper.getInstance(currentAccount).sendMessage(SendMessagesHelper.SendMessageParams.of(message, dialog_id, replyingMessageObject, getThreadMessage(), null, false, entities, null, null, notify, scheduleDate, null, false)); + SendMessagesHelper.SendMessageParams params = SendMessagesHelper.SendMessageParams.of(message, dialog_id, replyingMessageObject, getThreadMessage(), null, false, entities, null, null, notify, scheduleDate, null, false); + params.quick_reply_shortcut = quickReplyShortcut; + params.quick_reply_shortcut_id = getQuickReplyId(); + SendMessagesHelper.getInstance(currentAccount).sendMessage(params); afterMessageSend(); } @@ -30793,11 +31023,17 @@ private void markSponsoredAsRead(MessageObject object) { @Override public boolean canBeginSlide() { + if (chatMode == MODE_QUICK_REPLIES && (messages.isEmpty() || threadMessageId == 0)) { + return false; + } return swipeBackEnabled && chatActivityEnterView.swipeToBackEnabled() && pullingDownOffset == 0; } @Override public boolean isSwipeBackEnabled(MotionEvent event) { + if (chatMode == MODE_QUICK_REPLIES && (messages.isEmpty() || threadMessageId == 0)) { + return false; + } return swipeBackEnabled && (forwardingPreviewView == null || !forwardingPreviewView.isShowing()); } @@ -30886,6 +31122,12 @@ private void updateRowsInternal() { botInfoRow = -5; } + if (chatMode == MODE_QUICK_REPLIES && !QuickRepliesController.isSpecial(quickReplyShortcut)) { + hintRow = rowCount++; + } else { + hintRow = -5; + } + if (isFiltered ? !filteredEndReached : (!endReached[0] || mergeDialogId != 0 && !endReached[1]) && !(DISABLE_PROGRESS_VIEW && !AndroidUtilities.isTablet() && !isComments && currentUser == null)) { loadingUpRow = rowCount++; } else { @@ -31274,7 +31516,11 @@ public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { ChatActionCell actionCell = (ChatActionCell) holder.itemView; createHint2MessageObject(); actionCell.setMessageObject(hint2MessageObject); - actionCell.setCustomText(LocaleController.getString(R.string.SavedMessagesProfileHint)); + if (chatMode == MODE_SAVED) { + actionCell.setCustomText(LocaleController.getString(R.string.SavedMessagesProfileHint)); + } else if (chatMode == MODE_QUICK_REPLIES) { + actionCell.setCustomText(LocaleController.getString(R.string.BusinessRepliesHint)); + } actionCell.setAlpha(1.0f); actionCell.setSpoilersSuppressed(chatListView.getScrollState() != RecyclerView.SCROLL_STATE_IDLE); } else if (position >= messagesStartRow && position < messagesEndRow) { @@ -32335,7 +32581,9 @@ public void onTextChanged(EditText editText) { public void onCaptionCleared() { createSearchContainer(); if (searchingUserMessages != null || searchingChatMessages != null) { - searchUserButton.callOnClick(); + if (searchUserButton != null) { + searchUserButton.callOnClick(); + } } else { if (searchingForUser) { mentionContainer.getAdapter().searchUsernameOrHashtag(null, 0, null, false, true); @@ -32871,6 +33119,7 @@ private boolean isAvatarPreviewerEnabled() { @Override public void didPressBotButton(ChatMessageCell cell, TLRPC.KeyboardButton button) { + if (chatMode == MODE_QUICK_REPLIES) return; if (getParentActivity() == null || bottomOverlayChat.getVisibility() == View.VISIBLE && !(button instanceof TLRPC.TL_keyboardButtonSwitchInline) && !(button instanceof TLRPC.TL_keyboardButtonCallback) && !(button instanceof TLRPC.TL_keyboardButtonGame) && !(button instanceof TLRPC.TL_keyboardButtonUrl) && @@ -32901,7 +33150,7 @@ public void needShowPremiumBulletin(int type) { topUndoView.performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP, HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING); } catch (Exception ignored) {} } else if (type == 1) { - String until = LocaleController.formatDateTime(getMessagesController().transcribeAudioTrialCooldownUntil); + String until = LocaleController.formatDateTime(getMessagesController().transcribeAudioTrialCooldownUntil, true); CharSequence text = getMessagesController().transcribeAudioTrialCooldownUntil > 0 ? AndroidUtilities.replaceTags(LocaleController.formatPluralString("TranscriptionTrialLeftUntil", TranscribeButton.getTranscribeTrialCount(currentAccount), until)) : AndroidUtilities.replaceTags(LocaleController.formatPluralString("TranscriptionTrialLeft", TranscribeButton.getTranscribeTrialCount(currentAccount))); @@ -32910,7 +33159,7 @@ public void needShowPremiumBulletin(int type) { fragmentView.performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP, HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING); } catch (Exception ignored) {} } else if (type == 2 || type == 3) { - String until = LocaleController.formatDateTime(getMessagesController().transcribeAudioTrialCooldownUntil); + String until = LocaleController.formatDateTime(getMessagesController().transcribeAudioTrialCooldownUntil, true); BulletinFactory.of(ChatActivity.this).createSimpleBulletin( R.raw.transcribe, new SpannableStringBuilder().append( @@ -32936,6 +33185,7 @@ public void needShowPremiumBulletin(int type) { @Override public void didLongPressBotButton(ChatMessageCell cell, TLRPC.KeyboardButton button) { + if (chatMode == MODE_QUICK_REPLIES) return; if (getParentActivity() == null || bottomOverlayChat.getVisibility() == View.VISIBLE && !(button instanceof TLRPC.TL_keyboardButtonSwitchInline) && !(button instanceof TLRPC.TL_keyboardButtonCallback) && !(button instanceof TLRPC.TL_keyboardButtonGame) && !(button instanceof TLRPC.TL_keyboardButtonUrl) && @@ -33676,7 +33926,10 @@ public void didPressImage(ChatMessageCell cell, float x, float y) { } undoView.showWithAction(0, chatActivityEnterView.getVisibility() == View.VISIBLE && bottomOverlay.getVisibility() != View.VISIBLE ? UndoView.ACTION_DICE_INFO : UndoView.ACTION_DICE_NO_SEND_INFO, message.getDiceEmoji(), null, () -> { if (checkSlowModeAlert()) { - getSendMessagesHelper().sendMessage(SendMessagesHelper.SendMessageParams.of(message.getDiceEmoji(), dialog_id, replyingMessageObject, getThreadMessage(), null, false, null, null, null, true, 0, null, false)); + SendMessagesHelper.SendMessageParams params = SendMessagesHelper.SendMessageParams.of(message.getDiceEmoji(), dialog_id, replyingMessageObject, getThreadMessage(), null, false, null, null, null, true, 0, null, false); + params.quick_reply_shortcut_id = getQuickReplyId(); + params.quick_reply_shortcut = quickReplyShortcut; + getSendMessagesHelper().sendMessage(params); } }); } else if (message.isAnimatedEmoji() && (!message.isAnimatedAnimatedEmoji() || emojiAnimationsOverlay.supports(MessageObject.findAnimatedEmojiEmoticon(message.getDocument())) && currentUser != null) || message.isPremiumSticker()) { @@ -34345,6 +34598,10 @@ public void setPreloadedSticker(TLRPC.Document preloadedSticker, boolean history forceHistoryEmpty = historyEmpty; } + public void forceEmptyHistory() { + forceHistoryEmpty = true; + } + public class ChatScrollCallback extends RecyclerAnimationScrollHelper.AnimationCallback { private MessageObject scrollTo; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ChatActivityContainer.java b/TMessagesProj/src/main/java/org/telegram/ui/ChatActivityContainer.java index 0e004d6d3c7..1c723a431ec 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ChatActivityContainer.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ChatActivityContainer.java @@ -15,6 +15,7 @@ import com.google.android.exoplayer2.util.Log; import org.telegram.messenger.Utilities; +import org.telegram.ui.ActionBar.ActionBar; import org.telegram.ui.ActionBar.BaseFragment; import org.telegram.ui.ActionBar.DrawerLayoutContainer; import org.telegram.ui.ActionBar.INavigationLayout; @@ -31,7 +32,12 @@ public class ChatActivityContainer extends FrameLayout { private final INavigationLayout parentLayout; private View fragmentView; - public ChatActivityContainer(Context context, Utilities.Callback0Return resizableView, INavigationLayout parentLayout, Bundle args) { + public ChatActivityContainer( + Context context, + Utilities.Callback0Return resizableView, + INavigationLayout parentLayout, + Bundle args + ) { super(context); this.parentLayout = parentLayout; 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 ef3b2e35e4c..b656c3a010a 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/AlertsCreator.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/AlertsCreator.java @@ -8,6 +8,8 @@ package org.telegram.ui.Components; +import static org.telegram.messenger.AndroidUtilities.dp; + import android.Manifest; import android.annotation.SuppressLint; import android.app.Activity; @@ -17,6 +19,7 @@ import android.content.Intent; import android.content.SharedPreferences; import android.content.pm.PackageManager; +import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Outline; import android.graphics.PorterDuff; @@ -42,6 +45,7 @@ import android.text.TextWatcher; import android.text.style.URLSpan; import android.util.Base64; +import android.util.Pair; import android.util.SparseArray; import android.util.TypedValue; import android.view.Gravity; @@ -99,6 +103,7 @@ import org.telegram.ui.ActionBar.BaseFragment; import org.telegram.ui.ActionBar.BottomSheet; import org.telegram.ui.ActionBar.Theme; +import org.telegram.ui.Business.TimezonesController; import org.telegram.ui.CacheControlActivity; import org.telegram.ui.Cells.AccountSelectCell; import org.telegram.ui.Cells.CheckBoxCell; @@ -113,18 +118,29 @@ import org.telegram.ui.NotificationsCustomSettingsActivity; import org.telegram.ui.NotificationsSettingsActivity; import org.telegram.ui.ProfileNotificationsActivity; +import org.telegram.ui.Stories.recorder.ButtonWithCounterView; import org.telegram.ui.ThemePreviewActivity; import org.telegram.ui.TooManyCommunitiesActivity; import java.net.IDN; +import java.time.Instant; +import java.time.ZoneId; +import java.time.ZoneOffset; +import java.time.temporal.ChronoField; +import java.time.temporal.TemporalField; import java.util.ArrayList; import java.util.Arrays; import java.util.Calendar; +import java.util.Collection; +import java.util.Collections; +import java.util.Comparator; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Locale; import java.util.Map; +import java.util.Set; +import java.util.TimeZone; import java.util.concurrent.CountDownLatch; import java.util.concurrent.atomic.AtomicBoolean; @@ -686,7 +702,7 @@ public void onClick(View widget) { message.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16); message.setLinkTextColor(Theme.getColor(Theme.key_dialogTextLink)); message.setHighlightColor(Theme.getColor(Theme.key_dialogLinkSelection)); - message.setPadding(AndroidUtilities.dp(23), 0, AndroidUtilities.dp(23), 0); + message.setPadding(dp(23), 0, dp(23), 0); message.setMovementMethod(new AndroidUtilities.LinkMovementMethodMy()); message.setTextColor(Theme.getColor(Theme.key_dialogTextBlack)); builder.setView(message); @@ -815,7 +831,7 @@ public static void showBlockReportSpamReplyAlert(ChatActivity fragment, MessageO cells[0].setTag(0); cells[0].setText(LocaleController.getString("DeleteReportSpam", R.string.DeleteReportSpam), "", true, false); - cells[0].setPadding(LocaleController.isRTL ? AndroidUtilities.dp(16) : AndroidUtilities.dp(8), 0, LocaleController.isRTL ? AndroidUtilities.dp(8) : AndroidUtilities.dp(16), 0); + cells[0].setPadding(LocaleController.isRTL ? dp(16) : dp(8), 0, LocaleController.isRTL ? dp(8) : dp(16), 0); linearLayout.addView(cells[0], LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); cells[0].setOnClickListener(v -> { Integer num = (Integer) v.getTag(); @@ -894,7 +910,7 @@ public static void showBlockReportSpamAlert(BaseFragment fragment, long dialog_i } else { cells[a].setText(LocaleController.formatString("DeleteThisChat", R.string.DeleteThisChat), "", true, false); } - cells[a].setPadding(LocaleController.isRTL ? AndroidUtilities.dp(16) : AndroidUtilities.dp(8), 0, LocaleController.isRTL ? AndroidUtilities.dp(8) : AndroidUtilities.dp(16), 0); + cells[a].setPadding(LocaleController.isRTL ? dp(16) : dp(8), 0, LocaleController.isRTL ? dp(8) : dp(16), 0); linearLayout.addView(cells[a], LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); cells[a].setOnClickListener(v -> { Integer num = (Integer) v.getTag(); @@ -1003,10 +1019,10 @@ public static void showCustomNotificationsDialog(BaseFragment parentFragment, lo textView.setCompoundDrawablesWithIntrinsicBounds(drawable, null, null, null); textView.setTag(a); textView.setBackgroundDrawable(Theme.getSelectorDrawable(false)); - textView.setPadding(AndroidUtilities.dp(24), 0, AndroidUtilities.dp(24), 0); + textView.setPadding(dp(24), 0, dp(24), 0); textView.setSingleLine(true); textView.setGravity(Gravity.LEFT | Gravity.CENTER_VERTICAL); - textView.setCompoundDrawablePadding(AndroidUtilities.dp(26)); + textView.setCompoundDrawablePadding(dp(26)); textView.setText(descriptions[a]); linearLayout.addView(textView, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 48, Gravity.LEFT | Gravity.TOP)); textView.setOnClickListener(v -> { @@ -1120,7 +1136,7 @@ public static AlertDialog showSecretLocationAlert(Context context, int currentAc for (int a = 0; a < arrayList.size(); a++) { RadioColorCell cell = new RadioColorCell(context, resourcesProvider); - cell.setPadding(AndroidUtilities.dp(4), 0, AndroidUtilities.dp(4), 0); + cell.setPadding(dp(4), 0, dp(4), 0); cell.setTag(a); cell.setCheckColor(Theme.getColor(Theme.key_radioBackground), Theme.getColor(Theme.key_dialogRadioBackgroundChecked)); cell.setTextAndValue(arrayList.get(a), SharedConfig.mapPreviewType == types.get(a)); @@ -1261,7 +1277,7 @@ public void onClick(View widget) { message.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16); message.setLinkTextColor(Theme.getColor(Theme.key_dialogTextLink, resourcesProvider)); message.setHighlightColor(Theme.getColor(Theme.key_dialogLinkSelection, resourcesProvider)); - message.setPadding(AndroidUtilities.dp(23), 0, AndroidUtilities.dp(23), 0); + message.setPadding(dp(23), 0, dp(23), 0); message.setMovementMethod(new AndroidUtilities.LinkMovementMethodMy()); message.setTextColor(Theme.getColor(Theme.key_dialogTextBlack, resourcesProvider)); @@ -1366,10 +1382,10 @@ public static void createImportDialogAlert(BaseFragment fragment, String title, builder.setView(frameLayout); AvatarDrawable avatarDrawable = new AvatarDrawable(); - avatarDrawable.setTextSize(AndroidUtilities.dp(12)); + avatarDrawable.setTextSize(dp(12)); BackupImageView imageView = new BackupImageView(context); - imageView.setRoundRadius(AndroidUtilities.dp(20)); + imageView.setRoundRadius(dp(20)); frameLayout.addView(imageView, LayoutHelper.createFrame(40, 40, (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.TOP, 22, 5, 22, 0)); TextView textView = new TextView(context); @@ -1452,10 +1468,10 @@ public void setText(CharSequence text, BufferType type) { builder.setView(frameLayout); AvatarDrawable avatarDrawable = new AvatarDrawable(); - avatarDrawable.setTextSize(AndroidUtilities.dp(18)); + avatarDrawable.setTextSize(dp(18)); BackupImageView imageView = new BackupImageView(context); - imageView.setRoundRadius(AndroidUtilities.dp(20)); + imageView.setRoundRadius(dp(20)); frameLayout.addView(imageView, LayoutHelper.createFrame(40, 40, (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.TOP, 22, 5, 22, 0)); TextView textView = new TextView(context); @@ -1522,7 +1538,7 @@ public void setText(CharSequence text, BufferType type) { protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); if (cell[0] != null) { - setMeasuredDimension(getMeasuredWidth(), getMeasuredHeight() + cell[0].getMeasuredHeight() + AndroidUtilities.dp(7)); + setMeasuredDimension(getMeasuredWidth(), getMeasuredHeight() + cell[0].getMeasuredHeight() + dp(7)); } } }; @@ -1530,10 +1546,10 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { builder.setView(frameLayout); AvatarDrawable avatarDrawable = new AvatarDrawable(); - avatarDrawable.setTextSize(AndroidUtilities.dp(18)); + avatarDrawable.setTextSize(dp(18)); BackupImageView imageView = new BackupImageView(context); - imageView.setRoundRadius(AndroidUtilities.dp(20)); + imageView.setRoundRadius(dp(20)); frameLayout.addView(imageView, LayoutHelper.createFrame(40, 40, (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.TOP, 22, 5, 22, 0)); TextView titleView = new TextView(context); @@ -1567,7 +1583,7 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { SpannableString ssb = SpannableString.valueOf(LocaleController.getString(R.string.MoreAboutThisBot) + " "); ColoredImageSpan img = new ColoredImageSpan(R.drawable.attach_arrow_right); img.setTopOffset(1); - img.setSize(AndroidUtilities.dp(10)); + img.setSize(dp(10)); ssb.setSpan(img, ssb.length() - 1, ssb.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); subtitleView.setText(ssb); @@ -1582,7 +1598,7 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { cell[0].allowMultiline(); cell[0].setBackgroundDrawable(Theme.getSelectorDrawable(false)); cell[0].setText(AndroidUtilities.replaceTags(LocaleController.formatString("OpenUrlOption2", R.string.OpenUrlOption2, UserObject.getUserName(user))), "", true, false); - cell[0].setPadding(LocaleController.isRTL ? AndroidUtilities.dp(16) : AndroidUtilities.dp(8), 0, LocaleController.isRTL ? AndroidUtilities.dp(8) : AndroidUtilities.dp(16), 0); + cell[0].setPadding(LocaleController.isRTL ? dp(16) : dp(8), 0, LocaleController.isRTL ? dp(8) : dp(16), 0); cell[0].setChecked(true, false); frameLayout.addView(cell[0], LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 48, Gravity.BOTTOM | Gravity.LEFT, 0, 0, 0, 0)); cell[0].setOnClickListener(v -> { @@ -1652,7 +1668,7 @@ public void setText(CharSequence text, BufferType type) { protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); if (cell[0] != null) { - setMeasuredDimension(getMeasuredWidth(), getMeasuredHeight() + cell[0].getMeasuredHeight() + AndroidUtilities.dp(7)); + setMeasuredDimension(getMeasuredWidth(), getMeasuredHeight() + cell[0].getMeasuredHeight() + dp(7)); } } }; @@ -1660,10 +1676,10 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { builder.setView(frameLayout); AvatarDrawable avatarDrawable = new AvatarDrawable(); - avatarDrawable.setTextSize(AndroidUtilities.dp(18)); + avatarDrawable.setTextSize(dp(18)); BackupImageView imageView = new BackupImageView(context); - imageView.setRoundRadius(AndroidUtilities.dp(20)); + imageView.setRoundRadius(dp(20)); frameLayout.addView(imageView, LayoutHelper.createFrame(40, 40, (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.TOP, 22, 5, 22, 0)); TextView textView = new TextView(context); @@ -1732,7 +1748,7 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { cell[0] = new CheckBoxCell(context, 1, resourcesProvider); cell[0].setBackgroundDrawable(Theme.getSelectorDrawable(false)); cell[0].setText(LocaleController.getString(R.string.BlockBot), "", false, false); - cell[0].setPadding(LocaleController.isRTL ? AndroidUtilities.dp(16) : AndroidUtilities.dp(8), 0, LocaleController.isRTL ? AndroidUtilities.dp(8) : AndroidUtilities.dp(16), 0); + cell[0].setPadding(LocaleController.isRTL ? dp(16) : dp(8), 0, LocaleController.isRTL ? dp(8) : dp(16), 0); cell[0].setChecked(deleteForAll[0] = true, false); frameLayout.addView(cell[0], LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 48, Gravity.BOTTOM | Gravity.LEFT, 0, 0, 0, 0)); cell[0].setOnClickListener(v -> { @@ -1754,7 +1770,7 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { } 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); + cell[0].setPadding(LocaleController.isRTL ? dp(16) : dp(8), 0, LocaleController.isRTL ? dp(8) : dp(16), 0); frameLayout.addView(cell[0], LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 48, Gravity.BOTTOM | Gravity.LEFT, 0, 0, 0, 0)); cell[0].setOnClickListener(v -> { CheckBoxCell cell1 = (CheckBoxCell) v; @@ -1955,7 +1971,7 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { TextView textView = new TextView(context); textView.setTextColor(Theme.getColor(Theme.key_actionBarDefaultSubmenuItem)); textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 20); - textView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); + textView.setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)); textView.setLines(1); textView.setMaxLines(1); textView.setSingleLine(true); @@ -2001,7 +2017,7 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 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); + cell[0].setPadding(LocaleController.isRTL ? dp(16) : dp(8), 0, LocaleController.isRTL ? dp(8) : dp(16), 0); frameLayout.addView(cell[0], LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 48, Gravity.BOTTOM | Gravity.LEFT, 0, 0, 0, 0)); cell[0].setChecked(false, false); @@ -2061,19 +2077,19 @@ public void setText(CharSequence text, BufferType type) { messageTextView.setText(AndroidUtilities.replaceTags(message)); AvatarDrawable avatarDrawable = new AvatarDrawable(); - avatarDrawable.setTextSize(AndroidUtilities.dp(12)); + avatarDrawable.setTextSize(dp(12)); avatarDrawable.setScaleSize(1f); avatarDrawable.setInfo(fragment.getCurrentAccount(), user); BackupImageView imageView = new BackupImageView(context); - imageView.setRoundRadius(AndroidUtilities.dp(20)); + imageView.setRoundRadius(dp(20)); imageView.setForUserOrChat(user, avatarDrawable); frameLayout.addView(imageView, LayoutHelper.createFrame(40, 40, (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.TOP, 22, 5, 22, 0)); TextView textView = new TextView(context); textView.setTextColor(Theme.getColor(Theme.key_actionBarDefaultSubmenuItem)); textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 20); - textView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); + textView.setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)); textView.setLines(1); textView.setMaxLines(1); textView.setSingleLine(true); @@ -2141,7 +2157,7 @@ public CharSequence filter(CharSequence source, int start, int end, Spanned dest checkTextView.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteGrayText4)); checkTextView.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO); dialogView.addView(checkTextView, LayoutHelper.createFrame(20, 20, LocaleController.isRTL ? Gravity.LEFT : Gravity.RIGHT, 0, 14, 21, 0)); - editTextView.setPadding(LocaleController.isRTL ? AndroidUtilities.dp(24) : 0, AndroidUtilities.dp(8), LocaleController.isRTL ? 0 : AndroidUtilities.dp(24), AndroidUtilities.dp(8)); + editTextView.setPadding(LocaleController.isRTL ? dp(24) : 0, dp(8), LocaleController.isRTL ? 0 : dp(24), dp(8)); editTextView.addTextChangedListener(new TextWatcher() { @Override public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) { @@ -2264,7 +2280,7 @@ public static void createChangeNameAlert(long peerId, Context context, int curre firstNameEditTextView.setImeOptions(peerId > 0 ? EditorInfo.IME_ACTION_NEXT : EditorInfo.IME_ACTION_DONE); firstNameEditTextView.setHint(peerId > 0 ? LocaleController.getString("FirstName", R.string.FirstName) : LocaleController.getString("VoipEditTitleHint", R.string.VoipEditTitleHint)); firstNameEditTextView.setBackground(Theme.createEditTextDrawable(context, true)); - firstNameEditTextView.setPadding(0, AndroidUtilities.dp(8), 0, AndroidUtilities.dp(8)); + firstNameEditTextView.setPadding(0, dp(8), 0, dp(8)); firstNameEditTextView.requestFocus(); EditText lastNameEditTextView = null; @@ -2280,7 +2296,7 @@ public static void createChangeNameAlert(long peerId, Context context, int curre lastNameEditTextView.setImeOptions(EditorInfo.IME_ACTION_DONE); lastNameEditTextView.setHint(LocaleController.getString("LastName", R.string.LastName)); lastNameEditTextView.setBackground(Theme.createEditTextDrawable(context, true)); - lastNameEditTextView.setPadding(0, AndroidUtilities.dp(8), 0, AndroidUtilities.dp(8)); + lastNameEditTextView.setPadding(0, dp(8), 0, dp(8)); } AndroidUtilities.showKeyboard(firstNameEditTextView); @@ -2396,14 +2412,14 @@ public static void showChatWithAdmin(BaseFragment fragment, TLRPC.User user, Str TextView buttonTextView = new TextView(fragment.getParentActivity()); - buttonTextView.setPadding(AndroidUtilities.dp(34), 0, AndroidUtilities.dp(34), 0); + buttonTextView.setPadding(dp(34), 0, dp(34), 0); buttonTextView.setGravity(Gravity.CENTER); buttonTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); - buttonTextView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); + buttonTextView.setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)); buttonTextView.setText(LocaleController.getString("IUnderstand", R.string.IUnderstand)); buttonTextView.setTextColor(Theme.getColor(Theme.key_featuredStickers_buttonText)); - buttonTextView.setBackground(Theme.createSimpleSelectorRoundRectDrawable(AndroidUtilities.dp(8), Theme.getColor(Theme.key_featuredStickers_addButton), Theme.getColor(Theme.key_featuredStickers_addButtonPressed))); + buttonTextView.setBackground(Theme.createSimpleSelectorRoundRectDrawable(dp(8), Theme.getColor(Theme.key_featuredStickers_addButton), Theme.getColor(Theme.key_featuredStickers_addButtonPressed))); linearLayout.addView(buttonTextView, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 48, 0, 16, 12, 16, 8)); @@ -2466,7 +2482,7 @@ public static ActionBarPopupWindow createSimplePopup(BaseFragment fragment, View popupWindow.setClippingEnabled(true); popupWindow.setAnimationStyle(R.style.PopupContextAnimation); popupWindow.setFocusable(true); - popupView.measure(View.MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(1000), View.MeasureSpec.AT_MOST), View.MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(1000), View.MeasureSpec.AT_MOST)); + popupView.measure(View.MeasureSpec.makeMeasureSpec(dp(1000), View.MeasureSpec.AT_MOST), View.MeasureSpec.makeMeasureSpec(dp(1000), View.MeasureSpec.AT_MOST)); popupWindow.setInputMethodMode(ActionBarPopupWindow.INPUT_METHOD_NOT_NEEDED); popupWindow.getContentView().setFocusableInTouchMode(true); float viewX = 0, viewY = 0; @@ -2557,7 +2573,7 @@ public static void createBlockDialogAlert(BaseFragment fragment, int count, bool } else { cell[a].setText(count == 1 ? LocaleController.getString("DeleteThisChatBothSides", R.string.DeleteThisChatBothSides) : LocaleController.getString("DeleteTheseChatsBothSides", R.string.DeleteTheseChatsBothSides), "", true, false); } - cell[a].setPadding(LocaleController.isRTL ? AndroidUtilities.dp(16) : AndroidUtilities.dp(8), 0, LocaleController.isRTL ? AndroidUtilities.dp(8) : AndroidUtilities.dp(16), 0); + cell[a].setPadding(LocaleController.isRTL ? dp(16) : dp(8), 0, LocaleController.isRTL ? dp(8) : dp(16), 0); linearLayout.addView(cell[a], LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 48)); cell[a].setOnClickListener(v -> { CheckBoxCell cell1 = (CheckBoxCell) v; @@ -2580,6 +2596,298 @@ public interface DatePickerDelegate { void didSelectDate(int year, int month, int dayOfMonth); } + public static BottomSheet createTimezonePickerDialog(Context context, String title, String timezoneId, final Utilities.Callback whenPicked) { + final int currentAccount = UserConfig.selectedAccount; + if (TimezonesController.getInstance(currentAccount).getTimezones().isEmpty()) { + return null; + } + + ArrayList timezones = new ArrayList<>(TimezonesController.getInstance(currentAccount).getTimezones()); + Collections.sort(timezones, (a, b) -> a.utc_offset - b.utc_offset); + + ScheduleDatePickerColors datePickerColors = new ScheduleDatePickerColors(); + + BottomSheet.Builder builder = new BottomSheet.Builder(context, false, null); + builder.setApplyBottomPadding(false); + + LinearLayout linearLayout = new LinearLayout(context); + linearLayout.setOrientation(LinearLayout.HORIZONTAL); + linearLayout.setWeightSum(1f); + + final NumberPicker picker = new NumberPicker(context) { + @Override + protected CharSequence getContentDescription(int value) { + return TimezonesController.getInstance(currentAccount).getTimezoneName(timezones.get(value), true); + } + }; + picker.setAllItemsCount(24); + picker.setItemCount(8); + picker.setTextColor(datePickerColors.textColor); + picker.setGravity(Gravity.CENTER); + picker.setMinValue(0); + picker.setMaxValue(timezones.size() - 1); + for (int i = 0; i < timezones.size(); ++i) { + if (TextUtils.equals(timezoneId, timezones.get(i).id)) { + picker.setValue(i); + break; + } + } + + linearLayout.addView(picker, LayoutHelper.createLinear(0, 54 * 8, 1f)); + picker.setFormatter(value -> { + return TimezonesController.getInstance(currentAccount).getTimezoneName(timezones.get(value), true); + }); + + LinearLayout container = new LinearLayout(context) { + boolean ignoreLayout = false; + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + ignoreLayout = true; + picker.getLayoutParams().height = dp(NumberPicker.DEFAULT_SIZE_PER_COUNT) * 8; + ignoreLayout = false; + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + } + + @Override + public void requestLayout() { + if (ignoreLayout) { + return; + } + super.requestLayout(); + } + }; + container.setOrientation(LinearLayout.VERTICAL); + + FrameLayout titleLayout = new FrameLayout(context); + + TextView titleView = new TextView(context); + titleView.setText(title); + titleView.setTextColor(datePickerColors.textColor); + titleView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 20); + titleView.setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)); + titleLayout.addView(titleView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.LEFT | Gravity.TOP, 0, 12, 0, 0)); + titleView.setOnTouchListener((v, event) -> true); + container.addView(titleLayout, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.LEFT | Gravity.TOP, 22, 0, 0, 4)); + + container.addView(linearLayout, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, 1f, 0, 0, 12, 0, 12)); + + BottomSheet[] sheet = new BottomSheet[1]; + + ButtonWithCounterView button = new ButtonWithCounterView(context, null); + button.setText(LocaleController.getString(R.string.Select), false); + button.setOnClickListener(v -> sheet[0].dismiss()); + container.addView(button, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 48, 0, 16, 12, 16, 12)); + + builder.setCustomView(container); + BottomSheet bottomSheet = builder.show(); + bottomSheet.setOnDismissListener(dialog -> { + whenPicked.run(timezones.get(picker.getValue()).id); + }); + bottomSheet.setBackgroundColor(datePickerColors.backgroundColor); + bottomSheet.fixNavigationBar(datePickerColors.backgroundColor); + + return sheet[0] = builder.create(); + } + + public static BottomSheet createTimePickerDialog(Context context, String title, int time, int minTime, int maxTime, final Utilities.Callback whenPicked) { + if (context == null) { + return null; + } + + ScheduleDatePickerColors datePickerColors = new ScheduleDatePickerColors(); + + BottomSheet.Builder builder = new BottomSheet.Builder(context, false, null); + builder.setApplyBottomPadding(false); + + final NumberPicker hourPicker = new NumberPicker(context) { + @Override + protected CharSequence getContentDescription(int value) { + return LocaleController.formatPluralString("Hours", value); + } + }; + + LinearLayout linearLayout = new LinearLayout(context) { + private final Text separatorText = new Text(":", 18); + private boolean isAM; + private Text ampmText; + @Override + protected void dispatchDraw(Canvas canvas) { + separatorText.draw(canvas, (getWidth() - separatorText.getCurrentWidth()) / 2f, getHeight() / 2f, Theme.getColor(Theme.key_windowBackgroundWhiteBlackText), 1f); + if (!LocaleController.is24HourFormat) { + final boolean isAM = (hourPicker.getValue() % 24) < 12; + if (this.isAM != isAM || ampmText == null) { + this.isAM = isAM; + ampmText = new Text(isAM ? "AM" : "PM", 18); + } + ampmText.draw(canvas, getWidth() / 2f + dp(43), getHeight() / 2f + dp(1), Theme.getColor(Theme.key_windowBackgroundWhiteBlackText), 1f); + } + super.dispatchDraw(canvas); + } + }; + linearLayout.setOrientation(LinearLayout.HORIZONTAL); + linearLayout.setWeightSum(1f); + hourPicker.setAllItemsCount(24); + hourPicker.setItemCount(5); + hourPicker.setTextColor(datePickerColors.textColor); + hourPicker.setGravity(Gravity.RIGHT); + hourPicker.setTextOffset(-dp(12)); + + final NumberPicker minutePicker = new NumberPicker(context) { + @Override + protected CharSequence getContentDescription(int value) { + return LocaleController.formatPluralString("Minutes", value); + } + }; + minutePicker.setWrapSelectorWheel(true); + minutePicker.setAllItemsCount(60); + minutePicker.setItemCount(5); + minutePicker.setTextColor(datePickerColors.textColor); + minutePicker.setGravity(Gravity.LEFT); + minutePicker.setTextOffset(dp(12)); + final Utilities.Callback checkValue = (byChange) -> { + if (byChange) { + try { + linearLayout.performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP, HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING); + } catch (Exception ignore) { + } + } + + int minTimeMinutes = minTime % 60; + int minTimeHours = (minTime - minTimeMinutes) / 60; + int maxTimeMinutes = maxTime % 60; + int maxTimeHours = (maxTime - maxTimeMinutes) / 60; + if (maxTimeMinutes == 0 && maxTimeHours > 0) { + maxTimeHours--; + maxTimeMinutes = 59; + } + + int hour, minutes; + if (byChange) { + hour = hourPicker.getValue(); + minutes = minutePicker.getValue(); + } else { + minutes = time % 60; + hour = (time - minutes) / 60; + if (hour == 24) { + hour--; + minutes = 59; + } + } + hourPicker.setMinValue(minTimeHours); + hourPicker.setMaxValue(maxTimeHours); + if (hour > maxTimeHours) { + hourPicker.setValue(hour = maxTimeHours); + } else if (hour < minTimeHours) { + hourPicker.setValue(hour = minTimeHours); + } + if (hour <= minTimeHours) { + minutePicker.setMinValue(minTimeMinutes); + minutePicker.setMaxValue(minTimeHours == maxTimeHours ? maxTimeMinutes : 59); + } else if (hour >= maxTimeHours) { + minutePicker.setMinValue(minTimeHours == maxTimeHours ? minTimeMinutes : 0); + minutePicker.setMaxValue(maxTimeMinutes); + } else { + if (minTimeHours == maxTimeHours) { + minutePicker.setMinValue(minTimeMinutes); + minutePicker.setMaxValue(maxTimeMinutes); + } else { + minutePicker.setMinValue(0); + minutePicker.setMaxValue(59); + } + } + if (minutes > minutePicker.getMaxValue()) { + minutePicker.setValue(minutes = minutePicker.getMaxValue()); + } else if (minutes < minutePicker.getMinValue()) { + minutePicker.setValue(minutes = minutePicker.getMinValue()); + } + if (!byChange) { + hourPicker.setValue(hour); + minutePicker.setValue(minutes); + } + linearLayout.invalidate(); + }; + + linearLayout.addView(hourPicker, LayoutHelper.createLinear(0, 54 * 5, 0.5f)); + hourPicker.setFormatter(value -> { + int h = value % (LocaleController.is24HourFormat ? 24 : 12); + if ((value % 12) == 0 && !LocaleController.is24HourFormat) { + h = 12; + } + String str = String.format("%02d", h); + if (value >= 24) { + return LocaleController.formatString(R.string.BusinessHoursNextDayPicker, str); + } + return str; + }); + hourPicker.setOnValueChangedListener((p, v, o) -> checkValue.run(true)); + + linearLayout.addView(minutePicker, LayoutHelper.createLinear(0, 54 * 5, 0.5f)); + minutePicker.setFormatter(value -> String.format("%02d", value)); + minutePicker.setOnValueChangedListener((p, v, o) -> checkValue.run(true)); + checkValue.run(false); + + 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; + } + hourPicker.setItemCount(count); + minutePicker.setItemCount(count); + hourPicker.getLayoutParams().height = dp(NumberPicker.DEFAULT_SIZE_PER_COUNT) * count; + minutePicker.getLayoutParams().height = 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); + + TextView titleView = new TextView(context); + titleView.setText(title); + titleView.setTextColor(datePickerColors.textColor); + titleView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 20); + titleView.setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)); + titleLayout.addView(titleView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.LEFT | Gravity.TOP, 0, 12, 0, 0)); + titleView.setOnTouchListener((v, event) -> true); + container.addView(titleLayout, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.LEFT | Gravity.TOP, 22, 0, 0, 4)); + + container.addView(linearLayout, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, 1f, 0, 0, 12, 0, 12)); + + BottomSheet[] sheet = new BottomSheet[1]; + + ButtonWithCounterView button = new ButtonWithCounterView(context, null); + button.setText(LocaleController.getString(R.string.Select), false); + button.setOnClickListener(v -> sheet[0].dismiss()); + container.addView(button, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 48, 0, 16, 12, 16, 12)); + + builder.setCustomView(container); + BottomSheet bottomSheet = builder.show(); + bottomSheet.setOnDismissListener(dialog -> { + whenPicked.run(hourPicker.getValue() * 60 + minutePicker.getValue()); + }); + bottomSheet.setBackgroundColor(datePickerColors.backgroundColor); + bottomSheet.fixNavigationBar(datePickerColors.backgroundColor); + + return sheet[0] = builder.create(); + } + public static AlertDialog.Builder createDatePickerDialog(Context context, int minYear, int maxYear, int currentYearDiff, int selectedDay, int selectedMonth, int selectedYear, String title, final boolean checkMinDate, final DatePickerDelegate datePickerDelegate) { if (context == null) { return null; @@ -2850,7 +3158,7 @@ public static BottomSheet.Builder createScheduleDatePickerDialog(Context context final NumberPicker dayPicker = new NumberPicker(context, resourcesProvider); dayPicker.setTextColor(datePickerColors.textColor); - dayPicker.setTextOffset(AndroidUtilities.dp(10)); + dayPicker.setTextOffset(dp(10)); dayPicker.setItemCount(5); final NumberPicker hourPicker = new NumberPicker(context, resourcesProvider) { @Override @@ -2862,7 +3170,7 @@ protected CharSequence getContentDescription(int value) { hourPicker.setAllItemsCount(24); hourPicker.setItemCount(5); hourPicker.setTextColor(datePickerColors.textColor); - hourPicker.setTextOffset(-AndroidUtilities.dp(10)); + hourPicker.setTextOffset(-dp(10)); final NumberPicker minutePicker = new NumberPicker(context, resourcesProvider) { @Override protected CharSequence getContentDescription(int value) { @@ -2873,7 +3181,7 @@ protected CharSequence getContentDescription(int value) { minutePicker.setAllItemsCount(60); minutePicker.setItemCount(5); minutePicker.setTextColor(datePickerColors.textColor); - minutePicker.setTextOffset(-AndroidUtilities.dp(34)); + minutePicker.setTextOffset(-dp(34)); LinearLayout container = new LinearLayout(context) { @@ -2891,9 +3199,9 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { dayPicker.setItemCount(count); hourPicker.setItemCount(count); minutePicker.setItemCount(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; + dayPicker.getLayoutParams().height = dp(NumberPicker.DEFAULT_SIZE_PER_COUNT) * count; + hourPicker.getLayoutParams().height = dp(NumberPicker.DEFAULT_SIZE_PER_COUNT) * count; + minutePicker.getLayoutParams().height = dp(NumberPicker.DEFAULT_SIZE_PER_COUNT) * count; ignoreLayout = false; super.onMeasure(widthMeasureSpec, heightMeasureSpec); } @@ -3035,7 +3343,7 @@ public CharSequence getAccessibilityClassName() { checkScheduleDate(buttonTextView, null, selfUserId == dialogId ? 1 : 0, dayPicker, hourPicker, minutePicker); - buttonTextView.setPadding(AndroidUtilities.dp(34), 0, AndroidUtilities.dp(34), 0); + buttonTextView.setPadding(dp(34), 0, dp(34), 0); buttonTextView.setGravity(Gravity.CENTER); buttonTextView.setTextColor(datePickerColors.buttonTextColor); buttonTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); @@ -3067,7 +3375,7 @@ public CharSequence getAccessibilityClassName() { return builder; } - public static BottomSheet.Builder createDatePickerDialog(Context context, long currentDate, final ScheduleDatePickerDelegate datePickerDelegate) { + public static BottomSheet.Builder createDatePickerDialog(Context context, String title, String button, long currentDate, final ScheduleDatePickerDelegate datePickerDelegate) { if (context == null) { return null; } @@ -3078,7 +3386,7 @@ public static BottomSheet.Builder createDatePickerDialog(Context context, long c final NumberPicker dayPicker = new NumberPicker(context); dayPicker.setTextColor(datePickerColors.textColor); - dayPicker.setTextOffset(AndroidUtilities.dp(10)); + dayPicker.setTextOffset(dp(10)); dayPicker.setItemCount(5); final NumberPicker hourPicker = new NumberPicker(context) { @Override @@ -3088,7 +3396,7 @@ protected CharSequence getContentDescription(int value) { }; hourPicker.setItemCount(5); hourPicker.setTextColor(datePickerColors.textColor); - hourPicker.setTextOffset(-AndroidUtilities.dp(10)); + hourPicker.setTextOffset(-dp(10)); final NumberPicker minutePicker = new NumberPicker(context) { @Override protected CharSequence getContentDescription(int value) { @@ -3097,7 +3405,7 @@ protected CharSequence getContentDescription(int value) { }; minutePicker.setItemCount(5); minutePicker.setTextColor(datePickerColors.textColor); - minutePicker.setTextOffset(-AndroidUtilities.dp(34)); + minutePicker.setTextOffset(-dp(34)); LinearLayout container = new LinearLayout(context) { @@ -3115,9 +3423,9 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { dayPicker.setItemCount(count); hourPicker.setItemCount(count); minutePicker.setItemCount(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; + dayPicker.getLayoutParams().height = dp(NumberPicker.DEFAULT_SIZE_PER_COUNT) * count; + hourPicker.getLayoutParams().height = dp(NumberPicker.DEFAULT_SIZE_PER_COUNT) * count; + minutePicker.getLayoutParams().height = dp(NumberPicker.DEFAULT_SIZE_PER_COUNT) * count; ignoreLayout = false; super.onMeasure(widthMeasureSpec, heightMeasureSpec); } @@ -3136,7 +3444,7 @@ public void requestLayout() { 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("ExpireAfter", R.string.ExpireAfter)); + titleView.setText(title); titleView.setTextColor(datePickerColors.textColor); titleView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 20); @@ -3220,13 +3528,13 @@ public CharSequence getAccessibilityClassName() { checkScheduleDate(null, null, 0, dayPicker, hourPicker, minutePicker); - buttonTextView.setPadding(AndroidUtilities.dp(34), 0, AndroidUtilities.dp(34), 0); + buttonTextView.setPadding(dp(34), 0, 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(8), datePickerColors.buttonBackgroundColor, datePickerColors.buttonBackgroundPressedColor)); - buttonTextView.setText(LocaleController.getString("SetTimeLimit", R.string.SetTimeLimit)); + buttonTextView.setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)); + buttonTextView.setBackgroundDrawable(Theme.createSimpleSelectorRoundRectDrawable(dp(8), datePickerColors.buttonBackgroundColor, datePickerColors.buttonBackgroundPressedColor)); + buttonTextView.setText(button); container.addView(buttonTextView, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 48, Gravity.LEFT | Gravity.BOTTOM, 16, 15, 16, 16)); buttonTextView.setOnClickListener(v -> { boolean setSeconds = checkScheduleDate(null, null, 0, dayPicker, hourPicker, minutePicker); @@ -3262,7 +3570,7 @@ public static BottomSheet.Builder createStatusUntilDatePickerDialog(Context cont final NumberPicker dayPicker = new NumberPicker(context); dayPicker.setTextColor(datePickerColors.textColor); - dayPicker.setTextOffset(AndroidUtilities.dp(10)); + dayPicker.setTextOffset(dp(10)); dayPicker.setItemCount(5); final NumberPicker hourPicker = new NumberPicker(context) { @Override @@ -3272,7 +3580,7 @@ protected CharSequence getContentDescription(int value) { }; hourPicker.setItemCount(5); hourPicker.setTextColor(datePickerColors.textColor); - hourPicker.setTextOffset(-AndroidUtilities.dp(10)); + hourPicker.setTextOffset(-dp(10)); final NumberPicker minutePicker = new NumberPicker(context) { @Override protected CharSequence getContentDescription(int value) { @@ -3281,7 +3589,7 @@ protected CharSequence getContentDescription(int value) { }; minutePicker.setItemCount(5); minutePicker.setTextColor(datePickerColors.textColor); - minutePicker.setTextOffset(-AndroidUtilities.dp(34)); + minutePicker.setTextOffset(-dp(34)); LinearLayout container = new LinearLayout(context) { @@ -3299,9 +3607,9 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { dayPicker.setItemCount(count); hourPicker.setItemCount(count); minutePicker.setItemCount(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; + dayPicker.getLayoutParams().height = dp(NumberPicker.DEFAULT_SIZE_PER_COUNT) * count; + hourPicker.getLayoutParams().height = dp(NumberPicker.DEFAULT_SIZE_PER_COUNT) * count; + minutePicker.getLayoutParams().height = dp(NumberPicker.DEFAULT_SIZE_PER_COUNT) * count; ignoreLayout = false; super.onMeasure(widthMeasureSpec, heightMeasureSpec); } @@ -3408,12 +3716,12 @@ public CharSequence getAccessibilityClassName() { checkScheduleDate(null, null, 0, dayPicker, hourPicker, minutePicker); - buttonTextView.setPadding(AndroidUtilities.dp(34), 0, AndroidUtilities.dp(34), 0); + buttonTextView.setPadding(dp(34), 0, 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(8), datePickerColors.buttonBackgroundColor, datePickerColors.buttonBackgroundPressedColor)); + buttonTextView.setBackgroundDrawable(Theme.createSimpleSelectorRoundRectDrawable(dp(8), datePickerColors.buttonBackgroundColor, datePickerColors.buttonBackgroundPressedColor)); buttonTextView.setText(LocaleController.getString("SetEmojiStatusUntilButton", R.string.SetEmojiStatusUntilButton)); container.addView(buttonTextView, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 48, Gravity.LEFT | Gravity.BOTTOM, 16, 15, 16, 16)); buttonTextView.setOnClickListener(v -> { @@ -3512,7 +3820,7 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { count = 5; } numberPicker.setItemCount(count); - numberPicker.getLayoutParams().height = AndroidUtilities.dp(NumberPicker.DEFAULT_SIZE_PER_COUNT) * count; + numberPicker.getLayoutParams().height = dp(NumberPicker.DEFAULT_SIZE_PER_COUNT) * count; ignoreLayout = false; super.onMeasure(widthMeasureSpec, heightMeasureSpec); } @@ -3556,9 +3864,9 @@ public CharSequence getAccessibilityClassName() { buttonTextView.setPadding(0, 0, 0, 0); buttonTextView.setGravity(Gravity.CENTER); buttonTextView.setTextColor(datePickerColors.buttonTextColor); - buttonTextView.setTextSize(AndroidUtilities.dp(14)); + buttonTextView.setTextSize(dp(14)); buttonTextView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); - buttonTextView.setBackgroundDrawable(Theme.createSimpleSelectorRoundRectDrawable(AndroidUtilities.dp(8), datePickerColors.buttonBackgroundColor, datePickerColors.buttonBackgroundPressedColor)); + buttonTextView.setBackgroundDrawable(Theme.createSimpleSelectorRoundRectDrawable(dp(8), datePickerColors.buttonBackgroundColor, datePickerColors.buttonBackgroundPressedColor)); container.addView(buttonTextView, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 48, Gravity.LEFT | Gravity.BOTTOM, 16, 15, 16, 16)); buttonTextView.setText(LocaleController.getString("DisableAutoDeleteTimer", R.string.DisableAutoDeleteTimer)); @@ -3650,11 +3958,11 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { count = 5; } times.setItemCount(count); - times.getLayoutParams().height = AndroidUtilities.dp(NumberPicker.DEFAULT_SIZE_PER_COUNT) * count; + times.getLayoutParams().height = dp(NumberPicker.DEFAULT_SIZE_PER_COUNT) * count; minutes.setItemCount(count); - minutes.getLayoutParams().height = AndroidUtilities.dp(NumberPicker.DEFAULT_SIZE_PER_COUNT) * count; + minutes.getLayoutParams().height = dp(NumberPicker.DEFAULT_SIZE_PER_COUNT) * count; divider.setItemCount(count); - divider.getLayoutParams().height = AndroidUtilities.dp(NumberPicker.DEFAULT_SIZE_PER_COUNT) * count; + divider.getLayoutParams().height = dp(NumberPicker.DEFAULT_SIZE_PER_COUNT) * count; ignoreLayout = false; super.onMeasure(widthMeasureSpec, heightMeasureSpec); } @@ -3697,12 +4005,12 @@ public CharSequence getAccessibilityClassName() { 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.setPadding(dp(34), 0, 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(8), datePickerColors.buttonBackgroundColor, datePickerColors.buttonBackgroundPressedColor)); + buttonTextView.setBackgroundDrawable(Theme.createSimpleSelectorRoundRectDrawable(dp(8), datePickerColors.buttonBackgroundColor, datePickerColors.buttonBackgroundPressedColor)); buttonTextView.setText(LocaleController.getString("AutoDeleteConfirm", R.string.AutoDeleteConfirm)); container.addView(buttonTextView, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 48, Gravity.LEFT | Gravity.BOTTOM, 16, 15, 16, 16)); @@ -3819,7 +4127,7 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { count = 5; } numberPicker.setItemCount(count); - numberPicker.getLayoutParams().height = AndroidUtilities.dp(NumberPicker.DEFAULT_SIZE_PER_COUNT) * count; + numberPicker.getLayoutParams().height = dp(NumberPicker.DEFAULT_SIZE_PER_COUNT) * count; ignoreLayout = false; super.onMeasure(widthMeasureSpec, heightMeasureSpec); } @@ -3867,12 +4175,12 @@ public CharSequence getAccessibilityClassName() { }; numberPicker.setOnValueChangedListener(onValueChangeListener); - buttonTextView.setPadding(AndroidUtilities.dp(34), 0, AndroidUtilities.dp(34), 0); + buttonTextView.setPadding(dp(34), 0, 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(8), datePickerColors.buttonBackgroundColor, datePickerColors.buttonBackgroundPressedColor)); + buttonTextView.setBackgroundDrawable(Theme.createSimpleSelectorRoundRectDrawable(dp(8), datePickerColors.buttonBackgroundColor, datePickerColors.buttonBackgroundPressedColor)); buttonTextView.setText(LocaleController.getString("AutoDeleteConfirm", R.string.AutoDeleteConfirm)); container.addView(buttonTextView, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 48, Gravity.LEFT | Gravity.BOTTOM, 16, 15, 16, 16)); buttonTextView.setOnClickListener(v -> { @@ -3961,14 +4269,14 @@ public static BottomSheet.Builder createCalendarPickerDialog(Context context, lo builder.setApplyBottomPadding(false); final NumberPicker dayPicker = new NumberPicker(context, resourcesProvider); - dayPicker.setTextOffset(AndroidUtilities.dp(10)); + dayPicker.setTextOffset(dp(10)); dayPicker.setItemCount(5); final NumberPicker monthPicker = new NumberPicker(context, resourcesProvider); monthPicker.setItemCount(5); - monthPicker.setTextOffset(-AndroidUtilities.dp(10)); + monthPicker.setTextOffset(-dp(10)); final NumberPicker yearPicker = new NumberPicker(context, resourcesProvider); yearPicker.setItemCount(5); - yearPicker.setTextOffset(-AndroidUtilities.dp(24)); + yearPicker.setTextOffset(-dp(24)); LinearLayout container = new LinearLayout(context) { @@ -3986,9 +4294,9 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { dayPicker.setItemCount(count); monthPicker.setItemCount(count); yearPicker.setItemCount(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; + dayPicker.getLayoutParams().height = dp(NumberPicker.DEFAULT_SIZE_PER_COUNT) * count; + monthPicker.getLayoutParams().height = dp(NumberPicker.DEFAULT_SIZE_PER_COUNT) * count; + yearPicker.getLayoutParams().height = dp(NumberPicker.DEFAULT_SIZE_PER_COUNT) * count; ignoreLayout = false; super.onMeasure(widthMeasureSpec, heightMeasureSpec); } @@ -4087,13 +4395,13 @@ public CharSequence getAccessibilityClassName() { checkCalendarDate(minDate, dayPicker, monthPicker, yearPicker); - buttonTextView.setPadding(AndroidUtilities.dp(34), 0, AndroidUtilities.dp(34), 0); + buttonTextView.setPadding(dp(34), 0, dp(34), 0); buttonTextView.setGravity(Gravity.CENTER); buttonTextView.setTextColor(Theme.getColor(Theme.key_featuredStickers_buttonText, resourcesProvider)); buttonTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); buttonTextView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); buttonTextView.setText(LocaleController.getString(R.string.JumpToDate)); - buttonTextView.setBackground(Theme.createSimpleSelectorRoundRectDrawable(AndroidUtilities.dp(8), Theme.getColor(Theme.key_featuredStickers_addButton, resourcesProvider), Theme.getColor(Theme.key_featuredStickers_addButtonPressed, resourcesProvider))); + buttonTextView.setBackground(Theme.createSimpleSelectorRoundRectDrawable(dp(8), Theme.getColor(Theme.key_featuredStickers_addButton, resourcesProvider), Theme.getColor(Theme.key_featuredStickers_addButtonPressed, resourcesProvider))); container.addView(buttonTextView, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 48, Gravity.LEFT | Gravity.BOTTOM, 16, 15, 16, 16)); buttonTextView.setOnClickListener(v -> { checkCalendarDate(minDate, dayPicker, monthPicker, yearPicker); @@ -4669,7 +4977,7 @@ public static Dialog createColorSelectDialog(Activity parentActivity, final long final int[] selectedColor = new int[]{currentColor}; for (int a = 0; a < 9; a++) { RadioColorCell cell = new RadioColorCell(parentActivity, resourcesProvider); - cell.setPadding(AndroidUtilities.dp(4), 0, AndroidUtilities.dp(4), 0); + cell.setPadding(dp(4), 0, dp(4), 0); cell.setTag(a); cell.setCheckColor(TextColorCell.colors[a], TextColorCell.colors[a]); cell.setTextAndValue(descriptions[a], currentColor == TextColorCell.colorsToSave[a]); @@ -4801,7 +5109,7 @@ public static Dialog createVibrationSelectDialog(Activity parentActivity, final for (int a = 0; a < descriptions.length; a++) { RadioColorCell cell = new RadioColorCell(parentActivity, resourcesProvider); - cell.setPadding(AndroidUtilities.dp(4), 0, AndroidUtilities.dp(4), 0); + cell.setPadding(dp(4), 0, dp(4), 0); cell.setTag(a); cell.setCheckColor(Theme.getColor(Theme.key_radioBackground, resourcesProvider), Theme.getColor(Theme.key_dialogRadioBackgroundChecked, resourcesProvider)); cell.setTextAndValue(descriptions[a], selected[0] == a); @@ -4881,7 +5189,7 @@ public static Dialog createLocationUpdateDialog(final Activity parentActivity, T for (int a = 0; a < descriptions.length; a++) { RadioColorCell cell = new RadioColorCell(parentActivity, resourcesProvider); - cell.setPadding(AndroidUtilities.dp(4), 0, AndroidUtilities.dp(4), 0); + cell.setPadding(dp(4), 0, dp(4), 0); cell.setTag(a); int color1 = resourcesProvider != null ? resourcesProvider.getColorOrDefault(Theme.key_radioBackground) : Theme.getColor(Theme.key_radioBackground); int color2 = resourcesProvider != null ? resourcesProvider.getColorOrDefault(Theme.key_dialogRadioBackgroundChecked) : Theme.getColor(Theme.key_dialogRadioBackgroundChecked); @@ -4932,7 +5240,7 @@ public static AlertDialog.Builder createBackgroundLocationPermissionDialog(Activ frameLayout.setOutlineProvider(new ViewOutlineProvider() { @Override public void getOutline(View view, Outline outline) { - outline.setRoundRect(0, 0, view.getMeasuredWidth(), view.getMeasuredHeight() + AndroidUtilities.dp(6), AndroidUtilities.dp(6)); + outline.setRoundRect(0, 0, view.getMeasuredWidth(), view.getMeasuredHeight() + dp(6), dp(6)); } }); @@ -4945,7 +5253,7 @@ public void getOutline(View view, Outline outline) { frameLayout.addView(pin, LayoutHelper.createFrame(60, 82, Gravity.CENTER, 0, 0, 0, 0)); BackupImageView imageView = new BackupImageView(activity); - imageView.setRoundRadius(AndroidUtilities.dp(26)); + imageView.setRoundRadius(dp(26)); imageView.setForUserOrChat(selfUser, new AvatarDrawable(selfUser)); frameLayout.addView(imageView, LayoutHelper.createFrame(52, 52, Gravity.CENTER, 0, 0, 0, 11)); @@ -4971,13 +5279,13 @@ public static AlertDialog.Builder createGigagroupConvertAlert(Activity activity, frameLayout.setOutlineProvider(new ViewOutlineProvider() { @Override public void getOutline(View view, Outline outline) { - outline.setRoundRect(0, 0, view.getMeasuredWidth(), view.getMeasuredHeight() + AndroidUtilities.dp(6), AndroidUtilities.dp(6)); + outline.setRoundRect(0, 0, view.getMeasuredWidth(), view.getMeasuredHeight() + dp(6), dp(6)); } }); } float aspectRatio = 372f / 936f; View background = new View(activity); - background.setBackground(new BitmapDrawable(SvgHelper.getBitmap(svg, AndroidUtilities.dp(320), AndroidUtilities.dp(320 * aspectRatio), false))); + background.setBackground(new BitmapDrawable(SvgHelper.getBitmap(svg, dp(320), dp(320 * aspectRatio), false))); frameLayout.addView(background, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, 0, -1, -1, -1, -1)); builder.setTopView(frameLayout); @@ -5000,13 +5308,13 @@ public static AlertDialog.Builder createDrawOverlayPermissionDialog(Activity act frameLayout.setOutlineProvider(new ViewOutlineProvider() { @Override public void getOutline(View view, Outline outline) { - outline.setRoundRect(0, 0, view.getMeasuredWidth(), view.getMeasuredHeight() + AndroidUtilities.dp(6), AndroidUtilities.dpf2(6)); + outline.setRoundRect(0, 0, view.getMeasuredWidth(), view.getMeasuredHeight() + dp(6), AndroidUtilities.dpf2(6)); } }); float aspectRatio = 472f / 936f; View background = new View(activity); - background.setBackground(new BitmapDrawable(SvgHelper.getBitmap(svg, AndroidUtilities.dp(320), AndroidUtilities.dp(320 * aspectRatio), false))); + background.setBackground(new BitmapDrawable(SvgHelper.getBitmap(svg, dp(320), dp(320 * aspectRatio), false))); frameLayout.addView(background, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, 0, -1, -1, -1, -1)); builder.setTopView(frameLayout); @@ -5049,14 +5357,14 @@ protected void onLayout(boolean changed, int left, int top, int right, int botto frameLayout.setOutlineProvider(new ViewOutlineProvider() { @Override public void getOutline(View view, Outline outline) { - outline.setRoundRect(0, 0, view.getMeasuredWidth(), view.getMeasuredHeight() + AndroidUtilities.dp(6), AndroidUtilities.dpf2(6)); + outline.setRoundRect(0, 0, view.getMeasuredWidth(), view.getMeasuredHeight() + dp(6), AndroidUtilities.dpf2(6)); } }); float aspectRatio = 540f / 936f; View background = new View(context); - background.setBackground(new BitmapDrawable(SvgHelper.getBitmap(svg, AndroidUtilities.dp(320), AndroidUtilities.dp(320 * aspectRatio), false))); + background.setBackground(new BitmapDrawable(SvgHelper.getBitmap(svg, dp(320), dp(320 * aspectRatio), false))); frameLayout.addView(background, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, 0, -1, -1, -1, -1)); frameLayout.addView(button, LayoutHelper.createFrame(117, 117)); @@ -5166,7 +5474,7 @@ public static Dialog createPrioritySelectDialog(Activity parentActivity, final l for (int a = 0; a < descriptions.length; a++) { RadioColorCell cell = new RadioColorCell(parentActivity, resourcesProvider); - cell.setPadding(AndroidUtilities.dp(4), 0, AndroidUtilities.dp(4), 0); + cell.setPadding(dp(4), 0, dp(4), 0); cell.setTag(a); cell.setCheckColor(Theme.getColor(Theme.key_radioBackground, resourcesProvider), Theme.getColor(Theme.key_dialogRadioBackgroundChecked, resourcesProvider)); cell.setTextAndValue(descriptions[a], selected[0] == a); @@ -5254,7 +5562,7 @@ public static Dialog createPopupSelectDialog(Activity parentActivity, final int for (int a = 0; a < descriptions.length; a++) { RadioColorCell cell = new RadioColorCell(parentActivity); cell.setTag(a); - cell.setPadding(AndroidUtilities.dp(4), 0, AndroidUtilities.dp(4), 0); + cell.setPadding(dp(4), 0, dp(4), 0); cell.setCheckColor(Theme.getColor(Theme.key_radioBackground), Theme.getColor(Theme.key_dialogRadioBackgroundChecked)); cell.setTextAndValue(descriptions[a], selected[0] == a); linearLayout.addView(cell); @@ -5289,7 +5597,7 @@ public static Dialog createSingleChoiceDialog(Activity parentActivity, final Str AlertDialog.Builder builder = new AlertDialog.Builder(parentActivity); for (int a = 0; a < options.length; a++) { RadioColorCell cell = new RadioColorCell(parentActivity); - cell.setPadding(AndroidUtilities.dp(4), 0, AndroidUtilities.dp(4), 0); + cell.setPadding(dp(4), 0, dp(4), 0); cell.setTag(a); cell.setCheckColor(Theme.getColor(Theme.key_radioBackground), Theme.getColor(Theme.key_dialogRadioBackgroundChecked)); cell.setTextAndValue(options[a], selected == a); @@ -5391,7 +5699,7 @@ public static AlertDialog createAccountSelectDialog(Activity parentActivity, fin if (u != null) { AccountSelectCell cell = new AccountSelectCell(parentActivity, false); cell.setAccount(a, false); - cell.setPadding(AndroidUtilities.dp(14), 0, AndroidUtilities.dp(14), 0); + cell.setPadding(dp(14), 0, dp(14), 0); cell.setBackgroundDrawable(Theme.getSelectorDrawable(false)); linearLayout.addView(cell, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 50)); cell.setOnClickListener(v -> { @@ -5415,7 +5723,10 @@ public interface PaymentAlertDelegate { void didPressedNewCard(); } - public static void createDeleteMessagesAlert(BaseFragment fragment, TLRPC.User user, TLRPC.Chat chat, TLRPC.EncryptedChat encryptedChat, TLRPC.ChatFull chatInfo, long mergeDialogId, MessageObject selectedMessage, SparseArray[] selectedMessages, MessageObject.GroupedMessages selectedGroup, boolean scheduled, boolean isSavedMessages, int loadParticipant, Runnable onDelete, Runnable hideDim, Theme.ResourcesProvider resourcesProvider) { + public static void createDeleteMessagesAlert(BaseFragment fragment, TLRPC.User user, TLRPC.Chat chat, TLRPC.EncryptedChat encryptedChat, TLRPC.ChatFull chatInfo, long mergeDialogId, MessageObject selectedMessage, SparseArray[] selectedMessages, MessageObject.GroupedMessages selectedGroup, int topicId, int mode, int loadParticipant, Runnable onDelete, Runnable hideDim, Theme.ResourcesProvider resourcesProvider) { + final boolean scheduled = mode == ChatActivity.MODE_SCHEDULED; + final boolean isSavedMessages = mode == ChatActivity.MODE_SAVED; + final boolean quickReplies = mode == ChatActivity.MODE_QUICK_REPLIES; if (fragment == null || user == null && chat == null && encryptedChat == null) { return; } @@ -5552,7 +5863,7 @@ public static void createDeleteMessagesAlert(BaseFragment fragment, TLRPC.User u } else if (error != null && "USER_NOT_PARTICIPANT".equals(error.text)) { loadType = 0; } - createDeleteMessagesAlert(fragment, user, chat, encryptedChat, chatInfo, mergeDialogId, selectedMessage, selectedMessages, selectedGroup, scheduled, isSavedMessages, loadType, onDelete, hideDim, resourcesProvider); + createDeleteMessagesAlert(fragment, user, chat, encryptedChat, chatInfo, mergeDialogId, selectedMessage, selectedMessages, selectedGroup, topicId, mode, loadType, onDelete, hideDim, resourcesProvider); })); AndroidUtilities.runOnUIThread(() -> { if (progressDialog[0] == null) { @@ -5580,7 +5891,7 @@ public static void createDeleteMessagesAlert(BaseFragment fragment, TLRPC.User u } else { cell.setText(LocaleController.formatString("DeleteAllFrom", R.string.DeleteAllFrom, name), "", false, false); } - cell.setPadding(LocaleController.isRTL ? AndroidUtilities.dp(16) : AndroidUtilities.dp(8), 0, LocaleController.isRTL ? AndroidUtilities.dp(8) : AndroidUtilities.dp(16), 0); + cell.setPadding(LocaleController.isRTL ? dp(16) : dp(8), 0, LocaleController.isRTL ? dp(8) : dp(16), 0); frameLayout.addView(cell, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 48, Gravity.TOP | Gravity.LEFT, 0, 48 * num, 0, 0)); cell.setOnClickListener(v -> { if (!v.isEnabled()) { @@ -5604,7 +5915,7 @@ public static void createDeleteMessagesAlert(BaseFragment fragment, TLRPC.User u } else { cell.setText(LocaleController.getString("DeleteMessagesOption", R.string.DeleteMessagesOption), "", false, false); } - cell.setPadding(LocaleController.isRTL ? AndroidUtilities.dp(16) : AndroidUtilities.dp(8), 0, LocaleController.isRTL ? AndroidUtilities.dp(8) : AndroidUtilities.dp(16), 0); + cell.setPadding(LocaleController.isRTL ? dp(16) : dp(8), 0, LocaleController.isRTL ? dp(8) : dp(16), 0); frameLayout.addView(cell, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 48, Gravity.TOP | Gravity.LEFT, 0, 0, 0, 0)); cell.setOnClickListener(v -> { CheckBoxCell cell12 = (CheckBoxCell) v; @@ -5665,7 +5976,7 @@ public static void createDeleteMessagesAlert(BaseFragment fragment, TLRPC.User u } else { cell.setText(LocaleController.getString("DeleteMessagesOption", R.string.DeleteMessagesOption), "", false, false); } - cell.setPadding(LocaleController.isRTL ? AndroidUtilities.dp(16) : AndroidUtilities.dp(8), 0, LocaleController.isRTL ? AndroidUtilities.dp(8) : AndroidUtilities.dp(16), 0); + cell.setPadding(LocaleController.isRTL ? dp(16) : dp(8), 0, LocaleController.isRTL ? dp(8) : dp(16), 0); frameLayout.addView(cell, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 48, Gravity.TOP | Gravity.LEFT, 0, 0, 0, 0)); cell.setOnClickListener(v -> { CheckBoxCell cell1 = (CheckBoxCell) v; @@ -5706,7 +6017,7 @@ public static void createDeleteMessagesAlert(BaseFragment fragment, TLRPC.User u random_ids.add(selectedMessage.messageOwner.random_id); } } - MessagesController.getInstance(currentAccount).deleteMessages(ids, random_ids, encryptedChat, thisDialogId, deleteForAll[0], scheduled); + MessagesController.getInstance(currentAccount).deleteMessages(ids, random_ids, encryptedChat, thisDialogId, topicId, deleteForAll[0], mode); } else { for (int a = 1; a >= 0; a--) { ids = new ArrayList<>(); @@ -5723,7 +6034,7 @@ public static void createDeleteMessagesAlert(BaseFragment fragment, TLRPC.User u } } } - MessagesController.getInstance(currentAccount).deleteMessages(ids, random_ids, encryptedChat, thisDialogId, deleteForAll[0], scheduled); + MessagesController.getInstance(currentAccount).deleteMessages(ids, random_ids, encryptedChat, thisDialogId, topicId, deleteForAll[0], mode); selectedMessages[a].clear(); } } @@ -5849,8 +6160,8 @@ public static void createDeleteMessagesAlert(BaseFragment fragment, TLRPC.User u } TextView neutralButton = (TextView) dialog.getButton(DialogInterface.BUTTON_NEUTRAL); if (neutralButton != null) { - dialog.getButtonsLayout().setPadding(AndroidUtilities.dp(12), AndroidUtilities.dp(0), AndroidUtilities.dp(8), AndroidUtilities.dp(12)); - ((ViewGroup.MarginLayoutParams) dialog.getButtonsLayout().getLayoutParams()).topMargin = AndroidUtilities.dp(-8); + dialog.getButtonsLayout().setPadding(dp(12), dp(0), dp(8), dp(12)); + ((ViewGroup.MarginLayoutParams) dialog.getButtonsLayout().getLayoutParams()).topMargin = dp(-8); neutralButton.setTextColor(Theme.getColor(Theme.key_text_RedBold)); } } @@ -5882,7 +6193,7 @@ public static void createThemeCreateDialog(BaseFragment fragment, int type, Them message.setText(LocaleController.getString("EnterThemeName", R.string.EnterThemeName)); } message.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16); - message.setPadding(AndroidUtilities.dp(23), AndroidUtilities.dp(12), AndroidUtilities.dp(23), AndroidUtilities.dp(6)); + message.setPadding(dp(23), dp(12), dp(23), dp(6)); message.setTextColor(Theme.getColor(Theme.key_dialogTextBlack)); linearLayout.addView(message, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); @@ -5895,9 +6206,9 @@ public static void createThemeCreateDialog(BaseFragment fragment, int type, Them editText.setSingleLine(true); editText.setImeOptions(EditorInfo.IME_ACTION_DONE); editText.setCursorColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlackText)); - editText.setCursorSize(AndroidUtilities.dp(20)); + editText.setCursorSize(dp(20)); editText.setCursorWidth(1.5f); - editText.setPadding(0, AndroidUtilities.dp(4), 0, 0); + editText.setPadding(0, dp(4), 0, 0); linearLayout.addView(editText, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 36, Gravity.TOP | Gravity.LEFT, 24, 6, 24, 0)); editText.setOnEditorActionListener((textView, i, keyEvent) -> { AndroidUtilities.hideKeyboard(textView); @@ -6329,7 +6640,7 @@ public static ActionBarPopupWindow showPopupMenu(ActionBarPopupWindow.ActionBarP return false; }); - popupLayout.measure(View.MeasureSpec.makeMeasureSpec(AndroidUtilities.displaySize.x - AndroidUtilities.dp(40), View.MeasureSpec.AT_MOST), View.MeasureSpec.makeMeasureSpec(AndroidUtilities.displaySize.y, View.MeasureSpec.AT_MOST)); + popupLayout.measure(View.MeasureSpec.makeMeasureSpec(AndroidUtilities.displaySize.x - dp(40), View.MeasureSpec.AT_MOST), View.MeasureSpec.makeMeasureSpec(AndroidUtilities.displaySize.y, View.MeasureSpec.AT_MOST)); popupWindow.showAsDropDown(anchorView, offsetX, offsetY); popupLayout.updateRadialSelectors(); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/AnimatedTextView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/AnimatedTextView.java index 7de70b60693..26ce42baf1d 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/AnimatedTextView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/AnimatedTextView.java @@ -869,6 +869,10 @@ public void setGravity(int gravity) { this.gravity = gravity; } + public int getGravity() { + return this.gravity; + } + public void setAnimationProperties(float moveAmplitude, long startDelay, long duration, TimeInterpolator interpolator) { this.moveAmplitude = moveAmplitude; animateDelay = startDelay; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/AvatarDrawable.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/AvatarDrawable.java index 668988021f6..ef23bcd3fe1 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/AvatarDrawable.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/AvatarDrawable.java @@ -96,6 +96,22 @@ public class AvatarDrawable extends Drawable { public static final int AVATAR_TYPE_STORY = 20; public static final int AVATAR_TYPE_ANONYMOUS = 21; public static final int AVATAR_TYPE_MY_NOTES = 22; + public static final int AVATAR_TYPE_EXISTING_CHATS = 23; + public static final int AVATAR_TYPE_NEW_CHATS = 24; + + /** + * Matches {@link org.telegram.ui.Components.AvatarConstructorFragment#defaultColors} + * but reordered to preserve color tints. + */ + public static final int[][] advancedGradients = new int[][]{ + new int[]{0xFFF64884, 0xFFEF5B41, 0xFFF6A730, 0xFFFF7742}, + new int[]{0xFFF5694E, 0xFFF5772C, 0xFFFFD412, 0xFFFFA743}, + new int[]{0xFF837CFF, 0xFFB063FF, 0xFFFF72A9, 0xFFE269FF}, + new int[]{0xFF09D260, 0xFF5EDC40, 0xFFC1E526, 0xFF80DF2B}, + new int[]{0xFF5EB6FB, 0xFF1FCEEB, 0xFF45F7B7, 0xFF1FF1D9}, + new int[]{0xFF4D8DFF, 0xFF2BBFFF, 0xFF20E2CD, 0xFF0EE1F1}, + new int[]{0xFFF94BA0, 0xFFFB5C80, 0xFFFFB23A, 0xFFFE7E62}, + }; private int alpha = 255; private Theme.ResourcesProvider resourcesProvider; @@ -262,11 +278,11 @@ public void setAvatarType(int value) { hasGradient = true; color = getThemedColor(Theme.keys_avatar_background[getColorIndex(4)]); color2 = getThemedColor(Theme.keys_avatar_background2[getColorIndex(4)]); - } else if (avatarType == AVATAR_TYPE_FILTER_GROUPS) { + } else if (avatarType == AVATAR_TYPE_FILTER_GROUPS || avatarType == AVATAR_TYPE_EXISTING_CHATS) { hasGradient = true; color = getThemedColor(Theme.keys_avatar_background[getColorIndex(3)]); color2 = getThemedColor(Theme.keys_avatar_background2[getColorIndex(3)]); - } else if (avatarType == AVATAR_TYPE_FILTER_CHANNELS) { + } else if (avatarType == AVATAR_TYPE_FILTER_CHANNELS || avatarType == AVATAR_TYPE_NEW_CHATS) { hasGradient = true; color = getThemedColor(Theme.keys_avatar_background[getColorIndex(1)]); color2 = getThemedColor(Theme.keys_avatar_background2[getColorIndex(1)]); @@ -376,33 +392,72 @@ public void setInfo(long id, String firstName, String lastName, String custom) { } public void setInfo(long id, String firstName, String lastName, String custom, Integer customColor, MessagesController.PeerColor profileColor) { - hasGradient = true; - hasAdvancedGradient = false; + setInfo(id, firstName, lastName, custom, customColor, profileColor, false); + } + + public void setInfo(long id, String firstName, String lastName, String custom, Integer customColor, MessagesController.PeerColor profileColor, boolean advancedGradient) { invalidateTextLayout = true; + if (advancedGradient) { + hasGradient = false; + hasAdvancedGradient = true; + if (this.advancedGradient == null) { + this.advancedGradient = new GradientTools(); + } + } else { + hasGradient = true; + hasAdvancedGradient = false; + } + if (profileColor != null) { - color = profileColor.getAvatarColor1(); - color2 = profileColor.getAvatarColor2(); + if (advancedGradient) { + int[] gradient = advancedGradients[getPeerColorIndex(profileColor.getAvatarColor1())]; + this.advancedGradient.setColors(gradient[0], gradient[1], gradient[2], gradient[3]); + } else { + color = profileColor.getAvatarColor1(); + color2 = profileColor.getAvatarColor2(); + } } else if (customColor != null) { if (customColor >= 14) { MessagesController messagesController = MessagesController.getInstance(UserConfig.selectedAccount); if (messagesController != null && messagesController.peerColors != null && messagesController.peerColors.getColor(customColor) != null) { final int peerColor = messagesController.peerColors.getColor(customColor).getColor1(); - color = getThemedColor(Theme.keys_avatar_background[getPeerColorIndex(peerColor)]); - color2 = getThemedColor(Theme.keys_avatar_background2[getPeerColorIndex(peerColor)]); + if (advancedGradient) { + int[] gradient = advancedGradients[getPeerColorIndex(peerColor)]; + this.advancedGradient.setColors(gradient[0], gradient[1], gradient[2], gradient[3]); + } else { + color = getThemedColor(Theme.keys_avatar_background[getPeerColorIndex(peerColor)]); + color2 = getThemedColor(Theme.keys_avatar_background2[getPeerColorIndex(peerColor)]); + } + } else { + if (advancedGradient) { + int[] gradient = advancedGradients[getColorIndex(customColor)]; + this.advancedGradient.setColors(gradient[0], gradient[1], gradient[2], gradient[3]); + } else { + color = getThemedColor(Theme.keys_avatar_background[getColorIndex(customColor)]); + color2 = getThemedColor(Theme.keys_avatar_background2[getColorIndex(customColor)]); + } + } + } else { + if (advancedGradient) { + int[] gradient = advancedGradients[getColorIndex(customColor)]; + this.advancedGradient.setColors(gradient[0], gradient[1], gradient[2], gradient[3]); } else { color = getThemedColor(Theme.keys_avatar_background[getColorIndex(customColor)]); color2 = getThemedColor(Theme.keys_avatar_background2[getColorIndex(customColor)]); } - } else { - color = getThemedColor(Theme.keys_avatar_background[getColorIndex(customColor)]); - color2 = getThemedColor(Theme.keys_avatar_background2[getColorIndex(customColor)]); } } else { - color = getThemedColor(Theme.keys_avatar_background[getColorIndex(id)]); - color2 = getThemedColor(Theme.keys_avatar_background2[getColorIndex(id)]); + if (advancedGradient) { + int[] gradient = advancedGradients[getColorIndex(id)]; + this.advancedGradient.setColors(gradient[0], gradient[1], gradient[2], gradient[3]); + } else { + color = getThemedColor(Theme.keys_avatar_background[getColorIndex(id)]); + color2 = getThemedColor(Theme.keys_avatar_background2[getColorIndex(id)]); + } } needApplyColorAccent = id == 5; // Tinting manually set blue color + avatarType = AVATAR_TYPE_NORMAL; drawDeleted = false; @@ -558,6 +613,10 @@ public void draw(Canvas canvas) { drawable = Theme.avatarDrawables[18]; } else if (avatarType == AVATAR_TYPE_MY_NOTES) { drawable = Theme.avatarDrawables[19]; + } else if (avatarType == AVATAR_TYPE_EXISTING_CHATS) { + drawable = Theme.avatarDrawables[21]; + } else if (avatarType == AVATAR_TYPE_NEW_CHATS) { + drawable = Theme.avatarDrawables[20]; } else { drawable = Theme.avatarDrawables[9]; } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/BitmapShaderTools.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/BitmapShaderTools.java index b2aec0db8b1..5fbef14c715 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/BitmapShaderTools.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/BitmapShaderTools.java @@ -31,7 +31,7 @@ public BitmapShaderTools() { } public BitmapShaderTools(int width, int height) { - bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); + bitmap = Bitmap.createBitmap(Math.max(1, width), Math.max(1, height), Bitmap.Config.ARGB_8888); canvas = new Canvas(bitmap); paint.setShader(shader = new BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP)); updateBounds(); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/BotWebViewSheet.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/BotWebViewSheet.java index 6c01912e155..bbfcf9d9d8c 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/BotWebViewSheet.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/BotWebViewSheet.java @@ -41,7 +41,9 @@ import org.telegram.messenger.ContactsController; import org.telegram.messenger.DialogObject; import org.telegram.messenger.Emoji; +import org.telegram.messenger.FileLoader; import org.telegram.messenger.FileLog; +import org.telegram.messenger.ImageLocation; import org.telegram.messenger.LocaleController; import org.telegram.messenger.MediaDataController; import org.telegram.messenger.MessagesController; @@ -66,6 +68,7 @@ import org.telegram.ui.LaunchActivity; import org.telegram.ui.PaymentFormActivity; +import java.io.File; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.List; @@ -917,6 +920,9 @@ public void requestWebView(int currentAccount, long peerId, long botId, String b if (currentBot != null && (currentBot.show_in_side_menu || currentBot.show_in_attach_menu)) { otherItem.addSubItem(R.id.menu_delete_bot, R.drawable.msg_delete, LocaleController.getString(R.string.BotWebViewDeleteBot)); } + if (currentBot != null && currentBot.show_in_side_menu && !MediaDataController.getInstance(currentAccount).isShortcutAdded(botId, MediaDataController.SHORTCUT_TYPE_ATTACHED_BOT)) { + otherItem.addSubItem(R.id.menu_add_to_home_screen_bot, R.drawable.msg_home, LocaleController.getString(R.string.AddShortcut)); + } actionBar.setActionBarMenuOnItemClick(new ActionBar.ActionBarMenuOnItemClick() { @Override public void onItemClick(int id) { @@ -948,6 +954,8 @@ public void onItemClick(int id) { webViewContainer.onSettingsButtonPressed(); } else if (id == R.id.menu_delete_bot) { deleteBot(currentAccount, botId, () -> dismiss()); + } else if (id == R.id.menu_add_to_home_screen_bot) { + MediaDataController.getInstance(currentAccount).installShortcut(botId, MediaDataController.SHORTCUT_TYPE_ATTACHED_BOT); } } }); @@ -956,6 +964,7 @@ public void onItemClick(int id) { webViewContainer.setBotUser(MessagesController.getInstance(currentAccount).getUser(botId)); webViewContainer.loadFlickerAndSettingsItem(currentAccount, botId, settingsItem); + preloadShortcutBotIcon(botUser, currentBot); switch (type) { case TYPE_BOT_MENU_BUTTON: { TLRPC.TL_messages_requestWebView req = new TLRPC.TL_messages_requestWebView(); @@ -1081,6 +1090,21 @@ public void onItemClick(int id) { } } + private void preloadShortcutBotIcon(TLRPC.User botUser, TLRPC.TL_attachMenuBot currentBot) { + if (currentBot != null && currentBot.show_in_side_menu && !MediaDataController.getInstance(currentAccount).isShortcutAdded(botId, MediaDataController.SHORTCUT_TYPE_ATTACHED_BOT)) { + TLRPC.User user = botUser; + if (user == null) { + user = MessagesController.getInstance(currentAccount).getUser(botId); + } + if (user != null && user.photo != null) { + File f = FileLoader.getInstance(currentAccount).getPathToAttach(user.photo.photo_small, true); + if (!f.exists()) { + MediaDataController.getInstance(currentAccount).preloadImage(ImageLocation.getForUser(user, ImageLocation.TYPE_SMALL), FileLoader.PRIORITY_LOW); + } + } + } + } + public static void deleteBot(int currentAccount, long botId, Runnable onDone) { String description; TLRPC.TL_attachMenuBot currentBot = null; @@ -1108,6 +1132,7 @@ public static void deleteBot(int currentAccount, long botId, Runnable onDone) { }), ConnectionsManager.RequestFlagInvokeAfter | ConnectionsManager.RequestFlagFailOnServerErrors); finalCurrentBot.show_in_side_menu = false; NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.attachMenuBotsDidLoad); + MediaDataController.getInstance(currentAccount).uninstallShortcut(botId, MediaDataController.SHORTCUT_TYPE_ATTACHED_BOT); if (onDone != null) { onDone.run(); } @@ -1145,6 +1170,10 @@ public void onLayoutChange(View v, int left, int top, int right, int bottom, int super.show(); } + public long getBotId() { + return botId; + } + @Override public void onBackPressed() { if (passcodeView.getVisibility() == View.VISIBLE) { 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 287642198fd..0ea1575b177 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Bulletin.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Bulletin.java @@ -1741,6 +1741,10 @@ public UndoButton(@NonNull Context context, boolean text) { } public UndoButton(@NonNull Context context, boolean text, Theme.ResourcesProvider resourcesProvider) { + this(context, text, !text, resourcesProvider); + } + + public UndoButton(@NonNull Context context, boolean text, boolean icon, Theme.ResourcesProvider resourcesProvider) { super(context); this.resourcesProvider = resourcesProvider; @@ -1748,24 +1752,28 @@ public UndoButton(@NonNull Context context, boolean text, Theme.ResourcesProvide if (text) { undoTextView = new TextView(context); - undoTextView.setOnClickListener(v -> undo()); undoTextView.setBackground(Theme.createSelectorDrawable((undoCancelColor & 0x00ffffff) | 0x19000000, Theme.RIPPLE_MASK_ROUNDRECT_6DP)); undoTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); undoTextView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); undoTextView.setTextColor(undoCancelColor); undoTextView.setText(LocaleController.getString("Undo", R.string.Undo)); undoTextView.setGravity(Gravity.CENTER_VERTICAL); - ViewHelper.setPaddingRelative(undoTextView, 12, 8, 12, 8); + ViewHelper.setPaddingRelative(undoTextView, icon ? 34 : 12, 8, 12, 8); addView(undoTextView, LayoutHelper.createFrameRelatively(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_VERTICAL, 8, 0, 8, 0)); - } else { + } + + if (icon) { final ImageView undoImageView = new ImageView(getContext()); - undoImageView.setOnClickListener(v -> undo()); undoImageView.setImageResource(R.drawable.chats_undo); undoImageView.setColorFilter(new PorterDuffColorFilter(undoCancelColor, PorterDuff.Mode.MULTIPLY)); - undoImageView.setBackground(Theme.createSelectorDrawable((undoCancelColor & 0x00ffffff) | 0x19000000)); + if (!text) { + undoImageView.setBackground(Theme.createSelectorDrawable((undoCancelColor & 0x00ffffff) | 0x19000000)); + } ViewHelper.setPaddingRelative(undoImageView, 0, 12, 0, 12); addView(undoImageView, LayoutHelper.createFrameRelatively(56, 48, Gravity.CENTER_VERTICAL)); } + + setOnClickListener(v -> undo()); } public UndoButton setText(CharSequence text) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/CanvasButton.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/CanvasButton.java index 2cf5bda65f5..ff4c13910aa 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/CanvasButton.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/CanvasButton.java @@ -25,7 +25,7 @@ public class CanvasButton { - Path drawingPath; + CornerPath drawingPath; ArrayList drawingRects = new ArrayList<>(); int usingRectCount; boolean buttonPressed; @@ -111,7 +111,7 @@ private void drawInternal(Canvas canvas, Paint paint) { if (usingRectCount > 1) { if (!pathCreated) { if (drawingPath == null) { - drawingPath = new Path(); + drawingPath = new CornerPath(2); } else { drawingPath.rewind(); } @@ -141,6 +141,7 @@ private void drawInternal(Canvas canvas, Paint paint) { selectorDrawable.setBounds(left, top, right, bottom); } } + drawingPath.closeRects(); pathCreated = true; } paint.setPathEffect(pathEffect); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/CaptionPhotoViewer.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/CaptionPhotoViewer.java index 41276e7ed0d..44115c44113 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/CaptionPhotoViewer.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/CaptionPhotoViewer.java @@ -70,20 +70,7 @@ public CaptionPhotoViewer(Context context, FrameLayout rootView, SizeNotifierFra setTimerVisible(false, false); addView(timerButton, LayoutHelper.createFrame(44, 44, Gravity.RIGHT | Gravity.BOTTOM, 0, 0, 11, 10)); - hint = new HintView2(context, HintView2.DIRECTION_BOTTOM);// { -// @Override -// protected boolean drawBlur(Canvas canvas, RectF bounds, Path path, float alpha) { -// if (customBlur()) { -// canvas.saveLayerAlpha(bounds, (int) (0xFF * alpha), Canvas.ALL_SAVE_FLAG); -// canvas.clipPath(path); -// CaptionPhotoViewer.this.drawBlur(hintBlur, canvas, bounds, 0, false, 0, -hint.getY(), false); -// canvas.restore(); -// return true; -// } -// return false; -// } -// }; -// hintBlur = new BlurringShader.StoryBlurDrawer(blurManager, hint, BlurringShader.StoryBlurDrawer.BLUR_TYPE_MENU_BACKGROUND); + hint = new HintView2(context, HintView2.DIRECTION_BOTTOM); hint.setRounding(12); hint.setPadding(dp(12), 0, dp(12), dp(8)); hint.setJoint(1, -21); 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 3e026d75aff..8460200a918 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatActivityEnterView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatActivityEnterView.java @@ -63,7 +63,6 @@ import android.text.TextUtils; import android.text.TextWatcher; import android.text.style.ImageSpan; -import android.util.Log; import android.util.Property; import android.util.TypedValue; import android.view.ActionMode; @@ -96,7 +95,6 @@ import androidx.collection.LongSparseArray; import androidx.core.content.ContextCompat; import androidx.core.graphics.ColorUtils; -import androidx.core.graphics.drawable.DrawableCompat; import androidx.core.math.MathUtils; import androidx.core.os.BuildCompat; import androidx.core.view.ViewCompat; @@ -154,10 +152,10 @@ import org.telegram.ui.ActionBar.SimpleTextView; import org.telegram.ui.ActionBar.Theme; import org.telegram.ui.BasePermissionsActivity; +import org.telegram.ui.Business.QuickRepliesController; import org.telegram.ui.ChatActivity; import org.telegram.ui.Components.Premium.GiftPremiumBottomSheet; import org.telegram.ui.Components.Premium.PremiumFeatureBottomSheet; -import org.telegram.ui.Components.Premium.PremiumGradient; import org.telegram.ui.ContentPreviewViewer; import org.telegram.ui.DialogsActivity; import org.telegram.ui.GroupStickersActivity; @@ -173,8 +171,6 @@ import java.io.File; import java.io.FileOutputStream; import java.io.InputStream; -import java.io.ObjectOutputStream; -import java.io.Serializable; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -673,6 +669,7 @@ public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo i private TLRPC.TL_replyKeyboardMarkup botReplyMarkup; private int botCount; private boolean hasBotCommands; + private boolean hasQuickReplies; private PowerManager.WakeLock wakeLock; private AnimatorSet runningAnimation; @@ -910,7 +907,7 @@ public void run() { delegate.needStartRecordAudio(1); startedDraggingX = -1; TL_stories.StoryItem storyItem = delegate != null ? delegate.getReplyToStory() : null; - MediaController.getInstance().startRecording(currentAccount, dialog_id, replyingMessageObject, getThreadMessage(), storyItem, recordingGuid, true); + MediaController.getInstance().startRecording(currentAccount, dialog_id, replyingMessageObject, getThreadMessage(), storyItem, recordingGuid, true, parentFragment != null ? parentFragment.quickReplyShortcut : null, parentFragment != null ? parentFragment.getQuickReplyId() : 0); recordingAudioVideo = true; updateRecordInterface(RECORD_STATE_ENTER, true); if (recordTimerView != null) { @@ -3400,7 +3397,7 @@ private void createBotButton() { } else if (isPopupShowing() && currentPopupContentType == POPUP_CONTENT_BOT_KEYBOARD) { showPopup(0, POPUP_CONTENT_BOT_KEYBOARD); } - } else if (hasBotCommands) { + } else if (hasBotCommands || hasQuickReplies) { setFieldText("/"); if (messageEditText != null) { messageEditText.requestFocus(); @@ -4216,7 +4213,7 @@ public boolean hasOverlappingRendering() { private ActionBarMenuSubItem actionScheduleButton; private boolean onSendLongClick(View view) { - if (isInScheduleMode()) { + if (isInScheduleMode() || parentFragment != null && parentFragment.getChatMode() == ChatActivity.MODE_QUICK_REPLIES) { return false; } @@ -4394,7 +4391,10 @@ public void onItemClick(View view, int position) { if (parentFragment != null && parentFragment.checkSlowMode(view)) { return; } - SendMessagesHelper.getInstance(currentAccount).sendMessage(SendMessagesHelper.SendMessageParams.of(command, dialog_id, replyingMessageObject, getThreadMessage(), null, false, null, null, null, true, 0, null, false)); + SendMessagesHelper.SendMessageParams params = SendMessagesHelper.SendMessageParams.of(command, dialog_id, replyingMessageObject, getThreadMessage(), null, false, null, null, null, true, 0, null, false); + params.quick_reply_shortcut = parentFragment != null ? parentFragment.quickReplyShortcut : null; + params.quick_reply_shortcut_id = parentFragment != null ? parentFragment.getQuickReplyId() : 0; + SendMessagesHelper.getInstance(currentAccount).sendMessage(params); setFieldText(""); botCommandsMenuContainer.dismiss(); } @@ -4526,9 +4526,9 @@ private void send(InputContentInfoCompat inputContentInfo, boolean notify, int s } ClipDescription description = inputContentInfo.getDescription(); if (description.hasMimeType("image/gif")) { - SendMessagesHelper.prepareSendingDocument(accountInstance, null, null, inputContentInfo.getContentUri(), null, "image/gif", dialog_id, replyingMessageObject, getThreadMessage(), null, replyingQuote, null, notify, 0, inputContentInfo); + SendMessagesHelper.prepareSendingDocument(accountInstance, null, null, inputContentInfo.getContentUri(), null, "image/gif", dialog_id, replyingMessageObject, getThreadMessage(), null, replyingQuote, null, notify, 0, inputContentInfo, parentFragment != null ? parentFragment.quickReplyShortcut : null, parentFragment != null ? parentFragment.getQuickReplyId() : 0); } else { - SendMessagesHelper.prepareSendingPhoto(accountInstance, null, inputContentInfo.getContentUri(), dialog_id, replyingMessageObject, getThreadMessage(), replyingQuote, null, null, null, inputContentInfo, 0, null, notify, 0); + SendMessagesHelper.prepareSendingPhoto(accountInstance, null, inputContentInfo.getContentUri(), dialog_id, replyingMessageObject, getThreadMessage(), replyingQuote, null, null, null, inputContentInfo, 0, null, notify, 0, parentFragment == null ? 0 : parentFragment.getChatMode(), parentFragment != null ? parentFragment.quickReplyShortcut : null, parentFragment != null ? parentFragment.getQuickReplyId() : 0); } if (delegate != null) { delegate.onMessageSend(null, true, scheduleDate); @@ -4738,7 +4738,7 @@ public void sendButtonPressed(int index, VideoEditedInfo videoEditedInfo, boolea photoEntry.reset(); sending = true; boolean updateStickersOrder = SendMessagesHelper.checkUpdateStickersOrder(info.caption); - SendMessagesHelper.prepareSendingMedia(accountInstance, photos, dialog_id, replyingMessageObject, getThreadMessage(), null, replyingQuote, false, false, editingMessageObject, notify, scheduleDate, updateStickersOrder, null); + SendMessagesHelper.prepareSendingMedia(accountInstance, photos, dialog_id, replyingMessageObject, getThreadMessage(), null, replyingQuote, false, false, editingMessageObject, notify, scheduleDate, parentFragment == null ? 0 : parentFragment.getChatMode(), updateStickersOrder, null, parentFragment != null ? parentFragment.quickReplyShortcut : null, parentFragment != null ? parentFragment.getQuickReplyId() : 0); if (delegate != null) { delegate.onMessageSend(null, true, scheduleDate); } @@ -5244,7 +5244,8 @@ private void updateSlowModeText() { boolean isUploading; if (info != null && info.slowmode_seconds != 0 && info.slowmode_next_send_date <= serverTime && ( (isUploading = SendMessagesHelper.getInstance(currentAccount).isUploadingMessageIdDialog(dialog_id)) || - SendMessagesHelper.getInstance(currentAccount).isSendingMessageIdDialog(dialog_id))) { + SendMessagesHelper.getInstance(currentAccount).isSendingMessageIdDialog(dialog_id)) + ) { TLRPC.Chat chat = accountInstance.getMessagesController().getChat(info.id); if (!ChatObject.hasAdminRights(chat) && !ChatObject.isIgnoredChatRestrictionsForBoosters(info)) { currentTime = info.slowmode_seconds; @@ -5952,7 +5953,15 @@ public void updateFieldHint(boolean animated) { } } - if (replyingMessageObject != null && replyingMessageObject.messageOwner.reply_markup != null && !TextUtils.isEmpty(replyingMessageObject.messageOwner.reply_markup.placeholder)) { + if (parentFragment != null && parentFragment.getChatMode() == ChatActivity.MODE_QUICK_REPLIES) { + if (QuickRepliesController.GREETING.equalsIgnoreCase(parentFragment.quickReplyShortcut)) { + messageEditText.setHintText(LocaleController.getString(R.string.BusinessGreetingEnter)); + } else if (QuickRepliesController.AWAY.equalsIgnoreCase(parentFragment.quickReplyShortcut)) { + messageEditText.setHintText(LocaleController.getString(R.string.BusinessAwayEnter)); + } else { + messageEditText.setHintText(LocaleController.getString(R.string.BusinessRepliesEnter)); + } + } else if (replyingMessageObject != null && replyingMessageObject.messageOwner.reply_markup != null && !TextUtils.isEmpty(replyingMessageObject.messageOwner.reply_markup.placeholder)) { messageEditText.setHintText(replyingMessageObject.messageOwner.reply_markup.placeholder, animated); } else if (editingMessageObject != null) { messageEditText.setHintText(editingCaption ? LocaleController.getString("Caption", R.string.Caption) : LocaleController.getString("TypeMessage", R.string.TypeMessage)); @@ -6359,6 +6368,8 @@ private void sendMessageInternal(boolean notify, int scheduleDate, boolean allow } MediaDataController.getInstance(currentAccount).pushDraftVoiceMessage(dialog_id, parentFragment != null && parentFragment.isTopic ? parentFragment.getTopicId() : 0, null); SendMessagesHelper.SendMessageParams params = SendMessagesHelper.SendMessageParams.of(audioToSend, null, audioToSendPath, dialog_id, replyingMessageObject, getThreadMessage(), null, null, null, null, notify, scheduleDate, voiceOnce ? 0x7FFFFFFF : 0, null, null, false); + params.quick_reply_shortcut = parentFragment != null ? parentFragment.quickReplyShortcut : null; + params.quick_reply_shortcut_id = parentFragment != null ? parentFragment.getQuickReplyId() : 0; applyStoryToSendMessageParams(params); SendMessagesHelper.getInstance(currentAccount).sendMessage(params); if (delegate != null) { @@ -6710,6 +6721,8 @@ public boolean processSendingText(CharSequence text, boolean notify, int schedul replyToTopMsg = replyingTopMessage; } SendMessagesHelper.SendMessageParams params = SendMessagesHelper.SendMessageParams.of(message[0].toString(), dialog_id, replyingMessageObject, replyToTopMsg, messageWebPage, messageWebPageSearch, entities, null, null, notify, scheduleDate, sendAnimationData, updateStickersOrder); + params.quick_reply_shortcut = parentFragment != null ? parentFragment.quickReplyShortcut : null; + params.quick_reply_shortcut_id = parentFragment != null ? parentFragment.getQuickReplyId() : 0; applyStoryToSendMessageParams(params); params.invert_media = parentFragment != null && parentFragment.messagePreviewParams != null && parentFragment.messagePreviewParams.webpageTop; if (parentFragment != null && parentFragment.getCurrentChat() != null && !ChatObject.canSendEmbed(parentFragment.getCurrentChat())) { @@ -8464,6 +8477,8 @@ public void setCommand(MessageObject messageObject, String command, boolean long } else { sendMessageParams = SendMessagesHelper.SendMessageParams.of(command, dialog_id, replyingMessageObject, getThreadMessage(), null, false, null, null, null, true, 0, null, false); } + sendMessageParams.quick_reply_shortcut = parentFragment != null ? parentFragment.quickReplyShortcut : null; + sendMessageParams.quick_reply_shortcut_id = parentFragment != null ? parentFragment.getQuickReplyId() : 0; applyStoryToSendMessageParams(sendMessageParams); SendMessagesHelper.getInstance(currentAccount).sendMessage(sendMessageParams); } @@ -8857,7 +8872,7 @@ public void setVoiceDraft(MediaDataController.DraftVoice draft) { controlsView.periodDrawable.setValue(1, voiceOnce, true); } TL_stories.StoryItem storyItem = delegate != null ? delegate.getReplyToStory() : null; - MediaController.getInstance().prepareResumedRecording(currentAccount, draft, dialog_id, replyingMessageObject, getThreadMessage(), storyItem, recordingGuid, true); + MediaController.getInstance().prepareResumedRecording(currentAccount, draft, dialog_id, replyingMessageObject, getThreadMessage(), storyItem, recordingGuid, true, parentFragment != null ? parentFragment.quickReplyShortcut : null, parentFragment != null ? parentFragment.getQuickReplyId() : 0); } public void setSelection(int start) { @@ -9252,7 +9267,7 @@ private void updateBotButton(boolean animated) { boolean hasBotWebView = hasBotWebView(); boolean canShowBotsMenu = botMenuButtonType != BotMenuButtonType.NO_BUTTON && dialog_id > 0; boolean wasVisible = botButton != null && botButton.getVisibility() == VISIBLE; - if (hasBotWebView || hasBotCommands || botReplyMarkup != null) { + if (hasBotWebView || hasBotCommands || hasQuickReplies || botReplyMarkup != null) { if (botReplyMarkup != null) { if (isPopupShowing() && currentPopupContentType == POPUP_CONTENT_BOT_KEYBOARD && botReplyMarkup.is_persistent) { if (botButton != null && botButton.getVisibility() != GONE) { @@ -9332,10 +9347,11 @@ public void updateBotWebView(boolean animated) { updateBotButton(animated); } - public void setBotsCount(int count, boolean hasCommands, boolean animated) { + public void setBotsCount(int count, boolean hasCommands, boolean hasQuickReplies, boolean animated) { botCount = count; - if (hasBotCommands != hasCommands) { + if (hasBotCommands != hasCommands || this.hasQuickReplies != hasQuickReplies) { hasBotCommands = hasCommands; + this.hasQuickReplies = hasQuickReplies; updateBotButton(animated); } } @@ -9427,8 +9443,12 @@ public boolean didPressedBotButton(final TLRPC.KeyboardButton button, final Mess if (button == null || messageObject == null) { return false; } + if (parentFragment != null && parentFragment.getChatMode() == ChatActivity.MODE_QUICK_REPLIES) return false; if (button instanceof TLRPC.TL_keyboardButton) { - SendMessagesHelper.getInstance(currentAccount).sendMessage(SendMessagesHelper.SendMessageParams.of(button.text, dialog_id, replyMessageObject, getThreadMessage(), null, false, null, null, null, true, 0, null, false)); + SendMessagesHelper.SendMessageParams params = SendMessagesHelper.SendMessageParams.of(button.text, dialog_id, replyMessageObject, getThreadMessage(), null, false, null, null, null, true, 0, null, false); + params.quick_reply_shortcut = parentFragment != null ? parentFragment.quickReplyShortcut : null; + params.quick_reply_shortcut_id = parentFragment != null ? parentFragment.getQuickReplyId() : 0; + SendMessagesHelper.getInstance(currentAccount).sendMessage(params); } else if (button instanceof TLRPC.TL_keyboardButtonUrl) { if (Browser.urlMustNotHaveConfirmation(button.url)) { Browser.openUrl(parentActivity, Uri.parse(button.url), true, true, progress); @@ -9824,7 +9844,7 @@ public void onGifSelected(View view, Object gif, String query, Object parent, bo TL_stories.StoryItem storyItem = delegate != null ? delegate.getReplyToStory() : null; if (gif instanceof TLRPC.Document) { TLRPC.Document document = (TLRPC.Document) gif; - SendMessagesHelper.getInstance(currentAccount).sendSticker(document, query, dialog_id, replyingMessageObject, getThreadMessage(), storyItem, replyingQuote, null, notify, scheduleDate, false, parent); + SendMessagesHelper.getInstance(currentAccount).sendSticker(document, query, dialog_id, replyingMessageObject, getThreadMessage(), storyItem, replyingQuote, null, notify, scheduleDate, false, parent, parentFragment != null ? parentFragment.quickReplyShortcut : null, parentFragment != null ? parentFragment.getQuickReplyId() : 0); MediaDataController.getInstance(currentAccount).addRecentGif(document, (int) (System.currentTimeMillis() / 1000), true); if (DialogObject.isEncryptedDialog(dialog_id)) { accountInstance.getMessagesController().saveGif(parent, document); @@ -9847,9 +9867,9 @@ public void onGifSelected(View view, Object gif, String query, Object parent, bo params.put("force_gif", "1"); if (storyItem == null) { - SendMessagesHelper.prepareSendingBotContextResult(parentFragment, accountInstance, result, params, dialog_id, replyingMessageObject, getThreadMessage(), null, replyingQuote, notify, scheduleDate); + SendMessagesHelper.prepareSendingBotContextResult(parentFragment, accountInstance, result, params, dialog_id, replyingMessageObject, getThreadMessage(), null, replyingQuote, notify, scheduleDate, parentFragment != null ? parentFragment.quickReplyShortcut : null, parentFragment != null ? parentFragment.getQuickReplyId() : 0); } else { - SendMessagesHelper.getInstance(currentAccount).sendSticker(result.document, query, dialog_id, replyingMessageObject, getThreadMessage(), storyItem, replyingQuote, null, notify, scheduleDate, false, parent); + SendMessagesHelper.getInstance(currentAccount).sendSticker(result.document, query, dialog_id, replyingMessageObject, getThreadMessage(), storyItem, replyingQuote, null, notify, scheduleDate, false, parent, parentFragment != null ? parentFragment.quickReplyShortcut : null, parentFragment != null ? parentFragment.getQuickReplyId() : 0); } if (searchingType != 0) { setSearchingTypeInternal(0, true); @@ -10109,7 +10129,7 @@ public void onStickerSelected(TLRPC.Document sticker, String query, Object paren } setStickersExpanded(false, true, false); TL_stories.StoryItem storyItem = delegate != null ? delegate.getReplyToStory() : null; - SendMessagesHelper.getInstance(currentAccount).sendSticker(sticker, query, dialog_id, replyingMessageObject, getThreadMessage(), storyItem, replyingQuote, sendAnimationData, notify, scheduleDate, parent instanceof TLRPC.TL_messages_stickerSet, parent); + SendMessagesHelper.getInstance(currentAccount).sendSticker(sticker, query, dialog_id, replyingMessageObject, getThreadMessage(), storyItem, replyingQuote, sendAnimationData, notify, scheduleDate, parent instanceof TLRPC.TL_messages_stickerSet, parent, parentFragment != null ? parentFragment.quickReplyShortcut : null, parentFragment != null ? parentFragment.getQuickReplyId() : 0); if (delegate != null) { delegate.onMessageSend(null, true, scheduleDate); } @@ -11019,7 +11039,7 @@ public void didReceivedNotification(int id, int account, Object... args) { botMenuWebViewTitle = webViewButton.text; botMenuWebViewUrl = webViewButton.url; botMenuButtonType = BotMenuButtonType.WEB_VIEW; - } else if (hasBotCommands) { + } else if (hasBotCommands || hasQuickReplies) { botMenuButtonType = BotMenuButtonType.COMMANDS; } else { botMenuButtonType = BotMenuButtonType.NO_BUTTON; 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 4e1674b433c..cf77553c930 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlert.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlert.java @@ -72,6 +72,7 @@ import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.AnimationNotificationsLocker; +import org.telegram.messenger.BuildVars; import org.telegram.messenger.ChatObject; import org.telegram.messenger.ContactsController; import org.telegram.messenger.DialogObject; @@ -104,6 +105,8 @@ import org.telegram.ui.ActionBar.Theme; import org.telegram.ui.ActionBar.ThemeDescription; import org.telegram.ui.BasePermissionsActivity; +import org.telegram.ui.Business.ChatAttachAlertQuickRepliesLayout; +import org.telegram.ui.Business.QuickRepliesController; import org.telegram.ui.ChatActivity; import org.telegram.ui.DialogsActivity; import org.telegram.ui.LaunchActivity; @@ -134,6 +137,7 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N public boolean canOpenPreview = false; private boolean isSoundPicker = false; public boolean isStoryLocationPicker = false; + public boolean isBizLocationPicker = false; public boolean isStoryAudioPicker = false; private ImageUpdater.AvatarFor setAvatarFor; public boolean pinnedToTop; @@ -582,172 +586,172 @@ public AttachAlertLayout(ChatAttachAlert alert, Context context, Theme.Resources parentAlert = alert; } - boolean onSheetKeyDown(int keyCode, KeyEvent event) { + public boolean onSheetKeyDown(int keyCode, KeyEvent event) { return false; } - boolean onDismiss() { + public boolean onDismiss() { return false; } - boolean onCustomMeasure(View view, int width, int height) { + public boolean onCustomMeasure(View view, int width, int height) { return false; } - boolean onCustomLayout(View view, int left, int top, int right, int bottom) { + public boolean onCustomLayout(View view, int left, int top, int right, int bottom) { return false; } - boolean onContainerViewTouchEvent(MotionEvent event) { + public boolean onContainerViewTouchEvent(MotionEvent event) { return false; } - void onPreMeasure(int availableWidth, int availableHeight) { + public void onPreMeasure(int availableWidth, int availableHeight) { } - void onMenuItemClick(int id) { + public void onMenuItemClick(int id) { } - boolean hasCustomBackground() { + public boolean hasCustomBackground() { return false; } - int getCustomBackground() { + public int getCustomBackground() { return 0; } - boolean hasCustomActionBarBackground() { + public boolean hasCustomActionBarBackground() { return false; } - int getCustomActionBarBackground() { + public int getCustomActionBarBackground() { return 0; } - void onButtonsTranslationYUpdated() { + public void onButtonsTranslationYUpdated() { } - boolean canScheduleMessages() { + public boolean canScheduleMessages() { return true; } - void checkColors() { + public void checkColors() { } - ArrayList getThemeDescriptions() { + public ArrayList getThemeDescriptions() { return null; } - void onPause() { + public void onPause() { } - void onResume() { + public void onResume() { } - boolean onDismissWithTouchOutside() { + public boolean onDismissWithTouchOutside() { return true; } - boolean canDismissWithTouchOutside() { + public boolean canDismissWithTouchOutside() { return true; } - void onDismissWithButtonClick(int item) { + public void onDismissWithButtonClick(int item) { } - void onContainerTranslationUpdated(float currentPanTranslationY) { + public void onContainerTranslationUpdated(float currentPanTranslationY) { } - void onHideShowProgress(float progress) { + public void onHideShowProgress(float progress) { } - void onOpenAnimationEnd() { + public void onOpenAnimationEnd() { } - void onInit(boolean hasVideo, boolean hasPhoto, boolean hasDocuments) { + public void onInit(boolean hasVideo, boolean hasPhoto, boolean hasDocuments) { } - int getSelectedItemsCount() { + public int getSelectedItemsCount() { return 0; } - void onSelectedItemsCountChanged(int count) { + public void onSelectedItemsCountChanged(int count) { } - void applyCaption(CharSequence text) { + public void applyCaption(CharSequence text) { } - void onDestroy() { + public void onDestroy() { } - void onHide() { + public void onHide() { } - void onHidden() { + public void onHidden() { } - int getCurrentItemTop() { + public int getCurrentItemTop() { return 0; } - int getFirstOffset() { + public int getFirstOffset() { return 0; } - int getButtonsHideOffset() { + public int getButtonsHideOffset() { return AndroidUtilities.dp(needsActionBar() != 0 ? 12 : 17); } - int getListTopPadding() { + public int getListTopPadding() { return 0; } - int needsActionBar() { + public int needsActionBar() { return 0; } - void sendSelectedItems(boolean notify, int scheduleDate) { + public void sendSelectedItems(boolean notify, int scheduleDate) { } - void onShow(AttachAlertLayout previousLayout) { + public void onShow(AttachAlertLayout previousLayout) { } - void onShown() { + public void onShown() { } - void scrollToTop() { + public void scrollToTop() { } - boolean onBackPressed() { + public boolean onBackPressed() { return false; } - protected int getThemedColor(int key) { + public int getThemedColor(int key) { return Theme.getColor(key, resourcesProvider); } - boolean shouldHideBottomButtons() { + public boolean shouldHideBottomButtons() { return true; } @@ -759,8 +763,8 @@ public void onPanTransitionEnd() { } @Nullable - final BaseFragment baseFragment; - protected boolean inBubbleMode; + public final BaseFragment baseFragment; + public boolean inBubbleMode; private ActionBarPopupWindow sendPopupWindow; private ActionBarPopupWindow.ActionBarPopupWindowLayout sendPopupLayout; private ActionBarMenuSubItem[] itemCells; @@ -775,13 +779,14 @@ public void onPanTransitionEnd() { private ChatAttachAlertDocumentLayout documentLayout; private ChatAttachAlertPhotoLayoutPreview photoPreviewLayout; public ChatAttachAlertColorsLayout colorsLayout; - private AttachAlertLayout[] layouts = new AttachAlertLayout[7]; + private ChatAttachAlertQuickRepliesLayout quickRepliesLayout; + private AttachAlertLayout[] layouts = new AttachAlertLayout[8]; private LongSparseArray botAttachLayouts = new LongSparseArray<>(); private AttachAlertLayout currentAttachLayout; private AttachAlertLayout nextAttachLayout; private FrameLayout frameLayout2; - protected EditTextEmoji commentTextView; + public EditTextEmoji commentTextView; private int[] commentTextViewLocation = new int[2]; private FrameLayout writeButtonContainer; private ImageView writeButton; @@ -844,7 +849,7 @@ public void onPanTransitionEnd() { private boolean buttonPressed; - protected int currentAccount = UserConfig.selectedAccount; + public final int currentAccount = UserConfig.selectedAccount; private boolean documentsEnabled = true; private boolean photosEnabled = true; @@ -866,7 +871,7 @@ public void onPanTransitionEnd() { protected ChatAttachViewDelegate delegate; - protected int[] scrollOffsetY = new int[2]; + public int[] scrollOffsetY = new int[2]; private int previousScrollOffsetY; private float fromScrollY; private float toScrollY; @@ -982,6 +987,15 @@ public void setTextAndIcon(int id, CharSequence text, RLottieDrawable drawable, textView.setTextColor(ColorUtils.blendARGB(getThemedColor(Theme.key_dialogTextGray2), getThemedColor(textKey), checkedState)); } + public void setTextAndIcon(int id, CharSequence text, Drawable drawable, int background, int textColor) { + currentId = id; + textView.setText(text); + imageView.setImageDrawable(drawable); + backgroundKey = background; + textKey = textColor; + textView.setTextColor(ColorUtils.blendARGB(getThemedColor(Theme.key_dialogTextGray2), getThemedColor(textKey), checkedState)); + } + @Override protected void onDraw(Canvas canvas) { float scale = imageView.getScaleX() + 0.06f * checkedState; @@ -1261,6 +1275,7 @@ public ChatAttachAlert(Context context, final @Nullable BaseFragment parentFragm NotificationCenter.getInstance(currentAccount).addObserver(this, NotificationCenter.reloadInlineHints); NotificationCenter.getInstance(currentAccount).addObserver(this, NotificationCenter.attachMenuBotsDidLoad); NotificationCenter.getInstance(currentAccount).addObserver(this, NotificationCenter.currentUserPremiumStatusChanged); + NotificationCenter.getInstance(currentAccount).addObserver(this, NotificationCenter.quickRepliesUpdated); exclusionRects.add(exclustionRect); sizeNotifierFrameLayout = new SizeNotifierFrameLayout(context) { @@ -1777,7 +1792,7 @@ protected boolean drawChild(Canvas canvas, View child, long drawingTime) { } boolean result; - if (child != contactsLayout && child != audioLayout) { + if (child != contactsLayout && child != quickRepliesLayout && child != audioLayout) { canvas.save(); canvas.clipRect(backgroundPaddingLeft, actionBar.getY() + actionBar.getMeasuredHeight() - currentPanTranslationY, getMeasuredWidth() - backgroundPaddingLeft, getMeasuredHeight()); result = super.drawChild(canvas, child, drawingTime); @@ -2271,6 +2286,8 @@ public void setTranslationY(float translationY) { } showLayout(pollLayout); } + } else if (num == 11) { + openQuickRepliesLayout(); } else { delegate.didPressedButton((Integer) view.getTag(), true, true, 0, false); } @@ -2684,7 +2701,7 @@ public void getOutline(View view, Outline outline) { chatActivity = (ChatActivity) baseFragment; TLRPC.Chat chat = chatActivity.getCurrentChat(); user = chatActivity.getCurrentUser(); - if (chatActivity.isInScheduleMode()) { + if (chatActivity.isInScheduleMode() || chatActivity.getChatMode() == ChatActivity.MODE_QUICK_REPLIES) { return false; } dialogId = chatActivity.getDialogId(); @@ -3013,6 +3030,8 @@ public void showLayout(AttachAlertLayout layout) { newId = 9; } else if (layout == colorsLayout) { newId = 10; + } else if (layout == quickRepliesLayout) { + newId = 11; } showLayout(layout, newId); } @@ -3250,11 +3269,33 @@ private void openContactsLayout() { } if (contactsLayout == null) { layouts[2] = contactsLayout = new ChatAttachAlertContactsLayout(this, getContext(), resourcesProvider); - contactsLayout.setDelegate((user, notify, scheduleDate) -> ((ChatActivity) baseFragment).sendContact(user, notify, scheduleDate)); + contactsLayout.setDelegate(new ChatAttachAlertContactsLayout.PhonebookShareAlertDelegate() { + @Override + public void didSelectContact(TLRPC.User user, boolean notify, int scheduleDate) { + ((ChatActivity) baseFragment).sendContact(user, notify, scheduleDate); + } + + @Override + public void didSelectContacts(ArrayList users, String caption, boolean notify, int scheduleDate) { + ((ChatActivity) baseFragment).sendContacts(users, caption, notify, scheduleDate); + } + }); + } + if (baseFragment instanceof ChatActivity) { + ChatActivity chatActivity = (ChatActivity) baseFragment; + TLRPC.Chat currentChat = chatActivity.getCurrentChat(); + contactsLayout.setMultipleSelectionAllowed(!(currentChat != null && !ChatObject.hasAdminRights(currentChat) && currentChat.slowmode_enabled)); } showLayout(contactsLayout); } + private void openQuickRepliesLayout() { + if (quickRepliesLayout == null) { + layouts[7] = quickRepliesLayout = new ChatAttachAlertQuickRepliesLayout(this, getContext(), resourcesProvider); + } + showLayout(quickRepliesLayout); + } + public boolean checkCanRemoveRestrictionsByBoosts() { return (baseFragment instanceof ChatActivity) && ((ChatActivity) baseFragment).checkCanRemoveRestrictionsByBoosts(); } @@ -3663,7 +3704,7 @@ protected boolean onContainerTouchEvent(MotionEvent event) { return currentAttachLayout.onContainerViewTouchEvent(event); } - protected void makeFocusable(EditTextBoldCursor editText, boolean showKeyboard) { + public void makeFocusable(EditTextBoldCursor editText, boolean showKeyboard) { if (delegate == null) { return; } @@ -3825,7 +3866,7 @@ public void onActivityResultFragment(int requestCode, Intent data, String curren @Override public void didReceivedNotification(int id, int account, Object... args) { - if (id == NotificationCenter.reloadInlineHints || id == NotificationCenter.attachMenuBotsDidLoad) { + if (id == NotificationCenter.reloadInlineHints || id == NotificationCenter.attachMenuBotsDidLoad || id == NotificationCenter.quickRepliesUpdated) { if (buttonsAdapter != null) { buttonsAdapter.notifyDataSetChanged(); } @@ -4004,7 +4045,7 @@ public void onAnimationCancel(Animator animation) { } @SuppressLint("NewApi") - protected void updateLayout(AttachAlertLayout layout, boolean animated, int dy) { + public void updateLayout(AttachAlertLayout layout, boolean animated, int dy) { if (layout == null) { return; } @@ -4182,7 +4223,7 @@ public void init() { enterCommentEventSent = false; setFocusable(false); ChatAttachAlert.AttachAlertLayout layoutToSet; - if (isStoryLocationPicker) { + if (isStoryLocationPicker || isBizLocationPicker) { if (locationLayout == null) { layouts[5] = locationLayout = new ChatAttachAlertLocationLayout(this, getContext(), resourcesProvider); locationLayout.setDelegate((location, live, notify, scheduleDate) -> ((ChatActivity) baseFragment).didSelectLocation(location, live, notify, scheduleDate)); @@ -4255,6 +4296,7 @@ public void onDestroy() { NotificationCenter.getInstance(currentAccount).removeObserver(this, NotificationCenter.reloadInlineHints); NotificationCenter.getInstance(currentAccount).removeObserver(this, NotificationCenter.attachMenuBotsDidLoad); NotificationCenter.getInstance(currentAccount).removeObserver(this, NotificationCenter.currentUserPremiumStatusChanged); + NotificationCenter.getInstance(currentAccount).removeObserver(this, NotificationCenter.quickRepliesUpdated); destroyed = true; if (commentTextView != null) { commentTextView.onDestroy(); @@ -4337,6 +4379,12 @@ public void setSoundPicker() { public File storyLocationPickerPhotoFile; public double[] storyLocationPickerLatLong; + public void setBusinessLocationPicker() { + isBizLocationPicker = true; + buttonsRecyclerView.setVisibility(View.GONE); + shadow.setVisibility(View.GONE); + } + public void setStoryLocationPicker() { isStoryLocationPicker = true; buttonsRecyclerView.setVisibility(View.GONE); @@ -4378,6 +4426,10 @@ public ChatAttachAlertPhotoLayout getPhotoLayout() { return photoLayout; } + public ChatAttachAlertLocationLayout getLocationLayout() { + return locationLayout; + } + private class ButtonsAdapter extends RecyclerListView.SelectionAdapter { private final static int VIEW_TYPE_BUTTON = 0, VIEW_TYPE_BOT_BUTTON = 1; @@ -4392,6 +4444,7 @@ private class ButtonsAdapter extends RecyclerListView.SelectionAdapter { private int musicButton; private int pollButton; private int contactButton; + private int quickRepliesButton; private int locationButton; private int buttonsCount; @@ -4440,6 +4493,9 @@ public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { } else if (position == contactButton) { attachButton.setTextAndIcon(5, LocaleController.getString("AttachContact", R.string.AttachContact), Theme.chat_attachButtonDrawables[3], Theme.key_chat_attachContactBackground, Theme.key_chat_attachContactText); attachButton.setTag(5); + } else if (position == quickRepliesButton) { + attachButton.setTextAndIcon(11, LocaleController.getString(R.string.AttachQuickReplies), getContext().getResources().getDrawable(R.drawable.ic_ab_reply).mutate(), Theme.key_chat_attachContactBackground, Theme.key_chat_attachContactText); + attachButton.setTag(11); } break; case VIEW_TYPE_BOT_BUTTON: @@ -4486,6 +4542,7 @@ public void notifyDataSetChanged() { musicButton = -1; pollButton = -1; contactButton = -1; + quickRepliesButton = -1; locationButton = -1; attachBotsStartRow = -1; attachBotsEndRow = -1; @@ -4510,7 +4567,7 @@ public void notifyDataSetChanged() { } else { galleryButton = buttonsCount++; if (photosEnabled || videosEnabled) { - if (baseFragment instanceof ChatActivity && !((ChatActivity) baseFragment).isInScheduleMode() && !((ChatActivity) baseFragment).isSecretChat()) { + if (baseFragment instanceof ChatActivity && !((ChatActivity) baseFragment).isInScheduleMode() && !((ChatActivity) baseFragment).isSecretChat() && ((ChatActivity) baseFragment).getChatMode() != ChatActivity.MODE_QUICK_REPLIES) { ChatActivity chatActivity = (ChatActivity) baseFragment; attachBotsStartRow = buttonsCount; @@ -4536,9 +4593,12 @@ public void notifyDataSetChanged() { } else if (plainTextEnabled) { contactButton = buttonsCount++; } + TLRPC.User user = baseFragment instanceof ChatActivity ? ((ChatActivity) baseFragment).getCurrentUser() : null; + if (baseFragment instanceof ChatActivity && ((ChatActivity) baseFragment).getChatMode() == 0 && user != null && !user.bot && QuickRepliesController.getInstance(currentAccount).hasReplies()) { + quickRepliesButton = buttonsCount++; + } musicButton = buttonsCount++; - TLRPC.User user = baseFragment instanceof ChatActivity ? ((ChatActivity) baseFragment).getCurrentUser() : null; if (user != null && user.bot) { contactButton = buttonsCount++; } @@ -4579,6 +4639,7 @@ private void removeFromRoot() { actionBar.closeSearchField(); } contactsLayout = null; + quickRepliesLayout = null; audioLayout = null; pollLayout = null; locationLayout = null; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlertAudioLayout.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlertAudioLayout.java index b80b26ba742..792a485f1e7 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlertAudioLayout.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlertAudioLayout.java @@ -234,7 +234,7 @@ public void onScrolled(RecyclerView recyclerView, int dx, int dy) { } @Override - void onDestroy() { + public void onDestroy() { onHide(); NotificationCenter.getInstance(parentAlert.currentAccount).removeObserver(this, NotificationCenter.messagePlayingDidReset); NotificationCenter.getInstance(parentAlert.currentAccount).removeObserver(this, NotificationCenter.messagePlayingDidStart); @@ -242,7 +242,7 @@ void onDestroy() { } @Override - void onHide() { + public void onHide() { if (playingAudio != null && MediaController.getInstance().isPlayingMessage(playingAudio)) { MediaController.getInstance().cleanupPlayer(true, true); } @@ -290,12 +290,12 @@ public void setMaxSelectedFiles(int value) { } @Override - void scrollToTop() { + public void scrollToTop() { listView.smoothScrollToPosition(0); } @Override - int getCurrentItemTop() { + public int getCurrentItemTop() { if (listView.getChildCount() <= 0) { return Integer.MAX_VALUE; } @@ -314,7 +314,7 @@ int getCurrentItemTop() { } @Override - int getFirstOffset() { + public int getFirstOffset() { return getListTopPadding() + AndroidUtilities.dp(4); } @@ -325,7 +325,7 @@ public void setTranslationY(float translationY) { } @Override - boolean onDismiss() { + public boolean onDismiss() { if (playingAudio != null && MediaController.getInstance().isPlayingMessage(playingAudio)) { MediaController.getInstance().cleanupPlayer(true, true); } @@ -333,7 +333,7 @@ boolean onDismiss() { } @Override - int getListTopPadding() { + public int getListTopPadding() { return listView.getPaddingTop(); } @@ -344,7 +344,7 @@ protected void onLayout(boolean changed, int left, int top, int right, int botto } @Override - void onPreMeasure(int availableWidth, int availableHeight) { + public void onPreMeasure(int availableWidth, int availableHeight) { int padding; if (parentAlert.sizeNotifierFrameLayout.measureKeyboardHeight() > AndroidUtilities.dp(20)) { padding = AndroidUtilities.dp(8); @@ -365,13 +365,13 @@ void onPreMeasure(int availableWidth, int availableHeight) { } @Override - void onShow(ChatAttachAlert.AttachAlertLayout previousLayout) { + public void onShow(ChatAttachAlert.AttachAlertLayout previousLayout) { layoutManager.scrollToPositionWithOffset(0, 0); listAdapter.notifyDataSetChanged(); } @Override - void onHidden() { + public void onHidden() { selectedAudios.clear(); selectedAudiosOrder.clear(); } @@ -489,12 +489,12 @@ private void onItemClick(View view) { } @Override - int getSelectedItemsCount() { + public int getSelectedItemsCount() { return selectedAudios.size(); } @Override - void sendSelectedItems(boolean notify, int scheduleDate) { + public void sendSelectedItems(boolean notify, int scheduleDate) { if (selectedAudios.size() == 0 || delegate == null || sendPressed) { return; } @@ -828,7 +828,7 @@ public int getItemViewType(int i) { } @Override - void onContainerTranslationUpdated(float currentPanTranslationY) { + public void onContainerTranslationUpdated(float currentPanTranslationY) { this.currentPanTranslationProgress = currentPanTranslationY; super.onContainerTranslationUpdated(currentPanTranslationY); updateEmptyViewPosition(); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlertBotWebViewLayout.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlertBotWebViewLayout.java index c56d94fef84..38bfbc1e01e 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlertBotWebViewLayout.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlertBotWebViewLayout.java @@ -127,7 +127,7 @@ public class ChatAttachAlertBotWebViewLayout extends ChatAttachAlert.AttachAlert private int customActionBarBackground; @Override - void onMenuItemClick(int id) { + public void onMenuItemClick(int id) { if (id == -1) { if (!webViewContainer.onBackPressed()) { onCheckDismissByUser(); @@ -239,7 +239,7 @@ public void setNeedCloseConfirmation(boolean needCloseConfirmation) { } @Override - boolean onDismissWithTouchOutside() { + public boolean onDismissWithTouchOutside() { onCheckDismissByUser(); return false; } @@ -273,7 +273,7 @@ public void setCustomBackground(int customBackground) { } @Override - boolean hasCustomBackground() { + public boolean hasCustomBackground() { return hasCustomBackground; } @@ -283,12 +283,12 @@ public int getCustomBackground() { } @Override - boolean hasCustomActionBarBackground() { + public boolean hasCustomActionBarBackground() { return hasCustomActionBarBackground; } @Override - int getCustomActionBarBackground() { + public int getCustomActionBarBackground() { return customActionBarBackground; } @@ -381,7 +381,7 @@ public void onPanTransitionEnd() { } @Override - void onShow(ChatAttachAlert.AttachAlertLayout previousLayout) { + public void onShow(ChatAttachAlert.AttachAlertLayout previousLayout) { CharSequence title = UserObject.getUserName(MessagesController.getInstance(currentAccount).getUser(botId)); try { TextPaint tp = new TextPaint(); @@ -404,7 +404,7 @@ void onShow(ChatAttachAlert.AttachAlertLayout previousLayout) { } @Override - void onShown() { + public void onShown() { if (webViewContainer.isPageLoaded()) { requestEnableKeyboard(); } @@ -427,7 +427,7 @@ private void requestEnableKeyboard() { } @Override - void onHidden() { + public void onHidden() { super.onHidden(); parentAlert.setFocusable(false); @@ -435,7 +435,7 @@ void onHidden() { } @Override - int getCurrentItemTop() { + public int getCurrentItemTop() { return (int) (swipeContainer.getSwipeOffsetY() + swipeContainer.getOffsetY()); } @@ -511,7 +511,7 @@ public void requestWebView(int currentAccount, long peerId, long botId, boolean } @Override - void onDestroy() { + public void onDestroy() { NotificationCenter.getInstance(currentAccount).removeObserver(this, NotificationCenter.webViewResultSent); NotificationCenter.getGlobalInstance().removeObserver(this, NotificationCenter.didSetNewTheme); @@ -526,7 +526,7 @@ void onDestroy() { } @Override - void onHide() { + public void onHide() { super.onHide(); otherItem.setVisibility(GONE); isBotButtonAvailable = false; @@ -550,17 +550,17 @@ public boolean needReload() { } @Override - int getListTopPadding() { + public int getListTopPadding() { return (int) swipeContainer.getOffsetY(); } @Override - int getFirstOffset() { + public int getFirstOffset() { return getListTopPadding() + AndroidUtilities.dp(56); } @Override - void onPreMeasure(int availableWidth, int availableHeight) { + public void onPreMeasure(int availableWidth, int availableHeight) { int padding; if (!AndroidUtilities.isTablet() && AndroidUtilities.displaySize.x > AndroidUtilities.displaySize.y) { padding = (int) (availableHeight / 3.5f); @@ -580,12 +580,12 @@ void onPreMeasure(int availableWidth, int availableHeight) { } @Override - int getButtonsHideOffset() { + public int getButtonsHideOffset() { return (int) swipeContainer.getTopActionBarOffsetY() + AndroidUtilities.dp(12); } @Override - boolean onBackPressed() { + public boolean onBackPressed() { if (webViewContainer.onBackPressed()) { return true; } @@ -602,17 +602,17 @@ public void requestLayout() { } @Override - void scrollToTop() { + public void scrollToTop() { swipeContainer.stickTo(-swipeContainer.getOffsetY() + swipeContainer.getTopActionBarOffsetY()); } @Override - boolean shouldHideBottomButtons() { + public boolean shouldHideBottomButtons() { return false; } @Override - int needsActionBar() { + public int needsActionBar() { return 1; } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlertColorsLayout.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlertColorsLayout.java index a9db7d254e6..1d736e9e4c9 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlertColorsLayout.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlertColorsLayout.java @@ -129,24 +129,24 @@ public int getSpanSize(int position) { } @Override - void scrollToTop() { + public void scrollToTop() { gridView.smoothScrollToPosition(0); } @Override - int needsActionBar() { + public int needsActionBar() { return 1; } @Override - int getListTopPadding() { + public int getListTopPadding() { return gridView.getPaddingTop(); } public int currentItemTop = 0; @Override - int getCurrentItemTop() { + public int getCurrentItemTop() { if (gridView.getChildCount() <= 0) { gridView.setTopGlowOffset(currentItemTop = gridView.getPaddingTop()); return Integer.MAX_VALUE; @@ -163,7 +163,7 @@ int getCurrentItemTop() { } @Override - int getFirstOffset() { + public int getFirstOffset() { return getListTopPadding() + AndroidUtilities.dp(56); } @@ -272,7 +272,7 @@ public int getItemViewType(int position) { } @Override - void onShow(ChatAttachAlert.AttachAlertLayout previousLayout) { + public void onShow(ChatAttachAlert.AttachAlertLayout previousLayout) { try { parentAlert.actionBar.getTitleTextView().setBuildFullLayout(true); } catch (Exception ignore) {} 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 1a738067eeb..8093037771c 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlertContactsLayout.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlertContactsLayout.java @@ -14,7 +14,9 @@ import android.animation.ObjectAnimator; import android.content.Context; import android.graphics.Canvas; +import android.net.Uri; import android.os.Build; +import android.provider.ContactsContract; import android.text.TextUtils; import android.view.Gravity; import android.view.MotionEvent; @@ -39,18 +41,24 @@ import org.telegram.messenger.Utilities; import org.telegram.messenger.support.LongSparseIntArray; import org.telegram.tgnet.TLRPC; +import org.telegram.ui.ActionBar.AlertDialog; import org.telegram.ui.ActionBar.SimpleTextView; import org.telegram.ui.ActionBar.Theme; import org.telegram.ui.ActionBar.ThemeDescription; import java.util.ArrayList; import java.util.HashMap; +import java.util.Locale; +import java.util.Objects; public class ChatAttachAlertContactsLayout extends ChatAttachAlert.AttachAlertLayout implements NotificationCenter.NotificationCenterDelegate { private FrameLayout frameLayout; private RecyclerListView listView; private FillLastLinearLayoutManager layoutManager; + private HashMap selectedContacts = new HashMap<>(); + private ArrayList selectedContactsOrder = new ArrayList<>(); + private boolean sendPressed = false; private ShareAdapter listAdapter; private ShareSearchAdapter searchAdapter; private EmptyTextProgressView emptyView; @@ -62,8 +70,14 @@ public class ChatAttachAlertContactsLayout extends ChatAttachAlert.AttachAlertLa private PhonebookShareAlertDelegate delegate; + private boolean multipleSelectionAllowed; + public interface PhonebookShareAlertDelegate { void didSelectContact(TLRPC.User user, boolean notify, int scheduleDate); + + default void didSelectContacts(ArrayList users, String caption, boolean notify, int scheduleDate) { + + } } public static class UserCell extends FrameLayout { @@ -72,6 +86,7 @@ public static class UserCell extends FrameLayout { private BackupImageView avatarImageView; private SimpleTextView nameTextView; private SimpleTextView statusTextView; + private CheckBox2 checkBox; private AvatarDrawable avatarDrawable; private TLRPC.User currentUser; @@ -119,6 +134,12 @@ public boolean setText(CharSequence value, boolean force) { statusTextView.setTextColor(getThemedColor(Theme.key_dialogTextGray2)); statusTextView.setGravity((LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.TOP); addView(statusTextView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 20, (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.TOP, LocaleController.isRTL ? 28 : 72, 36, LocaleController.isRTL ? 72 : 28, 0)); + + checkBox = new CheckBox2(context, 21, resourcesProvider); + checkBox.setColor(-1, Theme.key_windowBackgroundWhite, Theme.key_checkboxCheck); + checkBox.setDrawUnchecked(false); + checkBox.setDrawBackgroundAsArc(3); + addView(checkBox, LayoutHelper.createFrame(24, 24, (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.TOP, LocaleController.isRTL ? 0 : 44, 37, LocaleController.isRTL ? 44 : 0, 0)); } public void setCurrentId(int id) { @@ -156,6 +177,13 @@ public void setData(TLRPC.User user, CharSequence name, CharSequenceCallback sta }); } + public void setChecked(boolean checked, boolean animated) { + if (checkBox.getVisibility() != VISIBLE) { + checkBox.setVisibility(VISIBLE); + } + checkBox.setChecked(checked, animated); + } + public void setStatus(CharSequence status) { currentStatus = status; if (currentStatus != null) { @@ -276,6 +304,51 @@ protected int getThemedColor(int key) { } } + private static class ListItemID { + public enum Type { + USER, + CONTACT + } + + private final Type type; + private final long id; + + public static ListItemID of(Object object) { + if (object instanceof ContactsController.Contact) { + return new ListItemID(Type.CONTACT, ((ContactsController.Contact) object).contact_id); + } else if (object instanceof TLRPC.User) { + return new ListItemID(Type.USER, ((TLRPC.User) object).id); + } + return null; + } + + public ListItemID(Type type, long id) { + this.type = type; + this.id = id; + } + + public Type getType() { + return type; + } + + public long getId() { + return id; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + ListItemID listItemID = (ListItemID) o; + return id == listItemID.id && type == listItemID.type; + } + + @Override + public int hashCode() { + return Objects.hash(type, id); + } + } + public ChatAttachAlertContactsLayout(ChatAttachAlert alert, Context context, Theme.ResourcesProvider resourcesProvider) { super(alert, context, resourcesProvider); @@ -365,6 +438,8 @@ protected int calculateTimeForDeceleration(int dx) { layoutManager.setBind(false); listView.setHorizontalScrollBarEnabled(false); listView.setVerticalScrollBarEnabled(false); + listView.setClipToPadding(false); + listView.setPadding(0, 0, 0, AndroidUtilities.dp(48)); addView(listView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.TOP | Gravity.LEFT, 0, 0, 0, 0)); listView.setAdapter(listAdapter = new ShareAdapter(context)); listView.setGlowColor(getThemedColor(Theme.key_dialogScrollGlow)); @@ -382,6 +457,11 @@ protected int calculateTimeForDeceleration(int dx) { } if (object != null) { + if (!selectedContacts.isEmpty()) { + addOrRemoveSelectedContact((UserCell) view, object); + return; + } + ContactsController.Contact contact; String firstName; String lastName; @@ -419,6 +499,22 @@ public void onScrolled(RecyclerView recyclerView, int dx, int dy) { } }); + listView.setOnItemLongClickListener((view, position) -> { + Object object; + if (listView.getAdapter() == searchAdapter) { + object = searchAdapter.getItem(position); + } else { + object = listAdapter.getItem(position); + } + + if (object != null) { + addOrRemoveSelectedContact((UserCell) view, object); + return true; + } + + return false; + }); + FrameLayout.LayoutParams frameLayoutParams = new FrameLayout.LayoutParams(LayoutHelper.MATCH_PARENT, AndroidUtilities.getShadowHeight(), Gravity.TOP | Gravity.LEFT); frameLayoutParams.topMargin = AndroidUtilities.dp(58); shadow = new View(context); @@ -433,13 +529,191 @@ public void onScrolled(RecyclerView recyclerView, int dx, int dy) { updateEmptyView(); } + public void addOrRemoveSelectedContact(UserCell cell, Object object) { + if (selectedContacts.isEmpty() && !multipleSelectionAllowed) { + showErrorBox(LocaleController.formatString("AttachContactsSlowMode", R.string.AttachContactsSlowMode)); + return; + } + + boolean checked; + ListItemID id = ListItemID.of(object); + if (selectedContacts.containsKey(id)) { + selectedContacts.remove(id); + selectedContactsOrder.remove(id); + checked = false; + } else { + selectedContacts.put(id, object); + selectedContactsOrder.add(id); + checked = true; + } + cell.setChecked(checked, true); + parentAlert.updateCountButton(checked ? 1 : 2); + } + + public void setMultipleSelectionAllowed(boolean multipleSelectionAllowed) { + this.multipleSelectionAllowed = multipleSelectionAllowed; + } + @Override - void scrollToTop() { + public int getSelectedItemsCount() { + return selectedContacts.size(); + } + + private void showErrorBox(String error) { + new AlertDialog.Builder(getContext(), resourcesProvider).setTitle(LocaleController.getString("AppName", R.string.AppName)).setMessage(error).setPositiveButton(LocaleController.getString("OK", R.string.OK), null).show(); + } + + private TLRPC.User prepareContact(Object object) { + ContactsController.Contact contact; + String firstName; + String lastName; + if (object instanceof ContactsController.Contact) { + contact = (ContactsController.Contact) object; + if (contact.user != null) { + firstName = contact.user.first_name; + lastName = contact.user.last_name; + } else { + firstName = contact.first_name; + lastName = contact.last_name; + } + } else { + TLRPC.User user = (TLRPC.User) object; + contact = new ContactsController.Contact(); + firstName = contact.first_name = user.first_name; + lastName = contact.last_name = user.last_name; + contact.phones.add(user.phone); + contact.user = user; + } + + String name = ContactsController.formatName(firstName, lastName); + ArrayList result = null; + ArrayList items = new ArrayList<>(); + ArrayList phones = new ArrayList<>(); + ArrayList other = new ArrayList<>(); + ArrayList vcard = null; + if (contact.key != null) { + Uri uri = Uri.withAppendedPath(ContactsContract.Contacts.CONTENT_VCARD_URI, contact.key); + result = AndroidUtilities.loadVCardFromStream(uri, parentAlert.currentAccount, true, items, name); + } else { + AndroidUtilities.VcardItem item = new AndroidUtilities.VcardItem(); + item.type = 0; + item.vcardData.add(item.fullData = "TEL;MOBILE:+" + contact.user.phone); + phones.add(item); + } + TLRPC.User user = contact.user; + if (result != null) { + for (int a = 0; a < items.size(); a++) { + AndroidUtilities.VcardItem item = items.get(a); + if (item.type == 0) { + boolean exists = false; + for (int b = 0; b < phones.size(); b++) { + if (phones.get(b).getValue(false).equals(item.getValue(false))) { + exists = true; + break; + } + } + if (exists) { + item.checked = false; + continue; + } + phones.add(item); + } else { + other.add(item); + } + } + if (!result.isEmpty()) { + TLRPC.User u = result.get(0); + vcard = u.restriction_reason; + if (TextUtils.isEmpty(firstName)) { + firstName = u.first_name; + lastName = u.last_name; + } + } + } + + TLRPC.User currentUser = new TLRPC.TL_userContact_old2(); + + if (user != null) { + currentUser.id = user.id; + currentUser.access_hash = user.access_hash; + currentUser.photo = user.photo; + currentUser.status = user.status; + currentUser.first_name = user.first_name; + currentUser.last_name = user.last_name; + currentUser.phone = user.phone; + if (vcard != null) { + currentUser.restriction_reason = vcard; + } + } else { + currentUser.first_name = firstName; + currentUser.last_name = lastName; + } + + StringBuilder builder; + if (!currentUser.restriction_reason.isEmpty()) { + builder = new StringBuilder(currentUser.restriction_reason.get(0).text); + } else { + builder = new StringBuilder(String.format(Locale.US, "BEGIN:VCARD\nVERSION:3.0\nFN:%1$s\nEND:VCARD", ContactsController.formatName(currentUser.first_name, currentUser.last_name))); + } + int idx = builder.lastIndexOf("END:VCARD"); + if (idx >= 0) { + currentUser.phone = null; + for (int a = phones.size() - 1; a >= 0; a--) { + AndroidUtilities.VcardItem item = phones.get(a); + if (!item.checked) { + continue; + } + if (currentUser.phone == null) { + currentUser.phone = item.getValue(false); + } + for (int b = 0; b < item.vcardData.size(); b++) { + builder.insert(idx, item.vcardData.get(b) + "\n"); + } + } + for (int a = other.size() - 1; a >= 0; a--) { + AndroidUtilities.VcardItem item = other.get(a); + if (!item.checked) { + continue; + } + for (int b = item.vcardData.size() - 1; b >= 0; b--) { + builder.insert(idx, item.vcardData.get(b) + "\n"); + } + } + currentUser.restriction_reason.clear(); + TLRPC.TL_restrictionReason reason = new TLRPC.TL_restrictionReason(); + reason.text = builder.toString(); + reason.reason = ""; + reason.platform = ""; + currentUser.restriction_reason.add(reason); + } + + return currentUser; + } + + @Override + public void sendSelectedItems(boolean notify, int scheduleDate) { + if (selectedContacts.size() == 0 && delegate == null || sendPressed) { + return; + } + sendPressed = true; + + ArrayList users = new ArrayList<>(selectedContacts.size()); + + for (ListItemID id : selectedContactsOrder) { + Object object = selectedContacts.get(id); + users.add(prepareContact(object)); + } + + delegate.didSelectContacts(users, parentAlert.commentTextView.getText().toString(), notify, scheduleDate); + } + + @Override + public void scrollToTop() { listView.smoothScrollToPosition(0); } @Override - int getCurrentItemTop() { + public int getCurrentItemTop() { if (listView.getChildCount() <= 0) { return Integer.MAX_VALUE; } @@ -458,7 +732,7 @@ int getCurrentItemTop() { } @Override - int getFirstOffset() { + public int getFirstOffset() { return getListTopPadding() + AndroidUtilities.dp(4); } @@ -469,12 +743,12 @@ public void setTranslationY(float translationY) { } @Override - int getListTopPadding() { + public int getListTopPadding() { return listView.getPaddingTop(); } @Override - void onPreMeasure(int availableWidth, int availableHeight) { + public void onPreMeasure(int availableWidth, int availableHeight) { int padding; if (parentAlert.sizeNotifierFrameLayout.measureKeyboardHeight() > AndroidUtilities.dp(20)) { padding = AndroidUtilities.dp(8); @@ -489,7 +763,7 @@ void onPreMeasure(int availableWidth, int availableHeight) { } if (listView.getPaddingTop() != padding) { ignoreLayout = true; - listView.setPadding(0, padding, 0, 0); + listView.setPadding(0, padding, 0, AndroidUtilities.dp(48)); ignoreLayout = false; } } @@ -561,12 +835,12 @@ public void didReceivedNotification(int id, int account, Object... args) { } @Override - void onDestroy() { + public void onDestroy() { NotificationCenter.getInstance(parentAlert.currentAccount).removeObserver(this, NotificationCenter.contactsDidLoad); } @Override - void onShow(ChatAttachAlert.AttachAlertLayout previousLayout) { + public void onShow(ChatAttachAlert.AttachAlertLayout previousLayout) { layoutManager.scrollToPositionWithOffset(0, 0); } @@ -698,6 +972,8 @@ public void onBindViewHolder(int section, int position, RecyclerView.ViewHolder final TLRPC.User finalUser = user; userCell.setData(user, null, () -> PhoneFormat.getInstance().format("+" + finalUser.phone), divider); } + + userCell.setChecked(selectedContacts.containsKey(ListItemID.of(object)), false); } } @@ -933,6 +1209,8 @@ public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { final TLRPC.User finalUser = user; userCell.setData(user, searchResultNames.get(position - 1), () -> PhoneFormat.getInstance().format("+" + finalUser.phone), divider); } + + userCell.setChecked(selectedContacts.containsKey(ListItemID.of(object)), false); } } 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 c72ada79b44..b95557546e6 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlertDocumentLayout.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlertDocumentLayout.java @@ -634,7 +634,7 @@ private void prepareAnimation() { } @Override - void onDestroy() { + public void onDestroy() { try { if (receiverRegistered) { ApplicationLoader.applicationContext.unregisterReceiver(receiver); @@ -649,7 +649,7 @@ void onDestroy() { } @Override - void onMenuItemClick(int id) { + public void onMenuItemClick(int id) { if (id == sort_button) { SharedConfig.toggleSortFilesByName(); sortByName = SharedConfig.sortFilesByName; @@ -661,12 +661,12 @@ void onMenuItemClick(int id) { } @Override - int needsActionBar() { + public int needsActionBar() { return 1; } @Override - int getCurrentItemTop() { + public int getCurrentItemTop() { if (listView.getChildCount() <= 0) { return Integer.MAX_VALUE; } @@ -687,17 +687,17 @@ public void setTranslationY(float translationY) { } @Override - int getListTopPadding() { + public int getListTopPadding() { return listView.getPaddingTop(); } @Override - int getFirstOffset() { + public int getFirstOffset() { return getListTopPadding() + AndroidUtilities.dp(5); } @Override - void onPreMeasure(int availableWidth, int availableHeight) { + public void onPreMeasure(int availableWidth, int availableHeight) { int padding; if (parentAlert.actionBar.isSearchFieldVisible() || parentAlert.sizeNotifierFrameLayout.measureKeyboardHeight() > AndroidUtilities.dp(20)) { padding = AndroidUtilities.dp(56); @@ -724,7 +724,7 @@ void onPreMeasure(int availableWidth, int availableHeight) { } @Override - int getButtonsHideOffset() { + public int getButtonsHideOffset() { return AndroidUtilities.dp(62); } @@ -737,17 +737,17 @@ public void requestLayout() { } @Override - void scrollToTop() { + public void scrollToTop() { listView.smoothScrollToPosition(0); } @Override - int getSelectedItemsCount() { + public int getSelectedItemsCount() { return selectedFiles.size() + selectedMessages.size(); } @Override - void sendSelectedItems(boolean notify, int scheduleDate) { + public void sendSelectedItems(boolean notify, int scheduleDate) { if (selectedFiles.size() == 0 && selectedMessages.size() == 0 || delegate == null || sendPressed) { return; } @@ -1036,7 +1036,7 @@ public void onResume() { } @Override - void onShow(ChatAttachAlert.AttachAlertLayout previousLayout) { + public void onShow(ChatAttachAlert.AttachAlertLayout previousLayout) { selectedFiles.clear(); selectedMessages.clear(); searchAdapter.currentSearchFilters.clear(); @@ -1051,7 +1051,7 @@ void onShow(ChatAttachAlert.AttachAlertLayout previousLayout) { } @Override - void onHide() { + public void onHide() { sortItem.setVisibility(GONE); searchItem.setVisibility(GONE); } @@ -2250,7 +2250,7 @@ public void getPositionForScrollProgress(RecyclerListView listView, float progre } @Override - ArrayList getThemeDescriptions() { + public ArrayList getThemeDescriptions() { ArrayList themeDescriptions = new ArrayList<>(); themeDescriptions.add(new ThemeDescription(searchItem.getSearchField(), ThemeDescription.FLAG_CURSORCOLOR, null, null, null, null, Theme.key_dialogTextBlack)); 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 939cf17372b..7c2246ff15c 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlertLocationLayout.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlertLocationLayout.java @@ -179,6 +179,7 @@ public class ChatAttachAlertLocationLayout extends ChatAttachAlert.AttachAlertLa public final static int LOCATION_TYPE_SEND = 0; public final static int LOCATION_TYPE_SEND_WITH_LIVE = 1; public final static int LOCATION_TYPE_STORY = 7; + public final static int LOCATION_TYPE_BIZ = 8; public static class VenueLocation { public int num; @@ -374,6 +375,8 @@ public ChatAttachAlertLocationLayout(ChatAttachAlert alert, Context context, The dialogId = chatActivity.getDialogId(); if (parentAlert.isStoryLocationPicker) { locationType = LOCATION_TYPE_STORY; + } else if (parentAlert.isBizLocationPicker) { + locationType = LOCATION_TYPE_BIZ; } else if (chatActivity.getCurrentEncryptedChat() == null && !chatActivity.isInScheduleMode() && !UserObject.isUserSelf(chatActivity.getCurrentUser())) { locationType = LOCATION_TYPE_SEND_WITH_LIVE; } else { @@ -455,7 +458,7 @@ public void onTextChanged(EditText editText) { searchAdapter.searchDelayed(text, userLocation); } }); - searchItem.setVisibility(locationDenied && !parentAlert.isStoryLocationPicker ? View.GONE : View.VISIBLE); + searchItem.setVisibility(locationDenied && !parentAlert.isStoryLocationPicker || parentAlert.isBizLocationPicker ? View.GONE : View.VISIBLE); searchItem.setSearchFieldHint(LocaleController.getString("Search", R.string.Search)); searchItem.setContentDescription(LocaleController.getString("Search", R.string.Search)); EditTextBoldCursor editText = searchItem.getSearchField(); @@ -463,7 +466,7 @@ public void onTextChanged(EditText editText) { editText.setCursorColor(getThemedColor(Theme.key_dialogTextBlack)); editText.setHintTextColor(getThemedColor(Theme.key_chat_messagePanelHint)); - FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, AndroidUtilities.dp(21)); + LayoutParams layoutParams = new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, AndroidUtilities.dp(21)); layoutParams.gravity = Gravity.LEFT | Gravity.BOTTOM; mapViewClip = new FrameLayout(context) { @@ -622,7 +625,7 @@ public void getOutline(View view, Outline outline) { locationButton.setColorFilter(new PorterDuffColorFilter(getThemedColor(Theme.key_location_actionActiveIcon), PorterDuff.Mode.MULTIPLY)); locationButton.setTag(Theme.key_location_actionActiveIcon); locationButton.setContentDescription(LocaleController.getString("AccDescrMyLocation", R.string.AccDescrMyLocation)); - FrameLayout.LayoutParams layoutParams1 = LayoutHelper.createFrame(Build.VERSION.SDK_INT >= 21 ? 40 : 44, Build.VERSION.SDK_INT >= 21 ? 40 : 44, Gravity.RIGHT | Gravity.BOTTOM, 0, 0, 12, 12); + LayoutParams layoutParams1 = LayoutHelper.createFrame(Build.VERSION.SDK_INT >= 21 ? 40 : 44, Build.VERSION.SDK_INT >= 21 ? 40 : 44, Gravity.RIGHT | Gravity.BOTTOM, 0, 0, 12, 12); mapViewClip.addView(locationButton, layoutParams1); locationButton.setOnClickListener(v -> { if (Build.VERSION.SDK_INT >= 23) { @@ -642,7 +645,7 @@ public void getOutline(View view, Outline outline) { showSearchPlacesButton(false); map.animateCamera(ApplicationLoader.getMapsProvider().newCameraUpdateLatLng(new IMapsProvider.LatLng(myLocation.getLatitude(), myLocation.getLongitude()))); if (searchedForCustomLocations) { - if (myLocation != null) { + if (myLocation != null && locationType != LOCATION_TYPE_BIZ) { adapter.searchPlacesWithQuery(null, myLocation, true, true); } searchedForCustomLocations = false; @@ -688,7 +691,7 @@ protected void onLayout(boolean changed, int l, int t, int r, int b) { } }; listView.setClipToPadding(false); - listView.setAdapter(adapter = new LocationActivityAdapter(context, locationType, dialogId, true, resourcesProvider, parentAlert.isStoryLocationPicker)); + listView.setAdapter(adapter = new LocationActivityAdapter(context, locationType, dialogId, true, resourcesProvider, parentAlert.isStoryLocationPicker, parentAlert.isBizLocationPicker)); DefaultItemAnimator itemAnimator = new DefaultItemAnimator(); itemAnimator.setDurations(350); itemAnimator.setInterpolator(CubicBezierInterpolator.EASE_OUT_QUINT); @@ -910,7 +913,7 @@ public void onScrolled(RecyclerView recyclerView, int dx, int dy) { searchListView = new RecyclerListView(context, resourcesProvider); searchListView.setVisibility(GONE); searchListView.setLayoutManager(new LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false)); - searchAdapter = new LocationActivitySearchAdapter(context, resourcesProvider, parentAlert.isStoryLocationPicker) { + searchAdapter = new LocationActivitySearchAdapter(context, resourcesProvider, parentAlert.isStoryLocationPicker, parentAlert.isBizLocationPicker) { @Override public void notifyDataSetChanged() { if (searchItem != null) { @@ -956,12 +959,12 @@ public void onScrollStateChanged(RecyclerView recyclerView, int newState) { } @Override - boolean shouldHideBottomButtons() { + public boolean shouldHideBottomButtons() { return !locationDenied; } @Override - void onPause() { + public void onPause() { if (mapView != null && mapsInitialized) { try { mapView.onPause(); @@ -973,7 +976,7 @@ void onPause() { } @Override - void onDestroy() { + public void onDestroy() { NotificationCenter.getGlobalInstance().removeObserver(this, NotificationCenter.locationPermissionGranted); NotificationCenter.getGlobalInstance().removeObserver(this, NotificationCenter.locationPermissionDenied); doNotDrawMap = true; @@ -1017,23 +1020,23 @@ void onDestroy() { } @Override - void onHide() { + public void onHide() { searchItem.setVisibility(GONE); } @Override - int needsActionBar() { + public int needsActionBar() { return 1; } @Override - boolean onDismiss() { + public boolean onDismiss() { onDestroy(); return false; } @Override - int getCurrentItemTop() { + public int getCurrentItemTop() { if (listView.getChildCount() <= 0) { return Integer.MAX_VALUE; } @@ -1054,17 +1057,17 @@ public void setTranslationY(float translationY) { } @Override - int getListTopPadding() { + public int getListTopPadding() { return listView.getPaddingTop(); } @Override - int getFirstOffset() { + public int getFirstOffset() { return getListTopPadding() + AndroidUtilities.dp(56); } @Override - void onPreMeasure(int availableWidth, int availableHeight) { + public void onPreMeasure(int availableWidth, int availableHeight) { int padding; if (parentAlert.actionBar.isSearchFieldVisible() || parentAlert.sizeNotifierFrameLayout.measureKeyboardHeight() > AndroidUtilities.dp(20)) { padding = mapHeight - overScrollHeight; @@ -1100,7 +1103,7 @@ protected void onLayout(boolean changed, int left, int top, int right, int botto } @Override - int getButtonsHideOffset() { + public int getButtonsHideOffset() { return AndroidUtilities.dp(56); } @@ -1113,7 +1116,7 @@ public void requestLayout() { } @Override - void scrollToTop() { + public void scrollToTop() { listView.smoothScrollToPosition(0); } @@ -1148,6 +1151,9 @@ private void showSearchPlacesButton(boolean show) { show = false; } } + if (locationType == LOCATION_TYPE_BIZ) { + show = false; + } if (searchAreaButton == null || show && searchAreaButton.getTag() != null || !show && searchAreaButton.getTag() == null) { return; } @@ -1315,7 +1321,7 @@ private void onMapInit() { return; } positionMarker(location); - if (adapter != null && locationType == LOCATION_TYPE_STORY && !userLocationMoved) { + if (adapter != null && (locationType == LOCATION_TYPE_STORY || locationType == LOCATION_TYPE_BIZ) && !userLocationMoved) { adapter.setCustomLocation(userLocation); } getLocationController().setMapLocation(location, isFirstLocation); @@ -1415,7 +1421,9 @@ private void resetMapPosition(double lat, double _long) { if (lat != 0 && _long != 0) { userLocationMoved = true; showSearchPlacesButton(false); - adapter.searchPlacesWithQuery(null, userLocation, true, true); + if (locationType != LOCATION_TYPE_BIZ) { + adapter.searchPlacesWithQuery(null, userLocation, true, true); + } searchedForCustomLocations = true; showResults(); } @@ -1543,7 +1551,7 @@ private boolean isTypeSend() { private int buttonsHeight() { int buttonsHeight = AndroidUtilities.dp(66); - if (locationType == LOCATION_TYPE_SEND_WITH_LIVE || locationType == LOCATION_TYPE_STORY) + if (locationType == LOCATION_TYPE_SEND_WITH_LIVE || locationType == LOCATION_TYPE_STORY || locationType == LOCATION_TYPE_BIZ) buttonsHeight += AndroidUtilities.dp(66); return buttonsHeight; } @@ -1664,7 +1672,7 @@ private void positionMarker(Location location) { if (map != null) { IMapsProvider.LatLng latLng = new IMapsProvider.LatLng(location.getLatitude(), location.getLongitude()); if (adapter != null) { - if (!searchedForCustomLocations) { + if (!searchedForCustomLocations && locationType != LOCATION_TYPE_BIZ) { adapter.searchPlacesWithQuery(null, myLocation, true); } adapter.setGpsLocation(myLocation); @@ -1715,7 +1723,7 @@ public void didReceivedNotification(int id, int account, Object... args) { } } fixLayoutInternal(true); - searchItem.setVisibility(locationDenied && !parentAlert.isStoryLocationPicker ? View.GONE : View.VISIBLE); + searchItem.setVisibility(locationDenied && !parentAlert.isStoryLocationPicker || parentAlert.isBizLocationPicker ? View.GONE : View.VISIBLE); } @Override @@ -1731,7 +1739,7 @@ public void onResume() { } @Override - void onShow(ChatAttachAlert.AttachAlertLayout previousLayout) { + public void onShow(ChatAttachAlert.AttachAlertLayout previousLayout) { parentAlert.actionBar.setTitle(LocaleController.getString("ShareLocation", R.string.ShareLocation)); if (mapView.getView().getParent() == null) { mapViewClip.addView(mapView.getView(), 0, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, overScrollHeight + AndroidUtilities.dp(10), Gravity.TOP | Gravity.LEFT)); 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 c37940f5160..c3117fc84ab 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlertPhotoLayout.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlertPhotoLayout.java @@ -256,6 +256,9 @@ public int setPhotoChecked(int index, VideoEditedInfo videoEditedInfo) { if (checkSendMediaEnabled(photoEntry)) { return -1; } + if (selectedPhotos.size() + 1 > maxCount()) { + return -1; + } boolean add = true; int num; if ((num = addToSelectedPhotos(photoEntry, -1)) == -1) { @@ -1504,6 +1507,13 @@ private boolean checkSendMediaEnabled(MediaController.PhotoEntry photoEntry) { return false; } + private int maxCount() { + if (parentAlert.baseFragment instanceof ChatActivity && ((ChatActivity) parentAlert.baseFragment).getChatMode() == ChatActivity.MODE_QUICK_REPLIES) { + return parentAlert.baseFragment.getMessagesController().quickReplyMessagesLimit - ((ChatActivity) parentAlert.baseFragment).messages.size(); + } + return Integer.MAX_VALUE; + } + private int addToSelectedPhotos(MediaController.PhotoEntry object, int index) { Object key = object.imageId; if (selectedPhotos.containsKey(key)) { @@ -2998,17 +3008,17 @@ public void checkStorage() { } @Override - void scrollToTop() { + public void scrollToTop() { gridView.smoothScrollToPosition(0); } @Override - int needsActionBar() { + public int needsActionBar() { return 1; } @Override - void onMenuItemClick(int id) { + public void onMenuItemClick(int id) { if (id == group || id == compress) { if (parentAlert.maxSelectedPhotos > 0 && selectedPhotosOrder.size() > 1) { TLRPC.Chat chat = parentAlert.getChat(); @@ -3138,12 +3148,12 @@ void onMenuItemClick(int id) { } @Override - int getSelectedItemsCount() { + public int getSelectedItemsCount() { return selectedPhotosOrder.size(); } @Override - void onSelectedItemsCountChanged(int count) { + public void onSelectedItemsCountChanged(int count) { if (count <= 1 || parentAlert.editingMessageObject != null) { parentAlert.selectedMenuItem.hideSubItem(group); if (count == 0) { @@ -3186,7 +3196,7 @@ void onSelectedItemsCountChanged(int count) { } @Override - void applyCaption(CharSequence text) { + public void applyCaption(CharSequence text) { for (int a = 0; a < selectedPhotosOrder.size(); a++) { if (a == 0) { final Object key = selectedPhotosOrder.get(a); @@ -3231,13 +3241,13 @@ public boolean captionForAllMedia() { } @Override - void onDestroy() { + public void onDestroy() { NotificationCenter.getGlobalInstance().removeObserver(this, NotificationCenter.cameraInitied); NotificationCenter.getGlobalInstance().removeObserver(this, NotificationCenter.albumsDidLoad); } @Override - void onPause() { + public void onPause() { if (shutterButton == null) { return; } @@ -3260,21 +3270,21 @@ void onPause() { } @Override - void onResume() { + public void onResume() { if (parentAlert.isShowing() && !parentAlert.isDismissed() && !PhotoViewer.getInstance().isVisible()) { checkCamera(false); } } @Override - int getListTopPadding() { + public int getListTopPadding() { return gridView.getPaddingTop(); } public int currentItemTop = 0; @Override - int getCurrentItemTop() { + public int getCurrentItemTop() { if (gridView.getChildCount() <= 0) { gridView.setTopGlowOffset(currentItemTop = gridView.getPaddingTop()); progressView.setTranslationY(0); @@ -3293,12 +3303,12 @@ int getCurrentItemTop() { } @Override - int getFirstOffset() { + public int getFirstOffset() { return getListTopPadding() + AndroidUtilities.dp(56); } @Override - void checkColors() { + public void checkColors() { if (cameraIcon != null) { cameraIcon.invalidate(); } @@ -3319,7 +3329,7 @@ void checkColors() { } @Override - void onInit(boolean hasVideo, boolean hasPhoto, boolean hasDocuments) { + public void onInit(boolean hasVideo, boolean hasPhoto, boolean hasDocuments) { mediaEnabled = hasVideo || hasPhoto; videoEnabled = hasVideo; photoEnabled = hasPhoto; @@ -3382,7 +3392,7 @@ void onInit(boolean hasVideo, boolean hasPhoto, boolean hasDocuments) { } @Override - boolean canScheduleMessages() { + public boolean canScheduleMessages() { boolean hasTtl = false; for (HashMap.Entry entry : selectedPhotos.entrySet()) { Object object = entry.getValue(); @@ -3407,7 +3417,7 @@ boolean canScheduleMessages() { } @Override - void onButtonsTranslationYUpdated() { + public void onButtonsTranslationYUpdated() { checkCameraViewPosition(); invalidate(); } @@ -3445,7 +3455,7 @@ public void requestLayout() { private ViewPropertyAnimator headerAnimator; @Override - void onShow(ChatAttachAlert.AttachAlertLayout previousLayout) { + public void onShow(ChatAttachAlert.AttachAlertLayout previousLayout) { if (headerAnimator != null) { headerAnimator.cancel(); } @@ -3475,7 +3485,7 @@ void onShow(ChatAttachAlert.AttachAlertLayout previousLayout) { } @Override - void onShown() { + public void onShown() { isHidden = false; if (cameraView != null) { cameraView.setVisibility(VISIBLE); @@ -3504,7 +3514,7 @@ public void setCheckCameraWhenShown(boolean checkCameraWhenShown) { } @Override - void onHideShowProgress(float progress) { + public void onHideShowProgress(float progress) { if (cameraView != null) { cameraView.setAlpha(progress); cameraIcon.setAlpha(progress); @@ -3582,7 +3592,7 @@ private void onPhotoEditModeChanged(boolean isEditMode) { } @Override - void onHidden() { + public void onHidden() { if (cameraView != null) { cameraView.setVisibility(GONE); cameraIcon.setVisibility(GONE); @@ -3653,7 +3663,7 @@ public void onPreMeasure(int availableWidth, int availableHeight) { } @Override - boolean canDismissWithTouchOutside() { + public boolean canDismissWithTouchOutside() { return !cameraOpened; } @@ -3674,7 +3684,7 @@ public void onPanTransitionStart(boolean keyboardVisible, int contentHeight) { } @Override - void onContainerTranslationUpdated(float currentPanTranslationY) { + public void onContainerTranslationUpdated(float currentPanTranslationY) { this.currentPanTranslationY = currentPanTranslationY; checkCameraViewPosition(); if (cameraView != null) { @@ -3691,12 +3701,12 @@ void onContainerTranslationUpdated(float currentPanTranslationY) { } @Override - void onOpenAnimationEnd() { + public void onOpenAnimationEnd() { checkCamera(parentAlert != null && parentAlert.baseFragment instanceof ChatActivity); } @Override - void onDismissWithButtonClick(int item) { + public void onDismissWithButtonClick(int item) { hideCamera(item != 0 && item != 2); } @@ -3781,7 +3791,7 @@ public boolean onCustomMeasure(View view, int width, int height) { } @Override - protected boolean onCustomLayout(View view, int left, int top, int right, int bottom) { + public boolean onCustomLayout(View view, int left, int top, int right, int bottom) { int width = (right - left); int height = (bottom - top); boolean isPortrait = width < height; @@ -3952,6 +3962,10 @@ public void getOutline(View view, Outline outline) { if (checkSendMediaEnabled(photoEntry)) { return; } + if (selectedPhotos.size() + 1 > maxCount()) { + BulletinFactory.of(parentAlert.sizeNotifierFrameLayout, resourcesProvider).createErrorBulletin(AndroidUtilities.replaceTags(LocaleController.formatPluralString("BusinessRepliesToastLimit", parentAlert.baseFragment.getMessagesController().quickReplyMessagesLimit))).show(); + return; + } boolean added = !selectedPhotos.containsKey(photoEntry.imageId); if (added && parentAlert.maxSelectedPhotos >= 0 && selectedPhotos.size() >= parentAlert.maxSelectedPhotos) { if (parentAlert.allowOrder && parentAlert.baseFragment instanceof ChatActivity) { 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 056b83d5f33..ebb7d7de2be 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlertPhotoLayoutPreview.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlertPhotoLayoutPreview.java @@ -212,7 +212,7 @@ public void invalidateGroupsView() { private boolean shown = false; @Override - void onShow(ChatAttachAlert.AttachAlertLayout previousLayout) { + public void onShow(ChatAttachAlert.AttachAlertLayout previousLayout) { shown = true; if (previousLayout instanceof ChatAttachAlertPhotoLayout) { this.photoLayout = (ChatAttachAlertPhotoLayout) previousLayout; @@ -251,7 +251,7 @@ void onShow(ChatAttachAlert.AttachAlertLayout previousLayout) { } @Override - void onHide() { + public void onHide() { shown = false; if (headerAnimator != null) { headerAnimator.cancel(); @@ -270,12 +270,12 @@ void onHide() { } @Override - int getSelectedItemsCount() { + public int getSelectedItemsCount() { return groupsView.getPhotosCount(); } @Override - void onHidden() { + public void onHidden() { draggingCell = null; if (undoView != null) { undoView.hide(false, 0); @@ -290,17 +290,17 @@ void onHidden() { } @Override - int getFirstOffset() { + public int getFirstOffset() { return getListTopPadding() + AndroidUtilities.dp(56); } @Override - boolean shouldHideBottomButtons() { + public boolean shouldHideBottomButtons() { return true; } @Override - void applyCaption(CharSequence text) { + public void applyCaption(CharSequence text) { if (photoLayout != null) { photoLayout.applyCaption(text); } @@ -776,12 +776,12 @@ private float getTop(MessageObject.GroupedMessagePosition except, int minY) { } @Override - int getListTopPadding() { + public int getListTopPadding() { return listView.getPaddingTop()/* + AndroidUtilities.dp(9)*/; } @Override - int getCurrentItemTop() { + public int getCurrentItemTop() { if (listView.getChildCount() <= 0) { listView.setTopGlowOffset(listView.getPaddingTop()); return Integer.MAX_VALUE; @@ -826,18 +826,18 @@ public void onPreMeasure(int availableWidth, int availableHeight) { } @Override - void scrollToTop() { + public void scrollToTop() { // scrollView.smoothScrollTo(0, 0); listView.smoothScrollToPosition(0); } @Override - int needsActionBar() { + public int needsActionBar() { return 1; } @Override - boolean onBackPressed() { + public boolean onBackPressed() { parentAlert.updatePhotoPreview(false); return true; } @@ -852,7 +852,7 @@ public void requestLayout() { } @Override - void onMenuItemClick(int id) { + public void onMenuItemClick(int id) { try { parentAlert.getPhotoLayout().onMenuItemClick(id); } catch (Exception ignore) {} @@ -908,7 +908,7 @@ protected void onLayout(boolean changed, int left, int top, int right, int botto } @Override - void onSelectedItemsCountChanged(int count) { + public void onSelectedItemsCountChanged(int count) { if (count > 1) { parentAlert.selectedMenuItem.showSubItem(ChatAttachAlertPhotoLayout.group); } else { 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 0e8a709265f..2e7deeff590 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlertPollLayout.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlertPollLayout.java @@ -363,24 +363,24 @@ public void onScrollStateChanged(RecyclerView recyclerView, int newState) { } @Override - int needsActionBar() { + public int needsActionBar() { return 1; } @Override - void onResume() { + public void onResume() { if (listAdapter != null) { listAdapter.notifyDataSetChanged(); } } @Override - void onHideShowProgress(float progress) { + public void onHideShowProgress(float progress) { parentAlert.doneItem.setAlpha((parentAlert.doneItem.isEnabled() ? 1.0f : 0.5f) * progress); } @Override - void onMenuItemClick(int id) { + public void onMenuItemClick(int id) { if (id == done_button) { if (quizPoll && parentAlert.doneItem.getAlpha() != 1.0f) { int checksCount = 0; @@ -443,7 +443,7 @@ void onMenuItemClick(int id) { } @Override - int getCurrentItemTop() { + public int getCurrentItemTop() { if (listView.getChildCount() <= 1) { return Integer.MAX_VALUE; } @@ -461,7 +461,7 @@ int getCurrentItemTop() { } @Override - int getFirstOffset() { + public int getFirstOffset() { return getListTopPadding() + AndroidUtilities.dp(17); } @@ -472,12 +472,12 @@ public void setTranslationY(float translationY) { } @Override - int getListTopPadding() { + public int getListTopPadding() { return topPadding; } @Override - void onPreMeasure(int availableWidth, int availableHeight) { + public void onPreMeasure(int availableWidth, int availableHeight) { int padding; if (parentAlert.sizeNotifierFrameLayout.measureKeyboardHeight() > AndroidUtilities.dp(20)) { padding = AndroidUtilities.dp(52); @@ -504,7 +504,7 @@ void onPreMeasure(int availableWidth, int availableHeight) { } @Override - int getButtonsHideOffset() { + public int getButtonsHideOffset() { return AndroidUtilities.dp(70); } @@ -517,7 +517,7 @@ public void requestLayout() { } @Override - void scrollToTop() { + public void scrollToTop() { listView.smoothScrollToPosition(1); } @@ -638,7 +638,7 @@ private void updateRows() { } @Override - void onShow(ChatAttachAlert.AttachAlertLayout previousLayout) { + public void onShow(ChatAttachAlert.AttachAlertLayout previousLayout) { try { parentAlert.actionBar.getTitleTextView().setBuildFullLayout(true); } catch (Exception ignore) {} @@ -652,12 +652,12 @@ void onShow(ChatAttachAlert.AttachAlertLayout previousLayout) { } @Override - void onHidden() { + public void onHidden() { parentAlert.doneItem.setVisibility(INVISIBLE); } @Override - boolean onBackPressed() { + public boolean onBackPressed() { if (!checkDiscard()) { return true; } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachRestrictedLayout.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachRestrictedLayout.java index ea398a9ccef..b037a8914bf 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachRestrictedLayout.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachRestrictedLayout.java @@ -93,7 +93,7 @@ public void onScrolled(RecyclerView recyclerView, int dx, int dy) { @Override - int getCurrentItemTop() { + public int getCurrentItemTop() { if (listView.getChildCount() <= 0) { return Integer.MAX_VALUE; } @@ -119,17 +119,17 @@ public void setTranslationY(float translationY) { } @Override - int getFirstOffset() { + public int getFirstOffset() { return getListTopPadding() + AndroidUtilities.dp(4); } @Override - int getListTopPadding() { + public int getListTopPadding() { return listView.getPaddingTop(); } @Override - void onPreMeasure(int availableWidth, int availableHeight) { + public void onPreMeasure(int availableWidth, int availableHeight) { super.onPreMeasure(availableWidth, availableHeight); int newSize = Math.max(0, availableHeight - ActionBar.getCurrentActionBarHeight()); if (gridExtraSpace != newSize) { 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 8c41096a2c9..8b4f30c96f6 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAvatarContainer.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAvatarContainer.java @@ -205,7 +205,15 @@ protected void onDraw(Canvas canvas) { if (storiesForceState != null) { params.forceState = storiesForceState; } - StoriesUtilities.drawAvatarWithStory(parentFragment != null ? parentFragment.getDialogId() : 0, canvas, imageReceiver, params); + + long dialogId = 0; + if (parentFragment != null) { + dialogId = parentFragment.getDialogId(); + } else if (baseFragment instanceof TopicsFragment) { + dialogId = ((TopicsFragment) baseFragment).getDialogId(); + } + + StoriesUtilities.drawAvatarWithStory(dialogId, canvas, imageReceiver, params); } else { super.onDraw(canvas); } @@ -222,8 +230,10 @@ public boolean onTouchEvent(MotionEvent event) { } }; if (baseFragment instanceof ChatActivity || baseFragment instanceof TopicsFragment) { - sharedMediaPreloader = new SharedMediaLayout.SharedMediaPreloader(baseFragment); - if (parentFragment != null && (parentFragment.isThreadChat() || parentFragment.getChatMode() == 2)) { + if (parentFragment == null || parentFragment.getChatMode() != ChatActivity.MODE_QUICK_REPLIES) { + sharedMediaPreloader = new SharedMediaLayout.SharedMediaPreloader(baseFragment); + } + if (parentFragment != null && (parentFragment.isThreadChat() || parentFragment.getChatMode() == ChatActivity.MODE_PINNED || parentFragment.getChatMode() == ChatActivity.MODE_QUICK_REPLIES)) { avatarImageView.setVisibility(GONE); } } @@ -243,7 +253,7 @@ public boolean onTouchEvent(MotionEvent event) { titleTextView.setTextColor(getThemedColor(Theme.key_actionBarDefaultTitle)); titleTextView.setTextSize(18); titleTextView.setGravity(Gravity.LEFT); - titleTextView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); + titleTextView.setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)); titleTextView.setLeftDrawableTopPadding(-AndroidUtilities.dp(1.3f)); titleTextView.setCanHideRightDrawable(false); titleTextView.setRightDrawableOutside(true); @@ -1094,7 +1104,7 @@ public void setChatAvatar(TLRPC.Chat chat) { avatarDrawable.setInfo(currentAccount, chat); if (avatarImageView != null) { avatarImageView.setForUserOrChat(chat, avatarDrawable); - avatarImageView.setRoundRadius(chat != null && chat.forum ? AndroidUtilities.dp(16) : AndroidUtilities.dp(21)); + avatarImageView.setRoundRadius(ChatObject.isForum(chat) ? AndroidUtilities.dp(ChatObject.hasStories(chat) ? 11 : 16) : AndroidUtilities.dp(21)); } } @@ -1183,7 +1193,7 @@ public void checkAndUpdateAvatar() { if (avatarImageView != null) { avatarImageView.setForUserOrChat(chat, avatarDrawable); } - avatarImageView.setRoundRadius(chat.forum ? AndroidUtilities.dp(16) : AndroidUtilities.dp(21)); + avatarImageView.setRoundRadius(chat.forum ? AndroidUtilities.dp(ChatObject.hasStories(chat) ? 11 : 16) : AndroidUtilities.dp(21)); } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/CircularProgressDrawable.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/CircularProgressDrawable.java index 5d189da0150..d2fef9ef70f 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/CircularProgressDrawable.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/CircularProgressDrawable.java @@ -16,8 +16,8 @@ public class CircularProgressDrawable extends Drawable { - private float size = AndroidUtilities.dp(18); - private float thickness = AndroidUtilities.dp(2.25f); + public float size = AndroidUtilities.dp(18); + public float thickness = AndroidUtilities.dp(2.25f); public CircularProgressDrawable() { this(0xffffffff); @@ -109,4 +109,5 @@ public void setColorFilter(@Nullable ColorFilter colorFilter) {} public int getOpacity() { return PixelFormat.TRANSPARENT; } + } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/ClickableAnimatedTextView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/ClickableAnimatedTextView.java new file mode 100644 index 00000000000..b8b99270d2a --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ClickableAnimatedTextView.java @@ -0,0 +1,108 @@ +package org.telegram.ui.Components; + +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.drawable.Drawable; +import android.graphics.Rect; +import android.os.Build; +import android.util.Log; +import android.util.StateSet; +import android.view.Gravity; +import android.view.MotionEvent; + +import androidx.annotation.NonNull; + +public class ClickableAnimatedTextView extends AnimatedTextView { + + private final Rect bounds = new Rect(); + public ClickableAnimatedTextView(Context context) { + super(context); + } + + @Override + protected void onDraw(Canvas canvas) { + bounds.set(getDrawable().getBounds()); + int w = (int) Math.ceil(getDrawable().getCurrentWidth()); + if (getDrawable().getGravity() == Gravity.LEFT) { + bounds.right = bounds.left + w; + } else if (getDrawable().getGravity() == Gravity.RIGHT) { + bounds.left = bounds.right - w; + } else if (getDrawable().getGravity() == Gravity.CENTER) { + int cx = (bounds.left + bounds.right) / 2; + bounds.left = cx - w / 2; + bounds.right = cx + w / 2; + } + bounds.left -= getPaddingLeft(); + bounds.top -= getPaddingTop(); + bounds.right += getPaddingRight(); + bounds.bottom += getPaddingBottom(); + backgroundDrawable.setBounds(bounds); + backgroundDrawable.draw(canvas); + super.onDraw(canvas); + } + + public Rect getClickBounds() { + return bounds; + } + + private Drawable backgroundDrawable; + + @Override + public void setBackground(Drawable background) { + if (backgroundDrawable != null) { + backgroundDrawable.setCallback(null); + } + backgroundDrawable = background; + if (backgroundDrawable != null) { + backgroundDrawable.setCallback(this); + } + invalidate(); + } + + @Override + public void setBackgroundDrawable(Drawable background) { + if (backgroundDrawable != null) { + backgroundDrawable.setCallback(null); + } + backgroundDrawable = background; + if (backgroundDrawable != null) { + backgroundDrawable.setCallback(this); + } + invalidate(); + } + + @Override + protected boolean verifyDrawable(@NonNull Drawable who) { + return who == backgroundDrawable || super.verifyDrawable(who); + } + + private boolean pressed; + @Override + public boolean onTouchEvent(MotionEvent event) { + final boolean hit = getClickBounds().contains((int) event.getX(), (int) event.getY()); + if (event.getAction() == MotionEvent.ACTION_DOWN && hit) { + pressed = true; + if (backgroundDrawable != null) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + backgroundDrawable.setHotspot(event.getX(), event.getY()); + } + backgroundDrawable.setState(new int[]{android.R.attr.state_pressed, android.R.attr.state_enabled}); + } + invalidate(); + } else if (event.getAction() == MotionEvent.ACTION_UP) { + if (pressed && hit) { + callOnClick(); + } + pressed = false; + if (backgroundDrawable != null) { + backgroundDrawable.setState(StateSet.NOTHING); + } + } else if (event.getAction() == MotionEvent.ACTION_CANCEL) { + pressed = false; + if (backgroundDrawable != null) { + backgroundDrawable.setState(StateSet.NOTHING); + } + } + return hit; + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/CornerPath.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/CornerPath.java new file mode 100644 index 00000000000..b288fdaac40 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/CornerPath.java @@ -0,0 +1,178 @@ +package org.telegram.ui.Components; + +import android.graphics.Path; +import android.graphics.RectF; +import android.os.Build; + +import androidx.annotation.NonNull; +import androidx.annotation.RequiresApi; + +import java.util.ArrayList; +import java.util.List; + +/** + * Workaround when using [android.graphics.CornerPathEffect] with a path based on rectangles. + * [closeRects] must be called when all rects are added. + * + * In Android 14, [android.graphics.CornerPathEffect] does not smooth out the lines between intersecting rectangles. + * https://issuetracker.google.com/issues/318612129 + */ +public class CornerPath extends Path { + + private static ArrayList recycled; + private final ArrayList rects; + private boolean isPathCreated = false; + protected boolean useCornerPathImplementation = true; + private float rectsUnionDiffDelta = 0f; + + public CornerPath() { + rects = new ArrayList<>(1); + } + + public CornerPath(int initialRectsCapacity) { + rects = new ArrayList<>(initialRectsCapacity); + } + + @Override + public void addRect(@NonNull RectF rect, @NonNull Direction dir) { + if (Build.VERSION.SDK_INT < 34 || !useCornerPathImplementation) { + super.addRect(rect.left, rect.top, rect.right, rect.bottom, dir); + } else { + if (rects.size() > 0 && rects.get(rects.size() - 1).contains(rect)) { + return; + } + if (rects.size() > 0 + && (Math.abs(rect.top - rects.get(rects.size() - 1).top) <= rectsUnionDiffDelta) + && (Math.abs(rect.bottom - rects.get(rects.size() - 1).bottom) <= rectsUnionDiffDelta)) { + rects.get(rects.size() - 1).union(rect); + } else { + RectF rectF; + if (recycled != null && recycled.size() > 0) { + rectF = recycled.remove(0); + } else { + rectF = new RectF(); + } + rectF.set(rect); + rects.add(rectF); + } + isPathCreated = false; + } + } + + @Override + public void addRect(float left, float top, float right, float bottom, @NonNull Direction dir) { + if (Build.VERSION.SDK_INT < 34 || !useCornerPathImplementation) { + super.addRect(left, top, right, bottom, dir); + } else { + if (rects.size() > 0 && rects.get(rects.size() - 1).contains(left, top, right, bottom)) { + return; + } + if (rects.size() > 0 + && (Math.abs(top - rects.get(rects.size() - 1).top) <= rectsUnionDiffDelta) + && (Math.abs(bottom - rects.get(rects.size() - 1).bottom) <= rectsUnionDiffDelta)) { + rects.get(rects.size() - 1).union(left, top, right, bottom); + } else { + RectF rectF; + if (recycled != null && recycled.size() > 0) { + rectF = recycled.remove(0); + } else { + rectF = new RectF(); + } + rectF.set(left, top, right, bottom); + rects.add(rectF); + } + isPathCreated = false; + } + } + + @Override + public void reset() { + super.reset(); + if (Build.VERSION.SDK_INT >= 34 && useCornerPathImplementation) { + resetRects(); + } + } + + @Override + public void rewind() { + super.rewind(); + if (Build.VERSION.SDK_INT >= 34 && useCornerPathImplementation) { + resetRects(); + } + } + + private void resetRects() { + if (recycled == null) { + recycled = new ArrayList<>(rects.size()); + } + recycled.addAll(rects); + rects.clear(); + isPathCreated = false; + } + + public void closeRects() { + if (Build.VERSION.SDK_INT >= 34 && useCornerPathImplementation && !isPathCreated) { + createClosedPathsFromRects(rects); + isPathCreated = true; + } + } + + public void setUseCornerPathImplementation(boolean use) { + useCornerPathImplementation = use; + } + + public void setRectsUnionDiffDelta(float delta) { + rectsUnionDiffDelta = delta; + } + + @RequiresApi(34) + private void createClosedPathsFromRects(List rects) { + if (rects.isEmpty()) { + return; + } + if (rects.size() == 1) { + super.addRect(rects.get(0).left, rects.get(0).top, rects.get(0).right, rects.get(0).bottom, Path.Direction.CW); + return; + } + RectF prev = rects.get(0); + RectF current; + int lastContourIndex = rects.size() - 1; + super.moveTo(prev.left, prev.top); + boolean hasGap = false; + for (int i = 1; i < rects.size(); i++) { + current = rects.get(i); + if (current.width() == 0) { + continue; + } + if (prev.bottom < current.top || prev.left > current.right || prev.right < current.left) { + // end of the current contour + hasGap = true; + lastContourIndex = i; + break; + } + if (prev.left != current.left) { + super.lineTo(prev.left, current.top); + super.lineTo(current.left, current.top); + } + prev = current; + } + super.lineTo(prev.left, prev.bottom); + super.lineTo(prev.right, prev.bottom); + for (int i = lastContourIndex - 1; i >= 0; i--) { + current = rects.get(i); + if (current.width() == 0) { + continue; + } + if (prev.right != current.right) { + super.lineTo(prev.right, prev.top); + super.lineTo(current.right, prev.top); + } + prev = current; + } + super.lineTo(prev.right, prev.top); + super.close(); + if (hasGap) { + createClosedPathsFromRects(rects.subList(lastContourIndex, rects.size())); + } + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Crop/CropView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Crop/CropView.java index ee1e89d3c90..355e547b734 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Crop/CropView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Crop/CropView.java @@ -472,6 +472,8 @@ public void updateMatrix(boolean force) { } private void fillAreaView(RectF targetRect, boolean allowZoomOut) { + if (state == null) return; + final float[] currentScale = new float[]{1.0f}; float scale = Math.max(targetRect.width() / areaView.getCropWidth(), targetRect.height() / areaView.getCropHeight()); 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 c031800fcaf..3150d65ab5c 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/CrossfadeDrawable.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/CrossfadeDrawable.java @@ -1,5 +1,6 @@ package org.telegram.ui.Components; +import android.animation.ValueAnimator; import android.graphics.Canvas; import android.graphics.ColorFilter; import android.graphics.PixelFormat; @@ -9,6 +10,8 @@ import androidx.annotation.NonNull; +import org.telegram.messenger.AndroidUtilities; + public class CrossfadeDrawable extends Drawable { private final Drawable topDrawable; @@ -119,4 +122,19 @@ public void setProgress(float value) { progress = value; invalidateSelf(); } + + private ValueAnimator animator; + public void animateToProgress(float value) { + if (animator != null) { + animator.cancel(); + } + animator = ValueAnimator.ofFloat(getProgress(), value); + animator.addUpdateListener(a -> { + setProgress((float) a.getAnimatedValue()); + invalidateSelf(); + }); + animator.setDuration((long) (200 * Math.abs(getProgress() - value))); + animator.setInterpolator(CubicBezierInterpolator.DEFAULT); + animator.start(); + } } \ No newline at end of file diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/DialogCellTags.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/DialogCellTags.java new file mode 100644 index 00000000000..799a8c18db7 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/DialogCellTags.java @@ -0,0 +1,240 @@ +package org.telegram.ui.Components; + +import static org.telegram.messenger.AndroidUtilities.dp; + +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.LinearGradient; +import android.graphics.Matrix; +import android.graphics.Paint; +import android.graphics.PorterDuff; +import android.graphics.PorterDuffXfermode; +import android.graphics.Shader; +import android.text.Layout; +import android.text.StaticLayout; +import android.text.TextUtils; + +import org.telegram.messenger.AccountInstance; +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.Emoji; +import org.telegram.messenger.LocaleController; +import org.telegram.messenger.MessagesController; +import org.telegram.messenger.UserConfig; +import org.telegram.ui.ActionBar.Theme; +import org.telegram.ui.DialogsActivity; + +import java.util.ArrayList; +import java.util.Locale; + +public class DialogCellTags { + + private final ArrayList filters = new ArrayList<>(); + private final ArrayList tags = new ArrayList<>(); + private Tag moreTags = null; + + private static class Tag { + private final static float padDp = 4.66f; + private final static float heightDp = 14.66f; + + public int filterId; + public int colorId; + + StaticLayout layout; + int color; + int left; + int width; + private int textHeight; + + public static Tag asMore(int n) { + Tag tag = new Tag(); + tag.filterId = n; + + String text = "+" + n; + tag.layout = new StaticLayout(text, Theme.dialogs_tagTextPaint, AndroidUtilities.displaySize.x, Layout.Alignment.ALIGN_NORMAL, 0f, 1f, false); + tag.left = (int) (tag.layout.getLineCount() >= 1 ? tag.layout.getLineLeft(0) : 0); + tag.width = dp(2 * padDp) + (int) (tag.layout.getLineCount() >= 1 ? tag.layout.getLineWidth(0) : 0); + tag.textHeight = tag.layout.getHeight(); + + tag.color = Theme.getColor(Theme.key_avatar_nameInMessageBlue); + + return tag; + } + + public static Tag fromFilter(int currentAccount, MessagesController.DialogFilter filter) { + Tag tag = new Tag(); + tag.filterId = filter.id; + tag.colorId = filter.color; + + CharSequence text = (filter.name == null ? "" : filter.name).toUpperCase(); + text = Emoji.replaceEmoji(text, Theme.dialogs_tagTextPaint.getFontMetricsInt(), false); + tag.layout = new StaticLayout(text, Theme.dialogs_tagTextPaint, AndroidUtilities.displaySize.x, Layout.Alignment.ALIGN_NORMAL, 0f, 1f, false); + tag.left = (int) (tag.layout.getLineCount() >= 1 ? tag.layout.getLineLeft(0) : 0); + tag.width = dp(2 * padDp) + (int) (tag.layout.getLineCount() >= 1 ? tag.layout.getLineWidth(0) : 0); + tag.textHeight = tag.layout.getHeight(); + + tag.color = Theme.getColor(Theme.keys_avatar_nameInMessage[filter.color % Theme.keys_avatar_nameInMessage.length]); + + return tag; + } + + public void draw(Canvas canvas) { + Theme.dialogs_tagPaint.setColor(Theme.multAlpha(color, Theme.isCurrentThemeDark() ? .20f : .10f)); + Theme.dialogs_tagTextPaint.setColor(color); + + AndroidUtilities.rectTmp.set(0, 0, width, dp(heightDp)); + canvas.drawRoundRect(AndroidUtilities.rectTmp, dp(4), dp(4), Theme.dialogs_tagPaint); + canvas.save(); + canvas.translate(dp(padDp) - left, (dp(heightDp) - textHeight) / 2f); + layout.draw(canvas); + canvas.restore(); + } + } + + public boolean update(int currentAccount, int dialogsType, long dialogId) { + final AccountInstance account = AccountInstance.getInstance(currentAccount); + final MessagesController controller = MessagesController.getInstance(currentAccount); + + if (!(controller.folderTags && account.getUserConfig().isPremium())) { + final boolean wasEmpty = tags.isEmpty(); + tags.clear(); + return !wasEmpty; + } + + ArrayList allFilters = controller.dialogFilters; + MessagesController.DialogFilter currentFilter = null; + if (dialogsType == DialogsActivity.DIALOGS_TYPE_FOLDER1) { + currentFilter = controller.selectedDialogFilter[0]; + } else if (dialogsType == DialogsActivity.DIALOGS_TYPE_FOLDER2) { + currentFilter = controller.selectedDialogFilter[1]; + } + filters.clear(); + if ( + dialogsType == DialogsActivity.DIALOGS_TYPE_DEFAULT || + dialogsType == DialogsActivity.DIALOGS_TYPE_FOLDER1 || + dialogsType == DialogsActivity.DIALOGS_TYPE_FOLDER2 + ) { + for (int i = 0; i < allFilters.size(); ++i) { + MessagesController.DialogFilter filter = allFilters.get(i); + if (filter == null || filter == currentFilter || filter.color < 0) + continue; + if (filter.includesDialog(account, dialogId)) { + filters.add(filter); + } + } + } + + boolean changed = false; + + // remove existing tags + for (int i = 0; i < tags.size(); ++i) { + Tag tag = tags.get(i); + MessagesController.DialogFilter filter = null; + for (int j = 0; j < filters.size(); ++j) { + if (filters.get(j).id == tag.filterId) { + filter = filters.get(j); + break; + } + } + + if (filter == null) { + changed = true; + tags.remove(i); + i--; + } else if (filter.color != tag.colorId || filter.name != null && tag.layout != null && filter.name.length() != tag.layout.getText().length()) { + tags.set(i, Tag.fromFilter(currentAccount, filter)); + changed = true; + } + } + + // add new tags + for (int i = 0; i < filters.size(); ++i) { + MessagesController.DialogFilter filter = filters.get(i); + Tag tag = null; + for (int j = 0; j < tags.size(); ++j) { + if (tags.get(j).filterId == filter.id) { + tag = tags.get(j); + break; + } + } + + if (tag == null) { + changed = true; + tags.add(i, Tag.fromFilter(currentAccount, filter)); + } + } + + filters.clear(); + + return changed; + } + + public boolean isEmpty() { + return tags.isEmpty(); + } + + public void clear() { + + } + +// private final static Paint ellipsizePaint = new Paint(Paint.ANTI_ALIAS_FLAG); +// private final static LinearGradient ellipsizeGradient; +// private final static Matrix ellipsizeMatrix = new Matrix(); +// static { +// ellipsizePaint.setShader(ellipsizeGradient = new LinearGradient(0, 0, dp(12), 0, new int[]{0, 0xffffffff}, new float[]{0f, 1f}, Shader.TileMode.CLAMP)); +// ellipsizePaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT)); +// } + + public void draw(Canvas canvas, int width) { + canvas.clipRect(0, 0, width, dp(Tag.heightDp)); + AndroidUtilities.rectTmp.set(0, 0, width, dp(Tag.heightDp)); + canvas.saveLayerAlpha(AndroidUtilities.rectTmp, 0xFF, Canvas.ALL_SAVE_FLAG); +// canvas.save(); + if (LocaleController.isRTL) { + canvas.translate(width, 0); + } + int leftwidth = width - dp(25); + int i = 0; + for (; i < tags.size(); ++i) { + Tag tag = tags.get(i); + leftwidth -= tag.width + dp(4); + if (leftwidth < 0) break; + if (LocaleController.isRTL) { + canvas.translate(-tag.width, 0); + tag.draw(canvas); + canvas.translate(-dp(4), 0); + } else { + tag.draw(canvas); + canvas.translate(tag.width + dp(4), 0); + } + } + if (i < tags.size()) { + final int count = tags.size() - i; + if (moreTags == null || moreTags.filterId != count) { + moreTags = Tag.asMore(count); + } + if (LocaleController.isRTL) { + canvas.translate(-moreTags.width, 0); + moreTags.draw(canvas); + canvas.translate(-dp(4), 0); + } else { + moreTags.draw(canvas); + canvas.translate(moreTags.width + dp(4), 0); + } + } +// canvas.restore(); +// canvas.save(); +// ellipsizeMatrix.reset(); +// if (LocaleController.isRTL) { +// ellipsizeMatrix.postTranslate(0, 0); +// ellipsizeMatrix.postScale(-1, 1f); +// ellipsizeMatrix.postTranslate(dp(12), 0); +// } else { +// ellipsizeMatrix.postTranslate(width - dp(12), 0); +// } +// ellipsizeGradient.setLocalMatrix(ellipsizeMatrix); +// canvas.drawRect(0, 0, width, dp(Tag.heightDp), ellipsizePaint); +// canvas.restore(); + canvas.restore(); + } + +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/FiltersListBottomSheet.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/FiltersListBottomSheet.java index 62846ead388..6f08c5b9140 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/FiltersListBottomSheet.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/FiltersListBottomSheet.java @@ -24,8 +24,11 @@ import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; +import org.checkerframework.common.subtyping.qual.Bottom; +import org.telegram.messenger.AccountInstance; import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.DialogObject; +import org.telegram.messenger.Emoji; import org.telegram.messenger.LocaleController; import org.telegram.messenger.MessagesController; import org.telegram.messenger.NotificationCenter; @@ -54,12 +57,24 @@ public class FiltersListBottomSheet extends BottomSheet implements NotificationC private ArrayList dialogFilters; public interface FiltersListBottomSheetDelegate { - void didSelectFilter(MessagesController.DialogFilter filter); + void didSelectFilter(MessagesController.DialogFilter filter, boolean checked); } + private final ArrayList selectedDialogs; + private final DialogsActivity fragment; + public FiltersListBottomSheet(DialogsActivity baseFragment, ArrayList selectedDialogs) { super(baseFragment.getParentActivity(), false); - dialogFilters = getCanAddDialogFilters(baseFragment, selectedDialogs); + this.selectedDialogs = selectedDialogs; + this.fragment = baseFragment; +// dialogFilters = getCanAddDialogFilters(baseFragment, selectedDialogs); + dialogFilters = new ArrayList<>(baseFragment.getMessagesController().dialogFilters); + for (int i = 0; i < dialogFilters.size(); ++i) { + if (dialogFilters.get(i).isDefault()) { + dialogFilters.remove(i); + i--; + } + } Context context = baseFragment.getParentActivity(); containerView = new FrameLayout(context) { @@ -205,7 +220,7 @@ public void onScrolled(RecyclerView recyclerView, int dx, int dy) { } }); listView.setOnItemClickListener((view, position) -> { - delegate.didSelectFilter(adapter.getItem(position)); + delegate.didSelectFilter(adapter.getItem(position), view instanceof BottomSheet.BottomSheetCell ? ((BottomSheet.BottomSheetCell) view).isChecked() : false); dismiss(); }); containerView.addView(listView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.TOP | Gravity.LEFT, 0, 48, 0, 0)); @@ -218,10 +233,10 @@ public void onScrolled(RecyclerView recyclerView, int dx, int dy) { titleTextView.setLinkTextColor(Theme.getColor(Theme.key_dialogTextLink)); titleTextView.setHighlightColor(Theme.getColor(Theme.key_dialogLinkSelection)); titleTextView.setEllipsize(TextUtils.TruncateAt.END); - titleTextView.setPadding(AndroidUtilities.dp(18), 0, AndroidUtilities.dp(18), 0); + titleTextView.setPadding(AndroidUtilities.dp(24), 0, AndroidUtilities.dp(24), 0); titleTextView.setGravity(Gravity.CENTER_VERTICAL); - titleTextView.setText(LocaleController.getString("FilterChoose", R.string.FilterChoose)); - titleTextView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); + titleTextView.setText(LocaleController.getString(R.string.FilterChoose)); + titleTextView.setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)); containerView.addView(titleTextView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 50, Gravity.LEFT | Gravity.TOP, 0, 0, 40, 0)); NotificationCenter.getGlobalInstance().addObserver(this, NotificationCenter.emojiLoaded); @@ -301,12 +316,13 @@ public void dismiss() { @Override public void didReceivedNotification(int id, int account, Object... args) { if (id == NotificationCenter.emojiLoaded) { - if (listView != null) { - int count = listView.getChildCount(); - for (int a = 0; a < count; a++) { - listView.getChildAt(a).invalidate(); + AndroidUtilities.forEachViews(listView, view -> { + if (view instanceof BottomSheetCell) { + ((BottomSheetCell) view).getTextView().invalidate(); + } else { + view.invalidate(); } - } + }); } } @@ -417,7 +433,15 @@ public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { } else { icon = R.drawable.msg_folders; } - cell.setTextAndIcon(filter.name, icon); + cell.setTextAndIcon(Emoji.replaceEmoji(filter.name, cell.getTextView().getPaint().getFontMetricsInt(), false), 0, new FolderDrawable(getContext(), icon, filter.color), false); + boolean isChecked = true; + for (int i = 0; i < selectedDialogs.size(); ++i) { + long did = selectedDialogs.get(i); + if (!filter.includesDialog(AccountInstance.getInstance(currentAccount), did)) { + isChecked = false; + } + } + cell.setChecked(isChecked); } else { cell.getImageView().setColorFilter(null); Drawable drawable1 = context.getResources().getDrawable(R.drawable.poll_add_circle); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/FolderDrawable.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/FolderDrawable.java new file mode 100644 index 00000000000..3fbc1226977 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/FolderDrawable.java @@ -0,0 +1,110 @@ +package org.telegram.ui.Components; + +import static org.telegram.messenger.AndroidUtilities.dp; +import static org.telegram.messenger.AndroidUtilities.lerp; + +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.ColorFilter; +import android.graphics.CornerPathEffect; +import android.graphics.Paint; +import android.graphics.Path; +import android.graphics.drawable.Drawable; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import org.telegram.messenger.R; +import org.telegram.ui.ActionBar.Theme; + +public class FolderDrawable extends Drawable { + + private final Drawable drawable; + private final Path path; + private boolean pathInvalidated = true; + private final Paint strokePaint, fillPaint; + + public FolderDrawable(Context context, int iconResId, int color) { + drawable = context.getResources().getDrawable(iconResId); + + if (color >= 0) { + path = new Path(); + + strokePaint = new Paint(Paint.ANTI_ALIAS_FLAG); + strokePaint.setStyle(Paint.Style.STROKE); + strokePaint.setColor(Theme.getColor(Theme.key_dialogBackground)); + strokePaint.setPathEffect(new CornerPathEffect(dp(1))); + strokePaint.setStrokeCap(Paint.Cap.ROUND); + strokePaint.setStrokeJoin(Paint.Join.ROUND); + + fillPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + fillPaint.setStyle(Paint.Style.FILL); + fillPaint.setColor(Theme.getColor(Theme.keys_avatar_nameInMessage[color % Theme.keys_avatar_nameInMessage.length])); + fillPaint.setPathEffect(new CornerPathEffect(dp(1))); + } else { + path = null; + strokePaint = null; + fillPaint = null; + } + } + + @Override + public void draw(@NonNull Canvas canvas) { + drawable.setBounds(getBounds()); + drawable.draw(canvas); + if (path != null) { + if (pathInvalidated) { + path.rewind(); + path.moveTo(x(.4871f), y(.6025f)); + path.lineTo(x(.8974f), y(.6025f)); + path.lineTo(x(1f), y(.7564f)); + path.lineTo(x(.8974f), y(.9102f)); + path.lineTo(x(.4871f), y(.9102f)); + path.close(); + pathInvalidated = false; + + strokePaint.setStrokeWidth(dp(3)); + } + canvas.drawPath(path, strokePaint); + canvas.drawPath(path, fillPaint); + } + } + + int x(float x) { + return lerp(getBounds().left, getBounds().right, x); + } + int y(float x) { + return lerp(getBounds().top, getBounds().bottom, x); + } + + @Override + public void setBounds(int left, int top, int right, int bottom) { + super.setBounds(left, top, right, bottom); + pathInvalidated = true; + } + + @Override + public void setAlpha(int alpha) { + drawable.setAlpha(alpha); + } + + @Override + public void setColorFilter(@Nullable ColorFilter colorFilter) { + drawable.setColorFilter(colorFilter); + } + + @Override + public int getOpacity() { + return drawable.getOpacity(); + } + + @Override + public int getIntrinsicWidth() { + return drawable.getIntrinsicWidth(); + } + + @Override + public int getIntrinsicHeight() { + return drawable.getIntrinsicHeight(); + } +} 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 9e370ff7d5f..50695fc5cf3 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/FragmentContextView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/FragmentContextView.java @@ -1639,7 +1639,7 @@ private void checkLocationString() { textView.setEllipsize(TextUtils.TruncateAt.END); } if (start >= 0) { - TypefaceSpan span = new TypefaceSpan(AndroidUtilities.getTypeface("fonts/rmedium.ttf"), 0, getThemedColor(Theme.key_inappPlayerPerformer)); + TypefaceSpan span = new TypefaceSpan(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM), 0, getThemedColor(Theme.key_inappPlayerPerformer)); stringBuilder.setSpan(span, start, start + liveLocation.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE); } titleTextView.setText(stringBuilder, false); @@ -1832,7 +1832,7 @@ public void onAnimationEnd(Animator animation) { textView.setEllipsize(TextUtils.TruncateAt.END); } } - TypefaceSpan span = new TypefaceSpan(AndroidUtilities.getTypeface("fonts/rmedium.ttf"), 0, getThemedColor(Theme.key_inappPlayerPerformer)); + TypefaceSpan span = new TypefaceSpan(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM), 0, getThemedColor(Theme.key_inappPlayerPerformer)); stringBuilder.setSpan(span, 0, messageObject.getMusicAuthor().length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE); titleTextView.setText(stringBuilder, !create && wasVisible && isMusic); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/GroupCreateSpan.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/GroupCreateSpan.java index 277222605ad..fb915c9709f 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/GroupCreateSpan.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/GroupCreateSpan.java @@ -133,6 +133,16 @@ public GroupCreateSpan(Context context, Object object, ContactsController.Contac uid = Long.MIN_VALUE + 6; firstName = LocaleController.getString("FilterRead", R.string.FilterRead); break; + case "existing_chats": + avatarDrawable.setAvatarType(AvatarDrawable.AVATAR_TYPE_EXISTING_CHATS); + uid = Long.MIN_VALUE + 8; + firstName = LocaleController.getString(R.string.FilterExistingChats); + break; + case "new_chats": + avatarDrawable.setAvatarType(AvatarDrawable.AVATAR_TYPE_NEW_CHATS); + uid = Long.MIN_VALUE + 9; + firstName = LocaleController.getString(R.string.FilterNewChats); + break; case "archived": default: avatarDrawable.setAvatarType(AvatarDrawable.AVATAR_TYPE_FILTER_ARCHIVED); 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 86f720c5d57..4836c0d1821 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/InstantCameraView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/InstantCameraView.java @@ -152,8 +152,9 @@ public class InstantCameraView extends FrameLayout implements NotificationCenter private Bitmap lastBitmap; private int recordingGuid; + private volatile boolean cameraTextureAvailable; private int[] position = new int[2]; - private int[] cameraTexture = new int[1]; + private int[] cameraTexture = new int[2]; private int[] oldCameraTexture = new int[1]; private float cameraTextureAlpha = 1.0f; @@ -170,8 +171,7 @@ public class InstantCameraView extends FrameLayout implements NotificationCenter private boolean cancelled; private CameraGLThread cameraThread; - private volatile int previewWidth, previewHeight; - private Size previewSize; + private Size[] previewSize = new Size[2]; private Size pictureSize; private Size aspectRatio = SharedConfig.roundCamera16to9 ? new Size(16, 9) : new Size(4, 3); private TextureView textureView; @@ -179,12 +179,14 @@ public class InstantCameraView extends FrameLayout implements NotificationCenter private final boolean useCamera2 = Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && SharedConfig.useCamera2; private final boolean supportHotSwap = useCamera2 && DualCameraView.dualAvailableStatic(ApplicationLoader.applicationContext); private CameraSession cameraSession; - private Camera2Session camera2Session; + private boolean bothCameras; + private Camera2Session[] camera2Sessions = new Camera2Session[2]; + private Camera2Session camera2SessionCurrent; private boolean needDrawFlickerStub; private boolean isCameraSessionInitiated() { if (useCamera2) { - return camera2Session != null && camera2Session.isInitiated(); + return camera2SessionCurrent != null && camera2SessionCurrent.isInitiated(); } else { return cameraSession != null && cameraSession.isInitied(); } @@ -282,8 +284,8 @@ public void setAlpha(int a) { if (Build.VERSION.SDK_INT >= 21) { cameraContainer = new InstantViewCameraContainer(context) { @Override - public void setScaleX(float scaleX) { - super.setScaleX(scaleX); + public void setRotationY(float rotationY) { + super.setRotationY(rotationY); InstantCameraView.this.invalidate(); } @@ -308,10 +310,9 @@ public void getOutline(View view, Outline outline) { paint.setColor(0xff000000); paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR)); cameraContainer = new InstantViewCameraContainer(context) { - @Override - public void setScaleX(float scaleX) { - super.setScaleX(scaleX); + public void setRotationY(float rotationY) { + super.setRotationY(rotationY); InstantCameraView.this.invalidate(); } @@ -347,38 +348,48 @@ protected void dispatchDraw(Canvas canvas) { if (!cameraReady || !isCameraSessionInitiated() || cameraThread == null) { return; } - switchCamera(); + if (!bothCameras) { + switchCamera(); + } if (switchCameraDrawable != null) { switchCameraDrawable.start(); } flipAnimationInProgress = true; ValueAnimator valueAnimator = ValueAnimator.ofFloat(0, 1f); - valueAnimator.setDuration(300); - valueAnimator.setInterpolator(CubicBezierInterpolator.DEFAULT); + valueAnimator.setDuration(580); + valueAnimator.setInterpolator(CubicBezierInterpolator.EASE_OUT_QUINT); + final boolean[] didSwap = new boolean[1]; + Runnable doSwap = () -> { + if (bothCameras) { + switchCamera(); + } + }; + cameraContainer.setCameraDistance(cameraContainer.getMeasuredHeight() * 8f); + textureOverlayView.setCameraDistance(textureOverlayView.getMeasuredHeight() * 8f); valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override 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; + if (p > 0.5f && !didSwap[0]) { + didSwap[0] = true; + doSwap.run(); } - float scaleDown = 0.9f + 0.1f * p; - cameraContainer.setScaleX(p * scaleDown); - cameraContainer.setScaleY(scaleDown); - textureOverlayView.setScaleX(p * scaleDown); - textureOverlayView.setScaleY(scaleDown); + float rotation = p < 0.5f ? p : p - 1f; + rotation *= 180; + cameraContainer.setRotationY(rotation); + textureOverlayView.setRotationY(rotation); } }); 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); + if (!didSwap[0]) { + didSwap[0] = true; + doSwap.run(); + } + cameraContainer.setRotationY(0f); + textureOverlayView.setRotationY(0f); flipAnimationInProgress = false; invalidate(); } @@ -503,9 +514,11 @@ public void didReceivedNotification(int id, int account, Object... args) { public void destroy(boolean async) { if (useCamera2) { - if (camera2Session != null) { - camera2Session.destroy(async); - camera2Session = null; + for (int a = 0; a < camera2Sessions.length; ++a) { + if (camera2Sessions[a] != null) { + camera2Sessions[a].destroy(async); + camera2Sessions[a] = null; + } } } else { if (cameraSession != null) { @@ -688,11 +701,28 @@ public boolean delete() { } if (useCamera2) { - camera2Session = Camera2Session.create(true, isFrontface, AndroidUtilities.roundPlayingMessageSize, AndroidUtilities.roundPlayingMessageSize); - if (camera2Session == null) return; - camera2Session.setRecordingVideo(true); - previewWidth = camera2Session.getPreviewWidth(); - previewHeight = camera2Session.getPreviewHeight(); + bothCameras = DualCameraView.dualAvailableStatic(getContext()); + if (bothCameras) { + for (int a = 0; a < 2; ++a) { + if (camera2Sessions[a] == null) { + camera2Sessions[a] = Camera2Session.create(a == 0, MessagesController.getInstance(UserConfig.selectedAccount).roundVideoSize, MessagesController.getInstance(UserConfig.selectedAccount).roundVideoSize); + if (camera2Sessions[a] != null) { + camera2Sessions[a].setRecordingVideo(true); + previewSize[a] = new Size(camera2Sessions[a].getPreviewWidth(), camera2Sessions[a].getPreviewHeight()); + } + } + } + camera2SessionCurrent = camera2Sessions[isFrontface ? 0 : 1]; + if (camera2SessionCurrent != null && camera2Sessions[isFrontface ? 1 : 0] == null) { + bothCameras = false; + } + if (camera2SessionCurrent == null) return; + } else { + camera2SessionCurrent = camera2Sessions[isFrontface ? 0 : 1] = Camera2Session.create(isFrontface, MessagesController.getInstance(UserConfig.selectedAccount).roundVideoSize, MessagesController.getInstance(UserConfig.selectedAccount).roundVideoSize); + if (camera2SessionCurrent == null) return; + camera2SessionCurrent.setRecordingVideo(true); + previewSize[0] = new Size(camera2SessionCurrent.getPreviewWidth(), camera2SessionCurrent.getPreviewHeight()); + } } textureView = new TextureView(getContext()); textureView.setSurfaceTextureListener(new TextureView.SurfaceTextureListener() { @@ -728,8 +758,11 @@ public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) { cameraThread = null; } if (useCamera2) { - if (camera2Session != null) { - camera2Session.destroy(false); + for (int a = 0; a < camera2Sessions.length; ++a) { + if (camera2Sessions[a] != null) { + camera2Sessions[a].destroy(false); + camera2Sessions[a] = null; + } } } else { if (cameraSession != null) { @@ -1009,24 +1042,32 @@ public void hideCamera(boolean async) { } private void switchCamera() { - saveLastCameraBitmap(); - if (lastBitmap != null) { - needDrawFlickerStub = false; - textureOverlayView.setImageBitmap(lastBitmap); - textureOverlayView.setAlpha(1f); + if (!(useCamera2 && bothCameras)) { + saveLastCameraBitmap(); + if (lastBitmap != null) { + needDrawFlickerStub = false; + textureOverlayView.setImageBitmap(lastBitmap); + textureOverlayView.setAlpha(1f); + } } isFrontface = !isFrontface; if (useCamera2) { - if (camera2Session != null) { - camera2Session.destroy(false); - camera2Session = null; - } - camera2Session = Camera2Session.create(true, isFrontface, AndroidUtilities.roundPlayingMessageSize, AndroidUtilities.roundPlayingMessageSize); - if (camera2Session == null) return; - camera2Session.setRecordingVideo(true); - previewWidth = camera2Session.getPreviewWidth(); - previewHeight = camera2Session.getPreviewHeight(); - cameraThread.setCurrentSession(camera2Session); + if (bothCameras) { + camera2SessionCurrent = camera2Sessions[isFrontface ? 0 : 1]; + cameraThread.flipSurfaces(); + return; + } else { + if (camera2SessionCurrent != null) { + camera2SessionCurrent.destroy(false); + camera2SessionCurrent = null; + camera2Sessions[isFrontface ? 1 : 0] = null; + } + camera2SessionCurrent = camera2Sessions[isFrontface ? 0 : 1] = Camera2Session.create(isFrontface, MessagesController.getInstance(UserConfig.selectedAccount).roundVideoSize, MessagesController.getInstance(UserConfig.selectedAccount).roundVideoSize); + if (camera2SessionCurrent == null) return; + camera2SessionCurrent.setRecordingVideo(true); + previewSize[0] = new Size(camera2SessionCurrent.getPreviewWidth(), camera2SessionCurrent.getPreviewHeight()); + cameraThread.setCurrentSession(camera2SessionCurrent); + } } else { if (cameraSession != null) { cameraSession.destroy(); @@ -1071,16 +1112,16 @@ private boolean initCamera() { ArrayList previewSizes = selectedCamera.getPreviewSizes(); ArrayList pictureSizes = selectedCamera.getPictureSizes(); - previewSize = chooseOptimalSize(previewSizes); + previewSize[0] = chooseOptimalSize(previewSizes); pictureSize = chooseOptimalSize(pictureSizes); - if (previewSize.mWidth != pictureSize.mWidth) { + if (previewSize[0].mWidth != pictureSize.mWidth) { boolean found = false; for (int a = previewSizes.size() - 1; a >= 0; a--) { Size preview = previewSizes.get(a); for (int b = pictureSizes.size() - 1; b >= 0; b--) { Size picture = pictureSizes.get(b); if (preview.mWidth >= pictureSize.mWidth && preview.mHeight >= pictureSize.mHeight && preview.mWidth == picture.mWidth && preview.mHeight == picture.mHeight) { - previewSize = preview; + previewSize[0] = preview; pictureSize = picture; found = true; break; @@ -1097,7 +1138,7 @@ private boolean initCamera() { for (int b = pictureSizes.size() - 1; b >= 0; b--) { Size picture = pictureSizes.get(b); if (preview.mWidth >= 360 && preview.mHeight >= 360 && preview.mWidth == picture.mWidth && preview.mHeight == picture.mHeight) { - previewSize = preview; + previewSize[0] = preview; pictureSize = picture; found = true; break; @@ -1110,7 +1151,7 @@ private boolean initCamera() { } } if (BuildVars.LOGS_ENABLED) { - FileLog.d("InstantCamera preview w = " + previewSize.mWidth + " h = " + previewSize.mHeight); + FileLog.d("InstantCamera preview w = " + previewSize[0].mWidth + " h = " + previewSize[0].mHeight); } return true; } @@ -1192,30 +1233,38 @@ public static boolean allowBigSizeCameraDebug() { return false; } - private void createCamera(final SurfaceTexture surfaceTexture) { + private void createCamera(final int index, final SurfaceTexture surfaceTexture) { AndroidUtilities.runOnUIThread(() -> { if (cameraThread == null) { return; } if (BuildVars.LOGS_ENABLED) { - FileLog.d("InstantCamera create camera session"); + FileLog.d("InstantCamera create camera session " + index); } if (useCamera2) { - cameraThread.setCurrentSession(camera2Session); - camera2Session.open(surfaceTexture); + if (bothCameras) { + if (camera2Sessions[index] != null) { + camera2Sessions[index].open(surfaceTexture); + } + } else { + if (index == 1) return; + cameraThread.setCurrentSession(camera2SessionCurrent); + camera2SessionCurrent.open(surfaceTexture); + } } else { - surfaceTexture.setDefaultBufferSize(previewSize.getWidth(), previewSize.getHeight()); - cameraSession = new CameraSession(selectedCamera, previewSize, pictureSize, ImageFormat.JPEG, true); + if (index == 1) return; + surfaceTexture.setDefaultBufferSize(previewSize[0].getWidth(), previewSize[0].getHeight()); + cameraSession = new CameraSession(selectedCamera, previewSize[0], pictureSize, ImageFormat.JPEG, true); cameraThread.setCurrentSession(cameraSession); CameraController.getInstance().openRound(cameraSession, surfaceTexture, () -> { if (cameraSession != null) { boolean updateScale = false; try { Camera.Size size = cameraSession.getCurrentPreviewSize(); - if (size.width != previewSize.getWidth() || size.height != previewSize.getHeight()) { - previewSize = new Size(size.width, size.height); - FileLog.d("InstantCamera change preview size to w = " + previewSize.getWidth() + " h = " + previewSize.getHeight()); + if (size.width != previewSize[0].getWidth() || size.height != previewSize[0].getHeight()) { + previewSize[0] = new Size(size.width, size.height); + FileLog.d("InstantCamera change preview size to w = " + previewSize[0].getWidth() + " h = " + previewSize[0].getHeight()); } } catch (Exception e) { FileLog.e(e); @@ -1341,6 +1390,7 @@ public void resetCameraFile() { private VideoRecorder videoEncoder; private Bitmap firstFrameThumb; + private volatile int surfaceIndex; public class CameraGLThread extends DispatchQueue { @@ -1355,12 +1405,13 @@ public class CameraGLThread extends DispatchQueue { private Object currentSession; - private SurfaceTexture cameraSurface; + private SurfaceTexture[] cameraSurface = new SurfaceTexture[2]; private final int DO_RENDER_MESSAGE = 0; private final int DO_SHUTDOWN_MESSAGE = 1; private final int DO_REINIT_MESSAGE = 2; private final int DO_SETSESSION_MESSAGE = 3; + private final int DO_FLIP = 4; private int drawProgram; private int vertexMatrixHandle; @@ -1381,22 +1432,15 @@ public CameraGLThread(SurfaceTexture surface, int surfaceWidth, int surfaceHeigh this.surfaceWidth = surfaceWidth; this.surfaceHeight = surfaceHeight; - - updateScale(); } private void updateScale() { int width, height; - if (useCamera2) { - width = previewWidth; - height = previewHeight; + if (previewSize[surfaceIndex] != null) { + width = previewSize[surfaceIndex].getWidth(); + height = previewSize[surfaceIndex].getHeight(); } else { - if (previewSize != null) { - width = previewSize.getWidth(); - height = previewSize.getHeight(); - } else { - return; - } + return; } float scale = surfaceWidth / (float) Math.min(width, height); @@ -1503,6 +1547,8 @@ private boolean initGL() { return false; } + updateScale(); + float tX = 1.0f / scaleX / 2.0f; float tY = 1.0f / scaleY / 2.0f; float[] verticesData = { @@ -1559,18 +1605,25 @@ private boolean initGL() { return false; } - GLES20.glGenTextures(1, cameraTexture, 0); - GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, cameraTexture[0]); - GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR); - GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR); - GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE); - GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE); - android.opengl.Matrix.setIdentityM(mMVPMatrix, 0); - cameraSurface = new SurfaceTexture(cameraTexture[0]); - cameraSurface.setOnFrameAvailableListener(surfaceTexture -> requestRender()); - createCamera(cameraSurface); + GLES20.glGenTextures(2, cameraTexture, 0); + for (int a = 0; a < 2; ++a) { + GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, cameraTexture[a]); + GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR); + GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR); + GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE); + GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE); + + cameraSurface[a] = new SurfaceTexture(cameraTexture[a]); + final int i = a; + cameraSurface[a].setOnFrameAvailableListener(surfaceTexture -> { + cameraTextureAvailable = true; + requestRender(i == 0, i == 1); + }); + createCamera(a, cameraSurface[a]); + } + if (BuildVars.LOGS_ENABLED) { FileLog.e("InstantCamera gl initied"); } @@ -1583,14 +1636,16 @@ public void reinitForNewCamera() { if (handler != null) { sendMessage(handler.obtainMessage(DO_REINIT_MESSAGE), 0); } - updateScale(); } public void finish() { - if (cameraSurface != null) { - cameraSurface.release(); - cameraSurface = null; + for (int a = 0; a < 2; ++a) { + if (cameraSurface[a] != null) { + cameraSurface[a].release(); + cameraSurface[a] = null; + } } + cameraTextureAvailable = false; if (eglSurface != null && eglContext != null) { if (!eglContext.equals(egl10.eglGetCurrentContext()) || !eglSurface.equals(egl10.eglGetCurrentSurface(EGL10.EGL_DRAW))) { egl10.eglMakeCurrent(eglDisplay, eglSurface, eglSurface, eglContext); @@ -1629,7 +1684,15 @@ public void setCurrentSession(Camera2Session session) { } } - private void onDraw(Integer cameraId) { + public void flipSurfaces() { + Handler handler = getHandler(); + if (handler != null) { + sendMessage(handler.obtainMessage(DO_FLIP), 0); + requestRender(true, true); + } + } + + private void onDraw(Integer cameraId, boolean updateTexImage1, boolean updateTexImage2) { if (!initied) { return; } @@ -1642,7 +1705,12 @@ private void onDraw(Integer cameraId) { return; } } - cameraSurface.updateTexImage(); + if (updateTexImage1) { + cameraSurface[0].updateTexImage(); + } + if (updateTexImage2) { + cameraSurface[1].updateTexImage(); + } boolean captureFirstFrameThumb = false; if (!recording) { @@ -1674,15 +1742,15 @@ private void onDraw(Integer cameraId) { recording = true; } - if (videoEncoder != null) { - videoEncoder.frameAvailable(cameraSurface, cameraId, System.nanoTime()); + if (videoEncoder != null && (surfaceIndex == 0 && updateTexImage1 || surfaceIndex == 1 && updateTexImage2)) { + videoEncoder.frameAvailable(cameraSurface[surfaceIndex], bothCameras ? surfaceIndex : cameraId, System.nanoTime()); } - cameraSurface.getTransformMatrix(mSTMatrix); + cameraSurface[surfaceIndex].getTransformMatrix(mSTMatrix); GLES20.glUseProgram(drawProgram); GLES20.glActiveTexture(GLES20.GL_TEXTURE0); - GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, cameraTexture[0]); + GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, cameraTexture[surfaceIndex]); GLES20.glVertexAttribPointer(positionHandle, 3, GLES20.GL_FLOAT, false, 12, vertexBuffer); GLES20.glEnableVertexAttribArray(positionHandle); @@ -1728,7 +1796,7 @@ public void handleMessage(Message inputMessage) { switch (what) { case DO_RENDER_MESSAGE: - onDraw((Integer) inputMessage.obj); + onDraw(inputMessage.arg1, (inputMessage.arg2 & 1) != 0, (inputMessage.arg2 & 2) != 0); break; case DO_SHUTDOWN_MESSAGE: finish(); @@ -1748,15 +1816,15 @@ public void handleMessage(Message inputMessage) { return; } - if (cameraSurface != null) { - cameraSurface.getTransformMatrix(moldSTMatrix); - cameraSurface.setOnFrameAvailableListener(null); - cameraSurface.release(); + if (cameraSurface[0] != null) { + cameraSurface[0].getTransformMatrix(moldSTMatrix); + cameraSurface[0].setOnFrameAvailableListener(null); + cameraSurface[0].release(); oldCameraTexture[0] = cameraTexture[0]; cameraTextureAlpha = 0.0f; cameraTexture[0] = 0; oldTextureTextureBuffer = textureBuffer.duplicate(); - oldTexturePreviewSize = previewSize; + oldTexturePreviewSize = previewSize[0]; } cameraId++; cameraReady = false; @@ -1768,9 +1836,9 @@ public void handleMessage(Message inputMessage) { GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE); GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE); - cameraSurface = new SurfaceTexture(cameraTexture[0]); - cameraSurface.setOnFrameAvailableListener(surfaceTexture -> requestRender()); - createCamera(cameraSurface); + cameraSurface[0] = new SurfaceTexture(cameraTexture[0]); + cameraSurface[0].setOnFrameAvailableListener(surfaceTexture -> requestRender(true, false)); + createCamera(0, cameraSurface[0]); updateScale(); @@ -1790,7 +1858,7 @@ public void handleMessage(Message inputMessage) { } case DO_SETSESSION_MESSAGE: { if (BuildVars.LOGS_ENABLED) { - FileLog.d("InstantCamera set gl rednderer session"); + FileLog.d("InstantCamera set gl renderer session"); } Object newSession = inputMessage.obj; if (currentSession == newSession) { @@ -1809,7 +1877,25 @@ public void handleMessage(Message inputMessage) { } else { currentSession = newSession; } + break; + } + case DO_FLIP: { + surfaceIndex = 1 - surfaceIndex; + updateScale(); + + float tX = 1.0f / scaleX / 2.0f; + float tY = 1.0f / scaleY / 2.0f; + + float[] texData = { + 0.5f - tX, 0.5f - tY, + 0.5f + tX, 0.5f - tY, + 0.5f - tX, 0.5f + tY, + 0.5f + tX, 0.5f + tY + }; + + textureBuffer = ByteBuffer.allocateDirect(texData.length * 4).order(ByteOrder.nativeOrder()).asFloatBuffer(); + textureBuffer.put(texData).position(0); break; } } @@ -1822,10 +1908,10 @@ public void shutdown(int send, int ttl) { } } - public void requestRender() { + public void requestRender(boolean updateTexImage1, boolean updateTexImage2) { Handler handler = getHandler(); if (handler != null) { - sendMessage(handler.obtainMessage(DO_RENDER_MESSAGE, cameraId), 0); + sendMessage(handler.obtainMessage(DO_RENDER_MESSAGE, cameraId, (updateTexImage1 ? 1 : 0) + (updateTexImage2 ? 2 : 0)), 0); } } } @@ -1997,6 +2083,7 @@ private class VideoRecorder implements Runnable { private int textureHandle; private int resolutionHandle; private int previewSizeHandle; + private int texelSizeHandle; private int alphaHandle; private int zeroTimeStamps; private Integer lastCameraId = 0; @@ -2362,7 +2449,7 @@ private void handleAudioFrameAvailable(AudioBufferInfo input) { } private void handleVideoFrameAvailable(long timestampNanos, Integer cameraId) { - if (pauseRecorder) { + if (pauseRecorder || !cameraTextureAvailable) { return; } try { @@ -2443,7 +2530,7 @@ private void handleVideoFrameAvailable(long timestampNanos, Integer cameraId) { GLES20.glUniform2f(resolutionHandle, videoWidth, videoHeight); - if (oldCameraTexture[0] != 0 && oldTextureBuffer != null) { + if (oldCameraTexture[0] != 0 && oldTextureBuffer != null && !bothCameras) { if (!blendEnabled) { GLES20.glEnable(GLES20.GL_BLEND); blendEnabled = true; @@ -2460,12 +2547,13 @@ private void handleVideoFrameAvailable(long timestampNanos, Integer cameraId) { } if (previewSize != null) { - GLES20.glUniform2f(previewSizeHandle, previewSize.getWidth(), previewSize.getHeight()); + GLES20.glUniform2f(previewSizeHandle, previewSize[surfaceIndex].getWidth(), previewSize[surfaceIndex].getHeight()); + GLES20.glUniform2f(texelSizeHandle, (float) 1f / previewSize[surfaceIndex].getWidth(), (float) 1f / previewSize[surfaceIndex].getHeight()); } GLES20.glUniformMatrix4fv(textureMatrixHandle, 1, false, mSTMatrix, 0); GLES20.glUniform1f(alphaHandle, cameraTextureAlpha); - GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, cameraTexture[0]); + GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, cameraTexture[surfaceIndex]); GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4); GLES20.glDisableVertexAttribArray(positionHandle); @@ -2479,7 +2567,7 @@ private void handleVideoFrameAvailable(long timestampNanos, Integer cameraId) { createKeyframeThumb(); frameCount++; - if (oldCameraTexture[0] != 0 && cameraTextureAlpha < 1.0f) { + if (oldCameraTexture[0] != 0 && cameraTextureAlpha < 1.0f && !bothCameras) { cameraTextureAlpha += alphaDt / 200000000.0f; if (cameraTextureAlpha > 1) { GLES20.glDisable(GLES20.GL_BLEND); @@ -2960,6 +3048,7 @@ private void prepareEncoder(boolean fromPause) { audioLast = -1; audioDiff = -1; skippedFirst = false; + skippedTime = 0; audioRecorder = new AudioRecord(MediaRecorder.AudioSource.DEFAULT, audioSampleRate, AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT, bufferSize); audioRecorder.startRecording(); @@ -3112,12 +3201,16 @@ private void prepareEncoder(boolean fromPause) { } GLES20.glBlendFunc(GLES20.GL_SRC_ALPHA, GLES20.GL_ONE_MINUS_SRC_ALPHA); - int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, VERTEX_SHADER); - Size previewSize = InstantCameraView.this.previewSize; - if (previewSize == null && useCamera2) { - previewSize = new Size(previewWidth, previewHeight); + String vertexShaderSource, fragmentShaderSource; + if (useCamera2) { + vertexShaderSource = RLottieDrawable.readRes(null, R.raw.instant_lanczos_vert); + fragmentShaderSource = RLottieDrawable.readRes(null, R.raw.instant_lanczos_frag_oes); + } else { + vertexShaderSource = VERTEX_SHADER; + fragmentShaderSource = createFragmentShader(previewSize[0]); } - int fragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER, createFragmentShader(previewSize)); + int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, vertexShaderSource); + int fragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentShaderSource); if (vertexShader != 0 && fragmentShader != 0) { drawProgram = GLES20.glCreateProgram(); GLES20.glAttachShader(drawProgram, vertexShader); @@ -3136,6 +3229,7 @@ private void prepareEncoder(boolean fromPause) { alphaHandle = GLES20.glGetUniformLocation(drawProgram, "alpha"); vertexMatrixHandle = GLES20.glGetUniformLocation(drawProgram, "uMVPMatrix"); textureMatrixHandle = GLES20.glGetUniformLocation(drawProgram, "uSTMatrix"); + texelSizeHandle = GLES20.glGetUniformLocation(drawProgram, "texelSize"); } } } @@ -3376,9 +3470,6 @@ protected void finalize() throws Throwable { } private String createFragmentShader(Size previewSize) { - if (useCamera2) { - // TODO: lanczos - } if (SharedConfig.deviceIsLow() || !allowBigSizeCamera() || previewSize != null && Math.max(previewSize.getHeight(), previewSize.getWidth()) * 0.7f < MessagesController.getInstance(currentAccount).roundVideoSize) { return "#extension GL_OES_EGL_image_external : require\n" + "precision highp float;\n" + @@ -3543,9 +3634,9 @@ public void onAnimationEnd(Animator animation) { } pinchScale = (float) Math.hypot(ev.getX(index2) - ev.getX(index1), ev.getY(index2) - ev.getY(index1)) / pinchStartDistance; if (useCamera2) { - if (camera2Session != null) { - float zoom = Utilities.clamp(pinchScale, camera2Session.getMaxZoom(), camera2Session.getMinZoom()); - camera2Session.setZoom(zoom); + if (camera2SessionCurrent != null) { + float zoom = Utilities.clamp(pinchScale, camera2SessionCurrent.getMaxZoom(), camera2SessionCurrent.getMinZoom()); + camera2SessionCurrent.setZoom(zoom); } } else { float zoom = Math.min(1f, Math.max(0, pinchScale - 1f)); @@ -3567,8 +3658,8 @@ public void finishZoom() { float zoom; if (useCamera2) { - if (camera2Session == null) return; - zoom = Utilities.clamp(pinchScale, camera2Session.getMaxZoom(), camera2Session.getMinZoom()); + if (camera2SessionCurrent == null) return; + zoom = Utilities.clamp(pinchScale, camera2SessionCurrent.getMaxZoom(), camera2SessionCurrent.getMinZoom()); } else { zoom = Math.min(1f, Math.max(0, pinchScale - 1f)); } @@ -3577,8 +3668,8 @@ public void finishZoom() { finishZoomTransition = ValueAnimator.ofFloat(zoom, 0); finishZoomTransition.addUpdateListener(valueAnimator -> { if (useCamera2) { - if (camera2Session != null) { - camera2Session.setZoom((float) valueAnimator.getAnimatedValue()); + if (camera2SessionCurrent != null) { + camera2SessionCurrent.setZoom((float) valueAnimator.getAnimatedValue()); } } else { if (cameraSession != null) { 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 b9c148aace5..f9629debf5a 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/LinkPath.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/LinkPath.java @@ -14,10 +14,12 @@ import android.os.Build; import android.text.Layout; +import androidx.annotation.NonNull; + import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.LiteMode; -public class LinkPath extends Path { +public class LinkPath extends CornerPath { private Layout currentLayout; private int currentLine; @@ -45,11 +47,13 @@ public static CornerPathEffect getRoundedEffect() { public LinkPath() { super(); + useCornerPathImplementation = false; } public LinkPath(boolean roundRect) { super(); useRoundRect = roundRect; + useCornerPathImplementation = false; } public void setCurrentLayout(Layout layout, int start, float yOffset) { @@ -103,7 +107,7 @@ public void setInset(float insetVert, float insetHoriz) { private float minX = Float.MAX_VALUE, maxX, minY = Float.MAX_VALUE, maxY; @Override - public void addRect(float left, float top, float right, float bottom, Direction dir) { + public void addRect(float left, float top, float right, float bottom, @NonNull Direction dir) { if (currentLayout == null) { superAddRect(left, top, right, bottom, dir); return; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/LinkSpanDrawable.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/LinkSpanDrawable.java index 2b7c472d685..8028a10b9d8 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/LinkSpanDrawable.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/LinkSpanDrawable.java @@ -104,6 +104,7 @@ public LinkPath obtainNewPath() { } else { linkPath = new LinkPath(true); } + linkPath.setUseCornerPathImplementation(!isLite); linkPath.reset(); mPathes.add(linkPath); mPathesCount = mPathes.size(); @@ -206,6 +207,7 @@ public boolean draw(Canvas canvas) { 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) { + mPathes.get(i).closeRects(); canvas.drawPath(mPathes.get(i), mSelectionPaint); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/ListView/AdapterWithDiffUtils.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/ListView/AdapterWithDiffUtils.java index d049902b0d6..7aef60ab8ba 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ListView/AdapterWithDiffUtils.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ListView/AdapterWithDiffUtils.java @@ -1,5 +1,7 @@ package org.telegram.ui.Components.ListView; +import android.util.Log; + import androidx.recyclerview.widget.DiffUtil; import org.telegram.ui.Components.RecyclerListView; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/MediaActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/MediaActivity.java index b931b14680d..0bfe9a11cd1 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/MediaActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/MediaActivity.java @@ -97,9 +97,6 @@ public class MediaActivity extends BaseFragment implements SharedMediaLayout.Sha private int shiftDp = -12; private ActionBarMenuSubItem calendarItem, zoomInItem, zoomOutItem; - private ImageView floatingButton; - private FrameLayout floatingButtonContainer; - private StoriesTabsView tabsView; private FrameLayout buttonContainer; private ButtonWithCounterView button; @@ -162,9 +159,7 @@ public void didReceivedNotification(int id, int account, Object... args) { } } } else if (id == NotificationCenter.currentUserPremiumStatusChanged || id == NotificationCenter.storiesEnabledUpdate) { - if (!getMessagesController().storiesEnabled()) { - hideFloatingButton(true, true); - } + } } @@ -492,54 +487,6 @@ public int getBottomOffset(int tag) { return AndroidUtilities.dp(64); } }); - - floatingButtonContainer = new FrameLayout(context); - floatingButtonContainer.setVisibility(View.VISIBLE); - floatingButtonContainer.setOnClickListener(v -> { - StoryRecorder.getInstance(getParentActivity(), getCurrentAccount()) - .open(StoryRecorder.SourceView.fromFloatingButton(floatingButtonContainer)); - }); - - floatingButton = new RLottieImageView(context); - floatingButton.setScaleType(ImageView.ScaleType.FIT_CENTER); - floatingButton.setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_chats_actionIcon), PorterDuff.Mode.MULTIPLY)); - floatingButton.setImageResource(R.drawable.story_camera); - floatingButtonContainer.setContentDescription(LocaleController.getString("AccDescrCaptureStory", R.string.AccDescrCaptureStory)); -// if (Build.VERSION.SDK_INT >= 21) { -// StateListAnimator animator = new StateListAnimator(); -// animator.addState(new int[]{android.R.attr.state_pressed}, ObjectAnimator.ofFloat(floatingButtonContainer, View.TRANSLATION_Z, AndroidUtilities.dp(2), AndroidUtilities.dp(4)).setDuration(200)); -// animator.addState(new int[]{}, ObjectAnimator.ofFloat(floatingButtonContainer, View.TRANSLATION_Z, AndroidUtilities.dp(4), AndroidUtilities.dp(2)).setDuration(200)); -// floatingButtonContainer.setStateListAnimator(animator); -// floatingButtonContainer.setOutlineProvider(new ViewOutlineProvider() { -// @SuppressLint("NewApi") -// @Override -// public void getOutline(View view, Outline outline) { -// outline.setOval(0, 0, AndroidUtilities.dp(56), AndroidUtilities.dp(56)); -// } -// }); -// } - Drawable drawable = Theme.createSimpleSelectorCircleDrawable(AndroidUtilities.dp(56), Theme.getColor(Theme.key_chats_actionBackground), Theme.getColor(Theme.key_chats_actionPressedBackground)); - if (Build.VERSION.SDK_INT < 21) { - Drawable shadowDrawable = context.getResources().getDrawable(R.drawable.floating_shadow).mutate(); - shadowDrawable.setColorFilter(new PorterDuffColorFilter(0xff000000, PorterDuff.Mode.MULTIPLY)); - CombinedDrawable combinedDrawable = new CombinedDrawable(shadowDrawable, drawable, 0, 0); - combinedDrawable.setIconSize(AndroidUtilities.dp(56), AndroidUtilities.dp(56)); - drawable = combinedDrawable; - } - floatingButtonContainer.addView(floatingButton, LayoutHelper.createFrame(56, 56, Gravity.CENTER)); - if (floatingButtonContainer != null) { - drawable = Theme.createSimpleSelectorCircleDrawable(AndroidUtilities.dp(56), Theme.getColor(Theme.key_chats_actionBackground), Theme.getColor(Theme.key_chats_actionPressedBackground)); - if (Build.VERSION.SDK_INT < 21) { - Drawable shadowDrawable = ContextCompat.getDrawable(getParentActivity(), R.drawable.floating_shadow).mutate(); - shadowDrawable.setColorFilter(new PorterDuffColorFilter(0xff000000, PorterDuff.Mode.MULTIPLY)); - CombinedDrawable combinedDrawable = new CombinedDrawable(shadowDrawable, drawable, 0, 0); - combinedDrawable.setIconSize(AndroidUtilities.dp(56), AndroidUtilities.dp(56)); - drawable = combinedDrawable; - } - floatingButtonContainer.setBackground(drawable); - } - - hideFloatingButton(true, false); } if (type == TYPE_MEDIA && dialogId == getUserConfig().getClientUserId() && topicId == 0 && !getMessagesController().getSavedMessagesController().unsupported && getMessagesController().getSavedMessagesController().hasDialogs()) { @@ -780,9 +727,6 @@ protected void onTabScroll(boolean scrolling) { showSubtitle(1, false, false); } - if (floatingButtonContainer != null) { - fragmentView.addView(floatingButtonContainer, LayoutHelper.createFrame((Build.VERSION.SDK_INT >= 21 ? 56 : 60), (Build.VERSION.SDK_INT >= 21 ? 56 : 60), (LocaleController.isRTL ? Gravity.LEFT : Gravity.RIGHT) | Gravity.BOTTOM, LocaleController.isRTL ? 14 : 0, 0, LocaleController.isRTL ? 0 : 14, 14 + 64)); - } if (tabsView != null) { fragmentView.addView(tabsView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.BOTTOM | Gravity.FILL_HORIZONTAL)); } @@ -942,7 +886,6 @@ private void updateMediaCount() { } else { showSubtitle(1, false, true); } - hideFloatingButton(id != SharedMediaLayout.TAB_ARCHIVED_STORIES || sharedMediaLayout.getStoriesCount(SharedMediaLayout.TAB_ARCHIVED_STORIES) > 0, true); } if (optionsItem != null) { @@ -1023,62 +966,6 @@ public long getDialogId() { return dialogId; } - private float floatingButtonTranslation1; - private float floatingButtonTranslation2; - private void updateFloatingButtonOffset() { - if (floatingButtonContainer == null) { - return; - } - floatingButtonContainer.setTranslationY(floatingButtonTranslation + floatingButtonTranslation1 + floatingButtonTranslation2); - } - - private boolean floatingHidden; - private AnimatorSet floatingAnimator; - private float floatingButtonHideProgress, floatingButtonTranslation; - private void hideFloatingButton(boolean hide, boolean animated) { - if (floatingButtonContainer == null) { - return; - } - if (!getMessagesController().storiesEnabled()) { - hide = true; - } - if (floatingHidden == hide) { - return; - } - floatingHidden = hide; - if (floatingAnimator != null) { - floatingAnimator.cancel(); - } - if (animated) { - floatingButtonContainer.setVisibility(View.VISIBLE); - floatingAnimator = new AnimatorSet(); - ValueAnimator valueAnimator = ValueAnimator.ofFloat(floatingButtonHideProgress, floatingHidden ? 1f : 0f); - valueAnimator.addUpdateListener(animation -> { - floatingButtonHideProgress = (float) animation.getAnimatedValue(); - floatingButtonTranslation = dp(100) * floatingButtonHideProgress; - updateFloatingButtonOffset(); - }); - valueAnimator.addListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator animation) { - if (floatingHidden) { - floatingButtonContainer.setVisibility(View.GONE); - } - } - }); - floatingAnimator.playTogether(valueAnimator); - floatingAnimator.setDuration(300); - floatingAnimator.setInterpolator(new AccelerateDecelerateInterpolator()); - floatingButtonContainer.setClickable(!hide); - floatingAnimator.start(); - } else { - floatingButtonHideProgress = hide ? 1f : 0f; - floatingButtonTranslation = dp(100) * floatingButtonHideProgress; - updateFloatingButtonOffset(); - floatingButtonContainer.setVisibility(hide ? View.GONE : View.VISIBLE); - } - } - private final boolean[] subtitleShown = new boolean[2]; private final float[] subtitleT = new float[2]; private final boolean[] firstSubtitleCheck = new boolean[] { true, true }; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/MentionsContainerView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/MentionsContainerView.java index 459e72e80a8..07f84192ac2 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/MentionsContainerView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/MentionsContainerView.java @@ -43,6 +43,7 @@ import org.telegram.ui.ActionBar.Theme; import org.telegram.ui.Adapters.MentionsAdapter; import org.telegram.ui.Adapters.PaddedListAdapter; +import org.telegram.ui.Business.QuickRepliesActivity; import org.telegram.ui.Cells.ContextLinkCell; import org.telegram.ui.Cells.MentionCell; import org.telegram.ui.Cells.StickerCell; @@ -886,6 +887,8 @@ public void didReceivedNotification(int id, int account, Object... args) { AndroidUtilities.forEachViews(listView, view -> { if (view instanceof MentionCell) { ((MentionCell) view).invalidateEmojis(); + } else if (view instanceof QuickRepliesActivity.QuickReplyView) { + ((QuickRepliesActivity.QuickReplyView) view).invalidateEmojis(); } else { view.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 e199a6433a8..b12e5a70d7e 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/NumberPicker.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/NumberPicker.java @@ -734,10 +734,27 @@ protected void onDetachedFromWindow() { removeAllCallbacks(); } + private int thisGravity; + @Override + public void setGravity(int gravity) { + super.setGravity(thisGravity = gravity); + } + 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; + float x; + if (thisGravity == Gravity.RIGHT) { + mSelectorWheelPaint.setTextAlign(Align.RIGHT); + x = getWidth(); + } else if (thisGravity == Gravity.LEFT) { + mSelectorWheelPaint.setTextAlign(Align.LEFT); + x = 0; + } else { + mSelectorWheelPaint.setTextAlign(Align.CENTER); + x = getWidth() / 2f; + } + x += textOffset; float y = mCurrentScrollOffset; // draw the selector wheel diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Paint/Views/EditTextOutline.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Paint/Views/EditTextOutline.java index 0b5ca489017..c3d96d8a8a2 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Paint/Views/EditTextOutline.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Paint/Views/EditTextOutline.java @@ -18,6 +18,7 @@ import android.text.TextPaint; import org.telegram.messenger.AndroidUtilities; +import org.telegram.ui.Components.CornerPath; import org.telegram.ui.Components.EditTextBoldCursor; public class EditTextOutline extends EditTextBoldCursor { @@ -30,7 +31,7 @@ public class EditTextOutline extends EditTextBoldCursor { private int mStrokeColor; private float mStrokeWidth; private int mFrameColor; - private Path path = new Path(); + private CornerPath path = new CornerPath(); private RectF[] lines; public RectF framePadding; @@ -246,6 +247,7 @@ protected void onDraw(Canvas canvas) { } path.addRect(lines[i], Path.Direction.CW); } + path.closeRects(); setFrameRoundRadius(r); canvas.drawPath(path, paint); canvas.restore(); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/PopupAudioView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/PopupAudioView.java index 1adfff22e92..00f2134dd35 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/PopupAudioView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/PopupAudioView.java @@ -217,7 +217,7 @@ public boolean onTouchEvent(MotionEvent event) { private void didPressedButton() { if (buttonState == 0) { boolean result = MediaController.getInstance().playMessage(currentMessageObject); - if (!currentMessageObject.isOut() && currentMessageObject.isContentUnread()) { + if (!currentMessageObject.isOut() && (currentMessageObject.isContentUnread())) { if (currentMessageObject.messageOwner.peer_id.channel_id == 0) { MessagesController.getInstance(currentAccount).markMessageContentAsRead(currentMessageObject); currentMessageObject.setContentIsRead(); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/FeaturesPageView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/FeaturesPageView.java new file mode 100644 index 00000000000..a177c553efc --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/FeaturesPageView.java @@ -0,0 +1,408 @@ +package org.telegram.ui.Components.Premium; + +import static org.telegram.messenger.AndroidUtilities.dp; + +import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.LinearGradient; +import android.graphics.Paint; +import android.graphics.PorterDuff; +import android.graphics.PorterDuffColorFilter; +import android.graphics.Shader; +import android.util.SparseIntArray; +import android.util.TypedValue; +import android.view.Gravity; +import android.view.View; +import android.view.ViewGroup; +import android.widget.FrameLayout; +import android.widget.ImageView; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.core.content.ContextCompat; +import androidx.core.graphics.ColorUtils; +import androidx.recyclerview.widget.RecyclerView; + +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.BuildVars; +import org.telegram.messenger.LocaleController; +import org.telegram.messenger.MessagesController; +import org.telegram.messenger.R; +import org.telegram.messenger.UserConfig; +import org.telegram.tgnet.TLRPC; +import org.telegram.ui.ActionBar.Theme; +import org.telegram.ui.Cells.FixedHeightEmptyCell; +import org.telegram.ui.Components.AvatarDrawable; +import org.telegram.ui.Components.BackupImageView; +import org.telegram.ui.Components.GradientTools; +import org.telegram.ui.Components.LayoutHelper; +import org.telegram.ui.Components.Premium.GLIcon.GLIconRenderer; +import org.telegram.ui.Components.Premium.GLIcon.GLIconTextureView; +import org.telegram.ui.Components.Premium.GLIcon.Icon3D; +import org.telegram.ui.Components.RecyclerListView; +import org.telegram.ui.PremiumPreviewFragment; + +import java.util.ArrayList; +import java.util.Collections; + +public class FeaturesPageView extends BaseListPageView { + + public final static int FEATURES_STORIES = 0; + public final static int FEATURES_BUSINESS = 1; + + RecyclerListView.SelectionAdapter adapter; + private final static int VIEW_TYPE_HEADER = 0; + private final static int VIEW_TYPE_ITEM = 1; + private final static int VIEW_TYPE_EMPTY = 2; + + ArrayList items = new ArrayList<>(); + Bitmap bitmap; + + public final int type; + + public FeaturesPageView(Context context, int type, Theme.ResourcesProvider resourcesProvider) { + super(context, resourcesProvider); + this.type = type; + ArrayList itemsTmp = new ArrayList<>(); + + MessagesController messagesController = MessagesController.getInstance(UserConfig.selectedAccount); + SparseIntArray order = null; + if (type == FEATURES_STORIES) { + itemsTmp.add(new Item(VIEW_TYPE_ITEM, R.drawable.msg_stories_order, + LocaleController.getString("PremiumStoriesPriority", R.string.PremiumStoriesPriority), + LocaleController.getString("PremiumStoriesPriorityDescription", R.string.PremiumStoriesPriorityDescription), + PremiumPreviewFragment.PREMIUM_FEATURE_STORIES_PRIORITY_ORDER + )); + itemsTmp.add(new Item(VIEW_TYPE_ITEM, R.drawable.msg_stories_stealth, + LocaleController.getString("PremiumStoriesStealth", R.string.PremiumStoriesStealth), + LocaleController.getString("PremiumStoriesStealthDescription", R.string.PremiumStoriesStealthDescription), + PremiumPreviewFragment.PREMIUM_FEATURE_STORIES_STEALTH_MODE + )); + itemsTmp.add(new Item(VIEW_TYPE_ITEM, R.drawable.menu_quality_hd, + LocaleController.getString(R.string.PremiumStoriesQuality), + LocaleController.getString(R.string.PremiumStoriesQualityDescription), + PremiumPreviewFragment.PREMIUM_FEATURE_STORIES_QUALITY + )); + itemsTmp.add(new Item(VIEW_TYPE_ITEM, R.drawable.msg_stories_views, + LocaleController.getString("PremiumStoriesViews", R.string.PremiumStoriesViews), + LocaleController.getString("PremiumStoriesViewsDescription", R.string.PremiumStoriesViewsDescription), + PremiumPreviewFragment.PREMIUM_FEATURE_STORIES_VIEWS_HISTORY + )); + itemsTmp.add(new Item(VIEW_TYPE_ITEM, R.drawable.msg_stories_timer, + LocaleController.getString("PremiumStoriesExpiration", R.string.PremiumStoriesExpiration), + LocaleController.getString("PremiumStoriesExpirationDescription", R.string.PremiumStoriesExpirationDescription), + PremiumPreviewFragment.PREMIUM_FEATURE_STORIES_EXPIRATION_DURATION + )); + itemsTmp.add(new Item(VIEW_TYPE_ITEM, R.drawable.msg_stories_save, + LocaleController.getString("PremiumStoriesSaveToGallery", R.string.PremiumStoriesSaveToGallery), + LocaleController.getString("PremiumStoriesSaveToGalleryDescription", R.string.PremiumStoriesSaveToGalleryDescription), + PremiumPreviewFragment.PREMIUM_FEATURE_STORIES_SAVE_TO_GALLERY + )); + itemsTmp.add(new Item(VIEW_TYPE_ITEM, R.drawable.msg_stories_caption, + LocaleController.getString("PremiumStoriesCaption", R.string.PremiumStoriesCaption), + LocaleController.getString("PremiumStoriesCaptionDescription", R.string.PremiumStoriesCaptionDescription), + PremiumPreviewFragment.PREMIUM_FEATURE_STORIES_CAPTION + )); + itemsTmp.add(new Item(VIEW_TYPE_ITEM, R.drawable.msg_stories_link, + LocaleController.getString("PremiumStoriesFormatting", R.string.PremiumStoriesFormatting), + LocaleController.getString("PremiumStoriesFormattingDescription", R.string.PremiumStoriesFormattingDescription), + PremiumPreviewFragment.PREMIUM_FEATURE_STORIES_LINKS_AND_FORMATTING + )); + } else if (type == FEATURES_BUSINESS) { + order = messagesController.businessFeaturesTypesToPosition; + itemsTmp.add(new Item(VIEW_TYPE_ITEM, R.drawable.menu_premium_location, + LocaleController.getString(R.string.PremiumBusinessLocation), + LocaleController.getString(R.string.PremiumBusinessLocationDescription), + PremiumPreviewFragment.PREMIUM_FEATURE_BUSINESS_LOCATION + )); + itemsTmp.add(new Item(VIEW_TYPE_ITEM, R.drawable.menu_premium_clock, + LocaleController.getString(R.string.PremiumBusinessOpeningHours), + LocaleController.getString(R.string.PremiumBusinessOpeningHoursDescription), + PremiumPreviewFragment.PREMIUM_FEATURE_BUSINESS_OPENING_HOURS + )); + itemsTmp.add(new Item(VIEW_TYPE_ITEM, R.drawable.menu_quickreply, + LocaleController.getString(R.string.PremiumBusinessQuickReplies), + LocaleController.getString(R.string.PremiumBusinessQuickRepliesDescription), + PremiumPreviewFragment.PREMIUM_FEATURE_BUSINESS_QUICK_REPLIES + )); + itemsTmp.add(new Item(VIEW_TYPE_ITEM, R.drawable.menu_feature_status, + LocaleController.getString(R.string.PremiumBusinessGreetingMessages), + LocaleController.getString(R.string.PremiumBusinessGreetingMessagesDescription), + PremiumPreviewFragment.PREMIUM_FEATURE_BUSINESS_GREETING_MESSAGES + )); + itemsTmp.add(new Item(VIEW_TYPE_ITEM, R.drawable.menu_premium_away, + LocaleController.getString(R.string.PremiumBusinessAwayMessages), + LocaleController.getString(R.string.PremiumBusinessAwayMessagesDescription), + PremiumPreviewFragment.PREMIUM_FEATURE_BUSINESS_AWAY_MESSAGES + )); + itemsTmp.add(new Item(VIEW_TYPE_ITEM, R.drawable.menu_premium_chatbot, + LocaleController.getString(R.string.PremiumBusinessChatbots), + LocaleController.getString(R.string.PremiumBusinessChatbotsDescription), + PremiumPreviewFragment.PREMIUM_FEATURE_BUSINESS_CHATBOTS + )); + } + if (order != null) { + final SparseIntArray finalOrder = order; +// if (finalOrder.size() > 0) { +// for (int i = 0; i < itemsTmp.size(); i++) { +// if (finalOrder.get(itemsTmp.get(i).order, -1) == -1 && !BuildVars.DEBUG_PRIVATE_VERSION) { +// itemsTmp.remove(i); +// i--; +// } +// } +// } + Collections.sort(itemsTmp, (o1, o2) -> { + int type1 = finalOrder.get(o1.order, Integer.MAX_VALUE); + int type2 = finalOrder.get(o2.order, Integer.MAX_VALUE); + return type1 - type2; + }); + } + + items.add(new Item(VIEW_TYPE_HEADER)); + items.addAll(itemsTmp); + items.add(new Item(VIEW_TYPE_EMPTY)); + bitmap = Bitmap.createBitmap(items.size(), 1, Bitmap.Config.ARGB_8888); + Canvas canvas = new Canvas(bitmap); + Paint paint = new Paint(); + paint.setShader(new LinearGradient(0, 0, bitmap.getWidth(), 0, new int[] { + Theme.getColor(Theme.key_premiumGradient1), + Theme.getColor(Theme.key_premiumGradient2), + Theme.getColor(Theme.key_premiumGradient3), + Theme.getColor(Theme.key_premiumGradient4) + }, null, Shader.TileMode.CLAMP)); + canvas.drawRect(0, 0, bitmap.getWidth(), bitmap.getHeight(), paint); + } + + @Override + public RecyclerView.Adapter createAdapter() { + adapter = new RecyclerListView.SelectionAdapter() { + + @Override + public boolean isEnabled(RecyclerView.ViewHolder holder) { + return false; + } + + @NonNull + @Override + public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { + View view; + if (viewType == VIEW_TYPE_HEADER) { + view = new HeaderView(getContext()); + } else if (viewType == VIEW_TYPE_EMPTY) { + view = new FixedHeightEmptyCell(getContext(), 16); + } else { + view = new ItemCell(getContext()); + } + view.setLayoutParams(new RecyclerView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)); + return new RecyclerListView.Holder(view); + } + + @Override + public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) { + if (items.get(position).viewType == VIEW_TYPE_ITEM) { + ItemCell cell = (ItemCell) holder.itemView; + cell.imageView.setColorFilter(new PorterDuffColorFilter(bitmap.getPixel(position, 0), PorterDuff.Mode.MULTIPLY)); + cell.imageView.setImageDrawable(ContextCompat.getDrawable(getContext(), items.get(position).iconRes)); + cell.textView.setText(items.get(position).text); + cell.description.setText(items.get(position).description); + } + } + + @Override + public int getItemViewType(int position) { + return items.get(position).viewType; + } + + @Override + public int getItemCount() { + return items.size(); + } + }; + return adapter; + } + + private class Item { + final int viewType; + int iconRes; + String text; + String description; + int order; + + private Item(int viewType) { + this.viewType = viewType; + } + + public Item(int viewType, int iconRes, String text, String description, int order) { + this.viewType = viewType; + this.iconRes = iconRes; + this.text = text; + this.description = description; + this.order = order; + } + } + + private class HeaderView extends FrameLayout { + + BackupImageView imageView; + GradientTools gradientTools = new GradientTools(); + + StarParticlesView starParticlesView; + GLIconTextureView iconTextureView; + + int height; + + public HeaderView(Context context) { + super(context); + if (type == FEATURES_STORIES) { + height = dp(150); + + imageView = new BackupImageView(context); + imageView.setRoundRadius((int) (dp(65) / 2f)); + addView(imageView, LayoutHelper.createFrame(65, 65, Gravity.CENTER_HORIZONTAL, 0, 32, 0, 0)); + + TLRPC.User user = UserConfig.getInstance(UserConfig.selectedAccount).getCurrentUser(); + AvatarDrawable avatarDrawable = new AvatarDrawable(); + avatarDrawable.setInfo(user); + imageView.getImageReceiver().setForUserOrChat(user, avatarDrawable); + + TextView textView = new TextView(context); + textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 20); + textView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); + textView.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlackText, resourcesProvider)); + textView.setText(LocaleController.getString("UpgradedStories", R.string.UpgradedStories)); + addView(textView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_HORIZONTAL, 0, 111, 0, 0)); + + gradientTools.isLinear = true; + gradientTools.isDiagonal = true; + gradientTools.setColors( + Theme.getColor(Theme.key_premiumGradient2), + Theme.getColor(Theme.key_premiumGradient1) + ); + gradientTools.paint.setStyle(Paint.Style.STROKE); + gradientTools.paint.setStrokeCap(Paint.Cap.ROUND); + gradientTools.paint.setStrokeWidth(AndroidUtilities.dpf2(3.3f)); + } else if (type == FEATURES_BUSINESS) { + starParticlesView = new StarParticlesView(context) { + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + drawable.rect2.set(0, 0, getMeasuredWidth(), getMeasuredHeight() - AndroidUtilities.dp(52)); + } + + @Override + protected void configure() { + drawable.useGradient = true; + drawable.useBlur = false; + drawable.checkBounds = true; + drawable.isCircle = true; + drawable.centerOffsetY = dp(-14); + drawable.minLifeTime = 2000; + drawable.randLifeTime = 3000; + drawable.size1 = 16; + drawable.useRotate = false; + drawable.type = PremiumPreviewFragment.PREMIUM_FEATURE_BUSINESS; + drawable.colorKey = Theme.key_premiumGradient2; + drawable.init(); + } + }; + addView(starParticlesView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 190, Gravity.TOP | Gravity.FILL_HORIZONTAL)); + + iconTextureView = new GLIconTextureView(context, GLIconRenderer.DIALOG_STYLE, Icon3D.TYPE_COIN) { + @Override + protected void onAttachedToWindow() { + super.onAttachedToWindow(); + setPaused(false); + } + + @Override + protected void onDetachedFromWindow() { + super.onDetachedFromWindow(); + setPaused(true); + } + }; + iconTextureView.setStarParticlesView(starParticlesView); + Bitmap bitmap = Bitmap.createBitmap(50, 50, Bitmap.Config.ARGB_8888); + Canvas canvas = new Canvas(bitmap); + canvas.drawColor(ColorUtils.blendARGB(Theme.getColor(Theme.key_premiumGradient2, resourcesProvider), Theme.getColor(Theme.key_dialogBackground, resourcesProvider), 0.5f)); + iconTextureView.setBackgroundBitmap(bitmap); + iconTextureView.mRenderer.forceNight = true; + iconTextureView.mRenderer.colorKey1 = Theme.key_premiumGradient2; + iconTextureView.mRenderer.colorKey2 = Theme.key_premiumGradient1; + iconTextureView.mRenderer.updateColors(); + addView(iconTextureView, LayoutHelper.createFrame(160, 160, Gravity.CENTER_HORIZONTAL)); + + if (iconTextureView != null) { + iconTextureView.startEnterAnimation(-360, 100); + } + + TextView textView = new TextView(context); + textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 20); + textView.setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)); + textView.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlackText, resourcesProvider)); + textView.setText(LocaleController.getString(R.string.TelegramBusiness)); + textView.setGravity(Gravity.CENTER); + addView(textView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_HORIZONTAL, 0, 150, 0, 0)); + + textView = new TextView(context); + textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); + textView.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteGrayText2, resourcesProvider)); + textView.setText(LocaleController.getString(R.string.TelegramBusinessSubtitle2)); + textView.setGravity(Gravity.CENTER); + addView(textView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_HORIZONTAL, 0, 183, 0, 20)); + + } + } + + @Override + protected void dispatchDraw(Canvas canvas) { + if (type == FEATURES_STORIES) { + imageView.getHitRect(AndroidUtilities.rectTmp2); + AndroidUtilities.rectTmp.set(AndroidUtilities.rectTmp2); + AndroidUtilities.rectTmp.inset(-dp(5), -dp(5)); + gradientTools.setBounds(AndroidUtilities.rectTmp); + int storiesCount = 7; + float step = 360 / (float) storiesCount; + int gapLen = 5; + for (int i = 0; i < storiesCount; i++) { + float startAngle = step * i - 90; + float endAngle = startAngle + step; + startAngle += gapLen; + endAngle -= gapLen; + canvas.drawArc(AndroidUtilities.rectTmp, startAngle, (endAngle - startAngle), false, gradientTools.paint); + } + } + super.dispatchDraw(canvas); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, height <= 0 ? heightMeasureSpec : MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY)); + } + } + + private class ItemCell extends FrameLayout { + + TextView textView; + TextView description; + ImageView imageView; + + public ItemCell(Context context) { + super(context); + imageView = new ImageView(context); + imageView.setScaleType(ImageView.ScaleType.CENTER_INSIDE); + addView(imageView, LayoutHelper.createFrame(28, 28, 0, 25, 12, 16, 0)); + + textView = new TextView(context); + textView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); + textView.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlackText, resourcesProvider)); + textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); + addView(textView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, 0, 68, 8, 16, 0)); + + description = new TextView(context); + description.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteGrayText, resourcesProvider)); + description.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); + addView(description, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, 0, 68, 28, 16, 8)); + } + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/GLIcon/GLIconRenderer.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/GLIcon/GLIconRenderer.java index 3a6e7ecb24c..8f4da1e5842 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/GLIcon/GLIconRenderer.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/GLIcon/GLIconRenderer.java @@ -17,7 +17,7 @@ public class GLIconRenderer implements GLSurfaceView.Renderer { private int mWidth; private int mHeight; - public Star3DIcon star; + public Icon3D model; public float angleX = 0; public float angleX2 = 0; public float angleY = 0; @@ -38,6 +38,8 @@ public class GLIconRenderer implements GLSurfaceView.Renderer { public float gradientScaleX; public float gradientScaleY; + public boolean forceNight; + boolean night; int color1; int color2; @@ -45,13 +47,16 @@ public class GLIconRenderer implements GLSurfaceView.Renderer { public int colorKey2 = Theme.key_premiumStartGradient2; private final int style; + private final int type; public final static int FRAGMENT_STYLE = 0; public final static int DIALOG_STYLE = 1; + public final static int BUSINESS_STYLE = 2; public boolean isDarkBackground; - public GLIconRenderer(Context context, int style) { + public GLIconRenderer(Context context, int style, int type) { this.context = context; this.style = style; + this.type = type; updateColors(); } @@ -86,18 +91,22 @@ public static void checkGlError(String glOperation, int program) { public void onSurfaceCreated(GL10 glUnused, EGLConfig config) { GLES20.glClearColor(0f, 0f, 0f, 0f); - if (star != null) { - star.destroy(); + if (model != null) { + model.destroy(); } - star = new Star3DIcon(context); + model = new Icon3D(context, type); if (backgroundBitmap != null) { - star.setBackground(backgroundBitmap); + model.setBackground(backgroundBitmap); } if (isDarkBackground) { - star.spec1 = 1f; - star.spec2 = 0.2f; + model.spec1 = 1f; + model.spec2 = 0.2f; } + } + private float dt; + public void setDeltaTime(float dt) { + this.dt = dt; } public void onDrawFrame(GL10 glUnused) { @@ -115,12 +124,12 @@ public void onDrawFrame(GL10 glUnused) { Matrix.multiplyMM(mMVPMatrix, 0, mViewMatrix, 0, mRotationMatrix, 0); Matrix.multiplyMM(mMVPMatrix, 0, mProjectionMatrix, 0, mMVPMatrix, 0); - if (star != null) { - star.gradientColor1 = color1; - star.gradientColor2 = color2; - star.draw(mMVPMatrix, mRotationMatrix, mWidth, mHeight, gradientStartX, gradientScaleX, gradientStartY, gradientScaleY); + if (model != null) { + model.night = night; + model.gradientColor1 = color1; + model.gradientColor2 = color2; + model.draw(mMVPMatrix, mRotationMatrix, mWidth, mHeight, gradientStartX, gradientScaleX, gradientStartY, gradientScaleY, dt); } - } public void onSurfaceChanged(GL10 glUnused, int width, int height) { @@ -134,13 +143,14 @@ public void onSurfaceChanged(GL10 glUnused, int width, int height) { } public void setBackground(Bitmap gradientTextureBitmap) { - if (star != null) { - star.setBackground(gradientTextureBitmap); + if (model != null) { + model.setBackground(gradientTextureBitmap); } backgroundBitmap = gradientTextureBitmap; } public void updateColors() { + night = forceNight || ColorUtils.calculateLuminance(Theme.getColor(Theme.key_dialogBackground)) < 0.5f; color1 = Theme.getColor(colorKey1); color2 = Theme.getColor(colorKey2); isDarkBackground = style == DIALOG_STYLE && ColorUtils.calculateLuminance(Theme.getColor(Theme.key_dialogBackground)) < 0.5f; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/GLIcon/GLIconTextureView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/GLIcon/GLIconTextureView.java index f2d20f1a12a..fd77e60c80c 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/GLIcon/GLIconTextureView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/GLIcon/GLIconTextureView.java @@ -65,16 +65,24 @@ public class GLIconTextureView extends TextureView implements TextureView.Surfac private long idleDelay = 2000; - private final int animationsCount = 5; + private final int animationsCount; int animationPointer; ArrayList animationIndexes = new ArrayList<>(); boolean attached; StarParticlesView starParticlesView; + int type; public GLIconTextureView(Context context, int style) { + this(context, style, Icon3D.TYPE_STAR); + } + + public GLIconTextureView(Context context, int style, int type) { super(context); + + this.type = type; + animationsCount = type == Icon3D.TYPE_COIN ? 1 : 5; setOpaque(false); - setRenderer(new GLIconRenderer(context, style)); + setRenderer(new GLIconRenderer(context, style, type)); initialize(context); gestureDetector = new GestureDetector(context, new GestureDetector.OnGestureListener() { @@ -287,8 +295,10 @@ public void run() { } if (!shouldSleep()) { - lastFrameTime = System.currentTimeMillis(); - drawSingleFrame(); + final long now = System.currentTimeMillis(); + float dt = (now - lastFrameTime) / 1000f; + lastFrameTime = now; + drawSingleFrame(dt); } try { @@ -316,9 +326,10 @@ private synchronized void initializeRenderer(GLIconRenderer renderer) { } } - private synchronized void drawSingleFrame() { + private synchronized void drawSingleFrame(float dt) { checkCurrent(); if (mRenderer != null) { + mRenderer.setDeltaTime(dt); mRenderer.onDrawFrame(mGl); } checkGlError(); @@ -511,6 +522,11 @@ protected void onAttachedToWindow() { protected void onDetachedFromWindow() { super.onDetachedFromWindow(); cancelAnimatons(); + if (mRenderer != null) { + mRenderer.angleX = 0; + mRenderer.angleY = 0; + mRenderer.angleX2 = 0; + } attached = false; } @@ -563,7 +579,7 @@ private void startIdleAnimation() { if (i == 0) { pullAnimation(); } else if (i == 1) { - slowFlipAination(); + slowFlipAnimation(); } else if (i == 2) { sleepAnimation(); } else { @@ -571,7 +587,7 @@ private void startIdleAnimation() { } } - private void slowFlipAination() { + private void slowFlipAnimation() { animatorSet = new AnimatorSet(); ValueAnimator v1 = ValueAnimator.ofFloat(mRenderer.angleX, 360); v1.addUpdateListener(xUpdater); @@ -594,7 +610,7 @@ public void onAnimationEnd(Animator animation) { private void pullAnimation() { int i = Math.abs(Utilities.random.nextInt() % 4); animatorSet = new AnimatorSet(); - if (i == 0) { + if (i == 0 && type != Icon3D.TYPE_COIN) { int a = 48; ValueAnimator v1 = ValueAnimator.ofFloat(mRenderer.angleY, a); @@ -610,9 +626,13 @@ private void pullAnimation() { v2.setInterpolator(AndroidUtilities.overshootInterpolator); animatorSet.playTogether(v1, v2); } else { - int a = 485; + int dg = 485; + if (type == Icon3D.TYPE_COIN) { + dg = 360; + } + int a = dg; if (i == 2) { - a = -485; + a = -dg; } ValueAnimator v1 = ValueAnimator.ofFloat(mRenderer.angleY, a); v1.addUpdateListener(xUpdater); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/GLIcon/Star3DIcon.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/GLIcon/Icon3D.java similarity index 60% rename from TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/GLIcon/Star3DIcon.java rename to TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/GLIcon/Icon3D.java index 882dfe53fea..6fd3fafca20 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/GLIcon/Star3DIcon.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/GLIcon/Icon3D.java @@ -11,11 +11,13 @@ import android.graphics.Shader; import android.opengl.GLES20; import android.opengl.GLUtils; +import android.util.Log; import org.telegram.messenger.R; import org.telegram.messenger.SvgHelper; import org.telegram.messenger.Utilities; import org.telegram.ui.ActionBar.Theme; +import org.telegram.ui.Components.RLottieDrawable; import java.io.BufferedReader; import java.io.IOException; @@ -26,18 +28,19 @@ import java.nio.FloatBuffer; import java.nio.charset.StandardCharsets; -public class Star3DIcon { +public class Icon3D { private int mProgramObject; private int mMVPMatrixHandle; private int mWorldMatrixHandle; - private FloatBuffer mVertices; - private FloatBuffer mTextures; - private FloatBuffer mNormals; + private FloatBuffer[] mVertices; + private FloatBuffer[] mTextures; + private FloatBuffer[] mNormals; private int mTextureUniformHandle; private int mNormalMapUniformHandle; private int mBackgroundTextureUniformHandle; private int mBackgroundTextureHandle; + private int mVerticesHandle; private int mTextureCoordinateHandle; private int mNormalCoordinateHandle; private int xOffsetHandle; @@ -45,7 +48,7 @@ public class Star3DIcon { private int mTextureDataHandle; float xOffset; - int trianglesCount; + int[] trianglesCount; float enterAlpha = 0f; public float spec1 = 2f; @@ -56,6 +59,7 @@ public class Star3DIcon { public float normalSpec = 0.2f; public int normalSpecColor = Color.WHITE; public int specColor = Color.WHITE; + public boolean night; int specHandleTop; int specHandleBottom; @@ -67,26 +71,57 @@ public class Star3DIcon { int specColorHandle; int resolutionHandle; int gradientPositionHandle; + int modelIndexHandle; + int nightHandle; + int timeHandle; Bitmap texture; Bitmap backgroundBitmap; - public Star3DIcon(Context context) { - ObjLoader starObj = new ObjLoader(context, "models/star.binobj"); + public final int N; + public final int type; + + public static final int TYPE_STAR = 0; + public static final int TYPE_COIN = 1; + + private static final String[] starModel = new String[] { "models/star.binobj" }; + private static final String[] coinModel = new String[] { + "models/coin_outer.binobj", + "models/coin_inner.binobj", + "models/coin_logo.binobj" + }; + + public Icon3D(Context context, int type) { + this.type = type; + String[] modelPaths; + if (type == TYPE_COIN) { + modelPaths = coinModel; + } else { + modelPaths = starModel; + } + + N = modelPaths.length; + mVertices = new FloatBuffer[N]; + mTextures = new FloatBuffer[N]; + mNormals = new FloatBuffer[N]; + trianglesCount = new int[N]; + for (int i = 0; i < N; ++i) { + ObjLoader obj = new ObjLoader(context, modelPaths[i]); - mVertices = ByteBuffer.allocateDirect(starObj.positions.length * 4) - .order(ByteOrder.nativeOrder()).asFloatBuffer(); - mVertices.put(starObj.positions).position(0); + mVertices[i] = ByteBuffer.allocateDirect(obj.positions.length * 4) + .order(ByteOrder.nativeOrder()).asFloatBuffer(); + mVertices[i].put(obj.positions).position(0); - mTextures = ByteBuffer.allocateDirect(starObj.textureCoordinates.length * 4) - .order(ByteOrder.nativeOrder()).asFloatBuffer(); - mTextures.put(starObj.textureCoordinates).position(0); + mTextures[i] = ByteBuffer.allocateDirect(obj.textureCoordinates.length * 4) + .order(ByteOrder.nativeOrder()).asFloatBuffer(); + mTextures[i].put(obj.textureCoordinates).position(0); - mNormals = ByteBuffer.allocateDirect(starObj.normals.length * 4) - .order(ByteOrder.nativeOrder()).asFloatBuffer(); - mNormals.put(starObj.normals).position(0); + mNormals[i] = ByteBuffer.allocateDirect(obj.normals.length * 4) + .order(ByteOrder.nativeOrder()).asFloatBuffer(); + mNormals[i].put(obj.normals).position(0); - trianglesCount = starObj.positions.length; + trianglesCount[i] = obj.positions.length; + } generateTexture(); @@ -96,12 +131,12 @@ public Star3DIcon(Context context) { int[] linked = new int[1]; vertexShader = GLIconRenderer.loadShader(GLES20.GL_VERTEX_SHADER, loadFromAsset(context, "shaders/vertex2.glsl")); - fragmentShader = GLIconRenderer.loadShader(GLES20.GL_FRAGMENT_SHADER, loadFromAsset(context, "shaders/fragment2.glsl")); + fragmentShader = GLIconRenderer.loadShader(GLES20.GL_FRAGMENT_SHADER, loadFromAsset(context, type == TYPE_COIN ? "shaders/fragment3.glsl" : "shaders/fragment2.glsl")); programObject = GLES20.glCreateProgram(); GLES20.glAttachShader(programObject, vertexShader); GLES20.glAttachShader(programObject, fragmentShader); - GLES20.glBindAttribLocation(programObject, 0, "vPosition"); +// GLES20.glBindAttribLocation(programObject, 0, "vPosition"); GLES20.glLinkProgram(programObject); GLES20.glGetProgramiv(programObject, GLES20.GL_LINK_STATUS, linked, 0); @@ -109,9 +144,12 @@ public Star3DIcon(Context context) { init(context); } + private int[] buffers; + private void init(Context context) { GLES20.glUseProgram(mProgramObject); + mVerticesHandle = GLES20.glGetAttribLocation(mProgramObject, "vPosition"); mTextureCoordinateHandle = GLES20.glGetAttribLocation(mProgramObject, "a_TexCoordinate"); mNormalCoordinateHandle = GLES20.glGetAttribLocation(mProgramObject, "a_Normal"); @@ -133,32 +171,33 @@ private void init(Context context) { specColorHandle = GLES20.glGetUniformLocation(mProgramObject, "specColor"); resolutionHandle = GLES20.glGetUniformLocation(mProgramObject, "resolution"); gradientPositionHandle = GLES20.glGetUniformLocation(mProgramObject, "gradientPosition"); - - mTextures.position(0); - GLES20.glVertexAttribPointer(mTextureCoordinateHandle, 2, GLES20.GL_FLOAT, false, 0, mTextures); - GLES20.glEnableVertexAttribArray(mTextureCoordinateHandle); - - mNormals.position(0); - GLES20.glVertexAttribPointer(mNormalCoordinateHandle, 3, GLES20.GL_FLOAT, false, 0, mNormals); - GLES20.glEnableVertexAttribArray(mNormalCoordinateHandle); - - mVertices.position(0); - GLES20.glVertexAttribPointer(0, 3, GLES20.GL_FLOAT, false, 0, mVertices); - GLES20.glEnableVertexAttribArray(0); - - - Bitmap bitmap = SvgHelper.getBitmap(R.raw.start_texture, 80, 80, Color.WHITE); - Utilities.stackBlurBitmap(bitmap, 3); - - final int[] texture = new int[1]; - GLES20.glGenTextures(1, texture, 0); - GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, texture[0]); - - GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR); - GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR); - - GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0); - bitmap.recycle(); + modelIndexHandle = GLES20.glGetUniformLocation(mProgramObject, "modelIndex"); + nightHandle = GLES20.glGetUniformLocation(mProgramObject, "night"); + timeHandle = GLES20.glGetUniformLocation(mProgramObject, "time"); + + buffers = new int[3 * N]; + GLES20.glGenBuffers(3 * N, buffers, 0); + + for (int i = 0; i < N; ++i) { + GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, buffers[3 * i + 0]); + mTextures[i].position(0); + GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, 4 * mTextures[i].capacity(), mTextures[i], GLES20.GL_STATIC_DRAW); + GLES20.glEnableVertexAttribArray(mTextureCoordinateHandle); + mTextures[i].clear(); + + GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, buffers[3 * i + 1]); + mNormals[i].position(0); + GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, 4 * mNormals[i].capacity(), mNormals[i], GLES20.GL_STATIC_DRAW); + GLES20.glEnableVertexAttribArray(mNormalCoordinateHandle); + mNormals[i].clear(); + + GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, buffers[3 * i + 2]); + mVertices[i].position(0); + GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, 4 * mVertices[i].capacity(), mVertices[i], GLES20.GL_STATIC_DRAW); + GLES20.glEnableVertexAttribArray(mVerticesHandle); + mVertices[i].clear(); + } + GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0); final int[] textureDatHandle = new int[1]; GLES20.glGenTextures(1, textureDatHandle, 0); @@ -188,18 +227,52 @@ private void init(Context context) { GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR); GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mBackgroundTextureHandle); - GLES20.glActiveTexture(GLES20.GL_TEXTURE0); - GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, texture[0]); - GLES20.glUniform1i(mTextureUniformHandle, 0); + if (type == TYPE_STAR) { + Bitmap bitmap = SvgHelper.getBitmap(R.raw.start_texture, 80, 80, Color.WHITE); + Utilities.stackBlurBitmap(bitmap, 3); - GLES20.glActiveTexture(GLES20.GL_TEXTURE1); - GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, normalMap[0]); - GLES20.glUniform1i(mNormalMapUniformHandle, 1); + final int[] texture = new int[1]; + GLES20.glGenTextures(1, texture, 0); + GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, texture[0]); + + GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR); + GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR); + + GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0); + bitmap.recycle(); + + GLES20.glActiveTexture(GLES20.GL_TEXTURE0); + GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, texture[0]); + GLES20.glUniform1i(mTextureUniformHandle, 0); + + GLES20.glActiveTexture(GLES20.GL_TEXTURE1); + GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, normalMap[0]); + GLES20.glUniform1i(mNormalMapUniformHandle, 1); + } else if (type == TYPE_COIN) { + Bitmap bitmap = getBitmapFromAsset(context, "models/coin_border.png"); + + final int[] texture = new int[1]; + GLES20.glGenTextures(1, texture, 0); + GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, texture[0]); + + GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR); + GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR); + + GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0); + bitmap.recycle(); + + GLES20.glActiveTexture(GLES20.GL_TEXTURE0); + GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, texture[0]); + GLES20.glUniform1i(mTextureUniformHandle, 0); + + GLES20.glActiveTexture(GLES20.GL_TEXTURE1); + GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, normalMap[0]); + GLES20.glUniform1i(mNormalMapUniformHandle, 1); + } GLES20.glActiveTexture(GLES20.GL_TEXTURE2); GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, backgroundBitmapHandel[0]); GLES20.glUniform1i(mBackgroundTextureUniformHandle, 2); - } private void generateTexture() { @@ -220,7 +293,9 @@ private void generateTexture() { mTextureDataHandle = textureHandle[0]; } - public void draw(float[] mvpMatrix, float[] worldMatrix, int width, int height, float gradientStartX, float gradientScaleX, float gradientStartY, float gradientScaleY) { + private float time = 0f; + + public void draw(float[] mvpMatrix, float[] worldMatrix, int width, int height, float gradientStartX, float gradientScaleX, float gradientStartY, float gradientScaleY, float dt) { if (backgroundBitmap != null) { GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mBackgroundTextureHandle); GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, backgroundBitmap, 0); @@ -231,7 +306,6 @@ public void draw(float[] mvpMatrix, float[] worldMatrix, int width, int height, GLES20.glUniform1f(alphaHandle, enterAlpha); GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, mvpMatrix, 0); GLES20.glUniformMatrix4fv(mWorldMatrixHandle, 1, false, worldMatrix, 0); - GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, trianglesCount / 3); GLES20.glUniform1f(specHandleTop, spec1); GLES20.glUniform1f(specHandleBottom, spec2); @@ -244,6 +318,21 @@ public void draw(float[] mvpMatrix, float[] worldMatrix, int width, int height, GLES20.glUniform3f(specColorHandle, Color.red(specColor) / 255f, Color.green(specColor) / 255f, Color.blue(specColor) / 255f); GLES20.glUniform2f(resolutionHandle, width, height); GLES20.glUniform4f(gradientPositionHandle, gradientStartX, gradientScaleX, gradientStartY, gradientScaleY); + GLES20.glUniform1i(nightHandle, night ? 1 : 0); + + time += dt; + GLES20.glUniform1f(timeHandle, time); + + for (int i = 0; i < N; ++i) { + GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, buffers[3 * i + 0]); + GLES20.glVertexAttribPointer(mTextureCoordinateHandle, 2, GLES20.GL_FLOAT, false, 0, 0); + GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, buffers[3 * i + 1]); + GLES20.glVertexAttribPointer(mNormalCoordinateHandle, 3, GLES20.GL_FLOAT, false, 0, 0); + GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, buffers[3 * i + 2]); + GLES20.glVertexAttribPointer(mVerticesHandle, 3, GLES20.GL_FLOAT, false, 0, 0); + GLES20.glUniform1i(modelIndexHandle, i); + GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, trianglesCount[i] / 3); + } if (enterAlpha < 1f) { enterAlpha += 16 / 220f; @@ -266,10 +355,7 @@ public String loadFromAsset(Context context, String name) { BufferedReader br = new BufferedReader(new InputStreamReader(is, StandardCharsets.UTF_8)); String str; while ((str = br.readLine()) != null) { - if (str.startsWith("//")) { - continue; - } - sb.append(str); + sb.append(str).append("\n"); } br.close(); is.close(); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/GLIcon/ObjLoader.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/GLIcon/ObjLoader.java index 527b7fa9fd4..401d7d43acb 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/GLIcon/ObjLoader.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/GLIcon/ObjLoader.java @@ -53,8 +53,9 @@ public ObjLoader(Context context, String file) { positions[positionIndex++] = vertices.get(index); index = 2 * inputStream.readInt(); - textureCoordinates[normalIndex++] = textures.get(index++); - textureCoordinates[normalIndex++] = 1 - textures.get(index); + textureCoordinates[normalIndex++] = index < 0 || index >= textures.size() ? 0 : textures.get(index); + index++; + textureCoordinates[normalIndex++] = index < 0 || index >= textures.size() ? 0 : 1 - textures.get(index); index = 3 * inputStream.readInt(); this.normals[textureIndex++] = normals.get(index++); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/LimitPreviewView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/LimitPreviewView.java index 61ff832a5bd..b82d83583b2 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/LimitPreviewView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/LimitPreviewView.java @@ -403,16 +403,14 @@ protected void onLayout(boolean changed, int l, int t, int r, int b) { arrowAnimator.addUpdateListener(animation -> { float v = (float) animation.getAnimatedValue(); float moveValue = Math.min(1f, v); - if (animatingRotate) { - if (v > 1f) { - if (!wasHaptic) { - wasHaptic = true; - limitIcon.performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP); - } - limitIcon.setRotation(limitIconRotation + (v - 1f) * 60); - } else { - limitIcon.setRotation(limitIconRotation); + if (v > 1f && animatingRotate) { + if (!wasHaptic) { + wasHaptic = true; + limitIcon.performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP); } + limitIcon.setRotation(limitIconRotation + (v - 1f) * 60); + } else if (!animatingRotation) { + limitIcon.setRotation(limitIconRotation); } if (animation == arrowAnimator) { limitIcon.setTranslationX(fromX * (1f - moveValue) + finalToX * moveValue); @@ -524,7 +522,9 @@ public void startDelayedAnimation() { public void setPremiumLocked() { limitsContainer.setVisibility(View.GONE); - limitIcon.setPadding(dp(24), dp(3), dp(24), dp(3)); + if (limitIcon != null) { + limitIcon.setPadding(dp(24), dp(3), dp(24), dp(3)); + } premiumLocked = true; } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/LimitReachedBottomSheet.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/LimitReachedBottomSheet.java index 2ef598a8963..81e5b07b06d 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/LimitReachedBottomSheet.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/LimitReachedBottomSheet.java @@ -309,7 +309,7 @@ public LimitReachedBottomSheet(BaseFragment fragment, Context context, int type, loadInactiveChannels(); } updatePremiumButtonText(); - if (type == TYPE_BOOSTS_FOR_USERS || type == TYPE_BOOSTS_FOR_REMOVE_RESTRICTIONS || type == TYPE_BOOSTS_FOR_POSTING) { + if (type == TYPE_BOOSTS_FOR_REMOVE_RESTRICTIONS || isBoostingForAdminPossible()) { fireworksOverlay = new FireworksOverlay(getContext()); container.addView(fireworksOverlay, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); } @@ -742,7 +742,7 @@ public Animator onDisappear(ViewGroup sceneRoot, View view, TransitionValues sta headerView.recreateTitleAndDescription(); headerView.title.setText(getBoostsTitleString()); - headerView.description.setText(AndroidUtilities.replaceTags(getBoostsDescriptionString(false))); + headerView.description.setText(AndroidUtilities.replaceTags(getBoostDescriptionStringAfterBoost())); updateButton(); fireworksOverlay.start(); fireworksOverlay.performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP); @@ -1384,7 +1384,20 @@ public int getItemCount() { } private boolean isMiniBoostBtnForAdminAvailable() { - return (type == TYPE_BOOSTS_FOR_USERS || type == TYPE_BOOSTS_FOR_POSTING) && ChatObject.hasAdminRights(getChat()); + return isBoostingForAdminPossible() && ChatObject.hasAdminRights(getChat()); + } + + private boolean isBoostingForAdminPossible() { + return type == TYPE_BOOSTS_FOR_USERS + || type == TYPE_BOOSTS_FOR_POSTING + || type == TYPE_BOOSTS_FOR_COLOR + || type == TYPE_BOOSTS_FOR_PROFILE_COLOR + || type == TYPE_BOOSTS_FOR_EMOJI_STATUS + || type == TYPE_BOOSTS_FOR_CUSTOM_EMOJI_PACK + || type == TYPE_BOOSTS_FOR_WALLPAPER + || type == TYPE_BOOSTS_FOR_REPLY_ICON + || type == TYPE_BOOSTS_FOR_PROFILE_ICON + || type == TYPE_BOOSTS_FOR_CUSTOM_WALLPAPER; } private String getBoostLink() { @@ -1909,6 +1922,57 @@ private int getNeededBoostsForUnlockGroup() { return Math.max(chatFull.boosts_unrestrict - chatFull.boosts_applied, 0); } + private String getBoostDescriptionStringAfterBoost() { + String descriptionStr = null; + MessagesController messagesController = MessagesController.getInstance(currentAccount); + boolean isGroup = isGroup(); + if (type == TYPE_BOOSTS_FOR_COLOR) { + descriptionStr = LocaleController.formatString( + isGroup ? R.string.GroupNeedBoostsForColorDescription : R.string.ChannelNeedBoostsForColorDescription, + channelColorLevelMin() + ); + } else if (type == TYPE_BOOSTS_FOR_PROFILE_COLOR) { + descriptionStr = LocaleController.formatString( + isGroup ? R.string.GroupNeedBoostsForProfileColorDescription : R.string.ChannelNeedBoostsForProfileColorDescription, + channelColorLevelMin() + ); + } else if (type == TYPE_BOOSTS_FOR_CUSTOM_EMOJI_PACK) { + descriptionStr = LocaleController.formatString( + R.string.GroupNeedBoostsForCustomEmojiPackDescription, + messagesController.groupEmojiStickersLevelMin + ); + } else if (type == TYPE_BOOSTS_FOR_EMOJI_STATUS) { + descriptionStr = LocaleController.formatString( + isGroup ? R.string.GroupNeedBoostsForEmojiStatusDescription : R.string.ChannelNeedBoostsForEmojiStatusDescription, + isGroup ? messagesController.groupEmojiStatusLevelMin : messagesController.channelEmojiStatusLevelMin + ); + } else if (type == TYPE_BOOSTS_FOR_REPLY_ICON) { + descriptionStr = LocaleController.formatString( + isGroup ? R.string.GroupNeedBoostsForReplyIconDescription : R.string.ChannelNeedBoostsForReplyIconDescription, + messagesController.channelBgIconLevelMin + ); + } else if (type == TYPE_BOOSTS_FOR_PROFILE_ICON) { + descriptionStr = LocaleController.formatString( + isGroup ? R.string.GroupNeedBoostsForProfileIconDescription : R.string.ChannelNeedBoostsForProfileIconDescription, + isGroup ? messagesController.groupProfileBgIconLevelMin : messagesController.channelProfileIconLevelMin + ); + } else if (type == TYPE_BOOSTS_FOR_WALLPAPER) { + descriptionStr = LocaleController.formatString( + isGroup ? R.string.GroupNeedBoostsForWallpaperDescription : R.string.ChannelNeedBoostsForWallpaperDescription, + isGroup ? messagesController.groupWallpaperLevelMin : messagesController.channelWallpaperLevelMin + ); + } else if (type == TYPE_BOOSTS_FOR_CUSTOM_WALLPAPER) { + descriptionStr = LocaleController.formatString( + isGroup ? R.string.GroupNeedBoostsForCustomWallpaperDescription : R.string.ChannelNeedBoostsForCustomWallpaperDescription, + isGroup ? messagesController.groupCustomWallpaperLevelMin : messagesController.channelCustomWallpaperLevelMin + ); + } + if (descriptionStr != null) { + return descriptionStr; + } + return getBoostsDescriptionString(false); + } + private String getBoostsDescriptionString(boolean init) { if (type == TYPE_BOOSTS_FOR_REMOVE_RESTRICTIONS) { return getDescriptionForRemoveRestrictions(); @@ -2320,6 +2384,9 @@ private void setupBoostFeatures() { if (boostsStatus != null) { startLevel = boostsStatus.level + 1; } + if (type == TYPE_FEATURES) { + startLevel = 1; + } int maxlvl = 10; final MessagesController m = MessagesController.getInstance(currentAccount); if (m != null) { @@ -2348,11 +2415,6 @@ private void setupBoostFeatures() { lastFeatureList = featureList; } } - - if (type == TYPE_FEATURES && boostFeatures.isEmpty()) { - boostFeatures.add(new BoostFeature.BoostFeatureLevel(10, true)); - boostFeatures.addAll(boostFeaturesForLevel(10)); - } } private ArrayList boostFeaturesForLevel(int level) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/PremiumFeatureBottomSheet.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/PremiumFeatureBottomSheet.java index 5e5912aeaf0..10e4d4a432c 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/PremiumFeatureBottomSheet.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/PremiumFeatureBottomSheet.java @@ -9,15 +9,18 @@ import android.graphics.Path; import android.graphics.drawable.Drawable; import android.os.Bundle; +import android.util.Log; 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.widget.FrameLayout; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.ScrollView; +import android.widget.Scroller; import android.widget.TextView; import androidx.annotation.NonNull; @@ -28,6 +31,7 @@ import androidx.viewpager.widget.ViewPager; import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.FileLog; import org.telegram.messenger.LocaleController; import org.telegram.messenger.MediaDataController; import org.telegram.messenger.NotificationCenter; @@ -38,7 +42,6 @@ import org.telegram.ui.ActionBar.BaseFragment; import org.telegram.ui.ActionBar.BottomSheet; import org.telegram.ui.ActionBar.Theme; -import org.telegram.ui.Cells.ChatActionCell; import org.telegram.ui.ChatActivity; import org.telegram.ui.Components.BottomPagesView; import org.telegram.ui.Components.CubicBezierInterpolator; @@ -48,6 +51,7 @@ import org.telegram.ui.PremiumPreviewFragment; import org.telegram.ui.ThemePreviewActivity; +import java.lang.reflect.Field; import java.util.ArrayList; public class PremiumFeatureBottomSheet extends BottomSheet implements NotificationCenter.NotificationCenterDelegate { @@ -88,14 +92,14 @@ public PremiumFeatureBottomSheet(BaseFragment fragment, int startType, boolean o } public PremiumFeatureBottomSheet(BaseFragment fragment, int startType, boolean onlySelectedType, PremiumPreviewFragment.SubscriptionTier subscriptionTier) { - this(fragment, fragment.getContext(), fragment.getCurrentAccount(), startType, onlySelectedType, subscriptionTier); + this(fragment, fragment.getContext(), fragment.getCurrentAccount(), false, startType, onlySelectedType, subscriptionTier); } public PremiumFeatureBottomSheet(BaseFragment fragment, Context context, int currentAccount, int startType, boolean onlySelectedType) { - this(fragment, context, currentAccount, startType, onlySelectedType, null); + this(fragment, context, currentAccount, false, startType, onlySelectedType, null); } - public PremiumFeatureBottomSheet(BaseFragment fragment, Context context, int currentAccount, int startType, boolean onlySelectedType, PremiumPreviewFragment.SubscriptionTier subscriptionTier) { + public PremiumFeatureBottomSheet(BaseFragment fragment, Context context, int currentAccount, boolean business, int startType, boolean onlySelectedType, PremiumPreviewFragment.SubscriptionTier subscriptionTier) { super(context, false, getResourceProvider(fragment)); this.baseFragment = fragment; if (fragment == null) { @@ -121,8 +125,12 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { } }; - - PremiumPreviewFragment.fillPremiumFeaturesList(premiumFeatures, currentAccount); + if (business || startType == PremiumPreviewFragment.PREMIUM_FEATURE_FOLDER_TAGS) { + PremiumPreviewFragment.fillBusinessFeaturesList(premiumFeatures, currentAccount, false); + PremiumPreviewFragment.fillBusinessFeaturesList(premiumFeatures, currentAccount, true); + } else { + PremiumPreviewFragment.fillPremiumFeaturesList(premiumFeatures, currentAccount, false); + } int selectedPositionLocal = 0; for (int i = 0; i < premiumFeatures.size(); i++) { @@ -191,21 +199,67 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(h + topGlobalOffset, MeasureSpec.EXACTLY)); } + private boolean processTap(MotionEvent ev, boolean intercept) { + if (ev.getAction() == MotionEvent.ACTION_DOWN) { + lastTapTime = System.currentTimeMillis(); + return true; + } else if (ev.getAction() == MotionEvent.ACTION_UP) { + if ((System.currentTimeMillis() - lastTapTime) <= ViewConfiguration.getTapTimeout() && (scroller != null && scroller.isFinished())) { + smoothScroll = true; + if (ev.getX() > getWidth() * .45f) { + if (selectedPosition + 1 < premiumFeatures.size()) { + setCurrentItem(selectedPosition + 1, true); + } + } else { + if (selectedPosition - 1 >= 0) { + setCurrentItem(selectedPosition - 1, true); + } + } + smoothScroll = false; + } + } else if (ev.getAction() == MotionEvent.ACTION_CANCEL) { + lastTapTime = -1; + } + return false; + } + @Override public boolean onInterceptTouchEvent(MotionEvent ev) { try { + processTap(ev, true); return super.onInterceptTouchEvent(ev); } catch (Exception e) { return false; } } + long lastTapTime; @Override public boolean onTouchEvent(MotionEvent ev) { if (enterAnimationIsRunning) { return false; } - return super.onTouchEvent(ev); + boolean r = processTap(ev, false); + return super.onTouchEvent(ev) || r; + } + + private boolean smoothScroll; + private Scroller scroller; + { + try { + Class viewpager = ViewPager.class; + Field scroller = viewpager.getDeclaredField("mScroller"); + scroller.setAccessible(true); + this.scroller = new Scroller(getContext()) { + @Override + public void startScroll(int startX, int startY, int dx, int dy, int duration) { + super.startScroll(startX, startY, dx, dy, (smoothScroll ? 3 : 1) * duration); + } + }; + scroller.set(this, this.scroller); + } catch (Exception e) { + FileLog.e(e); + } } }; viewPager.setOverScrollMode(View.OVER_SCROLL_NEVER); @@ -261,6 +315,9 @@ public void onPageSelected(int i) { } else if (premiumFeatures.get(i).type == PremiumPreviewFragment.PREMIUM_FEATURE_STORIES) { actionBar.setTitle(LocaleController.getString("UpgradedStories", R.string.UpgradedStories)); actionBar.requestLayout(); + } else if (premiumFeatures.get(i).type == PremiumPreviewFragment.PREMIUM_FEATURE_BUSINESS) { + actionBar.setTitle(LocaleController.getString(R.string.TelegramBusiness)); + actionBar.requestLayout(); } checkPage(); } @@ -467,7 +524,7 @@ private static Theme.ResourcesProvider getResourceProvider(BaseFragment fragment } private boolean isFullscreenType(int type) { - return type == PremiumPreviewFragment.PREMIUM_FEATURE_LIMITS || type == PremiumPreviewFragment.PREMIUM_FEATURE_STORIES; + return type == PremiumPreviewFragment.PREMIUM_FEATURE_LIMITS || type == PremiumPreviewFragment.PREMIUM_FEATURE_STORIES || type == PremiumPreviewFragment.PREMIUM_FEATURE_BUSINESS; } public void hideButton() { @@ -552,7 +609,10 @@ public void onItemClick(int id) { if (premiumFeatures.get(selectedPosition).type == PremiumPreviewFragment.PREMIUM_FEATURE_STORIES) { actionBar.setTitle(LocaleController.getString("UpgradedStories", R.string.UpgradedStories)); actionBar.requestLayout(); - } else { + } else if (premiumFeatures.get(selectedPosition).type == PremiumPreviewFragment.PREMIUM_FEATURE_BUSINESS) { + actionBar.setTitle(LocaleController.getString(R.string.TelegramBusiness)); + actionBar.requestLayout(); + } else { actionBar.setTitle(LocaleController.getString("DoubledLimits", R.string.DoubledLimits)); actionBar.requestLayout(); } @@ -667,7 +727,7 @@ protected boolean drawChild(Canvas canvas, View child, long drawingTime) { } void setFeatureDate(PremiumPreviewFragment.PremiumFeatureData featureData) { - if (featureData.type == PremiumPreviewFragment.PREMIUM_FEATURE_LIMITS || featureData.type == PremiumPreviewFragment.PREMIUM_FEATURE_STORIES) { + if (featureData.type == PremiumPreviewFragment.PREMIUM_FEATURE_LIMITS || featureData.type == PremiumPreviewFragment.PREMIUM_FEATURE_STORIES || featureData.type == PremiumPreviewFragment.PREMIUM_FEATURE_BUSINESS) { title.setText(""); description.setText(""); topViewOnFullHeight = true; @@ -731,9 +791,15 @@ public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) { }); return doubleLimitsPagerView; } - if (featureData.type == PremiumPreviewFragment.PREMIUM_FEATURE_STORIES) { - StoriesPageView storiesPageView = new StoriesPageView(context, resourcesProvider); - storiesPageView.recyclerListView.setOnScrollListener(new RecyclerView.OnScrollListener() { + if (featureData.type == PremiumPreviewFragment.PREMIUM_FEATURE_STORIES || featureData.type == PremiumPreviewFragment.PREMIUM_FEATURE_BUSINESS) { + final int type; + if (featureData.type == PremiumPreviewFragment.PREMIUM_FEATURE_BUSINESS) { + type = FeaturesPageView.FEATURES_BUSINESS; + } else { + type = FeaturesPageView.FEATURES_STORIES; + } + FeaturesPageView featuresPageView = new FeaturesPageView(context, type, resourcesProvider); + featuresPageView.recyclerListView.setOnScrollListener(new RecyclerView.OnScrollListener() { @Override public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) { super.onScrolled(recyclerView, dx, dy); @@ -741,7 +807,7 @@ public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) { checkTopOffset(); } }); - return storiesPageView; + return featuresPageView; } if (featureData.type == PremiumPreviewFragment.PREMIUM_FEATURE_STICKERS) { PremiumStickersPreviewRecycler recyclerListView = new PremiumStickersPreviewRecycler(context, currentAccount) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/PremiumPreviewBottomSheet.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/PremiumPreviewBottomSheet.java index a876bbe5ec5..6690a98b01a 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/PremiumPreviewBottomSheet.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/PremiumPreviewBottomSheet.java @@ -36,7 +36,6 @@ import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.ContactsController; import org.telegram.messenger.Emoji; -import org.telegram.messenger.FileLog; import org.telegram.messenger.LocaleController; import org.telegram.messenger.MediaDataController; import org.telegram.messenger.NotificationCenter; @@ -131,7 +130,7 @@ public PremiumPreviewBottomSheet(BaseFragment fragment, int currentAccount, TLRP this.currentAccount = currentAccount; this.giftTier = gift; dummyCell = new PremiumFeatureCell(getContext()); - PremiumPreviewFragment.fillPremiumFeaturesList(premiumFeatures, currentAccount); + PremiumPreviewFragment.fillPremiumFeaturesList(premiumFeatures, currentAccount, false); if (giftTier != null || UserConfig.getInstance(currentAccount).isPremium()) { buttonContainer.setVisibility(View.GONE); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/StarParticlesView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/StarParticlesView.java index a94e1c3dc46..e73d0bd6a28 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/StarParticlesView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/StarParticlesView.java @@ -1,17 +1,23 @@ package org.telegram.ui.Components.Premium; +import static org.telegram.messenger.AndroidUtilities.dp; + import android.animation.AnimatorSet; import android.animation.ValueAnimator; import android.content.Context; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.CornerPathEffect; +import android.graphics.LinearGradient; import android.graphics.Matrix; import android.graphics.Paint; import android.graphics.Path; import android.graphics.PorterDuff; import android.graphics.PorterDuffColorFilter; +import android.graphics.PorterDuffXfermode; import android.graphics.RectF; +import android.graphics.Shader; +import android.graphics.Xfermode; import android.view.View; import androidx.core.content.ContextCompat; @@ -33,20 +39,22 @@ public class StarParticlesView extends View { + public boolean doNotFling; public Drawable drawable; int size; public final static int TYPE_APP_ICON_REACT = 1001; public static final int TYPE_APP_ICON_STAR_PREMIUM = 1002; public StarParticlesView(Context context) { - super(context); + this(context, ( + SharedConfig.getDevicePerformanceClass() == SharedConfig.PERFORMANCE_CLASS_HIGH ? 200 : + SharedConfig.getDevicePerformanceClass() == SharedConfig.PERFORMANCE_CLASS_AVERAGE ? 100 : + 50 + )); + } - int particlesCount = 50; - if (SharedConfig.getDevicePerformanceClass() == SharedConfig.PERFORMANCE_CLASS_HIGH) { - particlesCount = 200; - } else if (SharedConfig.getDevicePerformanceClass() == SharedConfig.PERFORMANCE_CLASS_AVERAGE) { - particlesCount = 100; - } + public StarParticlesView(Context context, int particlesCount) { + super(context); drawable = new Drawable(particlesCount); configure(); @@ -67,9 +75,9 @@ protected void configure() { protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); int sizeInternal = getMeasuredWidth() << 16 + getMeasuredHeight(); - drawable.rect.set(0, 0, getStarsRectWidth(), AndroidUtilities.dp(140)); + drawable.rect.set(0, 0, getStarsRectWidth(), dp(140)); drawable.rect.offset((getMeasuredWidth() - drawable.rect.width()) / 2, (getMeasuredHeight() - drawable.rect.height()) / 2); - drawable.rect2.set(0, 0, getMeasuredWidth(), getMeasuredHeight()); + drawable.rect2.set(-dp(15), -dp(15), getMeasuredWidth() + dp(15), getMeasuredHeight() + dp(15)); if (size != sizeInternal) { size = sizeInternal; drawable.resetPositions(); @@ -77,19 +85,44 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { } protected int getStarsRectWidth() { - return AndroidUtilities.dp(140); + return dp(140); + } + + private Paint clipGradientPaint; + private LinearGradient clipGradient; + private Matrix clipGradientMatrix; + + public void setClipWithGradient() { + clipGradientPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + clipGradientPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT)); + clipGradient = new LinearGradient(0, 0, 0, dp(12), new int[] { 0x00FFFFFF, 0xFFFFFFFF }, new float[] { 0, 1 }, Shader.TileMode.CLAMP); + clipGradientPaint.setShader(clipGradient); + clipGradientMatrix = new Matrix(); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); + if (clipGradientPaint != null) { + canvas.saveLayerAlpha(0, 0, getWidth(), getHeight(), 0xFF, Canvas.ALL_SAVE_FLAG); + } drawable.onDraw(canvas); + if (clipGradientPaint != null) { + canvas.save(); + clipGradientMatrix.reset(); + clipGradientMatrix.postTranslate(0, 1 + getHeight() - dp(12)); + clipGradient.setLocalMatrix(clipGradientMatrix); + canvas.drawRect(0, 0, getWidth(), getHeight(), clipGradientPaint); + canvas.restore(); + canvas.restore(); + } if (!drawable.paused) { invalidate(); } } public void flingParticles(float sum) { + if (doNotFling) return; float maxSpeed = 15f; if (sum < 60) { maxSpeed = 5f; @@ -120,6 +153,7 @@ public static class Drawable { public boolean startFromCenter; public Paint paint = new Paint(); public float excludeRadius = 0; + public float centerOffsetX = 0, centerOffsetY = 0; public Paint overridePaint; public ArrayList particles = new ArrayList<>(); @@ -151,7 +185,8 @@ public static class Drawable { public int type = -1; public Theme.ResourcesProvider resourcesProvider; public int colorKey = Theme.key_premiumStartSmallStarsColor; - public boolean svg; + public final boolean[] svg = new boolean[3]; + public final boolean[] flip = new boolean[3]; public long pausedTime; @@ -194,13 +229,13 @@ private void generateBitmaps() { float k = k1; Bitmap bitmap; if (i == 0) { - size = AndroidUtilities.dp(size1); + size = dp(size1); } else if (i == 1) { k = k2; - size = AndroidUtilities.dp(size2); + size = dp(size2); } else { k = k3; - size = AndroidUtilities.dp(size3); + size = dp(size3); } if (type == PremiumPreviewFragment.PREMIUM_FEATURE_ADVANCED_CHAT_MANAGEMENT) { @@ -213,7 +248,7 @@ private void generateBitmaps() { res = R.raw.premium_object_settings; } stars[i] = SvgHelper.getBitmap(res, size, size, ColorUtils.setAlphaComponent(Theme.getColor(colorKey, resourcesProvider), 30)); - svg = true; + svg[i] = true; continue; } else if (type == PremiumPreviewFragment.PREMIUM_FEATURE_ANIMATED_EMOJI || type == PremiumPreviewFragment.PREMIUM_FEATURE_REACTIONS) { int res; @@ -225,7 +260,7 @@ private void generateBitmaps() { res = R.raw.premium_object_like; } stars[i] = SvgHelper.getBitmap(res, size, size, ColorUtils.setAlphaComponent(Theme.getColor(colorKey, resourcesProvider), 30)); - svg = true; + svg[i] = true; continue; } else if (type == PremiumPreviewFragment.PREMIUM_FEATURE_WALLPAPER) { int res; @@ -237,7 +272,7 @@ private void generateBitmaps() { res = R.raw.cache_profile_photos; } stars[i] = SvgHelper.getBitmap(res, size, size, ColorUtils.setAlphaComponent(Theme.getColor(colorKey, resourcesProvider), 30)); - svg = true; + svg[i] = true; continue; } else if (type == PremiumPreviewFragment.PREMIUM_FEATURE_ADS) { int res; @@ -249,7 +284,7 @@ private void generateBitmaps() { res = R.raw.premium_object_noads; } stars[i] = SvgHelper.getBitmap(res, size, size, ColorUtils.setAlphaComponent(Theme.getColor(colorKey, resourcesProvider), 30)); - svg = true; + svg[i] = true; continue; } else if (type == PremiumPreviewFragment.PREMIUM_FEATURE_ANIMATED_AVATARS) { int res; @@ -261,15 +296,15 @@ private void generateBitmaps() { res = R.raw.premium_object_user; } stars[i] = SvgHelper.getBitmap(res, size, size, ColorUtils.setAlphaComponent(Theme.getColor(colorKey, resourcesProvider), 30)); - svg = true; + svg[i] = true; continue; } else if (type == TYPE_APP_ICON_REACT) { stars[i] = SvgHelper.getBitmap(R.raw.premium_object_fire, size, size, ColorUtils.setAlphaComponent(Theme.getColor(colorKey, resourcesProvider), 30)); - svg = true; + svg[i] = true; continue; } else if (type == TYPE_APP_ICON_STAR_PREMIUM) { stars[i] = SvgHelper.getBitmap(R.raw.premium_object_star2, size, size, ColorUtils.setAlphaComponent(Theme.getColor(colorKey, resourcesProvider), 30)); - svg = true; + svg[i] = true; continue; } else if (type == PremiumPreviewFragment.PREMIUM_FEATURE_SAVED_TAGS) { int res; @@ -281,8 +316,16 @@ private void generateBitmaps() { res = R.raw.premium_object_star; } stars[i] = SvgHelper.getBitmap(res, size, size, ColorUtils.setAlphaComponent(Theme.getColor(colorKey, resourcesProvider), 30)); - svg = true; + svg[i] = true; continue; + } else if (type == PremiumPreviewFragment.PREMIUM_FEATURE_BUSINESS) { + int res; + if (i == 0) { + res = R.raw.filled_premium_dollar; + stars[i] = SvgHelper.getBitmap(res, size, size, ColorUtils.setAlphaComponent(Theme.getColor(colorKey, resourcesProvider), 0xFF)); + flip[i] = true; + continue; + } } bitmap = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888); @@ -313,7 +356,7 @@ private void generateBitmaps() { Paint paint = new Paint(); if (useGradient) { - if (size >= AndroidUtilities.dp(10)) { + if (size >= dp(10)) { PremiumGradient.getInstance().updateMainGradientMatrix(0, 0, size, size, -2 * size, 0); } else { PremiumGradient.getInstance().updateMainGradientMatrix(0, 0, size, size, -4 * size, 0); @@ -373,9 +416,9 @@ public void onDraw(Canvas canvas, float alpha) { a += 360f * (diff / 40000f); a1 += 360f * (diff / 50000f); a2 += 360f * (diff / 60000f); - matrix.setRotate(a, rect.centerX(), rect.centerY()); - matrix2.setRotate(a1, rect.centerX(), rect.centerY()); - matrix3.setRotate(a2, rect.centerX(), rect.centerY()); + matrix.setRotate(a, rect.centerX() + centerOffsetX, rect.centerY() + centerOffsetY); + matrix2.setRotate(a1, rect.centerX() + centerOffsetX, rect.centerY() + centerOffsetY); + matrix3.setRotate(a2, rect.centerX() + centerOffsetX, rect.centerY() + centerOffsetY); pointsCount1 = 0; pointsCount2 = 0; @@ -424,6 +467,7 @@ public class Particle { private int alpha; private float randomRotate; float inProgress; + float flipProgress; public void updatePoint() { if (starIndex == 0) { @@ -470,22 +514,31 @@ public void draw(Canvas canvas, long time, float alpha) { if (randomRotate != 0) { canvas.rotate(randomRotate, stars[starIndex].getWidth() / 2f, stars[starIndex].getHeight() / 2f); } - if (inProgress < 1f || GLIconSettingsView.smallStarsSize != 1f) { - float s = AndroidUtilities.overshootInterpolator.getInterpolation(inProgress) * GLIconSettingsView.smallStarsSize; - canvas.scale(s, s, 0, 0); - } float outProgress = 0f; if (checkTime && lifeTime - time < 200) { outProgress = 1f - (lifeTime - time) / 150f; outProgress = Utilities.clamp(outProgress, 1f, 0f); } + if (inProgress < 1f || GLIconSettingsView.smallStarsSize != 1f) { + float s = AndroidUtilities.overshootInterpolator.getInterpolation(inProgress) * GLIconSettingsView.smallStarsSize; + canvas.scale(s, s, 0, 0); + } + if (flip[starIndex]) { + flipProgress += dt / 1000f * Math.min(speedScale, 3.5f); + canvas.scale((float) Math.cos(Math.PI * flipProgress), 1f, 0, 0); + } Paint paint = overridePaint != null ? overridePaint : Drawable.this.paint; paint.setAlpha((int) (this.alpha * (1f - outProgress) * alpha)); canvas.drawBitmap(stars[starIndex], -(stars[starIndex].getWidth() >> 1), -(stars[starIndex].getHeight() >> 1), paint); canvas.restore(); } if (!paused) { - float speed = AndroidUtilities.dp(4) * (dt / 660f) * speedScale; + float speed = dp(4) * (dt / 660f); + if (flip[starIndex]) { + speed *= 4 * Math.min(speedScale, 3.5f); + } else { + speed *= speedScale; + } x += vecX * speed; y += vecY * speed; @@ -498,9 +551,16 @@ public void draw(Canvas canvas, long time, float alpha) { } } + private boolean first = true; public void genPosition(long time) { - starIndex = Math.abs(Utilities.fastRandom.nextInt() % stars.length); - lifeTime = time + minLifeTime + Utilities.fastRandom.nextInt(randLifeTime); + if (type == PremiumPreviewFragment.PREMIUM_FEATURE_BUSINESS) { + final float rand = Utilities.fastRandom.nextFloat(); + if (rand < .13f) starIndex = 0; + else starIndex = (int) Math.floor(1 + rand * (stars.length - 1)); + } else { + starIndex = Math.abs(Utilities.fastRandom.nextInt() % stars.length); + } + lifeTime = time + minLifeTime + Utilities.fastRandom.nextInt(randLifeTime * (flip[starIndex] ? 3 : 1)); randomRotate = 0; if (distributionAlgorithm) { @@ -539,18 +599,32 @@ public void genPosition(long time) { if (isCircle) { float r = (Math.abs(Utilities.fastRandom.nextInt() % 1000) / 1000f) * (rect.width() - excludeRadius) + excludeRadius; float a = Math.abs(Utilities.fastRandom.nextInt() % 360); - x = rect.centerX() + (float) (r * Math.sin(Math.toRadians(a))); - y = rect.centerY() + (float) (r * Math.cos(Math.toRadians(a))); + float oy = 0; + if (flip[starIndex] && !first) { + r = Math.min(r, dp(10)); + oy += dp(30); + } + x = rect.centerX() + centerOffsetX + (float) (r * Math.sin(Math.toRadians(a))); + y = rect.centerY() + oy + centerOffsetY + (float) (r * Math.cos(Math.toRadians(a))); } else { x = rect.left + Math.abs(Utilities.fastRandom.nextInt() % rect.width()); y = rect.top + Math.abs(Utilities.fastRandom.nextInt() % rect.height()); } } + if (flip[starIndex]) { + flipProgress = Math.abs(Utilities.fastRandom.nextFloat() * 2); + } - double a = Math.atan2(x - rect.centerX(), y - rect.centerY()); + double a; + if (flip[starIndex]) { + float d = 100; + a = Math.toRadians(180 + d - 2 * d * Utilities.fastRandom.nextFloat()); + } else { + a = Math.atan2(x - (rect.centerX() + centerOffsetX), y - (rect.centerY() + centerOffsetY)); + } vecX = (float) Math.sin(a); vecY = (float) Math.cos(a); - if (svg) { + if (svg[starIndex]) { alpha = (int) (120 * ((50 + Utilities.fastRandom.nextInt(50)) / 100f)); } else { alpha = (int) (255 * ((50 + Utilities.fastRandom.nextInt(50)) / 100f)); @@ -572,9 +646,10 @@ public void genPosition(long time) { if (startFromCenter) { x2 = x; y2 = y; - x = rect.centerX();// + (x - rect.centerX()) * 0.3f; - y = rect.centerY();// + (y - rect.centerY()) * 0.3f; + x = rect.centerX() + centerOffsetX;// + (x - rect.centerX()) * 0.3f; + y = rect.centerY() + centerOffsetY;// + (y - rect.centerY()) * 0.3f; } + first = false; } } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/StoriesPageView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/StoriesPageView.java deleted file mode 100644 index 58e57d3c349..00000000000 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/StoriesPageView.java +++ /dev/null @@ -1,268 +0,0 @@ -package org.telegram.ui.Components.Premium; - -import android.content.Context; -import android.graphics.Bitmap; -import android.graphics.Canvas; -import android.graphics.LinearGradient; -import android.graphics.Paint; -import android.graphics.PorterDuff; -import android.graphics.PorterDuffColorFilter; -import android.graphics.Shader; -import android.util.TypedValue; -import android.view.Gravity; -import android.view.View; -import android.view.ViewGroup; -import android.widget.FrameLayout; -import android.widget.ImageView; -import android.widget.TextView; - -import androidx.annotation.NonNull; -import androidx.core.content.ContextCompat; -import androidx.recyclerview.widget.RecyclerView; - -import org.telegram.messenger.AndroidUtilities; -import org.telegram.messenger.LocaleController; -import org.telegram.messenger.MessagesController; -import org.telegram.messenger.R; -import org.telegram.messenger.UserConfig; -import org.telegram.tgnet.TLRPC; -import org.telegram.ui.ActionBar.Theme; -import org.telegram.ui.Cells.FixedHeightEmptyCell; -import org.telegram.ui.Components.AvatarDrawable; -import org.telegram.ui.Components.BackupImageView; -import org.telegram.ui.Components.GradientTools; -import org.telegram.ui.Components.LayoutHelper; -import org.telegram.ui.Components.RecyclerListView; -import org.telegram.ui.PremiumPreviewFragment; - -import java.util.ArrayList; -import java.util.Collections; - -public class StoriesPageView extends BaseListPageView { - - RecyclerListView.SelectionAdapter adapter; - private final static int VIEW_TYPE_HEADER = 0; - private final static int VIEW_TYPE_ITEM = 1; - private final static int VIEW_TYPE_EMPTY = 2; - - ArrayList items = new ArrayList<>(); - Bitmap bitmap; - - public StoriesPageView(Context context, Theme.ResourcesProvider resourcesProvider) { - super(context, resourcesProvider); - ArrayList itemsTmp = new ArrayList<>(); - itemsTmp.add(new Item(VIEW_TYPE_ITEM, R.drawable.msg_stories_order, - LocaleController.getString("PremiumStoriesPriority", R.string.PremiumStoriesPriority), - LocaleController.getString("PremiumStoriesPriorityDescription", R.string.PremiumStoriesPriorityDescription), - PremiumPreviewFragment.PREMIUM_FEATURE_STORIES_PRIORITY_ORDER - )); - itemsTmp.add(new Item(VIEW_TYPE_ITEM, R.drawable.msg_stories_stealth, - LocaleController.getString("PremiumStoriesStealth", R.string.PremiumStoriesStealth), - LocaleController.getString("PremiumStoriesStealthDescription", R.string.PremiumStoriesStealthDescription), - PremiumPreviewFragment.PREMIUM_FEATURE_STORIES_STEALTH_MODE - )); - itemsTmp.add(new Item(VIEW_TYPE_ITEM, R.drawable.menu_quality_hd, - LocaleController.getString(R.string.PremiumStoriesQuality), - LocaleController.getString(R.string.PremiumStoriesQualityDescription), - PremiumPreviewFragment.PREMIUM_FEATURE_STORIES_QUALITY - )); - itemsTmp.add(new Item(VIEW_TYPE_ITEM, R.drawable.msg_stories_views, - LocaleController.getString("PremiumStoriesViews", R.string.PremiumStoriesViews), - LocaleController.getString("PremiumStoriesViewsDescription", R.string.PremiumStoriesViewsDescription), - PremiumPreviewFragment.PREMIUM_FEATURE_STORIES_VIEWS_HISTORY - )); - itemsTmp.add(new Item(VIEW_TYPE_ITEM, R.drawable.msg_stories_timer, - LocaleController.getString("PremiumStoriesExpiration", R.string.PremiumStoriesExpiration), - LocaleController.getString("PremiumStoriesExpirationDescription", R.string.PremiumStoriesExpirationDescription), - PremiumPreviewFragment.PREMIUM_FEATURE_STORIES_EXPIRATION_DURATION - )); - itemsTmp.add(new Item(VIEW_TYPE_ITEM, R.drawable.msg_stories_save, - LocaleController.getString("PremiumStoriesSaveToGallery", R.string.PremiumStoriesSaveToGallery), - LocaleController.getString("PremiumStoriesSaveToGalleryDescription", R.string.PremiumStoriesSaveToGalleryDescription), - PremiumPreviewFragment.PREMIUM_FEATURE_STORIES_SAVE_TO_GALLERY - )); - itemsTmp.add(new Item(VIEW_TYPE_ITEM, R.drawable.msg_stories_caption, - LocaleController.getString("PremiumStoriesCaption", R.string.PremiumStoriesCaption), - LocaleController.getString("PremiumStoriesCaptionDescription", R.string.PremiumStoriesCaptionDescription), - PremiumPreviewFragment.PREMIUM_FEATURE_STORIES_CAPTION - )); - itemsTmp.add(new Item(VIEW_TYPE_ITEM, R.drawable.msg_stories_link, - LocaleController.getString("PremiumStoriesFormatting", R.string.PremiumStoriesFormatting), - LocaleController.getString("PremiumStoriesFormattingDescription", R.string.PremiumStoriesFormattingDescription), - PremiumPreviewFragment.PREMIUM_FEATURE_STORIES_LINKS_AND_FORMATTING - )); - - MessagesController messagesController = MessagesController.getInstance(UserConfig.selectedAccount); - Collections.sort(itemsTmp, (o1, o2) -> { - int type1 = messagesController.premiumFeaturesTypesToPosition.get(o1.order, Integer.MAX_VALUE); - int type2 = messagesController.premiumFeaturesTypesToPosition.get(o2.order, Integer.MAX_VALUE); - return type1 - type2; - }); - - items.add(new Item(VIEW_TYPE_HEADER)); - items.addAll(itemsTmp); - items.add(new Item(VIEW_TYPE_EMPTY)); - bitmap = Bitmap.createBitmap(items.size(), 1, Bitmap.Config.ARGB_8888); - Canvas canvas = new Canvas(bitmap); - Paint paint = new Paint(); - paint.setShader(new LinearGradient(0, 0, bitmap.getWidth(), 0, new int[] { - Theme.getColor(Theme.key_premiumGradient1), - Theme.getColor(Theme.key_premiumGradient2), - Theme.getColor(Theme.key_premiumGradient3), - Theme.getColor(Theme.key_premiumGradient4) - }, null, Shader.TileMode.CLAMP)); - canvas.drawRect(0, 0, bitmap.getWidth(), bitmap.getHeight(), paint); - } - - @Override - public RecyclerView.Adapter createAdapter() { - adapter = new RecyclerListView.SelectionAdapter() { - - @Override - public boolean isEnabled(RecyclerView.ViewHolder holder) { - return false; - } - - @NonNull - @Override - public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { - View view; - if (viewType == VIEW_TYPE_HEADER) { - view = new HeaderView(getContext()); - } else if (viewType == VIEW_TYPE_EMPTY) { - view = new FixedHeightEmptyCell(getContext(), 16); - } else { - view = new ItemCell(getContext()); - } - view.setLayoutParams(new RecyclerView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)); - return new RecyclerListView.Holder(view); - } - - @Override - public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) { - if (items.get(position).viewType == VIEW_TYPE_ITEM) { - ItemCell cell = (ItemCell) holder.itemView; - cell.imageView.setColorFilter(new PorterDuffColorFilter(bitmap.getPixel(position, 0), PorterDuff.Mode.MULTIPLY)); - cell.imageView.setImageDrawable(ContextCompat.getDrawable(getContext(), items.get(position).iconRes)); - cell.textView.setText(items.get(position).text); - cell.description.setText(items.get(position).description); - } - } - - @Override - public int getItemViewType(int position) { - return items.get(position).viewType; - } - - @Override - public int getItemCount() { - return items.size(); - } - }; - return adapter; - } - - private class Item { - final int viewType; - int iconRes; - String text; - String description; - int order; - - private Item(int viewType) { - this.viewType = viewType; - } - - public Item(int viewType, int iconRes, String text, String description, int order) { - this.viewType = viewType; - this.iconRes = iconRes; - this.text = text; - this.description = description; - this.order = order; - } - } - - private class HeaderView extends FrameLayout { - - BackupImageView imageView; - GradientTools gradientTools = new GradientTools(); - - public HeaderView(Context context) { - super(context); - imageView = new BackupImageView(context); - imageView.setRoundRadius((int) (AndroidUtilities.dp(65) / 2f)); - addView(imageView, LayoutHelper.createFrame(65, 65, Gravity.CENTER_HORIZONTAL, 0, 32, 0, 0)); - - TLRPC.User user = UserConfig.getInstance(UserConfig.selectedAccount).getCurrentUser(); - AvatarDrawable avatarDrawable = new AvatarDrawable(); - avatarDrawable.setInfo(user); - imageView.getImageReceiver().setForUserOrChat(user, avatarDrawable); - - TextView textView = new TextView(context); - textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 20); - textView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); - textView.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlackText, resourcesProvider)); - textView.setText(LocaleController.getString("UpgradedStories", R.string.UpgradedStories)); - addView(textView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_HORIZONTAL, 0, 111, 0, 0)); - - gradientTools.isLinear = true; - gradientTools.isDiagonal = true; - gradientTools.setColors( - Theme.getColor(Theme.key_premiumGradient2), - Theme.getColor(Theme.key_premiumGradient1) - ); - gradientTools.paint.setStyle(Paint.Style.STROKE); - gradientTools.paint.setStrokeCap(Paint.Cap.ROUND); - gradientTools.paint.setStrokeWidth(AndroidUtilities.dpf2(3.3f)); - } - - @Override - protected void dispatchDraw(Canvas canvas) { - imageView.getHitRect(AndroidUtilities.rectTmp2); - AndroidUtilities.rectTmp.set(AndroidUtilities.rectTmp2); - AndroidUtilities.rectTmp.inset(-AndroidUtilities.dp(5), -AndroidUtilities.dp(5)); - gradientTools.setBounds(AndroidUtilities.rectTmp); - int storiesCount = 7; - float step = 360 / (float) storiesCount; - int gapLen = 5; - for (int i = 0; i < storiesCount; i++) { - float startAngle = step * i - 90; - float endAngle = startAngle + step; - startAngle += gapLen; - endAngle -= gapLen; - canvas.drawArc(AndroidUtilities.rectTmp, startAngle, (endAngle - startAngle), false, gradientTools.paint); - } - super.dispatchDraw(canvas); - } - - @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(150), MeasureSpec.EXACTLY)); - } - } - - private class ItemCell extends FrameLayout { - - TextView textView; - TextView description; - ImageView imageView; - - public ItemCell(Context context) { - super(context); - imageView = new ImageView(context); - imageView.setScaleType(ImageView.ScaleType.CENTER_INSIDE); - addView(imageView, LayoutHelper.createFrame(28, 28, 0, 25, 12, 16, 0)); - - textView = new TextView(context); - textView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); - textView.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlackText, resourcesProvider)); - textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); - addView(textView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, 0, 68, 8, 16, 0)); - - description = new TextView(context); - description.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteGrayText, resourcesProvider)); - description.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); - addView(description, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, 0, 68, 28, 16, 8)); - } - } -} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/VideoScreenPreview.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/VideoScreenPreview.java index c138f73eec0..5ab4720719d 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/VideoScreenPreview.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/VideoScreenPreview.java @@ -12,6 +12,7 @@ import android.media.MediaMetadataRetriever; import android.net.Uri; import android.os.Build; +import android.util.Log; import android.view.TextureView; import android.widget.FrameLayout; @@ -32,12 +33,14 @@ import org.telegram.messenger.SharedConfig; import org.telegram.messenger.SvgHelper; import org.telegram.messenger.Utilities; +import org.telegram.messenger.video.VideoPlayerHolderBase; import org.telegram.tgnet.TLRPC; import org.telegram.ui.ActionBar.Theme; import org.telegram.ui.Components.CombinedDrawable; import org.telegram.ui.Components.VideoPlayer; import org.telegram.ui.Components.voip.CellFlickerDrawable; import org.telegram.ui.PremiumPreviewFragment; +import org.telegram.ui.Stories.StoryViewer; import java.io.File; import java.net.URLEncoder; @@ -97,7 +100,8 @@ private void checkVideo() { boolean firstFrameRendered; float progress; - VideoPlayer videoPlayer; +// VideoPlayer videoPlayer; + VideoPlayerHolderBase videoPlayerBase; AspectRatioFrameLayout aspectRatioFrameLayout; TextureView textureView; @@ -375,8 +379,8 @@ protected void dispatchDraw(Canvas canvas) { } else if (speedLinesDrawable != null) { float videoSpeedScale = 0.2f; - if (videoPlayer != null) { - float p = videoPlayer.getCurrentPosition() / (float) videoPlayer.getDuration(); + if (videoPlayerBase != null) { + float p = videoPlayerBase.getCurrentPosition() / (float) videoPlayerBase.getDuration(); p = Utilities.clamp(p, 1f, 0); float step = 1f / (speedScaleVideoTimestamps.length - 1); int fromIndex = (int) (p / step); @@ -539,58 +543,38 @@ private void updateAttachState() { private void runVideoPlayer() { if (file != null || SharedConfig.streamMedia) { - if (videoPlayer != null) { + if (videoPlayerBase != null) { return; } aspectRatioFrameLayout.setAspectRatio(aspectRatio, 0); - videoPlayer = new VideoPlayer(); - videoPlayer.setTextureView(textureView); - videoPlayer.setDelegate(new VideoPlayer.VideoPlayerDelegate() { + videoPlayerBase = new VideoPlayerHolderBase() { @Override public void onStateChanged(boolean playWhenReady, int playbackState) { + if (videoPlayerBase == null) return; if (playbackState == ExoPlayer.STATE_ENDED) { - videoPlayer.seekTo(0); - videoPlayer.play(); + videoPlayerBase.seekTo(0); + videoPlayerBase.play(); } else if (playbackState == ExoPlayer.STATE_IDLE) { - videoPlayer.play(); + videoPlayerBase.play(); } } - @Override - public void onError(VideoPlayer player, Exception e) { - - } - - @Override - public void onVideoSizeChanged(int width, int height, int unappliedRotationDegrees, float pixelWidthHeightRatio) { - - } - @Override public void onRenderedFirstFrame() { - if (!firstFrameRendered) { + if (textureView == null) return; + if (!VideoScreenPreview.this.firstFrameRendered) { textureView.setAlpha(0); textureView.animate().alpha(1f).setListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { - firstFrameRendered = true; + VideoScreenPreview.this.firstFrameRendered = true; invalidate(); } }).setDuration(200); } } - - @Override - public void onSurfaceTextureUpdated(SurfaceTexture surfaceTexture) { - - } - - @Override - public boolean onSurfaceDestroyed(SurfaceTexture surfaceTexture) { - return false; - } - - }); + }; + videoPlayerBase.with(textureView); Uri uri; if (file != null && file.exists()) { @@ -616,25 +600,25 @@ public boolean onSurfaceDestroyed(SurfaceTexture surfaceTexture) { return; } - videoPlayer.preparePlayer(uri, "other"); - videoPlayer.setPlayWhenReady(true); + videoPlayerBase.preparePlayer(uri, false, 1f); if (!firstFrameRendered) { imageReceiver.stopAnimation(); textureView.setAlpha(0); } - videoPlayer.seekTo(lastFrameTime + 60); - videoPlayer.play(); + videoPlayerBase.seekTo(lastFrameTime + 60); + videoPlayerBase.play(); } } long lastFrameTime; private void stopVideoPlayer() { - if (videoPlayer != null) { - lastFrameTime = videoPlayer.getCurrentPosition(); - videoPlayer.setTextureView(null); - videoPlayer.releasePlayer(true); - videoPlayer = null; + if (videoPlayerBase != null) { + lastFrameTime = videoPlayerBase.getCurrentPosition(); + videoPlayerBase.release(() -> { + + }); + videoPlayerBase = null; } } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/BoostDialogs.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/BoostDialogs.java index 3f4f9dab5b8..93be3c61794 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/BoostDialogs.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/BoostDialogs.java @@ -81,7 +81,7 @@ public static void processApplyGiftCodeError(TLRPC.TL_error error, FrameLayout c } if (error.text.contains("PREMIUM_SUB_ACTIVE_UNTIL_")) { String strDate = error.text.replace("PREMIUM_SUB_ACTIVE_UNTIL_", ""); - int date = Integer.parseInt(strDate); + long date = Long.parseLong(strDate); String formattedDate = LocaleController.getInstance().formatterBoostExpired.format(new Date(date * 1000L)); String subTitleText = getString("GiftPremiumActivateErrorText", R.string.GiftPremiumActivateErrorText); SpannableStringBuilder subTitleWithLink = AndroidUtilities.replaceSingleTag( diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/QuoteHighlight.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/QuoteHighlight.java index 32eed942183..3c511f4c7ef 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/QuoteHighlight.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/QuoteHighlight.java @@ -29,7 +29,7 @@ public class QuoteHighlight extends Path { public final int id, start, end; public final Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG); - private final Path path = new Path(); + private final CornerPath path = new CornerPath(); private final AnimatedFloat t; @@ -166,6 +166,7 @@ public void draw(Canvas canvas, float textX, float textY, android.graphics.Rect Path.Direction.CW ); } + path.closeRects(); int wasAlpha = paint.getAlpha(); paint.setAlpha((int) (wasAlpha * alpha)); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/RadialProgress.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/RadialProgress.java index e05e273b814..aecef0518cb 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/RadialProgress.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/RadialProgress.java @@ -11,7 +11,10 @@ import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.ColorFilter; +import android.graphics.Matrix; import android.graphics.Paint; +import android.graphics.Path; +import android.graphics.PathMeasure; import android.graphics.PixelFormat; import android.graphics.RectF; import android.graphics.drawable.Drawable; @@ -69,6 +72,7 @@ public class RadialProgress { private float overrideAlpha = 1.0f; private Paint overridePaint = null; private boolean disableUpdate; + private boolean roundRectProgress; public float getAnimatedProgress() { return animatedProgressValue; @@ -528,7 +532,7 @@ public void draw(Canvas canvas) { finalPaint = progressPaint; } cicleRect.set(progressRect.left + diff, progressRect.top + diff, progressRect.right - diff, progressRect.bottom - diff); - canvas.drawArc(cicleRect, -90 + radOffset, Math.max(4, 360 * animatedProgressValue), false, finalPaint); + drawArc(canvas, cicleRect, -90 + radOffset, Math.max(4, 360 * animatedProgressValue), false, finalPaint); updateAnimation(true); } else { updateAnimation(false); @@ -536,7 +540,51 @@ public void draw(Canvas canvas) { } } + private final Path roundProgressRectPath = new Path(); + private final Matrix roundProgressRectMatrix = new Matrix(); + private final PathMeasure roundProgressRectPathMeasure = new PathMeasure(); + private final Path roundRectProgressPath = new Path(); + + private void drawArc(Canvas canvas, RectF oval, float startAngle, float sweepAngle, boolean useCenter, Paint paint) { + if (roundRectProgress) { + float r = oval.height() * 0.32f; + if (Math.abs(sweepAngle) == 360) { + canvas.drawRoundRect(oval, r, r, paint); + return; + } + float endAngle = startAngle + sweepAngle; + float rotateAngle = (((int) (startAngle)) / 90) * 90 + 90; + + float pathAngleStart = -199 + rotateAngle; + float percentFrom = (startAngle - pathAngleStart) / 360; + float percentTo = (endAngle - pathAngleStart) / 360; + + roundProgressRectPath.rewind(); + roundProgressRectPath.addRoundRect(oval, r, r, Path.Direction.CW); + roundProgressRectMatrix.reset(); + roundProgressRectMatrix.postRotate(rotateAngle, oval.centerX(), oval.centerY()); + roundProgressRectPath.transform(roundProgressRectMatrix); + + roundProgressRectPathMeasure.setPath(roundProgressRectPath, false); + float length = roundProgressRectPathMeasure.getLength(); + + roundRectProgressPath.reset(); + roundProgressRectPathMeasure.getSegment(length * percentFrom, length * percentTo, roundRectProgressPath, true); + roundRectProgressPath.rLineTo(0, 0); + canvas.drawPath(roundRectProgressPath, paint); + if (percentTo > 1) { + drawArc(canvas, oval, startAngle + 90, sweepAngle - 90, useCenter, paint); + } + } else { + canvas.drawArc(oval, startAngle, sweepAngle, useCenter, paint); + } + } + public void setPaint(Paint paint) { overridePaint = paint; } + + public void setRoundRectProgress(boolean roundRectProgress) { + this.roundRectProgress = roundRectProgress; + } } 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 35fa30cce29..5974e32b264 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/RecyclerListView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/RecyclerListView.java @@ -29,6 +29,7 @@ import android.text.SpannableStringBuilder; import android.text.StaticLayout; import android.text.TextPaint; +import android.util.Log; import android.util.SparseIntArray; import android.util.StateSet; import android.view.HapticFeedbackConstants; @@ -137,7 +138,7 @@ public class RecyclerListView extends RecyclerView { protected View selectorView; protected android.graphics.Rect selectorRect = new android.graphics.Rect(); private boolean isChildViewEnabled; - private boolean translateSelector; + private int translateSelector = -1; private boolean selfOnLayout; @@ -1463,6 +1464,9 @@ public void onScrolled(RecyclerView recyclerView, int dx, int dy) { if (dy != 0 && fastScroll != null) { fastScroll.showFloatingDate(); } + if (pendingHighlightPosition != null) { + highlightRowInternal(pendingHighlightPosition, 700, false); + } } }); addOnItemTouchListener(new RecyclerListViewItemClickListener(context)); @@ -1483,9 +1487,10 @@ protected void drawSectionBackground(Canvas canvas, int fromAdapterPosition, int continue; } int position = getChildAdapterPosition(child); + int y = (int) child.getTop(); if (position >= fromAdapterPosition && position <= toAdapterPosition) { - top = Math.min((int) child.getY(), top); - bottom = Math.max((int) child.getY() + child.getHeight(), bottom); + top = Math.min(y, top); + bottom = Math.max((int) (y + child.getHeight() * child.getAlpha()), bottom); } } @@ -2038,7 +2043,7 @@ private void highlightRowInternal(RecyclerListView.IntReturnCallback callback, i } RecyclerView.ViewHolder holder = findViewHolderForAdapterPosition(callback.run()); if (holder != null) { - positionSelector(highlightPosition = holder.getLayoutPosition(), holder.itemView); + positionSelector(highlightPosition = holder.getLayoutPosition(), holder.itemView, false, -1, -1, true); if (selectorDrawable != null) { final Drawable d = selectorDrawable.getCurrent(); if (d instanceof TransitionDrawable) { @@ -2058,6 +2063,7 @@ private void highlightRowInternal(RecyclerListView.IntReturnCallback callback, i } } if (removeAfter > 0) { + pendingHighlightPosition = null; AndroidUtilities.runOnUIThread(removeHighlighSelectionRunnable = () -> { removeHighlighSelectionRunnable = null; pendingHighlightPosition = null; @@ -2122,6 +2128,7 @@ private void checkIfEmpty(boolean animated) { if (!animateEmptyView || !SharedConfig.animationsEnabled()) { animated = false; } + emptyViewUpdated(emptyViewVisible, animated); if (animated) { if (emptyViewAnimateToVisibility != newVisibility) { emptyViewAnimateToVisibility = newVisibility; @@ -2167,6 +2174,10 @@ public void onAnimationEnd(Animator animation) { } } + protected void emptyViewUpdated(boolean shown, boolean animated) { + + } + public boolean emptyViewIsVisible() { if (getAdapter() == null || isFastScrollAnimationRunning()) { return false; @@ -2257,7 +2268,7 @@ public void setPinnedSectionOffsetY(int offset) { } private void positionSelector(int position, View sel) { - positionSelector(position, sel, false, -1, -1); + positionSelector(position, sel, false, -1, -1, false); } public void updateSelector() { @@ -2267,7 +2278,7 @@ public void updateSelector() { } } - private void positionSelector(int position, View sel, boolean manageHotspot, float x, float y) { + private void positionSelector(int position, View sel, boolean manageHotspot, float x, float y, boolean highlight) { if (removeHighlighSelectionRunnable != null) { AndroidUtilities.cancelRunOnUIThread(removeHighlighSelectionRunnable); removeHighlighSelectionRunnable = null; @@ -2519,7 +2530,11 @@ public Rect getSelectorRect() { } public void setTranslateSelector(boolean value) { - translateSelector = value; + translateSelector = value ? -2 : -1; + } + + public void setTranslateSelectorPosition(int position) { + translateSelector = position <= 0 ? -1 : position; } @Override @@ -2529,26 +2544,48 @@ protected void dispatchDraw(Canvas canvas) { } if (drawSelection && drawSelectorBehind && !selectorRect.isEmpty()) { - selectorDrawable.setBounds(selectorRect); + if ((translateSelector == -2 || translateSelector == selectorPosition) && selectorView != null) { + int bottomPadding; + if (getAdapter() instanceof SelectionAdapter) { + bottomPadding = ((SelectionAdapter) getAdapter()).getSelectionBottomPadding(selectorView); + } else { + bottomPadding = 0; + } + selectorDrawable.setBounds(selectorView.getLeft(), selectorView.getTop(), selectorView.getRight(), selectorView.getBottom() - bottomPadding); + } else { + selectorDrawable.setBounds(selectorRect); + } canvas.save(); - if (translateSelector && selectorTransformer != null) { + if ((translateSelector == -2 || translateSelector == selectorPosition) && selectorTransformer != null) { selectorTransformer.accept(canvas); } - if (translateSelector && selectorView != null) { + if ((translateSelector == -2 || translateSelector == selectorPosition) && selectorView != null) { canvas.translate(selectorView.getX() - selectorRect.left, selectorView.getY() - selectorRect.top); + selectorDrawable.setAlpha((int) (0xFF * selectorView.getAlpha())); } selectorDrawable.draw(canvas); canvas.restore(); } super.dispatchDraw(canvas); if (drawSelection && !drawSelectorBehind && !selectorRect.isEmpty()) { - selectorDrawable.setBounds(selectorRect); + if ((translateSelector == -2 || translateSelector == selectorPosition) && selectorView != null) { + int bottomPadding; + if (getAdapter() instanceof SelectionAdapter) { + bottomPadding = ((SelectionAdapter) getAdapter()).getSelectionBottomPadding(selectorView); + } else { + bottomPadding = 0; + } + selectorDrawable.setBounds(selectorView.getLeft(), selectorView.getTop(), selectorView.getRight(), selectorView.getBottom() - bottomPadding); + } else { + selectorDrawable.setBounds(selectorRect); + } canvas.save(); - if (translateSelector && selectorTransformer != null) { + if ((translateSelector == -2 || translateSelector == selectorPosition) && selectorTransformer != null) { selectorTransformer.accept(canvas); } - if (translateSelector && selectorView != null) { + if ((translateSelector == -2 || translateSelector == selectorPosition) && selectorView != null) { canvas.translate(selectorView.getX() - selectorRect.left, selectorView.getY() - selectorRect.top); + selectorDrawable.setAlpha((int) (0xFF * selectorView.getAlpha())); } selectorDrawable.draw(canvas); canvas.restore(); 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 1e257a49bdb..0f6497c6479 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/SharedMediaLayout.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/SharedMediaLayout.java @@ -2,6 +2,7 @@ import static org.telegram.messenger.AndroidUtilities.dp; import static org.telegram.messenger.AndroidUtilities.lerp; +import static org.telegram.messenger.LocaleController.getString; import static org.telegram.messenger.MediaDataController.MEDIA_PHOTOVIDEO; import android.animation.Animator; @@ -138,6 +139,7 @@ import org.telegram.ui.Stories.UserListPoller; import org.telegram.ui.Stories.ViewsForPeerStoriesRequester; import org.telegram.ui.Stories.recorder.ButtonWithCounterView; +import org.telegram.ui.Stories.recorder.StoryRecorder; import org.telegram.ui.TopicsFragment; import java.util.ArrayList; @@ -442,6 +444,7 @@ private static class MediaPage extends FrameLayout { private ClippingImageView animatingImageView; private RecyclerAnimationScrollHelper scrollHelper; private int selectedType; + private ButtonWithCounterView buttonView; public SharedMediaFastScrollTooltip fastScrollHintView; public Runnable fastScrollHideHintRunnable; @@ -1659,12 +1662,12 @@ public void onLayout(int l, int t, int r, int b) { } }); searchItem.setTranslationY(dp(10)); - searchItem.setSearchFieldHint(LocaleController.getString(searchTagsList != null && searchTagsList.hasFilters() && getSelectedTab() == TAB_SAVED_DIALOGS ? R.string.SavedTagSearchHint : R.string.Search)); - searchItem.setContentDescription(LocaleController.getString("Search", R.string.Search)); + searchItem.setSearchFieldHint(getString(searchTagsList != null && searchTagsList.hasFilters() && getSelectedTab() == TAB_SAVED_DIALOGS ? R.string.SavedTagSearchHint : R.string.Search)); + searchItem.setContentDescription(getString("Search", R.string.Search)); searchItem.setVisibility(isStoriesView() ? View.GONE : View.INVISIBLE); photoVideoOptionsItem = new ImageView(context); - photoVideoOptionsItem.setContentDescription(LocaleController.getString("AccDescrMoreOptions", R.string.AccDescrMoreOptions)); + photoVideoOptionsItem.setContentDescription(getString("AccDescrMoreOptions", R.string.AccDescrMoreOptions)); photoVideoOptionsItem.setTranslationY(dp(10)); photoVideoOptionsItem.setVisibility(View.INVISIBLE); @@ -1689,21 +1692,21 @@ public void onLayout(int l, int t, int r, int b) { public void onClick(View view) { if (getSelectedTab() == TAB_SAVED_DIALOGS) { ItemOptions.makeOptions(profileActivity, photoVideoOptionsItem) - .add(R.drawable.msg_discussion, LocaleController.getString(R.string.SavedViewAsMessages), () -> { + .add(R.drawable.msg_discussion, getString(R.string.SavedViewAsMessages), () -> { profileActivity.getMessagesController().setSavedViewAs(false); Bundle args = new Bundle(); args.putLong("user_id", profileActivity.getUserConfig().getClientUserId()); profileActivity.presentFragment(new ChatActivity(args), true); }) .addGap() - .add(R.drawable.msg_home, LocaleController.getString(R.string.AddShortcut), () -> { + .add(R.drawable.msg_home, getString(R.string.AddShortcut), () -> { try { - profileActivity.getMediaDataController().installShortcut(profileActivity.getUserConfig().getClientUserId()); + profileActivity.getMediaDataController().installShortcut(profileActivity.getUserConfig().getClientUserId(), MediaDataController.SHORTCUT_TYPE_USER_OR_CHAT); } catch (Exception e) { FileLog.e(e); } }) - .add(R.drawable.msg_delete, LocaleController.getString(R.string.DeleteAll), () -> { + .add(R.drawable.msg_delete, getString(R.string.DeleteAll), () -> { TLRPC.User currentUser = profileActivity.getUserConfig().getCurrentUser(); AlertsCreator.createClearOrDeleteDialogAlert(profileActivity, false, null, currentUser, false, true, true, (param) -> { profileActivity.finishFragment(); @@ -1742,11 +1745,11 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { mediaZoomInItem = new ActionBarMenuSubItem(context, true, false, resourcesProvider); mediaZoomOutItem = new ActionBarMenuSubItem(context, false, false, resourcesProvider); - mediaZoomInItem.setTextAndIcon(LocaleController.getString("MediaZoomIn", R.string.MediaZoomIn), R.drawable.msg_zoomin); + mediaZoomInItem.setTextAndIcon(getString("MediaZoomIn", R.string.MediaZoomIn), R.drawable.msg_zoomin); mediaZoomInItem.setOnClickListener(view1 -> zoomIn()); popupLayout.addView(mediaZoomInItem); - mediaZoomOutItem.setTextAndIcon(LocaleController.getString("MediaZoomOut", R.string.MediaZoomOut), R.drawable.msg_zoomout); + mediaZoomOutItem.setTextAndIcon(getString("MediaZoomOut", R.string.MediaZoomOut), R.drawable.msg_zoomout); mediaZoomOutItem.setOnClickListener(view1 -> zoomOut()); popupLayout.addView(mediaZoomOutItem); @@ -1766,7 +1769,7 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { boolean hasDifferentTypes = isStories || (sharedMediaData[0].hasPhotos && sharedMediaData[0].hasVideos) || !sharedMediaData[0].endReached[0] || !sharedMediaData[0].endReached[1] || !sharedMediaData[0].startReached; if (!DialogObject.isEncryptedDialog(dialog_id)) { ActionBarMenuSubItem calendarItem = new ActionBarMenuSubItem(context, false, false, resourcesProvider); - calendarItem.setTextAndIcon(LocaleController.getString("Calendar", R.string.Calendar), R.drawable.msg_calendar2); + calendarItem.setTextAndIcon(getString("Calendar", R.string.Calendar), R.drawable.msg_calendar2); popupLayout.addView(calendarItem); calendarItem.setOnClickListener(new OnClickListener() { @Override @@ -1782,7 +1785,7 @@ public void onClick(View view) { TLRPC.Chat chat = MessagesController.getInstance(profileActivity.getCurrentAccount()).getChat(info.id); if (chat != null && chat.admin_rights != null && chat.admin_rights.edit_stories) { ActionBarMenuSubItem openArchiveItem = new ActionBarMenuSubItem(context, false, true, resourcesProvider); - openArchiveItem.setTextAndIcon(LocaleController.getString(R.string.OpenChannelArchiveStories), R.drawable.msg_archive); + openArchiveItem.setTextAndIcon(getString(R.string.OpenChannelArchiveStories), R.drawable.msg_archive); openArchiveItem.setOnClickListener(e -> { Bundle args = new Bundle(); args.putInt("type", MediaActivity.TYPE_ARCHIVED_CHANNEL_STORIES); @@ -1805,10 +1808,10 @@ public void onClick(View view) { ActionBarMenuSubItem showPhotosItem = new ActionBarMenuSubItem(context, true, false, false, resourcesProvider); ActionBarMenuSubItem showVideosItem = new ActionBarMenuSubItem(context, true, false, true, resourcesProvider); - showPhotosItem.setTextAndIcon(LocaleController.getString("MediaShowPhotos", R.string.MediaShowPhotos), 0); + showPhotosItem.setTextAndIcon(getString("MediaShowPhotos", R.string.MediaShowPhotos), 0); popupLayout.addView(showPhotosItem); - showVideosItem.setTextAndIcon(LocaleController.getString("MediaShowVideos", R.string.MediaShowVideos), 0); + showVideosItem.setTextAndIcon(getString("MediaShowVideos", R.string.MediaShowVideos), 0); popupLayout.addView(showVideosItem); if (isStories) { @@ -1915,7 +1918,7 @@ public void onClick(View view) { closeButton.setImageDrawable(backDrawable = new BackDrawable(true)); backDrawable.setColor(getThemedColor(Theme.key_actionBarActionModeDefaultIcon)); closeButton.setBackground(Theme.createSelectorDrawable(getThemedColor(Theme.key_actionBarActionModeDefaultSelector), 1)); - closeButton.setContentDescription(LocaleController.getString("Close", R.string.Close)); + closeButton.setContentDescription(getString("Close", R.string.Close)); actionModeLayout.addView(closeButton, new LinearLayout.LayoutParams(dp(54), ViewGroup.LayoutParams.MATCH_PARENT)); actionModeViews.add(closeButton); closeButton.setOnClickListener(v -> closeActionMode()); @@ -1930,7 +1933,7 @@ public void onClick(View view) { if (!DialogObject.isEncryptedDialog(dialog_id)) { gotoItem = new ActionBarMenuItem(context, null, getThemedColor(Theme.key_actionBarActionModeDefaultSelector), getThemedColor(Theme.key_actionBarActionModeDefaultIcon), false); gotoItem.setIcon(R.drawable.msg_message); - gotoItem.setContentDescription(LocaleController.getString("AccDescrGoToMessage", R.string.AccDescrGoToMessage)); + gotoItem.setContentDescription(getString("AccDescrGoToMessage", R.string.AccDescrGoToMessage)); gotoItem.setDuplicateParentStateEnabled(false); actionModeLayout.addView(gotoItem, new LinearLayout.LayoutParams(dp(54), ViewGroup.LayoutParams.MATCH_PARENT)); actionModeViews.add(gotoItem); @@ -1938,7 +1941,7 @@ public void onClick(View view) { forwardItem = new ActionBarMenuItem(context, null, getThemedColor(Theme.key_actionBarActionModeDefaultSelector), getThemedColor(Theme.key_actionBarActionModeDefaultIcon), false); forwardItem.setIcon(R.drawable.msg_forward); - forwardItem.setContentDescription(LocaleController.getString("Forward", R.string.Forward)); + forwardItem.setContentDescription(getString("Forward", R.string.Forward)); forwardItem.setDuplicateParentStateEnabled(false); actionModeLayout.addView(forwardItem, new LinearLayout.LayoutParams(dp(54), ViewGroup.LayoutParams.MATCH_PARENT)); actionModeViews.add(forwardItem); @@ -1946,7 +1949,7 @@ public void onClick(View view) { pinItem = new ActionBarMenuItem(context, null, getThemedColor(Theme.key_actionBarActionModeDefaultSelector), getThemedColor(Theme.key_actionBarActionModeDefaultIcon), false); pinItem.setIcon(R.drawable.msg_pin); - pinItem.setContentDescription(LocaleController.getString(R.string.PinMessage)); + pinItem.setContentDescription(getString(R.string.PinMessage)); pinItem.setDuplicateParentStateEnabled(false); pinItem.setVisibility(View.GONE); actionModeLayout.addView(pinItem, new LinearLayout.LayoutParams(dp(54), ViewGroup.LayoutParams.MATCH_PARENT)); @@ -1955,7 +1958,7 @@ public void onClick(View view) { unpinItem = new ActionBarMenuItem(context, null, getThemedColor(Theme.key_actionBarActionModeDefaultSelector), getThemedColor(Theme.key_actionBarActionModeDefaultIcon), false); unpinItem.setIcon(R.drawable.msg_unpin); - unpinItem.setContentDescription(LocaleController.getString(R.string.UnpinMessage)); + unpinItem.setContentDescription(getString(R.string.UnpinMessage)); unpinItem.setDuplicateParentStateEnabled(false); unpinItem.setVisibility(View.GONE); actionModeLayout.addView(unpinItem, new LinearLayout.LayoutParams(dp(54), ViewGroup.LayoutParams.MATCH_PARENT)); @@ -1966,7 +1969,7 @@ public void onClick(View view) { } deleteItem = new ActionBarMenuItem(context, null, getThemedColor(Theme.key_actionBarActionModeDefaultSelector), getThemedColor(Theme.key_actionBarActionModeDefaultIcon), false); deleteItem.setIcon(R.drawable.msg_delete); - deleteItem.setContentDescription(LocaleController.getString("Delete", R.string.Delete)); + deleteItem.setContentDescription(getString("Delete", R.string.Delete)); deleteItem.setDuplicateParentStateEnabled(false); actionModeLayout.addView(deleteItem, new LinearLayout.LayoutParams(dp(54), ViewGroup.LayoutParams.MATCH_PARENT)); actionModeViews.add(deleteItem); @@ -2198,6 +2201,14 @@ public int getSpanSize(int position) { mediaPages[a].itemAnimator.setDurations(280); mediaPages[a].itemAnimator.setInterpolator(CubicBezierInterpolator.EASE_OUT_QUINT); mediaPages[a].itemAnimator.setSupportsChangeAnimations(false); + mediaPages[a].buttonView = new ButtonWithCounterView(context, resourcesProvider); + mediaPages[a].buttonView.setText(addPostText(), false); + mediaPages[a].buttonView.setVisibility(View.GONE); + mediaPages[a].buttonView.setOnClickListener(v -> { + if (v.getAlpha() < 0.5f) return; + profileActivity.getMessagesController().getMainSettings().edit().putBoolean("story_keep", true).apply(); + StoryRecorder.getInstance(profileActivity.getParentActivity(), profileActivity.getCurrentAccount()).open(null); + }); mediaPages[a].listView = new InternalListView(context) { final HashSet excludeDrawViews = new HashSet<>(); @@ -2241,40 +2252,47 @@ public boolean dispatchTouchEvent(MotionEvent event) { @Override protected void dispatchDraw(Canvas canvas) { - if (getAdapter() == archivedStoriesAdapter && getChildCount() > 0) { + if ((getAdapter() == archivedStoriesAdapter || getAdapter() == storiesAdapter) && getChildCount() > 0) { View topChild = getChildAt(0); if (topChild != null && getChildAdapterPosition(topChild) == 0) { int top = topChild.getTop(); - if (photoVideoChangeColumnsAnimation && changeColumnsTab == TAB_ARCHIVED_STORIES && mediaPage.animationSupportingListView.getChildCount() > 0) { + if (photoVideoChangeColumnsAnimation && changeColumnsTab == (getAdapter() == storiesAdapter ? TAB_STORIES : TAB_ARCHIVED_STORIES) && mediaPage.animationSupportingListView.getChildCount() > 0) { View supportingTopChild = mediaPage.animationSupportingListView.getChildAt(0); if (supportingTopChild != null && mediaPage.animationSupportingListView.getChildAdapterPosition(supportingTopChild) == 0) { top = lerp(top, supportingTopChild.getTop(), photoVideoChangeColumnsProgress); } } - if (archivedHintPaint == null) { - archivedHintPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG); - archivedHintPaint.setTextSize(dp(14)); - archivedHintPaint.setColor(getThemedColor(Theme.key_windowBackgroundWhiteGrayText2)); - } - int width = getMeasuredWidth() - dp(60); - if (archivedHintLayout == null || archivedHintLayout.getWidth() != width) { - boolean isChannel = profileActivity != null && ChatObject.isChannelAndNotMegaGroup(profileActivity.getMessagesController().getChat(-dialog_id)); - archivedHintLayout = new StaticLayout(LocaleController.getString(isArchivedOnlyStoriesView() ? (isChannel ? R.string.ProfileStoriesArchiveChannelHint : R.string.ProfileStoriesArchiveGroupHint) : R.string.ProfileStoriesArchiveHint), archivedHintPaint, width, Layout.Alignment.ALIGN_CENTER, 1f, 0f, false); - archivedHintLayoutWidth = 0; - archivedHintLayoutLeft = width; - for (int i = 0; i < archivedHintLayout.getLineCount(); ++i) { - archivedHintLayoutWidth = Math.max(archivedHintLayoutWidth, archivedHintLayout.getLineWidth(i)); - archivedHintLayoutLeft = Math.min(archivedHintLayoutLeft, archivedHintLayout.getLineLeft(i)); + if (getAdapter() == storiesAdapter) { + mediaPage.buttonView.setVisibility(View.VISIBLE); + mediaPage.buttonView.setTranslationY(getY() + top - dp(72)); + } else { + if (archivedHintPaint == null) { + archivedHintPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG); + archivedHintPaint.setTextSize(dp(14)); + archivedHintPaint.setColor(getThemedColor(Theme.key_windowBackgroundWhiteGrayText2)); + } + int width = getMeasuredWidth() - dp(60); + if (archivedHintLayout == null || archivedHintLayout.getWidth() != width) { + boolean isChannel = profileActivity != null && ChatObject.isChannelAndNotMegaGroup(profileActivity.getMessagesController().getChat(-dialog_id)); + archivedHintLayout = new StaticLayout(getString(isArchivedOnlyStoriesView() ? (isChannel ? R.string.ProfileStoriesArchiveChannelHint : R.string.ProfileStoriesArchiveGroupHint) : R.string.ProfileStoriesArchiveHint), archivedHintPaint, width, Layout.Alignment.ALIGN_CENTER, 1f, 0f, false); + archivedHintLayoutWidth = 0; + archivedHintLayoutLeft = width; + for (int i = 0; i < archivedHintLayout.getLineCount(); ++i) { + archivedHintLayoutWidth = Math.max(archivedHintLayoutWidth, archivedHintLayout.getLineWidth(i)); + archivedHintLayoutLeft = Math.min(archivedHintLayoutLeft, archivedHintLayout.getLineLeft(i)); + } } - } - canvas.save(); - canvas.translate( - (getWidth() - archivedHintLayoutWidth) / 2f - archivedHintLayoutLeft, - top - (dp(64) + archivedHintLayout.getHeight()) / 2f - ); - archivedHintLayout.draw(canvas); - canvas.restore(); + canvas.save(); + canvas.translate( + (getWidth() - archivedHintLayoutWidth) / 2f - archivedHintLayoutLeft, + top - (dp(64) + archivedHintLayout.getHeight()) / 2f + ); + archivedHintLayout.draw(canvas); + canvas.restore(); + } + } else if (getAdapter() == storiesAdapter) { + mediaPage.buttonView.setTranslationY(-dp(72)); } } SharedPhotoVideoAdapter movingAdapter, supportingMovingAdapter; @@ -2610,8 +2628,18 @@ public void onScrolled(int dx, int dy) { AndroidUtilities.hideKeyboard(profileActivity.getParentActivity().getCurrentFocus()); } } - }; + @Override + protected void emptyViewUpdated(boolean shown, boolean animated) { + if (getAdapter() == storiesAdapter) { + if (animated) { + mediaPage.buttonView.animate().alpha(shown ? 0f : 1f).start(); + } else { + mediaPage.buttonView.setAlpha(shown ? 0f : 1f); + } + } + } + }; mediaPages[a].listView.setFastScrollEnabled(RecyclerListView.FastScroll.DATE_TYPE); mediaPages[a].listView.setScrollingTouchSlop(RecyclerView.TOUCH_SLOP_PAGING); mediaPages[a].listView.setPinnedSectionOffsetY(-dp(2)); @@ -2621,6 +2649,7 @@ public void onScrolled(int dx, int dy) { mediaPages[a].listView.setSectionsType(RecyclerListView.SECTIONS_TYPE_DATE); mediaPages[a].listView.setLayoutManager(layoutManager); mediaPages[a].addView(mediaPages[a].listView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); + mediaPages[a].addView(mediaPages[a].buttonView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 48, Gravity.TOP | Gravity.FILL_HORIZONTAL, 12, 12, 12, 12)); mediaPages[a].animationSupportingListView = new InternalListView(context); mediaPages[a].animationSupportingListView.setLayoutManager(mediaPages[a].animationSupportingLayoutManager = new GridLayoutManager(context, 3) { @@ -2994,8 +3023,10 @@ protected void onDraw(Canvas canvas) { mediaPages[a].addView(mediaPages[a].emptyView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); mediaPages[a].emptyView.setOnTouchListener((v, event) -> true); mediaPages[a].emptyView.showProgress(true, false); - mediaPages[a].emptyView.title.setText(LocaleController.getString("NoResult", R.string.NoResult)); - mediaPages[a].emptyView.subtitle.setText(LocaleController.getString("SearchEmptyViewFilteredSubtitle2", R.string.SearchEmptyViewFilteredSubtitle2)); + mediaPages[a].emptyView.title.setText(getString("NoResult", R.string.NoResult)); + mediaPages[a].emptyView.button.setVisibility(View.GONE); + mediaPages[a].emptyView.subtitle.setText(getString("SearchEmptyViewFilteredSubtitle2", R.string.SearchEmptyViewFilteredSubtitle2)); + mediaPages[a].emptyView.button.setVisibility(View.GONE); mediaPages[a].emptyView.addView(mediaPages[a].progressView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); mediaPages[a].listView.setEmptyView(mediaPages[a].emptyView); @@ -3057,7 +3088,7 @@ public void updateTags(boolean notify) { searchItemIcon.setIcon(hasFilters() && profileActivity.getUserConfig().isPremium() ? R.drawable.navbar_search_tag : R.drawable.ic_ab_search, notify); } if (searchItem != null) { - searchItem.setSearchFieldHint(LocaleController.getString(searchTagsList != null && searchTagsList.hasFilters() && getSelectedTab() == TAB_SAVED_DIALOGS ? R.string.SavedTagSearchHint : R.string.Search)); + searchItem.setSearchFieldHint(getString(searchTagsList != null && searchTagsList.hasFilters() && getSelectedTab() == TAB_SAVED_DIALOGS ? R.string.SavedTagSearchHint : R.string.Search)); } } }; @@ -3323,7 +3354,7 @@ private void startPinchToMediaColumnsCount(boolean pinchScaleUp) { int newColumnsCount = getNextMediaColumnsCount(ci, mediaColumnsCount[ci], pinchScaleUp); animateToColumnsCount = newColumnsCount; - if (animateToColumnsCount == mediaColumnsCount[ci] || allowStoriesSingleColumn) { + if (animateToColumnsCount == mediaColumnsCount[ci] || allowStoriesSingleColumn && (changeColumnsTab == TAB_STORIES || changeColumnsTab == TAB_ARCHIVED_STORIES)) { return; } mediaPage.animationSupportingListView.setVisibility(View.VISIBLE); @@ -3336,10 +3367,11 @@ private void startPinchToMediaColumnsCount(boolean pinchScaleUp) { } mediaPage.animationSupportingListView.setPadding( mediaPage.animationSupportingListView.getPaddingLeft(), - changeColumnsTab == TAB_ARCHIVED_STORIES ? dp(64) : 0, + changeColumnsTab == TAB_ARCHIVED_STORIES ? dp(64) : (changeColumnsTab == TAB_STORIES && isStoriesView() ? dp(72) : 0), mediaPage.animationSupportingListView.getPaddingRight(), mediaPage.animationSupportingListView.getPaddingBottom() ); + mediaPage.buttonView.setVisibility(changeColumnsTab == TAB_STORIES && isStoriesView() ? View.VISIBLE : View.GONE); mediaPage.animationSupportingLayoutManager.setSpanCount(newColumnsCount); mediaPage.animationSupportingListView.invalidateItemDecorations(); @@ -3537,10 +3569,12 @@ private void animateToMediaColumnsCount(int newColumnsCount) { } mediaPage.animationSupportingListView.setPadding( mediaPage.animationSupportingListView.getPaddingLeft(), - (mediaPage.animationSupportingListView.hintPaddingTop = (changeColumnsTab == TAB_ARCHIVED_STORIES ? dp(64) : 0)), + (mediaPage.animationSupportingListView.hintPaddingTop = (changeColumnsTab == TAB_ARCHIVED_STORIES ? dp(64) : (changeColumnsTab == TAB_STORIES && isStoriesView() ? dp(72) : 0))), mediaPage.animationSupportingListView.getPaddingRight(), mediaPage.animationSupportingListView.getPaddingBottom() ); + mediaPage.buttonView.setVisibility(changeColumnsTab == TAB_STORIES ? View.VISIBLE : View.GONE); + mediaPage.buttonView.setVisibility(changeColumnsTab == TAB_STORIES ? View.VISIBLE : View.GONE); mediaPage.animationSupportingLayoutManager.setSpanCount(newColumnsCount); mediaPage.animationSupportingListView.invalidateItemDecorations(); for (int i = 0; i < mediaPages.length; ++i) { @@ -4021,7 +4055,7 @@ protected void onSelectedTabChanged() { storiesAdapter.poller.start(pollerEnabled && getClosestTab() == TAB_STORIES); } if (searchItem != null) { - searchItem.setSearchFieldHint(LocaleController.getString(searchTagsList != null && searchTagsList.hasFilters() && getSelectedTab() == TAB_SAVED_DIALOGS ? R.string.SavedTagSearchHint : R.string.Search)); + searchItem.setSearchFieldHint(getString(searchTagsList != null && searchTagsList.hasFilters() && getSelectedTab() == TAB_SAVED_DIALOGS ? R.string.SavedTagSearchHint : R.string.Search)); } } @@ -4234,7 +4268,7 @@ public void onActionBarItemClick(View v, int id) { TLRPC.User user = profileActivity.getMessagesController().getUser(did); if (user != null) { if (UserObject.isAnonymous(user)) { - firstDialog = LocaleController.getString(R.string.AnonymousForward); + firstDialog = getString(R.string.AnonymousForward); } else { firstDialog = UserObject.getUserName(user); } @@ -4244,14 +4278,14 @@ public void onActionBarItemClick(View v, int id) { AlertDialog dialog = new AlertDialog.Builder(getContext(), resourcesProvider) .setTitle(selectedDialogs.size() == 1 ? LocaleController.formatString(firstDialogSelf ? R.string.ClearHistoryMyNotesTitle : R.string.ClearHistoryTitleSingle2, firstDialog) : LocaleController.formatPluralString("ClearHistoryTitleMultiple", selectedDialogs.size())) .setMessage(selectedDialogs.size() == 1 ? LocaleController.formatString(firstDialogSelf ? R.string.ClearHistoryMyNotesMessage : R.string.ClearHistoryMessageSingle, firstDialog) : LocaleController.formatPluralString("ClearHistoryMessageMultiple", selectedDialogs.size())) - .setPositiveButton(LocaleController.getString(R.string.Remove), (di, w) -> { + .setPositiveButton(getString(R.string.Remove), (di, w) -> { for (int i = 0; i < selectedDialogs.size(); ++i) { final long did = selectedDialogs.get(i); profileActivity.getMessagesController().deleteSavedDialog(did); } closeActionMode(); }) - .setNegativeButton(LocaleController.getString(R.string.Cancel), null) + .setNegativeButton(getString(R.string.Cancel), null) .create(); profileActivity.showDialog(dialog); TextView button = (TextView) dialog.getButton(DialogInterface.BUTTON_POSITIVE); @@ -4270,7 +4304,7 @@ public void onActionBarItemClick(View v, int id) { } else { currentChat = profileActivity.getMessagesController().getChat(-dialog_id); } - AlertsCreator.createDeleteMessagesAlert(profileActivity, currentUser, currentChat, currentEncryptedChat, null, mergeDialogId, null, selectedFiles, null, false, false, 1, () -> { + AlertsCreator.createDeleteMessagesAlert(profileActivity, currentUser, currentChat, currentEncryptedChat, null, mergeDialogId, null, selectedFiles, null, 0, 0, 1, () -> { showActionMode(false); actionBar.closeSearchField(); cantDeleteMessagesCount = 0; @@ -4280,8 +4314,8 @@ public void onActionBarItemClick(View v, int id) { TLRPC.Chat chat = profileActivity.getMessagesController().getChat(info.id); if (profileActivity.getMessagesController().isChatNoForwards(chat)) { if (fwdRestrictedHint != null) { - fwdRestrictedHint.setText(ChatObject.isChannel(chat) && !chat.megagroup ? LocaleController.getString("ForwardsRestrictedInfoChannel", R.string.ForwardsRestrictedInfoChannel) : - LocaleController.getString("ForwardsRestrictedInfoGroup", R.string.ForwardsRestrictedInfoGroup)); + fwdRestrictedHint.setText(ChatObject.isChannel(chat) && !chat.megagroup ? getString("ForwardsRestrictedInfoChannel", R.string.ForwardsRestrictedInfoChannel) : + getString("ForwardsRestrictedInfoGroup", R.string.ForwardsRestrictedInfoGroup)); fwdRestrictedHint.showForView(v, true); } return; @@ -4289,7 +4323,7 @@ public void onActionBarItemClick(View v, int id) { } if (hasNoforwardsMessage()) { if (fwdRestrictedHint != null) { - fwdRestrictedHint.setText(LocaleController.getString("ForwardsRestrictedInfoBot", R.string.ForwardsRestrictedInfoBot)); + fwdRestrictedHint.setText(getString("ForwardsRestrictedInfoBot", R.string.ForwardsRestrictedInfoBot)); fwdRestrictedHint.showForView(v, true); } return; @@ -5605,16 +5639,16 @@ public Animator onDisappear(ViewGroup sceneRoot, View view, TransitionValues sta if ((DialogObject.isUserDialog(dialog_id) || DialogObject.isChatDialog(dialog_id)) && !DialogObject.isEncryptedDialog(dialog_id) && (userInfo != null && userInfo.stories_pinned_available || info != null && info.stories_pinned_available || isStoriesView()) && includeStories()) { if (isArchivedOnlyStoriesView()) { if (!scrollSlidingTextTabStrip.hasTab(TAB_ARCHIVED_STORIES)) { - scrollSlidingTextTabStrip.addTextTab(TAB_ARCHIVED_STORIES, LocaleController.getString("ProfileStories", R.string.ProfileStories), idToView); + scrollSlidingTextTabStrip.addTextTab(TAB_ARCHIVED_STORIES, getString("ProfileStories", R.string.ProfileStories), idToView); } scrollSlidingTextTabStrip.animationDuration = 420; } else { if (!scrollSlidingTextTabStrip.hasTab(TAB_STORIES)) { - scrollSlidingTextTabStrip.addTextTab(TAB_STORIES, LocaleController.getString("ProfileStories", R.string.ProfileStories), idToView); + scrollSlidingTextTabStrip.addTextTab(TAB_STORIES, getString("ProfileStories", R.string.ProfileStories), idToView); } if (isStoriesView()) { if (!scrollSlidingTextTabStrip.hasTab(TAB_ARCHIVED_STORIES)) { - scrollSlidingTextTabStrip.addTextTab(TAB_ARCHIVED_STORIES, LocaleController.getString("ProfileStories", R.string.ProfileStories), idToView); + scrollSlidingTextTabStrip.addTextTab(TAB_ARCHIVED_STORIES, getString("ProfileStories", R.string.ProfileStories), idToView); } scrollSlidingTextTabStrip.animationDuration = 420; } @@ -5623,70 +5657,70 @@ public Animator onDisappear(ViewGroup sceneRoot, View view, TransitionValues sta if (!isStoriesView()) { if (hasSavedDialogs) { if (!scrollSlidingTextTabStrip.hasTab(TAB_SAVED_DIALOGS)) { - scrollSlidingTextTabStrip.addTextTab(TAB_SAVED_DIALOGS, LocaleController.getString(R.string.SavedDialogsTab), idToView); + scrollSlidingTextTabStrip.addTextTab(TAB_SAVED_DIALOGS, getString(R.string.SavedDialogsTab), idToView); } } if (chatUsersAdapter.chatInfo != null) { if (!scrollSlidingTextTabStrip.hasTab(TAB_GROUPUSERS)) { - scrollSlidingTextTabStrip.addTextTab(TAB_GROUPUSERS, LocaleController.getString("GroupMembers", R.string.GroupMembers), idToView); + scrollSlidingTextTabStrip.addTextTab(TAB_GROUPUSERS, getString("GroupMembers", R.string.GroupMembers), idToView); } } if (hasMedia[0] > 0) { if (!scrollSlidingTextTabStrip.hasTab(TAB_PHOTOVIDEO)) { if (hasMedia[1] == 0 && hasMedia[2] == 0 && hasMedia[3] == 0 && hasMedia[4] == 0 && hasMedia[5] == 0 && hasMedia[6] == 0 && chatUsersAdapter.chatInfo == null) { - scrollSlidingTextTabStrip.addTextTab(TAB_PHOTOVIDEO, LocaleController.getString("SharedMediaTabFull2", R.string.SharedMediaTabFull2), idToView); + scrollSlidingTextTabStrip.addTextTab(TAB_PHOTOVIDEO, getString("SharedMediaTabFull2", R.string.SharedMediaTabFull2), idToView); } else { - scrollSlidingTextTabStrip.addTextTab(TAB_PHOTOVIDEO, LocaleController.getString("SharedMediaTab2", R.string.SharedMediaTab2), idToView); + scrollSlidingTextTabStrip.addTextTab(TAB_PHOTOVIDEO, getString("SharedMediaTab2", R.string.SharedMediaTab2), idToView); } } } if (hasSavedMessages) { if (!scrollSlidingTextTabStrip.hasTab(TAB_SAVED_MESSAGES)) { - scrollSlidingTextTabStrip.addTextTab(TAB_SAVED_MESSAGES, LocaleController.getString(R.string.SavedMessagesTab2), idToView); + scrollSlidingTextTabStrip.addTextTab(TAB_SAVED_MESSAGES, getString(R.string.SavedMessagesTab2), idToView); } MessagesController.getGlobalMainSettings().edit().putInt("savedhint", 3).apply(); } if (hasMedia[1] > 0) { if (!scrollSlidingTextTabStrip.hasTab(TAB_FILES)) { - scrollSlidingTextTabStrip.addTextTab(TAB_FILES, LocaleController.getString("SharedFilesTab2", R.string.SharedFilesTab2), idToView); + scrollSlidingTextTabStrip.addTextTab(TAB_FILES, getString("SharedFilesTab2", R.string.SharedFilesTab2), idToView); } } if (!DialogObject.isEncryptedDialog(dialog_id)) { if (hasMedia[3] > 0) { if (!scrollSlidingTextTabStrip.hasTab(TAB_LINKS)) { - scrollSlidingTextTabStrip.addTextTab(TAB_LINKS, LocaleController.getString("SharedLinksTab2", R.string.SharedLinksTab2), idToView); + scrollSlidingTextTabStrip.addTextTab(TAB_LINKS, getString("SharedLinksTab2", R.string.SharedLinksTab2), idToView); } } if (hasMedia[4] > 0) { if (!scrollSlidingTextTabStrip.hasTab(TAB_AUDIO)) { - scrollSlidingTextTabStrip.addTextTab(TAB_AUDIO, LocaleController.getString("SharedMusicTab2", R.string.SharedMusicTab2), idToView); + scrollSlidingTextTabStrip.addTextTab(TAB_AUDIO, getString("SharedMusicTab2", R.string.SharedMusicTab2), idToView); } } } else { if (hasMedia[4] > 0) { if (!scrollSlidingTextTabStrip.hasTab(TAB_AUDIO)) { - scrollSlidingTextTabStrip.addTextTab(TAB_AUDIO, LocaleController.getString("SharedMusicTab2", R.string.SharedMusicTab2), idToView); + scrollSlidingTextTabStrip.addTextTab(TAB_AUDIO, getString("SharedMusicTab2", R.string.SharedMusicTab2), idToView); } } } if (hasMedia[2] > 0) { if (!scrollSlidingTextTabStrip.hasTab(TAB_VOICE)) { - scrollSlidingTextTabStrip.addTextTab(TAB_VOICE, LocaleController.getString("SharedVoiceTab2", R.string.SharedVoiceTab2), idToView); + scrollSlidingTextTabStrip.addTextTab(TAB_VOICE, getString("SharedVoiceTab2", R.string.SharedVoiceTab2), idToView); } } if (hasMedia[5] > 0) { if (!scrollSlidingTextTabStrip.hasTab(TAB_GIF)) { - scrollSlidingTextTabStrip.addTextTab(TAB_GIF, LocaleController.getString("SharedGIFsTab2", R.string.SharedGIFsTab2), idToView); + scrollSlidingTextTabStrip.addTextTab(TAB_GIF, getString("SharedGIFsTab2", R.string.SharedGIFsTab2), idToView); } } if (hasMedia[6] > 0) { if (!scrollSlidingTextTabStrip.hasTab(TAB_COMMON_GROUPS)) { - scrollSlidingTextTabStrip.addTextTab(TAB_COMMON_GROUPS, LocaleController.getString("SharedGroupsTab2", R.string.SharedGroupsTab2), idToView); + scrollSlidingTextTabStrip.addTextTab(TAB_COMMON_GROUPS, getString("SharedGroupsTab2", R.string.SharedGroupsTab2), idToView); } } if (hasRecommendations) { if (!scrollSlidingTextTabStrip.hasTab(TAB_RECOMMENDED_CHANNELS)) { - scrollSlidingTextTabStrip.addTextTab(TAB_RECOMMENDED_CHANNELS, LocaleController.getString(R.string.SimilarChannelsTab), idToView); + scrollSlidingTextTabStrip.addTextTab(TAB_RECOMMENDED_CHANNELS, getString(R.string.SimilarChannelsTab), idToView); } } } @@ -5831,10 +5865,11 @@ private void switchToCurrentSelectedMode(boolean animated) { mediaPages[a].listView.setPinnedHeaderShadowDrawable(null); mediaPages[a].listView.setPadding( mediaPages[a].listView.getPaddingLeft(), - (mediaPages[a].listView.hintPaddingTop = mediaPages[a].selectedType == TAB_ARCHIVED_STORIES ? dp(64) : 0), + (mediaPages[a].listView.hintPaddingTop = mediaPages[a].selectedType == TAB_ARCHIVED_STORIES ? dp(64) : (mediaPages[a].selectedType == TAB_STORIES && isStoriesView() ? dp(72) : 0)), mediaPages[a].listView.getPaddingRight(), mediaPages[a].listView.getPaddingBottom() ); + mediaPages[a].buttonView.setVisibility(mediaPages[a].selectedType == TAB_STORIES && isStoriesView() ? View.VISIBLE : View.GONE); if (mediaPages[a].selectedType == TAB_PHOTOVIDEO) { if (currentAdapter != photoVideoAdapter) { @@ -6016,16 +6051,29 @@ private void switchToCurrentSelectedMode(boolean animated) { } if (mediaPages[a].selectedType == TAB_STORIES) { mediaPages[a].emptyView.setStickerType(StickerEmptyView.STICKER_TYPE_ALBUM); - mediaPages[a].emptyView.title.setText(isStoriesView() ? LocaleController.getString(R.string.NoPublicStoriesTitle) : LocaleController.getString(R.string.NoStoriesTitle)); - mediaPages[a].emptyView.subtitle.setText(isStoriesView() ? LocaleController.getString("NoStoriesSubtitle") : ""); + mediaPages[a].emptyView.title.setText(isStoriesView() ? getString(R.string.NoPublicStoriesTitle2) : getString(R.string.NoStoriesTitle)); + mediaPages[a].emptyView.subtitle.setText(isStoriesView() ? getString(R.string.NoStoriesSubtitle2) : ""); + mediaPages[a].emptyView.button.setVisibility(View.VISIBLE); + mediaPages[a].emptyView.button.setText(addPostText(), false); + mediaPages[a].emptyView.button.setOnClickListener(v -> { + profileActivity.getMessagesController().getMainSettings().edit().putBoolean("story_keep", true).apply(); + StoryRecorder.getInstance(profileActivity.getParentActivity(), profileActivity.getCurrentAccount()).open(null); + }); } else if (mediaPages[a].selectedType == TAB_ARCHIVED_STORIES) { mediaPages[a].emptyView.setStickerType(StickerEmptyView.STICKER_TYPE_ALBUM); - mediaPages[a].emptyView.title.setText(LocaleController.getString("NoArchivedStoriesTitle")); - mediaPages[a].emptyView.subtitle.setText(isStoriesView() ? LocaleController.getString("NoArchivedStoriesSubtitle") : ""); + mediaPages[a].emptyView.title.setText(getString(R.string.NoArchivedStoriesTitle)); + mediaPages[a].emptyView.subtitle.setText(isStoriesView() ? getString(R.string.NoArchivedStoriesSubtitle) : ""); + mediaPages[a].emptyView.button.setVisibility(View.VISIBLE); + mediaPages[a].emptyView.button.setText(addPostText(), false); + mediaPages[a].emptyView.button.setOnClickListener(v -> { + profileActivity.getMessagesController().getMainSettings().edit().putBoolean("story_keep", true).apply(); + StoryRecorder.getInstance(profileActivity.getParentActivity(), profileActivity.getCurrentAccount()).open(null); + }); } else { mediaPages[a].emptyView.setStickerType(StickerEmptyView.STICKER_TYPE_SEARCH); - mediaPages[a].emptyView.title.setText(LocaleController.getString("NoResult", R.string.NoResult)); - mediaPages[a].emptyView.subtitle.setText(LocaleController.getString("SearchEmptyViewFilteredSubtitle2", R.string.SearchEmptyViewFilteredSubtitle2)); + mediaPages[a].emptyView.title.setText(getString("NoResult", R.string.NoResult)); + mediaPages[a].emptyView.subtitle.setText(getString("SearchEmptyViewFilteredSubtitle2", R.string.SearchEmptyViewFilteredSubtitle2)); + mediaPages[a].emptyView.button.setVisibility(View.GONE); } mediaPages[a].listView.setVisibility(View.VISIBLE); } @@ -6292,7 +6340,7 @@ public void onLinkPress(String urlFinal, boolean longPress) { if (longPress) { BottomSheet.Builder builder = new BottomSheet.Builder(profileActivity.getParentActivity()); builder.setTitle(urlFinal); - builder.setItems(new CharSequence[]{LocaleController.getString("Open", R.string.Open), LocaleController.getString("Copy", R.string.Copy)}, (dialog, which) -> { + builder.setItems(new CharSequence[]{getString("Open", R.string.Open), getString("Copy", R.string.Copy)}, (dialog, which) -> { if (which == 0) { openUrl(urlFinal); } else if (which == 1) { @@ -6674,43 +6722,43 @@ public static View createEmptyStubView(Context context, int currentType, long di EmptyStubView emptyStubView = new EmptyStubView(context, resourcesProvider); if (currentType == 0) { if (DialogObject.isEncryptedDialog(dialog_id)) { - emptyStubView.emptyTextView.setText(LocaleController.getString("NoMediaSecret", R.string.NoMediaSecret)); + emptyStubView.emptyTextView.setText(getString("NoMediaSecret", R.string.NoMediaSecret)); } else { - emptyStubView.emptyTextView.setText(LocaleController.getString("NoMedia", R.string.NoMedia)); + emptyStubView.emptyTextView.setText(getString("NoMedia", R.string.NoMedia)); } } else if (currentType == 1) { if (DialogObject.isEncryptedDialog(dialog_id)) { - emptyStubView.emptyTextView.setText(LocaleController.getString("NoSharedFilesSecret", R.string.NoSharedFilesSecret)); + emptyStubView.emptyTextView.setText(getString("NoSharedFilesSecret", R.string.NoSharedFilesSecret)); } else { - emptyStubView.emptyTextView.setText(LocaleController.getString("NoSharedFiles", R.string.NoSharedFiles)); + emptyStubView.emptyTextView.setText(getString("NoSharedFiles", R.string.NoSharedFiles)); } } else if (currentType == 2) { if (DialogObject.isEncryptedDialog(dialog_id)) { - emptyStubView.emptyTextView.setText(LocaleController.getString("NoSharedVoiceSecret", R.string.NoSharedVoiceSecret)); + emptyStubView.emptyTextView.setText(getString("NoSharedVoiceSecret", R.string.NoSharedVoiceSecret)); } else { - emptyStubView.emptyTextView.setText(LocaleController.getString("NoSharedVoice", R.string.NoSharedVoice)); + emptyStubView.emptyTextView.setText(getString("NoSharedVoice", R.string.NoSharedVoice)); } } else if (currentType == 3) { if (DialogObject.isEncryptedDialog(dialog_id)) { - emptyStubView.emptyTextView.setText(LocaleController.getString("NoSharedLinksSecret", R.string.NoSharedLinksSecret)); + emptyStubView.emptyTextView.setText(getString("NoSharedLinksSecret", R.string.NoSharedLinksSecret)); } else { - emptyStubView.emptyTextView.setText(LocaleController.getString("NoSharedLinks", R.string.NoSharedLinks)); + emptyStubView.emptyTextView.setText(getString("NoSharedLinks", R.string.NoSharedLinks)); } } else if (currentType == 4) { if (DialogObject.isEncryptedDialog(dialog_id)) { - emptyStubView.emptyTextView.setText(LocaleController.getString("NoSharedAudioSecret", R.string.NoSharedAudioSecret)); + emptyStubView.emptyTextView.setText(getString("NoSharedAudioSecret", R.string.NoSharedAudioSecret)); } else { - emptyStubView.emptyTextView.setText(LocaleController.getString("NoSharedAudio", R.string.NoSharedAudio)); + emptyStubView.emptyTextView.setText(getString("NoSharedAudio", R.string.NoSharedAudio)); } } else if (currentType == 5) { if (DialogObject.isEncryptedDialog(dialog_id)) { - emptyStubView.emptyTextView.setText(LocaleController.getString("NoSharedGifSecret", R.string.NoSharedGifSecret)); + emptyStubView.emptyTextView.setText(getString("NoSharedGifSecret", R.string.NoSharedGifSecret)); } else { - emptyStubView.emptyTextView.setText(LocaleController.getString("NoGIFs", R.string.NoGIFs)); + emptyStubView.emptyTextView.setText(getString("NoGIFs", R.string.NoGIFs)); } } else if (currentType == 6) { emptyStubView.emptyImageView.setImageDrawable(null); - emptyStubView.emptyTextView.setText(LocaleController.getString("NoGroupsInCommon", R.string.NoGroupsInCommon)); + emptyStubView.emptyTextView.setText(getString("NoGroupsInCommon", R.string.NoGroupsInCommon)); } else if (currentType == 7) { emptyStubView.emptyImageView.setImageDrawable(null); emptyStubView.emptyTextView.setText(""); @@ -7182,6 +7230,7 @@ public void queryServerSearch(final String query, final int max_id, long did, lo if (mediaPages[a].selectedType == currentType) { if (searchesInProgress == 0 && count == 0) { mediaPages[a].emptyView.title.setText(LocaleController.formatString("NoResultFoundFor", R.string.NoResultFoundFor, query)); + mediaPages[a].emptyView.button.setVisibility(View.GONE); mediaPages[a].emptyView.showProgress(false, true); } else if (oldItemCounts == 0) { animateItemsEnter(mediaPages[a].listView, 0, null); @@ -7320,7 +7369,8 @@ private void updateSearchResults(final ArrayList documents) { for (int a = 0; a < mediaPages.length; a++) { if (mediaPages[a].selectedType == currentType) { if (searchesInProgress == 0 && count == 0) { - mediaPages[a].emptyView.title.setText(LocaleController.getString("NoResult", R.string.NoResult)); + mediaPages[a].emptyView.title.setText(getString("NoResult", R.string.NoResult)); + mediaPages[a].emptyView.button.setVisibility(View.GONE); mediaPages[a].emptyView.showProgress(false, true); } else if (oldItemCount == 0) { animateItemsEnter(mediaPages[a].listView, 0, null); @@ -7913,7 +7963,8 @@ private void updateMessages(boolean fromCache) { for (int a = 0; a < mediaPages.length; a++) { if (mediaPages[a].selectedType == TAB_SAVED_DIALOGS) { if (messages.isEmpty() && dialogs.isEmpty()) { - mediaPages[a].emptyView.title.setText(lastReaction != null && TextUtils.isEmpty(lastQuery) ? AndroidUtilities.replaceCharSequence("%s", LocaleController.getString(R.string.NoResultFoundForTag), lastReaction.toCharSequence(mediaPages[a].emptyView.title.getPaint().getFontMetricsInt())) : LocaleController.formatString(R.string.NoResultFoundFor, lastQuery)); + mediaPages[a].emptyView.title.setText(lastReaction != null && TextUtils.isEmpty(lastQuery) ? AndroidUtilities.replaceCharSequence("%s", getString(R.string.NoResultFoundForTag), lastReaction.toCharSequence(mediaPages[a].emptyView.title.getPaint().getFontMetricsInt())) : LocaleController.formatString(R.string.NoResultFoundFor, lastQuery)); + mediaPages[a].emptyView.button.setVisibility(View.GONE); mediaPages[a].emptyView.showProgress(false, true); } } @@ -8062,7 +8113,7 @@ public void openPreview(int position) { previewMenu.setBackgroundColor(getThemedColor(Theme.key_actionBarDefaultSubmenuBackground)); ActionBarMenuSubItem openChannel = new ActionBarMenuSubItem(getContext(), false, false); - openChannel.setTextAndIcon(LocaleController.getString(R.string.OpenChannel2), R.drawable.msg_channel); + openChannel.setTextAndIcon(getString(R.string.OpenChannel2), R.drawable.msg_channel); openChannel.setMinimumWidth(160); openChannel.setOnClickListener(view -> { if (profileActivity != null && profileActivity.getParentLayout() != null) { @@ -8072,7 +8123,7 @@ public void openPreview(int position) { previewMenu.addView(openChannel); ActionBarMenuSubItem joinChannel = new ActionBarMenuSubItem(getContext(), false, false); - joinChannel.setTextAndIcon(LocaleController.getString(R.string.ProfileJoinChannel), R.drawable.msg_addbot); + joinChannel.setTextAndIcon(getString(R.string.ProfileJoinChannel), R.drawable.msg_addbot); joinChannel.setMinimumWidth(160); joinChannel.setOnClickListener(view -> { profileActivity.finishPreviewFragment(); @@ -8149,7 +8200,7 @@ public MoreRecommendationsCell(int currentAccount, Context context, Theme.Resour button = new ButtonWithCounterView(context, resourcesProvider); SpannableStringBuilder buttonText = new SpannableStringBuilder(); - buttonText.append(LocaleController.getString(R.string.MoreSimilarButton)); + buttonText.append(getString(R.string.MoreSimilarButton)); buttonText.append(" "); SpannableString lock = new SpannableString("l"); lock.setSpan(new ColoredImageSpan(R.drawable.msg_mini_lock2), 0, 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); @@ -8169,7 +8220,7 @@ public MoreRecommendationsCell(int currentAccount, Context context, Theme.Resour textView.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlackText, resourcesProvider)); textView.setLinkTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlueText, resourcesProvider)); textView.setLineSpacing(dp(3), 1f); - SpannableStringBuilder text = AndroidUtilities.premiumText(LocaleController.getString(R.string.MoreSimilarText), () -> { + SpannableStringBuilder text = AndroidUtilities.premiumText(getString(R.string.MoreSimilarText), () -> { if (onPremiumClick != null) { onPremiumClick.run(); } @@ -8599,18 +8650,18 @@ public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { role = channelParticipant.rank; } else { if (channelParticipant instanceof TLRPC.TL_channelParticipantCreator) { - role = LocaleController.getString("ChannelCreator", R.string.ChannelCreator); + role = getString("ChannelCreator", R.string.ChannelCreator); } else if (channelParticipant instanceof TLRPC.TL_channelParticipantAdmin) { - role = LocaleController.getString("ChannelAdmin", R.string.ChannelAdmin); + role = getString("ChannelAdmin", R.string.ChannelAdmin); } else { role = null; } } } else { if (part instanceof TLRPC.TL_chatParticipantCreator) { - role = LocaleController.getString("ChannelCreator", R.string.ChannelCreator); + role = getString("ChannelCreator", R.string.ChannelCreator); } else if (part instanceof TLRPC.TL_chatParticipantAdmin) { - role = LocaleController.getString("ChannelAdmin", R.string.ChannelAdmin); + role = getString("ChannelAdmin", R.string.ChannelAdmin); } else { role = null; } @@ -9076,7 +9127,7 @@ public Boolean zoomIn() { } public Boolean zoomOut() { - if (photoVideoChangeColumnsAnimation || mediaPages[0] == null || allowStoriesSingleColumn) { + if (photoVideoChangeColumnsAnimation || mediaPages[0] == null || allowStoriesSingleColumn && (mediaPages[0].selectedType == TAB_STORIES || mediaPages[0].selectedType == TAB_ARCHIVED_STORIES)) { return null; } changeColumnsTab = mediaPages[0].selectedType; @@ -9110,7 +9161,7 @@ public boolean canZoomIn() { } public boolean canZoomOut() { - if (mediaPages == null || mediaPages[0] == null || allowStoriesSingleColumn) { + if (mediaPages == null || mediaPages[0] == null || allowStoriesSingleColumn && (mediaPages[0].selectedType == TAB_STORIES || mediaPages[0].selectedType == TAB_ARCHIVED_STORIES)) { return false; } final int ci = mediaPages[0].selectedType == TAB_STORIES || mediaPages[0].selectedType == TAB_ARCHIVED_STORIES ? 1 : 0; @@ -9239,4 +9290,14 @@ public void animateSearchToOptions(boolean toOptions, boolean animated) { } } } + + private SpannableStringBuilder addPostButton; + private CharSequence addPostText() { + if (addPostButton == null) { + addPostButton = new SpannableStringBuilder("c"); + addPostButton.setSpan(new ColoredImageSpan(R.drawable.filled_premium_camera), 0, 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + addPostButton.append(" ").append(getString(R.string.StoriesAddPost)); + } + return addPostButton; + } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/StickerEmptyView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/StickerEmptyView.java index 481078ecdc0..5d1edc267ee 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/StickerEmptyView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/StickerEmptyView.java @@ -32,6 +32,7 @@ import org.telegram.ui.ActionBar.Theme; import org.telegram.ui.Components.spoilers.SpoilersTextView; import org.telegram.ui.LaunchActivity; +import org.telegram.ui.Stories.recorder.ButtonWithCounterView; public class StickerEmptyView extends FrameLayout implements NotificationCenter.NotificationCenterDelegate { @@ -46,6 +47,7 @@ public class StickerEmptyView extends FrameLayout implements NotificationCenter. private RadialProgressView progressBar; public final SpoilersTextView title; public final LinkSpanDrawable.LinksTextView subtitle; + public final ButtonWithCounterView button; private boolean progressShowing; private final Theme.ResourcesProvider resourcesProvider; @@ -119,9 +121,13 @@ public void setVisibility(int visibility) { subtitle.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); subtitle.setGravity(Gravity.CENTER); + button = new ButtonWithCounterView(context, resourcesProvider); + button.setVisibility(View.GONE); + linearLayout.addView(stickerView, LayoutHelper.createLinear(117, 117, Gravity.CENTER_HORIZONTAL)); linearLayout.addView(title, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_HORIZONTAL, 0, 12, 0, 0)); linearLayout.addView(subtitle, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_HORIZONTAL, 0, 8, 0, 0)); + linearLayout.addView(button, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 48, Gravity.CENTER_HORIZONTAL, 28, 16, 28, 0)); addView(linearLayout, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER, 46, 0, 46, 30)); if (progressView == null) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/StickerSetBulletinLayout.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/StickerSetBulletinLayout.java index 44fbdfea126..5d942e9cddb 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/StickerSetBulletinLayout.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/StickerSetBulletinLayout.java @@ -204,7 +204,8 @@ public StickerSetBulletinLayout(@NonNull Context context, TLObject setObject, in } break; case TYPE_REPLACED_TO_FAVORITES_GIFS: - if (!MessagesController.getInstance(UserConfig.selectedAccount).premiumFeaturesBlocked()) { + final boolean isPremium = UserConfig.getInstance(UserConfig.selectedAccount).isPremium(); + if (!MessagesController.getInstance(UserConfig.selectedAccount).premiumFeaturesBlocked() || !isPremium) { titleTextView.setText(LocaleController.formatString("LimitReachedFavoriteGifs", R.string.LimitReachedFavoriteGifs, MessagesController.getInstance(UserConfig.selectedAccount).savedGifsLimitDefault)); CharSequence str = AndroidUtilities.premiumText(LocaleController.formatString("LimitReachedFavoriteGifsSubtitle", R.string.LimitReachedFavoriteGifsSubtitle, MessagesController.getInstance(UserConfig.selectedAccount).savedGifsLimitPremium), () -> { Activity activity = AndroidUtilities.findActivity(context); @@ -214,7 +215,7 @@ public StickerSetBulletinLayout(@NonNull Context context, TLObject setObject, in }); subtitleTextView.setText(str); } else { - titleTextView.setText(LocaleController.formatString("LimitReachedFavoriteGifs", R.string.LimitReachedFavoriteGifs, MessagesController.getInstance(UserConfig.selectedAccount).savedGifsLimitPremium)); + titleTextView.setText(LocaleController.formatString("LimitReachedFavoriteGifs", R.string.LimitReachedFavoriteGifs, isPremium ? MessagesController.getInstance(UserConfig.selectedAccount).savedGifsLimitPremium : MessagesController.getInstance(UserConfig.selectedAccount).savedGifsLimitDefault)); subtitleTextView.setText(LocaleController.formatString("LimitReachedFavoriteGifsSubtitlePremium", R.string.LimitReachedFavoriteGifsSubtitlePremium)); } break; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/TopViewCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/TopViewCell.java new file mode 100644 index 00000000000..baef2917b41 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/TopViewCell.java @@ -0,0 +1,84 @@ +package org.telegram.ui.Components; + +import static org.telegram.messenger.AndroidUtilities.dp; + +import android.content.Context; +import android.util.TypedValue; +import android.view.Gravity; +import android.widget.FrameLayout; +import android.widget.LinearLayout; +import android.widget.TextView; + +import androidx.recyclerview.widget.LinearLayoutManager; + +import org.telegram.messenger.MediaDataController; +import org.telegram.messenger.NotificationCenter; +import org.telegram.messenger.UserConfig; +import org.telegram.ui.ActionBar.Theme; +import org.telegram.ui.Stories.recorder.HintView2; + +public class TopViewCell extends LinearLayout { + + public final BackupImageView imageView; + public final LinkSpanDrawable.LinksTextView textView; + private int maxWidth; + + public TopViewCell(Context context, Theme.ResourcesProvider resourcesProvider) { + super(context); + + setOrientation(VERTICAL); + + imageView = new BackupImageView(context); + imageView.getImageReceiver().setAutoRepeatCount(1); + imageView.getImageReceiver().setAutoRepeat(1); + imageView.setOnClickListener(v -> { + RLottieDrawable lottie = imageView.getImageReceiver().getLottieAnimation(); + if (lottie != null) { + if (lottie.getCurrentFrame() < lottie.getFramesCount() - 20) return; + lottie.setProgress(0f); + } + imageView.getImageReceiver().startAnimation(); + }); + addView(imageView, LayoutHelper.createLinear(90, 90, Gravity.CENTER, 0, 9, 0, 9)); + + textView = new LinkSpanDrawable.LinksTextView(context) { + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + int width = MeasureSpec.getSize(widthMeasureSpec); + if (maxWidth > 0 && maxWidth < width) { + width = maxWidth; + } + super.onMeasure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY), heightMeasureSpec); + } + }; + textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); + textView.setGravity(Gravity.CENTER); + textView.setTextAlignment(TEXT_ALIGNMENT_CENTER); + textView.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteGrayText4, resourcesProvider)); + textView.setLinkTextColor(Theme.getColor(Theme.key_chat_messageLinkIn, resourcesProvider)); + addView(textView, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER, 48, 0, 48, 17)); + + } + + public void setEmoji(String setName, String emoji) { + MediaDataController.getInstance(UserConfig.selectedAccount).setPlaceholderImage(imageView, setName, emoji, "90_90"); + } + + private int lastIconResId; + public void setEmoji(int iconResId) { + if (lastIconResId != iconResId) { + imageView.setImageDrawable(new RLottieDrawable(lastIconResId = iconResId, "" + iconResId, dp(90), dp(90))); + } + } + + public void setText(CharSequence text) { + textView.setText(text); + maxWidth = HintView2.cutInFancyHalf(text, textView.getPaint()); + textView.requestLayout(); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.EXACTLY), heightMeasureSpec); + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/UItem.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/UItem.java new file mode 100644 index 00000000000..57fcacffe97 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/UItem.java @@ -0,0 +1,237 @@ +package org.telegram.ui.Components; + + +import android.text.TextUtils; +import android.view.View; + +import org.checkerframework.checker.guieffect.qual.UI; +import org.telegram.messenger.Utilities; +import org.telegram.ui.Business.QuickRepliesController; +import org.telegram.ui.Components.ListView.AdapterWithDiffUtils; + +import java.util.Objects; + +public class UItem extends AdapterWithDiffUtils.Item { + + public View view; + public int id; + public boolean checked; + public boolean enabled = true; + public int iconResId; + public CharSequence text, subtext, textValue; + public String[] texts; + public boolean accent, red; + + public boolean include; + public long dialogId; + public String chatType; + public int flags; + + public int intValue; + public Utilities.Callback intCallback; + + public Runnable clickCallback; + + public Object object; + + + public UItem(int viewType, boolean selectable) { + super(viewType, selectable); + } + + public static UItem asCustom(View view) { + UItem i = new UItem(UniversalAdapter.VIEW_TYPE_CUSTOM, false); + i.view = view; + return i; + } + + public static UItem asHeader(CharSequence text) { + UItem i = new UItem(UniversalAdapter.VIEW_TYPE_HEADER, false); + i.text = text; + return i; + } + + public static UItem asTopView(CharSequence text, String setName, String emoji) { + UItem i = new UItem(UniversalAdapter.VIEW_TYPE_TOPVIEW, false); + i.text = text; + i.subtext = setName; + i.textValue = emoji; + return i; + } + + public static UItem asTopView(CharSequence text, int lottieResId) { + UItem i = new UItem(UniversalAdapter.VIEW_TYPE_TOPVIEW, false); + i.text = text; + i.iconResId = lottieResId; + return i; + } + + public static UItem asButton(int id, CharSequence text) { + UItem i = new UItem(UniversalAdapter.VIEW_TYPE_TEXT, false); + i.id = id; + i.text = text; + return i; + } + + public static UItem asButton(int id, int iconResId, CharSequence text) { + UItem i = new UItem(UniversalAdapter.VIEW_TYPE_TEXT, false); + i.id = id; + i.iconResId = iconResId; + i.text = text; + return i; + } + + public static UItem asButton(int id, CharSequence text, CharSequence value) { + UItem i = new UItem(UniversalAdapter.VIEW_TYPE_TEXT, false); + i.id = id; + i.text = text; + i.textValue = value; + return i; + } + + public static UItem asButton(int id, int iconResId, CharSequence text, CharSequence value) { + UItem i = new UItem(UniversalAdapter.VIEW_TYPE_TEXT, false); + i.id = id; + i.iconResId = iconResId; + i.text = text; + i.textValue = value; + return i; + } + + public static UItem asRippleCheck(int id, CharSequence text) { + UItem i = new UItem(UniversalAdapter.VIEW_TYPE_CHECKRIPPLE, false); + i.id = id; + i.text = text; + return i; + } + + public static UItem asCheck(int id, CharSequence text) { + UItem i = new UItem(UniversalAdapter.VIEW_TYPE_CHECK, false); + i.id = id; + i.text = text; + return i; + } + + public static UItem asRadio(int id, CharSequence text) { + UItem i = new UItem(UniversalAdapter.VIEW_TYPE_RADIO, false); + i.id = id; + i.text = text; + return i; + } + + public static UItem asRadio(int id, CharSequence text, CharSequence value) { + UItem i = new UItem(UniversalAdapter.VIEW_TYPE_RADIO, false); + i.id = id; + i.text = text; + i.textValue = value; + return i; + } + + public static UItem asButtonCheck(int id, CharSequence text, CharSequence subtext) { + UItem i = new UItem(UniversalAdapter.VIEW_TYPE_TEXT_CHECK, false); + i.id = id; + i.text = text; + i.subtext = subtext; + return i; + } + + public static UItem asShadow(CharSequence text) { + UItem i = new UItem(UniversalAdapter.VIEW_TYPE_SHADOW, false); + i.text = text; + return i; + } + + public static UItem asShadow(int id, CharSequence text) { + UItem i = new UItem(UniversalAdapter.VIEW_TYPE_SHADOW, false); + i.id = id; + i.text = text; + return i; + } + + public static UItem asFilterChat(boolean include, long dialogId) { + UItem item = new UItem(UniversalAdapter.VIEW_TYPE_FILTER_CHAT, false); + item.include = include; + item.dialogId = dialogId; + return item; + } + + public static UItem asFilterChat(boolean include, CharSequence name, String chatType, int flags) { + UItem item = new UItem(UniversalAdapter.VIEW_TYPE_FILTER_CHAT, false); + item.include = include; + item.text = name; + item.chatType = chatType; + item.flags = flags; + return item; + } + + public static UItem asAddChat(Long dialogId) { + UItem item = new UItem(UniversalAdapter.VIEW_TYPE_USER_ADD, false); + item.dialogId = dialogId; + return item; + } + + public static UItem asSlideView(String[] choices, int chosen, Utilities.Callback whenChose) { + UItem item = new UItem(UniversalAdapter.VIEW_TYPE_SLIDE, false); + item.texts = choices; + item.intValue = chosen; + item.intCallback = whenChose; + return item; + } + + public static UItem asQuickReply(QuickRepliesController.QuickReply quickReply) { + UItem item = new UItem(UniversalAdapter.VIEW_TYPE_QUICK_REPLY, false); + item.object = quickReply; + return item; + } + + public static UItem asLargeQuickReply(QuickRepliesController.QuickReply quickReply) { + UItem item = new UItem(UniversalAdapter.VIEW_TYPE_LARGE_QUICK_REPLY, false); + item.object = quickReply; + return item; + } + + public UItem setCloseIcon(Runnable onCloseClick) { + clickCallback = onCloseClick; + return this; + } + + public UItem setChecked(boolean checked) { + this.checked = checked; + return this; + } + + public UItem setEnabled(boolean enabled) { + this.enabled = enabled; + return this; + } + + public UItem red() { + this.red = true; + return this; + } + + public UItem accent() { + this.accent = true; + return this; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + UItem item = (UItem) o; + return ( + viewType == item.viewType && + id == item.id && + iconResId == item.iconResId && + red == item.red && + accent == item.accent && + TextUtils.equals(text, item.text) && + TextUtils.equals(subtext, item.subtext) && + TextUtils.equals(textValue, item.textValue) && + view == item.view && + intValue == item.intValue && + Objects.equals(object, item.object) + ); + } +} 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 525d9d24ad7..d7b92a55dd5 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/UndoView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/UndoView.java @@ -827,10 +827,16 @@ public void showWithAction(ArrayList dialogIds, int action, Object infoObj } if (DialogObject.isUserDialog(dialogId)) { TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(dialogId); + String name = UserObject.getFirstName(user); + if (UserObject.isUserSelf(user)) { + name = LocaleController.getString(R.string.SavedMessages); + } else if (UserObject.isReplyUser(user)) { + name = LocaleController.getString(R.string.RepliesTitle); + } if (action == ACTION_ADDED_TO_FOLDER) { - infoText = AndroidUtilities.replaceTags(LocaleController.formatString("FilterUserAddedToExisting", R.string.FilterUserAddedToExisting, UserObject.getFirstName(user), filter.name)); + infoText = AndroidUtilities.replaceTags(LocaleController.formatString("FilterUserAddedToExisting", R.string.FilterUserAddedToExisting, name, filter.name)); } else { - infoText = AndroidUtilities.replaceTags(LocaleController.formatString("FilterUserRemovedFrom", R.string.FilterUserRemovedFrom, UserObject.getFirstName(user), filter.name)); + infoText = AndroidUtilities.replaceTags(LocaleController.formatString("FilterUserRemovedFrom", R.string.FilterUserRemovedFrom, name, filter.name)); } } else { TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(-dialogId); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/UniversalAdapter.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/UniversalAdapter.java new file mode 100644 index 00000000000..d6b869c2e8f --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/UniversalAdapter.java @@ -0,0 +1,483 @@ +package org.telegram.ui.Components; + +import android.content.Context; +import android.graphics.Canvas; +import android.text.TextUtils; +import android.util.Log; +import android.view.View; +import android.view.ViewGroup; +import android.widget.FrameLayout; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.recyclerview.widget.RecyclerView; + +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.R; +import org.telegram.messenger.Utilities; +import org.telegram.ui.ActionBar.Theme; +import org.telegram.ui.Business.QuickRepliesActivity; +import org.telegram.ui.Business.QuickRepliesController; +import org.telegram.ui.Cells.DialogRadioCell; +import org.telegram.ui.Cells.HeaderCell; +import org.telegram.ui.Cells.NotificationsCheckCell; +import org.telegram.ui.Cells.TextCell; +import org.telegram.ui.Cells.TextCheckCell; +import org.telegram.ui.Cells.TextInfoPrivacyCell; +import org.telegram.ui.Cells.UserCell; +import org.telegram.ui.Components.ListView.AdapterWithDiffUtils; + +import java.util.ArrayList; + +public class UniversalAdapter extends AdapterWithDiffUtils { + + public static final int VIEW_TYPE_CUSTOM = -1; + + public static final int VIEW_TYPE_HEADER = 0; + public static final int VIEW_TYPE_TOPVIEW = 1; + + public static final int VIEW_TYPE_TEXT = 2; + public static final int VIEW_TYPE_CHECK = 3; + public static final int VIEW_TYPE_TEXT_CHECK = 4; + public static final int VIEW_TYPE_ICON_TEXT_CHECK = 5; + public static final int VIEW_TYPE_SHADOW = 6; + public static final int VIEW_TYPE_CHECKRIPPLE = 7; + public static final int VIEW_TYPE_RADIO = 8; + public static final int VIEW_TYPE_FILTER_CHAT = 9; + public static final int VIEW_TYPE_USER_ADD = 10; + public static final int VIEW_TYPE_SLIDE = 11; + public static final int VIEW_TYPE_QUICK_REPLY = 12; + public static final int VIEW_TYPE_LARGE_QUICK_REPLY = 13; + + private final Context context; + private final int currentAccount; + private final Utilities.Callback2, UniversalAdapter> fillItems; + private final Theme.ResourcesProvider resourcesProvider; + + private final ArrayList oldItems = new ArrayList<>(); + private final ArrayList items = new ArrayList<>(); + + public UniversalAdapter(Context context, int currentAccount, Utilities.Callback2, UniversalAdapter> fillItems, Theme.ResourcesProvider resourcesProvider) { + super(); + this.context = context; + this.currentAccount = currentAccount; + this.fillItems = fillItems; + this.resourcesProvider = resourcesProvider; + update(false); + } + + + private static class Section { + public int start, end; + public boolean contains(int position) { + return position >= start && position <= end; + } + } + private final ArrayList
whiteSections = new ArrayList<>(); + private final ArrayList
reorderSections = new ArrayList<>(); + private Section currentWhiteSection, currentReorderSection; + public void whiteSectionStart() { + currentWhiteSection = new Section(); + currentWhiteSection.start = items.size(); + currentWhiteSection.end = -1; + whiteSections.add(currentWhiteSection); + } + public void whiteSectionEnd() { + if (currentWhiteSection != null) { + currentWhiteSection.end = Math.max(0, items.size() - 1); + } + } + + public int reorderSectionStart() { + currentReorderSection = new Section(); + currentReorderSection.start = items.size(); + currentReorderSection.end = -1; + reorderSections.add(currentReorderSection); + return reorderSections.size() - 1; + } + public void reorderSectionEnd() { + if (currentReorderSection != null) { + currentReorderSection.end = Math.max(0, items.size() - 1); + } + } + + public boolean isReorderItem(int position) { + return getReorderSectionId(position) >= 0; + } + public int getReorderSectionId(int position) { + for (int i = 0; i < reorderSections.size(); ++i) { + if (reorderSections.get(i).contains(position)) + return i; + } + return -1; + } + + private int orderChangedId; + private boolean orderChanged; + public void swapElements(int fromPosition, int toPosition) { + if (onReordered == null) return; + int fromPositionReorderId = getReorderSectionId(fromPosition); + int toPositionReorderId = getReorderSectionId(toPosition); + if (fromPositionReorderId < 0 || fromPositionReorderId != toPositionReorderId) { + return; + } + UItem fromItem = items.get(fromPosition); + UItem toItem = items.get(toPosition); + boolean fromItemHadDivider = hasDivider(fromPosition); + boolean toItemHadDivider = hasDivider(toPosition); + items.set(fromPosition, toItem); + items.set(toPosition, fromItem); + notifyItemMoved(fromPosition, toPosition); + if (hasDivider(toPosition) != fromItemHadDivider) { + notifyItemChanged(toPosition, 3); + } + if (hasDivider(fromPosition) != toItemHadDivider) { + notifyItemChanged(fromPosition, 3); + } + if (orderChanged && orderChangedId != fromPositionReorderId) { + callReorder(orderChangedId); + } + orderChanged = true; + orderChangedId = fromPositionReorderId; + } + + private void callReorder(int id) { + if (id < 0 || id >= reorderSections.size()) return; + Section section = reorderSections.get(id); + onReordered.run(id, new ArrayList(items.subList(section.start, section.end + 1))); + orderChanged = false; + } + + public void reorderDone() { + if (orderChanged) { + callReorder(orderChangedId); + } + } + + private Utilities.Callback2> onReordered; + public void listenReorder(Utilities.Callback2> onReordered) { + this.onReordered = onReordered; + } + + private boolean allowReorder; + public void updateReorder(boolean allowReorder) { + this.allowReorder = allowReorder; + } + + public void drawWhiteSections(Canvas canvas, RecyclerListView listView) { + for (int i = 0; i < whiteSections.size(); ++i) { + Section section = whiteSections.get(i); + if (section.end < 0) continue; + listView.drawSectionBackground(canvas, section.start, section.end, getThemedColor(Theme.key_windowBackgroundWhite)); + } + } + + public void update(boolean animated) { + oldItems.clear(); + oldItems.addAll(items); + items.clear(); + whiteSections.clear(); + reorderSections.clear(); + fillItems.run(items, this); + if (animated) { + setItems(oldItems, items); + } else { + notifyDataSetChanged(); + } + } + + @NonNull + @Override + public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { + View view; + switch (viewType) { + case VIEW_TYPE_HEADER: + view = new HeaderCell(context, resourcesProvider); + view.setBackgroundColor(getThemedColor(Theme.key_windowBackgroundWhite)); + break; + case VIEW_TYPE_TOPVIEW: + view = new TopViewCell(context, resourcesProvider); + break; + case VIEW_TYPE_TEXT: + view = new TextCell(context, resourcesProvider); + view.setBackgroundColor(getThemedColor(Theme.key_windowBackgroundWhite)); + break; + case VIEW_TYPE_CHECK: + case VIEW_TYPE_CHECKRIPPLE: + TextCheckCell cell = new TextCheckCell(context, resourcesProvider); + if (viewType == VIEW_TYPE_CHECKRIPPLE) { + cell.setDrawCheckRipple(true); + cell.setColors(Theme.key_windowBackgroundCheckText, Theme.key_switchTrackBlue, Theme.key_switchTrackBlueChecked, Theme.key_switchTrackBlueThumb, Theme.key_switchTrackBlueThumbChecked); + cell.setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)); + cell.setHeight(56); + } + cell.setBackgroundColor(getThemedColor(Theme.key_windowBackgroundWhite)); + view = cell; + break; + case VIEW_TYPE_RADIO: + view = new DialogRadioCell(context); + view.setBackgroundColor(getThemedColor(Theme.key_windowBackgroundWhite)); + break; + case VIEW_TYPE_TEXT_CHECK: + case VIEW_TYPE_ICON_TEXT_CHECK: + view = new NotificationsCheckCell(context, 21, 60, viewType == VIEW_TYPE_ICON_TEXT_CHECK, resourcesProvider); + view.setBackgroundColor(getThemedColor(Theme.key_windowBackgroundWhite)); + break; + case VIEW_TYPE_CUSTOM: + view = new FrameLayout(context) { + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.EXACTLY), heightMeasureSpec); + } + }; + break; + case VIEW_TYPE_FILTER_CHAT: + UserCell userCell = new UserCell(context, 6, 0, false); + userCell.setSelfAsSavedMessages(true); + userCell.setBackgroundColor(getThemedColor(Theme.key_windowBackgroundWhite)); + view = userCell; + break; + case VIEW_TYPE_USER_ADD: + UserCell userCell2 = new UserCell(context, 6, 0, false, true); + userCell2.setBackgroundColor(getThemedColor(Theme.key_windowBackgroundWhite)); + view = userCell2; + break; + case VIEW_TYPE_SLIDE: + view = new SlideChooseView(context, resourcesProvider); + view.setBackgroundColor(getThemedColor(Theme.key_windowBackgroundWhite)); + break; + case VIEW_TYPE_QUICK_REPLY: + view = new QuickRepliesActivity.QuickReplyView(context, onReordered != null, resourcesProvider); + view.setBackgroundColor(getThemedColor(Theme.key_windowBackgroundWhite)); + break; + case VIEW_TYPE_LARGE_QUICK_REPLY: + view = new QuickRepliesActivity.LargeQuickReplyView(context, resourcesProvider); + view.setBackgroundColor(getThemedColor(Theme.key_windowBackgroundWhite)); + break; + default: + case VIEW_TYPE_SHADOW: + view = new TextInfoPrivacyCell(context, resourcesProvider); + break; + } + return new RecyclerListView.Holder(view); + } + + @Override + public int getItemViewType(int position) { + UItem item = getItem(position); + if (item == null) return 0; + return item.viewType; + } + + private boolean hasDivider(int position) { + UItem item = getItem(position); + UItem nextItem = getItem(position + 1); + return item != null && nextItem != null && (nextItem.viewType != VIEW_TYPE_SHADOW) == (item.viewType != VIEW_TYPE_SHADOW); + } + + @Override + public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) { + UItem item = getItem(position); + UItem nextItem = getItem(position + 1); + UItem prevItem = getItem(position - 1); + if (item == null) return; + final int viewType = holder.getItemViewType(); + final boolean divider = hasDivider(position); + switch (viewType) { + case VIEW_TYPE_HEADER: + ((HeaderCell) holder.itemView).setText(item.text); + break; + case VIEW_TYPE_TOPVIEW: + TopViewCell topCell = (TopViewCell) holder.itemView; + if (item.iconResId != 0) { + topCell.setEmoji(item.iconResId); + } else { + topCell.setEmoji(item.subtext.toString(), item.textValue.toString()); + } + topCell.setText(item.text); + break; + case VIEW_TYPE_TEXT: + TextCell cell = (TextCell) holder.itemView; + if (TextUtils.isEmpty(item.textValue)) { + if (item.iconResId == 0) { + cell.setText(item.text, divider); + } else { + cell.setTextAndIcon(item.text, item.iconResId, divider); + } + } else { + if (item.iconResId == 0) { + cell.setTextAndValue(item.text, item.textValue, divider); + } else { + cell.setTextAndValueAndIcon(item.text, item.textValue, item.iconResId, divider); + } + } + if (item.accent) { + cell.setColors(Theme.key_windowBackgroundWhiteBlueText4, Theme.key_windowBackgroundWhiteBlueText4); + } else if (item.red) { + cell.setColors(Theme.key_text_RedBold, Theme.key_text_RedRegular); + } else { + cell.setColors(Theme.key_windowBackgroundWhiteGrayIcon, Theme.key_windowBackgroundWhiteBlackText); + } + break; + case VIEW_TYPE_CHECK: + case VIEW_TYPE_CHECKRIPPLE: + TextCheckCell checkCell = (TextCheckCell) holder.itemView; + if (checkCell.itemId == item.id) { + checkCell.setChecked(item.checked); + } + checkCell.setTextAndCheck(item.text, item.checked, divider); + checkCell.itemId = item.id; + if (viewType == VIEW_TYPE_CHECKRIPPLE) { + holder.itemView.setBackgroundColor(Theme.getColor(item.checked ? Theme.key_windowBackgroundChecked : Theme.key_windowBackgroundUnchecked)); + } + break; + case VIEW_TYPE_RADIO: + DialogRadioCell radioCell = (DialogRadioCell) holder.itemView; + if (radioCell.itemId == item.id) { + radioCell.setChecked(item.checked, true); + radioCell.setEnabled(item.enabled, true); + } else { + radioCell.setEnabled(item.enabled, false); + } + if (TextUtils.isEmpty(item.textValue)) { + radioCell.setText(item.text, item.checked, divider); + } else { + radioCell.setTextAndValue(item.text, item.textValue, item.checked, divider); + } + radioCell.itemId = item.id; + break; + case VIEW_TYPE_TEXT_CHECK: + NotificationsCheckCell checkCell1 = (NotificationsCheckCell) holder.itemView; + checkCell1.setTextAndValueAndCheck(item.text, item.subtext, item.checked, divider); + checkCell1.setMultiline(item.subtext != null && item.subtext.toString().contains("\n")); + break; + case VIEW_TYPE_ICON_TEXT_CHECK: + // TODO: image + ((NotificationsCheckCell) holder.itemView).setTextAndValueAndCheck(item.text, item.subtext, item.checked, divider); + break; + case VIEW_TYPE_SHADOW: + TextInfoPrivacyCell cell2 = (TextInfoPrivacyCell) holder.itemView; + if (TextUtils.isEmpty(item.text)) { + cell2.setFixedSize(12); + cell2.setText(""); + } else { + cell2.setFixedSize(0); + cell2.setText(item.text); + } + final boolean prev = prevItem != null && prevItem.viewType != viewType; + final boolean next = nextItem != null && nextItem.viewType != viewType; + int drawable; + if (prev && next) { + drawable = R.drawable.greydivider; + } else if (prev) { + drawable = R.drawable.greydivider_bottom; + } else if (next) { + drawable = R.drawable.greydivider_top; + } else { + drawable = R.drawable.field_carret_empty; + } + cell2.setBackground(Theme.getThemedDrawableByKey(context, drawable, Theme.key_windowBackgroundGrayShadow, resourcesProvider)); + break; + case VIEW_TYPE_CUSTOM: + FrameLayout frameLayout = (FrameLayout) holder.itemView; + if (frameLayout.getChildCount() != (item.view == null ? 0 : 1) || frameLayout.getChildAt(0) != item.view) { + frameLayout.removeAllViews(); + if (item.view != null) { + AndroidUtilities.removeFromParent(item.view); + frameLayout.addView(item.view, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); + } + } + break; + case VIEW_TYPE_FILTER_CHAT: + UserCell userCell = (UserCell) holder.itemView; + userCell.setFromUItem(currentAccount, item, divider); + break; + case VIEW_TYPE_USER_ADD: + UserCell userCell2 = (UserCell) holder.itemView; + userCell2.setFromUItem(currentAccount, item, divider); + userCell2.setAddButtonVisible(!item.checked); + userCell2.setCloseIcon(item.clickCallback); + break; + case VIEW_TYPE_SLIDE: + SlideChooseView slideView = (SlideChooseView) holder.itemView; + slideView.setOptions(item.intValue, item.texts); + slideView.setCallback(index -> { + if (item.intCallback != null) { + item.intCallback.run(index); + } + }); + break; + case VIEW_TYPE_QUICK_REPLY: + QuickRepliesActivity.QuickReplyView replyView = (QuickRepliesActivity.QuickReplyView) holder.itemView; + replyView.setChecked(item.checked, false); + replyView.setReorder(allowReorder); + if (item.object instanceof QuickRepliesController.QuickReply) { + replyView.set((QuickRepliesController.QuickReply) item.object, null, divider); + } + break; + case VIEW_TYPE_LARGE_QUICK_REPLY: + QuickRepliesActivity.LargeQuickReplyView replyView2 = (QuickRepliesActivity.LargeQuickReplyView) holder.itemView; + replyView2.setChecked(item.checked, false); + if (item.object instanceof QuickRepliesController.QuickReply) { + replyView2.set((QuickRepliesController.QuickReply) item.object, divider); + } + break; + } + } + + @Override + public void onViewAttachedToWindow(@NonNull RecyclerView.ViewHolder holder) { + updateReorder(holder, allowReorder); + } + + public void updateReorder(RecyclerView.ViewHolder holder, boolean allowReorder) { + if (holder == null) return; + final int viewType = holder.getItemViewType(); + switch (viewType) { + case VIEW_TYPE_QUICK_REPLY: + ((QuickRepliesActivity.QuickReplyView) holder.itemView).setReorder(allowReorder); + break; + } + } + + @Override + public int getItemCount() { + return items.size(); + } + + @Override + public boolean isEnabled(RecyclerView.ViewHolder holder) { + final int viewType = holder.getItemViewType(); + UItem item = getItem(holder.getAdapterPosition()); + return ( + viewType == VIEW_TYPE_TEXT || + viewType == VIEW_TYPE_TEXT_CHECK || + viewType == VIEW_TYPE_ICON_TEXT_CHECK || + viewType == VIEW_TYPE_CHECK || + viewType == VIEW_TYPE_RADIO || + viewType == VIEW_TYPE_FILTER_CHAT || + viewType == VIEW_TYPE_LARGE_QUICK_REPLY || + viewType == VIEW_TYPE_QUICK_REPLY + ) && (item == null || item.enabled); + } + + public UItem getItem(int position) { + if (position < 0 || position >= items.size()) return null; + return items.get(position); + } + + public UItem findItem(int itemId) { + for (int i = 0; i < items.size(); ++i) { + UItem item = items.get(i); + if (item != null && item.id == itemId) { + return item; + } + } + return null; + } + + private int getThemedColor(int key) { + return Theme.getColor(key, resourcesProvider); + } + +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/UniversalRecyclerView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/UniversalRecyclerView.java new file mode 100644 index 00000000000..bd6f2723864 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/UniversalRecyclerView.java @@ -0,0 +1,192 @@ +package org.telegram.ui.Components; + +import android.content.Context; +import android.graphics.Canvas; +import android.util.Log; +import android.util.Pair; +import android.view.View; + +import androidx.annotation.NonNull; +import androidx.recyclerview.widget.DefaultItemAnimator; +import androidx.recyclerview.widget.ItemTouchHelper; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; + +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.Utilities; +import org.telegram.ui.ActionBar.Theme; +import org.telegram.ui.Cells.DialogCell; +import org.telegram.ui.FiltersSetupActivity; + +import java.util.ArrayList; + +public class UniversalRecyclerView extends RecyclerListView { + + public final LinearLayoutManager layoutManager; + public final UniversalAdapter adapter; + private ItemTouchHelper itemTouchHelper; + + public UniversalRecyclerView( + Context context, + int currentAccount, + Utilities.Callback2, UniversalAdapter> fillItems, + Utilities.Callback5 onClick, + Utilities.Callback5Return onLongClick, + Theme.ResourcesProvider resourcesProvider + ) { + super(context, resourcesProvider); + setLayoutManager(layoutManager = new LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false)); + setAdapter(adapter = new UniversalAdapter(context, currentAccount, fillItems, resourcesProvider)); + + if (onClick != null) { + setOnItemClickListener((view, position, x, y) -> { + UItem item = adapter.getItem(position); + if (item == null) return; + onClick.run(item, view, position, x, y); + }); + } + + if (onLongClick != null) { + setOnItemLongClickListener((view, position, x, y) -> { + UItem item = adapter.getItem(position); + if (item == null) return false; + return onLongClick.run(item, view, position, x, y); + }); + } + + DefaultItemAnimator itemAnimator = new DefaultItemAnimator() { + @Override + protected void onMoveAnimationUpdate(ViewHolder holder) { + super.onMoveAnimationUpdate(holder); + invalidate(); + } + }; + itemAnimator.setSupportsChangeAnimations(false); + itemAnimator.setDelayAnimations(false); + itemAnimator.setInterpolator(CubicBezierInterpolator.EASE_OUT_QUINT); + itemAnimator.setDurations(350); + setItemAnimator(itemAnimator); + + setTranslateSelector(true); + } + + private boolean reorderingAllowed; + public void listenReorder( + Utilities.Callback2> onReordered + ) { + itemTouchHelper = new ItemTouchHelper(new TouchHelperCallback()); + itemTouchHelper.attachToRecyclerView(this); + adapter.listenReorder(onReordered); + } + + public void allowReorder(boolean allow) { + if (reorderingAllowed == allow) return; + adapter.updateReorder(reorderingAllowed = allow); + AndroidUtilities.forEachViews(this, view -> { + adapter.updateReorder(getChildViewHolder(view), reorderingAllowed); + }); + } + + @Override + protected void dispatchDraw(Canvas canvas) { + adapter.drawWhiteSections(canvas, this); + super.dispatchDraw(canvas); + } + + public UItem findItemByItemId(int itemId) { + for (int i = 0; i < adapter.getItemCount(); ++i) { + UItem item = adapter.getItem(i); + if (item != null && item.id == itemId) { + return item; + } + } + return null; + } + + public View findViewByItemId(int itemId) { + int position = -1; + for (int i = 0; i < adapter.getItemCount(); ++i) { + UItem item = adapter.getItem(i); + if (item != null && item.id == itemId) { + position = i; + break; + } + } + return findViewByPosition(position); + } + + public int findPositionByItemId(int itemId) { + int position = -1; + for (int i = 0; i < adapter.getItemCount(); ++i) { + UItem item = adapter.getItem(i); + if (item != null && item.id == itemId) { + return i; + } + } + return -1; + } + + public View findViewByPosition(int position) { + if (position == NO_POSITION) return null; + for (int i = 0; i < getChildCount(); ++i) { + View child = getChildAt(i); + int childPosition = getChildAdapterPosition(child); + if (childPosition != NO_POSITION && childPosition == position) { + return child; + } + } + return null; + } + + private class TouchHelperCallback extends ItemTouchHelper.Callback { + @Override + public boolean isLongPressDragEnabled() { + return reorderingAllowed; + } + + @Override + public int getMovementFlags(@NonNull RecyclerView recyclerView, @NonNull ViewHolder viewHolder) { + if (reorderingAllowed && adapter.isReorderItem(viewHolder.getAdapterPosition())) { + return makeMovementFlags(ItemTouchHelper.UP | ItemTouchHelper.DOWN, 0); + } else { + return makeMovementFlags(0, 0); + } + } + + @Override + public boolean onMove(@NonNull RecyclerView recyclerView, @NonNull ViewHolder viewHolder, @NonNull ViewHolder target) { + if (!adapter.isReorderItem(viewHolder.getAdapterPosition()) || adapter.getReorderSectionId(viewHolder.getAdapterPosition()) != adapter.getReorderSectionId(target.getAdapterPosition())) { + return false; + } + adapter.swapElements(viewHolder.getAdapterPosition(), target.getAdapterPosition()); + return true; + } + + @Override + public void onSwiped(@NonNull ViewHolder viewHolder, int direction) { + + } + + @Override + public void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState) { + if (viewHolder != null) { + hideSelector(false); + } + if (actionState == ItemTouchHelper.ACTION_STATE_IDLE) { + adapter.reorderDone(); + } else { + cancelClickRunnables(false); + if (viewHolder != null) { + viewHolder.itemView.setPressed(true); + } + } + super.onSelectedChanged(viewHolder, actionState); + } + + @Override + public void clearView(@NonNull RecyclerView recyclerView, @NonNull ViewHolder viewHolder) { + super.clearView(recyclerView, viewHolder); + viewHolder.itemView.setPressed(false); + } + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/VideoPlayer.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/VideoPlayer.java index 9fb2500fd82..3b5542ba45b 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/VideoPlayer.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/VideoPlayer.java @@ -322,7 +322,7 @@ public void preparePlayer(Uri uri, String type, int priority) { videoPlayerReady = false; mixedAudio = false; currentUri = uri; - String scheme = uri.getScheme(); + String scheme = uri != null ? uri.getScheme() : null; isStreaming = scheme != null && !scheme.startsWith("file"); ensurePlayerCreated(); MediaSource mediaSource = mediaSourceFromUri(uri, type); 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 bdb2fad73b2..3a6dc8f3658 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 @@ -606,7 +606,7 @@ public static void showRateAlert(final Context context, final Runnable onDismiss } if (includeLogs[0] && log.exists() && req.rating < 4) { AccountInstance accountInstance = AccountInstance.getInstance(UserConfig.selectedAccount); - SendMessagesHelper.prepareSendingDocument(accountInstance, log.getAbsolutePath(), log.getAbsolutePath(), null, TextUtils.join(" ", problemTags), "text/plain", VOIP_SUPPORT_ID, null, null, null, null, null, true, 0, null); + SendMessagesHelper.prepareSendingDocument(accountInstance, log.getAbsolutePath(), log.getAbsolutePath(), null, TextUtils.join(" ", problemTags), "text/plain", VOIP_SUPPORT_ID, null, null, null, null, null, true, 0, null, null, 0); Toast.makeText(context, LocaleController.getString("CallReportSent", R.string.CallReportSent), Toast.LENGTH_LONG).show(); } }); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ContactAddActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ContactAddActivity.java index 31c93533a8a..05827c26e21 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ContactAddActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ContactAddActivity.java @@ -755,7 +755,7 @@ private void createServiceMessageLocal(TLRPC.PhotoSize smallSize, TLRPC.PhotoSiz ArrayList arr = new ArrayList<>(); arr.add(message); // MessagesStorage.getInstance(currentAccount).putMessages(arr, false, true, false, 0, false, 0); - MessagesController.getInstance(currentAccount).updateInterfaceWithMessages(user_id, objArr, false); + MessagesController.getInstance(currentAccount).updateInterfaceWithMessages(user_id, objArr, 0); getMessagesController().photoSuggestion.put(message.local_id, imageUpdater); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ContactsActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ContactsActivity.java index 40809cecdb9..4c636e50192 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ContactsActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ContactsActivity.java @@ -79,6 +79,7 @@ import org.telegram.ui.ActionBar.ActionBarMenu; import org.telegram.ui.ActionBar.ActionBarMenuItem; import org.telegram.ui.ActionBar.AlertDialog; +import org.telegram.ui.ActionBar.BackDrawable; import org.telegram.ui.ActionBar.BaseFragment; import org.telegram.ui.ActionBar.Theme; import org.telegram.ui.ActionBar.ThemeDescription; @@ -98,6 +99,7 @@ import org.telegram.ui.Components.FlickerLoadingView; import org.telegram.ui.Components.ItemOptions; import org.telegram.ui.Components.LayoutHelper; +import org.telegram.ui.Components.NumberTextView; import org.telegram.ui.Components.RLottieImageView; import org.telegram.ui.Components.RecyclerListView; import org.telegram.ui.Components.StickerEmptyView; @@ -152,6 +154,16 @@ public class ContactsActivity extends BaseFragment implements NotificationCenter private boolean disableSections; + private LongSparseArray selectedContacts = new LongSparseArray<>(); + + private NumberTextView selectedContactsCountTextView; + + private ActionBarMenuItem deleteItem; + + private BackDrawable backDrawable; + + private String searchQuery; + private boolean checkPermission = true; private long permissionRequestTime; @@ -161,6 +173,8 @@ public class ContactsActivity extends BaseFragment implements NotificationCenter private final static int search_button = 0; private final static int sort_button = 1; + private final static int delete = 100; + public interface ContactsActivityDelegate { void didSelectContact(TLRPC.User user, String param, ContactsActivity activity); } @@ -235,7 +249,6 @@ public View createView(Context context) { searching = false; searchWas = false; - actionBar.setBackButtonImage(R.drawable.ic_ab_back); actionBar.setAllowOverlayTitle(true); if (destroyAfterSelect) { if (returnAsResult) { @@ -251,11 +264,32 @@ public View createView(Context context) { actionBar.setTitle(LocaleController.getString("Contacts", R.string.Contacts)); } + actionBar.setBackButtonDrawable(backDrawable = new BackDrawable(false)); + + final ActionBarMenu actionMode = actionBar.createActionMode(false, null); + actionMode.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); + actionMode.drawBlur = false; + + selectedContactsCountTextView = new NumberTextView(actionMode.getContext()); + selectedContactsCountTextView.setTextSize(18); + selectedContactsCountTextView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); + selectedContactsCountTextView.setTextColor(Theme.getColor(Theme.key_actionBarActionModeDefaultIcon)); + actionMode.addView(selectedContactsCountTextView, LayoutHelper.createLinear(0, LayoutHelper.MATCH_PARENT, 1.0f, 72, 0, 0, 0)); + selectedContactsCountTextView.setOnTouchListener((v, event) -> true); + + deleteItem = actionMode.addItemWithWidth(delete, R.drawable.msg_delete, AndroidUtilities.dp(54), LocaleController.getString("Delete", R.string.Delete)); + actionBar.setActionBarMenuOnItemClick(new ActionBar.ActionBarMenuOnItemClick() { @Override public void onItemClick(int id) { if (id == -1) { - finishFragment(); + if (actionBar.isActionModeShowed()) { + hideActionMode(); + } else { + finishFragment(); + } + } else if (id == delete) { + performSelectedContactsDelete(); } else if (id == sort_button) { SharedConfig.toggleSortContactsByName(); sortByName = SharedConfig.sortContactsByName; @@ -307,6 +341,7 @@ public void onTextChanged(EditText editText) { return; } String text = editText.getText().toString(); + searchQuery = text; if (text.length() != 0) { searchWas = true; if (listView != null) { @@ -333,7 +368,7 @@ public void onTextChanged(EditText editText) { sortItem.setContentDescription(LocaleController.getString("AccDescrContactSorting", R.string.AccDescrContactSorting)); } - searchListViewAdapter = new SearchAdapter(context, ignoreUsers, allowUsernameSearch, false, false, allowBots, allowSelf, true, 0) { + searchListViewAdapter = new SearchAdapter(context, ignoreUsers, selectedContacts, allowUsernameSearch, false, false, allowBots, allowSelf, true, 0) { @Override protected void onSearchProgressChanged() { if (!searchInProgress() && getItemCount() == 0) { @@ -358,7 +393,7 @@ protected void onSearchProgressChanged() { } catch (Throwable e) { hasGps = false; } - listViewAdapter = new ContactsAdapter(context, this, onlyUsers ? 1 : 0, needPhonebook, ignoreUsers, inviteViaLink, hasGps) { + listViewAdapter = new ContactsAdapter(context, this, onlyUsers ? 1 : 0, needPhonebook, ignoreUsers, selectedContacts, inviteViaLink, hasGps) { @Override public void notifyDataSetChanged() { super.notifyDataSetChanged(); @@ -451,6 +486,16 @@ public void setPadding(int left, int top, int right, int bottom) { listView.setOnItemClickListener((view, position, x, y) -> { if (listView.getAdapter() == searchListViewAdapter) { Object object = searchListViewAdapter.getItem(position); + + if (!selectedContacts.isEmpty() && view instanceof ProfileSearchCell) { + ProfileSearchCell cell = (ProfileSearchCell) view; + if (cell.getUser() != null && cell.getUser().contact) { + showOrUpdateActionMode(cell); + } + + return; + } + if (object instanceof TLRPC.User) { TLRPC.User user = (TLRPC.User) object; if (searchListViewAdapter.isGlobalSearch(position)) { @@ -497,6 +542,13 @@ public void setPadding(int left, int top, int right, int bottom) { if (row < 0 || section < 0) { return; } + + if (!selectedContacts.isEmpty() && view instanceof UserCell) { + UserCell userCell = (UserCell) view; + showOrUpdateActionMode(userCell); + return; + } + if (listViewAdapter.hasStories && section == 1) { if (!(view instanceof UserCell)) { return; @@ -623,52 +675,53 @@ public void setPadding(int left, int top, int right, int bottom) { listView.setOnItemLongClickListener(new RecyclerListView.OnItemLongClickListener() { @Override public boolean onItemClick(View view, int position) { - int section = listViewAdapter.getSectionForPosition(position); - int row = listViewAdapter.getPositionInSectionForPosition(position); - if (Bulletin.getVisibleBulletin() != null) { - Bulletin.getVisibleBulletin().hide(); - } - if (row < 0 || section < 0) { - return false; - } - if (listViewAdapter.hasStories && section == 1 && view instanceof UserCell) { - UserCell userCell = (UserCell) view; - long dialogId = userCell.getDialogId(); - TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(dialogId); - final String key = NotificationsController.getSharedPrefKey(dialogId, 0); - boolean muted = !NotificationsCustomSettingsActivity.areStoriesNotMuted(currentAccount, dialogId); - ItemOptions filterOptions = ItemOptions.makeOptions(ContactsActivity.this, view) - //.setViewAdditionalOffsets(0, AndroidUtilities.dp(8), 0, 0) - .setScrimViewBackground(Theme.createRoundRectDrawable(0, 0, Theme.getColor(Theme.key_windowBackgroundWhite))) - .add(R.drawable.msg_discussion, LocaleController.getString("SendMessage", R.string.SendMessage), () -> { - presentFragment(ChatActivity.of(dialogId)); - }) - .add(R.drawable.msg_openprofile, LocaleController.getString("OpenProfile", R.string.OpenProfile), () -> { - presentFragment(ProfileActivity.of(dialogId)); - }) - .addIf(!muted, R.drawable.msg_mute, LocaleController.getString("NotificationsStoryMute", R.string.NotificationsStoryMute), () -> { - MessagesController.getNotificationsSettings(currentAccount).edit().putBoolean("stories_" + key, false).apply(); - getNotificationsController().updateServerNotificationsSettings(dialogId, 0); - String name = user == null ? "" : user.first_name.trim(); - int index = name.indexOf(" "); - if (index > 0) { - name = name.substring(0, index); - } - BulletinFactory.of(ContactsActivity.this).createUsersBulletin(Arrays.asList(user), AndroidUtilities.replaceTags(LocaleController.formatString("NotificationsStoryMutedHint", R.string.NotificationsStoryMutedHint, name))).show(); - }) - .addIf(muted, R.drawable.msg_unmute, LocaleController.getString("NotificationsStoryUnmute", R.string.NotificationsStoryUnmute), () -> { - MessagesController.getNotificationsSettings(currentAccount).edit().putBoolean("stories_" + key, true).apply(); - getNotificationsController().updateServerNotificationsSettings(dialogId, 0); - String name = user == null ? "" : user.first_name.trim(); - int index = name.indexOf(" "); - if (index > 0) { - name = name.substring(0, index); - } - BulletinFactory.of(ContactsActivity.this).createUsersBulletin(Arrays.asList(user), AndroidUtilities.replaceTags(LocaleController.formatString("NotificationsStoryUnmutedHint", R.string.NotificationsStoryUnmutedHint, name))).show(); - }); - // if (user.stories_hidden) { + if (listView.getAdapter() == listViewAdapter) { + int section = listViewAdapter.getSectionForPosition(position); + int row = listViewAdapter.getPositionInSectionForPosition(position); + if (Bulletin.getVisibleBulletin() != null) { + Bulletin.getVisibleBulletin().hide(); + } + if (row < 0 || section < 0) { + return false; + } + if (listViewAdapter.hasStories && section == 1 && view instanceof UserCell) { + UserCell userCell = (UserCell) view; + long dialogId = userCell.getDialogId(); + TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(dialogId); + final String key = NotificationsController.getSharedPrefKey(dialogId, 0); + boolean muted = !NotificationsCustomSettingsActivity.areStoriesNotMuted(currentAccount, dialogId); + ItemOptions filterOptions = ItemOptions.makeOptions(ContactsActivity.this, view) + //.setViewAdditionalOffsets(0, AndroidUtilities.dp(8), 0, 0) + .setScrimViewBackground(Theme.createRoundRectDrawable(0, 0, Theme.getColor(Theme.key_windowBackgroundWhite))) + .add(R.drawable.msg_discussion, LocaleController.getString("SendMessage", R.string.SendMessage), () -> { + presentFragment(ChatActivity.of(dialogId)); + }) + .add(R.drawable.msg_openprofile, LocaleController.getString("OpenProfile", R.string.OpenProfile), () -> { + presentFragment(ProfileActivity.of(dialogId)); + }) + .addIf(!muted, R.drawable.msg_mute, LocaleController.getString("NotificationsStoryMute", R.string.NotificationsStoryMute), () -> { + MessagesController.getNotificationsSettings(currentAccount).edit().putBoolean("stories_" + key, false).apply(); + getNotificationsController().updateServerNotificationsSettings(dialogId, 0); + String name = user == null ? "" : user.first_name.trim(); + int index = name.indexOf(" "); + if (index > 0) { + name = name.substring(0, index); + } + BulletinFactory.of(ContactsActivity.this).createUsersBulletin(Arrays.asList(user), AndroidUtilities.replaceTags(LocaleController.formatString("NotificationsStoryMutedHint", R.string.NotificationsStoryMutedHint, name))).show(); + }) + .addIf(muted, R.drawable.msg_unmute, LocaleController.getString("NotificationsStoryUnmute", R.string.NotificationsStoryUnmute), () -> { + MessagesController.getNotificationsSettings(currentAccount).edit().putBoolean("stories_" + key, true).apply(); + getNotificationsController().updateServerNotificationsSettings(dialogId, 0); + String name = user == null ? "" : user.first_name.trim(); + int index = name.indexOf(" "); + if (index > 0) { + name = name.substring(0, index); + } + BulletinFactory.of(ContactsActivity.this).createUsersBulletin(Arrays.asList(user), AndroidUtilities.replaceTags(LocaleController.formatString("NotificationsStoryUnmutedHint", R.string.NotificationsStoryUnmutedHint, name))).show(); + }); + // if (user.stories_hidden) { filterOptions.add(R.drawable.msg_viewintopic, LocaleController.getString("ShowInChats", R.string.ShowInChats), () -> { - // listViewAdapter.removeStory(dialogId); + // listViewAdapter.removeStory(dialogId); getMessagesController().getStoriesController().toggleHidden(dialogId, false, false, true); BulletinFactory.UndoObject undoObject = new BulletinFactory.UndoObject(); undoObject.onUndo = () -> { @@ -682,7 +735,7 @@ public boolean onItemClick(View view, int position) { AndroidUtilities.replaceTags(LocaleController.formatString("StoriesMovedToDialogs", R.string.StoriesMovedToDialogs, ContactsController.formatName(user.first_name, null, 20))), null, undoObject - ).show(); + ).show(); }); // } else { @@ -699,8 +752,23 @@ public boolean onItemClick(View view, int position) { // }); // } - filterOptions.setGravity(Gravity.RIGHT) - .show(); + filterOptions.setGravity(Gravity.RIGHT) + .show(); + return true; + } + } + + if (!returnAsResult && !createSecretChat && view instanceof UserCell) { + UserCell cell = (UserCell) view; + showOrUpdateActionMode(cell); + return true; + } + + if (!returnAsResult && !createSecretChat && view instanceof ProfileSearchCell) { + ProfileSearchCell cell = (ProfileSearchCell) view; + if (cell.getUser() != null && cell.getUser().contact) { + showOrUpdateActionMode(cell); + } return true; } return false; @@ -823,6 +891,115 @@ public ActionBar createActionBar(Context context) { return actionBar; } + public boolean addOrRemoveSelectedContact(UserCell cell) { + long dialogId = cell.getDialogId(); + if (selectedContacts.indexOfKey(dialogId) >= 0) { + selectedContacts.remove(dialogId); + cell.setChecked(false, true); + return false; + } else { + if (cell.getCurrentObject() instanceof TLRPC.User) { + selectedContacts.put(dialogId, (TLRPC.User) cell.getCurrentObject()); + cell.setChecked(true, true); + return true; + } + return false; + } + } + + public boolean addOrRemoveSelectedContact(ProfileSearchCell cell) { + long dialogId = cell.getDialogId(); + if (selectedContacts.indexOfKey(dialogId) >= 0) { + selectedContacts.remove(dialogId); + cell.setChecked(false, true); + return false; + } else { + if (cell.getUser() != null) { + selectedContacts.put(dialogId, cell.getUser()); + cell.setChecked(true, true); + return true; + } + return false; + } + } + + private void showOrUpdateActionMode(Object cell) { + boolean checked; + if (cell instanceof UserCell) { + checked = addOrRemoveSelectedContact((UserCell) cell); + } else if (cell instanceof ProfileSearchCell) { + checked = addOrRemoveSelectedContact((ProfileSearchCell) cell); + } else { + return; + } + boolean updateAnimated = false; + + if (actionBar.isActionModeShowed()) { + if (selectedContacts.isEmpty()) { + hideActionMode(); + return; + } + updateAnimated = true; + } else if (checked) { + AndroidUtilities.hideKeyboard(fragmentView.findFocus()); + actionBar.showActionMode(); + + backDrawable.setRotation(1, true); + } + + selectedContactsCountTextView.setNumber(selectedContacts.size(), updateAnimated); + } + + private void hideActionMode() { + actionBar.hideActionMode(); + int count = listView.getChildCount(); + for (int i = 0; i < count; i++) { + View view = listView.getChildAt(i); + if (view instanceof UserCell) { + UserCell cell = (UserCell) view; + if (selectedContacts.indexOfKey(cell.getDialogId()) >= 0) { + cell.setChecked(false, true); + } + } else if (view instanceof ProfileSearchCell) { + ProfileSearchCell cell = (ProfileSearchCell) view; + if (selectedContacts.indexOfKey(cell.getDialogId()) >= 0) { + cell.setChecked(false, true); + } + } + } + selectedContacts.clear(); + backDrawable.setRotation(0, true); + } + + private void performSelectedContactsDelete() { + AlertDialog.Builder builder = new AlertDialog.Builder(getContext(), getResourceProvider()); + if (selectedContacts.size() == 1) { + builder.setTitle(LocaleController.getString("DeleteContactTitle", R.string.DeleteContactTitle)); + builder.setMessage(LocaleController.getString("DeleteContactSubtitle", R.string.DeleteContactSubtitle)); + } else { + builder.setTitle(LocaleController.formatPluralString("DeleteContactsTitle", selectedContacts.size())); + builder.setMessage(LocaleController.getString("DeleteContactsSubtitle", R.string.DeleteContactsSubtitle)); + } + builder.setPositiveButton(LocaleController.getString("Delete", R.string.Delete), (dialog, which) -> { + ArrayList contacts = new ArrayList<>(selectedContacts.size()); + for (int i = 0; i < selectedContacts.size(); i++) { + long key = selectedContacts.keyAt(i); + TLRPC.User contact = selectedContacts.get(key); + contacts.add(contact); + } + + getContactsController().deleteContactsUndoable(getContext(), ContactsActivity.this, contacts); + + hideActionMode(); + }); + builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), (dialog, which) -> { + dialog.dismiss(); + }); + AlertDialog dialog = builder.create(); + dialog.show(); + dialog.redPositive(); + } + private void didSelectResult(final TLRPC.User user, boolean useAlert, String param) { if (useAlert && selectAlertString != null) { if (getParentActivity() == null) { @@ -939,6 +1116,16 @@ public void afterTextChanged(Editable s) { } } + @Override + public boolean onBackPressed() { + if (actionBar.isActionModeShowed()) { + hideActionMode(); + return false; + } else { + return super.onBackPressed(); + } + } + @Override public void onResume() { super.onResume(); @@ -1080,6 +1267,9 @@ public void didReceivedNotification(int id, int account, Object... args) { } listViewAdapter.notifyDataSetChanged(); } + if (searchListViewAdapter != null && listView.getAdapter() == searchListViewAdapter) { + searchListViewAdapter.searchDialogs(searchQuery); + } } else if (id == NotificationCenter.updateInterfaces) { int mask = (Integer) args[0]; if ((mask & MessagesController.UPDATE_MASK_AVATAR) != 0 || (mask & MessagesController.UPDATE_MASK_NAME) != 0 || (mask & MessagesController.UPDATE_MASK_STATUS) != 0) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/DataAutoDownloadActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/DataAutoDownloadActivity.java index 5ac89edeef0..fe2561f0e3c 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/DataAutoDownloadActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/DataAutoDownloadActivity.java @@ -816,7 +816,7 @@ public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType case 0: { TextCheckCell cell = new TextCheckCell(mContext); cell.setColors(Theme.key_windowBackgroundCheckText, Theme.key_switchTrackBlue, Theme.key_switchTrackBlueChecked, Theme.key_switchTrackBlueThumb, Theme.key_switchTrackBlueThumbChecked); - cell.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); + cell.setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)); cell.setHeight(56); view = cell; break; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/DialogsActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/DialogsActivity.java index 1403e164760..96bcf834d02 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/DialogsActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/DialogsActivity.java @@ -8,6 +8,8 @@ package org.telegram.ui; +import static org.telegram.messenger.AndroidUtilities.dp; + import android.Manifest; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; @@ -72,6 +74,7 @@ import android.widget.FrameLayout; import android.widget.ImageView; import android.widget.LinearLayout; +import android.widget.ScrollView; import android.widget.TextView; import android.widget.Toast; @@ -181,6 +184,7 @@ import org.telegram.ui.Components.FloatingDebug.FloatingDebugController; import org.telegram.ui.Components.FloatingDebug.FloatingDebugProvider; import org.telegram.ui.Components.FolderBottomSheet; +import org.telegram.ui.Components.FolderDrawable; import org.telegram.ui.Components.Forum.ForumUtilities; import org.telegram.ui.Components.FragmentContextView; import org.telegram.ui.Components.ItemOptions; @@ -342,7 +346,7 @@ public boolean isDefaultDialogType() { protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { FrameLayout.LayoutParams lp = (LayoutParams) listView.getLayoutParams(); if (animateStoriesView) { - lp.bottomMargin = -AndroidUtilities.dp(85); + lp.bottomMargin = -dp(85); } else { lp.bottomMargin = 0; } @@ -739,7 +743,7 @@ public int getActionBarFullHeight() { rightSlidingProgress = rightSlidingDialogContainer.openedProgress; } if (hasStories) { - int storiesHeight = AndroidUtilities.dp(DialogStoriesCell.HEIGHT_IN_DP); + int storiesHeight = dp(DialogStoriesCell.HEIGHT_IN_DP); h += storiesHeight * (1f - searchAnimationProgress) * (1f - rightSlidingProgress) * (1f - progressToActionMode); } h += storiesOverscroll; @@ -774,10 +778,10 @@ protected boolean drawChild(Canvas canvas, View child, long drawingTime) { canvas.clipRect(0, -getY() + getActionBarTop() + getActionBarFullHeight(), getMeasuredWidth(), getMeasuredHeight()); if (slideFragmentProgress != 1f) { if (slideFragmentLite) { - canvas.translate((isDrawerTransition ? 1 : -1) * AndroidUtilities.dp(slideAmplitudeDp) * (1f - slideFragmentProgress), 0); + canvas.translate((isDrawerTransition ? 1 : -1) * dp(slideAmplitudeDp) * (1f - slideFragmentProgress), 0); } else { final float s = 1f - 0.05f * (1f - slideFragmentProgress); - canvas.translate((isDrawerTransition ? AndroidUtilities.dp(4) : -AndroidUtilities.dp(4)) * (1f - slideFragmentProgress), 0); + canvas.translate((isDrawerTransition ? dp(4) : -dp(4)) * (1f - slideFragmentProgress), 0); canvas.scale(s, s, isDrawerTransition ? getMeasuredWidth() : 0, -getY() + scrollYOffset + getActionBarFullHeight()); } } @@ -786,10 +790,10 @@ protected boolean drawChild(Canvas canvas, View child, long drawingTime) { } else if (child == actionBar && slideFragmentProgress != 1f) { canvas.save(); if (slideFragmentLite) { - canvas.translate((isDrawerTransition ? 1 : -1) * AndroidUtilities.dp(slideAmplitudeDp) * (1f - slideFragmentProgress), 0); + canvas.translate((isDrawerTransition ? 1 : -1) * dp(slideAmplitudeDp) * (1f - slideFragmentProgress), 0); } else { float s = 1f - 0.05f * (1f - slideFragmentProgress); - canvas.translate((isDrawerTransition ? AndroidUtilities.dp(4) : -AndroidUtilities.dp(4)) * (1f - slideFragmentProgress), 0); + canvas.translate((isDrawerTransition ? dp(4) : -dp(4)) * (1f - slideFragmentProgress), 0); canvas.scale(s, s, isDrawerTransition ? getMeasuredWidth() : 0, (actionBar.getOccupyStatusBar() ? AndroidUtilities.statusBarHeight : 0) + ActionBar.getCurrentActionBarHeight() / 2f); } result = super.drawChild(canvas, child, drawingTime); @@ -817,7 +821,7 @@ protected void dispatchDraw(Canvas canvas) { RecyclerView.ViewHolder archiveHolder = recyclerView.findViewHolderForLayoutPosition(0); if (archiveHolder == null) { fixScrollYAfterArchiveOpened = false; - } else if (archiveHolder.itemView.getBottom() <= recyclerView.getPaddingTop() - AndroidUtilities.dp(DialogStoriesCell.HEIGHT_IN_DP)) { + } else if (archiveHolder.itemView.getBottom() <= recyclerView.getPaddingTop() - dp(DialogStoriesCell.HEIGHT_IN_DP)) { fixScrollYAfterArchiveOpened = false; } else if (archiveHolder.itemView.getTop() >= recyclerView.getPaddingTop()) { fixScrollYAfterArchiveOpened = false; @@ -880,7 +884,7 @@ protected void dispatchDraw(Canvas canvas) { if (searchIsShowed || !searchWasFullyShowed) { canvas.save(); canvas.clipRect(0, top, getMeasuredWidth(), top + actionBarHeight); - float cX = getMeasuredWidth() - AndroidUtilities.dp(24); + float cX = getMeasuredWidth() - dp(24); int statusBarH = actionBar.getOccupyStatusBar() ? AndroidUtilities.statusBarHeight : 0; float cY = statusBarH + (actionBar.getMeasuredHeight() - statusBarH) / 2f; drawBlurCircle(canvas, 0, cX, cY, getMeasuredWidth() * 1.3f * searchAnimationProgress, actionBarSearchPaint, true); @@ -922,7 +926,7 @@ protected void dispatchDraw(Canvas canvas) { tabsYOffset = 0; storiesYOffset = 0; if (hasStories) { - tabsYOffset -= Math.min(AndroidUtilities.dp(DialogStoriesCell.HEIGHT_IN_DP) + scrollYOffset, progressToActionMode * AndroidUtilities.dp(DialogStoriesCell.HEIGHT_IN_DP)); + tabsYOffset -= Math.min(dp(DialogStoriesCell.HEIGHT_IN_DP) + scrollYOffset, progressToActionMode * dp(DialogStoriesCell.HEIGHT_IN_DP)); storiesYOffset = tabsYOffset; } if ((filtersTabAnimator != null || rightSlidingDialogContainer.hasFragment())) { @@ -993,10 +997,10 @@ protected void dispatchDraw(Canvas canvas) { canvas.translate(fragmentContextView.getX(), fragmentContextView.getY()); if (slideFragmentProgress != 1f) { if (slideFragmentLite) { - canvas.translate((isDrawerTransition ? 1 : -1) * AndroidUtilities.dp(slideAmplitudeDp) * (1f - slideFragmentProgress), 0); + canvas.translate((isDrawerTransition ? 1 : -1) * dp(slideAmplitudeDp) * (1f - slideFragmentProgress), 0); } else { final float s = 1f - 0.05f * (1f - slideFragmentProgress); - canvas.translate((isDrawerTransition ? AndroidUtilities.dp(4) : -AndroidUtilities.dp(4)) * (1f - slideFragmentProgress), 0); + canvas.translate((isDrawerTransition ? dp(4) : -dp(4)) * (1f - slideFragmentProgress), 0); canvas.scale(s, 1f, isDrawerTransition ? getMeasuredWidth() : 0, fragmentContextView.getY()); } } @@ -1046,7 +1050,7 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { measureChildWithMargins(commentView, widthMeasureSpec, 0, heightMeasureSpec, 0); Object tag = commentView.getTag(); if (tag != null && tag.equals(2)) { - if (keyboardSize <= AndroidUtilities.dp(20) && !AndroidUtilities.isInMultiwindow) { + if (keyboardSize <= dp(20) && !AndroidUtilities.isInMultiwindow) { heightSize -= commentView.getEmojiPadding(); } inputFieldHeight = commentView.getMeasuredHeight(); @@ -1079,21 +1083,21 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { if (child instanceof DatabaseMigrationHint) { int contentWidthSpec = View.MeasureSpec.makeMeasureSpec(widthSize, View.MeasureSpec.EXACTLY); int h = View.MeasureSpec.getSize(heightMeasureSpec) + keyboardSize; - int contentHeightSpec = View.MeasureSpec.makeMeasureSpec(Math.max(AndroidUtilities.dp(10), h - inputFieldHeight + AndroidUtilities.dp(2) - actionBar.getMeasuredHeight()), View.MeasureSpec.EXACTLY); + int contentHeightSpec = View.MeasureSpec.makeMeasureSpec(Math.max(dp(10), h - inputFieldHeight + dp(2) - actionBar.getMeasuredHeight()), View.MeasureSpec.EXACTLY); child.measure(contentWidthSpec, contentHeightSpec); } else if (child instanceof ViewPage) { int contentWidthSpec = View.MeasureSpec.makeMeasureSpec(widthSize, View.MeasureSpec.EXACTLY); - int h = heightSize - inputFieldHeight + AndroidUtilities.dp(2) - topPadding; + int h = heightSize - inputFieldHeight + dp(2) - topPadding; if (hasStories || (filterTabsView != null && filterTabsView.getVisibility() == VISIBLE)) { if (filterTabsView != null && filterTabsView.getVisibility() == VISIBLE) { - h -= AndroidUtilities.dp(44); + h -= dp(44); } if (rightSlidingDialogContainer.hasFragment()) { if (filterTabsView != null && filterTabsView.getVisibility() == VISIBLE) { - h += AndroidUtilities.dp(44); + h += dp(44); } if (hasStories) { - h += AndroidUtilities.dp(DialogStoriesCell.HEIGHT_IN_DP); + h += dp(DialogStoriesCell.HEIGHT_IN_DP); } if (dialogsHintCell != null && dialogsHintCell.getVisibility() == View.VISIBLE) { h += dialogsHintCell.getMeasuredHeight(); @@ -1117,19 +1121,19 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int transitionPadding = ((isSlideBackTransition || isDrawerTransition) ? (int) (h * 0.05f) : 0); h += transitionPadding; child.setPadding(child.getPaddingLeft(), child.getPaddingTop(), child.getPaddingRight(), transitionPadding); - child.measure(contentWidthSpec, View.MeasureSpec.makeMeasureSpec(Math.max(AndroidUtilities.dp(10), h), View.MeasureSpec.EXACTLY)); + child.measure(contentWidthSpec, View.MeasureSpec.makeMeasureSpec(Math.max(dp(10), h), View.MeasureSpec.EXACTLY)); child.setPivotX(child.getMeasuredWidth() / 2); } else if (child == searchViewPager) { searchViewPager.setTranslationY(searchViewPagerTranslationY); int contentWidthSpec = View.MeasureSpec.makeMeasureSpec(widthSize, View.MeasureSpec.EXACTLY); int h = View.MeasureSpec.getSize(heightMeasureSpec) + keyboardSize; - int contentHeightSpec = View.MeasureSpec.makeMeasureSpec(Math.max(AndroidUtilities.dp(10), h - inputFieldHeight + AndroidUtilities.dp(2) - (onlySelect && initialDialogsType != DIALOGS_TYPE_FORWARD ? 0 : actionBar.getMeasuredHeight()) - topPadding) - (searchTabsView == null ? 0 : AndroidUtilities.dp(44)), View.MeasureSpec.EXACTLY); + int contentHeightSpec = View.MeasureSpec.makeMeasureSpec(Math.max(dp(10), h - inputFieldHeight + dp(2) - (onlySelect && initialDialogsType != DIALOGS_TYPE_FORWARD ? 0 : actionBar.getMeasuredHeight()) - topPadding) - (searchTabsView == null ? 0 : dp(44)), View.MeasureSpec.EXACTLY); child.measure(contentWidthSpec, contentHeightSpec); child.setPivotX(child.getMeasuredWidth() / 2); } else if (commentView != null && commentView.isPopupView(child)) { if (AndroidUtilities.isInMultiwindow) { if (AndroidUtilities.isTablet()) { - child.measure(View.MeasureSpec.makeMeasureSpec(widthSize, View.MeasureSpec.EXACTLY), View.MeasureSpec.makeMeasureSpec(Math.min(AndroidUtilities.dp(320), heightSize - inputFieldHeight - AndroidUtilities.statusBarHeight + getPaddingTop()), View.MeasureSpec.EXACTLY)); + child.measure(View.MeasureSpec.makeMeasureSpec(widthSize, View.MeasureSpec.EXACTLY), View.MeasureSpec.makeMeasureSpec(Math.min(dp(320), heightSize - inputFieldHeight - AndroidUtilities.statusBarHeight + getPaddingTop()), View.MeasureSpec.EXACTLY)); } else { child.measure(View.MeasureSpec.makeMeasureSpec(widthSize, View.MeasureSpec.EXACTLY), View.MeasureSpec.makeMeasureSpec(heightSize - inputFieldHeight - AndroidUtilities.statusBarHeight + getPaddingTop(), View.MeasureSpec.EXACTLY)); } @@ -1141,7 +1145,7 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int transitionPadding = ((isSlideBackTransition || isDrawerTransition) ? (int) (h * 0.05f) : 0); h += transitionPadding; rightSlidingDialogContainer.setTransitionPaddingBottom(transitionPadding); - child.measure(widthMeasureSpec, View.MeasureSpec.makeMeasureSpec(Math.max(AndroidUtilities.dp(10), h), View.MeasureSpec.EXACTLY)); + child.measure(widthMeasureSpec, View.MeasureSpec.makeMeasureSpec(Math.max(dp(10), h), View.MeasureSpec.EXACTLY)); } else { measureChildWithMargins(child, widthMeasureSpec, 0, heightMeasureSpec, 0); } @@ -1166,7 +1170,7 @@ protected void onLayout(boolean changed, int l, int t, int r, int b) { Object tag = commentView != null ? commentView.getTag() : null; int keyboardSize = measureKeyboardHeight(); if (tag != null && tag.equals(2)) { - paddingBottom = keyboardSize <= AndroidUtilities.dp(20) && !AndroidUtilities.isInMultiwindow ? commentView.getEmojiPadding() : 0; + paddingBottom = keyboardSize <= dp(20) && !AndroidUtilities.isInMultiwindow ? commentView.getEmojiPadding() : 0; } else { paddingBottom = 0; } @@ -1224,20 +1228,20 @@ protected void onLayout(boolean changed, int l, int t, int r, int b) { if (commentView != null && commentView.isPopupView(child)) { if (AndroidUtilities.isInMultiwindow) { - childTop = commentView.getTop() - child.getMeasuredHeight() + AndroidUtilities.dp(1); + childTop = commentView.getTop() - child.getMeasuredHeight() + dp(1); } else { childTop = commentView.getBottom(); } } else if (child == filterTabsView || child == searchTabsView || child == filtersView || child == dialogStoriesCell) { childTop = actionBar.getMeasuredHeight(); if (hasStories && child == filterTabsView) { - childTop += AndroidUtilities.dp(DialogStoriesCell.HEIGHT_IN_DP); + childTop += dp(DialogStoriesCell.HEIGHT_IN_DP); } if (child == dialogStoriesCell && dialogStoriesCell.getPremiumHint() != null) { - dialogStoriesCell.getPremiumHint().layout(childLeft, childTop - AndroidUtilities.dp(24 + 8 + 22) + height, childLeft + width, childTop - AndroidUtilities.dp(24 + 8 + 22) + height + dialogStoriesCell.getPremiumHint().getMeasuredHeight()); + dialogStoriesCell.getPremiumHint().layout(childLeft, childTop - dp(24 + 8 + 22) + height, childLeft + width, childTop - dp(24 + 8 + 22) + height + dialogStoriesCell.getPremiumHint().getMeasuredHeight()); } } else if (child == searchViewPager) { - childTop = (onlySelect && initialDialogsType != DIALOGS_TYPE_FORWARD ? 0 : actionBar.getMeasuredHeight()) + topPadding + (searchTabsView == null ? 0 : AndroidUtilities.dp(44)); + childTop = (onlySelect && initialDialogsType != DIALOGS_TYPE_FORWARD ? 0 : actionBar.getMeasuredHeight()) + topPadding + (searchTabsView == null ? 0 : dp(44)); } else if (child instanceof DatabaseMigrationHint) { childTop = actionBar.getMeasuredHeight(); } else if (child instanceof ViewPage) { @@ -1245,7 +1249,7 @@ protected void onLayout(boolean changed, int l, int t, int r, int b) { if (hasStories || (filterTabsView != null && filterTabsView.getVisibility() == VISIBLE)) { childTop = 0; if (filterTabsView != null && filterTabsView.getVisibility() == VISIBLE) { - childTop += AndroidUtilities.dp(44); + childTop += dp(44); } } else { childTop = actionBar.getMeasuredHeight(); @@ -1542,7 +1546,7 @@ protected void drawList(Canvas blurCanvas, boolean top) { if (viewPages[i] != null && viewPages[i].getVisibility() == View.VISIBLE) { for (int j = 0; j < viewPages[i].listView.getChildCount(); j++) { View child = viewPages[i].listView.getChildAt(j); - if (child.getY() < viewPages[i].listView.blurTopPadding + AndroidUtilities.dp(100)) { + if (child.getY() < viewPages[i].listView.blurTopPadding + dp(100)) { int restore = blurCanvas.save(); blurCanvas.translate(viewPages[i].getX(), viewPages[i].getY() + viewPages[i].listView.getY() + child.getY()); if (child instanceof DialogCell) { @@ -1598,18 +1602,18 @@ private void updateStoriesViewAlpha(float alpha) { float containersAlpha; if (hasStories || animateToHasStories) { - float p = Utilities.clamp(-scrollYOffset / AndroidUtilities.dp(DialogStoriesCell.HEIGHT_IN_DP), 1f, 0f); + float p = Utilities.clamp(-scrollYOffset / dp(DialogStoriesCell.HEIGHT_IN_DP), 1f, 0f); if (progressToActionMode == 1f) { p = 1f; } float pHalf = Utilities.clamp(p / 0.5f, 1f, 0f); dialogStoriesCell.setClipTop(0); if (!hasStories && animateToHasStories) { - dialogStoriesCell.setTranslationY(-AndroidUtilities.dp(DialogStoriesCell.HEIGHT_IN_DP) - AndroidUtilities.dp(8)); + dialogStoriesCell.setTranslationY(-dp(DialogStoriesCell.HEIGHT_IN_DP) - dp(8)); dialogStoriesCell.setProgressToCollapse(1f); containersAlpha = 1f - progressToDialogStoriesCell; } else { - dialogStoriesCell.setTranslationY(scrollYOffset + storiesYOffset + storiesOverscroll / 2f - AndroidUtilities.dp(8)); + dialogStoriesCell.setTranslationY(scrollYOffset + storiesYOffset + storiesOverscroll / 2f - dp(8)); dialogStoriesCell.setProgressToCollapse(p, !rightSlidingDialogContainer.hasFragment()); if (!animateToHasStories) { containersAlpha = 1f - progressToDialogStoriesCell; @@ -1620,7 +1624,7 @@ private void updateStoriesViewAlpha(float alpha) { actionBar.setTranslationY(0); } else { if (hasOnlySlefStories) { - dialogStoriesCell.setTranslationY(-AndroidUtilities.dp(DialogStoriesCell.HEIGHT_IN_DP) + scrollYOffset - AndroidUtilities.dp(8)); + dialogStoriesCell.setTranslationY(-dp(DialogStoriesCell.HEIGHT_IN_DP) + scrollYOffset - dp(8)); dialogStoriesCell.setProgressToCollapse(1f); dialogStoriesCell.setClipTop((int) (AndroidUtilities.statusBarHeight - dialogStoriesCell.getY())); } @@ -1629,7 +1633,7 @@ private void updateStoriesViewAlpha(float alpha) { } if (containersAlpha != 1f) { actionBar.getTitlesContainer().setPivotY(AndroidUtilities.statusBarHeight + ActionBar.getCurrentActionBarHeight() / 2f); - actionBar.getTitlesContainer().setPivotX(AndroidUtilities.dp(72)); + actionBar.getTitlesContainer().setPivotX(dp(72)); float s = 0.8f + 0.2f * containersAlpha; actionBar.getTitlesContainer().setScaleY(s); actionBar.getTitlesContainer().setScaleX(s); @@ -1670,7 +1674,7 @@ public class DialogsRecyclerView extends BlurredRecyclerView implements StoriesL public DialogsRecyclerView(Context context, ViewPage page) { super(context); parentPage = page; - additionalClipBottom = AndroidUtilities.dp(200); + additionalClipBottom = dp(200); } public void prepareSelectorForAnimation() { @@ -1742,15 +1746,15 @@ public void onDraw(Canvas canvas) { protected void dispatchDraw(Canvas canvas) { canvas.save(); if (rightFragmentOpenedProgress > 0) { - canvas.clipRect(0, 0, AndroidUtilities.lerp(getMeasuredWidth(), AndroidUtilities.dp(RightSlidingDialogContainer.getRightPaddingSize()), rightFragmentOpenedProgress), getMeasuredHeight()); + canvas.clipRect(0, 0, AndroidUtilities.lerp(getMeasuredWidth(), dp(RightSlidingDialogContainer.getRightPaddingSize()), rightFragmentOpenedProgress), getMeasuredHeight()); paint.setColor(Theme.getColor(Theme.key_chats_pinnedOverlay)); paint.setAlpha((int) (paint.getAlpha() * rightFragmentOpenedProgress)); - canvas.drawRect(0, 0, AndroidUtilities.dp(RightSlidingDialogContainer.getRightPaddingSize()), getMeasuredHeight(), paint); + canvas.drawRect(0, 0, dp(RightSlidingDialogContainer.getRightPaddingSize()), getMeasuredHeight(), paint); int alpha = Theme.dividerPaint.getAlpha(); Theme.dividerPaint.setAlpha((int) (rightFragmentOpenedProgress * alpha)); - canvas.drawRect(AndroidUtilities.dp(RightSlidingDialogContainer.getRightPaddingSize()), 0, AndroidUtilities.dp(RightSlidingDialogContainer.getRightPaddingSize()) - 1, getMeasuredHeight(), Theme.dividerPaint); + canvas.drawRect(dp(RightSlidingDialogContainer.getRightPaddingSize()), 0, dp(RightSlidingDialogContainer.getRightPaddingSize()) - 1, getMeasuredHeight(), Theme.dividerPaint); Theme.dividerPaint.setAlpha(alpha); } @@ -1864,13 +1868,13 @@ protected void dispatchDraw(Canvas canvas) { if (hideProgrss == 1f) { lastDrawSelectorY = Integer.MIN_VALUE; } - float xOffset = -AndroidUtilities.dp(5) * hideProgrss; - AndroidUtilities.rectTmp.set(-AndroidUtilities.dp(4) + xOffset, lastDrawSelectorY - AndroidUtilities.dp(1), AndroidUtilities.dp(4) + xOffset, lastDrawSelectorY + selectedCell.avatarImage.getImageHeight() + AndroidUtilities.dp(1)); + float xOffset = -dp(5) * hideProgrss; + AndroidUtilities.rectTmp.set(-dp(4) + xOffset, lastDrawSelectorY - dp(1), dp(4) + xOffset, lastDrawSelectorY + selectedCell.avatarImage.getImageHeight() + dp(1)); if (selectorPaint == null) { selectorPaint = new Paint(Paint.ANTI_ALIAS_FLAG); } selectorPaint.setColor(Theme.getColor(Theme.key_featuredStickers_addButton)); - canvas.drawRoundRect(AndroidUtilities.rectTmp, AndroidUtilities.dp(4), AndroidUtilities.dp(4), selectorPaint); + canvas.drawRoundRect(AndroidUtilities.rectTmp, dp(4), dp(4), selectorPaint); canvas.restore(); } else { lastDrawSelectorY = Integer.MIN_VALUE; @@ -2001,7 +2005,7 @@ protected void onMeasure(int widthSpec, int heightSpec) { t = inPreviewMode && Build.VERSION.SDK_INT >= 21 ? AndroidUtilities.statusBarHeight : 0; } if (hasStories && !actionModeFullyShowed) { - t += AndroidUtilities.dp(DialogStoriesCell.HEIGHT_IN_DP); + t += dp(DialogStoriesCell.HEIGHT_IN_DP); } additionalPadding = 0; if (authHintCell != null && authHintCellProgress != 0 && !authHintCellAnimating) { @@ -2012,7 +2016,7 @@ protected void onMeasure(int widthSpec, int heightSpec) { setTopGlowOffset(t); setPadding(0, t, 0, 0); if (hasStories) { - parentPage.progressView.setPaddingTop(t - AndroidUtilities.dp(DialogStoriesCell.HEIGHT_IN_DP)); + parentPage.progressView.setPaddingTop(t - dp(DialogStoriesCell.HEIGHT_IN_DP)); } else { parentPage.progressView.setPaddingTop(t); } @@ -2069,7 +2073,7 @@ private void toggleArchiveHidden(boolean action, DialogCell dialogCell) { int offset = (dialogCell.getMeasuredHeight() + (dialogCell.getTop() - getPaddingTop())); if (hasStories && !dialogStoriesCell.isExpanded()) { fixScrollYAfterArchiveOpened = true; - offset += AndroidUtilities.dp(DialogStoriesCell.HEIGHT_IN_DP); + offset += dp(DialogStoriesCell.HEIGHT_IN_DP); } smoothScrollBy(0, offset, CubicBezierInterpolator.EASE_OUT); if (action) { @@ -2164,7 +2168,7 @@ public boolean onTouchEvent(MotionEvent e) { int pTop = getPaddingTop(); DialogCell view = findArchiveDialogCell(parentPage); if (view != null) { - int height = (int) (AndroidUtilities.dp(SharedConfig.useThreeLinesLayout ? 78 : 72) * PullForegroundDrawable.SNAP_HEIGHT); + int height = (int) (dp(SharedConfig.useThreeLinesLayout ? 78 : 72) * PullForegroundDrawable.SNAP_HEIGHT); int diff = (view.getTop() - pTop) + view.getMeasuredHeight(); long pullingTime = System.currentTimeMillis() - startArchivePullingTime; @@ -2265,7 +2269,7 @@ public void setAnimationSupportView(RecyclerListView animationSupportListView, f } } } - if (selectedDialogView != null && getAdapter().getItemCount() * AndroidUtilities.dp(70) > getMeasuredHeight() && (anchorView.getTop() - getPaddingTop()) > (getMeasuredHeight() - getPaddingTop()) / 2f) { + if (selectedDialogView != null && getAdapter().getItemCount() * dp(70) > getMeasuredHeight() && (anchorView.getTop() - getPaddingTop()) > (getMeasuredHeight() - getPaddingTop()) / 2f) { anchorView = selectedDialogView; } this.animationSupportListView = animationSupportListView; @@ -2290,7 +2294,7 @@ public void setAnimationSupportView(RecyclerListView animationSupportListView, f int p = adapter.findDialogPosition(anchorView.getDialogId()); int offset = (int) (anchorView.getTop() - getPaddingTop()); if (backward && hasStories) { - offset += AndroidUtilities.dp(DialogStoriesCell.HEIGHT_IN_DP); + offset += dp(DialogStoriesCell.HEIGHT_IN_DP); } if (p >= 0) { ((LinearLayoutManager) getLayoutManager()).scrollToPositionWithOffset(p, offset); @@ -2473,7 +2477,7 @@ public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) { parentPage.updateList(true); if (!SharedConfig.archiveHidden && parentPage.layoutManager.findFirstVisibleItemPosition() == 0) { disableActionBarScrolling = true; - parentPage.listView.smoothScrollBy(0, -AndroidUtilities.dp(SharedConfig.useThreeLinesLayout ? 78 : 72)); + parentPage.listView.smoothScrollBy(0, -dp(SharedConfig.useThreeLinesLayout ? 78 : 72)); } } ArrayList dialogs = getDialogsArray(currentAccount, parentPage.dialogsType, folderId, false); @@ -2766,11 +2770,11 @@ public void updateStatus(TLRPC.User user, boolean animated) { } else if (user != null && MessagesController.getInstance(currentAccount).isPremiumUser(user)) { if (premiumStar == null) { premiumStar = getContext().getResources().getDrawable(R.drawable.msg_premium_liststar).mutate(); - premiumStar = new AnimatedEmojiDrawable.WrapSizeDrawable(premiumStar, AndroidUtilities.dp(18), AndroidUtilities.dp(18)) { + premiumStar = new AnimatedEmojiDrawable.WrapSizeDrawable(premiumStar, dp(18), dp(18)) { @Override public void draw(@NonNull Canvas canvas) { canvas.save(); - canvas.translate(AndroidUtilities.dp(-2), AndroidUtilities.dp(1)); + canvas.translate(dp(-2), dp(1)); super.draw(canvas); canvas.restore(); } @@ -2968,7 +2972,7 @@ public View createView(final Context context) { proxyItem = menu.addItem(2, proxyDrawable); proxyItem.setContentDescription(LocaleController.getString("ProxySettings", R.string.ProxySettings)); - passcodeDrawable = new RLottieDrawable(R.raw.passcode_lock_close, "passcode_lock_close", AndroidUtilities.dp(28), AndroidUtilities.dp(28), true, null); + passcodeDrawable = new RLottieDrawable(R.raw.passcode_lock_close, "passcode_lock_close", dp(28), dp(28), true, null); passcodeItem = menu.addItem(1, passcodeDrawable); passcodeItem.setContentDescription(LocaleController.getString("AccDescrPasscodeLock", R.string.AccDescrPasscodeLock)); @@ -2991,13 +2995,13 @@ public void onPreToggleSearch() { speedItem = new ActionBarMenuItem(context, menu, Theme.getColor(Theme.key_actionBarActionModeDefaultSelector), Theme.getColor(Theme.key_actionBarActionModeDefaultIcon)); speedItem.setIcon(R.drawable.avd_speed); speedItem.getIconView().setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_actionBarActionModeDefaultIcon), PorterDuff.Mode.SRC_IN)); - speedItem.setTranslationX(AndroidUtilities.dp(32)); + speedItem.setTranslationX(dp(32)); speedItem.setAlpha(0f); speedItem.setOnClickListener(v -> showDialog(new PremiumFeatureBottomSheet(DialogsActivity.this, PremiumPreviewFragment.PREMIUM_FEATURE_DOWNLOAD_SPEED, true))); speedItem.setClickable(false); speedItem.setFixBackground(true); - FrameLayout.LayoutParams speedParams = new FrameLayout.LayoutParams(AndroidUtilities.dp(42), ViewGroup.LayoutParams.MATCH_PARENT); - speedParams.leftMargin = speedParams.rightMargin = AndroidUtilities.dp(14 + 24); + FrameLayout.LayoutParams speedParams = new FrameLayout.LayoutParams(dp(42), ViewGroup.LayoutParams.MATCH_PARENT); + speedParams.leftMargin = speedParams.rightMargin = dp(14 + 24); speedParams.gravity = Gravity.RIGHT; searchContainer.addView(speedItem, speedParams); searchItem.setSearchAdditionalButton(speedItem); @@ -3081,7 +3085,7 @@ public void onSearchCollapse() { floatingButton2Container.setVisibility(storiesEnabled ? View.VISIBLE : View.GONE); } floatingHidden = true; - floatingButtonTranslation = AndroidUtilities.dp(100); + floatingButtonTranslation = dp(100); floatingButtonHideProgress = 1f; updateFloatingButtonOffset(); } @@ -3196,7 +3200,7 @@ public boolean canToggleSearch() { if (folderId != 0) { actionBar.setTitle(LocaleController.getString("ArchivedChats", R.string.ArchivedChats)); } else { - statusDrawable = new AnimatedEmojiDrawable.SwapAnimatedEmojiDrawable(null, AndroidUtilities.dp(26)); + statusDrawable = new AnimatedEmojiDrawable.SwapAnimatedEmojiDrawable(null, dp(26)); statusDrawable.center = true; if (BuildVars.DEBUG_VERSION) { actionBar.setTitle(LocaleController.getString("AppNameBeta", R.string.AppNameBeta), statusDrawable); @@ -3455,7 +3459,7 @@ public boolean didSelectTab(FilterTabsView.TabView tabView, boolean selected) { } filterOptions = ItemOptions.makeOptions(DialogsActivity.this, tabView) - .setScrimViewBackground(Theme.createRoundRectDrawable(AndroidUtilities.dp(6), 0, Theme.getColor(Theme.key_actionBarDefault))) + .setScrimViewBackground(Theme.createRoundRectDrawable(dp(6), 0, Theme.getColor(Theme.key_actionBarDefault))) .addIf(getMessagesController().getDialogFilters().size() > 1, R.drawable.tabs_reorder, LocaleController.getString("FilterReorder", R.string.FilterReorder), () -> { resetScroll(); filterTabsView.setIsEditing(true); @@ -3489,7 +3493,7 @@ public boolean didSelectTab(FilterTabsView.TabView tabView, boolean selected) { showDeleteAlert(dialogFilter); }) .setGravity(Gravity.LEFT) - .translate(AndroidUtilities.dp(-8), AndroidUtilities.dp(-10)) + .translate(dp(-8), dp(-10)) .show(); return true; @@ -3508,12 +3512,12 @@ public void onDeletePressed(int id) { } if (allowSwitchAccount && UserConfig.getActivatedAccountsCount() > 1) { - switchItem = menu.addItemWithWidth(1, 0, AndroidUtilities.dp(56)); + switchItem = menu.addItemWithWidth(1, 0, dp(56)); AvatarDrawable avatarDrawable = new AvatarDrawable(); - avatarDrawable.setTextSize(AndroidUtilities.dp(12)); + avatarDrawable.setTextSize(dp(12)); BackupImageView imageView = new BackupImageView(context); - imageView.setRoundRadius(AndroidUtilities.dp(18)); + imageView.setRoundRadius(dp(18)); switchItem.addView(imageView, LayoutHelper.createFrame(36, 36, Gravity.CENTER)); TLRPC.User user = getUserConfig().getCurrentUser(); @@ -3527,7 +3531,7 @@ public void onDeletePressed(int id) { if (u != null) { AccountSelectCell cell = new AccountSelectCell(context, false); cell.setAccount(a, true); - switchItem.addSubItem(10 + a, cell, AndroidUtilities.dp(230), AndroidUtilities.dp(48)); + switchItem.addSubItem(10 + a, cell, dp(230), dp(48)); } } } @@ -3695,7 +3699,7 @@ public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler, RecyclerVi int pTop = viewPage.listView.getPaddingTop(); int realTopPadding = pTop; if (hasStories && !rightSlidingDialogContainer.hasFragment() && !fixScrollYAfterArchiveOpened) { - pTop -= AndroidUtilities.dp(DialogStoriesCell.HEIGHT_IN_DP); + pTop -= dp(DialogStoriesCell.HEIGHT_IN_DP); } boolean hasHidenArchive = !fixScrollYAfterArchiveOpened && viewPage.dialogsType == DIALOGS_TYPE_DEFAULT && !onlySelect && folderId == 0 && getMessagesController().hasHiddenArchive() && viewPage.archivePullViewState == ARCHIVE_ITEM_STATE_HIDDEN; if ((hasHidenArchive || (hasStories && !rightSlidingDialogContainer.hasFragment())) && dy < 0) { @@ -3703,21 +3707,21 @@ public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler, RecyclerVi int currentPosition = viewPage.layoutManager.findFirstVisibleItemPosition(); if (currentPosition == 0) { View view = viewPage.layoutManager.findViewByPosition(currentPosition); - if (view != null && (view.getBottom() - pTop) <= AndroidUtilities.dp(1)) { + if (view != null && (view.getBottom() - pTop) <= dp(1)) { currentPosition = 1; } } if (!isDragging) { View view = viewPage.layoutManager.findViewByPosition(currentPosition); if (view != null && currentPosition < 10) { - int dialogHeight = AndroidUtilities.dp(SharedConfig.useThreeLinesLayout ? 78 : 72) + 1; + int dialogHeight = dp(SharedConfig.useThreeLinesLayout ? 78 : 72) + 1; int viewsH = 0; for (int i = hasHidenArchive ? 1 : 0; i < currentPosition; i++) { viewsH += viewPage.dialogsAdapter.getItemHeight(i); } int canScrollDy = -(view.getTop() - pTop) + viewsH; if (hasStories && (viewPage.scroller.isRunning() || dialogStoriesCell.isExpanded()) && !rightSlidingDialogContainer.hasFragment() && !fixScrollYAfterArchiveOpened) { - canScrollDy += AndroidUtilities.dp(DialogStoriesCell.HEIGHT_IN_DP); + canScrollDy += dp(DialogStoriesCell.HEIGHT_IN_DP); } int positiveDy = Math.abs(dy); if (canScrollDy < positiveDy) { @@ -3773,7 +3777,7 @@ public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler, RecyclerVi if (currentPosition == 0) { firstView = viewPage.layoutManager.findViewByPosition(currentPosition); } - if (currentPosition == 0 && firstView != null && (firstView.getBottom() - pTop) >= AndroidUtilities.dp(4)) { + if (currentPosition == 0 && firstView != null && (firstView.getBottom() - pTop) >= dp(4)) { if (startArchivePullingTime == 0) { startArchivePullingTime = System.currentTimeMillis(); } @@ -3783,7 +3787,7 @@ public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler, RecyclerVi } } if (hasStories && !rightSlidingDialogContainer.hasFragment() && !fixScrollYAfterArchiveOpened) { - pTop += AndroidUtilities.dp(DialogStoriesCell.HEIGHT_IN_DP); + pTop += dp(DialogStoriesCell.HEIGHT_IN_DP); } float k = 1f + ((firstView.getTop() - pTop) / (float) firstView.getMeasuredHeight()); if (k > 1f) { @@ -4439,14 +4443,14 @@ public void onLongClickRelease() { }); if (Build.VERSION.SDK_INT >= 21) { StateListAnimator animator = new StateListAnimator(); - animator.addState(new int[]{android.R.attr.state_pressed}, ObjectAnimator.ofFloat(floatingButton2Container, View.TRANSLATION_Z, AndroidUtilities.dp(2), AndroidUtilities.dp(4)).setDuration(200)); - animator.addState(new int[]{}, ObjectAnimator.ofFloat(floatingButton2Container, View.TRANSLATION_Z, AndroidUtilities.dp(4), AndroidUtilities.dp(2)).setDuration(200)); + animator.addState(new int[]{android.R.attr.state_pressed}, ObjectAnimator.ofFloat(floatingButton2Container, View.TRANSLATION_Z, dp(2), dp(4)).setDuration(200)); + animator.addState(new int[]{}, ObjectAnimator.ofFloat(floatingButton2Container, View.TRANSLATION_Z, dp(4), dp(2)).setDuration(200)); floatingButton2Container.setStateListAnimator(animator); floatingButton2Container.setOutlineProvider(new ViewOutlineProvider() { @SuppressLint("NewApi") @Override public void getOutline(View view, Outline outline) { - outline.setOval(0, 0, AndroidUtilities.dp(36), AndroidUtilities.dp(36)); + outline.setOval(0, 0, dp(36), dp(36)); } }); } @@ -4464,7 +4468,7 @@ public void getOutline(View view, Outline outline) { floating2ProgressView.setScaleY(0.1f); floating2ProgressView.setAlpha(0f); floating2ProgressView.setVisibility(View.GONE); - floating2ProgressView.setSize(AndroidUtilities.dp(22)); + floating2ProgressView.setSize(dp(22)); floatingButton2Container.addView(floating2ProgressView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); } @@ -4563,23 +4567,23 @@ public StoryRecorder.SourceView getView(long dialogId) { floatingButton.setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_chats_actionIcon), PorterDuff.Mode.MULTIPLY)); if (Build.VERSION.SDK_INT >= 21) { StateListAnimator animator = new StateListAnimator(); - animator.addState(new int[]{android.R.attr.state_pressed}, ObjectAnimator.ofFloat(floatingButtonContainer, View.TRANSLATION_Z, AndroidUtilities.dp(2), AndroidUtilities.dp(4)).setDuration(200)); - animator.addState(new int[]{}, ObjectAnimator.ofFloat(floatingButtonContainer, View.TRANSLATION_Z, AndroidUtilities.dp(4), AndroidUtilities.dp(2)).setDuration(200)); + animator.addState(new int[]{android.R.attr.state_pressed}, ObjectAnimator.ofFloat(floatingButtonContainer, View.TRANSLATION_Z, dp(2), dp(4)).setDuration(200)); + animator.addState(new int[]{}, ObjectAnimator.ofFloat(floatingButtonContainer, View.TRANSLATION_Z, dp(4), dp(2)).setDuration(200)); floatingButtonContainer.setStateListAnimator(animator); floatingButtonContainer.setOutlineProvider(new ViewOutlineProvider() { @SuppressLint("NewApi") @Override public void getOutline(View view, Outline outline) { - outline.setOval(0, 0, AndroidUtilities.dp(56), AndroidUtilities.dp(56)); + outline.setOval(0, 0, dp(56), dp(56)); } }); } - Drawable drawable = Theme.createSimpleSelectorCircleDrawable(AndroidUtilities.dp(56), Theme.getColor(Theme.key_chats_actionBackground), Theme.getColor(Theme.key_chats_actionPressedBackground)); + Drawable drawable = Theme.createSimpleSelectorCircleDrawable(dp(56), Theme.getColor(Theme.key_chats_actionBackground), Theme.getColor(Theme.key_chats_actionPressedBackground)); if (Build.VERSION.SDK_INT < 21) { Drawable shadowDrawable = context.getResources().getDrawable(R.drawable.floating_shadow).mutate(); shadowDrawable.setColorFilter(new PorterDuffColorFilter(0xff000000, PorterDuff.Mode.MULTIPLY)); CombinedDrawable combinedDrawable = new CombinedDrawable(shadowDrawable, drawable, 0, 0); - combinedDrawable.setIconSize(AndroidUtilities.dp(56), AndroidUtilities.dp(56)); + combinedDrawable.setIconSize(dp(56), dp(56)); drawable = combinedDrawable; } floatingButtonContainer.addView(floatingButton, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); @@ -4647,7 +4651,7 @@ public void setTranslationY(float translationY) { commentView.forceSmoothKeyboard(true); commentView.setAllowStickersAndGifs(true, false, false); commentView.setForceShowSendButton(true, false); - commentView.setPadding(0, 0, AndroidUtilities.dp(20), 0); + commentView.setPadding(0, 0, dp(20), 0); commentView.setVisibility(View.GONE); commentView.getSendButton().setAlpha(0); commentViewBg = new View(getParentActivity()); @@ -4805,27 +4809,27 @@ public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) { writeButtonContainer.setAlpha(0.0f); contentView.addView(writeButtonContainer, LayoutHelper.createFrame(60, 60, Gravity.RIGHT | Gravity.BOTTOM, 0, 0, 6, 10)); - textPaint.setTextSize(AndroidUtilities.dp(12)); + textPaint.setTextSize(dp(12)); textPaint.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); selectedCountView = new View(context) { @Override protected void onDraw(Canvas canvas) { String text = String.format("%d", Math.max(1, selectedDialogs.size())); int textSize = (int) Math.ceil(textPaint.measureText(text)); - int size = Math.max(AndroidUtilities.dp(16) + textSize, AndroidUtilities.dp(24)); + int size = Math.max(dp(16) + textSize, dp(24)); int cx = getMeasuredWidth() / 2; int cy = getMeasuredHeight() / 2; textPaint.setColor(getThemedColor(Theme.key_dialogRoundCheckBoxCheck)); paint.setColor(getThemedColor(Theme.isCurrentThemeDark() ? Theme.key_voipgroup_inviteMembersBackground : Theme.key_dialogBackground)); rect.set(cx - size / 2, 0, cx + size / 2, getMeasuredHeight()); - canvas.drawRoundRect(rect, AndroidUtilities.dp(12), AndroidUtilities.dp(12), paint); + canvas.drawRoundRect(rect, dp(12), dp(12), paint); paint.setColor(getThemedColor(Theme.key_dialogRoundCheckBox)); - rect.set(cx - size / 2 + AndroidUtilities.dp(2), AndroidUtilities.dp(2), cx + size / 2 - AndroidUtilities.dp(2), getMeasuredHeight() - AndroidUtilities.dp(2)); - canvas.drawRoundRect(rect, AndroidUtilities.dp(10), AndroidUtilities.dp(10), paint); + rect.set(cx - size / 2 + dp(2), dp(2), cx + size / 2 - dp(2), getMeasuredHeight() - dp(2)); + canvas.drawRoundRect(rect, dp(10), dp(10), paint); - canvas.drawText(text, cx - textSize / 2, AndroidUtilities.dp(16.2f), textPaint); + canvas.drawText(text, cx - textSize / 2, dp(16.2f), textPaint); } }; selectedCountView.setAlpha(0.0f); @@ -4835,12 +4839,12 @@ protected void onDraw(Canvas canvas) { FrameLayout writeButtonBackground = new FrameLayout(context); - Drawable writeButtonDrawable = Theme.createSimpleSelectorCircleDrawable(AndroidUtilities.dp(56), getThemedColor(Theme.key_dialogFloatingButton), getThemedColor(Build.VERSION.SDK_INT >= 21 ? Theme.key_dialogFloatingButtonPressed : Theme.key_dialogFloatingButton)); + Drawable writeButtonDrawable = Theme.createSimpleSelectorCircleDrawable(dp(56), getThemedColor(Theme.key_dialogFloatingButton), getThemedColor(Build.VERSION.SDK_INT >= 21 ? Theme.key_dialogFloatingButtonPressed : Theme.key_dialogFloatingButton)); if (Build.VERSION.SDK_INT < 21) { Drawable shadowDrawable = context.getResources().getDrawable(R.drawable.floating_shadow_profile).mutate(); shadowDrawable.setColorFilter(new PorterDuffColorFilter(0xff000000, PorterDuff.Mode.MULTIPLY)); CombinedDrawable combinedDrawable = new CombinedDrawable(shadowDrawable, drawable, 0, 0); - combinedDrawable.setIconSize(AndroidUtilities.dp(56), AndroidUtilities.dp(56)); + combinedDrawable.setIconSize(dp(56), dp(56)); writeButtonDrawable = combinedDrawable; } writeButtonBackground.setBackgroundDrawable(writeButtonDrawable); @@ -4850,7 +4854,7 @@ protected void onDraw(Canvas canvas) { @SuppressLint("NewApi") @Override public void getOutline(View view, Outline outline) { - outline.setOval(0, 0, AndroidUtilities.dp(56), AndroidUtilities.dp(56)); + outline.setOval(0, 0, dp(56), dp(56)); } }); } @@ -4894,10 +4898,10 @@ public void getOutline(View view, Outline outline) { @Override public void onUserLongPressed(View view, long dialogId) { filterOptions = ItemOptions.makeOptions(DialogsActivity.this, view) - .setViewAdditionalOffsets(0, AndroidUtilities.dp(8), 0, 0) + .setViewAdditionalOffsets(0, dp(8), 0, 0) .setScrimViewBackground(Theme.createRoundRectDrawable( - AndroidUtilities.dp(6), - canShowFilterTabsView ? AndroidUtilities.dp(6) : 0, + dp(6), + canShowFilterTabsView ? dp(6) : 0, Theme.getColor(isArchive() ? Theme.key_actionBarDefaultArchived : Theme.key_actionBarDefault) )); if (UserObject.isService(dialogId)) { @@ -4969,7 +4973,7 @@ public void onUserLongPressed(View view, long dialogId) { }).makeMultiline(false); } filterOptions.setGravity(Gravity.LEFT) - .translate(AndroidUtilities.dp(-8), AndroidUtilities.dp(-10)) + .translate(dp(-8), dp(-10)) .show(); } @@ -5035,13 +5039,13 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { lastGradientWidth = width; } int x = (getMeasuredWidth() - updateTextView.getMeasuredWidth()) / 2; - updateLayoutIcon.setProgressRect(x, AndroidUtilities.dp(13), x + AndroidUtilities.dp(22), AndroidUtilities.dp(13 + 22)); + updateLayoutIcon.setProgressRect(x, dp(13), x + dp(22), dp(13 + 22)); } @Override public void setTranslationY(float translationY) { super.setTranslationY(translationY); - additionalFloatingTranslation2 = AndroidUtilities.dp(48) - translationY; + additionalFloatingTranslation2 = dp(48) - translationY; if (additionalFloatingTranslation2 < 0) { additionalFloatingTranslation2 = 0; } @@ -5052,7 +5056,7 @@ public void setTranslationY(float translationY) { }; updateLayout.setWillNotDraw(false); updateLayout.setVisibility(View.INVISIBLE); - updateLayout.setTranslationY(AndroidUtilities.dp(48)); + updateLayout.setTranslationY(dp(48)); if (Build.VERSION.SDK_INT >= 21) { updateLayout.setBackground(Theme.getSelectorDrawable(0x40ffffff, false)); } @@ -5066,7 +5070,7 @@ public void setTranslationY(float translationY) { updateLayoutIcon = new RadialProgress2(updateLayout); updateLayoutIcon.setColors(0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff); - updateLayoutIcon.setCircleRadius(AndroidUtilities.dp(11)); + updateLayoutIcon.setCircleRadius(dp(11)); updateLayoutIcon.setAsMini(); updateLayoutIcon.setIcon(MediaActionDrawable.ICON_UPDATE, true, false); @@ -5075,7 +5079,7 @@ public void setTranslationY(float translationY) { updateTextView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); updateTextView.setText(LocaleController.getString("AppUpdateNow", R.string.AppUpdateNow).toUpperCase()); updateTextView.setTextColor(0xffffffff); - updateTextView.setPadding(AndroidUtilities.dp(30), 0, 0, 0); + updateTextView.setPadding(dp(30), 0, 0, 0); updateLayout.addView(updateTextView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER, 0, 0, 0, 0)); } @@ -5123,7 +5127,7 @@ public void setAlpha(float alpha) { avatarContainer.setSubtitle(LocaleController.formatUserStatus(currentAccount, currentUser)); avatarContainer.setUserAvatar(currentUser, true); avatarContainer.setOccupyStatusBar(false); - avatarContainer.setLeftPadding(AndroidUtilities.dp(10)); + avatarContainer.setLeftPadding(dp(10)); actionBar.addView(avatarContainer, 0, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.MATCH_PARENT, Gravity.TOP | Gravity.LEFT, 0, 0, 40, 0)); floatingButton.setVisibility(View.INVISIBLE); actionBar.setOccupyStatusBar(false); @@ -5147,7 +5151,7 @@ public void setAlpha(float alpha) { actionBar.openSearchField(initialSearchString, false); initialSearchString = null; if (filterTabsView != null) { - filterTabsView.setTranslationY(-AndroidUtilities.dp(44)); + filterTabsView.setTranslationY(-dp(44)); } } else { showSearch(false, false, false); @@ -5356,7 +5360,7 @@ private void setStoriesOvercroll(ViewPage viewPage, float storiesOverscroll) { viewPage.listView.setViewsOffset(storiesOverscroll); viewPage.listView.setOverScrollMode(storiesOverscroll != 0 ? RecyclerView.OVER_SCROLL_NEVER : RecyclerView.OVER_SCROLL_ALWAYS); fragmentView.invalidate(); - if (storiesOverscroll > AndroidUtilities.dp(90) && !storiesOverscrollCalled) { + if (storiesOverscroll > dp(90) && !storiesOverscrollCalled) { storiesOverscrollCalled = true; getOrCreateStoryViewer().doOnAnimationReady(() -> { fragmentView.dispatchTouchEvent(AndroidUtilities.emptyMotionEvent()); @@ -5425,10 +5429,10 @@ private boolean checkAutoscrollToStories(ViewPage viewPage) { private float getActionBarMoveFrom(boolean showFilterTabs) { float h = 0; if (hasStories) { - h += AndroidUtilities.dp(DialogStoriesCell.HEIGHT_IN_DP); + h += dp(DialogStoriesCell.HEIGHT_IN_DP); } if (showFilterTabs) { - h += AndroidUtilities.dp(44); + h += dp(44); } if (dialogsHintCell != null && dialogsHintCell.getVisibility() == View.VISIBLE) { h += dialogsHintCell.getMeasuredHeight(); @@ -5441,7 +5445,7 @@ private float getActionBarMoveFrom(boolean showFilterTabs) { private int getMaxScrollYOffset() { if (hasStories) { - return AndroidUtilities.dp(DialogStoriesCell.HEIGHT_IN_DP); + return dp(DialogStoriesCell.HEIGHT_IN_DP); } else { return ActionBar.getCurrentActionBarHeight(); } @@ -5520,8 +5524,8 @@ public void showSelectStatusDialog() { hasEmoji = statusDrawable.getDrawable() instanceof AnimatedEmojiDrawable; AndroidUtilities.rectTmp2.set(actionBarTitle.getRightDrawable().getBounds()); AndroidUtilities.rectTmp2.offset((int) actionBarTitle.getX(), (int) actionBarTitle.getY()); - yoff = -(actionBar.getHeight() - AndroidUtilities.rectTmp2.centerY()) - AndroidUtilities.dp(16); - xoff = AndroidUtilities.rectTmp2.centerX() - AndroidUtilities.dp(16); + yoff = -(actionBar.getHeight() - AndroidUtilities.rectTmp2.centerY()) - dp(16); + xoff = AndroidUtilities.rectTmp2.centerX() - dp(16); if (animatedStatusView != null) { animatedStatusView.translate(AndroidUtilities.rectTmp2.centerX(), AndroidUtilities.rectTmp2.centerY()); } @@ -5563,7 +5567,7 @@ public void dismiss() { selectAnimatedEmojiDialog = null; } }; - popup[0].showAsDropDown(actionBar, AndroidUtilities.dp(16), yoff, Gravity.TOP); + popup[0].showAsDropDown(actionBar, dp(16), yoff, Gravity.TOP); popup[0].dimBehind(); } @@ -5599,7 +5603,7 @@ private void updateCommentView() { return; } int top = commentView.getTop(); - if (commentViewPreviousTop > 0 && Math.abs(top - commentViewPreviousTop) > AndroidUtilities.dp(20) && !commentView.isPopupShowing()) { + if (commentViewPreviousTop > 0 && Math.abs(top - commentViewPreviousTop) > dp(20) && !commentView.isPopupShowing()) { if (commentViewIgnoreTopUpdate) { commentViewIgnoreTopUpdate = false; commentViewPreviousTop = top; @@ -5789,16 +5793,23 @@ private void updateDialogsHint() { updateAuthHintCellVisibility(false); } else { if (folderId == 0 && ApplicationLoader.applicationLoaderInstance != null) { + boolean found = false; String foundSuggestion = null; - String[] output = new String[2]; + CharSequence[] output = new CharSequence[2]; boolean[] closeable = new boolean[1]; - for (String suggestion : MessagesController.getInstance(currentAccount).pendingSuggestions) { - if (ApplicationLoader.applicationLoaderInstance.onSuggestionFill(suggestion, output, closeable)) { - foundSuggestion = suggestion; - break; + if (ApplicationLoader.applicationLoaderInstance.onSuggestionFill(null, output, closeable)) { + found = true; + foundSuggestion = null; + } else { + for (String suggestion : MessagesController.getInstance(currentAccount).pendingSuggestions) { + if (ApplicationLoader.applicationLoaderInstance.onSuggestionFill(suggestion, output, closeable)) { + found = true; + foundSuggestion = suggestion; + break; + } } } - if (foundSuggestion != null) { + if (found) { final String finalSuggestion = foundSuggestion; dialogsHintCellVisible = true; dialogsHintCell.setVisibility(View.VISIBLE); @@ -5808,15 +5819,15 @@ private void updateDialogsHint() { } }); dialogsHintCell.setText( - AndroidUtilities.replaceSingleTag( - output[0], + output[0] instanceof String ? AndroidUtilities.replaceSingleTag( + output[0].toString(), Theme.key_windowBackgroundWhiteValueText, AndroidUtilities.REPLACING_TAG_TYPE_LINKBOLD, null - ), - AndroidUtilities.replaceTags(output[1]) + ) : output[0], + output[1] instanceof String ? AndroidUtilities.replaceTags(output[1].toString()) : output[1] ); - if (closeable[0]) { + if (closeable[0] && finalSuggestion != null) { dialogsHintCell.setOnCloseListener(v -> { AndroidUtilities.runOnUIThread(() -> { MessagesController.getInstance(currentAccount).removeSuggestion(0, finalSuggestion); @@ -6061,7 +6072,7 @@ public void onAnimationEnd(Animator animation) { updateLayoutAnimator = new AnimatorSet(); updateLayoutAnimator.setDuration(180); updateLayoutAnimator.setInterpolator(CubicBezierInterpolator.EASE_OUT); - updateLayoutAnimator.playTogether(ObjectAnimator.ofFloat(updateLayout, View.TRANSLATION_Y, AndroidUtilities.dp(48))); + updateLayoutAnimator.playTogether(ObjectAnimator.ofFloat(updateLayout, View.TRANSLATION_Y, dp(48))); updateLayoutAnimator.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { @@ -6073,7 +6084,7 @@ public void onAnimationEnd(Animator animation) { }); updateLayoutAnimator.start(); } else { - updateLayout.setTranslationY(AndroidUtilities.dp(48)); + updateLayout.setTranslationY(dp(48)); updateLayout.setVisibility(View.INVISIBLE); } } @@ -6090,7 +6101,7 @@ private void updateContextViewPosition() { } float storiesHeight = 0; if (hasStories) { - storiesHeight = AndroidUtilities.dp(DialogStoriesCell.HEIGHT_IN_DP); + storiesHeight = dp(DialogStoriesCell.HEIGHT_IN_DP); } float totalOffset; if (hasStories) { @@ -6123,14 +6134,14 @@ private void updateContextViewPosition() { if (fragmentContextView != null) { float from = 0; if (fragmentLocationContextView != null && fragmentLocationContextView.getVisibility() == View.VISIBLE) { - from += AndroidUtilities.dp(36); + from += dp(36); } fragmentContextView.setTranslationY(from + fragmentContextView.getTopPadding() + totalOffset); } if (fragmentLocationContextView != null) { float from = 0; if (fragmentContextView != null && fragmentContextView.getVisibility() == View.VISIBLE) { - from += AndroidUtilities.dp(fragmentContextView.getStyleHeight()) + fragmentContextView.getTopPadding(); + from += dp(fragmentContextView.getStyleHeight()) + fragmentContextView.getTopPadding(); } fragmentLocationContextView.setTranslationY(from + fragmentLocationContextView.getTopPadding() + totalOffset); } @@ -6297,11 +6308,11 @@ private void createActionMode(String tag) { actionMode.addView(selectedDialogsCountTextView, LayoutHelper.createLinear(0, LayoutHelper.MATCH_PARENT, 1.0f, 72, 0, 0, 0)); selectedDialogsCountTextView.setOnTouchListener((v, event) -> true); - pinItem = actionMode.addItemWithWidth(pin, R.drawable.msg_pin, AndroidUtilities.dp(54)); - muteItem = actionMode.addItemWithWidth(mute, R.drawable.msg_mute, AndroidUtilities.dp(54)); - archive2Item = actionMode.addItemWithWidth(archive2, R.drawable.msg_archive, AndroidUtilities.dp(54)); - deleteItem = actionMode.addItemWithWidth(delete, R.drawable.msg_delete, AndroidUtilities.dp(54), LocaleController.getString("Delete", R.string.Delete)); - ActionBarMenuItem otherItem = actionMode.addItemWithWidth(0, R.drawable.ic_ab_other, AndroidUtilities.dp(54), LocaleController.getString("AccDescrMoreOptions", R.string.AccDescrMoreOptions)); + pinItem = actionMode.addItemWithWidth(pin, R.drawable.msg_pin, dp(54)); + muteItem = actionMode.addItemWithWidth(mute, R.drawable.msg_mute, dp(54)); + archive2Item = actionMode.addItemWithWidth(archive2, R.drawable.msg_archive, dp(54)); + deleteItem = actionMode.addItemWithWidth(delete, R.drawable.msg_delete, dp(54), LocaleController.getString("Delete", R.string.Delete)); + ActionBarMenuItem otherItem = actionMode.addItemWithWidth(0, R.drawable.ic_ab_other, dp(54), LocaleController.getString("AccDescrMoreOptions", R.string.AccDescrMoreOptions)); archiveItem = otherItem.addSubItem(archive, R.drawable.msg_archive, LocaleController.getString("Archive", R.string.Archive)); pin2Item = otherItem.addSubItem(pin2, R.drawable.msg_pin, LocaleController.getString("DialogPin", R.string.DialogPin)); addToFolderItem = otherItem.addSubItem(add_to_folder, R.drawable.msg_addfolder, LocaleController.getString("FilterAddTo", R.string.FilterAddTo)); @@ -6389,36 +6400,56 @@ public void onItemClick(int id) { launchActivity.presentFragment(dialogsActivity, false, true); } else if (id == add_to_folder) { FiltersListBottomSheet sheet = new FiltersListBottomSheet(DialogsActivity.this, selectedDialogs); - sheet.setDelegate(filter -> { + sheet.setDelegate((filter, checked) -> { ArrayList alwaysShow = FiltersListBottomSheet.getDialogsCount(DialogsActivity.this, filter, selectedDialogs, true, false); - int currentCount; - if (filter != null) { - currentCount = filter.alwaysShow.size(); - } else { - currentCount = 0; - } - int totalCount = currentCount + alwaysShow.size(); - if ((totalCount > getMessagesController().dialogFiltersChatsLimitDefault && !getUserConfig().isPremium()) || totalCount > getMessagesController().dialogFiltersChatsLimitPremium) { - showDialog(new LimitReachedBottomSheet(DialogsActivity.this, fragmentView.getContext(), LimitReachedBottomSheet.TYPE_CHATS_IN_FOLDER, currentAccount, null)); - return; + if (!checked) { + int currentCount; + if (filter != null) { + currentCount = filter.alwaysShow.size(); + } else { + currentCount = 0; + } + int totalCount = currentCount + alwaysShow.size(); + if ((totalCount > getMessagesController().dialogFiltersChatsLimitDefault && !getUserConfig().isPremium()) || totalCount > getMessagesController().dialogFiltersChatsLimitPremium) { + showDialog(new LimitReachedBottomSheet(DialogsActivity.this, fragmentView.getContext(), LimitReachedBottomSheet.TYPE_CHATS_IN_FOLDER, currentAccount, null)); + return; + } } if (filter != null) { - if (!alwaysShow.isEmpty()) { - for (int a = 0; a < alwaysShow.size(); a++) { - filter.neverShow.remove(alwaysShow.get(a)); + if (checked) { + for (int a = 0; a < selectedDialogs.size(); a++) { + filter.neverShow.add(selectedDialogs.get(a)); + filter.alwaysShow.remove(selectedDialogs.get(a)); + } + FilterCreateActivity.saveFilterToServer(filter, filter.flags, filter.name, filter.color, filter.alwaysShow, filter.neverShow, filter.pinnedDialogs, false, false, true, true, false, DialogsActivity.this, null); + long did; + if (selectedDialogs.size() == 1) { + did = selectedDialogs.get(0); + } else { + did = 0; + } + final UndoView undoView = getUndoView(); + if (undoView != null) { + undoView.showWithAction(did, UndoView.ACTION_REMOVED_FROM_FOLDER, selectedDialogs.size(), filter, null, null); } - filter.alwaysShow.addAll(alwaysShow); - FilterCreateActivity.saveFilterToServer(filter, filter.flags, filter.name, filter.alwaysShow, filter.neverShow, filter.pinnedDialogs, false, false, true, true, false, DialogsActivity.this, null); - } - long did; - if (alwaysShow.size() == 1) { - did = alwaysShow.get(0); } else { - did = 0; - } - final UndoView undoView = getUndoView(); - if (undoView != null) { - undoView.showWithAction(did, UndoView.ACTION_ADDED_TO_FOLDER, alwaysShow.size(), filter, null, null); + if (!alwaysShow.isEmpty()) { + for (int a = 0; a < alwaysShow.size(); a++) { + filter.neverShow.remove(alwaysShow.get(a)); + } + filter.alwaysShow.addAll(alwaysShow); + FilterCreateActivity.saveFilterToServer(filter, filter.flags, filter.name, filter.color, filter.alwaysShow, filter.neverShow, filter.pinnedDialogs, false, false, true, true, false, DialogsActivity.this, null); + } + long did; + if (alwaysShow.size() == 1) { + did = alwaysShow.get(0); + } else { + did = 0; + } + final UndoView undoView = getUndoView(); + if (undoView != null) { + undoView.showWithAction(did, UndoView.ACTION_ADDED_TO_FOLDER, alwaysShow.size(), filter, null, null); + } } } else { presentFragment(new FilterCreateActivity(null, alwaysShow)); @@ -6450,7 +6481,7 @@ public void onItemClick(int id) { if (filter.isChatlist()) { filter.neverShow.clear(); } - FilterCreateActivity.saveFilterToServer(filter, filter.flags, filter.name, filter.alwaysShow, filter.neverShow, filter.pinnedDialogs, false, false, true, false, false, DialogsActivity.this, null); + FilterCreateActivity.saveFilterToServer(filter, filter.flags, filter.name, filter.color, filter.alwaysShow, filter.neverShow, filter.pinnedDialogs, false, false, true, false, false, DialogsActivity.this, null); } long did; if (neverShow.size() == 1) { @@ -6870,10 +6901,10 @@ public int getTopOffset(int tag) { return ( (actionBar != null ? actionBar.getMeasuredHeight() : 0) + (filterTabsView != null && filterTabsView.getVisibility() == View.VISIBLE ? filterTabsView.getMeasuredHeight() : 0) + - (fragmentContextView != null && fragmentContextView.isCallTypeVisible() ? AndroidUtilities.dp(fragmentContextView.getStyleHeight()) : 0) + + (fragmentContextView != null && fragmentContextView.isCallTypeVisible() ? dp(fragmentContextView.getStyleHeight()) : 0) + (dialogsHintCell != null && dialogsHintCell.getVisibility() == View.VISIBLE ? dialogsHintCell.getHeight() : 0) + (authHintCell != null && authHintCellVisible ? authHintCell.getHeight() : 0) + - (dialogStoriesCell != null && dialogStoriesCellVisible ? (int) ((1f - dialogStoriesCell.getCollapsedProgress()) * AndroidUtilities.dp(DialogStoriesCell.HEIGHT_IN_DP)) : 0) + (dialogStoriesCell != null && dialogStoriesCellVisible ? (int) ((1f - dialogStoriesCell.getCollapsedProgress()) * dp(DialogStoriesCell.HEIGHT_IN_DP)) : 0) ); } }); @@ -7238,7 +7269,7 @@ private void showSearch(boolean show, boolean startFromDownloads, boolean animat } animators.add(ObjectAnimator.ofFloat(searchViewPager, View.ALPHA, show ? 1.0f : 0.0f)); if (hasStories) { - float translationY = AndroidUtilities.dp(DialogStoriesCell.HEIGHT_IN_DP) + scrollYOffset; + float translationY = dp(DialogStoriesCell.HEIGHT_IN_DP) + scrollYOffset; animators.add(ObjectAnimator.ofFloat(searchViewPager, SEARCH_TRANSLATION_Y, show ? 0 : translationY)); } if (!budget) { @@ -7404,7 +7435,7 @@ public void onAnimationCancel(Animator animation) { searchViewPager.setScaleY(1); } if (filterTabsView != null && filterTabsView.getVisibility() == View.VISIBLE) { - filterTabsView.setTranslationY(show ? -AndroidUtilities.dp(44) : 0); + filterTabsView.setTranslationY(show ? -dp(44) : 0); filterTabsView.getTabsContainer().setAlpha(show ? 0.0f : 1.0f); } if (filterTabsView != null) { @@ -7637,7 +7668,7 @@ private void checkListLoad(ViewPage viewPage, int firstVisibleItem, int lastVisi boolean loadArchivedFromCache = false; boolean load = false; boolean loadFromCache = false; - if (viewPage.dialogsType == DIALOGS_TYPE_7 || viewPage.dialogsType == DIALOGS_TYPE_8) { + if (viewPage.dialogsType == DIALOGS_TYPE_FOLDER1 || viewPage.dialogsType == DIALOGS_TYPE_FOLDER2) { ArrayList dialogFilters = getMessagesController().getDialogFilters(); if (viewPage.selectedType >= 0 && viewPage.selectedType < dialogFilters.size()) { MessagesController.DialogFilter filter = dialogFilters.get(viewPage.selectedType); @@ -7688,8 +7719,8 @@ private void onItemClick(View view, int position, RecyclerListView.Adapter adapt if (adapter instanceof DialogsAdapter) { DialogsAdapter dialogsAdapter = (DialogsAdapter) adapter; int dialogsType = dialogsAdapter.getDialogsType(); - if (dialogsType == 7 || dialogsType == 8) { - MessagesController.DialogFilter dialogFilter = getMessagesController().selectedDialogFilter[dialogsType == 7 ? 0 : 1]; + if (dialogsType == DIALOGS_TYPE_FOLDER1 || dialogsType == DIALOGS_TYPE_FOLDER2) { + MessagesController.DialogFilter dialogFilter = getMessagesController().selectedDialogFilter[dialogsType == DIALOGS_TYPE_FOLDER1 ? 0 : 1]; filterId = dialogFilter.id; } TLObject object = dialogsAdapter.getItem(position); @@ -8155,123 +8186,128 @@ public boolean showChatPreview(DialogCell cell) { final ArrayList dialogIdArray = new ArrayList<>(); dialogIdArray.add(dialogId); -// boolean hasFolders = getMessagesController().filtersEnabled && getMessagesController().dialogFiltersLoaded && getMessagesController().dialogFilters != null && getMessagesController().dialogFilters.size() > 0; + boolean hasFolders = getMessagesController().filtersEnabled && getMessagesController().dialogFiltersLoaded && getMessagesController().dialogFilters != null && getMessagesController().dialogFilters.size() > 0; final ActionBarPopupWindow.ActionBarPopupWindowLayout[] previewMenu = new ActionBarPopupWindow.ActionBarPopupWindowLayout[1]; -// -// LinearLayout foldersMenuView = null; -// int[] foldersMenu = new int[1]; -// if (hasFolders) { -// foldersMenuView = new LinearLayout(getParentActivity()); -// foldersMenuView.setOrientation(LinearLayout.VERTICAL); -// -// ScrollView scrollView = new ScrollView(getParentActivity()) { -// @Override -// protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { -// super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec( -// (int) Math.min( -// MeasureSpec.getSize(heightMeasureSpec), -// Math.min(AndroidUtilities.displaySize.y * 0.35f, AndroidUtilities.dp(400)) -// ), -// MeasureSpec.getMode(heightMeasureSpec) -// )); -// } -// }; -// LinearLayout linearLayout = new LinearLayout(getParentActivity()); -// linearLayout.setOrientation(LinearLayout.VERTICAL); -// scrollView.addView(linearLayout); -// final boolean backButtonAtTop = true; -// -// final int foldersCount = getMessagesController().dialogFilters.size(); -// ActionBarMenuSubItem lastItem = null; -// for (int i = 0; i < foldersCount; ++i) { -// MessagesController.DialogFilter folder = getMessagesController().dialogFilters.get(i); -// if (folder.includesDialog(AccountInstance.getInstance(currentAccount), dialogId)) { -// continue; -// } -// final ArrayList alwaysShow = FiltersListBottomSheet.getDialogsCount(DialogsActivity.this, folder, dialogIdArray, true, false); -// int currentCount = folder.alwaysShow.size(); -// if (currentCount + alwaysShow.size() > 100) { -// continue; -// } -// ActionBarMenuSubItem folderItem = lastItem = new ActionBarMenuSubItem(getParentActivity(), !backButtonAtTop && linearLayout.getChildCount() == 0, false); -// folderItem.setTextAndIcon(folder.name, R.drawable.msg_folders); -// folderItem.setMinimumWidth(160); -// folderItem.setOnClickListener(e -> { -// if (!alwaysShow.isEmpty()) { -// for (int a = 0; a < alwaysShow.size(); a++) { -// folder.neverShow.remove(alwaysShow.get(a)); -// } -// folder.alwaysShow.addAll(alwaysShow); -// FilterCreateActivity.saveFilterToServer(folder, folder.flags, folder.name, folder.alwaysShow, folder.neverShow, folder.pinnedDialogs, false, false, true, true, false, DialogsActivity.this, null); -// } -// long did; -// if (alwaysShow.size() == 1) { -// did = alwaysShow.get(0); -// } else { -// did = 0; -// } -// getUndoView().showWithAction(did, UndoView.ACTION_ADDED_TO_FOLDER, alwaysShow.size(), folder, null, null); -// hideActionMode(true); -// finishPreviewFragment(); -// }); -// linearLayout.addView(folderItem); -// } -// if (lastItem != null && backButtonAtTop) { -// lastItem.updateSelectorBackground(false, true); -// } -// if (linearLayout.getChildCount() <= 0) { -// hasFolders = false; -// } else { -// ActionBarPopupWindow.GapView gap = new ActionBarPopupWindow.GapView(getParentActivity(), getResourceProvider(), Theme.key_actionBarDefaultSubmenuSeparator); -// gap.setTag(R.id.fit_width_tag, 1); -// ActionBarMenuSubItem backItem = new ActionBarMenuSubItem(getParentActivity(), backButtonAtTop, !backButtonAtTop); -// backItem.setTextAndIcon(LocaleController.getString("Back", R.string.Back), R.drawable.ic_ab_back); -// backItem.setMinimumWidth(160); -// backItem.setOnClickListener(e -> { -// if (previewMenu[0] != null) { -// previewMenu[0].getSwipeBack().closeForeground(); -// } -// }); -// if (backButtonAtTop) { -// foldersMenuView.addView(backItem); -// foldersMenuView.addView(gap, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 8)); -// foldersMenuView.addView(scrollView); -// } else { -// foldersMenuView.addView(scrollView); -// foldersMenuView.addView(gap, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 8)); -// foldersMenuView.addView(backItem); -// } -// } -// } + + LinearLayout foldersMenuView = null; + int[] foldersMenu = new int[1]; + if (hasFolders) { + foldersMenuView = new LinearLayout(getParentActivity()); + foldersMenuView.setOrientation(LinearLayout.VERTICAL); + + ScrollView scrollView = new ScrollView(getParentActivity()) { + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec( + (int) Math.min( + MeasureSpec.getSize(heightMeasureSpec), + Math.min(AndroidUtilities.displaySize.y * 0.35f, dp(400)) + ), + MeasureSpec.getMode(heightMeasureSpec) + )); + } + }; + LinearLayout linearLayout = new LinearLayout(getParentActivity()); + linearLayout.setOrientation(LinearLayout.VERTICAL); + scrollView.addView(linearLayout); + final boolean backButtonAtTop = true; + + final int foldersCount = getMessagesController().dialogFilters.size(); + ActionBarMenuSubItem lastItem = null; + for (int i = 0; i < foldersCount; ++i) { + MessagesController.DialogFilter folder = getMessagesController().dialogFilters.get(i); + if (folder.isDefault()) { + continue; + } + final boolean contains = folder.includesDialog(AccountInstance.getInstance(currentAccount), dialogId); + final ArrayList alwaysShow = FiltersListBottomSheet.getDialogsCount(DialogsActivity.this, folder, dialogIdArray, true, false); + if (!contains) { + int currentCount = folder.alwaysShow.size(); + if (currentCount + alwaysShow.size() > 100) { + continue; + } + } + ActionBarMenuSubItem folderItem = lastItem = new ActionBarMenuSubItem(getParentActivity(), 2, !backButtonAtTop && linearLayout.getChildCount() == 0, false, null); + folderItem.setChecked(contains); + folderItem.setTextAndIcon(Emoji.replaceEmoji(folder.name, null, false), 0, new FolderDrawable(getContext(), R.drawable.msg_folders, folder.color)); + folderItem.setMinimumWidth(160); + folderItem.setOnClickListener(e -> { + if (!contains) { + if (!alwaysShow.isEmpty()) { + for (int a = 0; a < alwaysShow.size(); a++) { + folder.neverShow.remove(alwaysShow.get(a)); + } + folder.alwaysShow.addAll(alwaysShow); + FilterCreateActivity.saveFilterToServer(folder, folder.flags, folder.name, folder.color, folder.alwaysShow, folder.neverShow, folder.pinnedDialogs, false, false, true, true, false, DialogsActivity.this, null); + } + getUndoView().showWithAction(dialogId, UndoView.ACTION_ADDED_TO_FOLDER, alwaysShow.size(), folder, null, null); + } else { + folder.alwaysShow.remove(dialogId); + folder.neverShow.add(dialogId); + FilterCreateActivity.saveFilterToServer(folder, folder.flags, folder.name, folder.color, folder.alwaysShow, folder.neverShow, folder.pinnedDialogs, false, false, true, true, false, DialogsActivity.this, null); + getUndoView().showWithAction(dialogId, UndoView.ACTION_REMOVED_FROM_FOLDER, alwaysShow.size(), folder, null, null); + } + hideActionMode(true); + finishPreviewFragment(); + }); + linearLayout.addView(folderItem); + } + if (lastItem != null && backButtonAtTop) { + lastItem.updateSelectorBackground(false, true); + } + if (linearLayout.getChildCount() <= 0) { + hasFolders = false; + } else { + ActionBarPopupWindow.GapView gap = new ActionBarPopupWindow.GapView(getParentActivity(), getResourceProvider(), Theme.key_actionBarDefaultSubmenuSeparator); + gap.setTag(R.id.fit_width_tag, 1); + ActionBarMenuSubItem backItem = new ActionBarMenuSubItem(getParentActivity(), backButtonAtTop, !backButtonAtTop); + backItem.setTextAndIcon(LocaleController.getString("Back", R.string.Back), R.drawable.ic_ab_back); + backItem.setMinimumWidth(160); + backItem.setOnClickListener(e -> { + if (previewMenu[0] != null) { + previewMenu[0].getSwipeBack().closeForeground(); + } + }); + if (backButtonAtTop) { + foldersMenuView.addView(backItem); + foldersMenuView.addView(gap, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 8)); + foldersMenuView.addView(scrollView); + } else { + foldersMenuView.addView(scrollView); + foldersMenuView.addView(gap, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 8)); + foldersMenuView.addView(backItem); + } + } + } int flags = ActionBarPopupWindow.ActionBarPopupWindowLayout.FLAG_SHOWN_FROM_BOTTOM; -// if (hasFolders) { -// flags |= ActionBarPopupWindow.ActionBarPopupWindowLayout.FLAG_USE_SWIPEBACK; -// } + if (hasFolders) { + flags |= ActionBarPopupWindow.ActionBarPopupWindowLayout.FLAG_USE_SWIPEBACK; + } final ChatActivity[] chatActivity = new ChatActivity[1]; previewMenu[0] = new ActionBarPopupWindow.ActionBarPopupWindowLayout(getParentActivity(), R.drawable.popup_fixed_alert2, getResourceProvider(), flags); -// if (hasFolders) { -// foldersMenu[0] = previewMenu[0].addViewToSwipeBack(foldersMenuView); -// ActionBarMenuSubItem addToFolderItem = new ActionBarMenuSubItem(getParentActivity(), true, false); -// addToFolderItem.setTextAndIcon(LocaleController.getString("FilterAddTo", R.string.FilterAddTo), R.drawable.msg_addfolder); -// addToFolderItem.setMinimumWidth(160); -// addToFolderItem.setOnClickListener(e -> -// previewMenu[0].getSwipeBack().openForeground(foldersMenu[0]) -// ); -// previewMenu[0].addView(addToFolderItem); -// previewMenu[0].getSwipeBack().setOnHeightUpdateListener(height -> { -// if (chatActivity[0] == null || chatActivity[0].getFragmentView() == null) { -// return; -// } -// ViewGroup.LayoutParams lp = chatActivity[0].getFragmentView().getLayoutParams(); -// if (lp instanceof ViewGroup.MarginLayoutParams) { -// ((ViewGroup.MarginLayoutParams) lp).bottomMargin = AndroidUtilities.dp(24 + 16 + 8) + height; -// chatActivity[0].getFragmentView().setLayoutParams(lp); -// } -// }); -// } + if (hasFolders) { + foldersMenu[0] = previewMenu[0].addViewToSwipeBack(foldersMenuView); + ActionBarMenuSubItem addToFolderItem = new ActionBarMenuSubItem(getParentActivity(), true, false); + addToFolderItem.setTextAndIcon(LocaleController.getString("FilterAddTo", R.string.FilterAddTo), R.drawable.msg_addfolder); + addToFolderItem.setMinimumWidth(160); + addToFolderItem.setOnClickListener(e -> + previewMenu[0].getSwipeBack().openForeground(foldersMenu[0]) + ); + previewMenu[0].addView(addToFolderItem); + previewMenu[0].getSwipeBack().setOnHeightUpdateListener(height -> { + if (chatActivity[0] == null || chatActivity[0].getFragmentView() == null || !chatActivity[0].isInPreviewMode()) { + return; + } + ViewGroup.LayoutParams lp = chatActivity[0].getFragmentView().getLayoutParams(); + if (lp instanceof ViewGroup.MarginLayoutParams) { + ((ViewGroup.MarginLayoutParams) lp).bottomMargin = dp(24 + 16 + 8) + height; + chatActivity[0].getFragmentView().setLayoutParams(lp); + } + }); + } ActionBarMenuSubItem markAsUnreadItem = new ActionBarMenuSubItem(getParentActivity(), true, false); if (cell.getHasUnread()) { @@ -8394,7 +8430,7 @@ public boolean showChatPreview(DialogCell cell) { undoView.showWithAction(0, UndoView.ACTION_UNPIN_DIALOGS, 1, 1600, null, null); } if (filter != null) { - FilterCreateActivity.saveFilterToServer(filter, filter.flags, filter.name, filter.alwaysShow, filter.neverShow, filter.pinnedDialogs, false, false, true, true, false, DialogsActivity.this, null); + FilterCreateActivity.saveFilterToServer(filter, filter.flags, filter.name, filter.color, filter.alwaysShow, filter.neverShow, filter.pinnedDialogs, false, false, true, true, false, DialogsActivity.this, null); } getMessagesController().reorderPinnedDialogs(folderId, null, 0); updateCounters(true); @@ -8474,7 +8510,7 @@ private void updateFloatingButtonOffset() { } } if (floatingButton2Container != null) { - floatingButton2Container.setTranslationY(floatingButtonTranslation - floatingButtonPanOffset - Math.max(additionalFloatingTranslation, additionalFloatingTranslation2) * (1f - floatingButtonHideProgress) + AndroidUtilities.dp(44) * floatingButtonHideProgress); + floatingButton2Container.setTranslationY(floatingButtonTranslation - floatingButtonPanOffset - Math.max(additionalFloatingTranslation, additionalFloatingTranslation2) * (1f - floatingButtonHideProgress) + dp(44) * floatingButtonHideProgress); } } @@ -8641,7 +8677,7 @@ private void hideActionMode(boolean animateCheck) { viewPages[i].listView.cancelClickRunnables(true); } } - translateListHeight = Math.max(0, AndroidUtilities.dp(DialogStoriesCell.HEIGHT_IN_DP) + scrollYOffset); + translateListHeight = Math.max(0, dp(DialogStoriesCell.HEIGHT_IN_DP) + scrollYOffset); } float finalTranslateListHeight = translateListHeight; actionBarColorAnimator = ValueAnimator.ofFloat(progressToActionMode, 0); @@ -8669,7 +8705,7 @@ public void onAnimationEnd(Animator animation) { invalidateScrollY = true; fixScrollYAfterArchiveOpened = true; fragmentView.invalidate(); - scrollAdditionalOffset = -(AndroidUtilities.dp(DialogStoriesCell.HEIGHT_IN_DP) - finalTranslateListHeight); + scrollAdditionalOffset = -(dp(DialogStoriesCell.HEIGHT_IN_DP) - finalTranslateListHeight); viewPages[0].setTranslationY(0); for (int i = 0; i < viewPages.length; i++) { if (viewPages[i] != null) { @@ -8687,7 +8723,7 @@ public void onAnimationEnd(Animator animation) { if (!movingDialogFilters.isEmpty()) { for (int a = 0, N = movingDialogFilters.size(); a < N; a++) { MessagesController.DialogFilter filter = movingDialogFilters.get(a); - FilterCreateActivity.saveFilterToServer(filter, filter.flags, filter.name, filter.alwaysShow, filter.neverShow, filter.pinnedDialogs, false, false, true, true, false, DialogsActivity.this, null); + FilterCreateActivity.saveFilterToServer(filter, filter.flags, filter.name, filter.color, filter.alwaysShow, filter.neverShow, filter.pinnedDialogs, false, false, true, true, false, DialogsActivity.this, null); } movingDialogFilters.clear(); } @@ -9087,7 +9123,7 @@ private void performSelectedDialogsAction(ArrayList selectedDialogs, int a } if (action == pin || action == pin2) { if (filter != null) { - FilterCreateActivity.saveFilterToServer(filter, filter.flags, filter.name, filter.alwaysShow, filter.neverShow, filter.pinnedDialogs, false, false, true, true, false, DialogsActivity.this, null); + FilterCreateActivity.saveFilterToServer(filter, filter.flags, filter.name, filter.color, filter.alwaysShow, filter.neverShow, filter.pinnedDialogs, false, false, true, true, false, DialogsActivity.this, null); } else { getMessagesController().reorderPinnedDialogs(folderId, null, 0); } @@ -9288,7 +9324,7 @@ public void scrollToTop(boolean animated, boolean expandStories) { int position = viewPages[0].dialogsType == 0 && hasHiddenArchive() && viewPages[0].archivePullViewState == ARCHIVE_ITEM_STATE_HIDDEN ? 1 : 0; int offset = 0; if (hasStories && !expandStories && !dialogStoriesCell.isExpanded()) { - offset = -AndroidUtilities.dp(DialogStoriesCell.HEIGHT_IN_DP); + offset = -dp(DialogStoriesCell.HEIGHT_IN_DP); } if (animated) { viewPages[0].scrollHelper.setScrollDirection(RecyclerAnimationScrollHelper.SCROLL_DIRECTION_UP); @@ -9629,7 +9665,7 @@ private void showOrUpdateActionMode(long dialogId, View cell) { viewPages[i].listView.cancelClickRunnables(true); } } - translateListHeight = Math.max(0, AndroidUtilities.dp(DialogStoriesCell.HEIGHT_IN_DP) + scrollYOffset); + translateListHeight = Math.max(0, dp(DialogStoriesCell.HEIGHT_IN_DP) + scrollYOffset); if (translateListHeight != 0) { actionModeAdditionalHeight = (int) translateListHeight; fragmentView.requestLayout(); @@ -9658,7 +9694,7 @@ public void onAnimationEnd(Animator animation) { actionModeAdditionalHeight = 0; actionModeFullyShowed = true; if (hasStories) { - scrollAdditionalOffset = AndroidUtilities.dp(DialogStoriesCell.HEIGHT_IN_DP) - finalTranslateListHeight; + scrollAdditionalOffset = dp(DialogStoriesCell.HEIGHT_IN_DP) - finalTranslateListHeight; viewPages[0].setTranslationY(0); for (int i = 0; i < viewPages.length; i++) { if (viewPages[i] != null) { @@ -9726,7 +9762,7 @@ public void createUndoView() { public void setTranslationY(float translationY) { super.setTranslationY(translationY); if (this == undoView[0] && (undoView[1] == null || undoView[1].getVisibility() != VISIBLE)) { - additionalFloatingTranslation = getMeasuredHeight() + AndroidUtilities.dp(8) - translationY; + additionalFloatingTranslation = getMeasuredHeight() + dp(8) - translationY; if (additionalFloatingTranslation < 0) { additionalFloatingTranslation = 0; } @@ -10066,7 +10102,7 @@ public void onConfigurationChanged(Configuration newConfig) { floatingButtonContainer.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { @Override public void onGlobalLayout() { - floatingButtonTranslation = floatingHidden ? AndroidUtilities.dp(100) : 0; + floatingButtonTranslation = floatingHidden ? dp(100) : 0; updateFloatingButtonOffset(); floatingButtonContainer.setClickable(!floatingHidden); if (floatingButtonContainer != null) { @@ -10620,8 +10656,8 @@ public DialogsHeader(int type) { public static final int DIALOGS_TYPE_USERS_ONLY = 4; public static final int DIALOGS_TYPE_CHANNELS_ONLY = 5; public static final int DIALOGS_TYPE_GROUPS_ONLY = 6; - public static final int DIALOGS_TYPE_7 = 7; - public static final int DIALOGS_TYPE_8 = 8; + public static final int DIALOGS_TYPE_FOLDER1 = 7; + public static final int DIALOGS_TYPE_FOLDER2 = 8; public static final int DIALOGS_TYPE_BLOCK = 9; public static final int DIALOGS_TYPE_WIDGET = 10; public static final int DIALOGS_TYPE_IMPORT_HISTORY_GROUPS = 11; // groups only @@ -10911,7 +10947,7 @@ private void hideFloatingButton(boolean hide) { ValueAnimator valueAnimator = ValueAnimator.ofFloat(floatingButtonHideProgress, floatingHidden ? 1f : 0f); valueAnimator.addUpdateListener(animation -> { floatingButtonHideProgress = (float) animation.getAnimatedValue(); - floatingButtonTranslation = AndroidUtilities.dp(100) * floatingButtonHideProgress; + floatingButtonTranslation = dp(100) * floatingButtonHideProgress; updateFloatingButtonOffset(); }); animatorSet.playTogether(valueAnimator); @@ -11405,7 +11441,7 @@ public boolean onTouch(View v, MotionEvent event) { ActionBarMenuSubItem sendWithoutSound = new ActionBarMenuSubItem(parentActivity, true, true, resourcesProvider); sendWithoutSound.setTextAndIcon(LocaleController.getString("SendWithoutSound", R.string.SendWithoutSound), R.drawable.input_notify_off); - sendWithoutSound.setMinimumWidth(AndroidUtilities.dp(196)); + sendWithoutSound.setMinimumWidth(dp(196)); sendPopupLayout2.addView(sendWithoutSound, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 48)); sendWithoutSound.setOnClickListener(v -> { if (sendPopupWindow != null && sendPopupWindow.isShowing()) { @@ -11434,12 +11470,12 @@ public boolean onTouch(View v, MotionEvent event) { sendPopupWindow.getContentView().setFocusableInTouchMode(true); SharedConfig.removeScheduledOrNoSoundHint(); - layout.measure(View.MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(1000), View.MeasureSpec.AT_MOST), View.MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(1000), View.MeasureSpec.AT_MOST)); + layout.measure(View.MeasureSpec.makeMeasureSpec(dp(1000), View.MeasureSpec.AT_MOST), View.MeasureSpec.makeMeasureSpec(dp(1000), View.MeasureSpec.AT_MOST)); sendPopupWindow.setFocusable(true); int[] location = new int[2]; view.getLocationInWindow(location); - int y = location[1] - layout.getMeasuredHeight() - AndroidUtilities.dp(2); - sendPopupWindow.showAtLocation(view, Gravity.LEFT | Gravity.TOP, location[0] + view.getMeasuredWidth() - layout.getMeasuredWidth() + AndroidUtilities.dp(8), y); + int y = location[1] - layout.getMeasuredHeight() - dp(2); + sendPopupWindow.showAtLocation(view, Gravity.LEFT | Gravity.TOP, location[0] + view.getMeasuredWidth() - layout.getMeasuredWidth() + dp(8), y); sendPopupWindow.dimBehind(); view.performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP, HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING); @@ -12006,12 +12042,12 @@ private void updateFloatingButtonColor() { } Drawable drawable; if (floatingButtonContainer != null) { - drawable = Theme.createSimpleSelectorCircleDrawable(AndroidUtilities.dp(56), Theme.getColor(Theme.key_chats_actionBackground), Theme.getColor(Theme.key_chats_actionPressedBackground)); + drawable = Theme.createSimpleSelectorCircleDrawable(dp(56), Theme.getColor(Theme.key_chats_actionBackground), Theme.getColor(Theme.key_chats_actionPressedBackground)); if (Build.VERSION.SDK_INT < 21) { Drawable shadowDrawable = ContextCompat.getDrawable(getParentActivity(), R.drawable.floating_shadow).mutate(); shadowDrawable.setColorFilter(new PorterDuffColorFilter(0xff000000, PorterDuff.Mode.MULTIPLY)); CombinedDrawable combinedDrawable = new CombinedDrawable(shadowDrawable, drawable, 0, 0); - combinedDrawable.setIconSize(AndroidUtilities.dp(56), AndroidUtilities.dp(56)); + combinedDrawable.setIconSize(dp(56), dp(56)); drawable = combinedDrawable; } floatingButtonContainer.setBackground(drawable); @@ -12019,7 +12055,7 @@ private void updateFloatingButtonColor() { if (floatingButton2Container != null) { drawable = Theme.createSimpleSelectorCircleDrawable( - AndroidUtilities.dp(36), + dp(36), ColorUtils.blendARGB(Theme.getColor(Theme.key_windowBackgroundWhite), Color.WHITE, 0.1f), Theme.blendOver(Theme.getColor(Theme.key_windowBackgroundWhite), Theme.getColor(Theme.key_listSelector)) ); @@ -12027,7 +12063,7 @@ private void updateFloatingButtonColor() { Drawable shadowDrawable = ContextCompat.getDrawable(getParentActivity(), R.drawable.floating_shadow).mutate(); shadowDrawable.setColorFilter(new PorterDuffColorFilter(0xff000000, PorterDuff.Mode.MULTIPLY)); CombinedDrawable combinedDrawable = new CombinedDrawable(shadowDrawable, drawable, 0, 0); - combinedDrawable.setIconSize(AndroidUtilities.dp(36), AndroidUtilities.dp(36)); + combinedDrawable.setIconSize(dp(36), dp(36)); drawable = combinedDrawable; } floatingButton2Container.setBackground(drawable); @@ -12146,15 +12182,15 @@ private void setSlideTransitionProgress(float progress) { if (slideFragmentLite) { if (filterTabsView != null) { - filterTabsView.getListView().setTranslationX((isDrawerTransition ? 1 : -1) * AndroidUtilities.dp(slideAmplitudeDp) * (1f - slideFragmentProgress)); + filterTabsView.getListView().setTranslationX((isDrawerTransition ? 1 : -1) * dp(slideAmplitudeDp) * (1f - slideFragmentProgress)); filterTabsView.invalidate(); } if (dialogStoriesCell != null) { - dialogStoriesCell.setTranslationX((isDrawerTransition ? 1 : -1) * AndroidUtilities.dp(slideAmplitudeDp) * (1f - slideFragmentProgress)); + dialogStoriesCell.setTranslationX((isDrawerTransition ? 1 : -1) * dp(slideAmplitudeDp) * (1f - slideFragmentProgress)); } if (rightSlidingDialogContainer != null && rightSlidingDialogContainer.getFragmentView() != null) { if (!rightFragmentTransitionInProgress) { - rightSlidingDialogContainer.getFragmentView().setTranslationX((isDrawerTransition ? 1 : -1) * AndroidUtilities.dp(slideAmplitudeDp) * (1f - slideFragmentProgress)); + rightSlidingDialogContainer.getFragmentView().setTranslationX((isDrawerTransition ? 1 : -1) * dp(slideAmplitudeDp) * (1f - slideFragmentProgress)); } } } else { @@ -12162,7 +12198,7 @@ private void setSlideTransitionProgress(float progress) { if (filterTabsView != null) { filterTabsView.getListView().setScaleX(s); filterTabsView.getListView().setScaleY(s); - filterTabsView.getListView().setTranslationX((isDrawerTransition ? AndroidUtilities.dp(4) : -AndroidUtilities.dp(4)) * (1f - slideFragmentProgress)); + filterTabsView.getListView().setTranslationX((isDrawerTransition ? dp(4) : -dp(4)) * (1f - slideFragmentProgress)); filterTabsView.getListView().setPivotX(isDrawerTransition ? filterTabsView.getMeasuredWidth() : 0); filterTabsView.getListView().setPivotY(0); filterTabsView.invalidate(); @@ -12170,7 +12206,7 @@ private void setSlideTransitionProgress(float progress) { if (dialogStoriesCell != null) { dialogStoriesCell.setScaleX(s); dialogStoriesCell.setScaleY(s); - dialogStoriesCell.setTranslationX((isDrawerTransition ? AndroidUtilities.dp(4) : -AndroidUtilities.dp(4)) * (1f - slideFragmentProgress)); + dialogStoriesCell.setTranslationX((isDrawerTransition ? dp(4) : -dp(4)) * (1f - slideFragmentProgress)); dialogStoriesCell.setPivotX(isDrawerTransition ? dialogStoriesCell.getMeasuredWidth() : 0); dialogStoriesCell.setPivotY(0); } @@ -12178,7 +12214,7 @@ private void setSlideTransitionProgress(float progress) { if (!rightFragmentTransitionInProgress) { rightSlidingDialogContainer.getFragmentView().setScaleX(s); rightSlidingDialogContainer.getFragmentView().setScaleY(s); - rightSlidingDialogContainer.getFragmentView().setTranslationX((isDrawerTransition ? AndroidUtilities.dp(4) : -AndroidUtilities.dp(4)) * (1f - slideFragmentProgress)); + rightSlidingDialogContainer.getFragmentView().setTranslationX((isDrawerTransition ? dp(4) : -dp(4)) * (1f - slideFragmentProgress)); } rightSlidingDialogContainer.getFragmentView().setPivotX(isDrawerTransition ? rightSlidingDialogContainer.getMeasuredWidth() : 0); rightSlidingDialogContainer.getFragmentView().setPivotY(0); @@ -12397,9 +12433,9 @@ public void onAnimationEnd(Animator animation) { } if (!newVisibility) { setScrollY(0); - scrollAdditionalOffset = AndroidUtilities.dp(DialogStoriesCell.HEIGHT_IN_DP); + scrollAdditionalOffset = dp(DialogStoriesCell.HEIGHT_IN_DP); } else { - scrollAdditionalOffset = -AndroidUtilities.dp(DialogStoriesCell.HEIGHT_IN_DP); + scrollAdditionalOffset = -dp(DialogStoriesCell.HEIGHT_IN_DP); setScrollY(-getMaxScrollYOffset()); } for (int i = 0; i < viewPages.length; i++) { @@ -12422,7 +12458,7 @@ public void onAnimationEnd(Animator animation) { if (!newVisibility) { setScrollY(0); } else { - scrollAdditionalOffset = -AndroidUtilities.dp(DialogStoriesCell.HEIGHT_IN_DP); + scrollAdditionalOffset = -dp(DialogStoriesCell.HEIGHT_IN_DP); setScrollY(-getMaxScrollYOffset()); } for (int i = 0; i < viewPages.length; i++) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/FilterCreateActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/FilterCreateActivity.java index 70c668f997a..80fc5beed46 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/FilterCreateActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/FilterCreateActivity.java @@ -1,6 +1,7 @@ package org.telegram.ui; import static org.telegram.messenger.AndroidUtilities.dp; +import static org.telegram.messenger.AndroidUtilities.dpf2; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; @@ -27,6 +28,7 @@ import android.text.style.DynamicDrawableSpan; import android.text.style.ImageSpan; import android.text.style.ReplacementSpan; +import android.util.Log; import android.util.TypedValue; import android.view.Gravity; import android.view.View; @@ -72,6 +74,7 @@ import org.telegram.ui.Cells.TextCell; import org.telegram.ui.Cells.TextInfoPrivacyCell; import org.telegram.ui.Cells.UserCell; +import org.telegram.ui.Components.AnimatedColor; import org.telegram.ui.Components.AnimatedTextView; import org.telegram.ui.Components.BottomSheetWithRecyclerListView; import org.telegram.ui.Components.Bulletin; @@ -85,6 +88,7 @@ import org.telegram.ui.Components.LayoutHelper; import org.telegram.ui.Components.ListView.AdapterWithDiffUtils; import org.telegram.ui.Components.Premium.LimitReachedBottomSheet; +import org.telegram.ui.Components.Premium.PremiumFeatureBottomSheet; import org.telegram.ui.Components.QRCodeBottomSheet; import org.telegram.ui.Components.RLottieImageView; import org.telegram.ui.Components.RecyclerListView; @@ -113,10 +117,13 @@ public class FilterCreateActivity extends BaseFragment { private boolean doNotCloseWhenSave; private String newFilterName; private int newFilterFlags; + private int newFilterColor; private ArrayList newAlwaysShow; private ArrayList newNeverShow; private LongSparseIntArray newPinned; private CreateLinkCell createLinkCell; + private HeaderCellColorPreview folderTagsHeader; + private boolean canCreateLink() { return ( (!TextUtils.isEmpty(newFilterName) || !TextUtils.isEmpty(filter.name)) && @@ -177,10 +184,12 @@ public FilterCreateActivity(MessagesController.DialogFilter dialogFilter, ArrayL filter.id++; } filter.name = ""; + filter.color = (int) (Math.random() * 8); creatingNew = true; } newFilterName = filter.name; newFilterFlags = filter.flags; + newFilterColor = filter.color; newAlwaysShow = new ArrayList<>(filter.alwaysShow); if (alwaysShow != null) { newAlwaysShow.addAll(alwaysShow); @@ -286,15 +295,15 @@ private void updateRows(boolean animated) { items.add(ItemInner.asShadow(LocaleController.getString("FilterIncludeInfo", R.string.FilterIncludeInfo))); if (!filter.isChatlist()) { items.add(ItemInner.asHeader(LocaleController.getString("FilterExclude", R.string.FilterExclude))); - items.add(ItemInner.asButton(R.drawable.msg2_chats_add, LocaleController.getString("FilterRemoveChats", R.string.FilterRemoveChats), false).whenClicked(v -> selectChatsFor(false))); + items.add(ItemInner.asButton(R.drawable.msg2_chats_add, LocaleController.getString(R.string.FilterRemoveChats), false).whenClicked(v -> selectChatsFor(false))); if ((newFilterFlags & MessagesController.DIALOG_FILTER_FLAG_EXCLUDE_MUTED) != 0) { - items.add(ItemInner.asChat(false, LocaleController.getString("FilterMuted", R.string.FilterMuted), "muted", MessagesController.DIALOG_FILTER_FLAG_EXCLUDE_MUTED)); + items.add(ItemInner.asChat(false, LocaleController.getString(R.string.FilterMuted), "muted", MessagesController.DIALOG_FILTER_FLAG_EXCLUDE_MUTED)); } if ((newFilterFlags & MessagesController.DIALOG_FILTER_FLAG_EXCLUDE_READ) != 0) { - items.add(ItemInner.asChat(false, LocaleController.getString("FilterRead", R.string.FilterRead), "read", MessagesController.DIALOG_FILTER_FLAG_EXCLUDE_READ)); + items.add(ItemInner.asChat(false, LocaleController.getString(R.string.FilterRead), "read", MessagesController.DIALOG_FILTER_FLAG_EXCLUDE_READ)); } if ((newFilterFlags & MessagesController.DIALOG_FILTER_FLAG_EXCLUDE_ARCHIVED) != 0) { - items.add(ItemInner.asChat(false, LocaleController.getString("FilterArchived", R.string.FilterArchived), "archived", MessagesController.DIALOG_FILTER_FLAG_EXCLUDE_ARCHIVED)); + items.add(ItemInner.asChat(false, LocaleController.getString(R.string.FilterArchived), "archived", MessagesController.DIALOG_FILTER_FLAG_EXCLUDE_ARCHIVED)); } if (!newNeverShow.isEmpty()) { int count = excludeExpanded || newNeverShow.size() < 8 ? newNeverShow.size() : Math.min(5, newNeverShow.size()); @@ -314,6 +323,12 @@ private void updateRows(boolean animated) { items.add(ItemInner.asShadow(LocaleController.getString("FilterExcludeInfo", R.string.FilterExcludeInfo))); } + if (getMessagesController().folderTags || !getUserConfig().isPremium()) { + items.add(new ItemInner(VIEW_TYPE_HEADER_COLOR_PREVIEW, false)); + items.add(new ItemInner(VIEW_TYPE_COLOR, false)); + items.add(ItemInner.asShadow(LocaleController.getString(R.string.FolderTagColorInfo))); + } + if (invites.isEmpty()) { items.add(ItemInner.asHeader(LocaleController.getString("FilterShareFolder", R.string.FilterShareFolder), true)); items.add(ItemInner.asButton(R.drawable.msg2_link2, LocaleController.getString("FilterShareFolderButton", R.string.FilterShareFolderButton), false)); @@ -791,6 +806,9 @@ private void fillFilterName() { newName = ""; } newFilterName = newName; + if (folderTagsHeader != null) { + folderTagsHeader.setPreviewText((newFilterName == null ? "" : newFilterName).toUpperCase(), false); + } RecyclerView.ViewHolder holder = listView.findViewHolderForAdapterPosition(nameRow); if (holder != null) { adapter.onViewAttachedToWindow(holder); @@ -878,7 +896,7 @@ private void processDone() { } private void save(boolean progress, Runnable after) { - saveFilterToServer(filter, newFilterFlags, newFilterName, newAlwaysShow, newNeverShow, newPinned, creatingNew, false, hasUserChanged, true, progress, this, () -> { + saveFilterToServer(filter, newFilterFlags, newFilterName, newFilterColor, newAlwaysShow, newNeverShow, newPinned, creatingNew, false, hasUserChanged, true, progress, this, () -> { hasUserChanged = false; creatingNew = false; @@ -893,7 +911,7 @@ private void save(boolean progress, Runnable after) { }); } - private static void processAddFilter(MessagesController.DialogFilter filter, int newFilterFlags, String newFilterName, ArrayList newAlwaysShow, ArrayList newNeverShow, boolean creatingNew, boolean atBegin, boolean hasUserChanged, boolean resetUnreadCounter, BaseFragment fragment, Runnable onFinish) { + private static void processAddFilter(MessagesController.DialogFilter filter, int newFilterFlags, String newFilterName, int newFilterColor, ArrayList newAlwaysShow, ArrayList newNeverShow, boolean creatingNew, boolean atBegin, boolean hasUserChanged, boolean resetUnreadCounter, BaseFragment fragment, Runnable onFinish) { if (filter.flags != newFilterFlags || hasUserChanged) { filter.pendingUnreadCount = -1; if (resetUnreadCounter) { @@ -902,6 +920,7 @@ private static void processAddFilter(MessagesController.DialogFilter filter, int } filter.flags = newFilterFlags; filter.name = newFilterName; + filter.color = newFilterColor; filter.neverShow = newNeverShow; filter.alwaysShow = newAlwaysShow; if (creatingNew) { @@ -923,7 +942,7 @@ private static void processAddFilter(MessagesController.DialogFilter filter, int } } - public static void saveFilterToServer(MessagesController.DialogFilter filter, int newFilterFlags, String newFilterName, ArrayList newAlwaysShow, ArrayList newNeverShow, LongSparseIntArray newPinned, boolean creatingNew, boolean atBegin, boolean hasUserChanged, boolean resetUnreadCounter, boolean progress, BaseFragment fragment, Runnable onFinish) { + public static void saveFilterToServer(MessagesController.DialogFilter filter, int newFilterFlags, String newFilterName, int newFilterColor, ArrayList newAlwaysShow, ArrayList newNeverShow, LongSparseIntArray newPinned, boolean creatingNew, boolean atBegin, boolean hasUserChanged, boolean resetUnreadCounter, boolean progress, BaseFragment fragment, Runnable onFinish) { if (fragment == null || fragment.getParentActivity() == null) { return; } @@ -949,6 +968,13 @@ public static void saveFilterToServer(MessagesController.DialogFilter filter, in req.filter.exclude_archived = (newFilterFlags & MessagesController.DIALOG_FILTER_FLAG_EXCLUDE_ARCHIVED) != 0; req.filter.id = filter.id; req.filter.title = newFilterName; + if (newFilterColor < 0) { + req.filter.flags &=~ 134217728; + req.filter.color = 0; + } else { + req.filter.flags |= 134217728; + req.filter.color = newFilterColor; + } MessagesController messagesController = fragment.getMessagesController(); ArrayList pinArray = new ArrayList<>(); if (newPinned.size() != 0) { @@ -1024,13 +1050,13 @@ public static void saveFilterToServer(MessagesController.DialogFilter filter, in } catch (Exception e) { FileLog.e(e); } - processAddFilter(filter, newFilterFlags, newFilterName, newAlwaysShow, newNeverShow, creatingNew, atBegin, hasUserChanged, resetUnreadCounter, fragment, onFinish); + processAddFilter(filter, newFilterFlags, newFilterName, newFilterColor, newAlwaysShow, newNeverShow, creatingNew, atBegin, hasUserChanged, resetUnreadCounter, fragment, onFinish); } else if (onFinish != null) { onFinish.run(); } })); if (!progress) { - processAddFilter(filter, newFilterFlags, newFilterName, newAlwaysShow, newNeverShow, creatingNew, atBegin, hasUserChanged, resetUnreadCounter, fragment, null); + processAddFilter(filter, newFilterFlags, newFilterName, newFilterColor, newAlwaysShow, newNeverShow, creatingNew, atBegin, hasUserChanged, resetUnreadCounter, fragment, null); } } @@ -1047,6 +1073,9 @@ private boolean hasChanges() { if (filter.neverShow.size() != newNeverShow.size()) { hasUserChanged = true; } + if (filter.color != newFilterColor) { + hasUserChanged = true; + } if (!hasUserChanged) { Collections.sort(filter.alwaysShow); Collections.sort(newAlwaysShow); @@ -1115,6 +1144,8 @@ private void setTextLeft(View cell) { private static final int VIEW_TYPE_SHADOW_TEXT = 6; private static final int VIEW_TYPE_LINK = 7; private static final int VIEW_TYPE_CREATE_LINK = 8; + private static final int VIEW_TYPE_HEADER_COLOR_PREVIEW = 9; + private static final int VIEW_TYPE_COLOR = 10; private static class ItemInner extends AdapterWithDiffUtils.Item { @@ -1254,7 +1285,8 @@ public boolean isEnabled(RecyclerView.ViewHolder holder) { type != VIEW_TYPE_SHADOW && type != VIEW_TYPE_HEADER && type != VIEW_TYPE_EDIT && - type != VIEW_TYPE_HINT + type != VIEW_TYPE_HINT && + type != VIEW_TYPE_HEADER_COLOR_PREVIEW ); } @@ -1302,6 +1334,9 @@ public void afterTextChanged(Editable s) { if (!TextUtils.equals(newName, newFilterName)) { nameChangedManually = !TextUtils.isEmpty(newName); newFilterName = newName; + if (folderTagsHeader != null) { + folderTagsHeader.setPreviewText((newFilterName == null ? "" : newFilterName).toUpperCase(), true); + } } RecyclerView.ViewHolder holder = listView.findViewHolderForAdapterPosition(nameRow); if (holder != null) { @@ -1344,6 +1379,14 @@ protected void reload() { view = new CreateLinkCell(mContext); view.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); break; + case VIEW_TYPE_HEADER_COLOR_PREVIEW: + view = new HeaderCellColorPreview(mContext); + view.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); + break; + case VIEW_TYPE_COLOR: + view = new PeerColorActivity.PeerColorGrid(getContext(), PeerColorActivity.PeerColorGrid.TYPE_FOLDER_TAG, currentAccount, resourceProvider); + view.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); + break; case VIEW_TYPE_SHADOW_TEXT: default: view = new TextInfoPrivacyCell(mContext); @@ -1467,6 +1510,30 @@ public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { createLinkCell.setDivider(divider); break; } + case VIEW_TYPE_HEADER_COLOR_PREVIEW: { + folderTagsHeader = (HeaderCellColorPreview) holder.itemView; + folderTagsHeader.setPreviewText((newFilterName == null ? "" : newFilterName).toUpperCase(), false); + folderTagsHeader.setPreviewColor(!getUserConfig().isPremium() ? -1 : newFilterColor, false); + folderTagsHeader.setText(LocaleController.getString(R.string.FolderTagColor)); + break; + } + case VIEW_TYPE_COLOR: { + PeerColorActivity.PeerColorGrid cell = (PeerColorActivity.PeerColorGrid) holder.itemView; + cell.setCloseAsLock(!getUserConfig().isPremium()); + cell.setSelected(!getUserConfig().isPremium() ? -1 : newFilterColor, false); + cell.setOnColorClick(color -> { + if (!getUserConfig().isPremium()) { + showDialog(new PremiumFeatureBottomSheet(FilterCreateActivity.this, PremiumPreviewFragment.PREMIUM_FEATURE_FOLDER_TAGS, true)); + return; + } + cell.setSelected(newFilterColor = color, true); + if (folderTagsHeader != null) { + folderTagsHeader.setPreviewColor(!getUserConfig().isPremium() ? -1 : newFilterColor, true); + } + checkDoneButton(true); + }); + break; + } } } @@ -1983,10 +2050,10 @@ public NewSpan(boolean outline) { textPaint.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); if (outline) { bgPaint.setStyle(Paint.Style.STROKE); - bgPaint.setStrokeWidth(AndroidUtilities.dpf2(1.33f)); + bgPaint.setStrokeWidth(dpf2(1.33f)); textPaint.setTextSize(dp(10)); textPaint.setStyle(Paint.Style.FILL_AND_STROKE); - textPaint.setStrokeWidth(AndroidUtilities.dpf2(0.2f)); + textPaint.setStrokeWidth(dpf2(0.2f)); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { textPaint.setLetterSpacing(.03f); } @@ -2490,4 +2557,66 @@ public static boolean processErrors(TLRPC.TL_error err, BaseFragment fragment, B } return true; } + + private class HeaderCellColorPreview extends HeaderCell { + + public final TextView noTag; + public final AnimatedTextView previewView; + private int currentColor; + private final AnimatedColor animatedColor; + + public HeaderCellColorPreview(Context context) { + super(context, Theme.key_windowBackgroundWhiteBlueHeader, 22, 15, false, resourceProvider); + + noTag = new TextView(getContext()); + noTag.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); + noTag.setTextColor(FilterCreateActivity.this.getThemedColor(Theme.key_windowBackgroundWhiteGrayText2)); + noTag.setText(LocaleController.getString(getUserConfig().isPremium() ? R.string.FolderTagNoColor : R.string.FolderTagNoColorPremium)); + noTag.setGravity(Gravity.RIGHT); + addView(noTag, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, (LocaleController.isRTL ? Gravity.LEFT : Gravity.RIGHT) | Gravity.TOP, padding, 16.66f, padding, bottomMargin)); + noTag.setAlpha(0f); + + previewView = new AnimatedTextView(getContext(), false, true, true) { + private final Paint backgroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + @Override + protected void dispatchDraw(Canvas canvas) { + final int color = animatedColor.set(currentColor); + setTextColor(color); + backgroundPaint.setColor(Theme.multAlpha(color, Theme.isCurrentThemeDark() ? .20f : .10f)); + AndroidUtilities.rectTmp.set(getWidth() - getDrawable().getCurrentWidth() - dpf2(4.66f * 2), (getHeight() - dpf2(14.66f)) / 2f, getWidth(), (getHeight() + dpf2(14.66f)) / 2f); + canvas.drawRoundRect(AndroidUtilities.rectTmp, dp(4), dp(4), backgroundPaint); + super.dispatchDraw(canvas); + } + }; + animatedColor = new AnimatedColor(previewView, 0, 320, CubicBezierInterpolator.EASE_OUT_QUINT); + previewView.setTextSize(dp(10)); + previewView.setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)); + previewView.setGravity(Gravity.RIGHT); + previewView.setPadding(dp(4.66f), 0, dp(4.66f), 0); + addView(previewView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, (LocaleController.isRTL ? Gravity.LEFT : Gravity.RIGHT) | Gravity.TOP, padding, 16.66f, padding, bottomMargin)); + } + + private boolean noTagShown; + public void setPreviewColor(int colorId, boolean animated) { + noTag.setText(LocaleController.getString(getUserConfig().isPremium() ? R.string.FolderTagNoColor : R.string.FolderTagNoColorPremium)); + + final boolean noTag = colorId < 0; + currentColor = noTag ? 0 : FilterCreateActivity.this.getThemedColor(Theme.keys_avatar_nameInMessage[colorId % Theme.keys_avatar_nameInMessage.length]); + if (!animated) { + this.animatedColor.set(currentColor, true); + } + if (noTag != noTagShown) { + noTagShown = noTag; + this.noTag.animate().alpha(noTag ? 1f : 0f).setDuration(320).setInterpolator(CubicBezierInterpolator.EASE_OUT_QUINT).start(); + previewView.animate().alpha(noTag ? 0f : 1f).setDuration(320).setInterpolator(CubicBezierInterpolator.EASE_OUT_QUINT).start(); + } + } + + public void setPreviewText(String text, boolean animated) { + if (text.length() > MAX_NAME_LENGTH) { + text = text.substring(0, MAX_NAME_LENGTH); + } + previewView.setText(Emoji.replaceEmoji(text, previewView.getPaint().getFontMetricsInt(), false), animated && !LocaleController.isRTL); + } + } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/FilteredSearchView.java b/TMessagesProj/src/main/java/org/telegram/ui/FilteredSearchView.java index e4e322c92a7..08fa11511b1 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/FilteredSearchView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/FilteredSearchView.java @@ -53,6 +53,7 @@ import org.telegram.ui.ActionBar.Theme; import org.telegram.ui.ActionBar.ThemeDescription; import org.telegram.ui.Adapters.FiltersView; +import org.telegram.ui.Business.QuickRepliesController; import org.telegram.ui.Cells.ChatActionCell; import org.telegram.ui.Cells.ContextLinkCell; import org.telegram.ui.Cells.DialogCell; @@ -434,6 +435,10 @@ public static CharSequence createFromInfoString(MessageObject messageObject, boo if (messageObject == null || messageObject.messageOwner == null) { return ""; } + if (messageObject.isQuickReply()) { + QuickRepliesController.QuickReply reply = QuickRepliesController.getInstance(messageObject.currentAccount).findReply(messageObject.getQuickReplyId()); + return reply == null ? "" : reply.name; + } if (arrowSpan[arrowType] == null) { arrowSpan[arrowType] = new SpannableStringBuilder(">"); int resId; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/FiltersSetupActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/FiltersSetupActivity.java index f655ebc54fa..d9f045425c9 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/FiltersSetupActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/FiltersSetupActivity.java @@ -1,5 +1,8 @@ package org.telegram.ui; +import static org.telegram.messenger.AndroidUtilities.dp; + +import android.animation.ValueAnimator; import android.annotation.SuppressLint; import android.content.Context; import android.content.DialogInterface; @@ -8,6 +11,7 @@ import android.graphics.PorterDuffColorFilter; import android.graphics.drawable.Drawable; import android.text.TextUtils; +import android.util.Log; import android.util.TypedValue; import android.view.Gravity; import android.view.HapticFeedbackConstants; @@ -27,6 +31,7 @@ import androidx.recyclerview.widget.RecyclerView; import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.BotWebViewVibrationEffect; import org.telegram.messenger.Emoji; import org.telegram.messenger.FileLog; import org.telegram.messenger.LocaleController; @@ -44,6 +49,9 @@ import org.telegram.ui.ActionBar.ThemeDescription; import org.telegram.ui.Cells.HeaderCell; import org.telegram.ui.Cells.ShadowSectionCell; +import org.telegram.ui.Cells.TextCheckCell; +import org.telegram.ui.Cells.TextInfoPrivacyCell; +import org.telegram.ui.Components.BotWebViewContainer; import org.telegram.ui.Components.Bulletin; import org.telegram.ui.Components.BulletinFactory; import org.telegram.ui.Components.CombinedDrawable; @@ -73,6 +81,13 @@ public class FiltersSetupActivity extends BaseFragment implements NotificationCe private boolean ignoreUpdates; + private boolean highlightTags; + private boolean scrollingToBottom; + public FiltersSetupActivity highlightTags() { + this.highlightTags = true; + return this; + } + public static class TextCell extends FrameLayout { private SimpleTextView textView; @@ -96,11 +111,11 @@ public TextCell(Context context) { @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int width = MeasureSpec.getSize(widthMeasureSpec); - int height = AndroidUtilities.dp(48); + int height = 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)); + textView.measure(MeasureSpec.makeMeasureSpec(width - dp(71 + 23), MeasureSpec.AT_MOST), MeasureSpec.makeMeasureSpec(dp(20), MeasureSpec.EXACTLY)); + imageView.measure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.AT_MOST), MeasureSpec.makeMeasureSpec(dp(50), MeasureSpec.EXACTLY)); + setMeasuredDimension(width, dp(50)); } @Override @@ -111,13 +126,13 @@ protected void onLayout(boolean changed, int left, int top, int right, int botto int viewLeft; int viewTop = (height - textView.getTextHeight()) / 2; if (LocaleController.isRTL) { - viewLeft = getMeasuredWidth() - textView.getMeasuredWidth() - AndroidUtilities.dp(imageView.getVisibility() == VISIBLE ? 64 : 23); + viewLeft = getMeasuredWidth() - textView.getMeasuredWidth() - dp(imageView.getVisibility() == VISIBLE ? 64 : 23); } else { - viewLeft = AndroidUtilities.dp(imageView.getVisibility() == VISIBLE ? 64 : 23); + viewLeft = dp(imageView.getVisibility() == VISIBLE ? 64 : 23); } textView.layout(viewLeft, viewTop, viewLeft + textView.getMeasuredWidth(), viewTop + textView.getMeasuredHeight()); - viewLeft = !LocaleController.isRTL ? AndroidUtilities.dp(20) : width - imageView.getMeasuredWidth() - AndroidUtilities.dp(20); + viewLeft = !LocaleController.isRTL ? dp(20) : width - imageView.getMeasuredWidth() - dp(20); imageView.layout(viewLeft, 0, viewLeft + imageView.getMeasuredWidth(), imageView.getMeasuredHeight()); } @@ -168,7 +183,7 @@ public SuggestedFilterCell(Context context) { @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec), AndroidUtilities.dp(64)); + setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec), dp(64)); measureChildWithMargins(addButton, widthMeasureSpec, 0, heightMeasureSpec, 0); measureChildWithMargins(textView, widthMeasureSpec, addButton.getMeasuredWidth(), heightMeasureSpec, 0); measureChildWithMargins(valueTextView, widthMeasureSpec, addButton.getMeasuredWidth(), heightMeasureSpec, 0); @@ -247,9 +262,9 @@ public class FilterCell extends FrameLayout { private final SimpleTextView textView; private final TextView valueTextView; - @SuppressWarnings("FieldCanBeLocal") private final ImageView moveImageView; - @SuppressWarnings("FieldCanBeLocal") + private int lastColor = -2, lastAppliedColor = -1; + private final View colorImageView; private final ImageView optionsImageView; private final ImageView shareImageView; private boolean shareLoading = false; @@ -270,7 +285,10 @@ public FilterCell(Context context) { moveImageView.setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_stickers_menu), PorterDuff.Mode.MULTIPLY)); moveImageView.setContentDescription(LocaleController.getString("FilterReorder", R.string.FilterReorder)); moveImageView.setClickable(true); - addView(moveImageView, LayoutHelper.createFrame(48, 48, (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.CENTER_VERTICAL, 6, 0, 6, 0)); + addView(moveImageView, LayoutHelper.createFrame(48, 48, (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.CENTER_VERTICAL, 7, 0, 6, 0)); + + colorImageView = new View(context); + addView(colorImageView, LayoutHelper.createFrame(20, 20, (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.CENTER_VERTICAL, 22, 0, 22, 0)); textView = new SimpleTextView(context); textView.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlackText)); @@ -304,7 +322,7 @@ public FilterCell(Context context) { Theme.multAlpha(selector, 0.9f), Theme.multAlpha(selector, 1.7f) ); - int stroke = AndroidUtilities.dp(1); + int stroke = dp(1); shareLoadingDrawable.strokePaint.setStrokeWidth(stroke); shareLoadingDrawable.setRadiiDp(40); shareImageView = new ImageView(context) { @@ -359,15 +377,51 @@ protected boolean verifyDrawable(@NonNull Drawable dr) { @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - super.onMeasure(MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(50), MeasureSpec.EXACTLY)); + super.onMeasure(MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(dp(50), MeasureSpec.EXACTLY)); } - public void setFilter(MessagesController.DialogFilter filter, boolean divider) { + private ValueAnimator moveImageViewAnimator; + + public void setFilter(MessagesController.DialogFilter filter, boolean divider, int position) { int oldId = currentFilter == null ? -1 : currentFilter.id; currentFilter = filter; int newId = currentFilter == null ? -1 : currentFilter.id; boolean animated = oldId != newId; + final int color = getMessagesController().folderTags ? filter.color : -1; + if (color >= 0 && filter.color != lastAppliedColor) { + colorImageView.setBackground(Theme.createCircleDrawable(dp(22), getThemedColor(Theme.keys_avatar_nameInMessage[(lastAppliedColor = color) % Theme.keys_avatar_nameInMessage.length]))); + } + if (color != lastColor) { + if (moveImageViewAnimator != null) { + moveImageViewAnimator.cancel(); + } + if (oldId == newId) { + moveImageViewAnimator = ValueAnimator.ofFloat(moveImageView.getAlpha(), color >= 0 ? 0f : 1f); + moveImageViewAnimator.addUpdateListener(anm -> { + final float t = (float) anm.getAnimatedValue(); + moveImageView.setAlpha(t); + moveImageView.setScaleX(.5f + .5f * t); + moveImageView.setScaleY(.5f + .5f * t); + colorImageView.setAlpha(1f - t); + colorImageView.setScaleX(.5f + .5f * (1f - t)); + colorImageView.setScaleY(.5f + .5f * (1f - t)); + }); + moveImageViewAnimator.setInterpolator(CubicBezierInterpolator.EASE_OUT_QUINT); + moveImageViewAnimator.setDuration(340); + moveImageViewAnimator.setStartDelay(color >= 0 ? Math.max(0, filtersSectionEnd - position) * 27L : Math.max(0, position - filtersSectionStart) * 27L); + moveImageViewAnimator.start(); + } else { + moveImageView.setScaleX(color >= 0 ? 0.5f : 1f); + moveImageView.setScaleY(color >= 0 ? 0.5f : 1f); + moveImageView.setAlpha(color >= 0 ? 0f : 1f); + colorImageView.setScaleX(color >= 0 ? 1f : 0.5f); + colorImageView.setScaleY(color >= 0 ? 1f : 0.5f); + colorImageView.setAlpha(color >= 0 ? 1f : 0f); + } + lastColor = color; + } + shareImageView.setVisibility(filter.isChatlist() ? VISIBLE : GONE); StringBuilder info = new StringBuilder(); @@ -422,7 +476,7 @@ public void setFilter(MessagesController.DialogFilter filter, boolean divider) { if (!animated) { progressToLock = currentFilter.locked ? 1f : 0; } - textView.setText(Emoji.replaceEmoji(name, textView.getPaint().getFontMetricsInt(), AndroidUtilities.dp(20), false)); + textView.setText(Emoji.replaceEmoji(name, textView.getPaint().getFontMetricsInt(), dp(20), false)); valueTextView.setText(info); needDivider = divider; @@ -446,7 +500,7 @@ public void setOnOptionsClick(OnClickListener listener) { @Override protected void onDraw(Canvas canvas) { if (needDivider) { - canvas.drawLine(LocaleController.isRTL ? 0 : AndroidUtilities.dp(62), getMeasuredHeight() - 1, getMeasuredWidth() - (LocaleController.isRTL ? AndroidUtilities.dp(62) : 0), getMeasuredHeight() - 1, Theme.dividerPaint); + canvas.drawLine(LocaleController.isRTL ? 0 : dp(62), getMeasuredHeight() - 1, getMeasuredWidth() - (LocaleController.isRTL ? dp(62) : 0), getMeasuredHeight() - 1, Theme.dividerPaint); } if (currentFilter != null) { if (currentFilter.locked && progressToLock != 1f) { @@ -485,6 +539,7 @@ public boolean onFragmentCreate() { private int filtersStartPosition; private int filtersSectionStart = -1, filtersSectionEnd = -1; + private int folderTagsPosition; private void updateRows(boolean animated) { oldItems.clear(); @@ -507,6 +562,9 @@ private void updateRows(boolean animated) { filtersStartPosition = items.size(); for (int i = 0; i < dialogFilters.size(); ++i) { items.add(ItemInner.asFilter(dialogFilters.get(i))); + if (MessagesController.getInstance(currentAccount).folderTags && dialogFilters.get(i).color >= 0) { + loadedColors = true; + } } filtersSectionEnd = items.size(); } else { @@ -516,7 +574,15 @@ private void updateRows(boolean animated) { items.add(ItemInner.asButton(LocaleController.getString("CreateNewFilter", R.string.CreateNewFilter))); } items.add(ItemInner.asShadow(null)); - + folderTagsPosition = items.size(); + items.add(ItemInner.asCheck(LocaleController.getString(R.string.FolderShowTags))); + items.add(ItemInner.asShadow(!getUserConfig().isPremium() ? AndroidUtilities.replaceSingleTag(LocaleController.getString(R.string.FolderShowTagsInfoPremium), Theme.key_windowBackgroundWhiteBlueHeader, AndroidUtilities.REPLACING_TAG_TYPE_LINKBOLD, () -> { + presentFragment(new PremiumPreviewFragment("settings")); + }) : LocaleController.getString(R.string.FolderShowTagsInfo))); + + if (scrollingToBottom) { + animated = false; + } if (adapter != null) { if (animated) { adapter.setItems(oldItems, items); @@ -546,6 +612,20 @@ public void onFragmentDestroy() { super.onFragmentDestroy(); } + @Override + public void onBecomeFullyVisible() { + super.onBecomeFullyVisible(); + if (highlightTags) { + highlightTags = false; + scrollingToBottom = true; + listView.smoothScrollToPosition(adapter.getItemCount() - 1); + AndroidUtilities.runOnUIThread(() -> { + scrollingToBottom = false; + listView.highlightRow(() -> folderTagsPosition); + }, 200); + } + } + @Override public View createView(Context context) { actionBar.setBackButtonImage(R.drawable.ic_ab_back); @@ -602,7 +682,24 @@ protected void dispatchDraw(Canvas canvas) { if (item == null) { return; } - if (item.viewType == VIEW_TYPE_FILTER) { + if (item.viewType == VIEW_TYPE_CHECK) { + if (!getUserConfig().isPremium()) { + showDialog(new PremiumFeatureBottomSheet(this, PremiumPreviewFragment.PREMIUM_FEATURE_FOLDER_TAGS, true)); + return; + } + TLRPC.TL_messages_toggleDialogFilterTags req = new TLRPC.TL_messages_toggleDialogFilterTags(); + req.enabled = !getMessagesController().folderTags; + getMessagesController().setFolderTags(req.enabled); + getConnectionsManager().sendRequest(req, (res, err) -> AndroidUtilities.runOnUIThread(() -> { + if (req.enabled && !loadedColors) { + loadingFiltersForColors = true; + getMessagesController().loadRemoteFilters(true); + loadedColors = true; + } + })); + ((TextCheckCell) view).setChecked(getMessagesController().folderTags); + adapter.notifyItemRangeChanged(filtersSectionStart, filtersSectionEnd - filtersSectionStart); + } else if (item.viewType == VIEW_TYPE_FILTER) { MessagesController.DialogFilter filter = item.filter; if (filter == null || filter.isDefault()) { return; @@ -646,6 +743,9 @@ public void onResume() { } } + private boolean loadingFiltersForColors; + private boolean loadedColors; + @Override public void didReceivedNotification(int id, int account, Object... args) { if (id == NotificationCenter.dialogFiltersUpdated) { @@ -654,7 +754,11 @@ public void didReceivedNotification(int id, int account, Object... args) { } updateRows(true); } else if (id == NotificationCenter.suggestedFiltersLoaded) { - updateRows(true); + if (scrollingToBottom) { + AndroidUtilities.runOnUIThread(() -> updateRows(true), 900); + } else { + updateRows(true); + } } } @@ -664,6 +768,9 @@ public void didReceivedNotification(int id, int account, Object... args) { private static final int VIEW_TYPE_SHADOW = 3; private static final int VIEW_TYPE_BUTTON = 4; private static final int VIEW_TYPE_FILTER_SUGGESTION = 5; + private static final int VIEW_TYPE_CHECK = 6; + + private int shiftDp = -4; private static class ItemInner extends AdapterWithDiffUtils.Item { public ItemInner(int viewType) { @@ -672,6 +779,7 @@ public ItemInner(int viewType) { CharSequence text; MessagesController.DialogFilter filter; + int filterColor; TLRPC.TL_dialogFilterSuggested suggested; public static ItemInner asHeader(CharSequence text) { @@ -690,6 +798,7 @@ public static ItemInner asShadow(CharSequence text) { public static ItemInner asFilter(MessagesController.DialogFilter filter) { ItemInner i = new ItemInner(VIEW_TYPE_FILTER); i.filter = filter; +// i.filterColor = filter == null || !MessagesController.getInstance(UserConfig.selectedAccount).folderTags ? -1 : filter.color; return i; } public static ItemInner asButton(CharSequence text) { @@ -702,6 +811,11 @@ public static ItemInner asSuggested(TLRPC.TL_dialogFilterSuggested suggested) { i.suggested = suggested; return i; } + public static ItemInner asCheck(CharSequence text) { + ItemInner i = new ItemInner(VIEW_TYPE_CHECK); + i.text = text; + return i; + } @Override public boolean equals(Object obj) { @@ -715,7 +829,7 @@ public boolean equals(Object obj) { if (other.viewType != viewType) { return false; } - if (viewType == VIEW_TYPE_HEADER || viewType == VIEW_TYPE_BUTTON || viewType == VIEW_TYPE_SHADOW) { + if (viewType == VIEW_TYPE_HEADER || viewType == VIEW_TYPE_BUTTON || viewType == VIEW_TYPE_SHADOW || viewType == VIEW_TYPE_CHECK) { if (!TextUtils.equals(text, other.text)) { return false; } @@ -724,7 +838,7 @@ public boolean equals(Object obj) { if ((filter == null) != (other.filter == null)) { return false; } - if (filter != null && filter.id != other.filter.id) { + if (filter != null && filter.id != other.filter.id) {// || filterColor != (!MessagesController.getInstance(UserConfig.selectedAccount).folderTags ? -1 : other.filter.color))) { return false; } } @@ -840,12 +954,16 @@ public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType view = filterCell; break; case VIEW_TYPE_SHADOW: - view = new ShadowSectionCell(mContext); + view = new TextInfoPrivacyCell(mContext); break; case VIEW_TYPE_BUTTON: view = new TextCell(mContext); view.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); break; + case VIEW_TYPE_CHECK: + view = new TextCheckCell(mContext); + view.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); + break; case VIEW_TYPE_FILTER_SUGGESTION: default: SuggestedFilterCell suggestedFilterCell = new SuggestedFilterCell(mContext); @@ -900,7 +1018,7 @@ public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType if (suggested.filter.exclude_muted) { filter.flags |= MessagesController.DIALOG_FILTER_FLAG_EXCLUDE_MUTED; } - FilterCreateActivity.saveFilterToServer(filter, filter.flags, filter.name, filter.alwaysShow, filter.neverShow, filter.pinnedDialogs, true, true, true, true, true, FiltersSetupActivity.this, () -> { + FilterCreateActivity.saveFilterToServer(filter, filter.flags, filter.name, filter.color, filter.alwaysShow, filter.neverShow, filter.pinnedDialogs, true, true, true, true, true, FiltersSetupActivity.this, () -> { getMessagesController().suggestedFilters.remove(suggested); getNotificationCenter().postNotificationName(NotificationCenter.dialogFiltersUpdated); }); @@ -918,6 +1036,7 @@ public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { return; } boolean divider = position + 1 < items.size() && items.get(position + 1).viewType != VIEW_TYPE_SHADOW; + boolean last = position + 1 >= items.size(); switch (holder.getItemViewType()) { case VIEW_TYPE_HEADER: { HeaderCell headerCell = (HeaderCell) holder.itemView; @@ -926,11 +1045,20 @@ public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { } case VIEW_TYPE_FILTER: { FilterCell filterCell = (FilterCell) holder.itemView; - filterCell.setFilter(item.filter, divider); + filterCell.setFilter(item.filter, divider, position); break; } case VIEW_TYPE_SHADOW: { - holder.itemView.setBackground(Theme.getThemedDrawableByKey(mContext, divider ? R.drawable.greydivider : R.drawable.greydivider_bottom, Theme.key_windowBackgroundGrayShadow)); + TextInfoPrivacyCell cell = (TextInfoPrivacyCell) holder.itemView; + if (TextUtils.isEmpty(item.text)) { + cell.setText(null); + cell.setFixedSize(12); + } else { + cell.setFixedSize(0); + cell.setText(item.text); + } + cell.setBottomPadding(last ? 32 : 17); + cell.setBackground(Theme.getThemedDrawableByKey(mContext, divider ? R.drawable.greydivider : R.drawable.greydivider_bottom, Theme.key_windowBackgroundGrayShadow)); break; } case VIEW_TYPE_BUTTON: { @@ -945,6 +1073,12 @@ public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { textCell.setTextAndIcon(item.text + "", combinedDrawable, false); break; } + case VIEW_TYPE_CHECK: { + TextCheckCell cell = (TextCheckCell) holder.itemView; + cell.setTextAndCheck(item.text, getMessagesController().folderTags, divider); + cell.setCheckBoxIcon(!getUserConfig().isPremium() ? R.drawable.permission_locked : 0); + break; + } case VIEW_TYPE_FILTER_SUGGESTION: { SuggestedFilterCell filterCell = (SuggestedFilterCell) holder.itemView; filterCell.setFilter(item.suggested, divider); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/GLIconSettingsView.java b/TMessagesProj/src/main/java/org/telegram/ui/GLIconSettingsView.java index a52dfefe721..dc5805923a2 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/GLIconSettingsView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/GLIconSettingsView.java @@ -38,7 +38,9 @@ public GLIconSettingsView(Context context, GLIconRenderer mRenderer) { seekBar.setDelegate(new SeekBarView.SeekBarViewDelegate() { @Override public void onSeekBarDrag(boolean stop, float progress) { - mRenderer.star.spec1 = 2 * progress; + if (mRenderer.model != null) { + mRenderer.model.spec1 = 2 * progress; + } } @Override @@ -46,7 +48,7 @@ public void onSeekBarPressed(boolean pressed) { } }); - seekBar.setProgress(mRenderer.star.spec1 / 2); + seekBar.setProgress(mRenderer.model == null ? 0 : mRenderer.model.spec1 / 2); seekBar.setReportChanges(true); addView(seekBar, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 38, 0, 5, 4, 5, 0)); @@ -65,7 +67,9 @@ public void onSeekBarPressed(boolean pressed) { seekBar.setDelegate(new SeekBarView.SeekBarViewDelegate() { @Override public void onSeekBarDrag(boolean stop, float progress) { - mRenderer.star.spec2 = 2 * progress; + if (mRenderer.model != null) { + mRenderer.model.spec2 = 2 * progress; + } } @Override @@ -73,7 +77,7 @@ public void onSeekBarPressed(boolean pressed) { } }); - seekBar.setProgress(mRenderer.star.spec2 / 2); + seekBar.setProgress(mRenderer.model == null ? 0 : mRenderer.model.spec2 / 2); seekBar.setReportChanges(true); addView(seekBar, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 38, 0, 5, 4, 5, 0)); @@ -94,7 +98,9 @@ public void onClick(View v) { @Override public void setColor(int color, int num, boolean applyNow) { - mRenderer.star.specColor = color; + if (mRenderer.model != null) { + mRenderer.model.specColor = color; + } } }) { @Override @@ -102,7 +108,7 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(300), MeasureSpec.EXACTLY)); } }; - colorPicker.setColor(mRenderer.star.specColor, 0); + colorPicker.setColor(mRenderer.model != null ? mRenderer.model.specColor : 0, 0); colorPicker.setType(-1, true, 1, 1, false, 0, false); BottomSheet bottomSheet = new BottomSheet(context, false); bottomSheet.setCustomView(colorPicker); @@ -127,7 +133,9 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { seekBar.setDelegate(new SeekBarView.SeekBarViewDelegate() { @Override public void onSeekBarDrag(boolean stop, float progress) { - mRenderer.star.diffuse = progress; + if (mRenderer.model != null) { + mRenderer.model.diffuse = progress; + } } @Override @@ -135,7 +143,7 @@ public void onSeekBarPressed(boolean pressed) { } }); - seekBar.setProgress(mRenderer.star.diffuse); + seekBar.setProgress(mRenderer.model == null ? 0 : mRenderer.model.diffuse); seekBar.setReportChanges(true); addView(seekBar, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 38, 0, 5, 4, 5, 0)); @@ -153,7 +161,9 @@ public void onSeekBarPressed(boolean pressed) { seekBar.setDelegate(new SeekBarView.SeekBarViewDelegate() { @Override public void onSeekBarDrag(boolean stop, float progress) { - mRenderer.star.normalSpec = 2 * progress; + if (mRenderer.model != null) { + mRenderer.model.normalSpec = 2 * progress; + } } @Override @@ -161,7 +171,7 @@ public void onSeekBarPressed(boolean pressed) { } }); - seekBar.setProgress(mRenderer.star.normalSpec / 2); + seekBar.setProgress(mRenderer.model == null ? 0 : mRenderer.model.normalSpec / 2); seekBar.setReportChanges(true); addView(seekBar, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 38, 0, 5, 4, 5, 0)); @@ -184,7 +194,9 @@ public void onClick(View v) { @Override public void setColor(int color, int num, boolean applyNow) { if (num == 0) { - mRenderer.star.normalSpecColor = color; + if (mRenderer.model != null) { + mRenderer.model.normalSpecColor = color; + } } } }) { @@ -193,7 +205,7 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(300), MeasureSpec.EXACTLY)); } }; - colorPicker.setColor(mRenderer.star.normalSpecColor, 0); + colorPicker.setColor(mRenderer.model == null ? 0 : mRenderer.model.normalSpecColor, 0); colorPicker.setType(-1, true, 1, 1, false, 0, false); BottomSheet bottomSheet = new BottomSheet(context, false); bottomSheet.setCustomView(colorPicker); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/GroupColorActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/GroupColorActivity.java index d3b39e6a8e3..496f5f4b2ae 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/GroupColorActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/GroupColorActivity.java @@ -158,7 +158,7 @@ public View createView(Context context) { public void onGlobalLayout() { view.getViewTreeObserver().removeOnGlobalLayoutListener(this); initProfilePreview(); - profilePreview.infoLayout.setOnClickListener(v -> openBoostDialog()); + profilePreview.infoLayout.setOnClickListener(v -> openBoostDialog(LimitReachedBottomSheet.TYPE_BOOSTS_FOR_USERS)); } }); return view; @@ -238,7 +238,7 @@ public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newStat }); } - private void openBoostDialog() { + protected void openBoostDialog(int type) { if (boostsStatus == null || isLoading) { return; } @@ -249,7 +249,7 @@ private void openBoostDialog() { isLoading = false; return; } - LimitReachedBottomSheet limitReachedBottomSheet = new LimitReachedBottomSheet(this, getContext(), LimitReachedBottomSheet.TYPE_BOOSTS_FOR_USERS, currentAccount, resourceProvider) { + LimitReachedBottomSheet limitReachedBottomSheet = new LimitReachedBottomSheet(this, getContext(), type, currentAccount, resourceProvider) { @Override public void onOpenAnimationEnd() { isLoading = false; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/InviteContactsActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/InviteContactsActivity.java index 6357380b6a5..0ee6eff556c 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/InviteContactsActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/InviteContactsActivity.java @@ -56,11 +56,12 @@ import org.telegram.ui.Cells.InviteTextCell; import org.telegram.ui.Cells.InviteUserCell; import org.telegram.ui.Components.EditTextBoldCursor; -import org.telegram.ui.Components.EmptyTextProgressView; +import org.telegram.ui.Components.FlickerLoadingView; import org.telegram.ui.Components.GroupCreateDividerItemDecoration; import org.telegram.ui.Components.GroupCreateSpan; import org.telegram.ui.Components.LayoutHelper; import org.telegram.ui.Components.RecyclerListView; +import org.telegram.ui.Components.StickerEmptyView; import java.util.ArrayList; import java.util.Collections; @@ -74,7 +75,7 @@ public class InviteContactsActivity extends BaseFragment implements Notification private SpansContainer spansContainer; private EditTextBoldCursor editText; private RecyclerListView listView; - private EmptyTextProgressView emptyView; + private StickerEmptyView emptyView; private InviteAdapter adapter; private TextView infoTextView; private FrameLayout counterView; @@ -278,6 +279,7 @@ public InviteContactsActivity() { @Override public boolean onFragmentCreate() { NotificationCenter.getInstance(currentAccount).addObserver(this, NotificationCenter.contactsImported); + NotificationCenter.getInstance(currentAccount).addObserver(this, NotificationCenter.contactsDidLoad); fetchContacts(); if (!UserConfig.getInstance(currentAccount).contactsReimported) { ContactsController.getInstance(currentAccount).forceImportContacts(); @@ -291,6 +293,7 @@ public boolean onFragmentCreate() { public void onFragmentDestroy() { super.onFragmentDestroy(); NotificationCenter.getInstance(currentAccount).removeObserver(this, NotificationCenter.contactsImported); + NotificationCenter.getInstance(currentAccount).removeObserver(this, NotificationCenter.contactsDidLoad); } @Override @@ -353,14 +356,14 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { } scrollView.measure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(maxSize, MeasureSpec.AT_MOST)); listView.measure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(height - scrollView.getMeasuredHeight() - h, MeasureSpec.EXACTLY)); - emptyView.measure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(height - scrollView.getMeasuredHeight() - AndroidUtilities.dp(72), MeasureSpec.EXACTLY)); + emptyView.measure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(height - scrollView.getMeasuredHeight() - h, MeasureSpec.EXACTLY)); } @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { scrollView.layout(0, 0, scrollView.getMeasuredWidth(), scrollView.getMeasuredHeight()); listView.layout(0, scrollView.getMeasuredHeight(), listView.getMeasuredWidth(), scrollView.getMeasuredHeight() + listView.getMeasuredHeight()); - emptyView.layout(0, scrollView.getMeasuredHeight() + AndroidUtilities.dp(72), emptyView.getMeasuredWidth(), scrollView.getMeasuredHeight() + emptyView.getMeasuredHeight()); + emptyView.layout(0, scrollView.getMeasuredHeight() + (searching ? 0 : AndroidUtilities.dp(72)), emptyView.getMeasuredWidth(), scrollView.getMeasuredHeight() + emptyView.getMeasuredHeight()); int y = bottom - top - infoTextView.getMeasuredHeight(); infoTextView.layout(0, y, infoTextView.getMeasuredWidth(), y + infoTextView.getMeasuredHeight()); y = bottom - top - counterView.getMeasuredHeight(); @@ -490,27 +493,49 @@ public void afterTextChanged(Editable editable) { adapter.searchDialogs(editText.getText().toString()); listView.setFastScrollVisible(false); listView.setVerticalScrollBarEnabled(true); - emptyView.setText(LocaleController.getString("NoResult", R.string.NoResult)); + emptyView.showProgress(true); + emptyView.setStickerType(StickerEmptyView.STICKER_TYPE_SEARCH); + emptyView.title.setText(LocaleController.getString("NoResult", R.string.NoResult)); + emptyView.subtitle.setText(LocaleController.getString("SearchEmptyViewFilteredSubtitle2", R.string.SearchEmptyViewFilteredSubtitle2)); } else { closeSearch(); } } }); - emptyView = new EmptyTextProgressView(context); - if (ContactsController.getInstance(currentAccount).isLoadingContacts()) { - emptyView.showProgress(); - } else { - emptyView.showTextView(); - } - emptyView.setText(LocaleController.getString("NoContacts", R.string.NoContacts)); + FlickerLoadingView flickerLoadingView = new FlickerLoadingView(context); + flickerLoadingView.setViewType(FlickerLoadingView.USERS_TYPE); + flickerLoadingView.showDate(false); + + emptyView = new StickerEmptyView(context, flickerLoadingView, StickerEmptyView.STICKER_TYPE_NO_CONTACTS); + emptyView.addView(flickerLoadingView, 0); + emptyView.setAnimateLayoutChange(true); + emptyView.title.setText(LocaleController.getString("NoContacts", R.string.NoContacts)); + emptyView.subtitle.setText(""); + emptyView.showProgress(ContactsController.getInstance(currentAccount).isLoadingContacts()); + frameLayout.addView(emptyView); LinearLayoutManager linearLayoutManager = new LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false); - listView = new RecyclerListView(context); + adapter = new InviteAdapter(context) { + @Override + protected void onSearchFinished() { + emptyView.showProgress(false); + } + }; + + listView = new RecyclerListView(context) { + @Override + public void setPadding(int left, int top, int right, int bottom) { + super.setPadding(left, top, right, bottom); + if (emptyView != null) { + emptyView.setPadding(left, top, right, bottom); + } + } + }; listView.setEmptyView(emptyView); - listView.setAdapter(adapter = new InviteAdapter(context)); + listView.setAdapter(adapter); listView.setLayoutManager(linearLayoutManager); listView.setVerticalScrollBarEnabled(true); listView.setVerticalScrollbarPosition(LocaleController.isRTL ? View.SCROLLBAR_POSITION_LEFT : View.SCROLLBAR_POSITION_RIGHT); @@ -643,6 +668,10 @@ public void onResume() { public void didReceivedNotification(int id, int account, Object... args) { if (id == NotificationCenter.contactsImported) { fetchContacts(); + } else if (id == NotificationCenter.contactsDidLoad) { + if (emptyView != null) { + emptyView.showProgress(false); + } } } @@ -691,7 +720,10 @@ private void closeSearch() { adapter.searchDialogs(null); listView.setFastScrollVisible(true); listView.setVerticalScrollBarEnabled(false); - emptyView.setText(LocaleController.getString("NoContacts", R.string.NoContacts)); + emptyView.showProgress(false); + emptyView.setStickerType(StickerEmptyView.STICKER_TYPE_NO_CONTACTS); + emptyView.title.setText(LocaleController.getString("NoContacts", R.string.NoContacts)); + emptyView.subtitle.setText(""); } private void fetchContacts() { @@ -705,7 +737,7 @@ private void fetchContacts() { return 0; }); if (emptyView != null) { - emptyView.showTextView(); + emptyView.showProgress(false); } if (adapter != null) { adapter.notifyDataSetChanged(); @@ -879,14 +911,21 @@ private void updateSearchResults(final ArrayList use searchResult = users; searchResultNames = names; notifyDataSetChanged(); + onSearchFinished(); }); } + protected void onSearchFinished() { + + } + @Override public void notifyDataSetChanged() { super.notifyDataSetChanged(); int count = getItemCount(); - emptyView.setVisibility(count == 1 ? View.VISIBLE : View.INVISIBLE); + if (!searching) { + emptyView.setVisibility(count == 1 ? View.VISIBLE : View.INVISIBLE); + } decoration.setSingle(count == 1); } } @@ -925,9 +964,6 @@ public ArrayList getThemeDescriptions() { themeDescriptions.add(new ThemeDescription(listView, 0, new Class[]{View.class}, Theme.dividerPaint, null, null, Theme.key_divider)); - themeDescriptions.add(new ThemeDescription(emptyView, ThemeDescription.FLAG_TEXTCOLOR, null, null, null, null, Theme.key_emptyListPlaceholder)); - themeDescriptions.add(new ThemeDescription(emptyView, ThemeDescription.FLAG_PROGRESSBAR, null, null, null, null, Theme.key_progressCircle)); - themeDescriptions.add(new ThemeDescription(editText, ThemeDescription.FLAG_TEXTCOLOR, null, null, null, null, Theme.key_windowBackgroundWhiteBlackText)); themeDescriptions.add(new ThemeDescription(editText, ThemeDescription.FLAG_HINTTEXTCOLOR, null, null, null, null, Theme.key_groupcreate_hintText)); themeDescriptions.add(new ThemeDescription(editText, ThemeDescription.FLAG_CURSORCOLOR, null, null, null, null, Theme.key_groupcreate_cursor)); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/LaunchActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/LaunchActivity.java index b1979e33b5b..0cba380ec0f 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/LaunchActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/LaunchActivity.java @@ -48,7 +48,6 @@ import android.text.TextUtils; import android.text.style.ClickableSpan; import android.util.Base64; -import android.util.Log; import android.util.SparseArray; import android.util.SparseIntArray; import android.view.ActionMode; @@ -112,6 +111,7 @@ import org.telegram.messenger.MessagesStorage; import org.telegram.messenger.NotificationCenter; import org.telegram.messenger.NotificationsController; +import org.telegram.messenger.OpenAttachedMenuBotReceiver; import org.telegram.messenger.PushListenerController; import org.telegram.messenger.R; import org.telegram.messenger.SendMessagesHelper; @@ -203,6 +203,7 @@ import java.util.List; import java.util.Map; import java.util.Set; +import java.util.concurrent.CountDownLatch; import java.util.concurrent.atomic.AtomicBoolean; import java.util.function.Consumer; import java.util.regex.Matcher; @@ -1728,6 +1729,9 @@ private boolean handleIntent(Intent intent, boolean isNew, boolean restore, bool boolean newContact = false; boolean newContactAlert = false; boolean scanQr = false; + boolean openBot = false; + long botId = 0; + long botType = -1; String searchQuery = null; String callSearchQuery = null; String newContactName = null; @@ -2613,6 +2617,8 @@ private boolean handleIntent(Intent intent, boolean isNew, boolean restore, bool open_settings = 8; } else if (url.contains("?disablelogs")) { open_settings = 9; + } else if (url.contains("premium_sms")) { + open_settings = 13; } else { open_settings = 1; } @@ -2806,6 +2812,11 @@ private boolean handleIntent(Intent intent, boolean isNew, boolean restore, bool showDialogsList = true; } } + } else if (intent.getAction().startsWith(OpenAttachedMenuBotReceiver.ACTION)) { + botId = intent.getLongExtra("botId", 0); + if (botId != 0) { + openBot = true; + } } else if (intent.getAction().equals("com.tmessages.openplayer")) { showPlayer = true; } else if (intent.getAction().equals("org.tmessages.openlocations")) { @@ -3003,6 +3014,8 @@ private boolean handleIntent(Intent intent, boolean isNew, boolean restore, bool fragment = new AutoDeleteMessagesActivity(); } else if (open_settings == 12) { fragment = new PrivacySettingsActivity(); + } else if (ApplicationLoader.applicationLoaderInstance != null) { + fragment = ApplicationLoader.applicationLoaderInstance.openSettings(open_settings); } else { fragment = null; } @@ -3139,6 +3152,9 @@ private boolean handleIntent(Intent intent, boolean isNew, boolean restore, bool drawerLayoutContainer.setAllowOpenDrawer(true, false); } pushOpened = true; + } else if (openBot) { + processAttachedMenuBotFromShortcut(botId); + pushOpened = false; } } if (!pushOpened && !isNew) { @@ -4940,6 +4956,47 @@ private void processWebAppBot(final int intentAccount, } + private void processAttachedMenuBotFromShortcut(long botId) { + for (int i = 0; i < visibleDialogs.size(); i++) { + if (visibleDialogs.get(i) instanceof BotWebViewSheet) { + BotWebViewSheet addedDialog = (BotWebViewSheet) visibleDialogs.get(i); + if (addedDialog.isShowing() && addedDialog.getBotId() == botId) { + return; + } + } + } + AtomicBoolean isMenuBotsUpdated = new AtomicBoolean(MediaDataController.getInstance(currentAccount).isMenuBotsUpdatedLocal()); + if (!isMenuBotsUpdated.get()) { + final CountDownLatch countDownLatch = new CountDownLatch(1); + MessagesStorage.getInstance(currentAccount).getStorageQueue().postRunnable(() -> { + isMenuBotsUpdated.set(MediaDataController.getInstance(currentAccount).isMenuBotsUpdatedLocal()); + countDownLatch.countDown(); + }); + try { + countDownLatch.await(); + } catch (Exception e) { + FileLog.e(e); + return; + } + } + if (isMenuBotsUpdated.get()) { + TLRPC.TL_attachMenuBots menuBots = MediaDataController.getInstance(currentAccount).getAttachMenuBots(); + if (menuBots.bots.isEmpty()) { + // Bot is removed from the menu. + MediaDataController.getInstance(currentAccount).uninstallShortcut(botId, MediaDataController.SHORTCUT_TYPE_ATTACHED_BOT); + return; + } + for (int i = 0; i < menuBots.bots.size(); i++) { + if (menuBots.bots.get(i).bot_id == botId) { + if (getLastFragment() != null) { + showAttachMenuBot(menuBots.bots.get(i), null); + } + return; + } + } + } + } + private void processBoostDialog(Long peerId, Runnable dismissLoading, Browser.Progress progress) { processBoostDialog(peerId, dismissLoading, progress, null); } @@ -5579,7 +5636,7 @@ public boolean didSelectDialogs(DialogsActivity dialogsFragment, ArrayList arrayList = new ArrayList<>(); arrayList.add(videoPath); - SendMessagesHelper.prepareSendingDocuments(accountInstance, arrayList, arrayList, null, captionToSend, null, did, replyToMsg, replyToMsg, null, null, null, notify, 0, null); + SendMessagesHelper.prepareSendingDocuments(accountInstance, arrayList, arrayList, null, captionToSend, null, did, replyToMsg, replyToMsg, null, null, null, notify, 0, null, null, 0); } } if (photoPathsArray != null && !photosEditorOpened) { @@ -5587,14 +5644,14 @@ public boolean didSelectDialogs(DialogsActivity dialogsFragment, ArrayList AlertsCreator.createDatePickerDialog(context, -1, (notify, scheduleDate) -> chooseDate(scheduleDate))); + timeEditText.setOnClickListener(view -> AlertsCreator.createDatePickerDialog(context, LocaleController.getString(R.string.ExpireAfter), LocaleController.getString(R.string.SetTimeLimit), -1, (notify, scheduleDate) -> chooseDate(scheduleDate))); timeChooseView.setCallback(index -> { if (index < dispalyedDates.size()) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/LocationActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/LocationActivity.java index f4a63769ad6..2bb63ff0281 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/LocationActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/LocationActivity.java @@ -100,6 +100,8 @@ import org.telegram.ui.Components.AlertsCreator; import org.telegram.ui.Components.AvatarDrawable; import org.telegram.ui.Components.BackupImageView; +import org.telegram.ui.Components.ChatAttachAlert; +import org.telegram.ui.Components.ChatAttachAlertLocationLayout; import org.telegram.ui.Components.CombinedDrawable; import org.telegram.ui.Components.CubicBezierInterpolator; import org.telegram.ui.Components.EditTextBoldCursor; @@ -111,7 +113,9 @@ import org.telegram.ui.Components.UndoView; import java.io.File; +import java.net.URLEncoder; import java.nio.ByteBuffer; +import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; @@ -578,12 +582,14 @@ public void onItemClick(int id) { } else { actionBar.setTitle(LocaleController.getString("ChatLocation", R.string.ChatLocation)); } - otherItem = menu.addItem(0, R.drawable.ic_ab_other, getResourceProvider()); - otherItem.addSubItem(open_in, R.drawable.msg_openin, LocaleController.getString("OpenInExternalApp", R.string.OpenInExternalApp)); - if (!getLocationController().isSharingLocation(dialogId) && isSharingAllowed) { - otherItem.addSubItem(share_live_location, R.drawable.msg_location, LocaleController.getString("SendLiveLocationMenu", R.string.SendLiveLocationMenu)); + if (locationType != 3) { + otherItem = menu.addItem(0, R.drawable.ic_ab_other, getResourceProvider()); + otherItem.addSubItem(open_in, R.drawable.msg_openin, LocaleController.getString("OpenInExternalApp", R.string.OpenInExternalApp)); + if (!getLocationController().isSharingLocation(dialogId) && isSharingAllowed) { + otherItem.addSubItem(share_live_location, R.drawable.msg_location, LocaleController.getString("SendLiveLocationMenu", R.string.SendLiveLocationMenu)); + } + otherItem.setContentDescription(LocaleController.getString("AccDescrMoreOptions", R.string.AccDescrMoreOptions)); } - otherItem.setContentDescription(LocaleController.getString("AccDescrMoreOptions", R.string.AccDescrMoreOptions)); } } else { actionBar.setTitle(LocaleController.getString("ShareLocation", R.string.ShareLocation)); @@ -603,6 +609,15 @@ public void onSearchCollapse() { searchWas = false; searchAdapter.searchDelayed(null, null); updateEmptyView(); + if (locationType == ChatAttachAlertLocationLayout.LOCATION_TYPE_BIZ) { + if (otherItem != null) { + otherItem.setVisibility(View.VISIBLE); + } + listView.setVisibility(View.VISIBLE); + mapViewClip.setVisibility(View.VISIBLE); + searchListView.setAdapter(null); + searchListView.setVisibility(View.GONE); + } } @Override @@ -698,7 +713,7 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { }; mapViewClip.setBackgroundDrawable(new MapPlaceholderDrawable(isActiveThemeDark())); - if (messageObject == null && (locationType == LOCATION_TYPE_SEND || locationType == LOCATION_TYPE_SEND_WITH_LIVE)) { + if (messageObject == null && (locationType == LOCATION_TYPE_SEND || locationType == LOCATION_TYPE_SEND_WITH_LIVE) || messageObject != null && locationType == 3) { searchAreaButton = new SearchButton(context); searchAreaButton.setTranslationX(-AndroidUtilities.dp(80)); Drawable drawable = Theme.createSimpleSelectorRoundRectDrawable(AndroidUtilities.dp(40), getThemedColor(Theme.key_location_actionBackground), getThemedColor(Theme.key_location_actionPressedBackground)); @@ -724,17 +739,31 @@ public void getOutline(View view, Outline outline) { searchAreaButton.setBackgroundDrawable(drawable); searchAreaButton.setTextColor(getThemedColor(Theme.key_location_actionActiveIcon)); searchAreaButton.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); - searchAreaButton.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); - searchAreaButton.setText(LocaleController.getString("PlacesInThisArea", R.string.PlacesInThisArea)); + searchAreaButton.setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)); searchAreaButton.setGravity(Gravity.CENTER); searchAreaButton.setPadding(AndroidUtilities.dp(20), 0, AndroidUtilities.dp(20), 0); mapViewClip.addView(searchAreaButton, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, Build.VERSION.SDK_INT >= 21 ? 40 : 44, Gravity.CENTER_HORIZONTAL | Gravity.TOP, 80, 12, 80, 0)); - searchAreaButton.setOnClickListener(v -> { - showSearchPlacesButton(false); - adapter.searchPlacesWithQuery(null, userLocation, true, true); - searchedForCustomLocations = true; - showResults(); - }); + if (locationType == 3) { + searchAreaButton.setText(LocaleController.getString(R.string.OpenInMaps)); + searchAreaButton.setOnClickListener(v -> { + try { + double lat = messageObject.messageOwner.media.geo.lat; + double lon = messageObject.messageOwner.media.geo._long; + getParentActivity().startActivity(new Intent(android.content.Intent.ACTION_VIEW, Uri.parse("geo:" + lat + "," + lon + "?q=" + lat + "," + lon))); + } catch (Exception e) { + FileLog.e(e); + } + }); + searchAreaButton.setTranslationX(0); + } else { + searchAreaButton.setText(LocaleController.getString(R.string.PlacesInThisArea)); + searchAreaButton.setOnClickListener(v -> { + showSearchPlacesButton(false); + adapter.searchPlacesWithQuery(null, userLocation, true, true); + searchedForCustomLocations = true; + showResults(); + }); + } } mapTypeButton = new ActionBarMenuItem(context, null, 0, getThemedColor(Theme.key_location_actionIcon), getResourceProvider()); @@ -823,10 +852,10 @@ public void getOutline(View view, Outline outline) { } } } - if (!checkGpsEnabled()) { + if (!checkGpsEnabled() && locationType != 3) { return; } - if (messageObject != null || chatLocation != null) { + if (messageObject != null && locationType != 3 || chatLocation != null) { if (myLocation != null && map != null) { map.animateCamera(ApplicationLoader.getMapsProvider().newCameraUpdateLatLngZoom(new IMapsProvider.LatLng(myLocation.getLatitude(), myLocation.getLongitude()), map.getMaxZoomLevel() - 4)); } @@ -838,7 +867,7 @@ public void getOutline(View view, Outline outline) { userLocationMoved = false; showSearchPlacesButton(false); map.animateCamera(ApplicationLoader.getMapsProvider().newCameraUpdateLatLng(new IMapsProvider.LatLng(myLocation.getLatitude(), myLocation.getLongitude()))); - if (searchedForCustomLocations) { + if (searchedForCustomLocations && locationType != ChatAttachAlertLocationLayout.LOCATION_TYPE_BIZ) { if (myLocation != null) { adapter.searchPlacesWithQuery(null, myLocation, true, true); } @@ -965,7 +994,7 @@ public void getOutline(View view, Outline outline) { emptyView.addView(emptySubtitleTextView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER, 0, 6, 0, 0)); listView = new RecyclerListView(context); - listView.setAdapter(adapter = new LocationActivityAdapter(context, locationType, dialogId, false, getResourceProvider(), false) { + listView.setAdapter(adapter = new LocationActivityAdapter(context, locationType, dialogId, false, getResourceProvider(), false, locationType == ChatAttachAlertLocationLayout.LOCATION_TYPE_BIZ) { @Override protected void onDirectionClick() { openDirections(null); @@ -999,6 +1028,9 @@ public void setLiveLocations(ArrayList liveLocations) { listView.setVerticalScrollBarEnabled(false); listView.setLayoutManager(layoutManager = new LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false)); frameLayout.addView(listView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.LEFT | Gravity.TOP)); + if (messageObject != null && messageObject.messageOwner != null && messageObject.messageOwner.media != null && !TextUtils.isEmpty(messageObject.messageOwner.media.address)) { + adapter.setAddressNameOverride(messageObject.messageOwner.media.address); + } listView.setOnScrollListener(new RecyclerView.OnScrollListener() { @Override @@ -1268,7 +1300,7 @@ public void dismiss() { searchListView = new RecyclerListView(context); searchListView.setVisibility(View.GONE); searchListView.setLayoutManager(new LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false)); - searchAdapter = new LocationActivitySearchAdapter(context, getResourceProvider(), false) { + searchAdapter = new LocationActivitySearchAdapter(context, getResourceProvider(), false, locationType == ChatAttachAlertLocationLayout.LOCATION_TYPE_BIZ) { @Override public void notifyDataSetChanged() { if (searchItem != null) { @@ -1295,7 +1327,17 @@ public void onScrollStateChanged(RecyclerView recyclerView, int newState) { }); searchListView.setOnItemClickListener((view, position) -> { TLRPC.TL_messageMediaVenue object = searchAdapter.getItem(position); - if (object != null && delegate != null) { + if (object != null && object.icon != null && locationType == ChatAttachAlertLocationLayout.LOCATION_TYPE_BIZ && this.map != null) { + userLocationMoved = true; + menu.closeSearchField(true); + final float zoom = "pin".equals(object.icon) ? this.map.getMaxZoomLevel() - 4 : this.map.getMaxZoomLevel() - 9; + this.map.animateCamera(ApplicationLoader.getMapsProvider().newCameraUpdateLatLngZoom(new IMapsProvider.LatLng(object.geo.lat, object.geo._long), zoom)); + if (userLocation != null) { + userLocation.setLatitude(object.geo.lat); + userLocation.setLongitude(object.geo._long); + } + adapter.setCustomLocation(userLocation); + } else if (object != null && delegate != null) { if (parentFragment != null && parentFragment.isInScheduleMode()) { AlertsCreator.createScheduleDatePickerDialog(getParentActivity(), parentFragment.getDialogId(), (notify, scheduleDate) -> { delegate.didSelectLocation(object, locationType, notify, scheduleDate); @@ -1439,6 +1481,9 @@ private void updateEmptyView() { } private void showSearchPlacesButton(boolean show) { + if (locationType == 3) { + show = true; + } if (show && searchAreaButton != null && searchAreaButton.getTag() == null) { if (myLocation == null || userLocation == null || userLocation.distanceTo(myLocation) < 300) { show = false; @@ -2239,7 +2284,7 @@ private void positionMarker(Location location) { if (messageObject == null && chatLocation == null && map != null) { IMapsProvider.LatLng latLng = new IMapsProvider.LatLng(location.getLatitude(), location.getLongitude()); if (adapter != null) { - if (!searchedForCustomLocations && locationType != LOCATION_TYPE_GROUP) { + if (!searchedForCustomLocations && locationType != LOCATION_TYPE_GROUP && locationType != ChatAttachAlertLocationLayout.LOCATION_TYPE_BIZ) { adapter.searchPlacesWithQuery(null, myLocation, true); } adapter.setGpsLocation(myLocation); @@ -2909,6 +2954,10 @@ public ArrayList getThemeDescriptions() { return themeDescriptions; } + public String getAddressName() { + return adapter != null ? adapter.getAddressName() : null; + } + @Override public boolean isLightStatusBar() { return ColorUtils.calculateLuminance(getThemedColor(Theme.key_windowBackgroundWhite)) > 0.7f; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/NewContactBottomSheet.java b/TMessagesProj/src/main/java/org/telegram/ui/NewContactBottomSheet.java index e1360ec519d..2a547673ab4 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/NewContactBottomSheet.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/NewContactBottomSheet.java @@ -667,7 +667,7 @@ private void doOnDone() { if (res != null) { if (!res.users.isEmpty()) { MessagesController.getInstance(currentAccount).putUsers(res.users, false); - MessagesController.openChatOrProfileWith(res.users.get(0), null, parentFragment, 1, true); + MessagesController.openChatOrProfileWith(res.users.get(0), null, parentFragment, 1, false); dismiss(); } else { if (parentFragment.getParentActivity() == null) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/PeerColorActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/PeerColorActivity.java index da59edd3dea..2dd4f57a4c9 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/PeerColorActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/PeerColorActivity.java @@ -2,6 +2,7 @@ import static org.telegram.messenger.AndroidUtilities.dp; import static org.telegram.messenger.AndroidUtilities.dpf2; +import static org.telegram.messenger.AndroidUtilities.lerp; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; @@ -1552,6 +1553,8 @@ public static class PeerColorGrid extends View { private final Paint backgroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG); { backgroundPaint.setStyle(Paint.Style.STROKE); } + public static final int TYPE_FOLDER_TAG = 2; + public class ColorButton { private final Paint paint1 = new Paint(Paint.ANTI_ALIAS_FLAG); private final Paint paint2 = new Paint(Paint.ANTI_ALIAS_FLAG); @@ -1559,6 +1562,11 @@ public class ColorButton { private final Path circlePath = new Path(); private final Path color2Path = new Path(); private boolean hasColor2, hasColor3; + private boolean hasClose; + + private Path closePath; + private Paint closePaint; + private Drawable lockDrawable; private final ButtonBounce bounce = new ButtonBounce(PeerColorGrid.this); @@ -1576,6 +1584,10 @@ public void set(int color1, int color2) { paint2.setColor(color2); } + public void setClose(boolean close) { + hasClose = close; + } + public void set(MessagesController.PeerColor color) { if (color == null) { return; @@ -1661,11 +1673,45 @@ protected void draw(Canvas canvas) { backgroundPaint.setColor(Theme.getColor(Theme.key_windowBackgroundWhite, resourcesProvider)); canvas.drawCircle( bounds.centerX(), bounds.centerY(), - Math.min(bounds.height() / 2f, bounds.width() / 2f) + backgroundPaint.getStrokeWidth() * AndroidUtilities.lerp(.5f, -2f, selectT), + Math.min(bounds.height() / 2f, bounds.width() / 2f) + backgroundPaint.getStrokeWidth() * lerp(.5f, -2f, selectT), backgroundPaint ); } + if (hasClose) { + if (lock) { + if (lockDrawable == null) { + lockDrawable = getContext().getResources().getDrawable(R.drawable.msg_mini_lock3); + lockDrawable.setColorFilter(new PorterDuffColorFilter(Color.WHITE, PorterDuff.Mode.SRC_IN)); + } + lockDrawable.setBounds( + (int) (bounds.centerX() - lockDrawable.getIntrinsicWidth() / 2f * 1.2f), + (int) (bounds.centerY() - lockDrawable.getIntrinsicHeight() / 2f * 1.2f), + (int) (bounds.centerX() + lockDrawable.getIntrinsicWidth() / 2f * 1.2f), + (int) (bounds.centerY() + lockDrawable.getIntrinsicHeight() / 2f * 1.2f) + ); + lockDrawable.draw(canvas); + } else { + if (closePath == null) { + closePath = new Path(); + } + if (closePaint == null) { + closePaint = new Paint(Paint.ANTI_ALIAS_FLAG); + closePaint.setColor(0xffffffff); + closePaint.setStyle(Paint.Style.STROKE); + closePaint.setStrokeCap(Paint.Cap.ROUND); + } + closePaint.setStrokeWidth(dp(2)); + closePath.rewind(); + final float r = lerp(dp(5), dp(4), selectT); + closePath.moveTo(bounds.centerX() - r, bounds.centerY() - r); + closePath.lineTo(bounds.centerX() + r, bounds.centerY() + r); + closePath.moveTo(bounds.centerX() + r, bounds.centerY() - r); + closePath.lineTo(bounds.centerX() - r, bounds.centerY() + r); + canvas.drawPath(closePath, closePaint); + } + } + canvas.restore(); } @@ -1681,6 +1727,7 @@ public void setPressed(boolean pressed) { private final int type; private final int currentAccount; + private boolean lock; private ColorButton[] buttons; @@ -1691,12 +1738,20 @@ public PeerColorGrid(Context context, int type, int currentAccount, Theme.Resour this.resourcesProvider = resourcesProvider; } + public void setCloseAsLock(boolean lock) { + this.lock = lock; + } + public void updateColors() { if (buttons == null) return; final MessagesController mc = MessagesController.getInstance(currentAccount); final MessagesController.PeerColors peerColors = type == PAGE_NAME ? mc.peerColors : mc.profilePeerColors; for (int i = 0; i < buttons.length; ++i) { - if (i < 7 && type == PAGE_NAME) { + if (type == TYPE_FOLDER_TAG) { + buttons[i].id = order[i]; + buttons[i].setClose(buttons[i].id < 0); + buttons[i].set(Theme.getColor(order[i] < 0 ? Theme.key_avatar_backgroundGray : Theme.keys_avatar_nameInMessage[order[i] % Theme.keys_avatar_nameInMessage.length], resourcesProvider)); + } else if (i < 7 && type == PAGE_NAME) { buttons[i].id = order[i]; buttons[i].set(Theme.getColor(Theme.keys_avatar_nameInMessage[order[i]], resourcesProvider)); } else { @@ -1709,7 +1764,7 @@ public void updateColors() { } invalidate(); } - final int[] order = new int[] { 5, 3, 1, 0, 2, 4, 6 }; + final int[] order = new int[] { 5, 3, 1, 0, 2, 4, 6, -1 }; @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { @@ -1717,8 +1772,18 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { final MessagesController mc = MessagesController.getInstance(currentAccount); final MessagesController.PeerColors peerColors = type == PAGE_NAME ? mc.peerColors : mc.profilePeerColors; - final int colorsCount = peerColors == null ? 0 : peerColors.colors.size(); - final int columns = type == PAGE_NAME ? 7 : 8; + int colorsCount = peerColors == null ? 0 : peerColors.colors.size(); + if (type == TYPE_FOLDER_TAG) { + colorsCount = 8; + } + final int columns; + if (type == TYPE_FOLDER_TAG) { + columns = 8; + } else if (type == PAGE_NAME) { + columns = 7; + } else { + columns = 8; + } final float iconSize = Math.min(dp(38 + 16), width / (columns + (columns + 1) * .28947f)); final float horizontalSeparator = Math.min(iconSize * .28947f, dp(8)); @@ -1733,7 +1798,11 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { buttons = new ColorButton[colorsCount]; for (int i = 0; i < colorsCount; ++i) { buttons[i] = new ColorButton(); - if (peerColors != null && i >= 0 && i < peerColors.colors.size()) { + if (type == TYPE_FOLDER_TAG) { + buttons[i].id = order[i]; + buttons[i].setClose(buttons[i].id < 0); + buttons[i].set(Theme.getColor(order[i] < 0 ? Theme.key_avatar_backgroundGray : Theme.keys_avatar_nameInMessage[order[i] % Theme.keys_avatar_nameInMessage.length], resourcesProvider)); + } else if (peerColors != null && i >= 0 && i < peerColors.colors.size()) { buttons[i].id = peerColors.colors.get(i).id; buttons[i].set(peerColors.colors.get(i)); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/PhotoViewer.java b/TMessagesProj/src/main/java/org/telegram/ui/PhotoViewer.java index 5abeceefe9e..1fc2fa57606 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/PhotoViewer.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/PhotoViewer.java @@ -76,6 +76,7 @@ import android.transition.TransitionSet; import android.transition.TransitionValues; import android.util.FloatProperty; +import android.util.Log; import android.util.Pair; import android.util.Property; import android.util.Range; @@ -136,6 +137,9 @@ import com.google.android.exoplayer2.ExoPlayer; import com.google.android.exoplayer2.analytics.AnalyticsListener; import com.google.android.exoplayer2.ui.AspectRatioFrameLayout; +import com.google.android.gms.vision.Frame; +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.AnimationNotificationsLocker; @@ -5052,7 +5056,7 @@ public void onItemClick(int id) { encryptedChat = MessagesController.getInstance(currentAccount).getEncryptedChat(DialogObject.getEncryptedChatId(obj.getDialogId())); } - MessagesController.getInstance(currentAccount).deleteMessages(arr, random_ids, encryptedChat, obj.getDialogId(), deleteForAll[0], obj.scheduled); + MessagesController.getInstance(currentAccount).deleteMessages(arr, random_ids, encryptedChat, obj.getDialogId(), obj.getQuickReplyId(), deleteForAll[0], obj.getChatMode()); } } else if (!avatarsArr.isEmpty()) { if (currentIndex < 0 || currentIndex >= avatarsArr.size()) { @@ -5062,7 +5066,7 @@ public void onItemClick(int id) { if (message != null) { ArrayList arr = new ArrayList<>(); arr.add(message.id); - MessagesController.getInstance(currentAccount).deleteMessages(arr, null, null, MessageObject.getDialogId(message), true, false); + MessagesController.getInstance(currentAccount).deleteMessages(arr, null, null, MessageObject.getDialogId(message), message.quick_reply_shortcut_id, true, 0); NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.reloadDialogPhotos); } if (isCurrentAvatarSet()) { @@ -9810,45 +9814,45 @@ private void detectFaces(String key, ImageReceiver.BitmapHolder bitmap, int orie if (key == null || bitmap == null || bitmap.bitmap == null) { return; } -// Utilities.globalQueue.postRunnable(() -> { -// FaceDetector faceDetector = null; -// try { -// faceDetector = new FaceDetector.Builder(ApplicationLoader.applicationContext) -// .setMode(FaceDetector.FAST_MODE) -// .setLandmarkType(FaceDetector.NO_LANDMARKS) -// .setTrackingEnabled(false).build(); -// if (faceDetector.isOperational()) { -// Frame frame = new Frame.Builder().setBitmap(bitmap.bitmap).setRotation(orientation).build(); -// SparseArray faces = faceDetector.detect(frame); -// boolean hasFaces = faces != null && faces.size() != 0; -// AndroidUtilities.runOnUIThread(() -> { -// String imageKey = centerImage.getImageKey(); -// if (key.equals(imageKey)) { -// currentImageHasFace = hasFaces ? 1 : 0; -// currentImageFaceKey = key; -// } -// }); -// } else { -// if (BuildVars.LOGS_ENABLED) { -// FileLog.e("face detection is not operational"); -// } -// AndroidUtilities.runOnUIThread(() -> { -// bitmap.release(); -// String imageKey = centerImage.getImageKey(); -// if (key.equals(imageKey)) { -// currentImageHasFace = 2; -// currentImageFaceKey = key; -// } -// }); -// } -// } catch (Exception e) { -// FileLog.e(e); -// } finally { -// if (faceDetector != null) { -// faceDetector.release(); -// } -// } -// }); + Utilities.globalQueue.postRunnable(() -> { + FaceDetector faceDetector = null; + try { + faceDetector = new FaceDetector.Builder(ApplicationLoader.applicationContext) + .setMode(FaceDetector.FAST_MODE) + .setLandmarkType(FaceDetector.NO_LANDMARKS) + .setTrackingEnabled(false).build(); + if (faceDetector.isOperational()) { + Frame frame = new Frame.Builder().setBitmap(bitmap.bitmap).setRotation(orientation).build(); + SparseArray faces = faceDetector.detect(frame); + boolean hasFaces = faces != null && faces.size() != 0; + AndroidUtilities.runOnUIThread(() -> { + String imageKey = centerImage.getImageKey(); + if (key.equals(imageKey)) { + currentImageHasFace = hasFaces ? 1 : 0; + currentImageFaceKey = key; + } + }); + } else { + if (BuildVars.LOGS_ENABLED) { + FileLog.e("face detection is not operational"); + } + AndroidUtilities.runOnUIThread(() -> { + bitmap.release(); + String imageKey = centerImage.getImageKey(); + if (key.equals(imageKey)) { + currentImageHasFace = 2; + currentImageFaceKey = key; + } + }); + } + } catch (Exception e) { + FileLog.e(e); + } finally { + if (faceDetector != null) { + faceDetector.release(); + } + } + }); } private boolean wasCountViewShown; @@ -9870,7 +9874,7 @@ public void switchToEditMode(final int mode) { navigationBarColorTo = 0xcc000000; } else if (mode == EDIT_MODE_PAINT) { navigationBarColorTo = 0xff000000; - } else if (mode == EDIT_MODE_NONE && fancyShadows) { + } else if (mode == EDIT_MODE_NONE && fancyShadows && savedState == null) { navigationBarColorTo = 0; } else { navigationBarColorTo = 0x7f000000; @@ -11628,10 +11632,10 @@ private void onPhotoShow(final MessageObject messageObject, final TLRPC.FileLoca if (messageObject.canForwardMessage() && !noforwards) { setItemVisible(sendItem, true, false); } - } else if (!messageObject.scheduled && !(MessageObject.getMedia(messageObject.messageOwner) instanceof TLRPC.TL_messageMediaInvoice) && !(MessageObject.getMedia(messageObject.messageOwner) instanceof TLRPC.TL_messageMediaWebPage) && (messageObject.messageOwner.action == null || messageObject.messageOwner.action instanceof TLRPC.TL_messageActionEmpty)) { + } else if (!messageObject.scheduled && !messageObject.isQuickReply() && !(MessageObject.getMedia(messageObject.messageOwner) instanceof TLRPC.TL_messageMediaInvoice) && !(MessageObject.getMedia(messageObject.messageOwner) instanceof TLRPC.TL_messageMediaWebPage) && (messageObject.messageOwner.action == null || messageObject.messageOwner.action instanceof TLRPC.TL_messageActionEmpty)) { needSearchImageInArr = true; imagesByIds[0].put(messageObject.getId(), messageObject); - if (parentChatActivity == null || !parentChatActivity.isThreadChat() && parentChatActivity.getChatMode() != ChatActivity.MODE_SAVED) { + if (parentChatActivity == null || !parentChatActivity.isThreadChat() && parentChatActivity.getChatMode() != ChatActivity.MODE_SAVED && parentChatActivity.getChatMode() != ChatActivity.MODE_QUICK_REPLIES) { menuItem.showSubItem(gallery_menu_showinchat); menuItem.showSubItem(gallery_menu_showall); } @@ -11694,7 +11698,7 @@ private void onPhotoShow(final MessageObject messageObject, final TLRPC.FileLoca imagesByIds[message.getDialogId() == currentDialogId ? 0 : 1].put(message.getId(), message); } MessageObject openingObject = imagesArr.get(index); - if (!openingObject.scheduled && (parentChatActivity == null || !parentChatActivity.isThreadChat())) { + if (!openingObject.scheduled && !openingObject.isQuickReply() && (parentChatActivity == null || !parentChatActivity.isThreadChat())) { opennedFromMedia = parentChatActivity == null; if (parentFragment instanceof ProfileActivity) { openedFromProfile = true; @@ -11950,7 +11954,7 @@ private void setIsAboutToSwitchToIndex(int index, boolean init, boolean animated title = FilteredSearchView.createFromInfoString(newMessageObject, opennedFromMedia && !openedFromProfile, 0); CharSequence subtitle = null; - if (newMessageObject.messageOwner != null) { + if (!newMessageObject.isQuickReply() && newMessageObject.messageOwner != null) { subtitle = LocaleController.formatDateAudio(newMessageObject.messageOwner.date, false); } actionBarContainer.setSubtitle(subtitle, animated); @@ -12085,7 +12089,11 @@ private void setIsAboutToSwitchToIndex(int index, boolean init, boolean animated } allowShare = !noforwards; } - if (currentFiltered && (currentFilterTag != null || !TextUtils.isEmpty(currentFilterQuery))) { + if (parentChatActivity != null && parentChatActivity.getChatMode() == ChatActivity.MODE_QUICK_REPLIES) { + if (countView != null) { + countView.updateShow(false, animated); + } + } else if (currentFiltered && (currentFilterTag != null || !TextUtils.isEmpty(currentFilterQuery))) { if (countView != null) { countView.updateShow(true, animated); countView.set(1 + switchingToIndex, imagesArr.size()); @@ -12243,7 +12251,7 @@ private void setIsAboutToSwitchToIndex(int index, boolean init, boolean animated } ImageLocation imageLocation = imagesArrLocations.get(index); if (imageLocation != null && imageLocation.photo != null) { - actionBarContainer.setSubtitle(LocaleController.formatDateTime(imageLocation.photo.date), animated); + actionBarContainer.setSubtitle(LocaleController.formatDateTime(imageLocation.photo.date, true), animated); } else { actionBarContainer.setSubtitle("", animated); } @@ -12557,6 +12565,9 @@ private void setIsAboutToSwitchToIndex(int index, boolean init, boolean animated actionBar.setBackgroundColor(fancyShadows || setAvatarFor != null ? 0 : Theme.ACTION_BAR_PHOTO_VIEWER_COLOR); actionBarContainer.setTextShadows(fancyShadows); navigationBar.setVisibility(fancyShadows ? View.GONE : View.VISIBLE); + if (currentEditMode == EDIT_MODE_NONE) { + navigationBar.setBackgroundColor(fancyShadows ? 0 : 0x7f000000); + } if (title != null) { if (animated) { if (wasIndex == index) { @@ -14212,15 +14223,15 @@ private void sendMedia(VideoEditedInfo videoEditedInfo, boolean notify, int sche } if (photoEntry.isVideo) { if (videoEditedInfo != null) { - SendMessagesHelper.prepareSendingVideo(parentChatActivity.getAccountInstance(), photoEntry.path, videoEditedInfo, parentChatActivity.getDialogId(), parentChatActivity.getReplyMessage(), parentChatActivity.getThreadMessage(), null, parentChatActivity.getReplyQuote(), photoEntry.entities, photoEntry.ttl, editingMessageObject, notify, scheduleDate, forceDocument, photoEntry.hasSpoiler, photoEntry.caption); + SendMessagesHelper.prepareSendingVideo(parentChatActivity.getAccountInstance(), photoEntry.path, videoEditedInfo, parentChatActivity.getDialogId(), parentChatActivity.getReplyMessage(), parentChatActivity.getThreadMessage(), null, parentChatActivity.getReplyQuote(), photoEntry.entities, photoEntry.ttl, editingMessageObject, notify, scheduleDate, forceDocument, photoEntry.hasSpoiler, photoEntry.caption, parentChatActivity.quickReplyShortcut, parentChatActivity.getQuickReplyId()); } else { - SendMessagesHelper.prepareSendingVideo(parentChatActivity.getAccountInstance(), photoEntry.path, null, parentChatActivity.getDialogId(), parentChatActivity.getReplyMessage(), parentChatActivity.getThreadMessage(), null, parentChatActivity.getReplyQuote(), photoEntry.entities, photoEntry.ttl, editingMessageObject, notify, scheduleDate, forceDocument, photoEntry.hasSpoiler, photoEntry.caption); + SendMessagesHelper.prepareSendingVideo(parentChatActivity.getAccountInstance(), photoEntry.path, null, parentChatActivity.getDialogId(), parentChatActivity.getReplyMessage(), parentChatActivity.getThreadMessage(), null, parentChatActivity.getReplyQuote(), photoEntry.entities, photoEntry.ttl, editingMessageObject, notify, scheduleDate, forceDocument, photoEntry.hasSpoiler, photoEntry.caption, parentChatActivity.quickReplyShortcut, parentChatActivity.getQuickReplyId()); } } else { if (photoEntry.imagePath != null) { - SendMessagesHelper.prepareSendingPhoto(parentChatActivity.getAccountInstance(), photoEntry.imagePath, photoEntry.thumbPath, null, parentChatActivity.getDialogId(), parentChatActivity.getReplyMessage(), parentChatActivity.getThreadMessage(), null, parentChatActivity.getReplyQuote(), photoEntry.entities, photoEntry.stickers, null, photoEntry.ttl, editingMessageObject, videoEditedInfo, notify, scheduleDate, forceDocument, photoEntry.caption); + SendMessagesHelper.prepareSendingPhoto(parentChatActivity.getAccountInstance(), photoEntry.imagePath, photoEntry.thumbPath, null, parentChatActivity.getDialogId(), parentChatActivity.getReplyMessage(), parentChatActivity.getThreadMessage(), null, parentChatActivity.getReplyQuote(), photoEntry.entities, photoEntry.stickers, null, photoEntry.ttl, editingMessageObject, videoEditedInfo, notify, scheduleDate, 0, forceDocument, photoEntry.caption, parentChatActivity.quickReplyShortcut, parentChatActivity.getQuickReplyId()); } else if (photoEntry.path != null) { - SendMessagesHelper.prepareSendingPhoto(parentChatActivity.getAccountInstance(), photoEntry.path, photoEntry.thumbPath, null, parentChatActivity.getDialogId(), parentChatActivity.getReplyMessage(), parentChatActivity.getThreadMessage(), null, parentChatActivity.getReplyQuote(), photoEntry.entities, photoEntry.stickers, null, photoEntry.ttl, editingMessageObject, videoEditedInfo, notify, scheduleDate, forceDocument, photoEntry.caption); + SendMessagesHelper.prepareSendingPhoto(parentChatActivity.getAccountInstance(), photoEntry.path, photoEntry.thumbPath, null, parentChatActivity.getDialogId(), parentChatActivity.getReplyMessage(), parentChatActivity.getThreadMessage(), null, parentChatActivity.getReplyQuote(), photoEntry.entities, photoEntry.stickers, null, photoEntry.ttl, editingMessageObject, videoEditedInfo, notify, scheduleDate, 0, forceDocument, photoEntry.caption, parentChatActivity.quickReplyShortcut, parentChatActivity.getQuickReplyId()); } } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/PremiumFeatureCell.java b/TMessagesProj/src/main/java/org/telegram/ui/PremiumFeatureCell.java index a38904f0a1b..fa60ded2b3f 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/PremiumFeatureCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/PremiumFeatureCell.java @@ -1,9 +1,15 @@ package org.telegram.ui; +import static org.telegram.messenger.AndroidUtilities.dp; + import android.content.Context; import android.graphics.Canvas; +import android.graphics.PorterDuff; +import android.graphics.PorterDuffColorFilter; +import android.graphics.drawable.Drawable; import android.util.TypedValue; import android.view.Gravity; +import android.view.View; import android.widget.FrameLayout; import android.widget.ImageView; import android.widget.LinearLayout; @@ -12,18 +18,28 @@ import androidx.core.content.ContextCompat; import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.LocaleController; import org.telegram.messenger.R; +import org.telegram.messenger.UserConfig; +import org.telegram.messenger.UserObject; +import org.telegram.tgnet.TLRPC; import org.telegram.ui.ActionBar.SimpleTextView; import org.telegram.ui.ActionBar.Theme; +import org.telegram.ui.Components.AnimatedEmojiDrawable; import org.telegram.ui.Components.LayoutHelper; +import org.telegram.ui.Components.Text; public class PremiumFeatureCell extends FrameLayout { private final SimpleTextView title; private final TextView description; public ImageView imageView; + public final ImageView nextIcon; boolean drawDivider; public PremiumPreviewFragment.PremiumFeatureData data; + + public AnimatedEmojiDrawable.SwapAnimatedEmojiDrawable imageDrawable; + public PremiumFeatureCell(Context context) { this(context, null); } @@ -54,15 +70,32 @@ public PremiumFeatureCell(Context context, Theme.ResourcesProvider resourcesProv imageView.setScaleType(ImageView.ScaleType.CENTER_INSIDE); addView(imageView, LayoutHelper.createFrame(28, 28, 0, 18, 12, 0, 0)); - ImageView nextIcon = new ImageView(context); + nextIcon = new ImageView(context); nextIcon.setScaleType(ImageView.ScaleType.CENTER_INSIDE); nextIcon.setImageResource(R.drawable.msg_arrowright); nextIcon.setColorFilter(Theme.getColor(Theme.key_switchTrack, resourcesProvider)); addView(nextIcon, LayoutHelper.createFrame(24, 24, Gravity.RIGHT | Gravity.CENTER_VERTICAL, 0, 0, 18, 0)); } - public void setData(PremiumPreviewFragment.PremiumFeatureData data, boolean drawDivider) { + if (UserConfig.getInstance(UserConfig.selectedAccount).isPremium() && data.type == PremiumPreviewFragment.PREMIUM_FEATURE_EMOJI_STATUS && data.icon == R.drawable.filled_premium_status2) { + nextIcon.setVisibility(View.GONE); + if (imageDrawable == null) { + imageDrawable = new AnimatedEmojiDrawable.SwapAnimatedEmojiDrawable(this, false, dp(24), AnimatedEmojiDrawable.CACHE_TYPE_ALERT_PREVIEW_STATIC); + if (isAttachedToWindow()) { + imageDrawable.attach(); + } + } + TLRPC.User user = UserConfig.getInstance(UserConfig.selectedAccount).getCurrentUser(); + Long emojiStatusDocumentId = UserObject.getEmojiStatusDocumentId(user); + setEmoji(emojiStatusDocumentId == null ? 0 : emojiStatusDocumentId, false); + } else { + nextIcon.setVisibility(View.VISIBLE); + if (imageDrawable != null){ + imageDrawable.detach(); + imageDrawable = null; + } + } this.data = data; title.setText(data.title); description.setText(data.description); @@ -70,11 +103,54 @@ public void setData(PremiumPreviewFragment.PremiumFeatureData data, boolean draw this.drawDivider = drawDivider; } + private Drawable premiumStar; + public void setEmoji(long documentId, boolean animated) { + if (documentId == 0) { + if (premiumStar == null) { + premiumStar = getContext().getResources().getDrawable(R.drawable.msg_premium_prolfilestar).mutate(); + premiumStar.setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_windowBackgroundWhiteBlueIcon), PorterDuff.Mode.SRC_IN)); + } + imageDrawable.set(premiumStar, animated); + } else { + imageDrawable.set(documentId, animated); + } + } + + public void updateImageBounds() { + imageDrawable.setBounds( + getWidth() - imageDrawable.getIntrinsicWidth() - dp(21), + (getHeight() - imageDrawable.getIntrinsicHeight()) / 2, + getWidth() - dp(21), + (getHeight() + imageDrawable.getIntrinsicHeight()) / 2 + ); + } + @Override protected void dispatchDraw(Canvas canvas) { super.dispatchDraw(canvas); + if (imageDrawable != null) { + updateImageBounds(); + imageDrawable.setColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlueIcon)); + imageDrawable.draw(canvas); + } if (drawDivider) { canvas.drawRect(AndroidUtilities.dp(62), getMeasuredHeight() - 1, getMeasuredWidth(), getMeasuredHeight(), Theme.dividerPaint); } } + + @Override + protected void onAttachedToWindow() { + if (imageDrawable != null) { + imageDrawable.attach(); + } + super.onAttachedToWindow(); + } + + @Override + protected void onDetachedFromWindow() { + if (imageDrawable != null) { + imageDrawable.detach(); + } + super.onDetachedFromWindow(); + } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/PremiumPreviewFragment.java b/TMessagesProj/src/main/java/org/telegram/ui/PremiumPreviewFragment.java index 628c678d013..429b8a5484e 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/PremiumPreviewFragment.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/PremiumPreviewFragment.java @@ -1,5 +1,7 @@ package org.telegram.ui; +import static org.telegram.messenger.AndroidUtilities.dp; + import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.ValueAnimator; @@ -22,6 +24,7 @@ import android.graphics.drawable.Drawable; import android.net.Uri; import android.os.Build; +import android.os.Bundle; import android.text.SpannableString; import android.text.SpannableStringBuilder; import android.text.Spanned; @@ -58,6 +61,7 @@ import org.telegram.messenger.NotificationCenter; import org.telegram.messenger.R; import org.telegram.messenger.UserConfig; +import org.telegram.messenger.UserObject; import org.telegram.messenger.Utilities; import org.telegram.messenger.browser.Browser; import org.telegram.tgnet.ConnectionsManager; @@ -66,23 +70,35 @@ import org.telegram.ui.ActionBar.BaseFragment; import org.telegram.ui.ActionBar.Theme; import org.telegram.ui.ActionBar.ThemeDescription; +import org.telegram.ui.Business.AwayMessagesActivity; +import org.telegram.ui.Business.BusinessChatbotController; +import org.telegram.ui.Business.ChatbotsActivity; +import org.telegram.ui.Business.GreetMessagesActivity; +import org.telegram.ui.Business.LocationActivity; +import org.telegram.ui.Business.OpeningHoursActivity; +import org.telegram.ui.Business.QuickRepliesActivity; +import org.telegram.ui.Business.QuickRepliesController; +import org.telegram.ui.Business.TimezonesController; +import org.telegram.ui.Cells.HeaderCell; import org.telegram.ui.Cells.ShadowSectionCell; import org.telegram.ui.Cells.TextInfoPrivacyCell; import org.telegram.ui.Components.AlertsCreator; +import org.telegram.ui.Components.AnimatedEmojiDrawable; import org.telegram.ui.Components.CombinedDrawable; import org.telegram.ui.Components.CubicBezierInterpolator; import org.telegram.ui.Components.FillLastLinearLayoutManager; import org.telegram.ui.Components.LayoutHelper; +import org.telegram.ui.Components.MediaActivity; import org.telegram.ui.Components.Premium.AboutPremiumView; import org.telegram.ui.Components.Premium.GLIcon.GLIconRenderer; import org.telegram.ui.Components.Premium.GLIcon.GLIconTextureView; +import org.telegram.ui.Components.Premium.GLIcon.Icon3D; import org.telegram.ui.Components.Premium.PremiumButtonView; import org.telegram.ui.Components.Premium.PremiumFeatureBottomSheet; import org.telegram.ui.Components.Premium.PremiumGradient; import org.telegram.ui.Components.Premium.PremiumNotAvailableBottomSheet; import org.telegram.ui.Components.Premium.PremiumTierCell; import org.telegram.ui.Components.Premium.StarParticlesView; -import org.telegram.ui.Components.Premium.StoriesPageView; import org.telegram.ui.Components.RecyclerListView; import org.telegram.ui.Components.SimpleThemeDescription; import org.telegram.ui.Components.TextStyleSpan; @@ -92,6 +108,7 @@ import org.telegram.ui.Components.URLSpanNoUnderline; import org.telegram.ui.Components.URLSpanReplacement; import org.telegram.ui.Components.URLSpanUserMention; +import org.telegram.ui.Stories.recorder.HintView2; import java.util.ArrayList; import java.util.Arrays; @@ -106,6 +123,7 @@ public class PremiumPreviewFragment extends BaseFragment implements Notification RecyclerListView listView; ArrayList premiumFeatures = new ArrayList<>(); + ArrayList morePremiumFeatures = new ArrayList<>(); ArrayList subscriptionTiers = new ArrayList<>(); int selectedTierIndex = 0; SubscriptionTier currentSubscriptionTier; @@ -114,6 +132,9 @@ public class PremiumPreviewFragment extends BaseFragment implements Notification int paddingRow; int featuresStartRow; int featuresEndRow; + int moreHeaderRow; + int moreFeaturesStartRow; + int moreFeaturesEndRow; int sectionRow; int helpUsRow; int statusRow; @@ -137,6 +158,9 @@ public class PremiumPreviewFragment extends BaseFragment implements Notification StarParticlesView particlesView; boolean isLandscapeMode; + public final static int FEATURES_PREMIUM = 0; + public final static int FEATURES_BUSINESS = 1; + public final static int PREMIUM_FEATURE_LIMITS = 0; public final static int PREMIUM_FEATURE_UPLOAD_LIMIT = 1; public final static int PREMIUM_FEATURE_DOWNLOAD_SPEED = 2; @@ -165,6 +189,14 @@ public class PremiumPreviewFragment extends BaseFragment implements Notification public final static int PREMIUM_FEATURE_STORIES_QUALITY = 25; public final static int PREMIUM_FEATURE_LAST_SEEN = 26; public final static int PREMIUM_FEATURE_MESSAGE_PRIVACY = 27; + public final static int PREMIUM_FEATURE_BUSINESS = 28; + public final static int PREMIUM_FEATURE_BUSINESS_LOCATION = 29; + public final static int PREMIUM_FEATURE_BUSINESS_OPENING_HOURS = 30; + public final static int PREMIUM_FEATURE_BUSINESS_QUICK_REPLIES = 31; + public final static int PREMIUM_FEATURE_BUSINESS_GREETING_MESSAGES = 32; + public final static int PREMIUM_FEATURE_BUSINESS_AWAY_MESSAGES = 33; + public final static int PREMIUM_FEATURE_BUSINESS_CHATBOTS = 34; + public final static int PREMIUM_FEATURE_FOLDER_TAGS = 35; private int statusBarHeight; private int firstViewHeight; @@ -176,6 +208,7 @@ public class PremiumPreviewFragment extends BaseFragment implements Notification private FrameLayout contentView; private PremiumButtonView premiumButtonView; float totalProgress; + private final int type; private String source; private boolean selectAnnualByDefault; @@ -218,6 +251,7 @@ public static int serverStringToFeatureType(String s) { return PREMIUM_FEATURE_EMOJI_STATUS; case "translations": return PREMIUM_FEATURE_TRANSLATIONS; + case "stories": return PREMIUM_FEATURE_STORIES; case "stories__stealth_mode": @@ -236,6 +270,7 @@ public static int serverStringToFeatureType(String s) { return PREMIUM_FEATURE_STORIES_PRIORITY_ORDER; case "stories__caption": return PREMIUM_FEATURE_STORIES_CAPTION; + case "wallpapers": return PREMIUM_FEATURE_WALLPAPER; case "peer_colors": @@ -246,6 +281,23 @@ public static int serverStringToFeatureType(String s) { return PREMIUM_FEATURE_LAST_SEEN; case "message_privacy": return PREMIUM_FEATURE_MESSAGE_PRIVACY; + case "folder_tags": + return PREMIUM_FEATURE_FOLDER_TAGS; + + case "business": + return PREMIUM_FEATURE_BUSINESS; + case "greeting_message": + return PREMIUM_FEATURE_BUSINESS_GREETING_MESSAGES; + case "away_message": + return PREMIUM_FEATURE_BUSINESS_AWAY_MESSAGES; + case "quick_replies": + return PREMIUM_FEATURE_BUSINESS_QUICK_REPLIES; + case "business_bots": + return PREMIUM_FEATURE_BUSINESS_CHATBOTS; + case "business_hours": + return PREMIUM_FEATURE_BUSINESS_OPENING_HOURS; + case "business_location": + return PREMIUM_FEATURE_BUSINESS_LOCATION; } return -1; } @@ -308,6 +360,23 @@ public static String featureTypeToServerString(int type) { return "last_seen"; case PREMIUM_FEATURE_MESSAGE_PRIVACY: return "message_privacy"; + case PREMIUM_FEATURE_FOLDER_TAGS: + return "folder_tags"; + + case PREMIUM_FEATURE_BUSINESS: + return "business"; + case PREMIUM_FEATURE_BUSINESS_GREETING_MESSAGES: + return "greeting_message"; + case PREMIUM_FEATURE_BUSINESS_AWAY_MESSAGES: + return "away_message"; + case PREMIUM_FEATURE_BUSINESS_QUICK_REPLIES: + return "quick_replies"; + case PREMIUM_FEATURE_BUSINESS_CHATBOTS: + return "business_bots"; + case PREMIUM_FEATURE_BUSINESS_OPENING_HOURS: + return "business_hours"; + case PREMIUM_FEATURE_BUSINESS_LOCATION: + return "business_location"; } return null; } @@ -318,7 +387,12 @@ public PremiumPreviewFragment setForcePremium() { } public PremiumPreviewFragment(String source) { + this(FEATURES_PREMIUM, source); + } + + public PremiumPreviewFragment(int type, String source) { super(); + this.type = type; this.source = source; } @@ -361,7 +435,25 @@ public View createView(Context context) { dummyTierCell = new PremiumTierCell(context); premiumFeatures.clear(); - fillPremiumFeaturesList(premiumFeatures, currentAccount); + morePremiumFeatures.clear(); + if (type == FEATURES_PREMIUM) { + fillPremiumFeaturesList(premiumFeatures, currentAccount, false); + } else { + fillBusinessFeaturesList(premiumFeatures, currentAccount, false); + fillBusinessFeaturesList(morePremiumFeatures, currentAccount, true); + + // preload + QuickRepliesController.getInstance(currentAccount).load(); + if (getUserConfig().isPremium()) { + TLRPC.InputStickerSet inputStickerSet = new TLRPC.TL_inputStickerSetShortName(); + inputStickerSet.short_name = "RestrictedEmoji"; + MediaDataController.getInstance(currentAccount).getStickerSet(inputStickerSet, false); + BusinessChatbotController.getInstance(currentAccount).load(null); + if (getMessagesController().suggestedFilters.isEmpty()) { + getMessagesController().loadSuggestedFilters(); + } + } + } Rect padding = new Rect(); shadowDrawable = context.getResources().getDrawable(R.drawable.sheet_shadow_round).mutate(); @@ -424,8 +516,8 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { } backgroundView.measure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED)); particlesView.getLayoutParams().height = backgroundView.getMeasuredHeight(); - int buttonHeight = (buttonContainer == null || buttonContainer.getVisibility() == View.GONE ? 0 : AndroidUtilities.dp(68)); - layoutManager.setAdditionalHeight(buttonHeight + statusBarHeight - AndroidUtilities.dp(16)); + int buttonHeight = (buttonContainer == null || buttonContainer.getVisibility() == View.GONE ? 0 : dp(68)); + layoutManager.setAdditionalHeight(buttonHeight + statusBarHeight - dp(16)); layoutManager.setMinimumLastViewHeight(buttonHeight); super.onMeasure(widthMeasureSpec, heightMeasureSpec); int size = getMeasuredHeight() + getMeasuredWidth() << 16; @@ -470,19 +562,19 @@ protected void dispatchDraw(Canvas canvas) { } currentYOffset = firstView == null ? 0 : firstView.getBottom(); - int h = actionBar.getBottom() + AndroidUtilities.dp(16); + int h = actionBar.getBottom() + dp(16); totalProgress = (1f - (currentYOffset - h) / (float) (firstViewHeight - h)); totalProgress = Utilities.clamp(totalProgress, 1f, 0f); - int maxTop = actionBar.getBottom() + AndroidUtilities.dp(16); + int maxTop = actionBar.getBottom() + dp(16); if (currentYOffset < maxTop) { currentYOffset = maxTop; } float oldProgress = progressToFull; progressToFull = 0; - if (currentYOffset < maxTop + AndroidUtilities.dp(30)) { - progressToFull = (maxTop + AndroidUtilities.dp(30) - currentYOffset) / (float) AndroidUtilities.dp(30); + if (currentYOffset < maxTop + dp(30)) { + progressToFull = (maxTop + dp(30) - currentYOffset) / (float) dp(30); } if (isLandscapeMode) { @@ -492,14 +584,14 @@ protected void dispatchDraw(Canvas canvas) { if (oldProgress != progressToFull) { listView.invalidate(); } - float fromTranslation = currentYOffset - (actionBar.getMeasuredHeight() + backgroundView.getMeasuredHeight() - statusBarHeight) + AndroidUtilities.dp(backgroundView.tierListView.getVisibility() == VISIBLE ? 24 : 16); + float fromTranslation = currentYOffset - (actionBar.getMeasuredHeight() + backgroundView.getMeasuredHeight() - statusBarHeight) + dp(backgroundView.tierListView.getVisibility() == VISIBLE ? 24 : 16); float toTranslation = ((actionBar.getMeasuredHeight() - statusBarHeight - backgroundView.titleView.getMeasuredHeight()) / 2f) + statusBarHeight - backgroundView.getTop() - backgroundView.titleView.getTop(); float translationsY = Math.max(toTranslation, fromTranslation); - float iconTranslationsY = -translationsY / 4f + AndroidUtilities.dp(16); + float iconTranslationsY = -translationsY / 4f + dp(16); backgroundView.setTranslationY(translationsY); - backgroundView.imageView.setTranslationY(iconTranslationsY + AndroidUtilities.dp(16)); + backgroundView.imageView.setTranslationY(iconTranslationsY + dp(type == FEATURES_BUSINESS ? 9 : 16)); float s = 0.6f + (1f - totalProgress) * 0.4f; float alpha = 1f - (totalProgress > 0.5f ? (totalProgress - 0.5f) / 0.5f : 0f); backgroundView.imageView.setScaleX(s); @@ -510,7 +602,7 @@ protected void dispatchDraw(Canvas canvas) { particlesView.setAlpha(1f - totalProgress); particlesView.setTranslationY(-(particlesView.getMeasuredHeight() - backgroundView.imageView.getMeasuredWidth()) / 2f + backgroundView.getY() + backgroundView.imageFrameLayout.getY()); - float toX = AndroidUtilities.dp(72) - backgroundView.titleView.getLeft(); + float toX = dp(72) - backgroundView.titleView.getLeft(); float f = totalProgress > 0.3f ? (totalProgress - 0.3f) / 0.7f : 0f; backgroundView.titleView.setTranslationX(toX * (1f - CubicBezierInterpolator.EASE_OUT_QUINT.getInterpolation(1 - f))); @@ -521,7 +613,7 @@ protected void dispatchDraw(Canvas canvas) { invalidate(); } gradientTools.gradientMatrix(0, 0, getMeasuredWidth(), getMeasuredHeight(), -getMeasuredWidth() * 0.1f * progress, 0); - canvas.drawRect(0, 0, getMeasuredWidth(), currentYOffset + AndroidUtilities.dp(20), gradientTools.paint); + canvas.drawRect(0, 0, getMeasuredWidth(), currentYOffset + dp(20), gradientTools.paint); super.dispatchDraw(canvas); } @@ -543,12 +635,12 @@ protected boolean drawChild(Canvas canvas, View child, long drawingTime) { listView = new RecyclerListView(context) { @Override public void onDraw(Canvas canvas) { - shadowDrawable.setBounds((int) (-padding.left - AndroidUtilities.dp(16) * progressToFull), currentYOffset - padding.top - AndroidUtilities.dp(16), (int) (getMeasuredWidth() + padding.right + AndroidUtilities.dp(16) * progressToFull), getMeasuredHeight()); + shadowDrawable.setBounds((int) (-padding.left - dp(16) * progressToFull), currentYOffset - padding.top - dp(16), (int) (getMeasuredWidth() + padding.right + dp(16) * progressToFull), getMeasuredHeight()); shadowDrawable.draw(canvas); super.onDraw(canvas); } }; - listView.setLayoutManager(layoutManager = new FillLastLinearLayoutManager(context, AndroidUtilities.dp(68) + statusBarHeight - AndroidUtilities.dp(16), listView)); + listView.setLayoutManager(layoutManager = new FillLastLinearLayoutManager(context, dp(68) + statusBarHeight - dp(16), listView)); layoutManager.setFixedLastItemHeight(); listView.setAdapter(new Adapter()); @@ -558,7 +650,7 @@ public void onDraw(Canvas canvas) { public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) { super.onScrollStateChanged(recyclerView, newState); if (newState == RecyclerView.SCROLL_STATE_IDLE) { - int maxTop = actionBar.getBottom() + AndroidUtilities.dp(16); + int maxTop = actionBar.getBottom() + dp(16); if (totalProgress > 0.5f) { listView.smoothScrollBy(0, currentYOffset - maxTop); } else { @@ -589,6 +681,17 @@ public boolean onInterceptTouchEvent(MotionEvent ev) { } }; particlesView = new StarParticlesView(context); + particlesView.setClipWithGradient(); + if (type == FEATURES_BUSINESS) { +// particlesView.doNotFling = true; + particlesView.drawable.isCircle = true; + particlesView.drawable.centerOffsetY = dp(28); + particlesView.drawable.minLifeTime = 2000; + particlesView.drawable.randLifeTime = 3000; + particlesView.drawable.size1 = 16; + particlesView.drawable.useRotate = false; + particlesView.drawable.type = PREMIUM_FEATURE_BUSINESS; + } backgroundView.imageView.setStarParticlesView(particlesView); contentView.addView(particlesView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); contentView.addView(backgroundView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); @@ -596,19 +699,50 @@ public boolean onInterceptTouchEvent(MotionEvent ev) { listView.setOnItemClickListener((view, position) -> { if (view instanceof PremiumFeatureCell) { PremiumFeatureCell cell = (PremiumFeatureCell) view; - PremiumPreviewFragment.sentShowFeaturePreview(currentAccount, cell.data.type); -// if (cell.data.type == PREMIUM_FEATURE_LIMITS) { -// DoubledLimitsBottomSheet bottomSheet = new DoubledLimitsBottomSheet(PremiumPreviewFragment.this, currentAccount, subscriptionTiers.get(selectedTierIndex)); -// bottomSheet.setParentFragment(PremiumPreviewFragment.this); -// showDialog(bottomSheet); -// } else { -// if (subscriptionTiers.isEmpty()) { -// return; -// } - // } + if (type == FEATURES_BUSINESS && getUserConfig().isPremium()) { + if (cell.data.type == PREMIUM_FEATURE_BUSINESS_LOCATION) { + presentFragment(new LocationActivity()); + } else if (cell.data.type == PREMIUM_FEATURE_BUSINESS_GREETING_MESSAGES) { + presentFragment(new GreetMessagesActivity()); + } else if (cell.data.type == PREMIUM_FEATURE_BUSINESS_AWAY_MESSAGES) { + presentFragment(new AwayMessagesActivity()); + } else if (cell.data.type == PREMIUM_FEATURE_BUSINESS_OPENING_HOURS) { + presentFragment(new OpeningHoursActivity()); + } else if (cell.data.type == PREMIUM_FEATURE_BUSINESS_CHATBOTS) { + presentFragment(new ChatbotsActivity()); + } else if (cell.data.type == PREMIUM_FEATURE_BUSINESS_QUICK_REPLIES) { + presentFragment(new QuickRepliesActivity()); + } else if (cell.data.type == PREMIUM_FEATURE_STORIES) { + Bundle args = new Bundle(); + args.putLong("dialog_id", UserConfig.getInstance(currentAccount).getClientUserId()); + args.putInt("type", MediaActivity.TYPE_STORIES); + presentFragment(new MediaActivity(args, null)); + } else if (cell.data.type == PREMIUM_FEATURE_EMOJI_STATUS) { + showSelectStatusDialog(cell, UserObject.getEmojiStatusDocumentId(getUserConfig().getCurrentUser()), (documentId, until) -> { + TLRPC.EmojiStatus emojiStatus; + if (documentId == null) { + emojiStatus = new TLRPC.TL_emojiStatusEmpty(); + } else if (until != null) { + emojiStatus = new TLRPC.TL_emojiStatusUntil(); + ((TLRPC.TL_emojiStatusUntil) emojiStatus).document_id = documentId; + ((TLRPC.TL_emojiStatusUntil) emojiStatus).until = until; + } else { + emojiStatus = new TLRPC.TL_emojiStatus(); + ((TLRPC.TL_emojiStatus) emojiStatus).document_id = documentId; + } + getMessagesController().updateEmojiStatus(emojiStatus); + cell.setEmoji(documentId == null ? 0 : documentId, true); + }); + } else if (cell.data.type == PREMIUM_FEATURE_FOLDER_TAGS) { + presentFragment(new FiltersSetupActivity().highlightTags()); + } + return; + } + + PremiumPreviewFragment.sentShowFeaturePreview(currentAccount, cell.data.type); SubscriptionTier tier = selectedTierIndex < 0 || selectedTierIndex >= subscriptionTiers.size() ? null : subscriptionTiers.get(selectedTierIndex); - showDialog(new PremiumFeatureBottomSheet(PremiumPreviewFragment.this, cell.data.type, false, tier)); + showDialog(new PremiumFeatureBottomSheet(PremiumPreviewFragment.this, getContext(), currentAccount, type == FEATURES_BUSINESS, cell.data.type, false, tier)); } }); contentView.addView(listView); @@ -663,11 +797,12 @@ public static void buyPremium(BaseFragment fragment) { buyPremium(fragment, "settings"); } - public static void fillPremiumFeaturesList(ArrayList premiumFeatures, int currentAccount) { + public static void fillPremiumFeaturesList(ArrayList premiumFeatures, int currentAccount, boolean all) { MessagesController messagesController = MessagesController.getInstance(currentAccount); + premiumFeatures.add(new PremiumFeatureData(PREMIUM_FEATURE_LIMITS, R.drawable.msg_premium_limits, LocaleController.getString("PremiumPreviewLimits", R.string.PremiumPreviewLimits), LocaleController.formatString("PremiumPreviewLimitsDescription", R.string.PremiumPreviewLimitsDescription, messagesController.channelsLimitPremium, messagesController.dialogFiltersLimitPremium, messagesController.dialogFiltersPinnedLimitPremium, messagesController.publicLinksLimitPremium, 4))); - premiumFeatures.add(new PremiumFeatureData(PREMIUM_FEATURE_STORIES, R.drawable.msg_filled_stories, LocaleController.getString("PremiumPreviewStories", R.string.PremiumPreviewStories), LocaleController.formatString("PremiumPreviewStoriesDescription", R.string.PremiumPreviewStoriesDescription))); + premiumFeatures.add(new PremiumFeatureData(PREMIUM_FEATURE_STORIES, R.drawable.msg_filled_stories, LocaleController.getString(R.string.PremiumPreviewStories), LocaleController.formatString(R.string.PremiumPreviewStoriesDescription))); premiumFeatures.add(new PremiumFeatureData(PREMIUM_FEATURE_UPLOAD_LIMIT, R.drawable.msg_premium_uploads, LocaleController.getString("PremiumPreviewUploads", R.string.PremiumPreviewUploads), LocaleController.getString("PremiumPreviewUploadsDescription", R.string.PremiumPreviewUploadsDescription))); premiumFeatures.add(new PremiumFeatureData(PREMIUM_FEATURE_DOWNLOAD_SPEED, R.drawable.msg_premium_speed, LocaleController.getString("PremiumPreviewDownloadSpeed", R.string.PremiumPreviewDownloadSpeed), LocaleController.getString("PremiumPreviewDownloadSpeedDescription", R.string.PremiumPreviewDownloadSpeedDescription))); premiumFeatures.add(new PremiumFeatureData(PREMIUM_FEATURE_VOICE_TO_TEXT, R.drawable.msg_premium_voice, LocaleController.getString("PremiumPreviewVoiceToText", R.string.PremiumPreviewVoiceToText), LocaleController.getString("PremiumPreviewVoiceToTextDescription", R.string.PremiumPreviewVoiceToTextDescription))); @@ -686,6 +821,7 @@ public static void fillPremiumFeaturesList(ArrayList premium premiumFeatures.add(new PremiumFeatureData(PREMIUM_FEATURE_NAME_COLOR, R.drawable.premium_colors, LocaleController.getString(R.string.PremiumPreviewProfileColor), LocaleController.getString(R.string.PremiumPreviewProfileColorDescription))); premiumFeatures.add(new PremiumFeatureData(PREMIUM_FEATURE_LAST_SEEN, R.drawable.menu_premium_seen, applyNewSpan(LocaleController.getString(R.string.PremiumPreviewLastSeen)), LocaleController.getString(R.string.PremiumPreviewLastSeenDescription))); premiumFeatures.add(new PremiumFeatureData(PREMIUM_FEATURE_MESSAGE_PRIVACY, R.drawable.menu_premium_privacy, applyNewSpan(LocaleController.getString(R.string.PremiumPreviewMessagePrivacy)), LocaleController.getString(R.string.PremiumPreviewMessagePrivacyDescription))); + premiumFeatures.add(new PremiumFeatureData(PREMIUM_FEATURE_BUSINESS, R.drawable.filled_premium_business, applyNewSpan(LocaleController.getString(R.string.TelegramBusiness)), LocaleController.getString(R.string.PremiumPreviewBusinessDescription))); if (messagesController.premiumFeaturesTypesToPosition.size() > 0) { for (int i = 0; i < premiumFeatures.size(); i++) { @@ -703,6 +839,38 @@ public static void fillPremiumFeaturesList(ArrayList premium }); } + public static void fillBusinessFeaturesList(ArrayList premiumFeatures, int currentAccount, boolean additional) { + MessagesController messagesController = MessagesController.getInstance(currentAccount); + + if (!additional) { + premiumFeatures.add(new PremiumFeatureData(PREMIUM_FEATURE_BUSINESS_LOCATION, R.drawable.filled_location, LocaleController.getString(R.string.PremiumBusinessLocation), LocaleController.getString(R.string.PremiumBusinessLocationDescription))); + premiumFeatures.add(new PremiumFeatureData(PREMIUM_FEATURE_BUSINESS_OPENING_HOURS, R.drawable.filled_premium_hours, LocaleController.getString(R.string.PremiumBusinessOpeningHours), LocaleController.getString(R.string.PremiumBusinessOpeningHoursDescription))); + premiumFeatures.add(new PremiumFeatureData(PREMIUM_FEATURE_BUSINESS_QUICK_REPLIES, R.drawable.filled_open_message, LocaleController.getString(R.string.PremiumBusinessQuickReplies), LocaleController.getString(R.string.PremiumBusinessQuickRepliesDescription))); + premiumFeatures.add(new PremiumFeatureData(PREMIUM_FEATURE_BUSINESS_GREETING_MESSAGES, R.drawable.premium_status, LocaleController.getString(R.string.PremiumBusinessGreetingMessages), LocaleController.getString(R.string.PremiumBusinessGreetingMessagesDescription))); + premiumFeatures.add(new PremiumFeatureData(PREMIUM_FEATURE_BUSINESS_AWAY_MESSAGES, R.drawable.filled_premium_away, LocaleController.getString(R.string.PremiumBusinessAwayMessages), LocaleController.getString(R.string.PremiumBusinessAwayMessagesDescription))); + premiumFeatures.add(new PremiumFeatureData(PREMIUM_FEATURE_BUSINESS_CHATBOTS, R.drawable.filled_premium_bots, LocaleController.getString(R.string.PremiumBusinessChatbots), LocaleController.getString(R.string.PremiumBusinessChatbotsDescription))); + } else { + premiumFeatures.add(new PremiumFeatureData(PREMIUM_FEATURE_EMOJI_STATUS, R.drawable.filled_premium_status2, LocaleController.getString(R.string.PremiumPreviewBusinessEmojiStatus), LocaleController.getString(R.string.PremiumPreviewBusinessEmojiStatusDescription))); + premiumFeatures.add(new PremiumFeatureData(PREMIUM_FEATURE_FOLDER_TAGS, R.drawable.premium_tags, LocaleController.getString(R.string.PremiumPreviewFolderTags), LocaleController.getString(R.string.PremiumPreviewFolderTagsDescription))); + premiumFeatures.add(new PremiumFeatureData(PREMIUM_FEATURE_STORIES, R.drawable.filled_premium_camera, LocaleController.getString(R.string.PremiumPreviewBusinessStories), LocaleController.getString(R.string.PremiumPreviewBusinessStoriesDescription))); + } + + if (messagesController.businessFeaturesTypesToPosition.size() > 0) { + for (int i = 0; i < premiumFeatures.size(); i++) { + if (messagesController.businessFeaturesTypesToPosition.get(premiumFeatures.get(i).type, -1) == -1 && !BuildVars.DEBUG_PRIVATE_VERSION) { + premiumFeatures.remove(i); + i--; + } + } + } + + Collections.sort(premiumFeatures, (o1, o2) -> { + int type1 = messagesController.businessFeaturesTypesToPosition.get(o1.type, Integer.MAX_VALUE); + int type2 = messagesController.businessFeaturesTypesToPosition.get(o2.type, Integer.MAX_VALUE); + return type1 - type2; + }); + } + public static CharSequence applyNewSpan(String str) { SpannableStringBuilder spannableStringBuilder = new SpannableStringBuilder(str); spannableStringBuilder.append(" d"); @@ -977,6 +1145,12 @@ private void measureGradient(int w, int h) { premiumFeatures.get(i).yOffset = yOffset; yOffset += dummyCell.getMeasuredHeight(); } + for (int i = 0; i < morePremiumFeatures.size(); i++) { + dummyCell.setData(morePremiumFeatures.get(i), false); + dummyCell.measure(View.MeasureSpec.makeMeasureSpec(w, View.MeasureSpec.EXACTLY), View.MeasureSpec.makeMeasureSpec(h, View.MeasureSpec.AT_MOST)); + morePremiumFeatures.get(i).yOffset = yOffset; + yOffset += dummyCell.getMeasuredHeight(); + } totalGradientHeight = yOffset; } @@ -985,18 +1159,28 @@ private void updateRows() { rowCount = 0; sectionRow = -1; privacyRow = -1; + moreHeaderRow = -1; + moreFeaturesStartRow = -1; + moreFeaturesEndRow = -1; paddingRow = rowCount++; featuresStartRow = rowCount; rowCount += premiumFeatures.size(); featuresEndRow = rowCount; + if (type == FEATURES_BUSINESS && getUserConfig().isPremium()) { + sectionRow = rowCount++; + moreHeaderRow = rowCount++; + moreFeaturesStartRow = rowCount; + rowCount += morePremiumFeatures.size(); + moreFeaturesEndRow = rowCount; + } statusRow = rowCount++; lastPaddingRow = rowCount++; AndroidUtilities.updateViewVisibilityAnimated(buttonContainer, !getUserConfig().isPremium() || currentSubscriptionTier != null && currentSubscriptionTier.getMonths() < subscriptionTiers.get(selectedTierIndex).getMonths() && !forcePremium, 1f, false); - int buttonHeight = buttonContainer.getVisibility() == View.VISIBLE ? AndroidUtilities.dp(64) : 0; - layoutManager.setAdditionalHeight(buttonHeight + statusBarHeight - AndroidUtilities.dp(16)); + int buttonHeight = buttonContainer.getVisibility() == View.VISIBLE ? dp(64) : 0; + layoutManager.setAdditionalHeight(buttonHeight + statusBarHeight - dp(16)); layoutManager.setMinimumLastViewHeight(buttonHeight); } @@ -1020,6 +1204,10 @@ public boolean onFragmentCreate() { } } + if (type == FEATURES_BUSINESS) { + TimezonesController.getInstance(currentAccount).load(); + } + return super.onFragmentCreate(); } @@ -1053,8 +1241,9 @@ private class Adapter extends RecyclerListView.SelectionAdapter { TYPE_SHADOW_SECTION = 2, TYPE_BUTTON = 3, TYPE_HELP_US = 4, - TYPE_STATUS_TEXT = 5, - TYPE_BOTTOM_PADDING = 6; + TYPE_SHADOW = 5, + TYPE_BOTTOM_PADDING = 6, + TYPE_HEADER = 7; @NonNull @Override @@ -1068,11 +1257,11 @@ public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { if (isLandscapeMode) { - firstViewHeight = statusBarHeight + actionBar.getMeasuredHeight() - AndroidUtilities.dp(16); + firstViewHeight = statusBarHeight + actionBar.getMeasuredHeight() - dp(16); } else { - int h = AndroidUtilities.dp(300) + statusBarHeight; - if (backgroundView.getMeasuredHeight() + AndroidUtilities.dp(24) > h) { - h = backgroundView.getMeasuredHeight() + AndroidUtilities.dp(24); + int h = dp(80) + statusBarHeight; + if (backgroundView.getMeasuredHeight() + dp(24) > h) { + h = backgroundView.getMeasuredHeight() + dp(24); } firstViewHeight = h; } @@ -1080,7 +1269,7 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { } }; break; - case TYPE_STATUS_TEXT: + case TYPE_SHADOW: view = new TextInfoPrivacyCell(context); break; case TYPE_FEATURE: @@ -1092,7 +1281,7 @@ protected void dispatchDraw(Canvas canvas) { matrix.postScale(1f, totalGradientHeight / 100f, 0, 0); matrix.postTranslate(0, -data.yOffset); shader.setLocalMatrix(matrix); - canvas.drawRoundRect(AndroidUtilities.rectTmp, AndroidUtilities.dp(8), AndroidUtilities.dp(8), gradientPaint); + canvas.drawRoundRect(AndroidUtilities.rectTmp, dp(8), dp(8), gradientPaint); super.dispatchDraw(canvas); } }; @@ -1113,6 +1302,9 @@ protected void dispatchDraw(Canvas canvas) { view = new View(context); view.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundGray)); break; + case TYPE_HEADER: + view = new HeaderCell(context); + break; } view.setLayoutParams(new RecyclerView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)); return new RecyclerListView.Holder(view); @@ -1122,6 +1314,19 @@ protected void dispatchDraw(Canvas canvas) { public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) { if (position >= featuresStartRow && position < featuresEndRow) { ((PremiumFeatureCell) holder.itemView).setData(premiumFeatures.get(position - featuresStartRow), position != featuresEndRow - 1); + } else if (position >= moreFeaturesStartRow && position < moreFeaturesEndRow) { + ((PremiumFeatureCell) holder.itemView).setData(morePremiumFeatures.get(position - moreFeaturesStartRow), position != moreFeaturesEndRow - 1); + } else if (position == sectionRow) { + TextInfoPrivacyCell privacyCell = (TextInfoPrivacyCell) holder.itemView; + + Drawable shadowDrawable = Theme.getThemedDrawable(privacyCell.getContext(), R.drawable.greydivider, Theme.getColor(Theme.key_windowBackgroundGrayShadow)); + Drawable background = new ColorDrawable(Theme.getColor(Theme.key_windowBackgroundGray)); + CombinedDrawable combinedDrawable = new CombinedDrawable(background, shadowDrawable, 0, 0); + combinedDrawable.setFullsize(true); + privacyCell.setBackground(combinedDrawable); + + privacyCell.setText(""); + privacyCell.setFixedSize(12); } else if (position == statusRow || position == privacyRow) { TextInfoPrivacyCell privacyCell = (TextInfoPrivacyCell) holder.itemView; @@ -1130,8 +1335,11 @@ public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int positi CombinedDrawable combinedDrawable = new CombinedDrawable(background, shadowDrawable, 0, 0); combinedDrawable.setFullsize(true); privacyCell.setBackground(combinedDrawable); + privacyCell.setFixedSize(0); - if (position == statusRow) { + if (position == statusRow && type == FEATURES_BUSINESS) { + privacyCell.setText(LocaleController.getString(R.string.PremiumPreviewMoreBusinessFeaturesInfo)); + } else if (position == statusRow) { TLRPC.TL_help_premiumPromo premiumPromo = getMediaDataController().getPremiumPromo(); if (premiumPromo == null) { return; @@ -1185,6 +1393,8 @@ public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int positi } privacyCell.setText(spannableString); } + } else if (position == moreHeaderRow) { + ((HeaderCell) holder.itemView).setText(LocaleController.getString(R.string.PremiumPreviewMoreBusinessFeatures)); } } @@ -1197,16 +1407,16 @@ public int getItemCount() { public int getItemViewType(int position) { if (position == paddingRow) { return TYPE_PADDING; - } else if (position >= featuresStartRow && position < featuresEndRow) { + } else if (position >= featuresStartRow && position < featuresEndRow || position >= moreFeaturesStartRow && position < moreFeaturesEndRow) { return TYPE_FEATURE; - } else if (position == sectionRow) { - return TYPE_SHADOW_SECTION; } else if (position == helpUsRow) { return TYPE_HELP_US; - } else if (position == statusRow || position == privacyRow) { - return TYPE_STATUS_TEXT; + } else if (position == sectionRow || position == statusRow || position == privacyRow) { + return TYPE_SHADOW; } else if (position == lastPaddingRow) { return TYPE_BOTTOM_PADDING; + } else if (position == moreHeaderRow) { + return TYPE_HEADER; } return TYPE_PADDING; } @@ -1247,8 +1457,9 @@ public BackgroundView(Context context) { super(context); setOrientation(VERTICAL); imageFrameLayout = new FrameLayout(context); - addView(imageFrameLayout, LayoutHelper.createLinear(190, 190, Gravity.CENTER_HORIZONTAL)); - imageView = new GLIconTextureView(context, GLIconRenderer.FRAGMENT_STYLE) { + final int sz = type == FEATURES_BUSINESS ? 175 : 190; + addView(imageFrameLayout, LayoutHelper.createLinear(sz, sz, Gravity.CENTER_HORIZONTAL)); + imageView = new GLIconTextureView(context, type == FEATURES_BUSINESS ? GLIconRenderer.BUSINESS_STYLE : GLIconRenderer.FRAGMENT_STYLE, type == FEATURES_BUSINESS ? Icon3D.TYPE_COIN : Icon3D.TYPE_STAR) { @Override public void onLongPress() { super.onLongPress(); @@ -1266,7 +1477,7 @@ public void onLongPress() { contentView.addView(settingsView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.BOTTOM)); ((MarginLayoutParams) settingsView.getLayoutParams()).topMargin = currentYOffset; - settingsView.setTranslationY(AndroidUtilities.dp(1000)); + settingsView.setTranslationY(dp(1000)); settingsView.animate().translationY(1).setDuration(300); } }; @@ -1278,13 +1489,13 @@ public void onLongPress() { titleView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 22); titleView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); titleView.setGravity(Gravity.CENTER_HORIZONTAL); - addView(titleView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, 0, Gravity.CENTER_HORIZONTAL, 16, 20, 16, 0)); + addView(titleView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, 0, Gravity.CENTER_HORIZONTAL, 16, type == FEATURES_BUSINESS ? 8 : 20, 16, 0)); subtitleView = new TextView(context); subtitleView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); - subtitleView.setLineSpacing(AndroidUtilities.dp(2), 1f); + subtitleView.setLineSpacing(dp(2), 1f); subtitleView.setGravity(Gravity.CENTER_HORIZONTAL); - addView(subtitleView, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, 0, 0, 16, 7, 16, 0)); + addView(subtitleView, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, 0, Gravity.CENTER_HORIZONTAL, 16, 7, 16, 0)); tierListView = new RecyclerListView(context) { Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG); @@ -1298,7 +1509,7 @@ public void onLongPress() { public void draw(Canvas c) { path.rewind(); AndroidUtilities.rectTmp.set(0, 0, getWidth(), getHeight()); - path.addRoundRect(AndroidUtilities.rectTmp, AndroidUtilities.dp(12), AndroidUtilities.dp(12), Path.Direction.CW); + path.addRoundRect(AndroidUtilities.rectTmp, dp(12), dp(12), Path.Direction.CW); c.drawPath(path, paint); c.save(); c.clipPath(path); @@ -1324,7 +1535,7 @@ protected void dispatchDraw(Canvas canvas) { if (discountView.getVisibility() == VISIBLE) { AndroidUtilities.rectTmp.set(discountView.getLeft(), discountView.getTop(), discountView.getRight(), discountView.getBottom()); tiersGradientTools.gradientMatrix(0, 0, getMeasuredWidth(), totalTiersGradientHeight, 0, -tier.yOffset); - canvas.drawRoundRect(AndroidUtilities.rectTmp, AndroidUtilities.dp(6), AndroidUtilities.dp(6), tiersGradientTools.paint); + canvas.drawRoundRect(AndroidUtilities.rectTmp, dp(6), dp(6), tiersGradientTools.paint); } super.dispatchDraw(canvas); @@ -1418,10 +1629,10 @@ public int getItemCount() { AndroidUtilities.rectTmp.set(selectorRect.left, selectorRect.top, selectorRect.right, selectorRect.bottom); Arrays.fill(radii, 0); if (position == 0) { - Arrays.fill(radii, 0, 4, AndroidUtilities.dp(12)); + Arrays.fill(radii, 0, 4, dp(12)); } if (position == tierListView.getAdapter().getItemCount() - 1) { - Arrays.fill(radii, 4, 8, AndroidUtilities.dp(12)); + Arrays.fill(radii, 4, 8, dp(12)); } path.addRoundRect(AndroidUtilities.rectTmp, radii, Path.Direction.CW); canvas.clipPath(path); @@ -1523,8 +1734,14 @@ public void updatePremiumTiers() { private boolean setTierListViewVisibility; private boolean tierListViewVisible; public void updateText() { - titleView.setText(LocaleController.getString(forcePremium ? R.string.TelegramPremiumSubscribedTitle : R.string.TelegramPremium)); - subtitleView.setText(AndroidUtilities.replaceTags(LocaleController.getString(getUserConfig().isPremium() || forcePremium ? R.string.TelegramPremiumSubscribedSubtitle : R.string.TelegramPremiumSubtitle))); + if (type == FEATURES_PREMIUM) { + titleView.setText(LocaleController.getString(forcePremium ? R.string.TelegramPremiumSubscribedTitle : R.string.TelegramPremium)); + subtitleView.setText(AndroidUtilities.replaceTags(LocaleController.getString(getUserConfig().isPremium() || forcePremium ? R.string.TelegramPremiumSubscribedSubtitle : R.string.TelegramPremiumSubtitle))); + } else if (type == FEATURES_BUSINESS) { + titleView.setText(LocaleController.getString(forcePremium ? R.string.TelegramPremiumSubscribedTitle : R.string.TelegramBusiness)); + subtitleView.setText(AndroidUtilities.replaceTags(LocaleController.getString(getUserConfig().isPremium() || forcePremium ? R.string.TelegramBusinessSubscribedSubtitleTemp : R.string.TelegramBusinessSubtitleTemp))); + } + subtitleView.getLayoutParams().width = Math.min(AndroidUtilities.displaySize.x - dp(42), HintView2.cutInFancyHalf(subtitleView.getText(), subtitleView.getPaint())); boolean tierNotVisible = forcePremium || BuildVars.IS_BILLING_UNAVAILABLE || IS_PREMIUM_TIERS_UNAVAILABLE || subscriptionTiers.size() <= 1; if (!setTierListViewVisibility || !tierNotVisible) { tierListView.setVisibility(tierNotVisible ? GONE : VISIBLE); @@ -1544,9 +1761,9 @@ public void updateText() { if (ch != tierListView) { float offset = 0; if (ch == imageFrameLayout) { - offset -= AndroidUtilities.dp(15) * f; + offset -= dp(15) * f; } else { - offset += AndroidUtilities.dp(8) * f; + offset += dp(8) * f; } ch.setTranslationY(f * v.getMeasuredHeight() + offset); } @@ -1672,7 +1889,7 @@ public boolean onBackPressed() { } private void closeSetting() { - settingsView.animate().translationY(AndroidUtilities.dp(1000)).setListener(new AnimatorListenerAdapter() { + settingsView.animate().translationY(dp(1000)).setListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { contentView.removeView(settingsView); @@ -1939,4 +2156,66 @@ private void checkOfferDetails() { } } } + + private SelectAnimatedEmojiDialog.SelectAnimatedEmojiDialogWindow selectAnimatedEmojiDialog; + public void showSelectStatusDialog(PremiumFeatureCell cell, Long documentId, Utilities.Callback2 onSet) { + if (selectAnimatedEmojiDialog != null || cell == null) { + return; + } + final SelectAnimatedEmojiDialog.SelectAnimatedEmojiDialogWindow[] popup = new SelectAnimatedEmojiDialog.SelectAnimatedEmojiDialogWindow[1]; + int xoff = 0, yoff = 0; + + final boolean down = cell.getTop() + cell.getHeight() > listView.getMeasuredHeight() / 2f; + AnimatedEmojiDrawable.SwapAnimatedEmojiDrawable scrimDrawable = null; + View scrimDrawableParent = null; + final int popupHeight = (int) Math.min(AndroidUtilities.dp(410 - 16 - 64), AndroidUtilities.displaySize.y * .75f); + final int popupWidth = (int) Math.min(dp(340 - 16), AndroidUtilities.displaySize.x * .95f); + if (cell != null && cell.imageDrawable != null) { + cell.imageDrawable.removeOldDrawable(); + scrimDrawable = cell.imageDrawable; + scrimDrawableParent = cell; + if (cell.imageDrawable != null) { + cell.imageDrawable.play(); + cell.updateImageBounds(); + AndroidUtilities.rectTmp2.set(cell.imageDrawable.getBounds()); + if (down) { + yoff = -AndroidUtilities.rectTmp2.centerY() + dp(12) - popupHeight; + } else { + yoff = -(cell.getHeight() - AndroidUtilities.rectTmp2.centerY()) - AndroidUtilities.dp(16); + } + xoff = AndroidUtilities.rectTmp2.centerX() - (AndroidUtilities.displaySize.x - popupWidth); + } + } + int type = down ? SelectAnimatedEmojiDialog.TYPE_EMOJI_STATUS_TOP : SelectAnimatedEmojiDialog.TYPE_EMOJI_STATUS; + SelectAnimatedEmojiDialog popupLayout = new SelectAnimatedEmojiDialog(PremiumPreviewFragment.this, getContext(), true, xoff, type, true, getResourceProvider(), down ? 24 : 16) { + @Override + protected void onEmojiSelected(View emojiView, Long documentId, TLRPC.Document document, Integer until) { + if (onSet != null) { + onSet.run(documentId, until); + } + if (popup[0] != null) { + selectAnimatedEmojiDialog = null; + popup[0].dismiss(); + } + } + + @Override + protected float getScrimDrawableTranslationY() { + return 0; + } + }; + popupLayout.useAccentForPlus = true; + popupLayout.setSelected(documentId); + popupLayout.setSaveState(3); + popupLayout.setScrimDrawable(scrimDrawable, scrimDrawableParent); + popup[0] = selectAnimatedEmojiDialog = new SelectAnimatedEmojiDialog.SelectAnimatedEmojiDialogWindow(popupLayout, LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT) { + @Override + public void dismiss() { + super.dismiss(); + selectAnimatedEmojiDialog = null; + } + }; + popup[0].showAsDropDown(cell, 0, yoff, Gravity.TOP | Gravity.RIGHT); + popup[0].dimBehind(); + } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ProfileActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ProfileActivity.java index 700980aa82e..057798c4234 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ProfileActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ProfileActivity.java @@ -150,6 +150,7 @@ import org.telegram.tgnet.SerializedData; import org.telegram.tgnet.TLObject; import org.telegram.tgnet.TLRPC; +import org.telegram.tgnet.tl.TL_stories; import org.telegram.ui.ActionBar.ActionBar; import org.telegram.ui.ActionBar.ActionBarMenu; import org.telegram.ui.ActionBar.ActionBarMenuItem; @@ -163,6 +164,10 @@ import org.telegram.ui.ActionBar.SimpleTextView; import org.telegram.ui.ActionBar.Theme; import org.telegram.ui.ActionBar.ThemeDescription; +import org.telegram.ui.Business.OpeningHoursActivity; +import org.telegram.ui.Business.ProfileHoursCell; +import org.telegram.ui.Business.ProfileLocationCell; +import org.telegram.ui.Business.TimezonesController; import org.telegram.ui.Cells.AboutLinkCell; import org.telegram.ui.Cells.CheckBoxCell; import org.telegram.ui.Cells.DividerCell; @@ -254,8 +259,11 @@ import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; +import java.time.DayOfWeek; +import java.time.format.TextStyle; import java.util.ArrayList; import java.util.Arrays; +import java.util.Calendar; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; @@ -534,7 +542,10 @@ public void setAlpha(int a) { private int usernameRow; private int notificationsDividerRow; private int notificationsRow; + private int bizHoursRow; + private int bizLocationRow; private int notificationsSimpleRow; + private int infoStartRow, infoEndRow; private int infoSectionRow; private int sendMessageRow; private int reportRow; @@ -544,6 +555,7 @@ public void setAlpha(int a) { private int addToGroupButtonRow; private int addToGroupInfoRow; private int premiumRow; + private int businessRow; private int premiumGiftingRow; private int premiumSectionsRow; @@ -568,6 +580,9 @@ public void setAlpha(int a) { private int joinRow; private int lastSectionRow; + private boolean hoursExpanded; + private boolean hoursShownMine; + private int transitionIndex; private final ArrayList visibleChatParticipants = new ArrayList<>(); private final ArrayList visibleSortedUsers = new ArrayList<>(); @@ -2289,7 +2304,7 @@ public void didChangeOwner(TLRPC.User user) { } else { return; } - getMediaDataController().installShortcut(did); + getMediaDataController().installShortcut(did, MediaDataController.SHORTCUT_TYPE_USER_OR_CHAT); } catch (Exception e) { FileLog.e(e); } @@ -3221,6 +3236,14 @@ public boolean drawChild(Canvas canvas, View child, long drawingTime) { } return super.drawChild(canvas, child, drawingTime); } + + @Override + protected void dispatchDraw(Canvas canvas) { + if (bizHoursRow >= 0 && infoStartRow >= 0 && infoEndRow >= 0) { + drawSectionBackground(canvas, infoStartRow, infoEndRow, getThemedColor(Theme.key_windowBackgroundWhite)); + } + super.dispatchDraw(canvas); + } }; listView.setVerticalScrollBarEnabled(false); DefaultItemAnimator defaultItemAnimator = new DefaultItemAnimator() { @@ -3653,8 +3676,61 @@ public void openExceptions() { onWriteButtonClick(); } else if (position == premiumRow) { presentFragment(new PremiumPreviewFragment("settings")); + } else if (position == businessRow) { + presentFragment(new PremiumPreviewFragment(PremiumPreviewFragment.FEATURES_BUSINESS, "settings")); } else if (position == premiumGiftingRow) { UserSelectorBottomSheet.open(); + } else if (position == bizHoursRow) { + hoursExpanded = !hoursExpanded; + saveScrollPosition(); + view.requestLayout(); + listAdapter.notifyItemChanged(bizHoursRow); + if (savedScrollPosition >= 0) { + layoutManager.scrollToPositionWithOffset(savedScrollPosition, savedScrollOffset - listView.getPaddingTop()); + } + } else if (position == bizLocationRow) { + if (userInfo == null || userInfo.business_location == null) return; + if (userInfo.business_location.geo_point != null) { + LocationActivity fragment = new LocationActivity(3) { + @Override + protected boolean disablePermissionCheck() { + return true; + } + }; + fragment.setResourceProvider(resourcesProvider); + TLRPC.TL_message message = new TLRPC.TL_message(); + message.local_id = -1; + message.peer_id = getMessagesController().getPeer(dialogId); + TLRPC.TL_messageMediaGeo media = new TLRPC.TL_messageMediaGeo(); + media.geo = userInfo.business_location.geo_point; + media.address = userInfo.business_location.address; + message.media = media; + fragment.setSharingAllowed(false); + fragment.setMessageObject(new MessageObject(UserConfig.selectedAccount, message, false, false)); + presentFragment(fragment); + } else { + String domain; + if (BuildVars.isHuaweiStoreApp()) { + domain = "mapapp://navigation"; + } else { + domain = "http://maps.google.com/maps"; + } +// if (myLocation != null) { +// try { +// Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(String.format(Locale.US, domain + "?saddr=%f,%f&daddr=%f,%f", myLocation.getLatitude(), myLocation.getLongitude(), daddrLat, daddrLong))); +// getParentActivity().startActivity(intent); +// } catch (Exception e) { +// FileLog.e(e); +// } +// } else { + try { + Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(String.format(Locale.US, domain + "?q=" + userInfo.business_location.address ))); + getParentActivity().startActivity(intent); + } catch (Exception e) { + FileLog.e(e); + } +// } + } } else { processOnClickOrPress(position, view, x, y); } @@ -3700,7 +3776,7 @@ public boolean onItemClick(View view, int position) { BuildVars.DEBUG_PRIVATE_VERSION ? (SharedConfig.photoViewerBlur ? "do not blur in photoviewer" : "blur in photoviewer") : null, !SharedConfig.payByInvoice ? "Enable Invoice Payment" : "Disable Invoice Payment", BuildVars.DEBUG_PRIVATE_VERSION ? "Update Attach Bots" : null, - null // Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP ? (!SharedConfig.useCamera2 ? "Use Camera 2 API" : "Use old Camera 1 API") : null + Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP ? (!SharedConfig.useCamera2 ? "Use Camera 2 API" : "Use old Camera 1 API") : null }; builder.setItems(items, (dialog, which) -> { @@ -4474,7 +4550,7 @@ protected TextView createTextView() { }; mediaCounterTextView.setAlpha(0.0f); avatarContainer2.addView(mediaCounterTextView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.LEFT | Gravity.TOP, 118.33f, -2, 8, 0)); - storyView = new ProfileStoriesView(context, currentAccount, getDialogId(), avatarContainer, avatarImage, resourcesProvider) { + storyView = new ProfileStoriesView(context, currentAccount, getDialogId(), isTopic, avatarContainer, avatarImage, resourcesProvider) { @Override protected void onTap(StoryViewer.PlaceProvider provider) { long did = getDialogId(); @@ -4731,6 +4807,10 @@ private void checkCanSendStoryForPosting() { }, false, resourcesProvider); } + private void updateAvatarRoundRadius() { + avatarImage.setRoundRadius((int) AndroidUtilities.lerp(getSmallAvatarRoundRadius(), 0f, currentExpandAnimatorValue)); + } + private void createFloatingActionButton(Context context) { if (!getMessagesController().storiesEnabled()) { return; @@ -4795,7 +4875,8 @@ public StoryRecorder.SourceView getView(long dialogId) { if (dialogId != getDialogId()) { return null; } - return StoryRecorder.SourceView.fromAvatarImage(avatarImage); + updateAvatarRoundRadius(); + return StoryRecorder.SourceView.fromAvatarImage(avatarImage, ChatObject.isForum(currentChat)); } }) .open(StoryRecorder.SourceView.fromFloatingButton(floatingButtonContainer), true); @@ -5017,7 +5098,7 @@ private int getSmallAvatarRoundRadius() { if (chatId != 0) { TLRPC.Chat chatLocal = getMessagesController().getChat(chatId); if (ChatObject.isForum(chatLocal)) { - return AndroidUtilities.dp(16); + return AndroidUtilities.dp(needInsetForStories() ? 11 : 16); } } return AndroidUtilities.dp(21); @@ -5825,6 +5906,112 @@ protected boolean drawChild(Canvas canvas, View child, long drawingTime) { showMenu.run(); } return true; + } else if (position == bizHoursRow || position == bizLocationRow) { + if (getParentActivity() == null || userInfo == null) { + return false; + } + final String finalText; + if (position == bizHoursRow) { + if (userInfo.business_work_hours == null) return false; + ArrayList[] days = OpeningHoursActivity.getDaysHours(userInfo.business_work_hours.weekly_open); + StringBuilder sb = new StringBuilder(); + if (userInfo.user != null) { + sb.append(LocaleController.formatString(R.string.BusinessHoursCopyHeader, UserObject.getUserName(userInfo.user))).append("\n"); + } + for (int i = 0; i < days.length; ++i) { + ArrayList periods = days[i]; + String day = DayOfWeek.values()[i].getDisplayName(TextStyle.FULL, LocaleController.getInstance().getCurrentLocale()); + day = day.substring(0, 1).toUpperCase() + day.substring(1); + sb.append(day).append(": "); + if (OpeningHoursActivity.isFull(periods)) { + sb.append(LocaleController.getString(R.string.BusinessHoursProfileOpen)); + } else if (periods.isEmpty()) { + sb.append(LocaleController.getString(R.string.BusinessHoursProfileClose)); + } else { + for (int j = 0; j < periods.size(); ++j) { + if (j > 0) sb.append(", "); + OpeningHoursActivity.Period p = periods.get(j); + sb.append(OpeningHoursActivity.Period.timeToString(p.start)); + sb.append(" - "); + sb.append(OpeningHoursActivity.Period.timeToString(p.end)); + } + } + sb.append("\n"); + } + TLRPC.TL_timezone timezone = TimezonesController.getInstance(currentAccount).findTimezone(userInfo.business_work_hours.timezone_id); + Calendar calendar = Calendar.getInstance(); + int currentUtcOffset = calendar.getTimeZone().getRawOffset() / 1000; + int valueUtcOffset = timezone == null ? 0 : timezone.utc_offset; + int utcOffset = (currentUtcOffset - valueUtcOffset) / 60; + if (utcOffset != 0 && timezone != null) { + sb.append(LocaleController.formatString(R.string.BusinessHoursCopyFooter, TimezonesController.getInstance(currentAccount).getTimezoneName(timezone, true))); + } + finalText = sb.toString(); + } else if (position == bizLocationRow) { + if (userInfo.business_location == null) return false; + finalText = userInfo.business_location.address; + } else return true; + + AtomicReference popupWindowRef = new AtomicReference<>(); + ActionBarPopupWindow.ActionBarPopupWindowLayout popupLayout = new ActionBarPopupWindow.ActionBarPopupWindowLayout(getContext(), R.drawable.popup_fixed_alert, resourcesProvider) { + Path path = new Path(); + + @Override + protected boolean drawChild(Canvas canvas, View child, long drawingTime) { + canvas.save(); + path.rewind(); + AndroidUtilities.rectTmp.set(child.getLeft(), child.getTop(), child.getRight(), child.getBottom()); + path.addRoundRect(AndroidUtilities.rectTmp, AndroidUtilities.dp(6), AndroidUtilities.dp(6), Path.Direction.CW); + canvas.clipPath(path); + boolean draw = super.drawChild(canvas, child, drawingTime); + canvas.restore(); + return draw; + } + }; + popupLayout.setFitItems(true); + + ActionBarMenuItem.addItem(popupLayout, R.drawable.msg_copy, LocaleController.getString(R.string.Copy), false, resourcesProvider).setOnClickListener(v -> { + popupWindowRef.get().dismiss(); + try { + AndroidUtilities.addToClipboard(finalText); + if (position == bizHoursRow) { + BulletinFactory.of(this).createCopyBulletin(LocaleController.getString(R.string.BusinessHoursCopied)).show(); + } else { + BulletinFactory.of(this).createCopyBulletin(LocaleController.getString(R.string.BusinessLocationCopied)).show(); + } + } catch (Exception e) { + FileLog.e(e); + } + }); + + ActionBarPopupWindow popupWindow = new ActionBarPopupWindow(popupLayout, 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); + popupLayout.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); + popupWindowRef.set(popupWindow); + + float px = x, py = y; + View v = view; + while (v != getFragmentView()) { + px += v.getX(); + py += v.getY(); + v = (View) v.getParent(); + } + if (AndroidUtilities.isTablet()) { + View pv = parentLayout.getView(); + px += pv.getX() + pv.getPaddingLeft(); + py += pv.getY() + pv.getPaddingTop(); + } + px -= popupLayout.getMeasuredWidth() / 2f; + popupWindow.showAtLocation(getFragmentView(), 0, (int) px, (int) py); + popupWindow.dimBehind(); + return true; } return false; } @@ -7055,6 +7242,7 @@ public void didReceivedNotification(int id, int account, final Object... args) { } else if (id == NotificationCenter.storiesUpdated || id == NotificationCenter.storiesReadUpdated) { if (avatarImage != null) { avatarImage.setHasStories(needInsetForStories()); + updateAvatarRoundRadius(); } } } @@ -7732,7 +7920,7 @@ public void setChatInfo(TLRPC.ChatFull value) { } private boolean needInsetForStories() { - return getMessagesController().getStoriesController().hasStories(getDialogId()); + return getMessagesController().getStoriesController().hasStories(getDialogId()) && !isTopic; } public void setUserInfo(TLRPC.UserFull value) { @@ -7810,6 +7998,7 @@ private void updateRowsIds() { notificationRow = -1; languageRow = -1; premiumRow = -1; + businessRow = -1; premiumGiftingRow = -1; premiumSectionsRow = -1; privacyRow = -1; @@ -7848,11 +8037,15 @@ private void updateRowsIds() { notificationsDividerRow = -1; reportDividerRow = -1; notificationsRow = -1; + bizLocationRow = -1; + bizHoursRow = -1; infoSectionRow = -1; secretSettingsSectionRow = -1; bottomPaddingRow = -1; addToGroupButtonRow = -1; addToGroupInfoRow = -1; + infoStartRow = -1; + infoEndRow = -1; membersHeaderRow = -1; membersStartRow = -1; @@ -7941,6 +8134,7 @@ private void updateRowsIds() { devicesSectionRow = rowCount++; if (!getMessagesController().premiumFeaturesBlocked()) { premiumRow = rowCount++; + businessRow = rowCount++; } if (!getMessagesController().premiumPurchaseBlocked()) { premiumGiftingRow = rowCount++; @@ -7970,6 +8164,7 @@ private void updateRowsIds() { boolean hasInfo = userInfo != null && !TextUtils.isEmpty(userInfo.about) || user != null && !TextUtils.isEmpty(username); boolean hasPhone = user != null && (!TextUtils.isEmpty(user.phone) || !TextUtils.isEmpty(vcardPhone)); + infoStartRow = rowCount; infoHeaderRow = rowCount++; if (!isBot && (hasPhone || !hasInfo)) { phoneRow = rowCount++; @@ -7980,12 +8175,21 @@ private void updateRowsIds() { if (user != null && username != null) { usernameRow = rowCount++; } - if (phoneRow != -1 || userInfoRow != -1 || usernameRow != -1) { + if (userInfo != null) { + if (userInfo.business_work_hours != null) { + bizHoursRow = rowCount++; + } + if (userInfo.business_location != null) { + bizLocationRow = rowCount++; + } + } + if (phoneRow != -1 || userInfoRow != -1 || usernameRow != -1 || bizHoursRow != -1 || bizLocationRow != -1) { notificationsDividerRow = rowCount++; } if (userId != getUserConfig().getClientUserId()) { notificationsRow = rowCount++; } + infoEndRow = rowCount - 1; infoSectionRow = rowCount++; if (currentEncryptedChat instanceof TLRPC.TL_encryptedChat) { @@ -8176,6 +8380,9 @@ private void updateRowsIds() { if (listView == null || prevRowsCount > rowCount || listContentHeight != 0 && listContentHeight + actionBarHeight + AndroidUtilities.dp(88) < listView.getMeasuredHeight()) { lastMeasuredContentWidth = 0; } + if (listView != null) { + listView.setTranslateSelectorPosition(bizHoursRow); + } } private Drawable getScamDrawable(int type) { @@ -8258,7 +8465,7 @@ private void updateEmojiStatusDrawableColor(float progress) { } else { fromColor = AndroidUtilities.getOffsetColor(getThemedColor(Theme.key_profile_verifiedBackground), getThemedColor(Theme.key_player_actionBarTitle), mediaHeaderAnimationProgress, 1.0f); } - final int color = ColorUtils.blendARGB(fromColor, 0xffffffff, progress); + final int color = ColorUtils.blendARGB(ColorUtils.blendARGB(fromColor, 0xffffffff, progress), getThemedColor(Theme.key_player_actionBarTitle), mediaHeaderAnimationProgress); if (emojiStatusDrawable[a] != null) { emojiStatusDrawable[a].setColor(color); } @@ -9834,7 +10041,9 @@ private class ListAdapter extends RecyclerListView.SelectionAdapter { VIEW_TYPE_ADDTOGROUP_INFO = 17, VIEW_TYPE_PREMIUM_TEXT_CELL = 18, VIEW_TYPE_TEXT_DETAIL_MULTILINE = 19, - VIEW_TYPE_NOTIFICATIONS_CHECK_SIMPLE = 20; + VIEW_TYPE_NOTIFICATIONS_CHECK_SIMPLE = 20, + VIEW_TYPE_LOCATION = 21, + VIEW_TYPE_HOURS = 22; private Context mContext; @@ -9848,6 +10057,7 @@ public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType switch (viewType) { case VIEW_TYPE_HEADER: { view = new HeaderCell(mContext, 23, resourcesProvider); + view.setBackgroundColor(getThemedColor(Theme.key_windowBackgroundWhite)); break; } case VIEW_TYPE_TEXT_DETAIL_MULTILINE: @@ -9855,6 +10065,7 @@ public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType final TextDetailCell textDetailCell = new TextDetailCell(mContext, resourcesProvider, viewType == VIEW_TYPE_TEXT_DETAIL_MULTILINE); textDetailCell.setContentDescriptionValueFirst(true); view = textDetailCell; + view.setBackgroundColor(getThemedColor(Theme.key_windowBackgroundWhite)); break; case VIEW_TYPE_ABOUT_LINK: { view = aboutLinkCell = new AboutLinkCell(mContext, ProfileActivity.this, resourcesProvider) { @@ -9878,6 +10089,7 @@ protected int processColor(int color) { return applyPeerColor(color, false); } }; + view.setBackgroundColor(getThemedColor(Theme.key_windowBackgroundWhite)); break; } case VIEW_TYPE_TEXT: { @@ -9887,10 +10099,12 @@ protected int processColor(int color) { return applyPeerColor(color, false); } }; + view.setBackgroundColor(getThemedColor(Theme.key_windowBackgroundWhite)); break; } case VIEW_TYPE_DIVIDER: { view = new DividerCell(mContext, resourcesProvider); + view.setBackgroundColor(getThemedColor(Theme.key_windowBackgroundWhite)); view.setPadding(AndroidUtilities.dp(20), AndroidUtilities.dp(4), 0, 0); break; } @@ -9901,10 +10115,12 @@ protected int processColor(int color) { return applyPeerColor(color, false); } }; + view.setBackgroundColor(getThemedColor(Theme.key_windowBackgroundWhite)); break; } case VIEW_TYPE_NOTIFICATIONS_CHECK_SIMPLE: { view = new TextCheckCell(mContext, resourcesProvider); + view.setBackgroundColor(getThemedColor(Theme.key_windowBackgroundWhite)); break; } case VIEW_TYPE_SHADOW: { @@ -9913,6 +10129,7 @@ protected int processColor(int color) { } case VIEW_TYPE_USER: { view = new UserCell(mContext, addMemberRow == -1 ? 9 : 6, 0, true, resourcesProvider); + view.setBackgroundColor(getThemedColor(Theme.key_windowBackgroundWhite)); break; } case VIEW_TYPE_EMPTY: { @@ -9971,8 +10188,17 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { } case VIEW_TYPE_ADDTOGROUP_INFO: { view = new TextInfoPrivacyCell(mContext, resourcesProvider); + view.setBackgroundColor(getThemedColor(Theme.key_windowBackgroundWhite)); break; } + case VIEW_TYPE_LOCATION: + view = new ProfileLocationCell(mContext, resourcesProvider); + view.setBackgroundColor(getThemedColor(Theme.key_windowBackgroundWhite)); + break; + case VIEW_TYPE_HOURS: + view = new ProfileHoursCell(mContext, resourcesProvider); + view.setBackgroundColor(getThemedColor(Theme.key_windowBackgroundWhite)); + break; case VIEW_TYPE_VERSION: default: { TextInfoPrivacyCell cell = new TextInfoPrivacyCell(mContext, 10, resourcesProvider); @@ -10030,6 +10256,7 @@ protected void onNoClick(int type) { } case VIEW_TYPE_PREMIUM_TEXT_CELL: view = new ProfilePremiumCell(mContext, resourcesProvider); + view.setBackgroundColor(getThemedColor(Theme.key_windowBackgroundWhite)); break; } if (viewType != VIEW_TYPE_SHARED_MEDIA) { @@ -10142,7 +10369,7 @@ public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { value = ""; usernames = new ArrayList<>(); } - detailCell.setTextAndValue(text, alsoUsernamesString(username, usernames, value), isTopic); + detailCell.setTextAndValue(text, alsoUsernamesString(username, usernames, value), isTopic || bizHoursRow != -1 || bizLocationRow != -1); } else if (position == locationRow) { if (chatInfo != null && chatInfo.location instanceof TLRPC.TL_channelLocation) { TLRPC.TL_channelLocation location = (TLRPC.TL_channelLocation) chatInfo.location; @@ -10323,7 +10550,7 @@ public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { } else if (position == chatRow) { textCell.setTextAndIcon(LocaleController.getString("ChatSettings", R.string.ChatSettings), R.drawable.msg2_discussion, true); } else if (position == filtersRow) { - textCell.setTextAndIcon(LocaleController.getString("Filters", R.string.Filters), R.drawable.msg2_folder, true); + textCell.setTextAndIcon(LocaleController.getString(R.string.Filters), R.drawable.msg2_folder, true); } else if (position == stickersRow) { textCell.setTextAndIcon(LocaleController.getString(R.string.StickersName), R.drawable.msg2_sticker, true); } else if (position == liteModeRow) { @@ -10358,8 +10585,11 @@ public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { } else if (position == premiumRow) { textCell.setTextAndIcon(LocaleController.getString("TelegramPremium", R.string.TelegramPremium), new AnimatedEmojiDrawable.WrapSizeDrawable(PremiumGradient.getInstance().premiumStarMenuDrawable, AndroidUtilities.dp(24), AndroidUtilities.dp(24)), true); textCell.setImageLeft(23); + } else if (position == businessRow) { + textCell.setTextAndIcon(TextCell.applyNewSpan(LocaleController.getString(R.string.TelegramBusiness)), R.drawable.menu_shop, true); + textCell.setImageLeft(23); } else if (position == premiumGiftingRow) { - textCell.setTextAndIcon(TextCell.applyNewSpan(LocaleController.getString("GiftPremiumGifting", R.string.GiftPremiumGifting)), R.drawable.menu_gift, false); + textCell.setTextAndIcon(LocaleController.getString("GiftPremiumGifting", R.string.GiftPremiumGifting), R.drawable.menu_gift, false); textCell.setImageLeft(23); } textCell.valueTextView.setTextColor(applyPeerColor(getThemedColor(Theme.key_windowBackgroundWhiteValueText), false)); @@ -10494,6 +10724,25 @@ public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { TextCheckCell textCheckCell = (TextCheckCell) holder.itemView; textCheckCell.setTextAndCheck(LocaleController.getString("Notifications", R.string.Notifications), !getMessagesController().isDialogMuted(getDialogId(), topicId), false); break; + case VIEW_TYPE_LOCATION: + ((ProfileLocationCell) holder.itemView).set(userInfo != null ? userInfo.business_location : null, notificationsDividerRow < 0); + break; + case VIEW_TYPE_HOURS: + ProfileHoursCell hoursCell = (ProfileHoursCell) holder.itemView; + hoursCell.setOnTimezoneSwitchClick(view -> { + hoursShownMine = !hoursShownMine; + if (!hoursExpanded) { + hoursExpanded = true; + } + saveScrollPosition(); + view.requestLayout(); + listAdapter.notifyItemChanged(bizHoursRow); + if (savedScrollPosition >= 0) { + layoutManager.scrollToPositionWithOffset(savedScrollPosition, savedScrollOffset - listView.getPaddingTop()); + } + }); + hoursCell.set(userInfo != null ? userInfo.business_work_hours : null, hoursExpanded, hoursShownMine, notificationsDividerRow < 0 || bizLocationRow >= 0); + break; } } @@ -10566,7 +10815,8 @@ public boolean isEnabled(RecyclerView.ViewHolder holder) { position == questionRow || position == devicesRow || position == filtersRow || position == stickersRow || position == faqRow || position == policyRow || position == sendLogsRow || position == sendLastLogsRow || position == clearLogsRow || position == switchBackendRow || position == setAvatarRow || - position == addToGroupButtonRow || position == premiumRow || position == premiumGiftingRow || position == liteModeRow; + position == addToGroupButtonRow || position == premiumRow || position == premiumGiftingRow || + position == businessRow || position == liteModeRow; } if (holder.itemView instanceof UserCell) { UserCell userCell = (UserCell) holder.itemView; @@ -10608,7 +10858,7 @@ public int getItemViewType(int position) { position == questionRow || position == devicesRow || position == filtersRow || position == stickersRow || position == faqRow || position == policyRow || position == sendLogsRow || position == sendLastLogsRow || position == clearLogsRow || position == switchBackendRow || position == setAvatarRow || position == addToGroupButtonRow || - position == addToContactsRow || position == liteModeRow || position == premiumGiftingRow) { + position == addToContactsRow || position == liteModeRow || position == premiumGiftingRow || position == businessRow) { return VIEW_TYPE_TEXT; } else if (position == notificationsDividerRow) { return VIEW_TYPE_DIVIDER; @@ -10616,7 +10866,7 @@ public int getItemViewType(int position) { return VIEW_TYPE_NOTIFICATIONS_CHECK; } else if (position == notificationsSimpleRow) { return VIEW_TYPE_NOTIFICATIONS_CHECK_SIMPLE; - }else if (position == infoSectionRow || position == lastSectionRow || position == membersSectionRow || + } else if (position == infoSectionRow || position == lastSectionRow || position == membersSectionRow || position == secretSettingsSectionRow || position == settingsSectionRow || position == devicesSectionRow || position == helpSectionCell || position == setAvatarSectionRow || position == passwordSuggestionSectionRow || position == phoneSuggestionSectionRow || position == premiumSectionsRow || position == reportDividerRow) { @@ -10637,6 +10887,10 @@ public int getItemViewType(int position) { return VIEW_TYPE_ADDTOGROUP_INFO; } else if (position == premiumRow) { return VIEW_TYPE_PREMIUM_TEXT_CELL; + } else if (position == bizLocationRow) { + return VIEW_TYPE_LOCATION; + } else if (position == bizHoursRow) { + return VIEW_TYPE_HOURS; } return 0; } @@ -11844,6 +12098,7 @@ public void fillPositions(SparseIntArray sparseIntArray) { put(++pointer, notificationRow, sparseIntArray); put(++pointer, languageRow, sparseIntArray); put(++pointer, premiumRow, sparseIntArray); + put(++pointer, businessRow, sparseIntArray); put(++pointer, premiumSectionsRow, sparseIntArray); put(++pointer, premiumGiftingRow, sparseIntArray); put(++pointer, privacyRow, sparseIntArray); @@ -11899,6 +12154,8 @@ public void fillPositions(SparseIntArray sparseIntArray) { put(++pointer, joinRow, sparseIntArray); put(++pointer, lastSectionRow, sparseIntArray); put(++pointer, notificationsSimpleRow, sparseIntArray); + put(++pointer, bizHoursRow, sparseIntArray); + put(++pointer, bizLocationRow, sparseIntArray); } private void put(int id, int position, SparseIntArray sparseIntArray) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/SelectAnimatedEmojiDialog.java b/TMessagesProj/src/main/java/org/telegram/ui/SelectAnimatedEmojiDialog.java index 74f253fdcc7..57c69ec2424 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/SelectAnimatedEmojiDialog.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/SelectAnimatedEmojiDialog.java @@ -148,9 +148,10 @@ public class SelectAnimatedEmojiDialog extends FrameLayout implements Notificati public final static int TYPE_EMOJI_STATUS_CHANNEL = 9; public final static int TYPE_EMOJI_STATUS_CHANNEL_TOP = 10; public final static int TYPE_TAGS = 11; + public final static int TYPE_EMOJI_STATUS_TOP = 12; public boolean isBottom() { - return type == TYPE_SET_REPLY_ICON || type == TYPE_EMOJI_STATUS_CHANNEL_TOP; + return type == TYPE_SET_REPLY_ICON || type == TYPE_EMOJI_STATUS_CHANNEL_TOP || type == TYPE_EMOJI_STATUS_TOP; } private final int SPAN_COUNT_FOR_EMOJI = 8; @@ -435,7 +436,7 @@ public SelectAnimatedEmojiDialog(BaseFragment baseFragment, Context context, boo this.type = type; this.includeEmpty = includeEmpty; this.baseFragment = baseFragment; - this.includeHint = MessagesController.getGlobalMainSettings().getInt("emoji" + (type == TYPE_EMOJI_STATUS || type == TYPE_EMOJI_STATUS_CHANNEL || type == TYPE_EMOJI_STATUS_CHANNEL_TOP ? "status" : "reaction") + "usehint", 0) < 3; + this.includeHint = MessagesController.getGlobalMainSettings().getInt("emoji" + (type == TYPE_EMOJI_STATUS || type == TYPE_EMOJI_STATUS_TOP || type == TYPE_EMOJI_STATUS_CHANNEL || type == TYPE_EMOJI_STATUS_CHANNEL_TOP ? "status" : "reaction") + "usehint", 0) < 3; this.accentColor = accentColor; selectorPaint.setColor(Theme.getColor(Theme.key_listSelector, resourcesProvider)); @@ -448,7 +449,7 @@ public SelectAnimatedEmojiDialog(BaseFragment baseFragment, Context context, boo setFocusableInTouchMode(true); - if (type == TYPE_EMOJI_STATUS || type == TYPE_EMOJI_STATUS_CHANNEL || type == TYPE_EMOJI_STATUS_CHANNEL_TOP || type == TYPE_SET_DEFAULT_REACTION || type == TYPE_SET_REPLY_ICON || type == TYPE_SET_REPLY_ICON_BOTTOM) { + if (type == TYPE_EMOJI_STATUS || type == TYPE_EMOJI_STATUS_TOP || type == TYPE_EMOJI_STATUS_CHANNEL || type == TYPE_EMOJI_STATUS_CHANNEL_TOP || type == TYPE_SET_DEFAULT_REACTION || type == TYPE_SET_REPLY_ICON || type == TYPE_SET_REPLY_ICON_BOTTOM) { topMarginDp = topPaddingDp; setPadding(AndroidUtilities.dp(4), AndroidUtilities.dp(4), AndroidUtilities.dp(4), AndroidUtilities.dp(4)); setOnTouchListener((v, e) -> { @@ -561,12 +562,12 @@ public void getOutline(View view, Outline outline) { } } - if (type == TYPE_EMOJI_STATUS || type == TYPE_EMOJI_STATUS_CHANNEL || type == TYPE_EMOJI_STATUS_CHANNEL_TOP || type == TYPE_SET_DEFAULT_REACTION || type == TYPE_SET_REPLY_ICON) { + if (type == TYPE_EMOJI_STATUS || type == TYPE_EMOJI_STATUS_TOP || type == TYPE_EMOJI_STATUS_CHANNEL || type == TYPE_EMOJI_STATUS_CHANNEL_TOP || type == TYPE_SET_DEFAULT_REACTION || type == TYPE_SET_REPLY_ICON) { contentView.setPadding(AndroidUtilities.dp(8), AndroidUtilities.dp(8), AndroidUtilities.dp(8), AndroidUtilities.dp(8)); } contentView.addView(backgroundView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); - addView(contentView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.FILL, 0, type == TYPE_EMOJI_STATUS || type == TYPE_EMOJI_STATUS_CHANNEL || type == TYPE_SET_DEFAULT_REACTION || type == TYPE_SET_REPLY_ICON_BOTTOM ? 6 + topMarginDp : 0, 0, isBottom() ? 6 + topMarginDp : 0)); + addView(contentView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.FILL, 0, type == TYPE_EMOJI_STATUS || type == TYPE_EMOJI_STATUS_TOP || type == TYPE_EMOJI_STATUS_CHANNEL || type == TYPE_SET_DEFAULT_REACTION || type == TYPE_SET_REPLY_ICON_BOTTOM ? 6 + topMarginDp : 0, 0, isBottom() ? 6 + topMarginDp : 0)); if (bubbleX != null) { bubble2View = new View(context) { @@ -651,7 +652,7 @@ protected void onTabCreate(EmojiTabsStrip.EmojiTabButton button) { if (type == TYPE_AVATAR_CONSTRUCTOR) { emojiTabs.setAnimatedEmojiCacheType(AnimatedEmojiDrawable.CACHE_TYPE_ALERT_PREVIEW_STATIC); } else { - emojiTabs.setAnimatedEmojiCacheType(type == TYPE_EMOJI_STATUS || type == TYPE_SET_DEFAULT_REACTION ? AnimatedEmojiDrawable.CACHE_TYPE_TAB_STRIP : AnimatedEmojiDrawable.CACHE_TYPE_ALERT_PREVIEW_TAB_STRIP); + emojiTabs.setAnimatedEmojiCacheType(type == TYPE_EMOJI_STATUS || type == TYPE_EMOJI_STATUS_TOP || type == TYPE_SET_DEFAULT_REACTION ? AnimatedEmojiDrawable.CACHE_TYPE_TAB_STRIP : AnimatedEmojiDrawable.CACHE_TYPE_ALERT_PREVIEW_TAB_STRIP); } emojiTabs.animateAppear = bubbleX == null; emojiTabs.setPaddingLeft(type == TYPE_CHAT_REACTIONS ? 10 : 5); @@ -687,7 +688,7 @@ public void onScrolled(int dx, int dy) { updateTabsPosition(layoutManager.findFirstCompletelyVisibleItemPosition()); } updateSearchBox(); - AndroidUtilities.updateViewVisibilityAnimated(emojiTabsShadow, emojiGridView.computeVerticalScrollOffset() != 0 || type == TYPE_EMOJI_STATUS || type == TYPE_EMOJI_STATUS_CHANNEL_TOP || type == TYPE_REACTIONS || type == TYPE_TAGS || type == TYPE_CHAT_REACTIONS, 1f, true); + AndroidUtilities.updateViewVisibilityAnimated(emojiTabsShadow, emojiGridView.computeVerticalScrollOffset() != 0 || type == TYPE_EMOJI_STATUS || type == TYPE_EMOJI_STATUS_TOP || type == TYPE_EMOJI_STATUS_CHANNEL_TOP || type == TYPE_REACTIONS || type == TYPE_TAGS || type == TYPE_CHAT_REACTIONS, 1f, true); invalidateParent(); } @@ -821,7 +822,7 @@ public void onScrolled(int dx, int dy) { TextView emptyViewText = new TextView(context); if (type == TYPE_AVATAR_CONSTRUCTOR) { emptyViewText.setText(LocaleController.getString("NoEmojiOrStickersFound", R.string.NoEmojiOrStickersFound)); - } else if (type == TYPE_EMOJI_STATUS || type == TYPE_TAGS || type == TYPE_EMOJI_STATUS_CHANNEL || type == TYPE_EMOJI_STATUS_CHANNEL_TOP) { + } else if (type == TYPE_EMOJI_STATUS || type == TYPE_EMOJI_STATUS_TOP || type == TYPE_TAGS || type == TYPE_EMOJI_STATUS_CHANNEL || type == TYPE_EMOJI_STATUS_CHANNEL_TOP) { emptyViewText.setText(LocaleController.getString("NoEmojiFound", R.string.NoEmojiFound)); } else if (type == TYPE_REACTIONS || type == TYPE_SET_DEFAULT_REACTION) { emptyViewText.setText(LocaleController.getString("NoReactionsFound", R.string.NoReactionsFound)); @@ -923,7 +924,7 @@ public boolean onItemClick(View view, int position, float x, float y) { invalidateParent(); return true; } - if (view instanceof ImageViewEmoji && ((ImageViewEmoji) view).span != null && (type == TYPE_EMOJI_STATUS || type == TYPE_EMOJI_STATUS_CHANNEL || type == TYPE_EMOJI_STATUS_CHANNEL_TOP)) { + if (view instanceof ImageViewEmoji && ((ImageViewEmoji) view).span != null && (type == TYPE_EMOJI_STATUS || type == TYPE_EMOJI_STATUS_TOP || type == TYPE_EMOJI_STATUS_CHANNEL || type == TYPE_EMOJI_STATUS_CHANNEL_TOP)) { SelectStatusDurationDialog dialog = selectStatusDateDialog = new SelectStatusDurationDialog(context, dismiss, SelectAnimatedEmojiDialog.this, (ImageViewEmoji) view, resourcesProvider) { @Override protected boolean getOutBounds(Rect rect) { @@ -2227,7 +2228,7 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 13); if (type == TYPE_TOPIC_ICON) { textView.setText(LocaleController.getString("SelectTopicIconHint", R.string.SelectTopicIconHint)); - } else if (type == TYPE_EMOJI_STATUS || type == TYPE_EMOJI_STATUS_CHANNEL || type == TYPE_EMOJI_STATUS_CHANNEL_TOP) { + } else if (type == TYPE_EMOJI_STATUS || type == TYPE_EMOJI_STATUS_TOP || type == TYPE_EMOJI_STATUS_CHANNEL || type == TYPE_EMOJI_STATUS_CHANNEL_TOP) { textView.setText(LocaleController.getString("EmojiLongtapHint", R.string.EmojiLongtapHint)); } else { textView.setText(LocaleController.getString("ReactionsLongtapHint", R.string.ReactionsLongtapHint)); @@ -3116,7 +3117,7 @@ public void createPremiumLockView() { public void onEmojiClick(View view, AnimatedEmojiSpan span) { incrementHintUse(); - if (span == null || (type == TYPE_EMOJI_STATUS || type == TYPE_EMOJI_STATUS_CHANNEL || type == TYPE_EMOJI_STATUS_CHANNEL_TOP) && selectedDocumentIds.contains(span.documentId)) { + if (span == null || (type == TYPE_EMOJI_STATUS || type == TYPE_EMOJI_STATUS_TOP || type == TYPE_EMOJI_STATUS_CHANNEL || type == TYPE_EMOJI_STATUS_CHANNEL_TOP) && selectedDocumentIds.contains(span.documentId)) { onEmojiSelected(view, null, null, null); } else { TLRPC.TL_emojiStatus status = new TLRPC.TL_emojiStatus(); @@ -3124,10 +3125,10 @@ public void onEmojiClick(View view, AnimatedEmojiSpan span) { TLRPC.Document document = span.document == null ? AnimatedEmojiDrawable.findDocument(currentAccount, span.documentId) : span.document; if (view instanceof ImageViewEmoji) { - if (type == TYPE_EMOJI_STATUS || type == TYPE_EMOJI_STATUS_CHANNEL || type == TYPE_EMOJI_STATUS_CHANNEL_TOP) { + if (type == TYPE_EMOJI_STATUS || type == TYPE_EMOJI_STATUS_TOP || type == TYPE_EMOJI_STATUS_CHANNEL || type == TYPE_EMOJI_STATUS_CHANNEL_TOP) { MediaDataController.getInstance(currentAccount).pushRecentEmojiStatus(status); } - if (type == TYPE_EMOJI_STATUS || type == TYPE_EMOJI_STATUS_CHANNEL || type == TYPE_EMOJI_STATUS_CHANNEL_TOP || type == TYPE_SET_DEFAULT_REACTION) { + if (type == TYPE_EMOJI_STATUS || type == TYPE_EMOJI_STATUS_TOP || type == TYPE_EMOJI_STATUS_CHANNEL || type == TYPE_EMOJI_STATUS_CHANNEL_TOP || type == TYPE_SET_DEFAULT_REACTION) { animateEmojiSelect((ImageViewEmoji) view, () -> { onEmojiSelected(view, span.documentId, document, null); }); @@ -3144,7 +3145,7 @@ private void incrementHintUse() { if (type == TYPE_SET_DEFAULT_REACTION) { return; } - final String key = "emoji" + (type == TYPE_EMOJI_STATUS || type == TYPE_EMOJI_STATUS_CHANNEL || type == TYPE_EMOJI_STATUS_CHANNEL_TOP ? "status" : "reaction") + "usehint"; + final String key = "emoji" + (type == TYPE_EMOJI_STATUS || type == TYPE_EMOJI_STATUS_TOP || type == TYPE_EMOJI_STATUS_CHANNEL || type == TYPE_EMOJI_STATUS_CHANNEL_TOP ? "status" : "reaction") + "usehint"; final int value = MessagesController.getGlobalMainSettings().getInt(key, 0); if (value <= 3) { MessagesController.getGlobalMainSettings().edit().putInt(key, value + 1).apply(); @@ -3174,7 +3175,7 @@ public void preload(int type, int account) { MediaDataController.getInstance(account).fetchEmojiStatuses(2, false); MediaDataController.getInstance(account).loadRestrictedStatusEmojis(); MediaDataController.getInstance(account).getStickerSet(new TLRPC.TL_inputStickerSetEmojiChannelDefaultStatuses(), false); - } else if (type == TYPE_EMOJI_STATUS) { + } else if (type == TYPE_EMOJI_STATUS || type == TYPE_EMOJI_STATUS_TOP) { MediaDataController.getInstance(account).fetchEmojiStatuses(0, true); MediaDataController.getInstance(account).getStickerSet(new TLRPC.TL_inputStickerSetEmojiDefaultStatuses(), false); } else if (type == TYPE_TOPIC_ICON) { @@ -3244,7 +3245,7 @@ private void updateRows(boolean updateEmojipacks, boolean animated, boolean diff stickerSets.clear(); recentStickers.clear(); - if ((!installedEmojipacks.isEmpty() || type == TYPE_AVATAR_CONSTRUCTOR) && type != TYPE_SET_REPLY_ICON && type != TYPE_SET_REPLY_ICON_BOTTOM && type != TYPE_CHAT_REACTIONS && type != TYPE_EXPANDABLE_REACTIONS && type != TYPE_EMOJI_STATUS_CHANNEL && type != TYPE_EMOJI_STATUS_CHANNEL_TOP) { + if ((!installedEmojipacks.isEmpty() || type == TYPE_AVATAR_CONSTRUCTOR) && type != TYPE_SET_REPLY_ICON && type != TYPE_SET_REPLY_ICON_BOTTOM && type != TYPE_CHAT_REACTIONS && type != TYPE_EXPANDABLE_REACTIONS) { searchRow = totalCount++; rowHashCodes.add(9L); } else { @@ -3392,9 +3393,9 @@ private void updateRows(boolean updateEmojipacks, boolean animated, boolean diff totalCount += recentReactions.size(); recentReactionsEndRow = totalCount; } - } else if (type == TYPE_EMOJI_STATUS || type == TYPE_EMOJI_STATUS_CHANNEL || type == TYPE_EMOJI_STATUS_CHANNEL_TOP) { + } else if (type == TYPE_EMOJI_STATUS || type == TYPE_EMOJI_STATUS_TOP || type == TYPE_EMOJI_STATUS_CHANNEL || type == TYPE_EMOJI_STATUS_CHANNEL_TOP) { ArrayList recentEmojiStatuses = MediaDataController.getInstance(currentAccount).getRecentEmojiStatuses(); - TLRPC.TL_messages_stickerSet defaultSet = MediaDataController.getInstance(currentAccount).getStickerSet(type == TYPE_EMOJI_STATUS ? new TLRPC.TL_inputStickerSetEmojiDefaultStatuses() : new TLRPC.TL_inputStickerSetEmojiChannelDefaultStatuses(), true); + TLRPC.TL_messages_stickerSet defaultSet = MediaDataController.getInstance(currentAccount).getStickerSet(type == TYPE_EMOJI_STATUS || type == TYPE_EMOJI_STATUS_TOP ? new TLRPC.TL_inputStickerSetEmojiDefaultStatuses() : new TLRPC.TL_inputStickerSetEmojiChannelDefaultStatuses(), true); if (defaultSet == null) { defaultSetLoading = true; } else { @@ -3403,7 +3404,7 @@ private void updateRows(boolean updateEmojipacks, boolean animated, boolean diff rowHashCodes.add(2L); } ArrayList defaultEmojiStatuses; - if (type == TYPE_EMOJI_STATUS) { + if (type == TYPE_EMOJI_STATUS || type == TYPE_EMOJI_STATUS_TOP) { defaultEmojiStatuses = MediaDataController.getInstance(currentAccount).getDefaultEmojiStatuses(); } else { defaultEmojiStatuses = MediaDataController.getInstance(currentAccount).getDefaultChannelEmojiStatuses(); @@ -3417,7 +3418,7 @@ private void updateRows(boolean updateEmojipacks, boolean animated, boolean diff } } } - if (type == TYPE_EMOJI_STATUS && recentEmojiStatuses != null && !recentEmojiStatuses.isEmpty()) { + if ((type == TYPE_EMOJI_STATUS || type == TYPE_EMOJI_STATUS_TOP) && recentEmojiStatuses != null && !recentEmojiStatuses.isEmpty()) { for (TLRPC.EmojiStatus emojiStatus : recentEmojiStatuses) { Long did = UserObject.getEmojiStatusDocumentId(emojiStatus); if (did == null) { @@ -3743,7 +3744,7 @@ private int getCacheType() { if (type == TYPE_TOPIC_ICON || type == TYPE_AVATAR_CONSTRUCTOR) { return AnimatedEmojiDrawable.CACHE_TYPE_ALERT_PREVIEW_STATIC; } - return type == TYPE_EMOJI_STATUS || type == TYPE_EMOJI_STATUS_CHANNEL || type == TYPE_EMOJI_STATUS_CHANNEL_TOP || type == TYPE_SET_DEFAULT_REACTION ? AnimatedEmojiDrawable.CACHE_TYPE_KEYBOARD : AnimatedEmojiDrawable.CACHE_TYPE_ALERT_PREVIEW; + return type == TYPE_EMOJI_STATUS || type == TYPE_EMOJI_STATUS_TOP || type == TYPE_EMOJI_STATUS_CHANNEL || type == TYPE_EMOJI_STATUS_CHANNEL_TOP || type == TYPE_SET_DEFAULT_REACTION ? AnimatedEmojiDrawable.CACHE_TYPE_KEYBOARD : AnimatedEmojiDrawable.CACHE_TYPE_ALERT_PREVIEW; } public class EmojiListView extends RecyclerListView { @@ -4732,13 +4733,14 @@ private void createCategoriesListView() { if (categoriesListView != null || getContext() == null) { return; } - if (type != TYPE_REACTIONS && type != TYPE_TAGS && type != TYPE_SET_DEFAULT_REACTION && type != TYPE_EMOJI_STATUS && type != TYPE_AVATAR_CONSTRUCTOR) { + if (type != TYPE_REACTIONS && type != TYPE_TAGS && type != TYPE_SET_DEFAULT_REACTION && type != TYPE_EMOJI_STATUS && type != TYPE_EMOJI_STATUS_TOP && type != TYPE_AVATAR_CONSTRUCTOR && type != TYPE_EMOJI_STATUS_CHANNEL_TOP && type != TYPE_EMOJI_STATUS_CHANNEL) { return; } int categoriesType; switch (type) { case TYPE_EMOJI_STATUS: + case TYPE_EMOJI_STATUS_TOP: categoriesType = StickerCategoriesListView.CategoriesType.STATUS; break; case TYPE_AVATAR_CONSTRUCTOR: diff --git a/TMessagesProj/src/main/java/org/telegram/ui/SessionBottomSheet.java b/TMessagesProj/src/main/java/org/telegram/ui/SessionBottomSheet.java index 351c5de0be1..0dd523fcc11 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/SessionBottomSheet.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/SessionBottomSheet.java @@ -6,7 +6,6 @@ import android.graphics.PorterDuff; import android.graphics.PorterDuffColorFilter; import android.graphics.drawable.Drawable; -import android.os.Build; import android.util.TypedValue; import android.view.Gravity; import android.view.View; @@ -30,8 +29,6 @@ import org.telegram.ui.ActionBar.BaseFragment; import org.telegram.ui.ActionBar.BottomSheet; import org.telegram.ui.ActionBar.Theme; -import org.telegram.ui.Cells.SessionCell; -import org.telegram.ui.Cells.TextCheckCell2; import org.telegram.ui.Components.BulletinFactory; import org.telegram.ui.Components.LayoutHelper; import org.telegram.ui.Components.RLottieImageView; @@ -85,7 +82,7 @@ public void onClick(View view) { if ((session.flags & 1) != 0) { timeText = LocaleController.getString("Online", R.string.Online); } else { - timeText = LocaleController.formatDateTime(session.date_active); + timeText = LocaleController.formatDateTime(session.date_active, true); } timeView.setText(timeText); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Stories/DialogStoriesCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Stories/DialogStoriesCell.java index 37fd08fdc82..9727efebb03 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Stories/DialogStoriesCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Stories/DialogStoriesCell.java @@ -1108,6 +1108,7 @@ public class StoryCell extends FrameLayout { public StoryCell(Context context) { super(context); params.isArchive = type == TYPE_ARCHIVE; + params.isDialogStoriesCell = true; avatarImage.setInvalidateAll(true); avatarImage.setAllowLoadingOnAttachedOnly(true); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Stories/PeerStoriesView.java b/TMessagesProj/src/main/java/org/telegram/ui/Stories/PeerStoriesView.java index 1d8ac37e6db..e280941955b 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Stories/PeerStoriesView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Stories/PeerStoriesView.java @@ -58,7 +58,6 @@ import androidx.core.math.MathUtils; import androidx.recyclerview.widget.ChatListItemAnimator; -import org.checkerframework.checker.units.qual.A; import org.telegram.messenger.AccountInstance; import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.AnimationNotificationsLocker; @@ -2733,7 +2732,7 @@ public void drawRoundRect(Canvas canvas, Rect rect, float radius) { mentionContainer.withDelegate(new MentionsContainerView.Delegate() { @Override public void onStickerSelected(TLRPC.TL_document document, String query, Object parent) { - SendMessagesHelper.getInstance(currentAccount).sendSticker(document, query, dialogId, null, null, currentStory.storyItem, null, null, true, 0, false, parent); + SendMessagesHelper.getInstance(currentAccount).sendSticker(document, query, dialogId, null, null, currentStory.storyItem, null, null, true, 0, false, parent, null, 0); chatActivityEnterView.addStickerToRecent(document); chatActivityEnterView.setFieldText(""); afterMessageSend(); @@ -2762,7 +2761,7 @@ public void sendBotInlineResult(TLRPC.BotInlineResult result, boolean notify, in params.put("query_id", "" + result.query_id); params.put("bot", "" + uid); params.put("bot_name", mentionContainer.getAdapter().getContextBotName()); - SendMessagesHelper.prepareSendingBotContextResult(storyViewer.fragment, getAccountInstance(), result, params, dialogId, null, null, currentStory.storyItem, null, notify, scheduleDate); + SendMessagesHelper.prepareSendingBotContextResult(storyViewer.fragment, getAccountInstance(), result, params, dialogId, null, null, currentStory.storyItem, null, notify, scheduleDate, null, 0); chatActivityEnterView.setFieldText(""); afterMessageSend(); MediaDataController.getInstance(currentAccount).increaseInlineRaiting(uid); @@ -2899,7 +2898,7 @@ public void didPressedButton(int button, boolean arg, boolean notify, int schedu if (i == 0) { updateStickersOrder = photos.get(0).updateStickersOrder; } - SendMessagesHelper.prepareSendingMedia(getAccountInstance(), photos, dialogId, null, null, storyItem, null, button == 4 || forceDocument, arg, null, notify, scheduleDate, updateStickersOrder, null); + SendMessagesHelper.prepareSendingMedia(getAccountInstance(), photos, dialogId, null, null, storyItem, null, button == 4 || forceDocument, arg, null, notify, scheduleDate, 0, updateStickersOrder, null, null, 0); } chatActivityEnterView.setFieldText(""); afterMessageSend(); @@ -2939,7 +2938,7 @@ public void sendAudio(ArrayList audios, CharSequence caption, boo if (storyItem == null || storyItem instanceof TL_stories.TL_storyItemSkipped) { return; } - SendMessagesHelper.prepareSendingAudioDocuments(getAccountInstance(), audios, caption != null ? caption : null, dialogId, null, null, storyItem, notify, scheduleDate, null); + SendMessagesHelper.prepareSendingAudioDocuments(getAccountInstance(), audios, caption != null ? caption : null, dialogId, null, null, storyItem, notify, scheduleDate, null, null, 0); afterMessageSend(); } @@ -2958,7 +2957,7 @@ public void didSelectFiles(ArrayList files, String caption, ArrayList AndroidUtilities.dp(50)) { chatActivityEnterView.getEditField().setTranslationY((1f - progressToKeyboard) * (chatActivityEnterView.getMeasuredHeight() - AndroidUtilities.dp(50))); @@ -6252,15 +6275,15 @@ public void sendMedia(MediaController.PhotoEntry photoEntry, VideoEditedInfo vid storyItem.dialogId = dialogId; if (photoEntry.isVideo) { if (videoEditedInfo != null) { - SendMessagesHelper.prepareSendingVideo(getAccountInstance(), photoEntry.path, videoEditedInfo, dialogId, null, null, storyItem, null, photoEntry.entities, photoEntry.ttl, null, notify, scheduleDate, forceDocument, photoEntry.hasSpoiler, photoEntry.caption); + SendMessagesHelper.prepareSendingVideo(getAccountInstance(), photoEntry.path, videoEditedInfo, dialogId, null, null, storyItem, null, photoEntry.entities, photoEntry.ttl, null, notify, scheduleDate, forceDocument, photoEntry.hasSpoiler, photoEntry.caption, null, 0); } else { - SendMessagesHelper.prepareSendingVideo(getAccountInstance(), photoEntry.path, null, dialogId, null, null, storyItem, null, photoEntry.entities, photoEntry.ttl, null, notify, scheduleDate, forceDocument, photoEntry.hasSpoiler, photoEntry.caption); + SendMessagesHelper.prepareSendingVideo(getAccountInstance(), photoEntry.path, null, dialogId, null, null, storyItem, null, photoEntry.entities, photoEntry.ttl, null, notify, scheduleDate, forceDocument, photoEntry.hasSpoiler, photoEntry.caption, null, 0); } } else { if (photoEntry.imagePath != null) { - SendMessagesHelper.prepareSendingPhoto(getAccountInstance(), photoEntry.imagePath, photoEntry.thumbPath, null, dialogId, null, null, storyItem, null, photoEntry.entities, photoEntry.stickers, null, photoEntry.ttl, null, videoEditedInfo, notify, scheduleDate, forceDocument, photoEntry.caption); + SendMessagesHelper.prepareSendingPhoto(getAccountInstance(), photoEntry.imagePath, photoEntry.thumbPath, null, dialogId, null, null, storyItem, null, photoEntry.entities, photoEntry.stickers, null, photoEntry.ttl, null, videoEditedInfo, notify, scheduleDate, 0, forceDocument, photoEntry.caption, null, 0); } else if (photoEntry.path != null) { - SendMessagesHelper.prepareSendingPhoto(getAccountInstance(), photoEntry.path, photoEntry.thumbPath, null, dialogId, null, null, storyItem, null, photoEntry.entities, photoEntry.stickers, null, photoEntry.ttl, null, videoEditedInfo, notify, scheduleDate, forceDocument, photoEntry.caption); + SendMessagesHelper.prepareSendingPhoto(getAccountInstance(), photoEntry.path, photoEntry.thumbPath, null, dialogId, null, null, storyItem, null, photoEntry.entities, photoEntry.stickers, null, photoEntry.ttl, null, videoEditedInfo, notify, scheduleDate, 0, forceDocument, photoEntry.caption, null, 0); } } afterMessageSend(); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Stories/ProfileStoriesView.java b/TMessagesProj/src/main/java/org/telegram/ui/Stories/ProfileStoriesView.java index 6815f183531..781014b881f 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Stories/ProfileStoriesView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Stories/ProfileStoriesView.java @@ -11,8 +11,10 @@ import android.animation.ValueAnimator; import android.content.Context; import android.graphics.Canvas; +import android.graphics.Matrix; import android.graphics.Paint; import android.graphics.Path; +import android.graphics.PathMeasure; import android.graphics.PorterDuff; import android.graphics.PorterDuffXfermode; import android.graphics.RectF; @@ -30,6 +32,7 @@ import com.google.zxing.common.detector.MathUtils; import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.ChatObject; import org.telegram.messenger.ImageReceiver; import org.telegram.messenger.LocaleController; import org.telegram.messenger.MessagesController; @@ -62,6 +65,7 @@ public class ProfileStoriesView extends View implements NotificationCenter.Notif private final int currentAccount; private final long dialogId; + private final boolean isTopic; private final View avatarContainer; private final ProfileActivity.AvatarImageView avatarImage; @@ -138,11 +142,12 @@ public void apply() { StoriesController storiesController; - public ProfileStoriesView(Context context, int currentAccount, long dialogId, @NonNull View avatarContainer, ProfileActivity.AvatarImageView avatarImage, Theme.ResourcesProvider resourcesProvider) { + public ProfileStoriesView(Context context, int currentAccount, long dialogId, boolean isTopic, @NonNull View avatarContainer, ProfileActivity.AvatarImageView avatarImage, Theme.ResourcesProvider resourcesProvider) { super(context); this.currentAccount = currentAccount; this.dialogId = dialogId; + this.isTopic = isTopic; this.avatarContainer = avatarContainer; this.avatarImage = avatarImage; storiesController = MessagesController.getInstance(currentAccount).getStoriesController(); @@ -180,6 +185,9 @@ public void setStories(TL_stories.PeerStories peerStories) { } private void updateStories(boolean animated, boolean asUpdate) { + if (isTopic) { + return; + } final boolean me = dialogId == UserConfig.getInstance(currentAccount).getClientUserId(); final int now = ConnectionsManager.getInstance(currentAccount).getCurrentTime(); TL_stories.PeerStories userFullStories = MessagesController.getInstance(currentAccount).getStoriesController().getStoriesFromFullPeer(dialogId); @@ -527,6 +535,7 @@ protected void dispatchDraw(Canvas canvas) { if (radialProgress == null) { radialProgress = new RadialProgress(this); radialProgress.setBackground(null, true, false); + radialProgress.setRoundRectProgress(ChatObject.isForum(UserConfig.selectedAccount, dialogId)); } float uploadingProgress = 0; if (!storiesController.hasUploadingStories(dialogId) || storiesController.isLastUploadingFailed(dialogId)) { @@ -576,7 +585,13 @@ protected void dispatchDraw(Canvas canvas) { final Paint paint = StoriesUtilities.getErrorPaint(rect2); paint.setStrokeWidth(AndroidUtilities.dp(2)); paint.setAlpha((int) (255 * segmentsAlpha)); - canvas.drawCircle(rect2.centerX(), rect2.centerY(), rect2.width() / 2f, paint); + boolean isForum = ChatObject.isForum(UserConfig.selectedAccount, dialogId); + if (isForum) { + float r = rect2.height() * 0.32f; + canvas.drawRoundRect(rect2, r, r, paint); + } else { + canvas.drawCircle(rect2.centerX(), rect2.centerY(), rect2.width() / 2f, paint); + } } else if ((mainCircle != null || uploadingStoriesCount > 0) && segmentsAlpha > 0) { rect2.set(rect1); rect2.inset(-dpf2(2.66f + 2.23f / 2), -dpf2(2.66f + 2.23f / 2)); @@ -621,13 +636,13 @@ protected void dispatchDraw(Canvas canvas) { unreadPaint = gradientTools.getPaint(rect2); unreadPaint.setAlpha((int) (0xFF * (1f - read) * segmentsAlpha)); unreadPaint.setStrokeWidth(dpf2(2.33f)); - canvas.drawArc(rect2, a, -widthAngle * appear, false, unreadPaint); + drawArc(canvas, rect2, a, -widthAngle * appear, false, unreadPaint); } if (read > 0) { readPaint.setAlpha((int) (readPaintAlpha * read * segmentsAlpha)); readPaint.setStrokeWidth(dpf2(1.5f)); - canvas.drawArc(rect3, a, -widthAngle * appear, false, readPaint); + drawArc(canvas, rect3, a, -widthAngle * appear, false, readPaint); } if (bounceScale != 1) { @@ -820,9 +835,47 @@ private StoryCircle nearest(StoryCircle a, StoryCircle b, StoryCircle c) { return b; } + private final Path forumRoundRectPath = new Path(); + private final Matrix forumRoundRectMatrix = new Matrix(); + private final PathMeasure forumRoundRectPathMeasure = new PathMeasure(); + private final Path forumSegmentPath = new Path(); + + private void drawArc(Canvas canvas, RectF oval, float startAngle, float sweepAngle, boolean useCenter, Paint paint) { + boolean isForum = ChatObject.isForum(UserConfig.selectedAccount, dialogId); + if (isForum) { + float r = oval.height() * 0.32f; + if (Math.abs(sweepAngle) == 360) { + canvas.drawRoundRect(oval, r, r, paint); + return; + } + startAngle = startAngle + sweepAngle; + float endAngle = startAngle - sweepAngle; + float rotateAngle = (((int) (startAngle)) / 90) * 90; + + float pathAngleStart = -199 + rotateAngle; + float percentFrom = (startAngle - pathAngleStart) / 360; + float percentTo = (endAngle - pathAngleStart) / 360; + forumRoundRectPath.rewind(); + forumRoundRectPath.addRoundRect(oval, r, r, Path.Direction.CW); + forumRoundRectMatrix.reset(); + forumRoundRectMatrix.postRotate(rotateAngle, oval.centerX(), oval.centerY()); + forumRoundRectPath.transform(forumRoundRectMatrix); + + forumRoundRectPathMeasure.setPath(forumRoundRectPath, false); + float length = forumRoundRectPathMeasure.getLength(); + + forumSegmentPath.reset(); + forumRoundRectPathMeasure.getSegment(length * percentFrom, length * percentTo, forumSegmentPath, true); + forumSegmentPath.rLineTo(0, 0); + canvas.drawPath(forumSegmentPath, paint); + } else { + canvas.drawArc(oval, startAngle, sweepAngle, useCenter, paint); + } + } + private void drawArcs(Canvas canvas, StoryCircle A, StoryCircle B, StoryCircle C, Paint paint) { if (A == null && C == null) { - canvas.drawArc(B.borderRect, 0, 360, false, paint); + drawArc(canvas, B.borderRect, 0, 360, false, paint); } else if (A != null && C != null) { float xA = A.borderRect.centerX(), rA = A.borderRect.width() / 2f; float xB = B.borderRect.centerX(), rB = B.borderRect.width() / 2f; @@ -852,16 +905,16 @@ private void drawArcs(Canvas canvas, StoryCircle A, StoryCircle B, StoryCircle C if (d1 && d2) { angle = Math.max(angle1, angle2); - canvas.drawArc(B.borderRect, angle, 360 - angle * 2, false, paint); + drawArc(canvas, B.borderRect, angle, 360 - angle * 2, false, paint); } else if (d1) { // d1 && !d2 - canvas.drawArc(B.borderRect, 180 + angle2, 180 - (angle1 + angle2), false, paint); - canvas.drawArc(B.borderRect, angle1, 180 - angle2 - angle1, false, paint); + drawArc(canvas, B.borderRect, 180 + angle2, 180 - (angle1 + angle2), false, paint); + drawArc(canvas, B.borderRect, angle1, 180 - angle2 - angle1, false, paint); } else if (d2) { // !d1 && d2 - canvas.drawArc(B.borderRect, 180 + angle1, 180 - (angle2 + angle1), false, paint); - canvas.drawArc(B.borderRect, angle2, 180 - angle2 - angle1, false, paint); + drawArc(canvas, B.borderRect, 180 + angle1, 180 - (angle2 + angle1), false, paint); + drawArc(canvas, B.borderRect, angle2, 180 - angle2 - angle1, false, paint); } else { // !d1 && !d2 angle = Math.max(angle1, angle2); - canvas.drawArc(B.borderRect, 180 + angle, 360 - angle * 2, false, paint); + drawArc(canvas, B.borderRect, 180 + angle, 360 - angle * 2, false, paint); } } else if (A != null || C != null) { @@ -872,19 +925,19 @@ private void drawArcs(Canvas canvas, StoryCircle A, StoryCircle B, StoryCircle C float xB = B.borderRect.centerX(), rB = B.borderRect.width() / 2f; if (Math.abs(xA - xB) > rA + rB) { - canvas.drawArc(B.borderRect, 0, 360, false, paint); + drawArc(canvas, B.borderRect, 0, 360, false, paint); } else { float mx, d; if (xA > xB) { mx = ((xA - rA) + (xB + rB)) / 2f; d = Math.abs(mx - xB); float angle = (float) Math.toDegrees(Math.acos(d / rB)); - canvas.drawArc(B.borderRect, angle, 360 - angle * 2, false, paint); + drawArc(canvas, B.borderRect, angle, 360 - angle * 2, false, paint); } else { mx = ((xA + rA) + (xB - rB)) / 2f; d = Math.abs(mx - xB); float angle = (float) Math.toDegrees(Math.acos(d / rB)); - canvas.drawArc(B.borderRect, 180 + angle, 360 - angle * 2, false, paint); + drawArc(canvas, B.borderRect, 180 + angle, 360 - angle * 2, false, paint); } } } @@ -971,6 +1024,7 @@ public boolean findView(long dialogId, int messageId, int storyId, int type, Sto holder.clipBottom = AndroidUtilities.displaySize.y; holder.clipParent = (View) getParent(); holder.radialProgressUpload = radialProgress; + holder.checkParentScale = true; return true; } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Stories/StoriesController.java b/TMessagesProj/src/main/java/org/telegram/ui/Stories/StoriesController.java index 1969c0f787d..52bf157ea31 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Stories/StoriesController.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Stories/StoriesController.java @@ -2,7 +2,6 @@ import android.content.Intent; import android.content.SharedPreferences; -import android.os.Bundle; import android.text.TextUtils; import android.util.SparseArray; import android.webkit.MimeTypeMap; @@ -20,7 +19,6 @@ import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.ApplicationLoader; import org.telegram.messenger.BuildVars; -import org.telegram.messenger.ChannelBoostsController; import org.telegram.messenger.ChatObject; import org.telegram.messenger.DialogObject; import org.telegram.messenger.DownloadController; @@ -455,7 +453,7 @@ private void processAllStoriesResponse(TL_stories.TL_stories_allStories storiesR } } if (!userStories.stories.isEmpty()) { - allStoriesMap.put(dialogId, userStories); + putToAllStories(dialogId, userStories); for (int k = 0; k < 2; k++) { ArrayList storiesList = k == 0 ? hiddenListStories : dialogListStories; for (int j = 0; j < storiesList.size(); j++) { @@ -612,7 +610,7 @@ public void uploadStory(StoryEntry entry, boolean count) { if (!found) { TL_stories.PeerStories peerStories = new TL_stories.TL_peerStories(); peerStories.peer = MessagesController.getInstance(currentAccount).getPeer(dialogId); - allStoriesMap.put(dialogId, peerStories); + putToAllStories(dialogId, peerStories); dialogListStories.add(0, peerStories); loadAllStoriesForDialog(dialogId); } @@ -699,7 +697,7 @@ public UploadingStory getEditingStory(long dialogId) { private void applyNewStories(TL_stories.PeerStories stories) { long dialogId = DialogObject.getPeerDialogId(stories.peer); - allStoriesMap.put(dialogId, stories); + putToAllStories(dialogId, stories); if (dialogId != UserConfig.getInstance(UserConfig.selectedAccount).clientUserId) { TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(dialogId); applyToList(stories); @@ -711,6 +709,28 @@ private void applyNewStories(TL_stories.PeerStories stories) { updateStoriesInLists(dialogId, stories.stories); } + private void putToAllStories(long dialogId, TL_stories.PeerStories stories) { + TL_stories.PeerStories old = allStoriesMap.get(dialogId); + if ( + old != null && old.stories != null && !old.stories.isEmpty() && + stories != null && stories.stories != null && !stories.stories.isEmpty() + ) { + // do not override loaded stories with skipped ones + for (int i = 0; i < stories.stories.size(); ++i) { + if (stories.stories.get(i) instanceof TL_stories.TL_storyItemSkipped) { + int storyId = stories.stories.get(i).id; + for (int j = 0; j < old.stories.size(); ++j) { + if (old.stories.get(j).id == storyId && old.stories.get(j) instanceof TL_stories.TL_storyItem) { + stories.stories.set(i, old.stories.get(j)); + break; + } + } + } + } + } + allStoriesMap.put(dialogId, stories); + } + public static TL_stories.StoryItem applyStoryUpdate(TL_stories.StoryItem oldStoryItem, TL_stories.StoryItem newStoryItem) { if (newStoryItem == null) { return oldStoryItem; @@ -1380,6 +1400,9 @@ void loadSkippedStories(TL_stories.PeerStories userStories, boolean profile) { } storyIdsToLoad.add(userStories.stories.get(i).id); } + if (storyIdsToLoad != null && storyIdsToLoad.size() > 14) { + break; + } } if (storyIdsToLoad != null) { loadingAllStories.add(key); @@ -1486,7 +1509,7 @@ public int getTotalStoriesCount(boolean hidden) { } public void putStories(long dialogId, TL_stories.PeerStories stories) { - allStoriesMap.put(dialogId, stories); + putToAllStories(dialogId, stories); if (dialogId > 0) { TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(dialogId); if (isContactOrService(user) || user.self) { @@ -2192,9 +2215,9 @@ private void putMessages() { for (int i = 0; i < count; ++i) { long userId = entry.shareUserIds.get(i); if (entry.wouldBeVideo()) { - SendMessagesHelper.prepareSendingVideo(AccountInstance.getInstance(currentAccount), path, null, userId, null, null, null, null, captionEntities, 0, null, !entry.silent, entry.scheduleDate, false, false, caption); + SendMessagesHelper.prepareSendingVideo(AccountInstance.getInstance(currentAccount), path, null, userId, null, null, null, null, captionEntities, 0, null, !entry.silent, entry.scheduleDate, false, false, caption, null, 0); } else { - SendMessagesHelper.prepareSendingPhoto(AccountInstance.getInstance(currentAccount), path, null, null, userId, null, null, null, null, captionEntities, null, null, 0, null, null, !entry.silent, entry.scheduleDate, false, caption /* TODO: */); + SendMessagesHelper.prepareSendingPhoto(AccountInstance.getInstance(currentAccount), path, null, null, userId, null, null, null, null, captionEntities, null, null, 0, null, null, !entry.silent, entry.scheduleDate, 0, false, caption, null, 0); } } putMessages = true; @@ -2626,11 +2649,13 @@ private void saveCache() { return; } saving = true; + + final ArrayList toSave = new ArrayList<>(); + fill(toSave, true, true); + final MessagesStorage storage = MessagesStorage.getInstance(currentAccount); storage.getStorageQueue().postRunnable(() -> { SQLitePreparedStatement state = null; - ArrayList toSave = new ArrayList<>(); - fill(toSave, true, true); FileLog.d("StoriesList " + type + "{"+ dialogId +"} saveCache {" + storyItemMessageIds(toSave) + "}"); try { SQLiteDatabase database = storage.getDatabase(); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Stories/StoriesUtilities.java b/TMessagesProj/src/main/java/org/telegram/ui/Stories/StoriesUtilities.java index d3900f3c363..0519e92a593 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Stories/StoriesUtilities.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Stories/StoriesUtilities.java @@ -6,7 +6,10 @@ import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Color; +import android.graphics.Matrix; import android.graphics.Paint; +import android.graphics.Path; +import android.graphics.PathMeasure; import android.graphics.RectF; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; @@ -111,7 +114,7 @@ public static void drawAvatarWithStory(long dialogId, Canvas canvas, ImageReceiv int state; int unreadState = 0; boolean showProgress = storiesController.isLoading(dialogId); - boolean isForum = ChatObject.isForum(UserConfig.selectedAccount, dialogId) && !params.isStoryCell; + boolean isForum = ChatObject.isForum(UserConfig.selectedAccount, dialogId) && !params.isDialogStoriesCell; if (params.drawHiddenStoriesAsSegments) { hasStories = storiesController.hasHiddenStories(); } @@ -564,11 +567,32 @@ private static void drawCircleInternal(Canvas canvas, View view, AvatarStoryPara } } + private static final Path forumRoundRectPath = new Path(); + private static final Matrix forumRoundRectMatrix = new Matrix(); + private static final PathMeasure forumRoundRectPathMeasure = new PathMeasure(); + private static final Path forumSegmentPath = new Path(); + private static void drawSegment(Canvas canvas, RectF rectTmp, Paint paint, float startAngle, float endAngle, AvatarStoryParams params, boolean isForum) { if (isForum) { - forumRect.set(rectTmp); - forumRect.inset(AndroidUtilities.dp(0.5f), AndroidUtilities.dp(0.5f)); - canvas.drawRoundRect(forumRect, AndroidUtilities.dp(18), AndroidUtilities.dp(18), paint); + float r = rectTmp.height() * 0.32f; + float rotateAngle = (((int)(startAngle)) / 90) * 90 + 90; + float pathAngleStart = -199 + rotateAngle; + float percentFrom = (startAngle - pathAngleStart) / 360; + float percentTo = (endAngle - pathAngleStart) / 360; + forumRoundRectPath.rewind(); + forumRoundRectPath.addRoundRect(rectTmp, r, r, Path.Direction.CW); + + forumRoundRectMatrix.reset(); + forumRoundRectMatrix.postRotate(rotateAngle, rectTmp.centerX(), rectTmp.centerY()); + forumRoundRectPath.transform(forumRoundRectMatrix); + + forumRoundRectPathMeasure.setPath(forumRoundRectPath, false); + float length = forumRoundRectPathMeasure.getLength(); + + forumSegmentPath.reset(); + forumRoundRectPathMeasure.getSegment(length * percentFrom, length * percentTo, forumSegmentPath, true); + forumSegmentPath.rLineTo(0, 0); + canvas.drawPath(forumSegmentPath, paint); return; } if (!params.isFirst && !params.isLast) { @@ -1066,6 +1090,7 @@ public static class AvatarStoryParams { public int prevState; public float progressToSate = 1f; public boolean showProgress = false; + public boolean isDialogStoriesCell; private final boolean isStoryCell; public RectF originalAvatarRect = new RectF(); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Stories/StoryViewer.java b/TMessagesProj/src/main/java/org/telegram/ui/Stories/StoryViewer.java index 6f87a6de069..1f1987d171f 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Stories/StoryViewer.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Stories/StoryViewer.java @@ -50,6 +50,7 @@ import org.telegram.messenger.AnimationNotificationsLocker; import org.telegram.messenger.BotWebViewVibrationEffect; import org.telegram.messenger.BuildVars; +import org.telegram.messenger.ChatObject; import org.telegram.messenger.DialogObject; import org.telegram.messenger.FileLoader; import org.telegram.messenger.FileLog; @@ -455,7 +456,9 @@ public boolean onScroll(@NonNull MotionEvent e1, @NonNull MotionEvent e2, float windowView.performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP); } swipeToReplyProgress = Utilities.clamp(swipeToReplyOffset / maxOffset, 1f, 0); - storiesViewPager.getCurrentPeerView().invalidate(); + if (storiesViewPager.getCurrentPeerView() != null) { + storiesViewPager.getCurrentPeerView().invalidate(); + } if (swipeToReplyOffset < 0) { swipeToReplyOffset = 0; allowSwipeToReply = false; @@ -470,7 +473,9 @@ public boolean onScroll(@NonNull MotionEvent e1, @NonNull MotionEvent e2, float selfStoriesViewsOffset += distanceY; } Bulletin.hideVisible(windowView); - storiesViewPager.getCurrentPeerView().invalidate(); + if (storiesViewPager.getCurrentPeerView() != null) { + storiesViewPager.getCurrentPeerView().invalidate(); + } containerView.invalidate(); if (selfStoriesViewsOffset < 0) { selfStoriesViewsOffset = 0; @@ -742,7 +747,11 @@ protected void dispatchDraw(Canvas canvas) { boolean crossfade = transitionViewHolder != null && transitionViewHolder.crossfadeToAvatarImage != null; if (!crossfade || progressToOpen != 0) { headerView.backupImageView.getImageReceiver().setImageCoords(rect3); - headerView.backupImageView.getImageReceiver().setRoundRadius((int) (rect3.width() / 2f)); + + Integer cellAvatarImageRadius = transitionViewHolder != null ? transitionViewHolder.getAvatarImageRoundRadius() : null; + int newRoundRadius = (int) (AndroidUtilities.lerp(rect3.width() / 2f, cellAvatarImageRadius != null ? cellAvatarImageRadius : rect3.width() / 2f, 1f - progressToOpen)); + + headerView.backupImageView.getImageReceiver().setRoundRadius(newRoundRadius); headerView.backupImageView.getImageReceiver().setVisible(true, false); final float alpha = crossfade ? progressToOpen : 1f; float thisAlpha = alpha; @@ -947,7 +956,7 @@ public boolean onInterceptTouchEvent(MotionEvent ev) { final float nowSeek = currentPlayerScope.player.seek((x - lastTouchX) / AndroidUtilities.dp(220), videoDuration); if ((int) (nowSeek * 10) != (int) (wasSeek * 10)) { try { - peerView.performHapticFeedback(HapticFeedbackConstants.TEXT_HANDLE_MOVE, HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING); + peerView.performHapticFeedback(9, HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING); } catch (Exception ignore) { } } @@ -1315,7 +1324,8 @@ public void setAllowTouchesByViewPager(boolean b) { @Override public void requestPlayer(TLRPC.Document document, Uri uri, long t, PeerStoriesView.VideoPlayerSharedScope scope) { - if (isClosed || progressToOpen != 1f) { + if (isClosed || progressToOpen < .9f) { + FileLog.d("StoryViewer requestPlayer ignored, because closed: " + isClosed + ", " + progressToOpen); scope.firstFrameRendered = false; scope.player = null; return; @@ -1367,8 +1377,11 @@ public void requestPlayer(TLRPC.Document document, Uri uri, long t, PeerStoriesV t = playerSavedPosition; currentPlayerScope.firstFrameRendered = true; } + FileLog.d("StoryViewer requestPlayer: currentPlayerScope.player start " + uri); currentPlayerScope.player.start(isPaused(), uri, t, isInSilentMode, currentSpeed); currentPlayerScope.invalidate(); + } else { + FileLog.d("StoryViewer requestPlayer: url is null (1)"); } } else if (sameUri) { currentPlayerScope = scope; @@ -1378,6 +1391,7 @@ public void requestPlayer(TLRPC.Document document, Uri uri, long t, PeerStoriesV currentPlayerScope.renderView = aspectRatioFrameLayout; currentPlayerScope.textureView = textureView; currentPlayerScope.surfaceView = surfaceView; + FileLog.d("StoryViewer requestPlayer: same url"); } if (USE_SURFACE_VIEW) { if (uri == null) { @@ -2451,10 +2465,12 @@ public boolean isFullyVisible() { } public void presentFragment(BaseFragment fragment) { + BaseFragment lastFragment = LaunchActivity.getLastFragment(); + if (lastFragment == null) return; if (ATTACH_TO_FRAGMENT) { - LaunchActivity.getLastFragment().presentFragment(fragment); + lastFragment.presentFragment(fragment); } else { - LaunchActivity.getLastFragment().presentFragment(fragment); + lastFragment.presentFragment(fragment); close(false); } } @@ -2744,9 +2760,20 @@ public static class TransitionViewHolder { public float alpha = 1; public ImageReceiver crossfadeToAvatarImage; public StoriesUtilities.AvatarStoryParams params; - + public boolean checkParentScale; public int storyId; + public Integer getAvatarImageRoundRadius() { + if (avatarImage != null) { + float scale = 1f; + if (checkParentScale && view != null && view.getParent() != null) { + scale = ((ViewGroup) (view.getParent())).getScaleY(); + } + return (int) (avatarImage.getRoundRadius()[0] * scale); + } + return null; + } + public void clear() { view = null; params = null; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/CaptionContainerView.java b/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/CaptionContainerView.java index fb20faacbe1..4cd01e7b1d4 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/CaptionContainerView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/CaptionContainerView.java @@ -171,7 +171,7 @@ protected void onWaitingForKeyboard() { protected void createEmojiView() { super.createEmojiView(); EmojiView emojiView = getEmojiView(); - if (emojiView != null && getEditTextStyle() == EditTextEmoji.STYLE_STORY) { + if (emojiView != null && (getEditTextStyle() == EditTextEmoji.STYLE_STORY || getEditTextStyle() == EditTextEmoji.STYLE_PHOTOVIEWER)) { emojiView.shouldLightenBackground = false; emojiView.fixBottomTabContainerTranslation = false; emojiView.setShouldDrawBackground(false); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/DraftsController.java b/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/DraftsController.java index 092b4e722cf..dffeafb73d2 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/DraftsController.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/DraftsController.java @@ -561,7 +561,7 @@ public StoryDraft(@NonNull StoryEntry entry) { this.audioRight = entry.audioRight; this.audioVolume = entry.audioVolume; - this.roundPath = entry.round == null ? "" : entry.round.getAbsolutePath(); + this.roundPath = entry.round == null ? null : entry.round.getAbsolutePath(); this.roundThumb = entry.roundThumb; this.roundDuration = entry.roundDuration; this.roundOffset = entry.roundOffset; @@ -778,7 +778,7 @@ public void toStream(AbstractSerializedData stream) { new TLRPC.TL_inputPeerSelf().serializeToStream(stream); } - if (roundPath == null) { + if (TextUtils.isEmpty(roundPath)) { stream.writeInt32(TLRPC.TL_null.constructor); } else { stream.writeInt32(TLRPC.TL_documentAttributeVideo.constructor); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/StoryPrivacyBottomSheet.java b/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/StoryPrivacyBottomSheet.java index 6d35d50a0ab..da00f36e883 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/StoryPrivacyBottomSheet.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/StoryPrivacyBottomSheet.java @@ -3632,7 +3632,7 @@ public StoryPrivacy(int currentAccount, ArrayList rules) { for (int i = 0; i < allowUsers.users.size(); ++i) { long userId = allowUsers.users.get(i); TLRPC.InputUser inputUser = messagesController.getInputUser(userId); - if (!(inputUser instanceof TLRPC.TL_inputUserEmpty)) { + if (inputUser != null && !(inputUser instanceof TLRPC.TL_inputUserEmpty)) { rule.users.add(inputUser); selectedUserIds.add(userId); selectedInputUsers.add(inputUser); @@ -4017,7 +4017,14 @@ public boolean containsUser(TLRPC.User user) { } else if (type == TYPE_CLOSE_FRIENDS) { return user.close_friend; } else if (type == TYPE_SELECTED_CONTACTS) { - return selectedUserIds.contains(user.id); + if (selectedUserIds.contains(user.id)) { + return true; + } + for (ArrayList userIds : selectedUserIdsByGroup.values()) { + if (userIds.contains(user.id)) { + return true; + } + } } return false; } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/StoryRecorder.java b/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/StoryRecorder.java index 2f4d6f195eb..615b2879da7 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/StoryRecorder.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/StoryRecorder.java @@ -264,13 +264,13 @@ protected void show() {} protected void hide() {} protected void drawAbove(Canvas canvas, float alpha) {} - public static SourceView fromAvatarImage(ProfileActivity.AvatarImageView avatarImage) { + public static SourceView fromAvatarImage(ProfileActivity.AvatarImageView avatarImage, boolean isForum) { if (avatarImage == null || avatarImage.getRootView() == null) { return null; } float scale = ((View)avatarImage.getParent()).getScaleX(); final float size = avatarImage.getImageReceiver().getImageWidth() * scale; - final float radius = size / 2f; + final float rounding = isForum ? size * 0.32f : size; SourceView src = new SourceView() { @Override protected void show() { @@ -293,7 +293,7 @@ protected void hide() { src.screenRect.set(x, y, x + size, y + size); src.backgroundImageReceiver = avatarImage.getImageReceiver(); - src.rounding = radius * 2; + src.rounding = rounding; return src; } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ThemePreviewActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ThemePreviewActivity.java index be69809428a..dc43dea4d29 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ThemePreviewActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ThemePreviewActivity.java @@ -48,7 +48,6 @@ import android.graphics.drawable.Drawable; import android.graphics.drawable.GradientDrawable; import android.os.Build; -import android.os.Bundle; import android.os.SystemClock; import android.text.SpannableStringBuilder; import android.text.Spanned; @@ -2433,17 +2432,19 @@ private void updateApplyButton1(boolean animated) { TLRPC.Chat chat = getMessagesController().getChat(-dialogId); if (chat != null) { applyButton1.setText(LocaleController.formatString(R.string.ApplyWallpaperForChannel, chat.title)); - if (boostsStatus != null && boostsStatus.level < getMessagesController().channelCustomWallpaperLevelMin) { + if (boostsStatus != null && boostsStatus.level < getCustomWallpaperLevelMin()) { SpannableStringBuilder text = new SpannableStringBuilder("l"); if (lockSpan == null) { lockSpan = new ColoredImageSpan(R.drawable.mini_switch_lock); lockSpan.setTopOffset(1); } text.setSpan(lockSpan, 0, 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); - text.append(" ").append(LocaleController.formatPluralString("ReactionLevelRequiredBtn", getMessagesController().channelCustomWallpaperLevelMin)); + text.append(" ").append(LocaleController.formatPluralString("ReactionLevelRequiredBtn", getCustomWallpaperLevelMin())); applyButton1.setSubText(text, animated); } else if (boostsStatus == null) { checkBoostsLevel(); + } else { + applyButton1.setSubText(null, animated); } } else { applyButton1.setText(LocaleController.formatString(R.string.ApplyWallpaperForChannel, LocaleController.getString(R.string.AccDescrChannel).toLowerCase())); @@ -2453,9 +2454,16 @@ private void updateApplyButton1(boolean animated) { } } + private int getCustomWallpaperLevelMin() { + if (ChatObject.isChannelAndNotMegaGroup(-dialogId, currentAccount)) { + return getMessagesController().channelCustomWallpaperLevelMin; + } + return getMessagesController().groupCustomWallpaperLevelMin; + } + private void applyWallpaperBackground(boolean forBoth) { if (dialogId < 0) { - if (boostsStatus != null && boostsStatus.level < getMessagesController().channelCustomWallpaperLevelMin) { + if (boostsStatus != null && boostsStatus.level < getCustomWallpaperLevelMin()) { getMessagesController().getBoostsController().userCanBoostChannel(dialogId, boostsStatus, canApplyBoost -> { if (getContext() == null) { return; @@ -3256,6 +3264,7 @@ private boolean checkDiscard() { @Override public boolean onFragmentCreate() { + NotificationCenter.getInstance(currentAccount).addObserver(this, NotificationCenter.chatWasBoostedByUser); NotificationCenter.getGlobalInstance().addObserver(this, NotificationCenter.emojiLoaded); NotificationCenter.getGlobalInstance().addObserver(this, NotificationCenter.invalidateMotionBackground); getNotificationCenter().addObserver(this, NotificationCenter.wallpaperSettedToUser); @@ -3288,6 +3297,7 @@ public boolean onFragmentCreate() { @Override public void onFragmentDestroy() { + NotificationCenter.getInstance(currentAccount).removeObserver(this, NotificationCenter.chatWasBoostedByUser); NotificationCenter.getGlobalInstance().removeObserver(this, NotificationCenter.emojiLoaded); NotificationCenter.getGlobalInstance().removeObserver(this, NotificationCenter.invalidateMotionBackground); getNotificationCenter().removeObserver(this, NotificationCenter.wallpaperSettedToUser); @@ -3541,7 +3551,12 @@ public boolean onBackPressed() { @SuppressWarnings("unchecked") @Override public void didReceivedNotification(int id, int account, Object... args) { - if (id == NotificationCenter.emojiLoaded) { + if (id == NotificationCenter.chatWasBoostedByUser) { + if (dialogId == (long) args[2]) { + this.boostsStatus = (TL_stories.TL_premium_boostsStatus) args[0]; + updateApplyButton1(true); + } + } else if (id == NotificationCenter.emojiLoaded) { if (listView == null) { return; } @@ -5796,7 +5811,7 @@ private void createServiceMessageLocal(TLRPC.WallPaper wallPaper, boolean forBot ArrayList arr = new ArrayList<>(); arr.add(message); // MessagesStorage.getInstance(currentAccount).putMessages(arr, false, true, false, 0, false, 0); - MessagesController.getInstance(currentAccount).updateInterfaceWithMessages(dialogId, objArr, false); + MessagesController.getInstance(currentAccount).updateInterfaceWithMessages(dialogId, objArr, 0); } public interface DayNightSwitchDelegate { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/TopicsFragment.java b/TMessagesProj/src/main/java/org/telegram/ui/TopicsFragment.java index d7332b9f89b..c847876d808 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/TopicsFragment.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/TopicsFragment.java @@ -752,6 +752,8 @@ public void onSearchFilterCleared(FiltersView.MediaFilterData filterData) { avatarContainer = new ChatAvatarContainer(context, this, false); avatarContainer.getAvatarImageView().setRoundRadius(AndroidUtilities.dp(16)); avatarContainer.setOccupyStatusBar(!AndroidUtilities.isTablet() && !inPreviewMode); + avatarContainer.allowDrawStories = getDialogId() < 0; + avatarContainer.setClipChildren(false); actionBar.addView(avatarContainer, 0, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.MATCH_PARENT, Gravity.TOP | Gravity.LEFT, 56, 0, 86, 0)); avatarContainer.getAvatarImageView().setOnClickListener(new View.OnClickListener() { @@ -2543,6 +2545,7 @@ private void updateSubtitle() { @Override public boolean onFragmentCreate() { getMessagesController().loadFullChat(chatId, 0, true); + NotificationCenter.getInstance(currentAccount).addObserver(this, NotificationCenter.storiesUpdated); NotificationCenter.getInstance(currentAccount).addObserver(this, NotificationCenter.chatWasBoostedByUser); NotificationCenter.getInstance(currentAccount).addObserver(this, NotificationCenter.chatInfoDidLoad); NotificationCenter.getInstance(currentAccount).addObserver(this, NotificationCenter.topicsDidLoaded); @@ -2581,6 +2584,7 @@ public boolean onFragmentCreate() { @Override public void onFragmentDestroy() { notificationsLocker.unlock(); + NotificationCenter.getInstance(currentAccount).removeObserver(this, NotificationCenter.storiesUpdated); NotificationCenter.getInstance(currentAccount).removeObserver(this, NotificationCenter.chatWasBoostedByUser); NotificationCenter.getInstance(currentAccount).removeObserver(this, NotificationCenter.chatInfoDidLoad); NotificationCenter.getInstance(currentAccount).removeObserver(this, NotificationCenter.topicsDidLoaded); @@ -2671,6 +2675,8 @@ public void didReceivedNotification(int id, int account, Object... args) { pendingRequestsDelegate.setChatInfo(chatFull, true); } } + } else if (id == NotificationCenter.storiesUpdated) { + updateChatInfo(); } else if (id == NotificationCenter.chatWasBoostedByUser) { if (chatId == -(long) args[2]) { boostsStatus = (TL_stories.TL_premium_boostsStatus) args[0]; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/UsersSelectActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/UsersSelectActivity.java index 1a75e863e3e..cfeab417ef0 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/UsersSelectActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/UsersSelectActivity.java @@ -65,6 +65,7 @@ import org.telegram.ui.ActionBar.Theme; import org.telegram.ui.ActionBar.ThemeDescription; import org.telegram.ui.Adapters.SearchAdapterHelper; +import org.telegram.ui.Business.BusinessRecipientsHelper; import org.telegram.ui.Cells.GraySectionCell; import org.telegram.ui.Cells.GroupCreateUserCell; import org.telegram.ui.Components.AnimatedAvatarContainer; @@ -73,10 +74,12 @@ import org.telegram.ui.Components.CombinedDrawable; import org.telegram.ui.Components.EditTextBoldCursor; import org.telegram.ui.Components.EmptyTextProgressView; +import org.telegram.ui.Components.FlickerLoadingView; import org.telegram.ui.Components.GroupCreateSpan; import org.telegram.ui.Components.LayoutHelper; import org.telegram.ui.Components.Premium.LimitReachedBottomSheet; import org.telegram.ui.Components.RecyclerListView; +import org.telegram.ui.Components.StickerEmptyView; import java.util.ArrayList; @@ -84,12 +87,14 @@ public class UsersSelectActivity extends BaseFragment implements NotificationCen public final static int TYPE_FILTER = 0; public final static int TYPE_AUTO_DELETE_EXISTING_CHATS = 1; + public final static int TYPE_PRIVATE = 2; private ScrollView scrollView; private SpansContainer spansContainer; private EditTextBoldCursor editText; private RecyclerListView listView; - private EmptyTextProgressView emptyView; + private FlickerLoadingView progressView; + private StickerEmptyView emptyView; private GroupCreateAdapter adapter; private FilterUsersActivityDelegate delegate; private AnimatorSet currentDoneButtonAnimation; @@ -103,6 +108,8 @@ public class UsersSelectActivity extends BaseFragment implements NotificationCen AnimatedAvatarContainer animatedAvatarContainer; public boolean noChatTypes; + public boolean allowSelf; + public boolean doNotNewChats; private boolean isInclude; private int filterFlags; private ArrayList initialIds; @@ -358,11 +365,19 @@ public UsersSelectActivity(boolean include, ArrayList arrayList, int flags filterFlags = flags; initialIds = arrayList; type = TYPE_FILTER; + allowSelf = type != TYPE_AUTO_DELETE_EXISTING_CHATS; + } + + public UsersSelectActivity asPrivateChats() { + type = TYPE_PRIVATE; + allowSelf = false; + return this; } public UsersSelectActivity(int type) { super(); this.type = type; + allowSelf = type != TYPE_AUTO_DELETE_EXISTING_CHATS; } @Override @@ -387,22 +402,34 @@ public void onClick(View v) { if (span.isDeleting()) { currentDeletingSpan = null; spansContainer.removeSpan(span); - if (span.getUid() == Long.MIN_VALUE) { - filterFlags &=~ MessagesController.DIALOG_FILTER_FLAG_CONTACTS; - } else if (span.getUid() == Long.MIN_VALUE + 1) { - filterFlags &=~ MessagesController.DIALOG_FILTER_FLAG_NON_CONTACTS; - } else if (span.getUid() == Long.MIN_VALUE + 2) { - filterFlags &=~ MessagesController.DIALOG_FILTER_FLAG_GROUPS; - } else if (span.getUid() == Long.MIN_VALUE + 3) { - filterFlags &=~ MessagesController.DIALOG_FILTER_FLAG_CHANNELS; - } else if (span.getUid() == Long.MIN_VALUE + 4) { - filterFlags &=~ MessagesController.DIALOG_FILTER_FLAG_BOTS; - } else if (span.getUid() == Long.MIN_VALUE + 5) { - filterFlags &=~ MessagesController.DIALOG_FILTER_FLAG_EXCLUDE_MUTED; - } else if (span.getUid() == Long.MIN_VALUE + 6) { - filterFlags &=~ MessagesController.DIALOG_FILTER_FLAG_EXCLUDE_READ; - } else if (span.getUid() == Long.MIN_VALUE + 7) { - filterFlags &=~ MessagesController.DIALOG_FILTER_FLAG_EXCLUDE_ARCHIVED; + if (type == TYPE_PRIVATE) { + if (span.getUid() == Long.MIN_VALUE + 8) { + filterFlags &= ~BusinessRecipientsHelper.PRIVATE_FLAG_EXISTING_CHATS; + } else if (span.getUid() == Long.MIN_VALUE + 9) { + filterFlags &= ~BusinessRecipientsHelper.PRIVATE_FLAG_NEW_CHATS; + } else if (span.getUid() == Long.MIN_VALUE) { + filterFlags &= ~BusinessRecipientsHelper.PRIVATE_FLAG_CONTACTS; + } else if (span.getUid() == Long.MIN_VALUE + 1) { + filterFlags &= ~BusinessRecipientsHelper.PRIVATE_FLAG_NON_CONTACTS; + } + } else { + if (span.getUid() == Long.MIN_VALUE) { + filterFlags &= ~MessagesController.DIALOG_FILTER_FLAG_CONTACTS; + } else if (span.getUid() == Long.MIN_VALUE + 1) { + filterFlags &= ~MessagesController.DIALOG_FILTER_FLAG_NON_CONTACTS; + } else if (span.getUid() == Long.MIN_VALUE + 2) { + filterFlags &= ~MessagesController.DIALOG_FILTER_FLAG_GROUPS; + } else if (span.getUid() == Long.MIN_VALUE + 3) { + filterFlags &= ~MessagesController.DIALOG_FILTER_FLAG_CHANNELS; + } else if (span.getUid() == Long.MIN_VALUE + 4) { + filterFlags &= ~MessagesController.DIALOG_FILTER_FLAG_BOTS; + } else if (span.getUid() == Long.MIN_VALUE + 5) { + filterFlags &= ~MessagesController.DIALOG_FILTER_FLAG_EXCLUDE_MUTED; + } else if (span.getUid() == Long.MIN_VALUE + 6) { + filterFlags &= ~MessagesController.DIALOG_FILTER_FLAG_EXCLUDE_READ; + } else if (span.getUid() == Long.MIN_VALUE + 7) { + filterFlags &= ~MessagesController.DIALOG_FILTER_FLAG_EXCLUDE_ARCHIVED; + } } updateHint(); checkVisibleRows(); @@ -430,7 +457,7 @@ public View createView(Context context) { } actionBar.setBackButtonImage(R.drawable.ic_ab_back); actionBar.setAllowOverlayTitle(true); - if (type == TYPE_FILTER) { + if (type == TYPE_FILTER || type == TYPE_PRIVATE) { if (isInclude) { actionBar.setTitle(LocaleController.getString("FilterAlwaysShow", R.string.FilterAlwaysShow)); } else { @@ -466,6 +493,7 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { scrollView.measure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(maxSize, MeasureSpec.AT_MOST)); listView.measure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(height - scrollView.getMeasuredHeight(), MeasureSpec.EXACTLY)); emptyView.measure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(height - scrollView.getMeasuredHeight(), MeasureSpec.EXACTLY)); + progressView.measure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(height - scrollView.getMeasuredHeight(), MeasureSpec.EXACTLY)); if (floatingButton != null) { int w = AndroidUtilities.dp(Build.VERSION.SDK_INT >= 21 ? 56 : 60); floatingButton.measure(MeasureSpec.makeMeasureSpec(w, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(w, MeasureSpec.EXACTLY)); @@ -477,7 +505,7 @@ protected void onLayout(boolean changed, int left, int top, int right, int botto scrollView.layout(0, 0, scrollView.getMeasuredWidth(), scrollView.getMeasuredHeight()); listView.layout(0, scrollView.getMeasuredHeight(), listView.getMeasuredWidth(), scrollView.getMeasuredHeight() + listView.getMeasuredHeight()); emptyView.layout(0, scrollView.getMeasuredHeight(), emptyView.getMeasuredWidth(), scrollView.getMeasuredHeight() + emptyView.getMeasuredHeight()); - + progressView.layout(0, scrollView.getMeasuredHeight(), emptyView.getMeasuredWidth(), scrollView.getMeasuredHeight() + progressView.getMeasuredHeight()); if (floatingButton != null) { int l = LocaleController.isRTL ? AndroidUtilities.dp(14) : (right - left) - AndroidUtilities.dp(14) - floatingButton.getMeasuredWidth(); int t = bottom - top - AndroidUtilities.dp(14) - floatingButton.getMeasuredHeight(); @@ -584,22 +612,34 @@ public boolean onKey(View v, int keyCode, KeyEvent event) { } else if (event.getAction() == KeyEvent.ACTION_UP && wasEmpty && !allSpans.isEmpty()) { GroupCreateSpan span = allSpans.get(allSpans.size() - 1); spansContainer.removeSpan(span); - if (span.getUid() == Long.MIN_VALUE) { - filterFlags &=~ MessagesController.DIALOG_FILTER_FLAG_CONTACTS; - } else if (span.getUid() == Long.MIN_VALUE + 1) { - filterFlags &=~ MessagesController.DIALOG_FILTER_FLAG_NON_CONTACTS; - } else if (span.getUid() == Long.MIN_VALUE + 2) { - filterFlags &=~ MessagesController.DIALOG_FILTER_FLAG_GROUPS; - } else if (span.getUid() == Long.MIN_VALUE + 3) { - filterFlags &=~ MessagesController.DIALOG_FILTER_FLAG_CHANNELS; - } else if (span.getUid() == Long.MIN_VALUE + 4) { - filterFlags &=~ MessagesController.DIALOG_FILTER_FLAG_BOTS; - } else if (span.getUid() == Long.MIN_VALUE + 5) { - filterFlags &=~ MessagesController.DIALOG_FILTER_FLAG_EXCLUDE_MUTED; - } else if (span.getUid() == Long.MIN_VALUE + 6) { - filterFlags &=~ MessagesController.DIALOG_FILTER_FLAG_EXCLUDE_READ; - } else if (span.getUid() == Long.MIN_VALUE + 7) { - filterFlags &=~ MessagesController.DIALOG_FILTER_FLAG_EXCLUDE_ARCHIVED; + if (type == TYPE_PRIVATE) { + if (span.getUid() == Long.MIN_VALUE + 8) { + filterFlags &= ~BusinessRecipientsHelper.PRIVATE_FLAG_EXISTING_CHATS; + } else if (span.getUid() == Long.MIN_VALUE + 9) { + filterFlags &= ~BusinessRecipientsHelper.PRIVATE_FLAG_NEW_CHATS; + } else if (span.getUid() == Long.MIN_VALUE) { + filterFlags &= ~BusinessRecipientsHelper.PRIVATE_FLAG_CONTACTS; + } else if (span.getUid() == Long.MIN_VALUE + 1) { + filterFlags &= ~BusinessRecipientsHelper.PRIVATE_FLAG_NON_CONTACTS; + } + } else { + if (span.getUid() == Long.MIN_VALUE) { + filterFlags &= ~MessagesController.DIALOG_FILTER_FLAG_CONTACTS; + } else if (span.getUid() == Long.MIN_VALUE + 1) { + filterFlags &= ~MessagesController.DIALOG_FILTER_FLAG_NON_CONTACTS; + } else if (span.getUid() == Long.MIN_VALUE + 2) { + filterFlags &= ~MessagesController.DIALOG_FILTER_FLAG_GROUPS; + } else if (span.getUid() == Long.MIN_VALUE + 3) { + filterFlags &= ~MessagesController.DIALOG_FILTER_FLAG_CHANNELS; + } else if (span.getUid() == Long.MIN_VALUE + 4) { + filterFlags &= ~MessagesController.DIALOG_FILTER_FLAG_BOTS; + } else if (span.getUid() == Long.MIN_VALUE + 5) { + filterFlags &= ~MessagesController.DIALOG_FILTER_FLAG_EXCLUDE_MUTED; + } else if (span.getUid() == Long.MIN_VALUE + 6) { + filterFlags &= ~MessagesController.DIALOG_FILTER_FLAG_EXCLUDE_READ; + } else if (span.getUid() == Long.MIN_VALUE + 7) { + filterFlags &= ~MessagesController.DIALOG_FILTER_FLAG_EXCLUDE_ARCHIVED; + } } updateHint(); checkVisibleRows(); @@ -629,9 +669,9 @@ public void afterTextChanged(Editable editable) { adapter.setSearching(true); listView.setFastScrollVisible(false); listView.setVerticalScrollBarEnabled(true); - emptyView.setText(LocaleController.getString("NoResult", R.string.NoResult)); - emptyView.showProgress(); + emptyView.title.setText(LocaleController.getString("NoResult", R.string.NoResult)); } + emptyView.showProgress(true); adapter.searchDialogs(editText.getText().toString()); } else { closeSearch(); @@ -639,14 +679,24 @@ public void afterTextChanged(Editable editable) { } }); - emptyView = new EmptyTextProgressView(context); - if (ContactsController.getInstance(currentAccount).isLoadingContacts()) { - emptyView.showProgress(); - } else { - emptyView.showTextView(); - } - emptyView.setShowAtCenter(true); - emptyView.setText(LocaleController.getString("NoContacts", R.string.NoContacts)); + progressView = new FlickerLoadingView(context); + progressView.setViewType(FlickerLoadingView.USERS2_TYPE); + progressView.showDate(false); + progressView.setItemsCount(3); + progressView.setColors(Theme.key_actionBarDefaultSubmenuBackground, Theme.key_listSelector, Theme.key_listSelector); + frameLayout.addView(progressView); + + emptyView = new StickerEmptyView(context, progressView, StickerEmptyView.STICKER_TYPE_SEARCH) { + @Override + public void setVisibility(int visibility) { + super.setVisibility(visibility); + if (visibility != View.VISIBLE) { + showProgress(false, false); + } + } + }; + emptyView.showProgress(ContactsController.getInstance(currentAccount).isLoadingContacts()); + emptyView.title.setText(LocaleController.getString("NoContacts", R.string.NoContacts)); frameLayout.addView(emptyView); LinearLayoutManager linearLayoutManager = new LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false); @@ -667,7 +717,21 @@ public void afterTextChanged(Editable editable) { long id; if (object instanceof String) { int flag; - if (isInclude) { + if (type == TYPE_PRIVATE) { + if (position == 1) { + flag = BusinessRecipientsHelper.PRIVATE_FLAG_EXISTING_CHATS; + id = Long.MIN_VALUE + 8; + } else if (position == 2 && !doNotNewChats) { + flag = BusinessRecipientsHelper.PRIVATE_FLAG_NEW_CHATS; + id = Long.MIN_VALUE + 9; + } else if (position == 2 + (doNotNewChats ? 0 : 1)) { + flag = BusinessRecipientsHelper.PRIVATE_FLAG_CONTACTS; + id = Long.MIN_VALUE; + } else { + flag = BusinessRecipientsHelper.PRIVATE_FLAG_NON_CONTACTS; + id = Long.MIN_VALUE + 1; + } + } else if (isInclude) { if (position == 1) { flag = MessagesController.DIALOG_FILTER_FLAG_CONTACTS; id = Long.MIN_VALUE; @@ -795,7 +859,21 @@ public void getOutline(View view, Outline outline) { int id; int flag; Object object; - if (isInclude) { + if (type == TYPE_PRIVATE) { + if (position == 1) { + object = "existing_chats"; + flag = BusinessRecipientsHelper.PRIVATE_FLAG_EXISTING_CHATS; + } else if (position == 2 && !doNotNewChats) { + object = "new_chats"; + flag = BusinessRecipientsHelper.PRIVATE_FLAG_NEW_CHATS; + } else if (position == 2 + (doNotNewChats ? 0 : 1)) { + object = "contacts"; + flag = BusinessRecipientsHelper.PRIVATE_FLAG_CONTACTS; + } else { + object = "non_contacts"; + flag = BusinessRecipientsHelper.PRIVATE_FLAG_NON_CONTACTS; + } + } else if (isInclude) { if (position == 1) { object = "contacts"; flag = MessagesController.DIALOG_FILTER_FLAG_CONTACTS; @@ -865,7 +943,7 @@ public void onResume() { public void didReceivedNotification(int id, int account, Object... args) { if (id == NotificationCenter.contactsDidLoad) { if (emptyView != null) { - emptyView.showTextView(); + emptyView.showProgress(false); } if (adapter != null) { adapter.notifyDataSetChanged(); @@ -933,6 +1011,12 @@ private void checkVisibleRows() { case "read": id = Long.MIN_VALUE + 6; break; + case "existing_chats": + id = Long.MIN_VALUE + 8; + break; + case "new_chats": + id = Long.MIN_VALUE + 8; + break; case "archived": default: id = Long.MIN_VALUE + 7; @@ -960,7 +1044,7 @@ private boolean onDonePressed(boolean alert) { ArrayList result = new ArrayList<>(); for (int a = 0; a < selectedContacts.size(); a++) { long uid = selectedContacts.keyAt(a); - if (uid <= Long.MIN_VALUE + 7) { + if (uid <= Long.MIN_VALUE + 9) { continue; } result.add(selectedContacts.keyAt(a)); @@ -979,7 +1063,7 @@ private void closeSearch() { adapter.searchDialogs(null); listView.setFastScrollVisible(true); listView.setVerticalScrollBarEnabled(false); - emptyView.setText(LocaleController.getString("NoContacts", R.string.NoContacts)); + emptyView.title.setText(LocaleController.getString("NoContacts", R.string.NoContacts)); } private void updateHint() { @@ -1025,11 +1109,30 @@ public class GroupCreateAdapter extends RecyclerListView.FastScrollAdapter { private Runnable searchRunnable; private boolean searching; private ArrayList contacts = new ArrayList<>(); - private final int usersStartRow = type == TYPE_FILTER && !noChatTypes ? isInclude ? 7 : 5 : 0; + private final int usersStartRow; public GroupCreateAdapter(Context ctx) { context = ctx; + if (type == TYPE_PRIVATE) { + usersStartRow = 5 + (doNotNewChats ? 0 : 1); + } else if (type == TYPE_FILTER) { + if (!noChatTypes) { + if (isInclude) { + usersStartRow = 7; + } else { + usersStartRow = 5; + } + } else { + usersStartRow = 0; + } + } else { + usersStartRow = 0; + } + + final boolean allowBots = type != TYPE_PRIVATE; + final boolean allowChats = type != TYPE_PRIVATE; + boolean hasSelf = false; ArrayList dialogs = getMessagesController().getAllDialogs(); for (int a = 0, N = dialogs.size(); a < N; a++) { @@ -1040,7 +1143,10 @@ public GroupCreateAdapter(Context ctx) { if (DialogObject.isUserDialog(dialog.id)) { TLRPC.User user = getMessagesController().getUser(dialog.id); if (user != null) { - if (type == TYPE_AUTO_DELETE_EXISTING_CHATS && UserObject.isUserSelf(user)) { + if (!allowSelf && UserObject.isUserSelf(user)) { + continue; + } + if (user.bot && !allowBots) { continue; } contacts.add(user); @@ -1050,12 +1156,13 @@ public GroupCreateAdapter(Context ctx) { } } else { TLRPC.Chat chat = getMessagesController().getChat(-dialog.id); + if (!allowChats) continue; if (chat != null) { contacts.add(chat); } } } - if (!hasSelf && type != TYPE_AUTO_DELETE_EXISTING_CHATS) { + if (!hasSelf && allowSelf) { TLRPC.User user = getMessagesController().getUser(getUserConfig().clientUserId); contacts.add(0, user); } @@ -1064,7 +1171,7 @@ public GroupCreateAdapter(Context ctx) { searchAdapterHelper.setAllowGlobalResults(false); searchAdapterHelper.setDelegate((searchId) -> { if (searchRunnable == null && !searchAdapterHelper.isSearchInProgress()) { - emptyView.showTextView(); + emptyView.showProgress(false); } notifyDataSetChanged(); }); @@ -1093,7 +1200,9 @@ public int getItemCount() { count += localServerCount + globalCount; return count; } else { - if (type == TYPE_FILTER) { + if (type == TYPE_PRIVATE) { + count = 3 + (doNotNewChats ? 0 : 1); + } else if (type == TYPE_FILTER) { if (noChatTypes) { count = 0; } else if (isInclude) { @@ -1129,7 +1238,7 @@ public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { switch (holder.getItemViewType()) { case 1: { GroupCreateUserCell cell = (GroupCreateUserCell) holder.itemView; - Object object; + Object object = null; CharSequence username = null; CharSequence name = null; if (searching) { @@ -1189,7 +1298,25 @@ public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { } else { if (position < usersStartRow) { int flag; - if (isInclude) { + if (type == TYPE_PRIVATE) { + if (position == 1) { + name = LocaleController.getString(R.string.FilterExistingChats); + object = "existing_chats"; + flag = BusinessRecipientsHelper.PRIVATE_FLAG_EXISTING_CHATS; + } else if (position == 2 && !doNotNewChats) { + name = LocaleController.getString(R.string.FilterNewChats); + object = "new_chats"; + flag = BusinessRecipientsHelper.PRIVATE_FLAG_NEW_CHATS; + } else if (position == 2 + (doNotNewChats ? 0 : 1)) { + name = LocaleController.getString(R.string.FilterContacts); + object = "contacts"; + flag = BusinessRecipientsHelper.PRIVATE_FLAG_CONTACTS; + } else { + name = LocaleController.getString(R.string.FilterNonContacts); + object = "non_contacts"; + flag = BusinessRecipientsHelper.PRIVATE_FLAG_NON_CONTACTS; + } + } else if (isInclude) { if (position == 1) { name = LocaleController.getString("FilterContacts", R.string.FilterContacts); object = "contacts"; @@ -1243,7 +1370,9 @@ public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { } boolean blueText = false; boolean enabled = true; - if (type == TYPE_FILTER) { + if (type == TYPE_PRIVATE) { + + } else if (type == TYPE_FILTER) { if (!searching) { StringBuilder builder = new StringBuilder(); ArrayList filters = getMessagesController().dialogFilters; @@ -1312,7 +1441,11 @@ public int getItemViewType(int position) { if (searching) { return 1; } else { - if (type == TYPE_FILTER) { + if (type == TYPE_PRIVATE) { + if (position == 0 || position == 4 + (doNotNewChats ? 0 : 1)) { + return 2; + } + } else if (type == TYPE_FILTER) { if (noChatTypes) { if (position == 0) { return 2; @@ -1354,19 +1487,18 @@ public void searchDialogs(final String query) { Utilities.searchQueue.cancelRunnable(searchRunnable); searchRunnable = null; } - boolean allowSerachChats = true; - + final boolean allowBots = type != TYPE_PRIVATE; + final boolean allowChats = type != TYPE_PRIVATE; if (query == null) { searchResult.clear(); searchResultNames.clear(); searchAdapterHelper.mergeResults(null); - searchAdapterHelper.queryServerSearch(null, true, allowSerachChats, false, false, false, 0, false, 0, 0); + searchAdapterHelper.queryServerSearch(null, true, false, false, false, false, 0, false, 0, 0); notifyDataSetChanged(); } else { - boolean finalAllowSerachChats = allowSerachChats; Utilities.searchQueue.postRunnable(searchRunnable = () -> AndroidUtilities.runOnUIThread(() -> { - searchAdapterHelper.queryServerSearch(query, true, finalAllowSerachChats, true, type != TYPE_AUTO_DELETE_EXISTING_CHATS, false, 0, false, 0, 0); + searchAdapterHelper.queryServerSearch(query, true, allowChats, allowChats, allowSelf, false, 0, false, 0, 0); Utilities.searchQueue.postRunnable(searchRunnable = () -> { String search1 = query.trim().toLowerCase(); if (search1.length() == 0) { @@ -1398,13 +1530,18 @@ public void searchDialogs(final String query) { username = UserObject.getPublicUsername(user); if (UserObject.isReplyUser(user)) { names[2] = LocaleController.getString("RepliesTitle", R.string.RepliesTitle).toLowerCase(); - } else if (user.self) { + } else if (UserObject.isUserSelf(user)) { + if (!allowSelf) continue; names[2] = LocaleController.getString("SavedMessages", R.string.SavedMessages).toLowerCase(); + } else if (user.bot && !allowBots) { + continue; } } else { TLRPC.Chat chat = (TLRPC.Chat) object; names[0] = chat.title.toLowerCase(); username = chat.username; + if (!allowChats) + continue; } names[1] = LocaleController.getInstance().getTranslitString(names[0]); if (names[0].equals(names[1])) { @@ -1457,7 +1594,7 @@ private void updateSearchResults(final ArrayList users, final ArrayList< searchResultNames = names; searchAdapterHelper.mergeResults(searchResult); if (searching && !searchAdapterHelper.isSearchInProgress()) { - emptyView.showTextView(); + emptyView.showProgress(false); } notifyDataSetChanged(); }); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/VoIPFragment.java b/TMessagesProj/src/main/java/org/telegram/ui/VoIPFragment.java index e73083120cb..2345a032778 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/VoIPFragment.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/VoIPFragment.java @@ -1694,7 +1694,7 @@ private void updateViewState() { showAcceptDeclineView = true; lockOnScreen = false; acceptDeclineView.setRetryMod(false); - if (service != null && service.privateCall.video) { + if (service != null && service.privateCall != null && service.privateCall.video) { statusTextView.setText(LocaleController.getString("VoipInVideoCallBranding", R.string.VoipInVideoCallBranding), false, animated); acceptDeclineView.setTranslationY(-AndroidUtilities.dp(60)); } else { diff --git a/TMessagesProj/src/main/res/drawable-hdpi/filled_folder_existing.png b/TMessagesProj/src/main/res/drawable-hdpi/filled_folder_existing.png new file mode 100644 index 00000000000..87c692151a0 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/filled_folder_existing.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/filled_folder_new.png b/TMessagesProj/src/main/res/drawable-hdpi/filled_folder_new.png new file mode 100644 index 00000000000..4b92769bc11 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/filled_folder_new.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/filled_location.png b/TMessagesProj/src/main/res/drawable-hdpi/filled_location.png new file mode 100644 index 00000000000..2c092306f67 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/filled_location.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/filled_premium_away.png b/TMessagesProj/src/main/res/drawable-hdpi/filled_premium_away.png new file mode 100644 index 00000000000..78eb9ed9199 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/filled_premium_away.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/filled_premium_bots.png b/TMessagesProj/src/main/res/drawable-hdpi/filled_premium_bots.png new file mode 100644 index 00000000000..652f2b0448b Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/filled_premium_bots.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/filled_premium_business.png b/TMessagesProj/src/main/res/drawable-hdpi/filled_premium_business.png new file mode 100644 index 00000000000..3fccf28a9bf Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/filled_premium_business.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/filled_premium_camera.png b/TMessagesProj/src/main/res/drawable-hdpi/filled_premium_camera.png new file mode 100644 index 00000000000..6ee3fd6da18 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/filled_premium_camera.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/filled_premium_hours.png b/TMessagesProj/src/main/res/drawable-hdpi/filled_premium_hours.png new file mode 100644 index 00000000000..c656392ab94 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/filled_premium_hours.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/filled_premium_status2.png b/TMessagesProj/src/main/res/drawable-hdpi/filled_premium_status2.png new file mode 100644 index 00000000000..aa3d81e7874 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/filled_premium_status2.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/large_away.png b/TMessagesProj/src/main/res/drawable-hdpi/large_away.png new file mode 100644 index 00000000000..11670c24ef4 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/large_away.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/large_greeting.png b/TMessagesProj/src/main/res/drawable-hdpi/large_greeting.png new file mode 100644 index 00000000000..ef9eedeef69 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/large_greeting.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/large_quickreplies.png b/TMessagesProj/src/main/res/drawable-hdpi/large_quickreplies.png new file mode 100644 index 00000000000..e8b8376db17 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/large_quickreplies.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/menu_premium_away.png b/TMessagesProj/src/main/res/drawable-hdpi/menu_premium_away.png new file mode 100644 index 00000000000..330a75825d1 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/menu_premium_away.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/menu_premium_chatbot.png b/TMessagesProj/src/main/res/drawable-hdpi/menu_premium_chatbot.png new file mode 100644 index 00000000000..6d6364f54e5 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/menu_premium_chatbot.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/menu_premium_clock.png b/TMessagesProj/src/main/res/drawable-hdpi/menu_premium_clock.png new file mode 100644 index 00000000000..9badea245ce Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/menu_premium_clock.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/menu_premium_clock_add.png b/TMessagesProj/src/main/res/drawable-hdpi/menu_premium_clock_add.png new file mode 100644 index 00000000000..3d4fdf421c2 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/menu_premium_clock_add.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/menu_premium_location.png b/TMessagesProj/src/main/res/drawable-hdpi/menu_premium_location.png new file mode 100644 index 00000000000..f2b6ba7c7be Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/menu_premium_location.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/menu_quickreply.png b/TMessagesProj/src/main/res/drawable-hdpi/menu_quickreply.png new file mode 100644 index 00000000000..455501bb63c Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/menu_quickreply.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/menu_shop.png b/TMessagesProj/src/main/res/drawable-hdpi/menu_shop.png new file mode 100644 index 00000000000..42e9c69887c Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/menu_shop.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/filled_folder_existing.png b/TMessagesProj/src/main/res/drawable-mdpi/filled_folder_existing.png new file mode 100644 index 00000000000..3c40e827710 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/filled_folder_existing.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/filled_folder_new.png b/TMessagesProj/src/main/res/drawable-mdpi/filled_folder_new.png new file mode 100644 index 00000000000..6d4f8317e94 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/filled_folder_new.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/filled_location.png b/TMessagesProj/src/main/res/drawable-mdpi/filled_location.png new file mode 100644 index 00000000000..ff30bb05cd6 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/filled_location.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/filled_premium_away.png b/TMessagesProj/src/main/res/drawable-mdpi/filled_premium_away.png new file mode 100644 index 00000000000..fa9e9900115 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/filled_premium_away.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/filled_premium_bots.png b/TMessagesProj/src/main/res/drawable-mdpi/filled_premium_bots.png new file mode 100644 index 00000000000..39e22ddaf88 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/filled_premium_bots.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/filled_premium_business.png b/TMessagesProj/src/main/res/drawable-mdpi/filled_premium_business.png new file mode 100644 index 00000000000..d87952934f3 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/filled_premium_business.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/filled_premium_camera.png b/TMessagesProj/src/main/res/drawable-mdpi/filled_premium_camera.png new file mode 100644 index 00000000000..2556dfca9eb Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/filled_premium_camera.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/filled_premium_hours.png b/TMessagesProj/src/main/res/drawable-mdpi/filled_premium_hours.png new file mode 100644 index 00000000000..5dd91533edd Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/filled_premium_hours.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/filled_premium_status2.png b/TMessagesProj/src/main/res/drawable-mdpi/filled_premium_status2.png new file mode 100644 index 00000000000..1262a863fd6 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/filled_premium_status2.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/large_away.png b/TMessagesProj/src/main/res/drawable-mdpi/large_away.png new file mode 100644 index 00000000000..24f2a4377ae Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/large_away.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/large_greeting.png b/TMessagesProj/src/main/res/drawable-mdpi/large_greeting.png new file mode 100644 index 00000000000..1bc565149dc Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/large_greeting.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/large_quickreplies.png b/TMessagesProj/src/main/res/drawable-mdpi/large_quickreplies.png new file mode 100644 index 00000000000..a4d1f4fe053 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/large_quickreplies.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/menu_premium_away.png b/TMessagesProj/src/main/res/drawable-mdpi/menu_premium_away.png new file mode 100644 index 00000000000..079d76e59aa Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/menu_premium_away.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/menu_premium_chatbot.png b/TMessagesProj/src/main/res/drawable-mdpi/menu_premium_chatbot.png new file mode 100644 index 00000000000..3e589d811c1 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/menu_premium_chatbot.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/menu_premium_clock.png b/TMessagesProj/src/main/res/drawable-mdpi/menu_premium_clock.png new file mode 100644 index 00000000000..bd30b23993f Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/menu_premium_clock.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/menu_premium_clock_add.png b/TMessagesProj/src/main/res/drawable-mdpi/menu_premium_clock_add.png new file mode 100644 index 00000000000..43be994a914 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/menu_premium_clock_add.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/menu_premium_location.png b/TMessagesProj/src/main/res/drawable-mdpi/menu_premium_location.png new file mode 100644 index 00000000000..da5b2418cdb Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/menu_premium_location.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/menu_quickreply.png b/TMessagesProj/src/main/res/drawable-mdpi/menu_quickreply.png new file mode 100644 index 00000000000..60d540bb0e9 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/menu_quickreply.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/menu_shop.png b/TMessagesProj/src/main/res/drawable-mdpi/menu_shop.png new file mode 100644 index 00000000000..d36fb3e83df Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/menu_shop.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/filled_folder_existing.png b/TMessagesProj/src/main/res/drawable-xhdpi/filled_folder_existing.png new file mode 100644 index 00000000000..7ef56b76878 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/filled_folder_existing.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/filled_folder_new.png b/TMessagesProj/src/main/res/drawable-xhdpi/filled_folder_new.png new file mode 100644 index 00000000000..292add32ec4 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/filled_folder_new.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/filled_location.png b/TMessagesProj/src/main/res/drawable-xhdpi/filled_location.png new file mode 100644 index 00000000000..78e72960095 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/filled_location.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/filled_premium_away.png b/TMessagesProj/src/main/res/drawable-xhdpi/filled_premium_away.png new file mode 100644 index 00000000000..b6aa4d287db Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/filled_premium_away.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/filled_premium_bots.png b/TMessagesProj/src/main/res/drawable-xhdpi/filled_premium_bots.png new file mode 100644 index 00000000000..35db556567e Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/filled_premium_bots.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/filled_premium_business.png b/TMessagesProj/src/main/res/drawable-xhdpi/filled_premium_business.png new file mode 100644 index 00000000000..14d09c01f2c Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/filled_premium_business.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/filled_premium_camera.png b/TMessagesProj/src/main/res/drawable-xhdpi/filled_premium_camera.png new file mode 100644 index 00000000000..b4ccdb5f9ad Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/filled_premium_camera.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/filled_premium_hours.png b/TMessagesProj/src/main/res/drawable-xhdpi/filled_premium_hours.png new file mode 100644 index 00000000000..afb707b47a1 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/filled_premium_hours.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/filled_premium_status2.png b/TMessagesProj/src/main/res/drawable-xhdpi/filled_premium_status2.png new file mode 100644 index 00000000000..fd8d8a63454 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/filled_premium_status2.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/large_away.png b/TMessagesProj/src/main/res/drawable-xhdpi/large_away.png new file mode 100644 index 00000000000..192a2533362 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/large_away.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/large_greeting.png b/TMessagesProj/src/main/res/drawable-xhdpi/large_greeting.png new file mode 100644 index 00000000000..0aa1c386f00 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/large_greeting.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/large_quickreplies.png b/TMessagesProj/src/main/res/drawable-xhdpi/large_quickreplies.png new file mode 100644 index 00000000000..0de6883ccaf Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/large_quickreplies.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/menu_premium_away.png b/TMessagesProj/src/main/res/drawable-xhdpi/menu_premium_away.png new file mode 100644 index 00000000000..2a9735b35b1 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/menu_premium_away.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/menu_premium_chatbot.png b/TMessagesProj/src/main/res/drawable-xhdpi/menu_premium_chatbot.png new file mode 100644 index 00000000000..ee5c89c74f3 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/menu_premium_chatbot.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/menu_premium_clock.png b/TMessagesProj/src/main/res/drawable-xhdpi/menu_premium_clock.png new file mode 100644 index 00000000000..36c87ddf65e Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/menu_premium_clock.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/menu_premium_clock_add.png b/TMessagesProj/src/main/res/drawable-xhdpi/menu_premium_clock_add.png new file mode 100644 index 00000000000..d8975f62df8 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/menu_premium_clock_add.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/menu_premium_location.png b/TMessagesProj/src/main/res/drawable-xhdpi/menu_premium_location.png new file mode 100644 index 00000000000..09ee1ecf429 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/menu_premium_location.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/menu_quickreply.png b/TMessagesProj/src/main/res/drawable-xhdpi/menu_quickreply.png new file mode 100644 index 00000000000..ff397676a2b Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/menu_quickreply.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/menu_shop.png b/TMessagesProj/src/main/res/drawable-xhdpi/menu_shop.png new file mode 100644 index 00000000000..bc4ecf134a0 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/menu_shop.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/filled_folder_existing.png b/TMessagesProj/src/main/res/drawable-xxhdpi/filled_folder_existing.png new file mode 100644 index 00000000000..61491a2996c Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/filled_folder_existing.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/filled_folder_new.png b/TMessagesProj/src/main/res/drawable-xxhdpi/filled_folder_new.png new file mode 100644 index 00000000000..40cbc38014d Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/filled_folder_new.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/filled_location.png b/TMessagesProj/src/main/res/drawable-xxhdpi/filled_location.png new file mode 100644 index 00000000000..ee24c2be680 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/filled_location.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/filled_premium_away.png b/TMessagesProj/src/main/res/drawable-xxhdpi/filled_premium_away.png new file mode 100644 index 00000000000..f1a67cc6e05 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/filled_premium_away.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/filled_premium_bots.png b/TMessagesProj/src/main/res/drawable-xxhdpi/filled_premium_bots.png new file mode 100644 index 00000000000..fc6e346e61d Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/filled_premium_bots.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/filled_premium_business.png b/TMessagesProj/src/main/res/drawable-xxhdpi/filled_premium_business.png new file mode 100644 index 00000000000..43ed7722614 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/filled_premium_business.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/filled_premium_camera.png b/TMessagesProj/src/main/res/drawable-xxhdpi/filled_premium_camera.png new file mode 100644 index 00000000000..8c86e3de472 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/filled_premium_camera.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/filled_premium_hours.png b/TMessagesProj/src/main/res/drawable-xxhdpi/filled_premium_hours.png new file mode 100644 index 00000000000..30111ce5ac3 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/filled_premium_hours.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/filled_premium_status2.png b/TMessagesProj/src/main/res/drawable-xxhdpi/filled_premium_status2.png new file mode 100644 index 00000000000..d2957e82ada Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/filled_premium_status2.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/large_away.png b/TMessagesProj/src/main/res/drawable-xxhdpi/large_away.png new file mode 100644 index 00000000000..efc26f796b6 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/large_away.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/large_greeting.png b/TMessagesProj/src/main/res/drawable-xxhdpi/large_greeting.png new file mode 100644 index 00000000000..632b4d16166 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/large_greeting.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/large_quickreplies.png b/TMessagesProj/src/main/res/drawable-xxhdpi/large_quickreplies.png new file mode 100644 index 00000000000..50aa4ca7ef3 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/large_quickreplies.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/menu_premium_away.png b/TMessagesProj/src/main/res/drawable-xxhdpi/menu_premium_away.png new file mode 100644 index 00000000000..d4452b745ae Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/menu_premium_away.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/menu_premium_chatbot.png b/TMessagesProj/src/main/res/drawable-xxhdpi/menu_premium_chatbot.png new file mode 100644 index 00000000000..25c089d7c81 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/menu_premium_chatbot.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/menu_premium_clock.png b/TMessagesProj/src/main/res/drawable-xxhdpi/menu_premium_clock.png new file mode 100644 index 00000000000..1ce65744065 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/menu_premium_clock.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/menu_premium_clock_add.png b/TMessagesProj/src/main/res/drawable-xxhdpi/menu_premium_clock_add.png new file mode 100644 index 00000000000..5a039d2c00a Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/menu_premium_clock_add.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/menu_premium_location.png b/TMessagesProj/src/main/res/drawable-xxhdpi/menu_premium_location.png new file mode 100644 index 00000000000..3c437fb8856 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/menu_premium_location.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/menu_quickreply.png b/TMessagesProj/src/main/res/drawable-xxhdpi/menu_quickreply.png new file mode 100644 index 00000000000..731ff529a61 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/menu_quickreply.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/menu_shop.png b/TMessagesProj/src/main/res/drawable-xxhdpi/menu_shop.png new file mode 100644 index 00000000000..29e341e209c Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/menu_shop.png differ diff --git a/TMessagesProj/src/main/res/raw/biz_clock.json b/TMessagesProj/src/main/res/raw/biz_clock.json new file mode 100644 index 00000000000..762ca468714 --- /dev/null +++ b/TMessagesProj/src/main/res/raw/biz_clock.json @@ -0,0 +1 @@ +{"tgs":1,"v":"5.5.2","fr":60,"ip":0,"op":180,"w":512,"h":512,"nm":"Alarm Clock MAIN","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":3,"nm":"NULL MOVE","sr":1,"ks":{"o":{"a":0,"k":0},"r":{"a":1,"k":[{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":5,"s":[0]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":9,"s":[0.7]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":13,"s":[-0.8]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":17,"s":[1]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":21,"s":[-1]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":25,"s":[1]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":29,"s":[0]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":33,"s":[1.5]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":37,"s":[-1.5]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":41,"s":[1.5]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":45,"s":[-1.5]},{"i":{"x":[0.41],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":49,"s":[3]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":56,"s":[-4.5]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":64,"s":[2]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":68,"s":[-2]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":72,"s":[2]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":76,"s":[-2.5]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":80,"s":[2]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":84,"s":[-2]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":88,"s":[2]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":92,"s":[-2]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":96,"s":[2]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.48],"y":[0]},"t":100,"s":[-4]},{"i":{"x":[0.6],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":108,"s":[5]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.5],"y":[0]},"t":114,"s":[-2.5]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":119,"s":[3]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":123,"s":[-1.5]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":127,"s":[2]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":131,"s":[-1]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":135,"s":[2]},{"i":{"x":[0.5],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":138,"s":[-2]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.6],"y":[0]},"t":144,"s":[4]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":151,"s":[-3.5]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":157,"s":[1.7]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":162,"s":[-0.8]},{"i":{"x":[0.5],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":169,"s":[0.5]},{"t":179,"s":[0]}]},"p":{"a":1,"k":[{"i":{"x":0.7,"y":1},"o":{"x":0.3,"y":0},"t":31,"s":[256,462,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.7,"y":1},"o":{"x":0.3,"y":0},"t":35,"s":[256,458,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.7,"y":1},"o":{"x":0.3,"y":0},"t":39,"s":[256,463,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,455,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.2,"y":1},"o":{"x":0.3,"y":0},"t":48,"s":[256,462,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.9,"y":1},"o":{"x":0.8,"y":0},"t":52,"s":[256,434,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.4,"y":1},"o":{"x":0.1,"y":0},"t":57,"s":[256,462,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.7,"y":1},"o":{"x":0.6,"y":0},"t":61,"s":[256,447,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.7,"y":1},"o":{"x":0.3,"y":0},"t":65,"s":[256,462,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.7,"y":1},"o":{"x":0.3,"y":0},"t":69,"s":[256,456,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.4,"y":1},"o":{"x":0.302,"y":0},"t":73,"s":[256,462,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.701,"y":1},"o":{"x":0.6,"y":0},"t":77,"s":[256,448,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.7,"y":1},"o":{"x":0.3,"y":0},"t":82,"s":[256,462,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.7,"y":1},"o":{"x":0.3,"y":0},"t":86,"s":[256,458,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.7,"y":1},"o":{"x":0.3,"y":0},"t":90,"s":[256,463,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.7,"y":1},"o":{"x":0.3,"y":0},"t":94,"s":[256,455,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.2,"y":1},"o":{"x":0.3,"y":0},"t":99,"s":[256,468,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.9,"y":1},"o":{"x":0.8,"y":0},"t":103,"s":[256,433,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.4,"y":1},"o":{"x":0.1,"y":0},"t":109,"s":[256,464,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.7,"y":1},"o":{"x":0.6,"y":0},"t":113,"s":[256,447,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.7,"y":1},"o":{"x":0.3,"y":0},"t":117,"s":[256,464,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.7,"y":1},"o":{"x":0.3,"y":0},"t":121,"s":[256,454,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.4,"y":1},"o":{"x":0.3,"y":0},"t":125,"s":[256,462,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.7,"y":1},"o":{"x":0.6,"y":0},"t":128,"s":[256,446,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.7,"y":1},"o":{"x":0.3,"y":0},"t":132,"s":[256,462,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.2,"y":1},"o":{"x":0.3,"y":0},"t":137,"s":[256,466,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.9,"y":1},"o":{"x":0.8,"y":0},"t":142,"s":[256,433,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.4,"y":1},"o":{"x":0.1,"y":0},"t":148,"s":[256,468,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.7,"y":1},"o":{"x":0.3,"y":0},"t":154,"s":[256,445,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.7,"y":1},"o":{"x":0.3,"y":0},"t":160,"s":[256,462,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.7,"y":1},"o":{"x":0.3,"y":0},"t":165,"s":[256,456,0],"to":[0,0,0],"ti":[0,0,0]},{"t":171,"s":[256,462,0]}]},"s":{"a":1,"k":[{"i":{"x":[0.2,0.2,0.2],"y":[1,1,1]},"o":{"x":[0.3,0.3,0.3],"y":[0,0,0]},"t":137,"s":[100,100,100]},{"i":{"x":[0.9,0.9,0.9],"y":[1,1,1]},"o":{"x":[0.8,0.8,0.8],"y":[0,0,0]},"t":142,"s":[100,98,100]},{"t":148,"s":[100,100,100]}]}},"ao":0,"ip":0,"op":180,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"Glass","parent":7,"sr":1,"ks":{"p":{"a":0,"k":[202.443,202.443,0]},"a":{"a":0,"k":[187.443,187.443,0]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[92.329,0],[0,92.329],[-92.329,0],[0,-92.329]],"o":[[-92.329,0],[0,-92.329],[92.329,0],[0,92.329]],"v":[[0,167.443],[-167.443,0.001],[0,-167.443],[167.443,0.001]],"c":true}},"nm":"Path 1","hd":false},{"ty":"tm","s":{"a":0,"k":0},"e":{"a":0,"k":45},"o":{"a":0,"k":-93},"m":1,"nm":"Trim Paths 1","hd":false},{"ty":"st","c":{"a":0,"k":[0.721568644047,0.1882353127,0.200000017881,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":[187.443,187.443]},"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":[[92.329,0],[0,92.329],[-92.329,0],[0,-92.329]],"o":[[-92.329,0],[0,-92.329],[92.329,0],[0,92.329]],"v":[[0,167.443],[-167.443,0.001],[0,-167.443],[167.443,0.001]],"c":true}},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":0,"k":[0.450980424881,0.054901964962,0.054901964962,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":[187.443,187.443]},"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":[[11.984,4.748],[0.834,86.797],[-50.154,15.722],[-4.667,-102.649]],"o":[[-44.165,-17.497],[-0.834,-86.797],[9.347,-2.93],[5.257,115.631]],"v":[[-59.331,155.711],[-167.671,-0.933],[-53.408,-157.551],[-149.806,-0.29]],"c":true}},"nm":"Path 1","hd":false},{"ty":"gf","o":{"a":0,"k":90},"r":1,"bm":0,"g":{"p":3,"k":{"a":0,"k":[0,1,1,1,0.5,1,1,1,1,1,1,1,0,1,0.5,0.5,1,0]}},"s":{"a":0,"k":[-169.909,18.984]},"e":{"a":0,"k":[-78.981,-121.54]},"t":2,"h":{"a":0,"k":0},"a":{"a":0,"k":0},"nm":"Gradient_qShtS32uJO","hd":false},{"ty":"tr","p":{"a":0,"k":[187.443,187.443]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":45},"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":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[25.839,8.925],[0,92.329],[-46.286,12.179],[0.878,-87.029]],"o":[[-41.602,-14.37],[0,-92.329],[10.124,-2.664],[-0.899,89.129]],"v":[[-60.457,155.069],[-167.443,0.001],[-53.033,-157.544],[-46.103,-4.242]],"c":true}},"nm":"Path 1","hd":false},{"ty":"gf","o":{"a":0,"k":60},"r":1,"bm":0,"g":{"p":3,"k":{"a":0,"k":[0,1,1,1,0.5,1,1,1,1,1,1,1,0,0,0.5,0.5,1,1]}},"s":{"a":0,"k":[-103.945,-5.719]},"e":{"a":0,"k":[-157.501,-1.567]},"t":1,"nm":"Gradient_WQtdHRVtaR","hd":false},{"ty":"gf","o":{"a":0,"k":30},"r":1,"bm":0,"g":{"p":3,"k":{"a":0,"k":[0,1,1,1,0.5,1,1,1,1,1,1,1,0,0,0.36,0,0.72,0,0.786,0.1,0.853,0.2,0.926,0.6,1,1]}},"s":{"a":0,"k":[0,0]},"e":{"a":0,"k":[171.303,-2.061]},"t":2,"h":{"a":0,"k":0},"a":{"a":0,"k":0},"nm":"Gradient_AH28nDjitv","hd":false},{"ty":"tr","p":{"a":0,"k":[187.443,187.443]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":45},"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":[[35.739,-0.267],[0,92.329],[-92.329,0],[0,-92.329]],"o":[[-92.326,0.69],[0,-92.329],[92.329,0],[0,92.329]],"v":[[0,167.443],[-167.443,0.001],[0,-167.443],[0.212,0.354]],"c":true}},"nm":"Path 1","hd":false},{"ty":"gf","o":{"a":0,"k":20},"r":1,"bm":0,"g":{"p":3,"k":{"a":0,"k":[0,1,1,1,0.5,1,1,1,1,1,1,1,0,0,0.36,0,0.72,0,0.786,0.1,0.853,0.2,0.926,0.6,1,1]}},"s":{"a":0,"k":[0,0]},"e":{"a":0,"k":[172.01,0.061]},"t":2,"h":{"a":0,"k":0},"a":{"a":0,"k":0},"nm":"Gradient_hl21lXptt4","hd":false},{"ty":"tr","p":{"a":0,"k":[187.443,187.443]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":45},"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":[[34.697,-8.57],[0,92.329],[-119.825,-33.783],[-2.657,-89.15]],"o":[[-116.289,28.724],[0,-92.329],[74.332,20.957],[2.751,92.288]],"v":[[37.83,161.434],[-167.443,0.001],[46.316,-160.019],[55.013,9.193]],"c":true}},"nm":"Path 1","hd":false},{"ty":"gf","o":{"a":0,"k":10},"r":1,"bm":0,"g":{"p":3,"k":{"a":0,"k":[0,1,1,1,0.5,1,1,1,1,1,1,1,0,0,0.36,0,0.72,0,0.786,0.1,0.853,0.2,0.926,0.6,1,1]}},"s":{"a":0,"k":[0,0]},"e":{"a":0,"k":[172.01,0.768]},"t":2,"h":{"a":0,"k":0},"a":{"a":0,"k":0},"nm":"Gradient_78ttC2H5X9","hd":false},{"ty":"tr","p":{"a":0,"k":[187.443,187.443]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":45},"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":[[11.984,4.748],[0.834,86.797],[-50.154,15.722],[-4.667,-102.649]],"o":[[-44.165,-17.497],[-0.834,-86.797],[9.347,-2.93],[5.257,115.631]],"v":[[-59.331,155.711],[-167.671,-0.933],[-53.408,-157.551],[-149.806,-0.29]],"c":true}},"nm":"Path 1","hd":false},{"ty":"gf","o":{"a":0,"k":90},"r":1,"bm":0,"g":{"p":3,"k":{"a":0,"k":[0,0.682,0.674,0.674,0.5,0.682,0.674,0.674,1,0.682,0.675,0.675,0,1,0.5,0.5,1,0]}},"s":{"a":0,"k":[-169.909,18.984]},"e":{"a":0,"k":[-78.981,-121.54]},"t":2,"h":{"a":0,"k":0},"a":{"a":0,"k":0},"nm":"Gradient_8uKRT9GufW","hd":false},{"ty":"tr","p":{"a":0,"k":[187.443,187.443]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":224},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Group 8","bm":0,"hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[92.329,0],[0,92.329],[-92.329,0],[0,-92.329]],"o":[[-92.329,0],[0,-92.329],[92.329,0],[0,92.329]],"v":[[0,167.443],[-167.443,0.001],[0,-167.443],[167.443,0.001]],"c":true}},"nm":"Path 1","hd":false},{"ty":"gf","o":{"a":0,"k":60},"r":1,"bm":0,"g":{"p":3,"k":{"a":0,"k":[0,0.616,0.596,0.6,0.5,0.616,0.596,0.6,1,0.616,0.596,0.6,0,1,0.5,0.5,1,0]}},"s":{"a":0,"k":[180.305,-32.067]},"e":{"a":0,"k":[122.427,-21.078]},"t":1,"nm":"Gradient_DmelAXQb63","hd":false},{"ty":"gf","o":{"a":0,"k":100},"r":1,"bm":0,"g":{"p":3,"k":{"a":0,"k":[0,0.678,0.662,0.666,0.5,0.678,0.663,0.667,1,0.678,0.663,0.667,0,0,0.36,0,0.72,0,0.786,0.1,0.853,0.2,0.926,0.6,1,1]}},"s":{"a":0,"k":[0,0]},"e":{"a":0,"k":[170.95,-1]},"t":2,"h":{"a":0,"k":0},"a":{"a":0,"k":0},"nm":"Gradient_xSFTmSMFMB","hd":false},{"ty":"tr","p":{"a":0,"k":[187.443,187.443]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":45},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Group 4","bm":0,"hd":false}],"ip":0,"op":180.18018018018,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"Arrows","parent":7,"sr":1,"ks":{"p":{"a":0,"k":[202.4,203.062,0]},"a":{"a":0,"k":[69.896,88.99,0]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[0,-3.375],[0.031,3.281]],"o":[[0,3.375],[-0.031,-3.281]],"v":[[2.625,0],[-2.625,0]],"c":true}},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.262745112181,0.262745112181,0.262745112181,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"st","c":{"a":0,"k":[0.678431391716,0.517647087574,0.301960796118,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":6},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"tr","p":{"a":0,"k":[69.874,89.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":"Ellipse 2","bm":0,"hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[69.939,63.354],[69.939,248.792]],"c":false}},"nm":"Path 1","hd":false},{"ty":"tm","s":{"a":0,"k":0},"e":{"a":0,"k":42},"o":{"a":0,"k":0},"m":1,"nm":"Trim Paths 1","hd":false},{"ty":"st","c":{"a":0,"k":[0.850980460644,0.737254917622,0.552941203117,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":[69.906,88.969]},"a":{"a":0,"k":[69.906,88.969]},"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 10","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":[[69.939,63.354],[69.939,248.792]],"c":false}},"nm":"Path 1","hd":false},{"ty":"tm","s":{"a":0,"k":0},"e":{"a":0,"k":65},"o":{"a":0,"k":0},"m":1,"nm":"Trim Paths 1","hd":false},{"ty":"st","c":{"a":0,"k":[0.850980460644,0.700207650661,0.552941203117,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":4.5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"tr","p":{"a":0,"k":[69.906,88.969]},"a":{"a":0,"k":[69.906,88.969]},"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 11","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":[[69.939,63.354],[69.939,248.792]],"c":false}},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":0,"k":[0.815686285496,0.586993038654,0.486212998629,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":3},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"tr","p":{"a":0,"k":[69.906,88.969]},"a":{"a":0,"k":[69.906,88.969]},"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":"tr","p":{"a":0,"k":[69.906,88.969]},"a":{"a":0,"k":[69.906,88.969]},"s":{"a":0,"k":[100,100]},"r":{"a":1,"k":[{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.118],"y":[0]},"t":0,"s":[0]},{"t":170,"s":[360]}]},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"sec","bm":0,"hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[69.948,88.905],[69.99,168.394]],"c":false}},"nm":"Path 1","hd":false},{"ty":"tm","s":{"a":0,"k":32},"e":{"a":0,"k":100},"o":{"a":0,"k":0},"m":1,"nm":"Trim Paths 1","hd":false},{"ty":"st","c":{"a":0,"k":[0.352941185236,0.35686275363,0.352941185236,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":4},"lc":2,"lj":2,"bm":0,"nm":"Stroke 2","hd":false},{"ty":"st","c":{"a":0,"k":[0.262745112181,0.262745112181,0.262745112181,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":12},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"tr","p":{"a":0,"k":[69.906,88.969]},"a":{"a":0,"k":[69.906,88.969]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":124},"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":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[69.948,88.905],[69.99,168.394]],"c":false}},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":0,"k":[0.262745112181,0.262745112181,0.262745112181,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":[69.906,88.969]},"a":{"a":0,"k":[69.906,88.969]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":124},"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":"tr","p":{"a":0,"k":[69.943,89.05]},"a":{"a":0,"k":[69.943,89.05]},"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":"hour","bm":0,"hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[69.834,88.965],[69.441,234.06]],"c":false}},"nm":"Path 1","hd":false},{"ty":"tm","s":{"a":0,"k":17},"e":{"a":0,"k":100},"o":{"a":0,"k":0},"m":1,"nm":"Trim Paths 1","hd":false},{"ty":"st","c":{"a":0,"k":[0.352941185236,0.35686275363,0.352941185236,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":4},"lc":2,"lj":2,"bm":0,"nm":"Stroke 4","hd":false},{"ty":"st","c":{"a":0,"k":[0.262745112181,0.262745112181,0.262745112181,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":12},"lc":2,"lj":2,"bm":0,"nm":"Stroke 3","hd":false},{"ty":"tr","p":{"a":0,"k":[69.906,88.969]},"a":{"a":0,"k":[69.906,88.969]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":-126},"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":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[69.834,88.965],[69.441,234.06]],"c":false}},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":0,"k":[0.262745112181,0.262745112181,0.262745112181,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":6},"lc":2,"lj":2,"bm":0,"nm":"Stroke 2","hd":false},{"ty":"tr","p":{"a":0,"k":[69.906,88.969]},"a":{"a":0,"k":[69.906,88.969]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":-126},"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":[69.909,89.046]},"a":{"a":0,"k":[69.909,89.046]},"s":{"a":0,"k":[100,100]},"r":{"a":1,"k":[{"i":{"x":[0.8],"y":[1]},"o":{"x":[0.6],"y":[0]},"t":0,"s":[0]},{"i":{"x":[0.4],"y":[1]},"o":{"x":[0.2],"y":[0]},"t":9,"s":[12]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":14,"s":[10]},{"i":{"x":[0.895],"y":[1]},"o":{"x":[1],"y":[0]},"t":56,"s":[10]},{"t":155,"s":[0]}]},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"minutes","bm":0,"hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[0,-3.375],[0.031,3.281]],"o":[[0,3.375],[-0.031,-3.281]],"v":[[2.625,0],[-2.625,0]],"c":true}},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":0,"k":[0.262745112181,0.262745112181,0.262745112181,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":12},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"tr","p":{"a":0,"k":[69.874,89.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":"Ellipse 3","bm":0,"hd":false}],"ip":0,"op":180.18018018018,"st":0,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"Shadow Arrows","parent":3,"sr":1,"ks":{"o":{"a":0,"k":10},"p":{"a":0,"k":[69.896,97.49,0]},"a":{"a":0,"k":[69.896,88.99,0]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[69.939,63.354],[69.939,248.792]],"c":false}},"nm":"Path 1","hd":false},{"ty":"tm","s":{"a":0,"k":0},"e":{"a":0,"k":100},"o":{"a":0,"k":0},"m":1,"nm":"Trim Paths 1","hd":false},{"ty":"st","c":{"a":0,"k":[0.262745112181,0.262745112181,0.262745112181,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":8.5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"tr","p":{"a":0,"k":[69.906,88.969]},"a":{"a":0,"k":[69.906,88.969]},"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 11","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":[[69.939,63.354],[69.939,248.792]],"c":false}},"nm":"Path 1","hd":false},{"ty":"tm","s":{"a":0,"k":0},"e":{"a":0,"k":42},"o":{"a":0,"k":0},"m":1,"nm":"Trim Paths 1","hd":false},{"ty":"st","c":{"a":0,"k":[0.266666680574,0.266666680574,0.266666680574,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":11},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"tr","p":{"a":0,"k":[69.906,88.969]},"a":{"a":0,"k":[69.906,88.969]},"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 10","bm":0,"hd":false},{"ty":"tr","p":{"a":0,"k":[69.906,88.969]},"a":{"a":0,"k":[69.906,88.969]},"s":{"a":0,"k":[100,100]},"r":{"a":1,"k":[{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.118],"y":[0]},"t":0,"s":[0]},{"t":170,"s":[360]}]},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"sec","bm":0,"hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[69.948,88.905],[69.99,168.394]],"c":false}},"nm":"Path 1","hd":false},{"ty":"tm","s":{"a":0,"k":32},"e":{"a":0,"k":100},"o":{"a":0,"k":0},"m":1,"nm":"Trim Paths 1","hd":false},{"ty":"st","c":{"a":0,"k":[0.262745112181,0.262745112181,0.262745112181,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":14},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"tr","p":{"a":0,"k":[69.906,88.969]},"a":{"a":0,"k":[69.906,88.969]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":124},"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":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[69.948,88.905],[69.99,168.394]],"c":false}},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":0,"k":[0.262745112181,0.262745112181,0.262745112181,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":[69.906,88.969]},"a":{"a":0,"k":[69.906,88.969]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":124},"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":"tr","p":{"a":0,"k":[69.943,89.05]},"a":{"a":0,"k":[69.943,89.05]},"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":"hour","bm":0,"hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[69.834,88.965],[69.441,234.06]],"c":false}},"nm":"Path 1","hd":false},{"ty":"tm","s":{"a":0,"k":17},"e":{"a":0,"k":100},"o":{"a":0,"k":0},"m":1,"nm":"Trim Paths 1","hd":false},{"ty":"st","c":{"a":0,"k":[0.262745112181,0.262745112181,0.262745112181,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":14},"lc":2,"lj":2,"bm":0,"nm":"Stroke 3","hd":false},{"ty":"tr","p":{"a":0,"k":[69.906,88.969]},"a":{"a":0,"k":[69.906,88.969]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":-126},"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":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[69.834,88.965],[69.441,234.06]],"c":false}},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":0,"k":[0.262745112181,0.262745112181,0.262745112181,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":8},"lc":2,"lj":2,"bm":0,"nm":"Stroke 2","hd":false},{"ty":"tr","p":{"a":0,"k":[69.906,88.969]},"a":{"a":0,"k":[69.906,88.969]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":-126},"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":[69.909,89.046]},"a":{"a":0,"k":[69.909,89.046]},"s":{"a":0,"k":[100,100]},"r":{"a":1,"k":[{"i":{"x":[0.8],"y":[1]},"o":{"x":[0.6],"y":[0]},"t":0,"s":[0]},{"i":{"x":[0.4],"y":[1]},"o":{"x":[0.2],"y":[0]},"t":9,"s":[12]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":14,"s":[10]},{"i":{"x":[0.895],"y":[1]},"o":{"x":[1],"y":[0]},"t":56,"s":[10]},{"t":155,"s":[0]}]},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"minutes","bm":0,"hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[0,-3.375],[0.031,3.281]],"o":[[0,3.375],[-0.031,-3.281]],"v":[[2.625,0],[-2.625,0]],"c":true}},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":0,"k":[0.262745112181,0.262745112181,0.262745112181,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":14},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"tr","p":{"a":0,"k":[69.874,89.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":"Ellipse 3","bm":0,"hd":false}],"ip":0,"op":180.18018018018,"st":0,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":"Clock Outlines","parent":7,"sr":1,"ks":{"p":{"a":0,"k":[202.442,202.441,0]},"a":{"a":0,"k":[161.44,161.445,0]}},"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":[[161.44,52],[161.44,4]],"c":false}},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":8,"s":[0.905882418156,0.349019616842,0.349019616842,1]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":83,"s":[0.806536018848,0.279388219118,0.279388219118,1]},{"t":107,"s":[0.905882418156,0.349019616842,0.349019616842,1]}]},"o":{"a":0,"k":100},"w":{"a":0,"k":10},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"st","c":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":45,"s":[1,1,1,1]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":92,"s":[0.566013216972,0.472787499428,0.472787499428,1]},{"t":107,"s":[1,1,1,1]}]},"o":{"a":0,"k":50},"w":{"a":0,"k":18},"lc":2,"lj":2,"bm":0,"nm":"Stroke 3","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":"12_chas","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":[[11.995,-20.78],[-11.995,20.78]],"c":false}},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":8,"s":[0.905882418156,0.349019616842,0.349019616842,1]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":83,"s":[0.806536018848,0.279388219118,0.279388219118,1]},{"t":107,"s":[0.905882418156,0.349019616842,0.349019616842,1]}]},"o":{"a":0,"k":100},"w":{"a":0,"k":10},"lc":2,"lj":2,"bm":0,"nm":"Stroke 2","hd":false},{"ty":"st","c":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":45,"s":[1,1,1,1]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":92,"s":[0.566013216972,0.472787499428,0.472787499428,1]},{"t":107,"s":[1,1,1,1]}]},"o":{"a":0,"k":50},"w":{"a":0,"k":18},"lc":2,"lj":2,"bm":0,"nm":"Stroke 3","hd":false},{"ty":"tr","p":{"a":0,"k":[228.425,46.07]},"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":"1_chas","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":[[20.78,-12],[-20.78,12]],"c":false}},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":8,"s":[0.905882418156,0.349019616842,0.349019616842,1]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":83,"s":[0.806536018848,0.279388219118,0.279388219118,1]},{"t":107,"s":[0.905882418156,0.349019616842,0.349019616842,1]}]},"o":{"a":0,"k":100},"w":{"a":0,"k":10},"lc":2,"lj":2,"bm":0,"nm":"Stroke 2","hd":false},{"ty":"st","c":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":45,"s":[1,1,1,1]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":92,"s":[0.566013216972,0.472787499428,0.472787499428,1]},{"t":107,"s":[1,1,1,1]}]},"o":{"a":0,"k":50},"w":{"a":0,"k":18},"lc":2,"lj":2,"bm":0,"nm":"Stroke 3","hd":false},{"ty":"tr","p":{"a":0,"k":[277.26,95.23]},"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":"2_chas","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":[[318.88,162.1],[270.87,162.1]],"c":false}},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":45,"s":[0.905882418156,0.349019616842,0.349019616842,1]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":92,"s":[0.759477198124,0.261101394892,0.261101394892,1]},{"t":107,"s":[0.905882418156,0.349019616842,0.349019616842,1]}]},"o":{"a":0,"k":100},"w":{"a":0,"k":10},"lc":2,"lj":2,"bm":0,"nm":"Stroke 2","hd":false},{"ty":"st","c":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":45,"s":[1,1,1,1]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":92,"s":[0.566013216972,0.472787499428,0.472787499428,1]},{"t":107,"s":[1,1,1,1]}]},"o":{"a":0,"k":50},"w":{"a":0,"k":18},"lc":2,"lj":2,"bm":0,"nm":"Stroke 3","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":"3_chas","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":[[20.645,12.22],[-20.645,-12.22]],"c":false}},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":45,"s":[0.905882418156,0.349019616842,0.349019616842,1]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":92,"s":[0.759477198124,0.261101394892,0.261101394892,1]},{"t":107,"s":[0.905882418156,0.349019616842,0.349019616842,1]}]},"o":{"a":0,"k":100},"w":{"a":0,"k":10},"lc":2,"lj":2,"bm":0,"nm":"Stroke 2","hd":false},{"ty":"st","c":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":45,"s":[1,1,1,1]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":92,"s":[0.566013216972,0.472787499428,0.472787499428,1]},{"t":107,"s":[1,1,1,1]}]},"o":{"a":0,"k":50},"w":{"a":0,"k":18},"lc":2,"lj":2,"bm":0,"nm":"Stroke 3","hd":false},{"ty":"tr","p":{"a":0,"k":[275.945,229.901]},"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":"4_chas","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":[[11.995,20.78],[-11.995,-20.78]],"c":false}},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":45,"s":[0.905882418156,0.349019616842,0.349019616842,1]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":92,"s":[0.759477198124,0.261101394892,0.261101394892,1]},{"t":107,"s":[0.905882418156,0.349019616842,0.349019616842,1]}]},"o":{"a":0,"k":100},"w":{"a":0,"k":10},"lc":2,"lj":2,"bm":0,"nm":"Stroke 2","hd":false},{"ty":"st","c":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":45,"s":[1,1,1,1]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":92,"s":[0.566013216972,0.472787499428,0.472787499428,1]},{"t":107,"s":[1,1,1,1]}]},"o":{"a":0,"k":50},"w":{"a":0,"k":18},"lc":2,"lj":2,"bm":0,"nm":"Stroke 3","hd":false},{"ty":"tr","p":{"a":0,"k":[227.866,277.15]},"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":"5_chas","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":[[161.44,318.89],[161.44,270.89]],"c":false}},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":45,"s":[0.905882418156,0.349019616842,0.349019616842,1]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":92,"s":[0.759477198124,0.261101394892,0.261101394892,1]},{"t":107,"s":[0.905882418156,0.349019616842,0.349019616842,1]}]},"o":{"a":0,"k":100},"w":{"a":0,"k":10},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"st","c":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":45,"s":[1,1,1,1]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":92,"s":[0.566013216972,0.472787499428,0.472787499428,1]},{"t":107,"s":[1,1,1,1]}]},"o":{"a":0,"k":50},"w":{"a":0,"k":18},"lc":2,"lj":2,"bm":0,"nm":"Stroke 3","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":"6_chas","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":[[11.995,-20.78],[-11.995,20.78]],"c":false}},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":45,"s":[0.905882418156,0.349019616842,0.349019616842,1]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":92,"s":[0.759477198124,0.261101394892,0.261101394892,1]},{"t":107,"s":[0.905882418156,0.349019616842,0.349019616842,1]}]},"o":{"a":0,"k":100},"w":{"a":0,"k":10},"lc":2,"lj":2,"bm":0,"nm":"Stroke 2","hd":false},{"ty":"st","c":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":45,"s":[1,1,1,1]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":92,"s":[0.566013216972,0.472787499428,0.472787499428,1]},{"t":107,"s":[1,1,1,1]}]},"o":{"a":0,"k":50},"w":{"a":0,"k":18},"lc":2,"lj":2,"bm":0,"nm":"Stroke 3","hd":false},{"ty":"tr","p":{"a":0,"k":[95.015,277.151]},"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":"7_chas","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":[[20.775,-12],[-20.775,12]],"c":false}},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":45,"s":[0.905882418156,0.349019616842,0.349019616842,1]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":92,"s":[0.759477198124,0.261101394892,0.261101394892,1]},{"t":107,"s":[0.905882418156,0.349019616842,0.349019616842,1]}]},"o":{"a":0,"k":100},"w":{"a":0,"k":10},"lc":2,"lj":2,"bm":0,"nm":"Stroke 2","hd":false},{"ty":"st","c":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":45,"s":[1,1,1,1]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":92,"s":[0.566013216972,0.472787499428,0.472787499428,1]},{"t":107,"s":[1,1,1,1]}]},"o":{"a":0,"k":50},"w":{"a":0,"k":18},"lc":2,"lj":2,"bm":0,"nm":"Stroke 3","hd":false},{"ty":"tr","p":{"a":0,"k":[46.185,228.64]},"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":"8_chas","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":[[52.01,162.1],[4,162.1]],"c":false}},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":45,"s":[0.905882418156,0.349019616842,0.349019616842,1]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":92,"s":[0.759477198124,0.261101394892,0.261101394892,1]},{"t":107,"s":[0.905882418156,0.349019616842,0.349019616842,1]}]},"o":{"a":0,"k":100},"w":{"a":0,"k":10},"lc":2,"lj":2,"bm":0,"nm":"Stroke 2","hd":false},{"ty":"st","c":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":45,"s":[1,1,1,1]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":92,"s":[0.566013216972,0.472787499428,0.472787499428,1]},{"t":107,"s":[1,1,1,1]}]},"o":{"a":0,"k":50},"w":{"a":0,"k":18},"lc":2,"lj":2,"bm":0,"nm":"Stroke 3","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":"9_chas","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":[[20.65,12.225],[-20.65,-12.225]],"c":false}},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":45,"s":[0.905882418156,0.349019616842,0.349019616842,1]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":92,"s":[0.759477198124,0.261101394892,0.261101394892,1]},{"t":107,"s":[0.905882418156,0.349019616842,0.349019616842,1]}]},"o":{"a":0,"k":100},"w":{"a":0,"k":10},"lc":2,"lj":2,"bm":0,"nm":"Stroke 2","hd":false},{"ty":"st","c":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":45,"s":[1,1,1,1]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":92,"s":[0.566013216972,0.472787499428,0.472787499428,1]},{"t":107,"s":[1,1,1,1]}]},"o":{"a":0,"k":50},"w":{"a":0,"k":18},"lc":2,"lj":2,"bm":0,"nm":"Stroke 3","hd":false},{"ty":"tr","p":{"a":0,"k":[46.36,93.955]},"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":"10_chas","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":[[11.995,20.78],[-11.995,-20.78]],"c":false}},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":45,"s":[0.905882418156,0.349019616842,0.349019616842,1]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":92,"s":[0.759477198124,0.261101394892,0.261101394892,1]},{"t":107,"s":[0.905882418156,0.349019616842,0.349019616842,1]}]},"o":{"a":0,"k":100},"w":{"a":0,"k":10},"lc":2,"lj":2,"bm":0,"nm":"Stroke 2","hd":false},{"ty":"st","c":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":45,"s":[1,1,1,1]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":92,"s":[0.566013216972,0.472787499428,0.472787499428,1]},{"t":107,"s":[1,1,1,1]}]},"o":{"a":0,"k":50},"w":{"a":0,"k":18},"lc":2,"lj":2,"bm":0,"nm":"Stroke 3","hd":false},{"ty":"tr","p":{"a":0,"k":[94.455,46.07]},"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":"11_chas","bm":0,"hd":false}],"ip":0,"op":180.18018018018,"st":0,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":"Screen","parent":7,"sr":1,"ks":{"p":{"a":0,"k":[202.443,202.443,0]},"a":{"a":0,"k":[187.443,187.443,0]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[92.329,0],[0,92.329],[-92.329,0],[0,-92.329]],"o":[[-92.329,0],[0,-92.329],[92.329,0],[0,92.329]],"v":[[0,167.443],[-167.443,0.001],[0,-167.443],[167.443,0.001]],"c":true}},"nm":"Path 1","hd":false},{"ty":"gf","o":{"a":0,"k":100},"r":1,"bm":0,"g":{"p":3,"k":{"a":1,"k":[{"i":{"x":0.1,"y":1},"o":{"x":0.15,"y":0},"t":45,"s":[0,0.925,0.922,0.922,0.75,0.882,0.867,0.867,1,0.839,0.813,0.813]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.5,"y":0},"t":92,"s":[0,0.817,0.783,0.783,0.75,0.754,0.714,0.714,1,0.692,0.644,0.644]},{"t":107,"s":[0,0.925,0.922,0.922,0.75,0.882,0.867,0.867,1,0.839,0.813,0.813]}]}},"s":{"a":0,"k":[0,0]},"e":{"a":0,"k":[166.5,0]},"t":2,"h":{"a":0,"k":0},"a":{"a":0,"k":0},"nm":"Gradient_HtITSMot26","hd":false},{"ty":"tr","p":{"a":0,"k":[187.443,187.443]},"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":180.18018018018,"st":0,"bm":0},{"ddd":0,"ind":7,"ty":4,"nm":"FRONT BODY","parent":1,"sr":1,"ks":{"p":{"a":1,"k":[{"i":{"x":0.1,"y":1},"o":{"x":0.15,"y":0},"t":45,"s":[-3.06,-197.983,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.5,"y":0},"t":92,"s":[21.935,-198.384,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0,"y":1},"o":{"x":0.095,"y":0.095},"t":104,"s":[-3.06,-197.983,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0,"y":1},"o":{"x":0.25,"y":0},"t":137,"s":[-33.047,-197.895,0],"to":[0,0,0],"ti":[0,0,0]},{"t":179,"s":[-3.06,-197.983,0]}]},"a":{"a":0,"k":[202.443,202.443,0]},"s":{"a":1,"k":[{"i":{"x":[0.1,0.1,0.1],"y":[1,1,1]},"o":{"x":[0.15,0.15,0.15],"y":[0,0,0]},"t":45,"s":[100,100,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,1,1]},"o":{"x":[0.5,0.5,0.5],"y":[0,0,0]},"t":92,"s":[88,100,100]},{"i":{"x":[0,0,0],"y":[1,1,1]},"o":{"x":[0.095,0.167,0.167],"y":[0.088,0,0]},"t":104,"s":[100,100,100]},{"i":{"x":[0,0,0],"y":[1,1,1]},"o":{"x":[0.25,0.25,0.25],"y":[0,0,0]},"t":137,"s":[87,100,100]},{"t":179,"s":[100,100,100]}]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[100.6,0],[0,100.599],[-100.6,0],[0,-100.6]],"o":[[-100.6,0],[0,-100.6],[100.6,0],[0,100.599]],"v":[[0,182.443],[-182.443,0.001],[0,-182.443],[182.443,0.001]],"c":true}},"nm":"Path 1","hd":false},{"ty":"tm","s":{"a":0,"k":0},"e":{"a":0,"k":8},"o":{"a":0,"k":167},"m":1,"nm":"Trim Paths 1","hd":false},{"ty":"st","c":{"a":0,"k":[0.941176474094,0.579469442368,0.597706735134,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":[202.443,202.443]},"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":[[100.6,0],[0,100.599],[-100.6,0],[0,-100.6]],"o":[[-100.6,0],[0,-100.6],[100.6,0],[0,100.599]],"v":[[0,182.443],[-182.443,0.001],[0,-182.443],[182.443,0.001]],"c":true}},"nm":"Path 1","hd":false},{"ty":"tm","s":{"a":0,"k":0},"e":{"a":0,"k":45},"o":{"a":0,"k":110},"m":1,"nm":"Trim Paths 1","hd":false},{"ty":"st","c":{"a":0,"k":[0.850980401039,0.390449821949,0.4136698246,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":[202.443,202.443]},"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":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[100.6,0],[0,100.599],[-100.6,0],[0,-100.6]],"o":[[-100.6,0],[0,-100.6],[100.6,0],[0,100.599]],"v":[[0,182.443],[-182.443,0.001],[0,-182.443],[182.443,0.001]],"c":true}},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":0,"k":[0.654901981354,0.233710110188,0.233710110188,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":6},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"tr","p":{"a":0,"k":[202.443,202.443]},"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.52,-2.884],[-61.042,-13.054],[0.834,4.278],[101.899,-2.452]],"o":[[-11.283,5.895],[104.176,22.279],[-12.395,-63.559],[-48.065,1.157]],"v":[[-60.564,-12.148],[47.917,-13.368],[186.007,117.225],[4.991,-27.244]],"c":true}},"nm":"Path 1","hd":false},{"ty":"gf","o":{"a":0,"k":100},"r":1,"bm":0,"g":{"p":3,"k":{"a":0,"k":[0,0.584,0.037,0.037,0.5,0.584,0.036,0.036,1,0.584,0.035,0.035,0,1,0.5,0.5,1,0]}},"s":{"a":0,"k":[41.933,-23.424]},"e":{"a":0,"k":[8.158,42.794]},"t":2,"h":{"a":0,"k":0.804},"a":{"a":0,"k":-564.188},"nm":"Gradient_K8KZZk4D59","hd":false},{"ty":"gf","o":{"a":0,"k":100},"r":1,"bm":0,"g":{"p":3,"k":{"a":0,"k":[0,0.584,0.037,0.037,0.5,0.584,0.036,0.036,1,0.584,0.035,0.035,0,1,0.5,0.5,1,0]}},"s":{"a":0,"k":[104.272,5.751]},"e":{"a":0,"k":[16.049,33.468]},"t":2,"h":{"a":0,"k":52.722},"a":{"a":0,"k":-505.133},"nm":"Gradient_H6UXEj3I3o","hd":false},{"ty":"tr","p":{"a":0,"k":[197.022,47.259]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0.662},"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":[[1.78,-5.968],[-31.401,3.669],[-0.032,4.359],[79.428,-3.295]],"o":[[-1.689,5.665],[81.921,-9.572],[0.05,-6.815],[-26.53,1.101]],"v":[[-57.523,-8.683],[-2.427,-21.287],[129.023,32.377],[-0.285,-29.433]],"c":true}},"nm":"Path 1","hd":false},{"ty":"gf","o":{"a":0,"k":100},"r":1,"bm":0,"g":{"p":3,"k":{"a":0,"k":[0,1,0.773,0.783,0.5,1,0.739,0.75,1,1,0.706,0.718,0,1,0.5,0.5,1,0]}},"s":{"a":0,"k":[56.044,-13.693]},"e":{"a":0,"k":[-43.051,25.15]},"t":2,"h":{"a":0,"k":56.614},"a":{"a":0,"k":-326.487},"nm":"Gradient_b8FsvTjRaB","hd":false},{"ty":"tr","p":{"a":0,"k":[60.022,160.759]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":-71.87},"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":[[100.6,0],[0,100.599],[-100.6,0],[0,-100.6]],"o":[[-100.6,0],[0,-100.6],[100.6,0],[0,100.599]],"v":[[0,182.443],[-182.443,0.001],[0,-182.443],[182.443,0.001]],"c":true}},"nm":"Path 1","hd":false},{"ty":"gf","o":{"a":0,"k":100},"r":1,"bm":0,"g":{"p":3,"k":{"a":0,"k":[0,0.875,0.298,0.259,0.5,0.875,0.298,0.258,1,0.875,0.299,0.257,0,1,0.71,0.5,1,0]}},"s":{"a":0,"k":[172,1.5]},"e":{"a":0,"k":[143.5,11]},"t":2,"h":{"a":0,"k":43.374},"a":{"a":0,"k":149.731},"nm":"Gradient_5Wfw06G5tk","hd":false},{"ty":"gf","o":{"a":0,"k":100},"r":1,"bm":0,"g":{"p":5,"k":{"a":0,"k":[0,0.824,0.271,0.302,0.234,0.796,0.229,0.235,0.468,0.769,0.188,0.169,0.563,0.62,0.153,0.145,1,0.471,0.118,0.122]}},"s":{"a":0,"k":[-1,-197]},"e":{"a":0,"k":[-1,190]},"t":1,"nm":"Gradient_RJTWjaVOTt","hd":false},{"ty":"tr","p":{"a":0,"k":[202.443,202.443]},"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":180.18018018018,"st":0,"bm":0},{"ddd":0,"ind":8,"ty":4,"nm":"Hummer Top","parent":18,"sr":1,"ks":{"o":{"a":1,"k":[{"t":30,"s":[100],"h":1},{"t":56,"s":[0],"h":1},{"t":97,"s":[100],"h":1}]},"r":{"a":1,"k":[{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":5,"s":[0]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":9,"s":[10]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":13,"s":[-11]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":17,"s":[12]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":21,"s":[-15]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":25,"s":[17]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":29,"s":[-22]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":33,"s":[25]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":37,"s":[-23]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":41,"s":[24]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":45,"s":[-24]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":49,"s":[22]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":53,"s":[0]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":56,"s":[30]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":60,"s":[-23]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":64,"s":[29]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":68,"s":[-22]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":72,"s":[34]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":76,"s":[-20]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":80,"s":[35]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":84,"s":[-20]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":88,"s":[29]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":92,"s":[-20]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":96,"s":[31]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":100,"s":[-20]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":108,"s":[21]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":114,"s":[-19]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":119,"s":[14]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":123,"s":[-18]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":127,"s":[13]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":131,"s":[-18]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":135,"s":[11]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":139,"s":[-25]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":144,"s":[17]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":148,"s":[-26]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":152,"s":[27]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":157,"s":[-23]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":162,"s":[16]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":169,"s":[-8]},{"t":179,"s":[0]}]},"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.3,"y":0},"t":14,"s":[217.441,101.083,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":31,"s":[217.836,92.577,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":48,"s":[217.849,93.577,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":51,"s":[214.684,100.095,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":58,"s":[220.374,93.227,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":96,"s":[220.374,93.227,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":102,"s":[217.439,101.066,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":119,"s":[217.901,94.576,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":148,"s":[217.821,91.578,0],"to":[0,0,0],"ti":[0,0,0]},{"t":152,"s":[217.441,101.083,0]}]},"a":{"a":0,"k":[45.938,133.717,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":14,"s":[{"i":[[2.379,1.586],[-3.917,2.195],[-1.486,-1.31],[3.583,-3.333]],"o":[[-5,-3.333],[1.502,-0.842],[3.5,3.083],[-2.318,2.156]],"v":[[-20.5,8.952],[-20.75,-10.048],[22,-9.798],[21.75,8.952]],"c":true}]},{"i":{"x":0.6,"y":1},"o":{"x":0.167,"y":0.167},"t":31,"s":[{"i":[[13.19,-3.194],[-13.193,5.273],[-11.003,-6.528],[6.61,1.697]],"o":[[-8.423,2.04],[13.501,-5.396],[11.124,6.6],[-17.667,-4.537]],"v":[[-31.401,13.305],[-31.784,-9.818],[33.698,-9.514],[33.316,13.305]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.4,"y":0},"t":102,"s":[{"i":[[13.19,-3.194],[-13.193,5.273],[-11.003,-6.528],[6.61,1.697]],"o":[[-8.423,2.04],[13.501,-5.396],[11.124,6.6],[-17.667,-4.537]],"v":[[-31.401,13.305],[-31.784,-9.818],[33.698,-9.514],[33.316,13.305]],"c":true}]},{"t":157,"s":[{"i":[[2.379,1.586],[-3.917,2.195],[-1.486,-1.31],[3.583,-3.333]],"o":[[-5,-3.333],[1.502,-0.842],[3.5,3.083],[-2.318,2.156]],"v":[[-20.5,8.952],[-20.75,-10.048],[22,-9.798],[21.75,8.952]],"c":true}]}]},"nm":"Path 1","hd":false},{"ty":"tm","s":{"a":0,"k":0},"e":{"a":0,"k":5},"o":{"a":0,"k":28},"m":1,"nm":"Trim Paths 1","hd":false},{"ty":"st","c":{"a":0,"k":[0.870588302612,0.937254965305,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":[45.5,31.108]},"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.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":14,"s":[{"i":[[2.379,1.586],[-3.917,2.195],[-1.486,-1.31],[3.583,-3.333]],"o":[[-5,-3.333],[1.502,-0.842],[3.5,3.083],[-2.318,2.156]],"v":[[-20.5,8.952],[-20.75,-10.048],[22,-9.798],[21.75,8.952]],"c":true}]},{"i":{"x":0.6,"y":1},"o":{"x":0.167,"y":0.167},"t":31,"s":[{"i":[[17.382,-4.22],[-13.901,5.946],[-12.239,-7.311],[6.765,0.902]],"o":[[-8.422,2.045],[10.474,-4.48],[10.866,6.491],[-22.957,-3.062]],"v":[[-31.401,13.305],[-31.784,-9.818],[33.698,-9.514],[33.315,13.305]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.4,"y":0},"t":102,"s":[{"i":[[17.382,-4.22],[-13.901,5.946],[-12.239,-7.311],[6.765,0.902]],"o":[[-8.422,2.045],[10.474,-4.48],[10.866,6.491],[-22.957,-3.062]],"v":[[-31.401,13.305],[-31.784,-9.818],[33.698,-9.514],[33.315,13.305]],"c":true}]},{"t":157,"s":[{"i":[[2.379,1.586],[-3.917,2.195],[-1.486,-1.31],[3.583,-3.333]],"o":[[-5,-3.333],[1.502,-0.842],[3.5,3.083],[-2.318,2.156]],"v":[[-20.5,8.952],[-20.75,-10.048],[22,-9.798],[21.75,8.952]],"c":true}]}]},"nm":"Path 1","hd":false},{"ty":"tm","s":{"a":0,"k":0},"e":{"a":0,"k":42},"o":{"a":0,"k":-137},"m":1,"nm":"Trim Paths 1","hd":false},{"ty":"st","c":{"a":0,"k":[0.533333361149,0.192156881094,0.196078449488,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":[45.5,31.108]},"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.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":14,"s":[{"i":[[2.379,1.586],[-3.917,2.195],[-1.486,-1.31],[3.583,-3.333]],"o":[[-5,-3.333],[1.502,-0.842],[3.5,3.083],[-2.318,2.156]],"v":[[-20.5,8.952],[-20.75,-10.048],[22,-9.798],[21.75,8.952]],"c":true}]},{"i":{"x":0.6,"y":1},"o":{"x":0.167,"y":0.167},"t":31,"s":[{"i":[[17.829,-3.122],[-14.367,6.478],[-11.808,-7.198],[6.749,1.013]],"o":[[-8.537,1.495],[11.102,-5.006],[10.484,6.391],[-16.53,-2.481]],"v":[[-31.401,13.305],[-31.784,-9.818],[33.698,-9.514],[33.316,13.305]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.4,"y":0},"t":102,"s":[{"i":[[17.829,-3.122],[-14.367,6.478],[-11.808,-7.198],[6.749,1.013]],"o":[[-8.537,1.495],[11.102,-5.006],[10.484,6.391],[-16.53,-2.481]],"v":[[-31.401,13.305],[-31.784,-9.818],[33.698,-9.514],[33.316,13.305]],"c":true}]},{"t":157,"s":[{"i":[[2.379,1.586],[-3.917,2.195],[-1.486,-1.31],[3.583,-3.333]],"o":[[-5,-3.333],[1.502,-0.842],[3.5,3.083],[-2.318,2.156]],"v":[[-20.5,8.952],[-20.75,-10.048],[22,-9.798],[21.75,8.952]],"c":true}]}]},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":0,"k":[0.627451002598,0.701960802078,0.768627524376,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":5,"k":{"a":0,"k":[0,0.808,0.902,0.973,0.441,0.673,0.676,0.725,0.53,0.537,0.451,0.478,0.627,0.627,0.375,0.396,1,0.718,0.298,0.314]}},"s":{"a":0,"k":[0.75,-10.75]},"e":{"a":0,"k":[0.5,10.5]},"t":1,"nm":"Gradient_6esHIrtKAL","hd":false},{"ty":"tr","p":{"a":0,"k":[45.5,31.108]},"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":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[0,0],[-0.222,10]],"o":[[0.222,-10],[0,0]],"v":[[0,19.66],[0,-19.66]],"c":false}},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":0,"k":[0.733333349228,0.749019622803,0.764705955982,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":2},"lc":2,"lj":2,"bm":0,"nm":"Stroke 2","hd":false},{"ty":"tr","p":{"a":0,"k":[43.94,54.4]},"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.222,10]],"o":[[0.222,-10],[0,0]],"v":[[0,19.66],[0,-19.66]],"c":false}},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":0,"k":[0.529411792755,0.443137288094,0.466666698456,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":6},"lc":2,"lj":2,"bm":0,"nm":"Stroke 3","hd":false},{"ty":"tr","p":{"a":0,"k":[45.44,54.4]},"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":[[0,0],[-0.222,10]],"o":[[0.222,-10],[0,0]],"v":[[0,19.66],[0,-19.66]],"c":false}},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":0,"k":[0.592156887054,0.592156887054,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":[45.94,54.4]},"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":[45.94,54.4]},"a":{"a":0,"k":[45.94,54.4]},"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":180.18018018018,"st":0,"bm":0},{"ddd":0,"ind":9,"ty":4,"nm":"L Ring Stick TOP","parent":12,"sr":1,"ks":{"p":{"a":1,"k":[{"i":{"x":0,"y":1},"o":{"x":0.1,"y":0},"t":45,"s":[30.535,77.275,0],"to":[0.07,0.115,0],"ti":[0.007,-0.134,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.3,"y":0},"t":92,"s":[30.953,77.966,0],"to":[-0.007,0.134,0],"ti":[0.077,-0.018,0]},{"t":104,"s":[30.491,78.077,0]}]},"a":{"a":0,"k":[30.044,72.438,0]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0,"y":1},"o":{"x":0.167,"y":0.167},"t":45,"s":[{"i":[[7.922,3.457],[-0.209,-2.364],[0.006,6.977],[0.667,0.829]],"o":[[0.045,1.551],[0.567,6.418],[-0.001,-1.181],[-8.453,2.294]],"v":[[-11.644,38.802],[-12.117,39.227],[11.055,40.191],[10.826,40.122]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0},"t":92,"s":[{"i":[[-0.212,-7.388],[0,-2.373],[0.006,13.246],[0.667,1.574]],"o":[[0.045,1.551],[0,13.312],[-0.001,-2.242],[-4.377,-10.332]],"v":[[-13.053,28.155],[-12.73,35.962],[11.252,36.304],[10.929,28.705]],"c":true}]},{"t":104,"s":[{"i":[[7.922,3.457],[-0.209,-2.364],[0.006,6.977],[0.667,0.829]],"o":[[0.045,1.551],[0.567,6.418],[-0.001,-1.181],[-8.453,2.294]],"v":[[-11.644,38.802],[-12.117,39.227],[11.055,40.191],[10.826,40.122]],"c":true}]}]},"nm":"Path 1","hd":false},{"ty":"tm","s":{"a":0,"k":0},"e":{"a":0,"k":11},"o":{"a":0,"k":125},"m":1,"nm":"Trim Paths 1","hd":false},{"ty":"st","c":{"a":0,"k":[0.870588243008,0.936953246593,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":[31.039,2.886]},"a":{"a":0,"k":[0,-48.25]},"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,"y":1},"o":{"x":0.167,"y":0.167},"t":45,"s":[{"i":[[8.042,1.485],[-0.248,-2.36],[0.006,6.977],[0.266,0.864]],"o":[[-0.382,1.524],[0.802,7.636],[-0.001,-1.181],[-7.877,1.108]],"v":[[-11.644,38.802],[-12.117,39.227],[11.055,40.191],[10.826,40.122]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0},"t":92,"s":[{"i":[[2.428,-9.684],[0,-2.373],[0.006,13.246],[0.266,1.64]],"o":[[-0.382,1.524],[0,13.312],[-0.001,-2.242],[-1.418,-8.732]],"v":[[-13.053,28.155],[-12.73,35.962],[11.252,36.304],[10.929,28.705]],"c":true}]},{"t":104,"s":[{"i":[[8.042,1.485],[-0.248,-2.36],[0.006,6.977],[0.266,0.864]],"o":[[-0.382,1.524],[0.802,7.636],[-0.001,-1.181],[-7.877,1.108]],"v":[[-11.644,38.802],[-12.117,39.227],[11.055,40.191],[10.826,40.122]],"c":true}]}]},"nm":"Path 1","hd":false},{"ty":"tm","s":{"a":0,"k":0},"e":{"a":0,"k":46},"o":{"a":0,"k":0},"m":1,"nm":"Trim Paths 1","hd":false},{"ty":"st","c":{"a":0,"k":[0.541176497936,0.639215707779,0.733333349228,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":[31.039,2.886]},"a":{"a":0,"k":[0,-48.25]},"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,"y":1},"o":{"x":0.167,"y":0.167},"t":45,"s":[{"i":[[14.426,9.444],[-0.348,-2.348],[0.006,6.977],[0.403,0.856]],"o":[[-1.336,-0.875],[1.269,8.56],[-0.001,-1.181],[-7.547,1.58]],"v":[[-11.644,38.802],[-12.117,39.227],[11.055,40.191],[10.826,40.122]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0},"t":92,"s":[{"i":[[4.765,-12.188],[0,-2.373],[0.006,13.246],[0.403,1.624]],"o":[[-0.581,1.487],[0,13.312],[-0.001,-2.242],[-1.531,-6.17]],"v":[[-13.053,28.155],[-12.73,35.962],[11.252,36.304],[10.929,28.705]],"c":true}]},{"t":104,"s":[{"i":[[14.426,9.444],[-0.348,-2.348],[0.006,6.977],[0.403,0.856]],"o":[[-1.336,-0.875],[1.269,8.56],[-0.001,-1.181],[-7.547,1.58]],"v":[[-11.644,38.802],[-12.117,39.227],[11.055,40.191],[10.826,40.122]],"c":true}]}]},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":0,"k":[0.36862745098,0.356862745098,0.427451010311,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":8},"lc":2,"lj":2,"bm":0,"nm":"Stroke 2","hd":false},{"ty":"tr","p":{"a":0,"k":[31.039,2.886]},"a":{"a":0,"k":[0,-48.25]},"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,"y":1},"o":{"x":0.167,"y":0.167},"t":45,"s":[{"i":[[9.341,2.664],[-0.481,-2.324],[0.006,6.977],[0.199,0.867]],"o":[[-0.437,1.515],[1.848,8.935],[-0.001,-1.181],[-9.029,1.134]],"v":[[-11.644,38.802],[-12.117,39.227],[11.055,40.191],[10.826,40.122]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0},"t":92,"s":[{"i":[[2.849,-9.884],[0,-2.373],[0.006,13.246],[0.199,1.646]],"o":[[-0.437,1.515],[0,13.312],[-0.001,-2.242],[-0.998,-8.237]],"v":[[-13.053,28.155],[-12.73,35.962],[11.252,36.304],[10.929,28.705]],"c":true}]},{"t":104,"s":[{"i":[[9.341,2.664],[-0.481,-2.324],[0.006,6.977],[0.199,0.867]],"o":[[-0.437,1.515],[1.848,8.935],[-0.001,-1.181],[-9.029,1.134]],"v":[[-11.644,38.802],[-12.117,39.227],[11.055,40.191],[10.826,40.122]],"c":true}]}]},"nm":"Path 1","hd":false},{"ty":"gf","o":{"a":0,"k":100},"r":1,"bm":0,"g":{"p":3,"k":{"a":0,"k":[0,0.69,0.769,0.843,0.5,0.79,0.849,0.9,1,0.89,0.929,0.957,0,1,0.5,0.5,1,0]}},"s":{"a":0,"k":[2.067,45.81]},"e":{"a":0,"k":[-0.253,40.575]},"t":1,"nm":"Gradient_rhx1889K33","hd":false},{"ty":"gf","o":{"a":0,"k":100},"r":1,"bm":0,"g":{"p":9,"k":{"a":0,"k":[0,0.694,0.738,0.773,0.226,0.847,0.869,0.886,0.298,1,1,1,0.465,0.72,0.659,0.667,0.598,0.439,0.318,0.333,0.642,0.388,0.296,0.312,0.68,0.337,0.275,0.29,0.727,0.416,0.378,0.373,1,0.494,0.481,0.455]}},"s":{"a":0,"k":[-8.075,-10.936]},"e":{"a":0,"k":[10.383,-11.04]},"t":1,"nm":"Gradient_eKJQpxVAmP","hd":false},{"ty":"tr","p":{"a":0,"k":[31.039,2.886]},"a":{"a":0,"k":[0,-48.25]},"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":48,"op":101,"st":0,"bm":0},{"ddd":0,"ind":10,"ty":4,"nm":"L Ring","parent":12,"sr":1,"ks":{"r":{"a":1,"k":[{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":6,"s":[-180]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":11,"s":[-182]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":15,"s":[-178]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":19,"s":[-182]},{"i":{"x":[0.779],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":23,"s":[-176]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":27,"s":[-182]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":31,"s":[-173]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":35,"s":[-183]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":39,"s":[-173]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":43,"s":[-183]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":47,"s":[-171]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":51,"s":[-183]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":55,"s":[-173]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":58,"s":[-188]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":62,"s":[-168]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":65,"s":[-189]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":69,"s":[-173]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":73,"s":[-184]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":77,"s":[-168]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":81,"s":[-184]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":85,"s":[-169]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":89,"s":[-183]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":93,"s":[-172]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":97,"s":[-183]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":101,"s":[-169]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":110,"s":[-189]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":116,"s":[-167]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":121,"s":[-187]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":125,"s":[-171]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":129,"s":[-183]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":133,"s":[-169]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":137,"s":[-183]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":141,"s":[-169]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":146,"s":[-183]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":150,"s":[-171]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":154,"s":[-185]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":159,"s":[-172]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":164,"s":[-182]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":171,"s":[-178]},{"t":179,"s":[-180]}]},"p":{"a":0,"k":[31.451,58.3,0]},"a":{"a":0,"k":[111.522,53.259,0]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0.1,"y":1},"o":{"x":0.15,"y":0},"t":45,"s":[{"i":[[-8.534,-2.532],[-22.619,-0.194],[-5.458,2.05],[69.782,1.099]],"o":[[5.476,1.625],[22.185,0.192],[8.98,-3.374],[-72.252,-1.139]],"v":[[-82.988,31.634],[0.848,32.372],[82.542,31.023],[-0.113,-32.12]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.461,"y":0},"t":92,"s":[{"i":[[-6.757,-7.215],[-62.396,-0.208],[-4.633,3],[78.626,1.167]],"o":[[8.25,8.81],[61.198,0.204],[7.623,-4.937],[-81.409,-1.209]],"v":[[-94.293,32.008],[6.573,55.445],[93.541,31.658],[-0.851,-37.566]],"c":true}]},{"i":{"x":0,"y":1},"o":{"x":0.095,"y":0.173},"t":104,"s":[{"i":[[-8.534,-2.532],[-22.619,-0.194],[-5.458,2.05],[69.782,1.099]],"o":[[5.476,1.625],[22.185,0.192],[8.98,-3.374],[-72.252,-1.139]],"v":[[-82.988,31.634],[0.848,32.372],[82.542,31.023],[-0.113,-32.12]],"c":true}]},{"i":{"x":0,"y":1},"o":{"x":0.25,"y":0},"t":137,"s":[{"i":[[-8.296,-2.316],[-52.73,-0.179],[-5.261,-5.678],[67.84,1.006]],"o":[[8.11,-5.013],[51.719,0.176],[8.73,-3.086],[-70.241,-1.042]],"v":[[-80.961,20.312],[1.602,-5.404],[79.963,19.753],[-0.392,-38.002]],"c":true}]},{"t":179,"s":[{"i":[[-8.534,-2.532],[-22.619,-0.194],[-5.458,2.05],[69.782,1.099]],"o":[[5.476,1.625],[22.185,0.192],[8.98,-3.374],[-72.252,-1.139]],"v":[[-82.988,31.634],[0.848,32.372],[82.542,31.023],[-0.113,-32.12]],"c":true}]}]},"nm":"Path 1","hd":false},{"ty":"tm","s":{"a":0,"k":0},"e":{"a":0,"k":42},"o":{"a":1,"k":[{"i":{"x":[0.1],"y":[1]},"o":{"x":[0.15],"y":[0]},"t":45,"s":[153]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.461],"y":[0]},"t":92,"s":[159]},{"i":{"x":[0],"y":[1]},"o":{"x":[0.095],"y":[0.095]},"t":104,"s":[153]},{"i":{"x":[0],"y":[1]},"o":{"x":[0.25],"y":[0]},"t":137,"s":[169]},{"t":179,"s":[153]}]},"m":1,"nm":"Trim Paths 1","hd":false},{"ty":"st","c":{"a":0,"k":[0.686274528503,0.166858896613,0.171260729432,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":[111.522,53.259]},"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.1,"y":1},"o":{"x":0.15,"y":0},"t":45,"s":[{"i":[[-8.534,-2.532],[-22.619,-0.194],[-5.458,2.05],[69.782,1.099]],"o":[[5.476,1.625],[22.185,0.192],[8.98,-3.374],[-72.252,-1.139]],"v":[[-82.988,31.634],[0.848,32.372],[82.542,31.023],[-0.113,-32.12]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.461,"y":0},"t":92,"s":[{"i":[[-6.603,-6.102],[-62.396,-0.208],[-4.633,3],[78.626,1.167]],"o":[[11.742,10.853],[61.198,0.204],[7.623,-4.937],[-81.409,-1.209]],"v":[[-94.293,32.008],[6.573,55.445],[93.541,31.658],[-0.851,-37.566]],"c":true}]},{"i":{"x":0,"y":1},"o":{"x":0.095,"y":0.173},"t":104,"s":[{"i":[[-8.534,-2.532],[-22.619,-0.194],[-5.458,2.05],[69.782,1.099]],"o":[[5.476,1.625],[22.185,0.192],[8.98,-3.374],[-72.252,-1.139]],"v":[[-82.988,31.634],[0.848,32.372],[82.542,31.023],[-0.113,-32.12]],"c":true}]},{"i":{"x":0,"y":1},"o":{"x":0.25,"y":0},"t":137,"s":[{"i":[[-8.296,-2.316],[-52.73,-0.179],[-4.536,-5.946],[67.84,1.006]],"o":[[9.336,-6.329],[51.719,0.176],[8.73,-3.086],[-70.241,-1.042]],"v":[[-80.961,20.312],[1.602,-5.404],[79.963,19.753],[-0.392,-38.002]],"c":true}]},{"t":179,"s":[{"i":[[-8.534,-2.532],[-22.619,-0.194],[-5.458,2.05],[69.782,1.099]],"o":[[5.476,1.625],[22.185,0.192],[8.98,-3.374],[-72.252,-1.139]],"v":[[-82.988,31.634],[0.848,32.372],[82.542,31.023],[-0.113,-32.12]],"c":true}]}]},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":0,"k":[0.450980395079,0.053056515753,0.056428749114,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":[111.522,53.259]},"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.1,"y":1},"o":{"x":0.15,"y":0},"t":45,"s":[{"i":[[-1.405,-9.497],[-66.911,2.535],[-0.032,4.359],[69.782,1.099]],"o":[[0.865,5.848],[62.523,-2.368],[0.05,-6.815],[-72.252,-1.139]],"v":[[-83.81,28.334],[-2.427,-21.287],[83.52,25.969],[-0.113,-32.12]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.461,"y":0},"t":92,"s":[{"i":[[-1.04,-10.141],[-75.39,2.69],[-0.036,3.164],[78.626,1.167]],"o":[[0.64,6.244],[70.446,-2.513],[0.056,-4.947],[-81.409,-1.209]],"v":[[-95.028,29.535],[-3.459,-26.071],[94.097,27.509],[-0.851,-37.566]],"c":true}]},{"i":{"x":0,"y":1},"o":{"x":0.095,"y":0.173},"t":104,"s":[{"i":[[-1.405,-9.497],[-66.911,2.535],[-0.032,4.359],[69.782,1.099]],"o":[[0.865,5.848],[62.523,-2.368],[0.05,-6.815],[-72.252,-1.139]],"v":[[-83.81,28.334],[-2.427,-21.287],[83.52,25.969],[-0.113,-32.12]],"c":true}]},{"i":{"x":0,"y":1},"o":{"x":0.25,"y":0},"t":137,"s":[{"i":[[-1.366,-8.687],[-65.048,2.318],[-0.031,3.987],[67.84,1.006]],"o":[[0.841,5.349],[60.783,-2.166],[0.049,-6.234],[-70.241,-1.042]],"v":[[-81.759,17.294],[-2.642,-28.093],[80.913,15.13],[-0.392,-38.002]],"c":true}]},{"t":179,"s":[{"i":[[-1.405,-9.497],[-66.911,2.535],[-0.032,4.359],[69.782,1.099]],"o":[[0.865,5.848],[62.523,-2.368],[0.05,-6.815],[-72.252,-1.139]],"v":[[-83.81,28.334],[-2.427,-21.287],[83.52,25.969],[-0.113,-32.12]],"c":true}]}]},"nm":"Path 1","hd":false},{"ty":"gf","o":{"a":0,"k":100},"r":1,"bm":0,"g":{"p":3,"k":{"a":0,"k":[0,0.945,0.498,0.518,0.5,0.945,0.498,0.518,1,0.945,0.498,0.518,0,1,0.5,0.5,1,0]}},"s":{"a":0,"k":[-2.8,-23.889]},"e":{"a":0,"k":[61.9,2.624]},"t":2,"h":{"a":0,"k":0},"a":{"a":0,"k":0},"nm":"Gradient_YEinOM1TgI","hd":false},{"ty":"tr","p":{"a":0,"k":[111.522,53.259]},"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.1,"y":1},"o":{"x":0.15,"y":0},"t":45,"s":[{"i":[[-3.322,-29.382],[-5.08,1.711],[-2.7,20.576],[-12.143,31.192]],"o":[[0.455,4.022],[4.772,-1.607],[0.262,-1.998],[4.243,-10.899]],"v":[[-84.138,30.67],[1.046,30.58],[-42.445,-0.098],[-52.749,-11.294]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.461,"y":0},"t":92,"s":[{"i":[[1.391,-30.045],[-55.971,23.244],[13.966,11.686],[-19.945,19.018]],"o":[[19.789,18.98],[-57.353,14.15],[-7.803,-6.529],[9.057,-8.637]],"v":[[-95.531,31.078],[73.568,42.434],[-62.008,16.709],[-58.569,-20.964]],"c":true}]},{"i":{"x":0,"y":1},"o":{"x":0.095,"y":0.173},"t":104,"s":[{"i":[[-3.322,-29.382],[-5.08,1.711],[-2.7,20.576],[-12.143,31.192]],"o":[[0.455,4.022],[4.772,-1.607],[0.262,-1.998],[4.243,-10.899]],"v":[[-84.138,30.67],[1.046,30.58],[-42.445,-0.098],[-52.749,-11.294]],"c":true}]},{"i":{"x":0,"y":1},"o":{"x":0.25,"y":0},"t":137,"s":[{"i":[[-3.23,-26.874],[-11.842,1.565],[9.984,2.173],[0.916,10.16]],"o":[[30.351,-28.575],[-17.864,-0.48],[-1.846,-0.402],[-0.974,-10.8]],"v":[[-82.078,19.43],[2.063,-7.043],[-42.133,-11.574],[-49.962,-22.231]],"c":true}]},{"t":179,"s":[{"i":[[-3.322,-29.382],[-5.08,1.711],[-2.7,20.576],[-12.143,31.192]],"o":[[0.455,4.022],[4.772,-1.607],[0.262,-1.998],[4.243,-10.899]],"v":[[-84.138,30.67],[1.046,30.58],[-42.445,-0.098],[-52.749,-11.294]],"c":true}]}]},"nm":"Path 1","hd":false},{"ty":"gf","o":{"a":0,"k":100},"r":1,"bm":0,"g":{"p":3,"k":{"a":0,"k":[0,0.443,0.098,0.102,0.5,0.563,0.112,0.116,1,0.682,0.125,0.129,0,1,0.593,1,0.733,1,0.866,0.775,1,0.55]}},"s":{"a":1,"k":[{"i":{"x":0.1,"y":1},"o":{"x":0.15,"y":0},"t":45,"s":[-68.588,35.458],"to":[0,0],"ti":[0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.461,"y":0},"t":92,"s":[-83.2,58.776],"to":[0,0],"ti":[0,0]},{"i":{"x":0,"y":1},"o":{"x":0.095,"y":0.095},"t":104,"s":[-68.588,35.458],"to":[0,0],"ti":[0,0]},{"i":{"x":0,"y":1},"o":{"x":0.25,"y":0},"t":137,"s":[-81.24,32.466],"to":[0,0],"ti":[0,0]},{"t":179,"s":[-68.588,35.458]}]},"e":{"a":1,"k":[{"i":{"x":0.1,"y":1},"o":{"x":0.15,"y":0},"t":45,"s":[-47.604,2.444],"to":[0,0],"ti":[0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.461,"y":0},"t":92,"s":[-62.224,18.204],"to":[0,0],"ti":[0,0]},{"i":{"x":0,"y":1},"o":{"x":0.095,"y":0.095},"t":104,"s":[-47.604,2.444],"to":[0,0],"ti":[0,0]},{"i":{"x":0,"y":1},"o":{"x":0.25,"y":0},"t":137,"s":[-43.509,-10.025],"to":[0,0],"ti":[0,0]},{"t":179,"s":[-47.604,2.444]}]},"t":1,"nm":"Gradient_1aPp2TA5im","hd":false},{"ty":"tr","p":{"a":0,"k":[111.522,53.259]},"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.1,"y":1},"o":{"x":0.15,"y":0},"t":45,"s":[{"i":[[-8.534,-4.83],[-22.619,-0.373],[-5.457,3.911],[69.782,2.098]],"o":[[5.476,3.099],[22.185,0.366],[8.98,-6.435],[-72.252,-2.172]],"v":[[-82.988,62.419],[0.848,63.826],[82.542,61.253],[-0.113,-59.175]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.461,"y":0},"t":92,"s":[{"i":[[-4.217,-8.586],[-62.395,-0.396],[-4.677,5.875],[78.625,2.226]],"o":[[9.979,20.318],[61.198,0.389],[7.697,-9.667],[-81.409,-2.305]],"v":[[-94.268,63.244],[6.573,109.917],[93.356,62.793],[-0.851,-69.758]],"c":true}]},{"i":{"x":0,"y":1},"o":{"x":0.095,"y":0.173},"t":104,"s":[{"i":[[-8.534,-4.83],[-22.619,-0.373],[-5.457,3.911],[69.782,2.098]],"o":[[5.476,3.099],[22.185,0.366],[8.98,-6.435],[-72.252,-2.172]],"v":[[-82.988,62.419],[0.848,63.826],[82.542,61.253],[-0.113,-59.175]],"c":true}]},{"i":{"x":0,"y":1},"o":{"x":0.25,"y":0},"t":137,"s":[{"i":[[-8.296,-4.418],[-52.73,-0.342],[-4.511,-8.5],[67.84,1.919]],"o":[[9.476,-14.631],[51.719,0.335],[8.73,-5.886],[-70.241,-1.987]],"v":[[-80.961,39.847],[1.601,-11.648],[79.963,38.781],[-0.392,-71.371]],"c":true}]},{"t":179,"s":[{"i":[[-8.534,-4.83],[-22.619,-0.373],[-5.457,3.911],[69.782,2.098]],"o":[[5.476,3.099],[22.185,0.366],[8.98,-6.435],[-72.252,-2.172]],"v":[[-82.988,62.419],[0.848,63.826],[82.542,61.253],[-0.113,-59.175]],"c":true}]}]},"nm":"Path 1","hd":false},{"ty":"gf","o":{"a":0,"k":100},"r":1,"bm":0,"g":{"p":3,"k":{"a":0,"k":[0,1,0.843,0.835,0.5,0.939,0.586,0.6,1,0.878,0.329,0.365,0,1,0.5,0.5,1,0]}},"s":{"a":0,"k":[-25.766,10.624]},"e":{"a":0,"k":[16.989,-9.923]},"t":2,"h":{"a":0,"k":8.403},"a":{"a":0,"k":182.771},"nm":"Gradient_aoywu5OWy6","hd":false},{"ty":"gf","o":{"a":0,"k":100},"r":1,"bm":0,"g":{"p":3,"k":{"a":0,"k":[0,0.906,0.376,0.412,0.5,0.906,0.376,0.412,1,0.906,0.376,0.412,0,1,0.5,0.5,1,0]}},"s":{"a":0,"k":[-53.885,24.131]},"e":{"a":0,"k":[5.401,-24.3]},"t":1,"nm":"Gradient_UufWHr9y3J","hd":false},{"ty":"gf","o":{"a":0,"k":100},"r":1,"bm":0,"g":{"p":3,"k":{"a":0,"k":[0,0.988,0.482,0.498,0.5,0.988,0.482,0.498,1,0.988,0.482,0.498,0,1,0.5,0.5,1,0]}},"s":{"a":0,"k":[-0.57,9.65]},"e":{"a":0,"k":[46.769,14.517]},"t":2,"h":{"a":0,"k":0},"a":{"a":0,"k":0},"nm":"Gradient_cdxe8CyECM","hd":false},{"ty":"gf","o":{"a":0,"k":100},"r":1,"bm":0,"g":{"p":3,"k":{"a":0,"k":[0,0.988,0.482,0.498,0.5,0.988,0.482,0.498,1,0.988,0.482,0.498,0,1,0.5,0.5,1,0]}},"s":{"a":0,"k":[20.179,18.31]},"e":{"a":0,"k":[58.669,27.823]},"t":2,"h":{"a":0,"k":0},"a":{"a":0,"k":0},"nm":"Gradient_F0HKBrUa6K","hd":false},{"ty":"gf","o":{"a":0,"k":100},"r":1,"bm":0,"g":{"p":3,"k":{"a":0,"k":[0,0.831,0.263,0.314,0.5,0.792,0.229,0.284,1,0.753,0.196,0.255]}},"s":{"a":0,"k":[0.139,-30.933]},"e":{"a":0,"k":[46.889,19.287]},"t":1,"nm":"Gradient_KkrhEDhKug","hd":false},{"ty":"tr","p":{"a":0,"k":[111.522,53.259]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,50]},"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}],"ip":0,"op":180.18018018018,"st":0,"bm":0},{"ddd":0,"ind":11,"ty":4,"nm":"Hummer Top 2","parent":18,"sr":1,"ks":{"r":{"a":1,"k":[{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":56,"s":[30]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":60,"s":[-23]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":64,"s":[29]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":68,"s":[-22]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":72,"s":[34]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":76,"s":[-20]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":80,"s":[35]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":84,"s":[-20]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":88,"s":[29]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":92,"s":[-20]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":96,"s":[31]},{"t":100,"s":[-20]}]},"p":{"a":0,"k":[217.849,93.577,0]},"a":{"a":0,"k":[45.938,133.717,0]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[4.08,0.807],[-10.727,3.358],[-12.76,-10.076],[9.522,1.699]],"o":[[-12.971,-2.564],[10.993,-3.442],[8.636,6.82],[-26.23,-4.681]],"v":[[-29.096,11.313],[-29.465,-9.998],[29.28,-8.164],[28.912,10.586]],"c":true}},"nm":"Path 1","hd":false},{"ty":"tm","s":{"a":0,"k":0},"e":{"a":0,"k":5},"o":{"a":0,"k":28},"m":1,"nm":"Trim Paths 1","hd":false},{"ty":"st","c":{"a":0,"k":[0.870588302612,0.937254965305,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":[45.5,31.108]},"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":[[4.045,0.904],[-13.06,2.53],[-20.009,-10.066],[9.932,0.896]],"o":[[-13.192,-2.95],[2.46,-0.477],[9.831,4.945],[-37.854,-3.414]],"v":[[-29.096,11.313],[-29.465,-9.998],[29.28,-8.164],[28.912,10.586]],"c":true}},"nm":"Path 1","hd":false},{"ty":"tm","s":{"a":0,"k":0},"e":{"a":0,"k":42},"o":{"a":0,"k":-137},"m":1,"nm":"Trim Paths 1","hd":false},{"ty":"st","c":{"a":0,"k":[0.533333361149,0.192156881094,0.196078449488,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":[45.5,31.108]},"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":[[4.169,0.478],[-14.495,1.782],[-29.008,-9.053],[8.859,1.242]],"o":[[-10.587,-1.214],[2.506,-0.308],[10.542,3.29],[-23.603,-3.31]],"v":[[-29.096,11.313],[-29.465,-9.998],[29.28,-8.164],[28.912,10.586]],"c":true}},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":0,"k":[0.627451002598,0.701960802078,0.768627524376,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":5,"k":{"a":0,"k":[0,0.808,0.902,0.973,0.441,0.673,0.676,0.725,0.53,0.537,0.451,0.478,0.627,0.627,0.375,0.396,1,0.718,0.298,0.314]}},"s":{"a":0,"k":[0.75,-10.75]},"e":{"a":0,"k":[0.5,10.5]},"t":1,"nm":"Gradient_rYnEIfsEjH","hd":false},{"ty":"tr","p":{"a":0,"k":[45.5,31.108]},"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":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[0,0],[-0.36,10]],"o":[[0.222,-10],[0,0]],"v":[[0,19.66],[0.489,-19.66]],"c":false}},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":0,"k":[0.733333349228,0.749019622803,0.764705955982,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":2},"lc":2,"lj":2,"bm":0,"nm":"Stroke 2","hd":false},{"ty":"tr","p":{"a":0,"k":[43.94,54.4]},"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.36,10]],"o":[[0.222,-10],[0,0]],"v":[[0,19.66],[1.425,-19.66]],"c":false}},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":0,"k":[0.529411792755,0.443137288094,0.466666698456,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":6},"lc":2,"lj":2,"bm":0,"nm":"Stroke 3","hd":false},{"ty":"tr","p":{"a":0,"k":[45.44,54.4]},"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":[[0,0],[-0.36,10]],"o":[[0.222,-10],[0,0]],"v":[[0,19.66],[1.737,-19.66]],"c":false}},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":0,"k":[0.592156887054,0.592156887054,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":[45.94,54.4]},"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":[45.94,54.4]},"a":{"a":0,"k":[45.94,54.4]},"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":56,"op":97,"st":0,"bm":0},{"ddd":0,"ind":12,"ty":4,"nm":"L Ring Stick","parent":18,"sr":1,"ks":{"r":{"a":1,"k":[{"i":{"x":[0.1],"y":[1]},"o":{"x":[0.15],"y":[0]},"t":45,"s":[140]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.3],"y":[0]},"t":92,"s":[143]},{"i":{"x":[0],"y":[1]},"o":{"x":[0.095],"y":[0.083]},"t":104,"s":[140]},{"i":{"x":[0],"y":[1]},"o":{"x":[0.25],"y":[0]},"t":137,"s":[148]},{"t":179,"s":[140]}]},"p":{"a":1,"k":[{"i":{"x":0.1,"y":1},"o":{"x":0.15,"y":0},"t":45,"s":[103.092,80.581,0],"to":[3.435,-0.339,0],"ti":[0.001,-0.167,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.3,"y":0},"t":92,"s":[123.7,78.546,0],"to":[-0.001,0.167,0],"ti":[-1.401,-0.334,0]},{"i":{"x":0,"y":1},"o":{"x":0.095,"y":0.098},"t":104,"s":[103.084,81.581,0],"to":[1.401,0.334,0],"ti":[-0.001,0.167,0]},{"i":{"x":0,"y":1},"o":{"x":0.25,"y":0},"t":137,"s":[132.105,80.55,0],"to":[0.001,-0.167,0],"ti":[4.835,-0.005,0]},{"t":179,"s":[103.092,80.581,0]}]},"a":{"a":0,"k":[31.164,2.761,0]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[0.092,-2.159],[0,-2.875],[0.003,16.045],[0.009,2.002]],"o":[[-0.081,1.877],[0,16.125],[-0.001,-2.716],[-0.016,-3.605]],"v":[[-10.958,-46.698],[-10.958,38.55],[11.03,38.964],[11.03,-46.031]],"c":true}},"nm":"Path 1","hd":false},{"ty":"tm","s":{"a":0,"k":0},"e":{"a":0,"k":3},"o":{"a":0,"k":160},"m":1,"nm":"Trim Paths 1","hd":false},{"ty":"st","c":{"a":0,"k":[0.870588243008,0.936953246593,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":[31.039,2.886]},"a":{"a":0,"k":[0,-48.25]},"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.092,-2.159],[0,-2.875],[0.003,16.045],[0.009,2.002]],"o":[[-0.081,1.877],[0,16.125],[-0.001,-2.716],[-0.016,-3.605]],"v":[[-10.958,-46.698],[-10.958,38.55],[11.03,38.964],[11.03,-46.031]],"c":true}},"nm":"Path 1","hd":false},{"ty":"tm","s":{"a":0,"k":0},"e":{"a":0,"k":33},"o":{"a":0,"k":0},"m":1,"nm":"Trim Paths 1","hd":false},{"ty":"st","c":{"a":0,"k":[0.368781238794,0.35704728961,0.427450984716,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":[31.039,2.886]},"a":{"a":0,"k":[0,-48.25]},"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.092,-2.159],[0,-2.875],[0.003,16.045],[0.009,2.002]],"o":[[-0.081,1.877],[0,16.125],[-0.001,-2.716],[-0.016,-3.605]],"v":[[-10.958,-46.698],[-10.958,38.55],[11.03,38.964],[11.03,-46.031]],"c":true}},"nm":"Path 1","hd":false},{"ty":"tm","s":{"a":0,"k":0},"e":{"a":0,"k":46},"o":{"a":0,"k":0},"m":1,"nm":"Trim Paths 1","hd":false},{"ty":"st","c":{"a":0,"k":[0.541176497936,0.639215707779,0.733333349228,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":[31.039,2.886]},"a":{"a":0,"k":[0,-48.25]},"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":[[0.092,-2.159],[0,-2.875],[0.003,16.045],[0.009,2.002]],"o":[[-0.081,1.877],[0,16.125],[-0.001,-2.716],[-0.016,-3.605]],"v":[[-10.958,-46.698],[-10.958,38.55],[11.03,38.964],[11.03,-46.031]],"c":true}},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":0,"k":[0.230311438441,0.230311438441,0.250980407,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":8},"lc":2,"lj":2,"bm":0,"nm":"Stroke 2","hd":false},{"ty":"tr","p":{"a":0,"k":[31.039,2.886]},"a":{"a":0,"k":[0,-48.25]},"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.093,-1.619],[0,-2.155],[0.006,12.029],[0.009,1.501]],"o":[[-0.081,1.407],[0,12.089],[-0.001,-2.036],[-0.016,-2.703]],"v":[[-10.958,-47.433],[-10.958,16.477],[11.03,16.788],[11.03,-46.933]],"c":true}},"nm":"Path 1","hd":false},{"ty":"gf","o":{"a":0,"k":100},"r":1,"bm":0,"g":{"p":7,"k":{"a":0,"k":[0,0.459,0.459,0.537,0.34,0.449,0.388,0.435,0.448,0.439,0.318,0.333,0.48,0.388,0.296,0.312,0.507,0.337,0.275,0.29,0.58,0.349,0.239,0.253,1,0.361,0.204,0.216]}},"s":{"a":0,"k":[-8.075,-10.936]},"e":{"a":0,"k":[10.383,-11.04]},"t":1,"nm":"Gradient_DcdefVcIGF","hd":false},{"ty":"tr","p":{"a":0,"k":[31.039,2.886]},"a":{"a":0,"k":[0,-48.25]},"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":[[0.092,-2.159],[0,-2.875],[0.003,16.045],[0.009,2.002]],"o":[[-0.081,1.877],[0,16.125],[-0.001,-2.716],[-0.016,-3.605]],"v":[[-10.958,-46.698],[-10.958,38.55],[11.03,38.964],[11.03,-46.031]],"c":true}},"nm":"Path 1","hd":false},{"ty":"gf","o":{"a":0,"k":100},"r":1,"bm":0,"g":{"p":3,"k":{"a":0,"k":[0,0.69,0.769,0.843,0.5,0.79,0.849,0.9,1,0.89,0.929,0.957,0,1,0.5,0.5,1,0]}},"s":{"a":0,"k":[2.067,45.81]},"e":{"a":0,"k":[-0.253,40.575]},"t":1,"nm":"Gradient_d645ZclREg","hd":false},{"ty":"gf","o":{"a":0,"k":100},"r":1,"bm":0,"g":{"p":9,"k":{"a":0,"k":[0,0.694,0.738,0.773,0.226,0.847,0.869,0.886,0.298,1,1,1,0.465,0.72,0.659,0.667,0.598,0.439,0.318,0.333,0.642,0.388,0.296,0.312,0.68,0.337,0.275,0.29,0.727,0.416,0.378,0.373,1,0.494,0.481,0.455]}},"s":{"a":0,"k":[-8.075,-10.936]},"e":{"a":0,"k":[10.383,-11.04]},"t":1,"nm":"Gradient_qTVJFcKrra","hd":false},{"ty":"tr","p":{"a":0,"k":[31.039,2.886]},"a":{"a":0,"k":[0,-48.25]},"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":180.18018018018,"st":0,"bm":0},{"ddd":0,"ind":13,"ty":4,"nm":"R Ring Stick TOP","parent":14,"sr":1,"ks":{"r":{"a":0,"k":181},"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":104,"s":[112.541,34.267,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":137,"s":[111.233,29.391,0],"to":[0,0,0],"ti":[0,0,0]},{"t":148,"s":[113.58,35.681,0]}]},"a":{"a":0,"k":[30.044,72.438,0]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0,"y":1},"o":{"x":0.167,"y":0.167},"t":104,"s":[{"i":[[5.128,2.353],[-0.135,-1.609],[0.006,6.977],[0.667,0.829]],"o":[[0.029,1.055],[0.367,4.367],[-0.001,-1.181],[-8.453,2.294]],"v":[[-6.555,41.82],[-6.862,42.109],[12.513,39.685],[12.284,39.615]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0},"t":137,"s":[{"i":[[0.204,-2.446],[0.279,-2.772],[-2.437,13.363],[1.002,1.407]],"o":[[-0.098,0.491],[-1.563,15.549],[0.412,-2.262],[-6.579,-9.237]],"v":[[-13.623,27.371],[-14.822,30.328],[11.426,34.819],[12.04,28.883]],"c":true}]},{"t":148,"s":[{"i":[[4.295,-1.142],[0.1,-2.012],[-0.683,7.219],[0.582,0.921]],"o":[[-0.106,1.316],[-0.271,5.461],[0.116,-1.222],[-7.992,-0.156]],"v":[[-4.991,43.349],[-5.232,43.689],[12.879,43.215],[12.658,43.122]],"c":true}]}]},"nm":"Path 1","hd":false},{"ty":"tm","s":{"a":0,"k":0},"e":{"a":0,"k":11},"o":{"a":0,"k":125},"m":1,"nm":"Trim Paths 1","hd":false},{"ty":"st","c":{"a":0,"k":[0.870588243008,0.936953246593,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":[31.039,2.886]},"a":{"a":0,"k":[0,-48.25]},"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,"y":1},"o":{"x":0.167,"y":0.167},"t":104,"s":[{"i":[[5.205,1.01],[-0.16,-1.606],[0.006,6.977],[0.266,0.864]],"o":[[-0.247,1.037],[0.519,5.196],[-0.001,-1.181],[-7.877,1.108]],"v":[[-6.555,41.82],[-6.862,42.109],[12.513,39.685],[12.284,39.615]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0},"t":137,"s":[{"i":[[2.81,-5.654],[0.279,-2.772],[-2.437,13.363],[0.66,1.504]],"o":[[-0.284,0.562],[-1.563,15.549],[0.412,-2.262],[-3.301,-7.516]],"v":[[-13.623,27.371],[-14.822,30.328],[11.426,34.819],[12.04,28.883]],"c":true}]},{"t":148,"s":[{"i":[[4.301,-1.137],[0.083,-2.01],[-0.683,7.219],[0.18,0.919]],"o":[[-0.29,1.275],[-0.267,6.503],[0.116,-1.222],[-7.409,0.017]],"v":[[-4.991,43.349],[-5.232,43.689],[12.879,43.215],[12.658,43.122]],"c":true}]}]},"nm":"Path 1","hd":false},{"ty":"tm","s":{"a":0,"k":0},"e":{"a":0,"k":46},"o":{"a":0,"k":0},"m":1,"nm":"Trim Paths 1","hd":false},{"ty":"st","c":{"a":0,"k":[0.541176497936,0.639215707779,0.733333349228,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":[31.039,2.886]},"a":{"a":0,"k":[0,-48.25]},"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,"y":1},"o":{"x":0.167,"y":0.167},"t":104,"s":[{"i":[[9.338,6.426],[-0.225,-1.598],[0.006,6.977],[0.403,0.856]],"o":[[-0.865,-0.595],[0.821,5.825],[-0.001,-1.181],[-7.547,1.58]],"v":[[-6.555,41.82],[-6.862,42.109],[12.513,39.685],[12.284,39.615]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0},"t":137,"s":[{"i":[[4.776,-6.058],[0.279,-2.772],[-2.437,13.363],[0.559,1.598]],"o":[[-1.003,1.272],[-1.563,15.549],[0.412,-2.262],[-2.217,-6.339]],"v":[[-13.623,27.371],[-14.822,30.328],[11.426,34.819],[12.04,28.883]],"c":true}]},{"t":148,"s":[{"i":[[5.835,-0.626],[0.038,-2.004],[-0.683,7.219],[0.317,0.924]],"o":[[-0.823,0.088],[-0.138,7.305],[0.116,-1.222],[-7.341,-0.176]],"v":[[-4.991,43.349],[-5.232,43.689],[12.879,43.215],[12.658,43.122]],"c":true}]}]},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":0,"k":[0.36862745098,0.356862745098,0.427451010311,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":8},"lc":2,"lj":2,"bm":0,"nm":"Stroke 2","hd":false},{"ty":"tr","p":{"a":0,"k":[31.039,2.886]},"a":{"a":0,"k":[0,-48.25]},"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,"y":1},"o":{"x":0.167,"y":0.167},"t":104,"s":[{"i":[[6.046,1.813],[-0.311,-1.582],[0.006,6.977],[0.199,0.867]],"o":[[-0.283,1.031],[1.196,6.08],[-0.001,-1.181],[-9.029,1.134]],"v":[[-6.555,41.82],[-6.862,42.109],[12.513,39.685],[12.284,39.615]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0},"t":137,"s":[{"i":[[2.562,-5.849],[0.279,-2.772],[-2.437,13.363],[0.569,1.587]],"o":[[-0.649,1.481],[-1.563,15.549],[0.412,-2.262],[-2.386,-6.657]],"v":[[-13.623,27.371],[-14.822,30.328],[11.426,34.819],[12.04,28.883]],"c":true}]},{"t":148,"s":[{"i":[[4.043,-0.926],[-0.022,-1.989],[-0.683,7.219],[0.113,0.916]],"o":[[-0.314,1.266],[0.085,7.647],[0.116,-1.222],[-8.443,-0.897]],"v":[[-4.991,43.349],[-5.232,43.689],[12.879,43.215],[12.658,43.122]],"c":true}]}]},"nm":"Path 1","hd":false},{"ty":"gf","o":{"a":0,"k":100},"r":1,"bm":0,"g":{"p":3,"k":{"a":0,"k":[0,0.69,0.769,0.843,0.5,0.79,0.849,0.9,1,0.89,0.929,0.957,0,1,0.5,0.5,1,0]}},"s":{"a":0,"k":[2.067,45.81]},"e":{"a":0,"k":[-0.253,40.575]},"t":1,"nm":"Gradient_Xca79ManzR","hd":false},{"ty":"gf","o":{"a":0,"k":100},"r":1,"bm":0,"g":{"p":9,"k":{"a":0,"k":[0,0.694,0.738,0.773,0.226,0.847,0.869,0.886,0.298,1,1,1,0.465,0.72,0.659,0.667,0.598,0.439,0.318,0.333,0.642,0.388,0.296,0.312,0.68,0.337,0.275,0.29,0.727,0.416,0.378,0.373,1,0.494,0.481,0.455]}},"s":{"a":0,"k":[-8.075,-10.936]},"e":{"a":0,"k":[10.383,-11.04]},"t":1,"nm":"Gradient_H3pNrzwae8","hd":false},{"ty":"tr","p":{"a":0,"k":[31.039,2.886]},"a":{"a":0,"k":[0,-48.25]},"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":106,"op":146,"st":56,"bm":0},{"ddd":0,"ind":14,"ty":4,"nm":"R Ring","parent":15,"sr":1,"ks":{"r":{"a":1,"k":[{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":6,"s":[-180]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":11,"s":[-182]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":15,"s":[-178]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":19,"s":[-182]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":23,"s":[-178]},{"i":{"x":[0.842],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":27,"s":[-185]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":31,"s":[-177]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":34,"s":[-186]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":38,"s":[-177]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":42,"s":[-185]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":46,"s":[-177]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":50,"s":[-188]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":54,"s":[-176]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":57,"s":[-189]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":61,"s":[-175]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":65,"s":[-192]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":69,"s":[-175]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":73,"s":[-194]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":77,"s":[-177]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":81,"s":[-196]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":85,"s":[-177]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":89,"s":[-193]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":93,"s":[-174]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":97,"s":[-191]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":101,"s":[-177]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":109,"s":[-192]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":115,"s":[-175]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":120,"s":[-188]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":124,"s":[-174]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":128,"s":[-192]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":132,"s":[-175]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":136,"s":[-188]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":141,"s":[-178]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":145,"s":[-191]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":149,"s":[-177]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":153,"s":[-191]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":157,"s":[-177]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":161,"s":[-186]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":169,"s":[-176]},{"t":178,"s":[-180]}]},"p":{"a":0,"k":[30.042,58.423,0]},"a":{"a":0,"k":[111.522,53.259,0]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0.1,"y":1},"o":{"x":0.15,"y":0},"t":45,"s":[{"i":[[-8.534,-2.532],[-22.619,-0.194],[-5.458,2.05],[69.782,1.099]],"o":[[5.476,1.625],[22.185,0.192],[8.98,-3.374],[-72.252,-1.139]],"v":[[-82.988,31.634],[0.848,32.372],[82.542,31.023],[-0.113,-32.12]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.461,"y":0},"t":92,"s":[{"i":[[-7.94,-2.099],[-55.77,5.042],[-5.078,1.7],[64.934,0.03]],"o":[[5.095,1.347],[57.206,-5.172],[8.355,-2.796],[-59.259,-0.027]],"v":[[-77.213,22.617],[-6.137,-5.607],[76.798,22.11],[-0.105,-30.223]],"c":true}]},{"i":{"x":0,"y":1},"o":{"x":0.095,"y":0.173},"t":104,"s":[{"i":[[-8.534,-2.532],[-22.619,-0.194],[-5.458,2.05],[69.782,1.099]],"o":[[5.476,1.625],[22.185,0.192],[8.98,-3.374],[-72.252,-1.139]],"v":[[-82.988,31.634],[0.848,32.372],[82.542,31.023],[-0.113,-32.12]],"c":true}]},{"i":{"x":0,"y":1},"o":{"x":0.25,"y":0},"t":137,"s":[{"i":[[-5.395,-7.775],[-59.999,-1.12],[-5.946,2.155],[74.469,1.156]],"o":[[3.462,4.989],[63.083,1.177],[9.784,-3.546],[-77.105,-1.197]],"v":[[-94.364,29.658],[-6.026,54.164],[89.933,29.23],[-0.355,-38.888]],"c":true}]},{"t":179,"s":[{"i":[[-8.534,-2.532],[-22.619,-0.194],[-5.458,2.05],[69.782,1.099]],"o":[[5.476,1.625],[22.185,0.192],[8.98,-3.374],[-72.252,-1.139]],"v":[[-82.988,31.634],[0.848,32.372],[82.542,31.023],[-0.113,-32.12]],"c":true}]}]},"nm":"Path 1","hd":false},{"ty":"tm","s":{"a":0,"k":0},"e":{"a":0,"k":40},"o":{"a":0,"k":212},"m":1,"nm":"Trim Paths 1","hd":false},{"ty":"st","c":{"a":0,"k":[0.686274528503,0.166858896613,0.171260729432,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":8},"lc":2,"lj":2,"bm":0,"nm":"Stroke 2","hd":false},{"ty":"tr","p":{"a":0,"k":[111.522,53.259]},"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 8","bm":0,"hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0.1,"y":1},"o":{"x":0.15,"y":0},"t":45,"s":[{"i":[[-8.534,-2.532],[-22.619,-0.194],[-5.458,2.05],[69.782,1.099]],"o":[[5.476,1.625],[22.185,0.192],[8.98,-3.374],[-72.252,-1.139]],"v":[[-82.988,31.634],[0.848,32.372],[82.542,31.023],[-0.113,-32.12]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.461,"y":0},"t":92,"s":[{"i":[[-7.94,-2.099],[-49.286,3.854],[-5.078,1.7],[64.921,1.151]],"o":[[5.095,1.347],[53.843,-4.211],[8.355,-2.796],[-58.058,-1.029]],"v":[[-77.213,22.617],[-6.137,-5.607],[76.798,22.11],[-0.105,-30.223]],"c":true}]},{"i":{"x":0,"y":1},"o":{"x":0.095,"y":0.173},"t":104,"s":[{"i":[[-8.534,-2.532],[-22.619,-0.194],[-5.458,2.05],[69.782,1.099]],"o":[[5.476,1.625],[22.185,0.192],[8.98,-3.374],[-72.252,-1.139]],"v":[[-82.988,31.634],[0.848,32.372],[82.542,31.023],[-0.113,-32.12]],"c":true}]},{"i":{"x":0,"y":1},"o":{"x":0.25,"y":0},"t":137,"s":[{"i":[[-5.395,-7.775],[-64.326,-0.206],[-5.946,2.155],[74.469,1.156]],"o":[[3.462,4.989],[63.091,0.202],[9.784,-3.546],[-77.105,-1.197]],"v":[[-94.364,29.658],[-6.026,54.164],[89.933,29.23],[-0.355,-38.888]],"c":true}]},{"t":179,"s":[{"i":[[-8.534,-2.532],[-22.619,-0.194],[-5.458,2.05],[69.782,1.099]],"o":[[5.476,1.625],[22.185,0.192],[8.98,-3.374],[-72.252,-1.139]],"v":[[-82.988,31.634],[0.848,32.372],[82.542,31.023],[-0.113,-32.12]],"c":true}]}]},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":0,"k":[0.450980424881,0.054901964962,0.054901964962,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":[111.522,53.259]},"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.1,"y":1},"o":{"x":0.15,"y":0},"t":45,"s":[{"i":[[-1.405,-9.497],[-66.911,2.535],[-0.032,4.359],[69.782,1.099]],"o":[[0.865,5.848],[62.523,-2.368],[0.05,-6.815],[-72.252,-1.139]],"v":[[-83.81,28.334],[-2.427,-21.287],[83.52,25.969],[-0.113,-32.12]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.461,"y":0},"t":92,"s":[{"i":[[-1.307,-7.871],[-62.254,2.101],[-0.03,3.612],[64.93,0.643]],"o":[[0.805,4.847],[58.172,-1.963],[0.047,-5.648],[-55.981,-0.554]],"v":[[-77.977,19.882],[-2.259,-21.245],[77.708,17.921],[-0.105,-30.223]],"c":true}]},{"i":{"x":0,"y":1},"o":{"x":0.095,"y":0.173},"t":104,"s":[{"i":[[-1.405,-9.497],[-66.911,2.535],[-0.032,4.359],[69.782,1.099]],"o":[[0.865,5.848],[62.523,-2.368],[0.05,-6.815],[-72.252,-1.139]],"v":[[-83.81,28.334],[-2.427,-21.287],[83.52,25.969],[-0.113,-32.12]],"c":true}]},{"i":{"x":0,"y":1},"o":{"x":0.25,"y":0},"t":137,"s":[{"i":[[5.428,-8.626],[-71.405,2.664],[-0.035,4.581],[74.469,1.156]],"o":[[-3.342,5.311],[66.722,-2.489],[0.055,-7.163],[-77.105,-1.197]],"v":[[-92.757,26.437],[-2.826,-27.501],[90.998,23.918],[-0.355,-38.888]],"c":true}]},{"t":179,"s":[{"i":[[-1.405,-9.497],[-66.911,2.535],[-0.032,4.359],[69.782,1.099]],"o":[[0.865,5.848],[62.523,-2.368],[0.05,-6.815],[-72.252,-1.139]],"v":[[-83.81,28.334],[-2.427,-21.287],[83.52,25.969],[-0.113,-32.12]],"c":true}]}]},"nm":"Path 1","hd":false},{"ty":"gf","o":{"a":0,"k":100},"r":1,"bm":0,"g":{"p":3,"k":{"a":0,"k":[0,0.945,0.498,0.518,0.5,0.945,0.498,0.518,1,0.945,0.498,0.518,0,1,0.5,0.5,1,0]}},"s":{"a":0,"k":[-36.325,-17.949]},"e":{"a":0,"k":[48.406,6.767]},"t":2,"h":{"a":0,"k":0},"a":{"a":0,"k":0},"nm":"Gradient_Skmp1PWsCH","hd":false},{"ty":"tr","p":{"a":0,"k":[111.522,53.259]},"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.037,"y":1},"o":{"x":0.096,"y":0},"t":45,"s":[{"i":[[-0.156,-4.733],[1.438,2.939]],"o":[[0.354,10.733],[-3.772,-7.707]],"v":[[-60.585,19.085],[-45.901,12.953]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.461,"y":0},"t":92,"s":[{"i":[[-3.35,-3.184],[1.936,2.093]],"o":[[7.503,7.13],[-5.664,-6.121]],"v":[[-29.339,-11.699],[-29.716,-11.295]],"c":true}]},{"i":{"x":0,"y":1},"o":{"x":0.095,"y":0.173},"t":104,"s":[{"i":[[-0.156,-4.733],[1.438,2.939]],"o":[[0.354,10.733],[-3.772,-7.707]],"v":[[-60.585,19.085],[-45.901,12.953]],"c":true}]},{"i":{"x":0,"y":1},"o":{"x":0.25,"y":0},"t":137,"s":[{"i":[[-0.582,-6.4],[2.233,3.823]],"o":[[1.319,14.513],[-5.856,-10.026]],"v":[[-66.651,33.732],[-46.629,23.768]],"c":true}]},{"t":179,"s":[{"i":[[-0.156,-4.733],[1.438,2.939]],"o":[[0.354,10.733],[-3.772,-7.707]],"v":[[-60.585,19.085],[-45.901,12.953]],"c":true}]}]},"nm":"Path 1","hd":false},{"ty":"gf","o":{"a":0,"k":100},"r":1,"bm":0,"g":{"p":3,"k":{"a":0,"k":[0,0.863,0.357,0.333,0.5,0.863,0.333,0.302,1,0.863,0.31,0.271]}},"s":{"a":0,"k":[-33.342,-10.435]},"e":{"a":0,"k":[-26.658,-3.709]},"t":1,"nm":"Gradient_kPNCr1W47U","hd":false},{"ty":"tr","p":{"a":0,"k":[198.522,52.708]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":70},"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.037,"y":1},"o":{"x":0.096,"y":0},"t":45,"s":[{"i":[[-4.895,-4.426],[-2.347,2.749],[5.923,-2.694],[1.05,-2.963]],"o":[[4.838,4.375],[4.442,-5.202],[-7.476,3.4],[-1.418,4]],"v":[[-42.7,8.809],[-18.683,0.08],[-36.805,-14.202],[-35.427,-2.44]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.461,"y":0},"t":92,"s":[{"i":[[-4.555,-3.668],[-0.944,0.055],[5.791,-1.574],[-0.842,-1.564]],"o":[[4.502,3.626],[2.716,-1.089],[-4.354,1.183],[0.891,1.654]],"v":[[-32.066,-11.108],[-23.438,-3.442],[-39.307,-16.908],[-37.404,-14.5]],"c":true}]},{"i":{"x":0,"y":1},"o":{"x":0.095,"y":0.173},"t":104,"s":[{"i":[[-4.895,-4.426],[-2.347,2.749],[5.923,-2.694],[1.05,-2.963]],"o":[[4.838,4.375],[4.442,-5.202],[-7.476,3.4],[-1.418,4]],"v":[[-42.7,8.809],[-18.683,0.08],[-36.805,-14.202],[-35.427,-2.44]],"c":true}]},{"i":{"x":0,"y":1},"o":{"x":0.25,"y":0},"t":137,"s":[{"i":[[-5.113,-4.894],[-7.085,13.307],[8.376,-3.995],[1.144,-3.115]],"o":[[6.747,6.458],[3.407,-6.399],[-8.028,3.829],[-1.544,4.205]],"v":[[-45.581,13.25],[-12.093,-2.44],[-34.363,-15.812],[-39.707,-2.409]],"c":true}]},{"t":179,"s":[{"i":[[-4.895,-4.426],[-2.347,2.749],[5.923,-2.694],[1.05,-2.963]],"o":[[4.838,4.375],[4.442,-5.202],[-7.476,3.4],[-1.418,4]],"v":[[-42.7,8.809],[-18.683,0.08],[-36.805,-14.202],[-35.427,-2.44]],"c":true}]}]},"nm":"Path 1","hd":false},{"ty":"gf","o":{"a":0,"k":100},"r":1,"bm":0,"g":{"p":3,"k":{"a":0,"k":[0,0.863,0.357,0.333,0.5,0.863,0.333,0.302,1,0.863,0.31,0.271]}},"s":{"a":0,"k":[-33.342,-10.435]},"e":{"a":0,"k":[-26.658,-3.709]},"t":1,"nm":"Gradient_Od5j54Tv2S","hd":false},{"ty":"tr","p":{"a":0,"k":[198.522,52.708]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":70},"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.1,"y":1},"o":{"x":0.15,"y":0},"t":45,"s":[{"i":[[3.589,-4.185],[-3.901,3.677],[25.06,10.459],[4.19,-11.996]],"o":[[-2.635,3.073],[7.382,-6.959],[-1.86,-0.776],[-5.69,16.288]],"v":[[-84.138,30.67],[-4.009,31.558],[-40.428,-19.087],[-50.601,8.769]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.461,"y":0},"t":92,"s":[{"i":[[3.337,-3.471],[-3.629,3.047],[23.316,8.669],[5.506,-2.527]],"o":[[49.999,-1.237],[6.868,-5.767],[-1.73,-0.643],[-6.407,2.94]],"v":[[-91.264,-6.924],[-9.784,22.648],[-43.669,-19.327],[-54.737,-10.923]],"c":true}]},{"i":{"x":0,"y":1},"o":{"x":0.095,"y":0.173},"t":104,"s":[{"i":[[3.589,-4.185],[-3.901,3.677],[25.06,10.459],[4.19,-11.996]],"o":[[-2.635,3.073],[7.382,-6.959],[-1.86,-0.776],[-5.69,16.288]],"v":[[-84.138,30.67],[-4.009,31.558],[-40.428,-19.087],[-50.601,8.769]],"c":true}]},{"i":{"x":0,"y":1},"o":{"x":0.25,"y":0},"t":137,"s":[{"i":[[27.768,-9.339],[-4.25,3.864],[27.303,10.993],[-2.486,-13.178]],"o":[[26.554,4.044],[8.043,-7.314],[-2.026,-0.816],[4.814,25.523]],"v":[[-91.428,52.577],[3.423,29.764],[-36.258,-23.466],[-47.759,2.916]],"c":true}]},{"t":179,"s":[{"i":[[3.589,-4.186],[-3.901,3.677],[25.06,10.459],[4.19,-11.996]],"o":[[-2.635,3.073],[7.382,-6.959],[-1.86,-0.776],[-5.69,16.288]],"v":[[-84.138,30.67],[-4.009,31.558],[-40.428,-19.087],[-50.601,8.769]],"c":true}]}]},"nm":"Path 1","hd":false},{"ty":"gf","o":{"a":0,"k":100},"r":1,"bm":0,"g":{"p":3,"k":{"a":0,"k":[0,0.443,0.098,0.102,0.5,0.563,0.112,0.116,1,0.682,0.125,0.129,0,1,0.593,1,0.733,1,0.866,0.775,1,0.55]}},"s":{"a":1,"k":[{"i":{"x":0.1,"y":1},"o":{"x":0.15,"y":0},"t":45,"s":[-22.533,24.226],"to":[0,0],"ti":[0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.461,"y":0},"t":92,"s":[-27.012,6.492],"to":[0,0],"ti":[0,0]},{"i":{"x":0,"y":1},"o":{"x":0.095,"y":0.06},"t":104,"s":[-22.533,24.226],"to":[0,0],"ti":[0,0]},{"i":{"x":0,"y":1},"o":{"x":0.25,"y":0},"t":137,"s":[-15.631,38.68],"to":[0,0],"ti":[0,0]},{"t":179,"s":[-22.533,24.226]}]},"e":{"a":1,"k":[{"i":{"x":0.1,"y":1},"o":{"x":0.15,"y":0},"t":45,"s":[-35.369,4.579],"to":[0,0],"ti":[0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.461,"y":0},"t":92,"s":[-54.969,-14.879],"to":[0,0],"ti":[0,0]},{"i":{"x":0,"y":1},"o":{"x":0.095,"y":0.023},"t":104,"s":[-35.369,4.579],"to":[0,0],"ti":[0,0]},{"i":{"x":0,"y":1},"o":{"x":0.25,"y":0},"t":137,"s":[-37.39,8.216],"to":[0,0],"ti":[0,0]},{"t":179,"s":[-35.369,4.579]}]},"t":1,"nm":"Gradient_HxJsZ53byF","hd":false},{"ty":"tr","p":{"a":0,"k":[198.522,52.708]},"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.1,"y":1},"o":{"x":0.15,"y":0},"t":45,"s":[{"i":[[-8.534,-4.083],[-22.619,-0.316],[-5.458,3.306],[69.782,1.774]],"o":[[5.476,2.62],[22.185,0.31],[8.98,-5.44],[-72.252,-1.836]],"v":[[-82.988,50.46],[0.848,51.65],[82.542,49.475],[-0.113,-52.331]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.461,"y":0},"t":92,"s":[{"i":[[-7.94,-3.384],[-47.941,3.454],[-5.078,2.74],[64.882,2.582]],"o":[[5.095,2.171],[50.834,-3.662],[8.355,-4.509],[-59.602,-2.372]],"v":[[-77.213,35.818],[-6.138,-11.254],[76.798,35.002],[-0.105,-49.376]],"c":true}]},{"i":{"x":0,"y":1},"o":{"x":0.095,"y":0.173},"t":104,"s":[{"i":[[-8.534,-4.083],[-22.619,-0.316],[-5.458,3.306],[69.782,1.774]],"o":[[5.476,2.62],[22.185,0.31],[8.98,-5.44],[-72.252,-1.836]],"v":[[-82.988,50.46],[0.848,51.65],[82.542,49.475],[-0.113,-52.331]],"c":true}]},{"i":{"x":0,"y":1},"o":{"x":0.25,"y":0},"t":137,"s":[{"i":[[-5.452,-12.846],[-64.326,-0.332],[-5.946,3.475],[74.469,1.864]],"o":[[3.499,8.243],[63.092,0.325],[9.784,-5.718],[-77.105,-1.93]],"v":[[-93.419,47.599],[-6.026,87.852],[89.933,46.373],[-0.355,-63.549]],"c":true}]},{"t":179,"s":[{"i":[[-8.534,-4.083],[-22.619,-0.316],[-5.458,3.306],[69.782,1.774]],"o":[[5.476,2.62],[22.185,0.31],[8.98,-5.44],[-72.252,-1.836]],"v":[[-82.988,50.46],[0.848,51.65],[82.542,49.475],[-0.113,-52.331]],"c":true}]}]},"nm":"Path 1","hd":false},{"ty":"gf","o":{"a":0,"k":100},"r":1,"bm":0,"g":{"p":3,"k":{"a":0,"k":[0,0.988,0.482,0.498,0.5,0.988,0.482,0.498,1,0.988,0.482,0.498,0,1,0.5,0.5,1,0]}},"s":{"a":0,"k":[-32.885,23.698]},"e":{"a":0,"k":[-1.232,18.308]},"t":2,"h":{"a":0,"k":29.579},"a":{"a":0,"k":98.388},"nm":"Gradient_3FlT1kHBp4","hd":false},{"ty":"gf","o":{"a":0,"k":100},"r":1,"bm":0,"g":{"p":3,"k":{"a":0,"k":[0,0.831,0.263,0.314,0.5,0.792,0.229,0.284,1,0.753,0.196,0.255]}},"s":{"a":0,"k":[-18.73,30.589]},"e":{"a":0,"k":[3.602,-29.37]},"t":1,"nm":"Gradient_ukVJigAcVW","hd":false},{"ty":"tr","p":{"a":0,"k":[111.522,53.259]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,60]},"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":180.18018018018,"st":0,"bm":0},{"ddd":0,"ind":15,"ty":4,"nm":"R Ring Stick","parent":18,"sr":1,"ks":{"r":{"a":1,"k":[{"i":{"x":[0.1],"y":[1]},"o":{"x":[0.15],"y":[0]},"t":45,"s":[220]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.3],"y":[0]},"t":92,"s":[215]},{"i":{"x":[0],"y":[1]},"o":{"x":[0.095],"y":[0.142]},"t":104,"s":[220]},{"i":{"x":[0],"y":[1]},"o":{"x":[0.25],"y":[0]},"t":137,"s":[216]},{"t":179,"s":[220]}]},"p":{"a":1,"k":[{"i":{"x":0.1,"y":1},"o":{"x":0.15,"y":0},"t":45,"s":[332.592,81.081,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.3,"y":0},"t":92,"s":[302.636,81.419,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0,"y":1},"o":{"x":0.095,"y":0.091},"t":104,"s":[332.584,82.081,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0,"y":1},"o":{"x":0.25,"y":0},"t":137,"s":[315.143,78.299,0],"to":[0,0,0],"ti":[0,0,0]},{"t":179,"s":[332.592,81.081,0]}]},"a":{"a":0,"k":[31.164,2.761,0]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[0.092,-2.159],[0,-2.875],[0.003,16.045],[0.009,2.002]],"o":[[-0.081,1.877],[0,16.125],[-0.001,-2.716],[-0.016,-3.605]],"v":[[-10.958,-46.698],[-10.958,38.55],[11.03,38.964],[11.03,-46.031]],"c":true}},"nm":"Path 1","hd":false},{"ty":"tm","s":{"a":0,"k":0},"e":{"a":0,"k":2},"o":{"a":0,"k":168},"m":1,"nm":"Trim Paths 1","hd":false},{"ty":"st","c":{"a":0,"k":[0.783590912819,0.886525690556,0.984313726425,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":[31.039,2.886]},"a":{"a":0,"k":[0,-48.25]},"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.092,-2.159],[0,-2.875],[0.003,16.045],[0.009,2.002]],"o":[[-0.081,1.877],[0,16.125],[-0.001,-2.716],[-0.016,-3.605]],"v":[[-10.958,-46.698],[-10.958,38.55],[11.03,38.964],[11.03,-46.031]],"c":true}},"nm":"Path 1","hd":false},{"ty":"tm","s":{"a":0,"k":0},"e":{"a":0,"k":39},"o":{"a":0,"k":0},"m":1,"nm":"Trim Paths 2","hd":false},{"ty":"st","c":{"a":0,"k":[0.23137255013,0.23137255013,0.258823543787,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":8},"lc":2,"lj":2,"bm":0,"nm":"Stroke 3","hd":false},{"ty":"tr","p":{"a":0,"k":[31.039,2.886]},"a":{"a":0,"k":[0,-48.25]},"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.092,-2.159],[0,-2.875],[0.003,16.045],[0.009,2.002]],"o":[[-0.081,1.877],[0,16.125],[-0.001,-2.716],[-0.016,-3.605]],"v":[[-10.958,-46.698],[-10.958,38.55],[11.03,38.964],[11.03,-46.031]],"c":true}},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":0,"k":[0.487197250128,0.570088624954,0.647058844566,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":8},"lc":2,"lj":2,"bm":0,"nm":"Stroke 2","hd":false},{"ty":"tr","p":{"a":0,"k":[31.039,2.886]},"a":{"a":0,"k":[0,-48.25]},"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.092,-2.159],[0,-2.875],[0.003,16.045],[0.009,2.002]],"o":[[-0.081,1.877],[0,16.125],[-0.001,-2.716],[-0.016,-3.605]],"v":[[-10.958,-46.698],[-10.958,38.55],[11.03,38.964],[11.03,-46.031]],"c":true}},"nm":"Path 1","hd":false},{"ty":"gf","o":{"a":0,"k":100},"r":1,"bm":0,"g":{"p":3,"k":{"a":0,"k":[0,0.69,0.769,0.843,0.5,0.79,0.849,0.9,1,0.89,0.929,0.957,0,1,0.5,0.5,1,0]}},"s":{"a":0,"k":[4.946,45.352]},"e":{"a":0,"k":[-1.019,41.218]},"t":1,"nm":"Gradient_LdrvkV2B0z","hd":false},{"ty":"gf","o":{"a":0,"k":100},"r":1,"bm":0,"g":{"p":9,"k":{"a":0,"k":[0,0.494,0.481,0.455,0.104,0.416,0.378,0.373,0.207,0.337,0.275,0.29,0.259,0.388,0.296,0.312,0.307,0.439,0.318,0.333,0.462,0.567,0.527,0.553,0.635,0.694,0.737,0.773,0.839,0.694,0.737,0.773,1,0.694,0.738,0.773]}},"s":{"a":0,"k":[-7.183,-10.772]},"e":{"a":0,"k":[11.184,-10.907]},"t":1,"nm":"Gradient_YavTzocNWf","hd":false},{"ty":"tr","p":{"a":0,"k":[31.039,2.886]},"a":{"a":0,"k":[0,-48.25]},"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}],"ip":0,"op":180.18018018018,"st":0,"bm":0},{"ddd":0,"ind":16,"ty":4,"nm":"Leg L","parent":18,"sr":1,"ks":{"r":{"a":1,"k":[{"i":{"x":[0.1],"y":[1]},"o":{"x":[0.15],"y":[0]},"t":45,"s":[41]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.3],"y":[0]},"t":92,"s":[33]},{"i":{"x":[0],"y":[1]},"o":{"x":[0.095],"y":[0.131]},"t":104,"s":[41]},{"i":{"x":[0],"y":[1]},"o":{"x":[0.25],"y":[0]},"t":137,"s":[33]},{"t":179,"s":[41]}]},"p":{"a":1,"k":[{"i":{"x":0.1,"y":1},"o":{"x":0.15,"y":0},"t":45,"s":[103.592,354.581,0],"to":[0.514,-0.824,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.3,"y":0},"t":92,"s":[106.679,349.635,0],"to":[0,0,0],"ti":[-0.364,1.995,0]},{"i":{"x":0,"y":1},"o":{"x":0.095,"y":0.079},"t":104,"s":[103.592,354.581,0],"to":[0.364,-1.995,0],"ti":[0,0,0]},{"i":{"x":0,"y":1},"o":{"x":0.25,"y":0},"t":137,"s":[108.866,337.664,0],"to":[0,0,0],"ti":[0.879,-2.82,0]},{"t":179,"s":[103.592,354.581,0]}]},"a":{"a":0,"k":[31.164,2.761,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.15,"y":0},"t":45,"s":[{"i":[[0.092,-2.159],[0,-2.875],[0.003,16.045],[0.009,2.002]],"o":[[-0.081,1.877],[0,16.125],[-0.001,-2.716],[-0.016,-3.605]],"v":[[-10.958,-46.698],[-10.958,14.677],[11.03,15.091],[11.03,-46.031]],"c":true}]},{"i":{"x":0.1,"y":1},"o":{"x":0.167,"y":0.167},"t":54,"s":[{"i":[[-0.037,-5.131],[0,-2.875],[0.003,16.045],[-0.052,2]],"o":[[-0.027,1.878],[0,16.125],[-0.001,-2.716],[0.356,-7.634]],"v":[[-10.936,-40.563],[-10.958,14.677],[11.03,15.091],[11.645,-34.251]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.3,"y":0},"t":92,"s":[{"i":[[-0.202,-8.928],[0,-2.875],[0.003,16.045],[-0.13,1.998]],"o":[[0.043,1.878],[0,16.125],[-0.001,-2.716],[0.831,-12.783]],"v":[[-10.74,-41.725],[-10.958,14.677],[11.03,15.091],[11.185,-37.52]],"c":true}]},{"t":104,"s":[{"i":[[0.092,-2.159],[0,-2.875],[0.003,16.045],[0.009,2.002]],"o":[[-0.081,1.877],[0,16.125],[-0.001,-2.716],[-0.016,-3.605]],"v":[[-10.958,-46.698],[-10.958,14.677],[11.03,15.091],[11.03,-46.031]],"c":true}]}]},"nm":"Path 1","hd":false},{"ty":"tm","s":{"a":0,"k":0},"e":{"a":0,"k":7},"o":{"a":0,"k":143},"m":1,"nm":"Trim Paths 1","hd":false},{"ty":"st","c":{"a":0,"k":[0.250980407,0.262745112181,0.270588248968,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":[31.039,2.886]},"a":{"a":0,"k":[0,-48.25]},"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.833,"y":0.833},"o":{"x":0.15,"y":0},"t":45,"s":[{"i":[[0.092,-2.159],[0,-2.875],[0.003,16.045],[0.009,2.002]],"o":[[-0.081,1.877],[0,16.125],[-0.001,-2.716],[-0.016,-3.605]],"v":[[-10.958,-46.698],[-10.958,14.677],[11.03,15.091],[11.03,-46.031]],"c":true}]},{"i":{"x":0.1,"y":1},"o":{"x":0.167,"y":0.167},"t":54,"s":[{"i":[[-0.047,-5.253],[0,-2.875],[0.003,16.045],[-0.046,2.001]],"o":[[-0.025,1.878],[0,16.125],[-0.001,-2.716],[0.318,-7.643]],"v":[[-10.936,-40.563],[-10.958,14.677],[11.03,15.091],[11.645,-34.251]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.3,"y":0},"t":92,"s":[{"i":[[-0.224,-9.207],[0,-2.875],[0.003,16.045],[-0.116,1.999]],"o":[[0.046,1.878],[0,16.125],[-0.001,-2.716],[0.746,-12.804]],"v":[[-10.74,-41.725],[-10.958,14.677],[11.03,15.091],[11.185,-37.52]],"c":true}]},{"t":104,"s":[{"i":[[0.092,-2.159],[0,-2.875],[0.003,16.045],[0.009,2.002]],"o":[[-0.081,1.877],[0,16.125],[-0.001,-2.716],[-0.016,-3.605]],"v":[[-10.958,-46.698],[-10.958,14.677],[11.03,15.091],[11.03,-46.031]],"c":true}]}]},"nm":"Path 1","hd":false},{"ty":"tm","s":{"a":0,"k":0},"e":{"a":0,"k":38},"o":{"a":0,"k":0},"m":1,"nm":"Trim Paths 1","hd":false},{"ty":"st","c":{"a":0,"k":[0.685628592968,0.72256487608,0.75686275959,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":[31.039,2.886]},"a":{"a":0,"k":[0,-48.25]},"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.833,"y":0.833},"o":{"x":0.15,"y":0},"t":45,"s":[{"i":[[0.092,-2.159],[0,-2.875],[0.003,16.045],[0.009,2.002]],"o":[[-0.081,1.877],[0,16.125],[-0.001,-2.716],[-0.016,-3.605]],"v":[[-10.958,-46.698],[-10.958,14.677],[11.03,15.091],[11.03,-46.031]],"c":true}]},{"i":{"x":0.1,"y":1},"o":{"x":0.167,"y":0.167},"t":54,"s":[{"i":[[0.005,-5.22],[0,-2.875],[0.003,16.045],[-0.052,2]],"o":[[-0.036,1.878],[0,16.125],[-0.001,-2.716],[0.361,-7.733]],"v":[[-10.936,-40.563],[-10.958,14.677],[11.03,15.091],[11.645,-34.251]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.3,"y":0},"t":92,"s":[{"i":[[-0.106,-9.132],[0,-2.875],[0.003,16.045],[-0.129,1.998]],"o":[[0.022,1.879],[0,16.125],[-0.001,-2.716],[0.842,-13.008]],"v":[[-10.74,-41.725],[-10.958,14.677],[11.03,15.091],[11.185,-37.52]],"c":true}]},{"t":104,"s":[{"i":[[0.092,-2.159],[0,-2.875],[0.003,16.045],[0.009,2.002]],"o":[[-0.081,1.877],[0,16.125],[-0.001,-2.716],[-0.016,-3.605]],"v":[[-10.958,-46.698],[-10.958,14.677],[11.03,15.091],[11.03,-46.031]],"c":true}]}]},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":0,"k":[0.324675142765,0.324675142765,0.35686275363,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":[31.039,2.886]},"a":{"a":0,"k":[0,-48.25]},"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.833,"y":0.833},"o":{"x":0.15,"y":0},"t":45,"s":[{"i":[[0.092,-2.159],[0,-2.875],[0.003,16.045],[0.009,2.002]],"o":[[-0.081,1.877],[0,16.125],[-0.001,-2.716],[-0.016,-3.605]],"v":[[-10.958,-46.698],[-10.958,14.677],[11.03,15.091],[11.03,-46.031]],"c":true}]},{"i":{"x":0.1,"y":1},"o":{"x":0.167,"y":0.167},"t":54,"s":[{"i":[[0.584,-5.216],[0,-2.875],[0.003,16.045],[0.046,2.001]],"o":[[-0.154,1.871],[0,16.125],[-0.001,-2.716],[-0.279,-7.892]],"v":[[-10.936,-40.563],[-10.958,14.677],[11.03,15.091],[11.645,-34.251]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.3,"y":0},"t":92,"s":[{"i":[[1.213,-9.122],[0,-2.875],[0.003,16.045],[0.092,2]],"o":[[-0.248,1.862],[0,16.125],[-0.001,-2.716],[-0.616,-13.371]],"v":[[-10.74,-41.725],[-10.958,14.677],[11.03,15.091],[11.185,-37.52]],"c":true}]},{"t":104,"s":[{"i":[[0.092,-2.159],[0,-2.875],[0.003,16.045],[0.009,2.002]],"o":[[-0.081,1.877],[0,16.125],[-0.001,-2.716],[-0.016,-3.605]],"v":[[-10.958,-46.698],[-10.958,14.677],[11.03,15.091],[11.03,-46.031]],"c":true}]}]},"nm":"Path 1","hd":false},{"ty":"gf","o":{"a":0,"k":100},"r":1,"bm":0,"g":{"p":3,"k":{"a":0,"k":[0,0.38,0.294,0.31,0.5,0.38,0.294,0.31,1,0.38,0.294,0.31,0,1,0.5,0.5,1,0]}},"s":{"a":0,"k":[3.018,20.173]},"e":{"a":0,"k":[0.124,14.457]},"t":1,"nm":"Gradient_0Qi9QDxYHr","hd":false},{"ty":"gf","o":{"a":0,"k":100},"r":1,"bm":0,"g":{"p":9,"k":{"a":0,"k":[0,0.694,0.738,0.773,0.226,0.847,0.869,0.886,0.298,1,1,1,0.465,0.72,0.659,0.667,0.598,0.439,0.318,0.333,0.642,0.388,0.296,0.312,0.68,0.337,0.275,0.29,0.727,0.416,0.378,0.373,1,0.494,0.481,0.455]}},"s":{"a":0,"k":[-10.924,-11.042]},"e":{"a":0,"k":[9.326,-10.948]},"t":1,"nm":"Gradient_vAUlT89YEb","hd":false},{"ty":"tr","p":{"a":0,"k":[31.039,2.886]},"a":{"a":0,"k":[0,-48.25]},"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":180.18018018018,"st":0,"bm":0},{"ddd":0,"ind":17,"ty":4,"nm":"Leg R","parent":18,"sr":1,"ks":{"r":{"a":1,"k":[{"i":{"x":[0.1],"y":[1]},"o":{"x":[0.15],"y":[0]},"t":45,"s":[-41]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.3],"y":[0]},"t":92,"s":[-30]},{"i":{"x":[0],"y":[1]},"o":{"x":[0.095],"y":[0.131]},"t":104,"s":[-41]},{"i":{"x":[0],"y":[1]},"o":{"x":[0.25],"y":[0]},"t":137,"s":[-33]},{"t":179,"s":[-41]}]},"p":{"a":1,"k":[{"i":{"x":0.1,"y":1},"o":{"x":0.15,"y":0},"t":45,"s":[331.592,354.581,0],"to":[-1.129,-2.187,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.3,"y":0},"t":92,"s":[324.82,341.461,0],"to":[0,0,0],"ti":[0.121,-2.167,0]},{"i":{"x":0,"y":1},"o":{"x":0.095,"y":0.059},"t":104,"s":[331.592,354.581,0],"to":[-0.121,2.167,0],"ti":[0,0,0]},{"i":{"x":0,"y":1},"o":{"x":0.25,"y":0},"t":137,"s":[324.093,354.46,0],"to":[0,0,0],"ti":[-1.25,-0.02,0]},{"t":179,"s":[331.592,354.581,0]}]},"a":{"a":0,"k":[31.164,2.761,0]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0,"y":1},"o":{"x":0.095,"y":0.173},"t":104,"s":[{"i":[[0.092,-2.159],[0,-2.875],[0.003,16.045],[0.009,2.002]],"o":[[-0.081,1.877],[0,16.125],[-0.001,-2.716],[-0.016,-3.605]],"v":[[-10.958,-46.698],[-10.958,14.677],[11.03,15.091],[11.03,-46.031]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.25,"y":0},"t":137,"s":[{"i":[[0.24,-10.615],[0,-2.875],[0.003,16.045],[0.025,2.002]],"o":[[-0.042,1.878],[0,16.125],[-0.001,-2.716],[-0.147,-11.818]],"v":[[-10.42,-42.57],[-10.958,14.677],[11.03,15.091],[11.638,-42.007]],"c":true}]},{"i":{"x":0,"y":1},"o":{"x":0.167,"y":0.167},"t":148,"s":[{"i":[[0.151,-5.544],[0,-2.875],[0.003,16.045],[0.015,2.002]],"o":[[-0.066,1.878],[0,16.125],[-0.001,-2.716],[-0.069,-6.893]],"v":[[-9.962,-36.944],[-10.958,14.677],[11.03,15.091],[12.054,-36.318]],"c":true}]},{"t":179,"s":[{"i":[[0.092,-2.159],[0,-2.875],[0.003,16.045],[0.009,2.002]],"o":[[-0.081,1.877],[0,16.125],[-0.001,-2.716],[-0.016,-3.605]],"v":[[-10.958,-46.698],[-10.958,14.677],[11.03,15.091],[11.03,-46.031]],"c":true}]}]},"nm":"Path 1","hd":false},{"ty":"tm","s":{"a":0,"k":0},"e":{"a":0,"k":47},"o":{"a":0,"k":0},"m":1,"nm":"Trim Paths 2","hd":false},{"ty":"st","c":{"a":0,"k":[0.23137255013,0.23137255013,0.258823543787,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":8},"lc":2,"lj":2,"bm":0,"nm":"Stroke 2","hd":false},{"ty":"tr","p":{"a":0,"k":[31.039,2.886]},"a":{"a":0,"k":[0,-48.25]},"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,"y":1},"o":{"x":0.095,"y":0.173},"t":104,"s":[{"i":[[0.092,-2.159],[0,-2.875],[0.003,16.045],[0.009,2.002]],"o":[[-0.081,1.877],[0,16.125],[-0.001,-2.716],[-0.016,-3.605]],"v":[[-10.958,-46.698],[-10.958,14.677],[11.03,15.091],[11.03,-46.031]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.25,"y":0},"t":137,"s":[{"i":[[0.375,-9.921],[0,-2.875],[0.003,16.045],[-0.01,2.002]],"o":[[-0.071,1.877],[0,16.125],[-0.001,-2.716],[0.066,-13.03]],"v":[[-10.42,-42.57],[-10.958,14.677],[11.03,15.091],[11.638,-42.007]],"c":true}]},{"i":{"x":0,"y":1},"o":{"x":0.167,"y":0.167},"t":148,"s":[{"i":[[0.205,-5.266],[0,-2.875],[0.003,16.045],[0.001,2.002]],"o":[[-0.077,1.877],[0,16.125],[-0.001,-2.716],[0.017,-7.378]],"v":[[-9.962,-36.944],[-10.958,14.677],[11.03,15.091],[12.054,-36.318]],"c":true}]},{"t":179,"s":[{"i":[[0.092,-2.159],[0,-2.875],[0.003,16.045],[0.009,2.002]],"o":[[-0.081,1.877],[0,16.125],[-0.001,-2.716],[-0.016,-3.605]],"v":[[-10.958,-46.698],[-10.958,14.677],[11.03,15.091],[11.03,-46.031]],"c":true}]}]},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":0,"k":[0.487197250128,0.570088624954,0.647058844566,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":8},"lc":2,"lj":2,"bm":0,"nm":"Stroke 2","hd":false},{"ty":"tr","p":{"a":0,"k":[31.039,2.886]},"a":{"a":0,"k":[0,-48.25]},"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,"y":1},"o":{"x":0.095,"y":0.173},"t":104,"s":[{"i":[[0.092,-2.159],[0,-2.875],[0.003,16.045],[0.009,2.002]],"o":[[-0.081,1.877],[0,16.125],[-0.001,-2.716],[-0.016,-3.605]],"v":[[-10.958,-46.698],[-10.958,14.677],[11.03,15.091],[11.03,-46.031]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.25,"y":0},"t":137,"s":[{"i":[[-1.137,-13.047],[0,-2.875],[0.003,16.045],[-0.152,1.996]],"o":[[0.163,1.872],[0,16.125],[-0.001,-2.716],[0.782,-10.288]],"v":[[-10.42,-42.57],[-10.958,14.677],[11.03,15.091],[11.638,-42.007]],"c":true}]},{"i":{"x":0,"y":1},"o":{"x":0.167,"y":0.167},"t":148,"s":[{"i":[[-0.4,-6.518],[0,-2.875],[0.003,16.045],[-0.055,2]],"o":[[0.017,1.875],[0,16.125],[-0.001,-2.716],[0.304,-6.28]],"v":[[-9.962,-36.944],[-10.958,14.677],[11.03,15.091],[12.054,-36.318]],"c":true}]},{"t":179,"s":[{"i":[[0.092,-2.159],[0,-2.875],[0.003,16.045],[0.009,2.002]],"o":[[-0.081,1.877],[0,16.125],[-0.001,-2.716],[-0.016,-3.605]],"v":[[-10.958,-46.698],[-10.958,14.677],[11.03,15.091],[11.03,-46.031]],"c":true}]}]},"nm":"Path 1","hd":false},{"ty":"gf","o":{"a":0,"k":100},"r":1,"bm":0,"g":{"p":3,"k":{"a":0,"k":[0,0.38,0.294,0.31,0.5,0.38,0.294,0.31,1,0.38,0.294,0.31,0,1,0.5,0.5,1,0]}},"s":{"a":0,"k":[-0.1,19.157]},"e":{"a":0,"k":[2.633,14.219]},"t":1,"nm":"Gradient_Z6SUlP1gzQ","hd":false},{"ty":"gf","o":{"a":0,"k":100},"r":1,"bm":0,"g":{"p":9,"k":{"a":0,"k":[0,0.494,0.481,0.455,0.104,0.416,0.378,0.373,0.207,0.337,0.275,0.29,0.259,0.388,0.296,0.312,0.307,0.439,0.318,0.333,0.462,0.567,0.527,0.553,0.635,0.694,0.737,0.773,0.839,0.694,0.737,0.773,1,0.694,0.738,0.773]}},"s":{"a":0,"k":[-7.183,-10.772]},"e":{"a":0,"k":[11.184,-10.907]},"t":1,"nm":"Gradient_Nz9kpxK3uC","hd":false},{"ty":"tr","p":{"a":0,"k":[31.039,2.886]},"a":{"a":0,"k":[0,-48.25]},"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":180.18018018018,"st":0,"bm":0},{"ddd":0,"ind":18,"ty":4,"nm":"BACK BODY","parent":1,"sr":1,"ks":{"p":{"a":1,"k":[{"i":{"x":0.1,"y":1},"o":{"x":0.15,"y":0},"t":45,"s":[-3.06,-197.982,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.5,"y":0},"t":92,"s":[-16.064,-198.384,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0,"y":1},"o":{"x":0.095,"y":0.071},"t":104,"s":[-3.06,-197.982,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0,"y":1},"o":{"x":0.25,"y":0},"t":137,"s":[4.947,-197.235,0],"to":[0,0,0],"ti":[0,0,0]},{"t":179,"s":[-3.06,-197.982,0]}]},"a":{"a":0,"k":[217.443,217.443,0]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[0,-109.045],[109.045,0],[0,109.045],[-109.045,0]],"o":[[0,109.045],[-109.045,0],[0,-109.045],[109.045,0]],"v":[[197.443,0],[0.001,197.443],[-197.443,0],[0.001,-197.443]],"c":true}},"nm":"Path 1","hd":false},{"ty":"tm","s":{"a":0,"k":0},"e":{"a":0,"k":10},"o":{"a":0,"k":253},"m":1,"nm":"Trim Paths 1","hd":false},{"ty":"st","c":{"a":0,"k":[0.584313750267,0.128319874406,0.131967827678,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":[217.443,217.443]},"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,-109.045],[109.045,0],[0,109.045],[-109.045,0]],"o":[[0,109.045],[-109.045,0],[0,-109.045],[109.045,0]],"v":[[197.443,0],[0.001,197.443],[-197.443,0],[0.001,-197.443]],"c":true}},"nm":"Path 1","hd":false},{"ty":"tm","s":{"a":0,"k":0},"e":{"a":0,"k":8},"o":{"a":0,"k":178},"m":1,"nm":"Trim Paths 1","hd":false},{"ty":"st","c":{"a":0,"k":[0.635294139385,0.145098045468,0.149019613862,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":[217.443,217.443]},"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,-109.045],[109.045,0],[0,109.045],[-109.045,0]],"o":[[0,109.045],[-109.045,0],[0,-109.045],[109.045,0]],"v":[[197.443,0],[0.001,197.443],[-197.443,0],[0.001,-197.443]],"c":true}},"nm":"Path 1","hd":false},{"ty":"tm","s":{"a":0,"k":0},"e":{"a":0,"k":43},"o":{"a":0,"k":180},"m":1,"nm":"Trim Paths 1","hd":false},{"ty":"st","c":{"a":0,"k":[0.32549020648,0.039569396526,0.039569396526,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":[217.443,217.443]},"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":[[0,-109.045],[109.045,0],[0,109.045],[-109.045,0]],"o":[[0,109.045],[-109.045,0],[0,-109.045],[109.045,0]],"v":[[197.443,0],[0.001,197.443],[-197.443,0],[0.001,-197.443]],"c":true}},"nm":"Path 1","hd":false},{"ty":"tm","s":{"a":0,"k":0},"e":{"a":0,"k":39},"o":{"a":0,"k":15},"m":1,"nm":"Trim Paths 1","hd":false},{"ty":"st","c":{"a":0,"k":[0.32549020648,0.039569396526,0.039569396526,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":[217.443,217.443]},"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":[[0,-109.045],[109.045,0],[0,109.045],[-109.045,0]],"o":[[0,109.045],[-109.045,0],[0,-109.045],[109.045,0]],"v":[[197.443,0],[0.001,197.443],[-197.443,0],[0.001,-197.443]],"c":true}},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":0,"k":[0.450980424881,0.054901964962,0.054901964962,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":3,"k":{"a":0,"k":[0,0.478,0.023,0.023,0.66,0.58,0.066,0.066,1,0.682,0.11,0.11,0,1,0.92,0.5,1,0]}},"s":{"a":0,"k":[128.5,-146]},"e":{"a":0,"k":[65,-93.5]},"t":2,"h":{"a":0,"k":68.617},"a":{"a":0,"k":-81.895},"nm":"Gradient_sw2Xcy7fTL","hd":false},{"ty":"gf","o":{"a":0,"k":100},"r":1,"bm":0,"g":{"p":3,"k":{"a":0,"k":[0,0.478,0.023,0.023,0.66,0.58,0.066,0.066,1,0.682,0.11,0.11,0,1,0.92,0.5,1,0]}},"s":{"a":0,"k":[-125,-150.5]},"e":{"a":0,"k":[-69,-94.5]},"t":2,"h":{"a":0,"k":23.396},"a":{"a":0,"k":86.991},"nm":"Gradient_AFJAA2M45d","hd":false},{"ty":"gf","o":{"a":0,"k":100},"r":1,"bm":0,"g":{"p":3,"k":{"a":0,"k":[0,0.561,0.024,0.031,0.5,0.561,0.024,0.03,1,0.561,0.024,0.029,0,1,0.5,0.5,1,0]}},"s":{"a":0,"k":[-187.25,-58.5]},"e":{"a":0,"k":[-181.25,-56]},"t":1,"nm":"Gradient_AXFFQRDFa9","hd":false},{"ty":"gf","o":{"a":0,"k":100},"r":1,"bm":0,"g":{"p":3,"k":{"a":0,"k":[0,0.561,0.024,0.031,0.5,0.561,0.024,0.03,1,0.561,0.024,0.029,0,1,0.5,0.5,1,0]}},"s":{"a":0,"k":[-192.25,-47.625]},"e":{"a":0,"k":[-186,-47.125]},"t":1,"nm":"Gradient_Qb1MVMw8lm","hd":false},{"ty":"gf","o":{"a":0,"k":100},"r":1,"bm":0,"g":{"p":3,"k":{"a":0,"k":[0,0.941,0.541,0.537,0.5,0.929,0.356,0.344,1,0.918,0.171,0.151,0,1,0.5,0.5,1,0]}},"s":{"a":0,"k":[-182.5,-53.5]},"e":{"a":0,"k":[-128,-18.5]},"t":2,"h":{"a":0,"k":27.771},"a":{"a":0,"k":230.17},"nm":"Gradient_KIo2PpPxM8","hd":false},{"ty":"gf","o":{"a":0,"k":100},"r":1,"bm":0,"g":{"p":3,"k":{"a":0,"k":[0,0.824,0.282,0.243,0.5,0.824,0.282,0.243,1,0.824,0.282,0.243,0,1,0.71,0.5,1,0]}},"s":{"a":0,"k":[193,-8.5]},"e":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":38,"s":[166,-12],"to":[0,0],"ti":[0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":92,"s":[166,-12],"to":[0,0],"ti":[0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":104,"s":[193,-12],"to":[0,0],"ti":[0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":146,"s":[193,-12],"to":[0,0],"ti":[0,0]},{"t":160,"s":[166,-12]}]},"t":2,"h":{"a":0,"k":46.691},"a":{"a":0,"k":141.24},"nm":"Gradient_zehpRb7etP","hd":false},{"ty":"gf","o":{"a":0,"k":100},"r":1,"bm":0,"g":{"p":3,"k":{"a":0,"k":[0,0.796,0.22,0.259,0.5,0.608,0.12,0.141,1,0.42,0.02,0.024]}},"s":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":38,"s":[-1,-197],"to":[0,0],"ti":[0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":92,"s":[-1,-38],"to":[0,0],"ti":[0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":104,"s":[-1,-314],"to":[0,0],"ti":[0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":146,"s":[-1,-314],"to":[0,0],"ti":[0,0]},{"t":160,"s":[-1,-197]}]},"e":{"a":0,"k":[-1,190]},"t":1,"nm":"Gradient_vlPlLlOlQv","hd":false},{"ty":"tr","p":{"a":0,"k":[217.443,217.443]},"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":180.18018018018,"st":0,"bm":0},{"ddd":0,"ind":19,"ty":4,"nm":"L Ring Back","parent":10,"sr":1,"ks":{"r":{"a":0,"k":31},"p":{"a":0,"k":[110.926,78.078,0]},"a":{"a":0,"k":[70.867,-151.4,0]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0,"y":1},"o":{"x":0.095,"y":0.173},"t":104,"s":[{"i":[[7.1,-48.659],[-37.809,22.062],[4.566,11.239]],"o":[[3.999,15.311],[32.95,-19.226],[-52.416,-32.376]],"v":[[0.326,-112.732],[75.95,-146.928],[140.08,-196.274]],"c":true}]},{"i":{"x":0,"y":1},"o":{"x":0.25,"y":0},"t":137,"s":[{"i":[[7.1,-48.659],[-37.809,22.062],[9.878,24.521]],"o":[[6.257,20.711],[32.95,-19.226],[-52.416,-32.376]],"v":[[-4.951,-120.296],[84.645,-131.886],[134.803,-203.837]],"c":true}]},{"t":179,"s":[{"i":[[7.099,-48.659],[-37.809,22.062],[-19.368,3.976]],"o":[[14.197,-16.4],[32.95,-19.226],[-52.416,-32.376]],"v":[[0.326,-112.732],[71.253,-166.259],[140.08,-196.274]],"c":true}]}]},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":0,"k":[0.450980422076,0.054901964524,0.054901964524,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":8},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.265359556909,0.023934388628,0.023934388628,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":"Shape 1","bm":0,"hd":false}],"ip":104,"op":157,"st":0,"bm":0},{"ddd":0,"ind":20,"ty":4,"nm":"R Ring Back","parent":14,"sr":1,"ks":{"r":{"a":0,"k":-35},"p":{"a":0,"k":[109.874,82.848,0]},"a":{"a":0,"k":[86.75,-141.523,0]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0.1,"y":1},"o":{"x":0.15,"y":0},"t":45,"s":[{"i":[[47.75,-11.75],[-36.279,-23.034],[-13.983,-2.503]],"o":[[-2.189,8.36],[30.693,19.488],[10.25,-60.75]],"v":[[27.826,-191.542],[87.831,-139.9],[156.17,-98.965]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.461,"y":0},"t":92,"s":[{"i":[[47.75,-11.75],[-23.949,-16.117],[-11.116,12.97]],"o":[[-16.632,16.279],[24.32,16.367],[10.25,-60.75]],"v":[[31.5,-194.5],[74.976,-126.972],[156.25,-102.5]],"c":true}]},{"t":104,"s":[{"i":[[47.75,-11.75],[-34.524,-23.121],[-12.313,-19.278]],"o":[[19.298,11.392],[31.269,20.941],[10.25,-60.75]],"v":[[31.5,-194.5],[95.854,-156.205],[156.25,-102.5]],"c":true}]}]},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":0,"k":[0.450980422076,0.054901964524,0.054901964524,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":8},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.265359556909,0.023934388628,0.023934388628,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":"Shape 1","bm":0,"hd":false}],"ip":46,"op":105,"st":0,"bm":0}]} \ No newline at end of file diff --git a/TMessagesProj/src/main/res/raw/biz_map.json b/TMessagesProj/src/main/res/raw/biz_map.json new file mode 100644 index 00000000000..ac9c878baf4 --- /dev/null +++ b/TMessagesProj/src/main/res/raw/biz_map.json @@ -0,0 +1 @@ +{"tgs":1,"v":"5.5.2","fr":60,"ip":0,"op":180,"w":512,"h":512,"nm":"Comp 1","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Shape Layer 19","parent":15,"sr":1,"ks":{"r":{"a":0,"k":-55.937},"p":{"a":0,"k":[175.43,178.205,0]},"s":{"a":0,"k":[91.992,92.448,100]}},"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.166},"t":91,"s":[{"i":[[-2.556,-7.908],[9.677,3.853],[0.501,5.737],[1.284,5.781]],"o":[[1.668,5.16],[9.169,4.142],[-2.71,-7.542],[2.144,5.768]],"v":[[0.211,9.515],[-18.662,0.11],[0.546,9.776],[6.413,-2.153]],"c":true}]},{"i":{"x":0.833,"y":1},"o":{"x":0.167,"y":0.167},"t":113,"s":[{"i":[[9.97,-3.466],[15.529,-4.331],[-14.231,3.382],[-6.898,5.261]],"o":[[-10.009,3.48],[15.71,-1.717],[16.649,-5.386],[-8.656,0.63]],"v":[[2.713,32.655],[-32.452,31.394],[2.935,38.924],[19.273,8.902]],"c":true}]},{"t":136,"s":[{"i":[[10.552,-0.282],[6.171,6.398],[-13.016,-0.47],[-3.131,17.507]],"o":[[-10.226,0.274],[6.429,6.894],[14.3,3.333],[-5.257,25.043]],"v":[[-4.924,66.166],[-47.851,73.728],[-5.141,66.459],[26.057,38.057]],"c":true}]}]},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":0},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"gf","o":{"a":0,"k":100},"r":1,"bm":0,"g":{"p":3,"k":{"a":0,"k":[0,1,1,1,0.5,0.604,0.869,0.978,1,0.208,0.737,0.957]}},"s":{"a":0,"k":[-23.378,-52.012]},"e":{"a":0,"k":[12.676,70.922]},"t":1,"nm":"Gradient 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":"Shape 2","bm":0,"hd":false}],"ip":91,"op":137,"st":3,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"Shape Layer 14","parent":15,"sr":1,"ks":{"r":{"a":0,"k":205.163},"p":{"a":0,"k":[128.815,163.157,0]},"s":{"a":0,"k":[91.335,93.112,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.177},"t":103,"s":[{"i":[[2.142,-2.991],[8.613,2.858],[-3.952,3.382],[-8.843,4.599]],"o":[[-3.157,4.408],[7.355,2.378],[2.42,-4.474],[-9.593,4.611]],"v":[[9.762,9.343],[-2.652,17.405],[10.303,10.124],[23.172,-7.727]],"c":true}]},{"i":{"x":0.833,"y":1},"o":{"x":0.167,"y":0},"t":127.102,"s":[{"i":[[7.653,-7.27],[8.613,2.858],[-10.111,8.983],[-12.289,7.906]],"o":[[-3.931,3.735],[6.429,6.894],[8.12,-7.567],[-13.609,3.677]],"v":[[16.884,31.979],[-11.942,45.561],[20.982,36.202],[44.35,2.928]],"c":true}]},{"t":148,"s":[{"i":[[20.731,-4.033],[8.579,-11.033],[-12.972,3.807],[-12.199,5.32]],"o":[[-14.146,2.751],[8.575,-11.026],[21.367,-3.386],[-12.287,6.014]],"v":[[28.638,36.637],[-1.118,53.196],[27.967,36.346],[61.937,9.879]],"c":true}]}]},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":0},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"gf","o":{"a":0,"k":100},"r":1,"bm":0,"g":{"p":3,"k":{"a":0,"k":[0,0.941,0.98,1,0.5,0.575,0.859,0.978,1,0.208,0.737,0.957]}},"s":{"a":0,"k":[-33.782,-21.262]},"e":{"a":0,"k":[62.59,57.526]},"t":1,"nm":"Gradient Fill 2","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 2","bm":0,"hd":false}],"ip":103,"op":149,"st":15,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"карта загиб 1","parent":38,"sr":1,"ks":{"r":{"a":0,"k":5.69},"p":{"a":0,"k":[344.026,251.83,0]},"s":{"a":0,"k":[99.747,99.747,100]}},"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":10,"s":[{"i":[[-15,3],[15.83,-15.095],[-7.443,-129.654],[-6.393,51.27]],"o":[[-14.896,3.62],[-8.463,75.503],[-5.863,-127.715],[14.3,-15.069]],"v":[[-187.739,-154.609],[-259.52,-133.257],[-273.359,210.402],[-259.988,-133.167]],"c":true}]},{"i":{"x":0.317,"y":1},"o":{"x":0.167,"y":0.167},"t":12,"s":[{"i":[[-28.864,1.459],[8.662,-25.848],[-11.082,-140.044],[-45.155,44.404]],"o":[[-9.726,2.172],[-13.4,55.281],[-4.961,-105.95],[-28.516,-44.27]],"v":[[-184.952,-156.829],[-229.687,-130.103],[-273.695,210.025],[-220.76,-82.004]],"c":true}]},{"i":{"x":0.833,"y":0.964},"o":{"x":0.696,"y":0},"t":19,"s":[{"i":[[-39.438,4.086],[17.827,-27.703],[-16.228,-154.736],[-84.558,24.009]],"o":[[-3.914,1.361],[-12.494,41.175],[-3.686,-75.175],[-58.967,-67.556]],"v":[[-181.01,-159.968],[-225.283,-132.37],[-274.169,209.492],[-195.492,-50.243]],"c":true}]},{"t":26,"s":[{"i":[[-19.175,1.987],[16.333,-19.13],[-9.889,-133.06],[-16.951,53.895]],"o":[[-19.721,1],[-21.826,81],[-10.888,-133.02],[17.798,-19.974]],"v":[[-187.974,-158.728],[-241.99,-132.254],[-273.182,213.4],[-242.457,-132.165]],"c":true}]}]},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":0,"k":[0.725490196078,0.36862745098,0.019607843137,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":8},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 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":"Shape 1","bm":0,"hd":false}],"ip":10,"op":26,"st":0,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"Shape Layer 18","parent":21,"sr":1,"ks":{"r":{"a":0,"k":342.216},"p":{"a":0,"k":[221.076,133.37,0]},"s":{"a":0,"k":[83.102,99.743,100]}},"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.124},"t":76,"s":[{"i":[[-0.076,-7.393],[9.144,1.836],[-0.114,7.264],[30.383,5.831]],"o":[[0.08,7.817],[8.448,-0.526],[-2.71,-7.542],[30.135,5.798]],"v":[[0.9,7.862],[-7.468,22.704],[0.772,7.81],[2.069,-13.787]],"c":true}]},{"i":{"x":0.833,"y":1},"o":{"x":0.167,"y":0.167},"t":106,"s":[{"i":[[13.002,-7.226],[7.078,-0.711],[-8.294,2.587],[8.286,18.09]],"o":[[-6.846,3.804],[9.576,-0.666],[9.791,-2.338],[5.057,17.031]],"v":[[13.637,10.28],[-3.751,34.842],[16.393,16.632],[31.63,-15.788]],"c":true}]},{"t":140,"s":[{"i":[[2.933,-2.644],[3.31,0.321],[-3.817,3.029],[3.363,5.741]],"o":[[-2.843,2.562],[3.504,0.399],[4.877,-2.526],[4.589,8.401]],"v":[[39.561,23.322],[29.187,35.902],[39.571,23.458],[41.545,7.799]],"c":true}]}]},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":0},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"gf","o":{"a":0,"k":100},"r":1,"bm":0,"g":{"p":3,"k":{"a":0,"k":[0,0.922,0.973,1,0.5,0.565,0.855,0.978,1,0.208,0.737,0.957]}},"s":{"a":0,"k":[-22.285,-15.096]},"e":{"a":0,"k":[67.347,39.246]},"t":1,"nm":"Gradient Fill 3","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 2","bm":0,"hd":false}],"ip":76,"op":140,"st":-12,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":"Shape Layer 23","parent":29,"sr":1,"ks":{"r":{"a":0,"k":-196.006},"p":{"a":0,"k":[295.259,163.597,0]},"s":{"a":0,"k":[89.029,93.915,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.834},"o":{"x":0.167,"y":0.112},"t":60,"s":[{"i":[[1.235,-0.617],[0.982,0.483],[1.292,0.264],[-0.77,-0.381],[-0.834,0.167],[-0.938,0.347],[-0.701,-1.275],[0.88,-0.31]],"o":[[-0.742,0.371],[-0.787,-0.387],[1.314,0.229],[0.888,0.44],[0.972,-0.476],[0.977,-0.362],[-0.801,-1.282],[-0.828,0.292]],"v":[[-3.689,-1.844],[-6.124,-2.301],[-9.165,-3.427],[-6.154,-2.37],[-3.75,-1.744],[-0.831,-3.317],[1.748,-2.33],[-0.675,-3.471]],"c":true}]},{"i":{"x":0.833,"y":1},"o":{"x":0.167,"y":0.166},"t":93,"s":[{"i":[[13.001,-0.699],[6.554,4.431],[4.953,1.587],[-4.924,-5.028],[-10.617,2.006],[-4.792,2.787],[-3.865,5.294],[8.021,-4.326]],"o":[[-6.866,0.369],[-4.837,-3.27],[4.02,2.67],[5.363,5.476],[12.188,-2.303],[9.465,-5.504],[-3.478,4.232],[-5.615,3.028]],"v":[[5.687,27.005],[-19.047,30.611],[-37.297,32.142],[-18.642,37.137],[6.223,34.439],[29.05,32.102],[42.916,9.89],[26.789,27.283]],"c":true}]},{"t":130,"s":[{"i":[[6.084,4.407],[6.546,-3.673],[3.706,5.297],[-5.582,3.253],[-4.16,-3.524],[-9.385,8.822],[-5.226,15.962],[10.139,-8.939]],"o":[[-4.6,-3.332],[-5.243,2.942],[3.827,5.418],[6.438,-3.752],[6.863,4.531],[8.939,-8.402],[-4.962,15.486],[-9.548,8.417]],"v":[[-2.84,54.012],[-18.077,52.532],[-35.58,51.167],[-18.144,52.422],[-2.915,54.067],[29.184,50.805],[56.232,26.459],[29.049,51.022]],"c":true}]}]},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":0},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"gf","o":{"a":0,"k":100},"r":1,"bm":0,"g":{"p":3,"k":{"a":0,"k":[0,1,1,1,0.5,0.604,0.869,0.978,1,0.208,0.737,0.957]}},"s":{"a":0,"k":[7.216,-29.575]},"e":{"a":0,"k":[19.272,62.443]},"t":1,"nm":"Gradient Fill 4","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 2","bm":0,"hd":false}],"ip":60,"op":131,"st":-28,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":"Shape Layer 24","parent":29,"sr":1,"ks":{"r":{"a":0,"k":-139.914},"p":{"a":0,"k":[371.873,167.171,0]},"s":{"a":0,"k":[90.069,92.831,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":87,"s":[{"i":[[12.808,-2.338],[9.423,1.839],[4.953,1.587],[-6.912,-1.325],[-10.617,2.006],[-4.792,2.787],[-3.999,7.413],[8.021,-4.326]],"o":[[-10.791,1.97],[-5.73,-1.118],[4.02,2.67],[9.511,1.823],[12.188,-2.303],[9.465,-5.504],[-3.974,7.066],[-5.615,3.028]],"v":[[-3.084,37.887],[-20.579,50.231],[-47.087,58.857],[-20.501,50.442],[-3.262,37.721],[20.582,36.207],[39.617,17.477],[20.271,35.805]],"c":true}]},{"i":{"x":0.833,"y":1},"o":{"x":0.167,"y":0},"t":120.23,"s":[{"i":[[13.001,-0.699],[6.554,4.431],[4.953,1.587],[-4.924,-5.028],[-10.617,2.006],[-4.792,2.787],[0.257,11.145],[8.021,-4.326]],"o":[[-6.866,0.369],[-4.837,-3.27],[4.02,2.67],[5.363,5.476],[12.188,-2.303],[9.465,-5.504],[-1.936,8.439],[-5.615,3.028]],"v":[[-1.714,48.888],[-23.396,57.054],[-44.728,63.512],[-23.86,64.888],[-1.178,56.322],[21.649,53.986],[44.336,26.787],[19.317,46.698]],"c":true}]},{"t":159,"s":[{"i":[[6.467,3.824],[6.178,-4.264],[4.181,4.931],[-5.257,3.756],[-4.468,-3.124],[-8.527,9.654],[-3.725,16.378],[9.268,-9.84]],"o":[[-4.889,-2.891],[-4.948,3.415],[4.313,5.04],[6.063,-4.332],[7.253,3.876],[8.122,-9.194],[-3.506,15.879],[-8.727,9.265]],"v":[[-3.37,73.526],[-21.937,81.665],[-39.492,81.928],[-22.015,81.561],[-3.44,73.588],[28.219,67.366],[52.895,40.619],[28.105,67.595]],"c":true}]}]},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":0},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"gf","o":{"a":0,"k":100},"r":1,"bm":0,"g":{"p":3,"k":{"a":0,"k":[0,1,1,1,0.5,0.604,0.869,0.978,1,0.208,0.737,0.957]}},"s":{"a":0,"k":[-34.707,-214.552]},"e":{"a":0,"k":[25.174,166.22]},"t":1,"nm":"Gradient Fill 5","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 2","bm":0,"hd":false}],"ip":87,"op":159,"st":-1,"bm":0},{"ddd":0,"ind":7,"ty":4,"nm":"Shape Layer 21","parent":29,"sr":1,"ks":{"r":{"a":0,"k":2.175},"p":{"a":0,"k":[358.243,220.544,0]},"s":{"a":0,"k":[88.942,94.007,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.143},"t":48,"s":[{"i":[[0.199,-2.841],[1.989,-2.2],[-0.523,1.499],[-2.85,-0.086]],"o":[[-0.104,1.491],[1.863,-2.187],[0.172,-2.202],[-2.933,0.074]],"v":[[-18.89,-16.686],[-23.036,-12.775],[-18.835,-16.582],[-16.544,-21.615]],"c":true}]},{"i":{"x":0.833,"y":1},"o":{"x":0.167,"y":0},"t":74.189,"s":[{"i":[[8.391,6.405],[10.543,3.379],[-17.209,-10.017],[12.833,6.418]],"o":[[-11.291,-8.618],[7.853,5.215],[20.858,2.638],[14.662,15.383]],"v":[[9.722,23.972],[-21.27,32.034],[12.874,34.677],[21.552,-0.855]],"c":true}]},{"t":105,"s":[{"i":[[13.901,6.841],[3.011,14.511],[-8.765,-5.176],[13.593,14.489]],"o":[[-9.178,-4.517],[3.02,14.76],[15.373,6.757],[14.174,16.715]],"v":[[19.597,47.103],[-8.307,56.169],[19.38,47.396],[62.04,11.883]],"c":true}]}]},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":0},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"gf","o":{"a":0,"k":100},"r":1,"bm":0,"g":{"p":3,"k":{"a":0,"k":[0,0.584,0.878,1,0.5,0.396,0.807,0.978,1,0.208,0.737,0.957]}},"s":{"a":0,"k":[45.355,12.601]},"e":{"a":0,"k":[-75.907,-4.894]},"t":1,"nm":"Gradient Fill 6","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 2","bm":0,"hd":false}],"ip":48,"op":105,"st":-40,"bm":0},{"ddd":0,"ind":8,"ty":4,"nm":"Shape Layer 27","parent":26,"sr":1,"ks":{"r":{"a":0,"k":183.995},"p":{"a":0,"k":[404.884,292.199,0]},"s":{"a":0,"k":[115.11,91.211,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.22},"t":82,"s":[{"i":[[0.199,-2.841],[0.303,-0.295],[0.359,-0.237],[0.966,-1.069],[-0.684,0.45],[-0.311,0.25],[-0.164,0.471],[-2.85,-0.086]],"o":[[-0.03,0.428],[-0.24,0.234],[-0.766,0.507],[0.799,-0.939],[0.409,-0.269],[0.381,-0.306],[0.172,-2.202],[-2.933,0.074]],"v":[[11.138,11.937],[10.615,12.983],[9.704,13.671],[6.991,15.847],[9.265,13.901],[10.356,13.151],[11.193,12.04],[13.483,7.008]],"c":true}]},{"i":{"x":0.833,"y":1},"o":{"x":0.167,"y":0},"t":104,"s":[{"i":[[4.52,-13.648],[4.069,-0.46],[3.204,1.39],[7.156,5.242],[-7.639,-9.239],[-5.137,0.643],[-3.24,11.852],[-5.63,9.986]],"o":[[-1.467,4.429],[-2.897,0.328],[-5.997,-2.602],[5.475,6.435],[7.06,8.538],[5.695,-0.713],[3.205,-11.722],[-5.702,6.247]],"v":[[18.003,23.918],[7.455,25.567],[-0.244,29.429],[-12.392,9.847],[-3.418,34.536],[8.954,32.905],[23.304,27.688],[26.43,0.147]],"c":true}]},{"t":132,"s":[{"i":[[13.901,6.841],[3.253,-2.295],[2.459,-2.077],[7.964,6.558],[-4.459,3.564],[-2.895,2.177],[-2.752,-1.625],[-3.674,13.476]],"o":[[-2.632,-1.295],[-2.58,1.82],[-5.253,4.436],[6.346,5.904],[2.668,-2.132],[3.54,-2.662],[15.373,6.757],[-3.506,13.162]],"v":[[19.597,47.103],[10.542,49.488],[2.869,55.777],[-19.766,54.06],[1.117,57.268],[9.631,50.148],[19.38,47.396],[47.554,19.487]],"c":true}]}]},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":0},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"gf","o":{"a":0,"k":100},"r":1,"bm":0,"g":{"p":3,"k":{"a":0,"k":[0,0.584,0.878,1,0.5,0.396,0.807,0.978,1,0.208,0.737,0.957]}},"s":{"a":0,"k":[2.127,-15.797]},"e":{"a":0,"k":[26.354,120.772]},"t":1,"nm":"Gradient Fill 7","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 2","bm":0,"hd":false}],"ip":81,"op":132,"st":-7,"bm":0},{"ddd":0,"ind":9,"ty":4,"nm":"Shape Layer 26","parent":26,"sr":1,"ks":{"r":{"a":0,"k":65.655},"p":{"a":0,"k":[393.068,296.732,0]},"s":{"a":0,"k":[96.018,109.067,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.22},"t":58,"s":[{"i":[[0.199,-2.841],[1.989,-2.2],[-0.523,1.499],[-2.85,-0.086]],"o":[[-0.104,1.491],[1.863,-2.187],[0.172,-2.202],[-2.933,0.074]],"v":[[11.138,11.937],[6.991,15.847],[11.193,12.04],[13.483,7.008]],"c":true}]},{"i":{"x":0.833,"y":1},"o":{"x":0.167,"y":0},"t":80,"s":[{"i":[[8.391,6.405],[10.543,3.379],[-17.209,-10.017],[12.833,6.418]],"o":[[-11.291,-8.618],[7.853,5.215],[20.858,2.638],[14.662,15.383]],"v":[[19.253,25.238],[-11.74,33.3],[22.405,35.943],[31.082,0.411]],"c":true}]},{"t":108,"s":[{"i":[[13.901,6.841],[3.011,14.511],[-8.765,-5.176],[13.593,14.489]],"o":[[-9.178,-4.517],[3.02,14.76],[15.373,6.757],[14.174,16.715]],"v":[[19.597,47.103],[-8.307,56.169],[19.38,47.396],[62.04,11.883]],"c":true}]}]},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":0},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"gf","o":{"a":0,"k":100},"r":1,"bm":0,"g":{"p":3,"k":{"a":0,"k":[0,0.584,0.878,1,0.5,0.396,0.807,0.978,1,0.208,0.737,0.957]}},"s":{"a":0,"k":[5.66,5.844]},"e":{"a":0,"k":[37.244,60.794]},"t":1,"nm":"Gradient Fill 8","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 2","bm":0,"hd":false}],"ip":57,"op":108,"st":-31,"bm":0},{"ddd":0,"ind":10,"ty":4,"nm":"карта загиб 2","parent":39,"sr":1,"ks":{"a":{"a":0,"k":[256,256,0]},"s":{"a":0,"k":[100.214,100.214,100]}},"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":39,"s":[{"i":[[31.867,4.102],[0,0],[-19.843,7.672],[0,0]],"o":[[-3.049,19.97],[0,0],[1.465,-17.702],[0,0]],"v":[[400.546,6.459],[336.275,490.53],[392.271,485.444],[432.8,23.605]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":41,"s":[{"i":[[31.867,4.102],[0,0],[-19.843,7.672],[0,0]],"o":[[-3.049,19.97],[0,0],[1.465,-17.702],[0,0]],"v":[[409.287,8.774],[345.016,492.846],[401.012,487.759],[441.65,26.96]],"c":true}]},{"t":44,"s":[{"i":[[4.854,1.556],[0,0],[-5.723,2.678],[0,0]],"o":[[-3.049,19.97],[0,0],[-0.064,-0.263],[0,0]],"v":[[451.876,62.912],[437.481,447.385],[455.256,444.302],[458.398,72.681]],"c":true}]}]},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":0},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"gf","o":{"a":0,"k":100},"r":1,"bm":0,"g":{"p":3,"k":{"a":0,"k":[0,0.588,0.922,1,0.331,0.363,0.724,0.845,0.663,0.137,0.525,0.69,0,0,0.2,0.5,0.4,1]}},"s":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":39,"s":[414.419,262.695],"to":[-4.974,-0.809],"ti":[-4.851,-0.315]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":41,"s":[384.575,257.844],"to":[4.851,0.315],"ti":[-9.825,-1.123]},{"t":44,"s":[443.522,264.583]}]},"e":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":39,"s":[463.194,266.013],"to":[0.694,-0.075],"ti":[-1.122,0.12]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":41,"s":[467.357,265.564],"to":[1.122,-0.12],"ti":[-0.428,0.046]},{"t":44,"s":[469.925,265.29]}]},"t":1,"nm":"Gradient Fill 9","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},{"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":39,"s":[{"i":[[0,0],[-2.729,32.913],[-2.804,28.061],[0.019,0.178],[1.187,2.328],[5.279,2.691],[3.857,-2.11],[4.17,-33.397],[0,0],[0,0],[0,0],[0,0],[-6.952,1.645],[-0.55,0.528],[-0.016,0.068],[-2.775,34.094]],"o":[[0,0],[2.251,-27.155],[-0.003,-0.204],[-0.164,-0.513],[-2,-4.04],[-3.58,-1.355],[-2.778,21.576],[-4.203,33.663],[0,0],[0,0],[4.878,4.802],[2.768,-0.345],[5.962,-1.41],[0.146,-0.009],[2.609,-35.842],[2.664,-32.739]],"v":[[155.543,5.498],[161.907,-73.453],[172.711,-202.475],[172.634,-202.875],[170.981,-208.353],[161.79,-218.168],[151.05,-218.98],[130.652,-60.36],[122.706,1.938],[113.564,71.227],[96.036,206.142],[112.499,213.34],[127.16,212.483],[138.036,206.655],[138.136,206.93],[149.151,81.49]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":41,"s":[{"i":[[0,0],[-2.764,34.304],[-3.505,29.191],[0.05,0.435],[4.427,4.591],[15.653,0.265],[9.614,-5.996],[6.306,-34.546],[0,0],[0,0],[0,0],[0,0],[-9.911,-0.824],[-1.377,1.323],[-0.037,0.124],[-2.738,35.541]],"o":[[0,0],[2.28,-28.302],[-0.011,-0.487],[-0.413,-1.271],[-3.236,-3.356],[-9.932,-0.168],[-4.275,22.295],[-6.356,34.821],[0,0],[0,0],[22.662,7.334],[6.648,1.017],[15.265,1.27],[0.368,-0.028],[2.139,-37.399],[2.629,-34.128]],"v":[[163.59,1.33],[169.781,-80.979],[183.217,-210.942],[182.817,-211.34],[176.908,-218.294],[151.172,-227.747],[124.057,-221.39],[94.08,-68.955],[81.917,-4.561],[67.662,66.974],[40.586,206.143],[89.371,216.435],[119.871,219.551],[143.977,219.187],[144.233,219.83],[156.986,80.522]],"c":true}]},{"t":44,"s":[{"i":[[0,0],[-0.271,27.864],[-0.606,23.767],[0.021,0.148],[0.41,1.964],[3.666,1.43],[3.145,-1.829],[1.446,-28.302],[0,0],[0,0],[0,0],[0,0],[-3.248,0.352],[-0.449,0.45],[-0.011,0.057],[-0.24,28.862]],"o":[[0,0],[0.224,-22.989],[-0.008,-0.17],[-0.148,-0.424],[-1.724,-5.859],[-3.027,-0.452],[-1,18.287],[-1.457,28.528],[0,0],[0,0],[7.588,2.05],[2.235,0.102],[5.078,-0.551],[0.123,-0.011],[0.011,-30.335],[0.23,-27.715]],"v":[[202.358,1.427],[202.865,-65.408],[203.989,-166.017],[203.915,-166.349],[203.144,-170.381],[194.527,-179.923],[185.096,-179.593],[178.034,-53.711],[175.206,-0.912],[171.824,57.819],[165.464,172.171],[181.613,174.136],[191.924,173.414],[199.803,171.674],[199.894,171.901],[201.66,65.763]],"c":true}]}]},"nm":"Path 1","hd":false},{"ty":"tm","s":{"a":0,"k":22},"e":{"a":0,"k":78},"o":{"a":0,"k":0},"m":1,"nm":"Trim Paths 1","hd":false},{"ty":"st","c":{"a":0,"k":[0.345098048449,0.349019616842,0.35686275363,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":4},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.603921508789,0.88337689568,1,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[256.461,255.128]},"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.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":39,"s":[{"i":[[0,0],[-3.5,41.84],[-0.171,2.42],[1.086,4.416],[0.281,0.392],[3.921,1.77],[5.213,-1.883],[4.605,-35.569],[0,0],[0,0],[0,0],[-6.182,-1.8],[-4.665,0.606],[-1.517,3.025],[0.063,0.039],[-2.888,31.715]],"o":[[0,0],[2.286,-27.331],[0.171,-2.42],[-0.564,-1.13],[-3.737,-5.755],[-4.203,-1.565],[-3.337,24.053],[-4.409,34.051],[0,0],[0,0],[6.185,6.576],[5.743,1.389],[5.28,-0.571],[0.054,-0.177],[3.717,-44.973],[2.43,-26.685]],"v":[[158.124,5.536],[164.46,-71.557],[177.64,-222.924],[176.706,-232.983],[175.029,-236.718],[164.264,-244.369],[151.104,-244.705],[127.274,-61.741],[119.518,0.282],[110.096,71.494],[89.574,230.168],[106.905,240.641],[125.052,241.182],[138.11,234.054],[138.287,233.935],[151.726,80.015]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":41,"s":[{"i":[[0,0],[-3.588,43.604],[-2.468,29.082],[0.122,-0.3],[3.41,3.281],[5.828,-0.18],[13.044,-5.754],[7.109,-36.746],[0,0],[0,0],[0,0],[-14.516,-1.146],[-9.67,1.014],[-3.182,1.675],[0.158,0.067],[-3.285,33.024]],"o":[[0,0],[2.344,-28.483],[0.052,0.128],[0.815,-8.253],[-7.965,-7.665],[-13.266,0.411],[-5.339,24.786],[-6.805,35.178],[0,0],[0,0],[17.849,11.139],[12.293,0.971],[13.199,-1.384],[0.13,-0.415],[3.749,-46.875],[2.764,-27.786]],"v":[[169.346,1.674],[175.686,-78.683],[189.188,-226.258],[189.14,-226.077],[182.028,-240.857],[153.469,-250.657],[120.389,-242.56],[85.252,-71.239],[73.515,-7.086],[58.8,66.427],[27.544,225.85],[89.68,240.852],[123.041,240.131],[148.57,234.118],[148.521,233.885],[162.554,79.273]],"c":true}]},{"t":44,"s":[{"i":[[0,0],[-0.369,35.422],[-0.27,23.628],[0.034,-0.249],[2.531,3.834],[1.934,1.527],[4.295,-1.663],[1.668,-30.147],[0,0],[0,0],[0,0],[-4.788,0.642],[-3.606,0.927],[-1.048,0.559],[0.053,0.031],[-0.464,26.855]],"o":[[0,0],[0.241,-23.138],[0.019,0.101],[-0.297,-1.004],[-4.187,-5.576],[-4.41,-1.79],[-1.301,20.391],[-1.597,28.86],[0,0],[0,0],[6.01,3.502],[4.115,-0.784],[4.986,-1.289],[0.039,-0.149],[0.361,-38.073],[0.39,-22.596]],"v":[[204.52,1.278],[205.11,-63.986],[205.949,-180.544],[206.135,-183.403],[202.713,-192.593],[194.63,-199.645],[183.713,-199.731],[175.385,-54.927],[172.691,-2.365],[169.194,57.997],[161.909,192.52],[182.565,195.102],[193.638,193.163],[202.017,190.184],[201.998,190.102],[203.731,64.336]],"c":true}]}]},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":0,"k":[0.72549021244,0.368627458811,0.019607843831,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":8},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 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":[256.066,255.984]},"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}],"ip":39,"op":45,"st":7,"bm":0},{"ddd":0,"ind":11,"ty":4,"nm":"Shape Layer 13","parent":23,"sr":1,"ks":{"r":{"a":0,"k":241},"p":{"a":0,"k":[288.321,289.075,0]},"s":{"a":0,"k":[-92.887,91.708,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.139},"t":109,"s":[{"i":[[2.142,-2.991],[8.613,2.858],[-3.952,3.382],[-8.843,4.599]],"o":[[-3.157,4.408],[7.355,2.378],[2.42,-4.474],[-9.593,4.611]],"v":[[9.762,9.343],[-2.652,17.405],[10.303,10.124],[23.172,-7.727]],"c":true}]},{"i":{"x":0.833,"y":1},"o":{"x":0.167,"y":0},"t":136,"s":[{"i":[[7.653,-7.27],[8.613,2.858],[-10.111,8.983],[-12.289,7.906]],"o":[[-3.931,3.735],[6.429,6.894],[8.12,-7.567],[-13.609,3.677]],"v":[[10.809,25.046],[-18.017,38.627],[14.907,29.269],[38.275,-4.006]],"c":true}]},{"t":163,"s":[{"i":[[20.753,-4.028],[16.246,-0.405],[-12.977,3.798],[6.078,10.824]],"o":[[-14.163,2.749],[16.25,-0.786],[21.389,-3.379],[4.962,9.672]],"v":[[28.658,36.645],[-1.796,60.773],[27.979,36.347],[34.504,7.783]],"c":true}]}]},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":0},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"gf","o":{"a":0,"k":100},"r":1,"bm":0,"g":{"p":3,"k":{"a":0,"k":[0,0.949,0.983,1,0.5,0.578,0.86,0.978,1,0.208,0.737,0.957]}},"s":{"a":0,"k":[-40.134,-22.055]},"e":{"a":0,"k":[77.379,87.297]},"t":1,"nm":"Gradient Fill 10","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 2","bm":0,"hd":false}],"ip":109,"op":164,"st":21,"bm":0},{"ddd":0,"ind":12,"ty":4,"nm":"Shape Layer 11","parent":15,"sr":1,"ks":{"r":{"a":0,"k":3.013},"p":{"a":0,"k":[198.662,284.904,0]},"s":{"a":0,"k":[82.543,99.778,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.866},"o":{"x":0.167,"y":0.125},"t":88,"s":[{"i":[[2.142,-2.991],[1.762,-3.281],[-3.952,3.382],[6.753,-4.908]],"o":[[-3.157,4.408],[2.778,-2.297],[2.42,-4.474],[7.778,-3.424]],"v":[[11.422,5.764],[4.04,15.743],[11.963,6.544],[7.744,-1.275]],"c":true}]},{"i":{"x":0.739,"y":0.846},"o":{"x":0.167,"y":0.109},"t":118,"s":[{"i":[[14.34,-11.13],[9.532,-9.723],[-20.563,10.9],[36.693,-8.269]],"o":[[-19.931,15.47],[11.076,-4.081],[18.697,-2.513],[27.269,-2.635]],"v":[[23.226,14.371],[10.097,42.437],[25.872,16.668],[16.858,-12.902]],"c":true}]},{"t":152,"s":[{"i":[[14.34,-11.131],[13,-5],[-13.615,8.791],[-17.376,11.375]],"o":[[-19.931,15.47],[12.519,-2.957],[15.812,-11.194],[-17.739,9.398]],"v":[[22.986,61.567],[-16.356,88.638],[22.522,62.114],[49.305,15.246]],"c":true}]}]},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":0},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"gf","o":{"a":0,"k":100},"r":1,"bm":0,"g":{"p":3,"k":{"a":0,"k":[0,0.976,0.992,1,0.5,0.592,0.865,0.978,1,0.208,0.737,0.957]}},"s":{"a":0,"k":[-50.664,-9.783]},"e":{"a":0,"k":[65.831,56.648]},"t":1,"nm":"Gradient Fill 12","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 2","bm":0,"hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.866},"o":{"x":0.167,"y":0.125},"t":88,"s":[{"i":[[-1.178,-1.021],[-4.182,-5.837],[0.708,-1.198],[1.857,4.205],[4.838,2.688],[-2.004,3.764],[-1.004,3.868],[0.593,-3.311]],"o":[[0.916,4.695],[0.415,0.088],[0.24,-1.053],[-4.142,-10.949],[-3.783,-2.102],[1.881,-3.301],[-0.332,2.726],[-3.743,6.761]],"v":[[-19.385,9.89],[-20.958,25.283],[-21.41,31.591],[-21.08,25.395],[-19.094,9.578],[-21.636,0.405],[-17.442,-7.935],[-21.36,-0.318]],"c":true}]},{"i":{"x":0.739,"y":0.846},"o":{"x":0.167,"y":0.109},"t":118,"s":[{"i":[[-5.827,-16.948],[-12.197,-21.958],[-5.157,10.785],[6.742,9.136],[2.819,13.194],[-4.514,17.02],[-15.839,-3.81],[2.686,-16.339]],"o":[[0.78,10.7],[7.832,10.218],[-5.994,5.312],[-10.789,-17.469],[-0.909,-4.256],[4.507,-10.845],[-13.843,-6.799],[-2.119,12.482]],"v":[[-40.86,21.159],[-44.328,71.589],[-21.705,63.417],[-41.285,69.285],[-34.056,17.12],[-39.909,-20.229],[-15.7,-36.648],[-45.118,-18.098]],"c":true}]},{"t":152,"s":[{"i":[[-11.312,-9.106],[-12.197,-21.958],[6.999,-9.884],[1.857,4.205],[4.02,3.805],[-8.555,14.181],[21.203,3.502],[5.678,-13.396]],"o":[[0.916,4.695],[7.832,10.218],[7.443,-16.768],[-14.091,-23.038],[-10.369,-9.814],[4.507,-10.845],[14.183,2.367],[-5.431,10.539]],"v":[[-69.118,45.718],[-68.892,79.333],[-65.774,109.599],[-68.768,79.192],[-69.573,45.668],[-64.206,15.613],[-76.257,-5.121],[-64.172,15.394]],"c":true}]}]},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":0},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"gf","o":{"a":0,"k":100},"r":1,"bm":0,"g":{"p":3,"k":{"a":0,"k":[0,0.976,0.992,1,0.5,0.592,0.865,0.978,1,0.208,0.737,0.957]}},"s":{"a":0,"k":[38.051,32.206]},"e":{"a":0,"k":[-110.446,25.346]},"t":1,"nm":"Gradient Fill 13","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":88,"op":153,"st":0,"bm":0},{"ddd":0,"ind":13,"ty":4,"nm":"Shape Layer 25","parent":23,"sr":1,"ks":{"r":{"a":0,"k":-44.541},"p":{"a":0,"k":[262.214,262.078,0]},"s":{"a":0,"k":[90.203,92.693,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.909},"o":{"x":0.167,"y":0},"t":51,"s":[{"i":[[5.722,-2.623],[4.975,0.971],[-0.581,3.441],[-3.649,-0.699],[-5.188,2.371],[-2.53,1.471],[-8.044,-1.335],[4.235,-2.284]],"o":[[-5.264,2.413],[-3.025,-0.59],[-0.542,3.806],[5.021,0.962],[5.714,-2.612],[4.997,-2.906],[-8.044,-1.335],[-2.964,1.599]],"v":[[-2.06,37.096],[-10.875,39.55],[-17.401,32.348],[-10.833,39.662],[-2.154,37.008],[5.547,31.204],[15.924,20.672],[5.383,30.992]],"c":true}]},{"i":{"x":0.833,"y":1},"o":{"x":0.167,"y":0.091},"t":80,"s":[{"i":[[13.001,-0.699],[6.554,4.431],[-0.327,7.714],[-4.924,-5.028],[-10.617,2.006],[-4.792,2.787],[-9.213,8.751],[8.021,-4.326]],"o":[[-6.866,0.369],[-4.837,-3.27],[-3.236,9.046],[5.363,5.476],[12.188,-2.303],[9.465,-5.504],[-9.021,3.791],[-5.615,3.028]],"v":[[-0.731,57.896],[-22.414,66.062],[-33.858,54.082],[-22.878,73.896],[-0.195,65.33],[22.631,62.994],[45.318,35.795],[20.3,55.706]],"c":true}]},{"t":112,"s":[{"i":[[6.467,3.824],[6.178,-4.264],[4.181,4.931],[-5.257,3.756],[-4.468,-3.124],[-8.527,9.654],[-3.725,16.378],[9.268,-9.84]],"o":[[-4.889,-2.891],[-4.948,3.415],[4.313,5.04],[6.063,-4.332],[7.253,3.876],[8.122,-9.194],[-3.506,15.879],[-8.727,9.265]],"v":[[7.929,100.791],[-10.639,108.93],[-28.194,109.193],[-10.716,108.827],[7.859,100.853],[39.518,94.631],[64.193,67.884],[39.404,94.86]],"c":true}]}]},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":0},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"gf","o":{"a":0,"k":100},"r":1,"bm":0,"g":{"p":3,"k":{"a":0,"k":[0,1,1,1,0.5,0.604,0.869,0.978,1,0.208,0.737,0.957]}},"s":{"a":0,"k":[-14.02,2.632]},"e":{"a":0,"k":[28.362,103.977]},"t":1,"nm":"Gradient Fill 14","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 2","bm":0,"hd":false}],"ip":51,"op":113,"st":-37,"bm":0},{"ddd":0,"ind":14,"ty":4,"nm":"Shape Layer 10","parent":15,"td":1,"sr":1,"ks":{"p":{"a":0,"k":[250.404,257.996,0]},"s":{"a":0,"k":[82.797,99.787,100]}},"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.156},"t":67,"s":[{"i":[[35.5,-55.5],[-0.058,0.276],[0.089,-0.494],[-0.173,0.174],[0.015,-0.189],[0.172,-0.218],[0.203,-0.116],[0.118,-0.273],[-0.103,0.275],[0.102,0.072],[0.053,0.213],[17,-2],[-31.5,-40.5],[-12,37],[32,23.5]],"o":[[-16.443,25.707],[0.029,-0.14],[-0.056,0.312],[0.111,-0.111],[-0.015,0.189],[-0.126,0.159],[-0.203,0.116],[-0.078,0.181],[0.078,-0.208],[-0.66,-0.464],[-0.102,-0.406],[-17,2],[31.5,40.5],[12,-37],[-32,-23.5]],"v":[[-121.5,-14.5],[-71.128,37.433],[-70.639,37.672],[-70.342,37.853],[-69.956,37.861],[-70.384,38.39],[-70.668,38.724],[-70.892,39.086],[-71.156,39.159],[-70.895,38.223],[-71.142,37.462],[-123,-6.75],[-120,133],[-18.5,110.5],[2,-10.5]],"c":true}]},{"i":{"x":0.739,"y":0.764},"o":{"x":0.167,"y":0.167},"t":103,"s":[{"i":[[50.535,-88.565],[-2,9.5],[3.062,-17.035],[-5.976,5.993],[0.5,-6.5],[5.934,-7.504],[7,-4],[4.074,-9.416],[-3.552,9.486],[3.519,2.475],[1.834,7.336],[17,-2],[-31.5,-40.5],[-12,37],[17.325,35.722]],"o":[[-15.124,26.505],[1.014,-4.819],[-1.931,10.741],[3.819,-3.83],[-0.5,6.5],[-4.342,5.491],[-7,4],[-2.7,6.241],[2.679,-7.154],[-22.749,-16],[-3.5,-14],[-17,2],[31.5,40.5],[12,-37],[-19.828,-40.884]],"v":[[-142.2,-31.765],[-83.812,10.252],[-66.988,18.499],[-56.718,24.749],[-43.437,24.998],[-58.17,43.247],[-67.966,54.749],[-75.687,67.248],[-84.797,69.752],[-75.811,37.502],[-84.312,11.252],[-123,-6.75],[-120,133],[-18.5,110.5],[9.275,-34.409]],"c":true}]},{"t":159,"s":[{"i":[[35.5,-55.5],[-2,9.5],[-10,-9.5],[-4.5,-3],[0.5,-6.5],[0,-7],[7,-4],[7.5,-7],[13.5,20],[3.519,2.475],[1.834,7.336],[17,-2],[-31.5,-40.5],[-12,37],[32,23.5]],"o":[[-16.443,25.707],[1.014,-4.819],[10,9.5],[4.5,3],[-0.5,6.5],[0,7],[-7,4],[-7.5,7],[-6.426,-9.52],[-22.749,-16],[-3.5,-14],[-17,2],[31.5,40.5],[12,-37],[-32,-23.5]],"v":[[-121.5,-14.5],[-99,0],[-63,-8.5],[-48,7],[-27.5,21],[-38.5,51.5],[-60.5,82],[-61,99.5],[-97.5,98],[-91.001,40.25],[-99.5,1],[-123,-6.75],[-120,133],[-18.5,110.5],[2,-10.5]],"c":true}]}]},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":0},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.283336983475,0.343620988434,0.368627002192,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":"Shape 1","bm":0,"hd":false}],"ip":67,"op":180,"st":-10,"bm":0},{"ddd":0,"ind":15,"ty":4,"nm":"южная америка","parent":18,"tt":2,"sr":1,"ks":{"r":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":89,"s":[19.415]},{"t":179,"s":[0]}]},"p":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":89,"s":[232.695,303.169,0],"to":[18.898,-15.367,0],"ti":[-0.679,12.206,0]},{"t":179,"s":[256,256,0]}]},"a":{"a":0,"k":[256,256,0]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[-8.688,17.032],[-2.801,3.159],[-12.637,-0.059],[4.047,-5.902]],"o":[[1.33,-0.921],[3.488,5.27],[-9.45,7.072],[0,0]],"v":[[-4.316,-17.032],[0.65,-20.455],[9.769,-6.633],[-8.707,20.455]],"c":true}},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.517647087574,0.639215707779,0,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[194.498,320.076]},"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 47","bm":0,"hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[-4.081,2.896],[3.096,1.43],[1.777,-2.369],[4.739,-0.064],[4.677,20.506],[2.569,10.439],[-9.238,-7.249],[6.224,-9.205],[-0.397,-0.794],[-1.58,0.922],[0.263,3.423],[-3.336,8.437],[0,0],[-6.977,3.159]],"o":[[-3.643,-3.517],[-0.226,3.418],[-1.777,2.369],[-6.496,0.686],[-4.047,-3.455],[-0.168,5.656],[-0.948,12.594],[-0.872,5.23],[1.316,2.633],[1.58,-0.922],[-0.124,-1.611],[3.336,-8.437],[0,0],[2.106,-11.716]],"v":[[25.516,-35.033],[15.022,-42.081],[10.115,-36.613],[8.14,-25.886],[-10.915,-19.139],[-25.504,-38.195],[-14.962,-17.46],[-20.657,25.256],[-21.61,34.997],[-14.238,41.974],[-14.238,32.891],[-4.694,15.021],[7.613,-0.413],[14.722,-12.524]],"c":true}},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.901960790157,0.615686297417,0,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[196.654,313.856]},"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 48","bm":0,"hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[2.959,3.061],[-6.291,-0.061],[0.143,-3.061],[4.174,0]],"o":[[-7.366,-10.676],[2.561,-0.065],[-0.428,3.061],[-4.174,0]],"v":[[-10.949,6.118],[3.713,-6.811],[12.869,2.009],[0.677,1.121]],"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":107,"s":[0.231372565031,0.65098041296,0,1]},{"t":179,"s":[0.007843137719,0.321568638086,0.027450980619,1]}]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[187.71,265.475]},"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 52","bm":0,"hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[0.658,-2.501],[-1.185,1.777]],"o":[[-0.727,2.761],[1.185,-1.777]],"v":[[-1.7,-0.896],[1.591,1.013]],"c":true}},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.843137264252,0.584313750267,0.003921568859,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[193.33,349.947]},"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 67","bm":0,"hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[22.564,0.641],[-21.239,-18.329],[-1.316,-2.633],[2.603,12.357],[-11.189,4.114],[-6.977,3.159],[-4.081,2.896],[1.448,1.711]],"o":[[1.689,10.748],[-0.394,15.533],[5.521,8.855],[-0.263,-3.422],[0.033,-4.114],[2.106,-11.716],[-7.635,-7.372],[-14.765,-17.42]],"v":[[-21.708,-49.24],[-14.206,-10.012],[-21.577,42.906],[-14.206,40.799],[6.495,7.43],[14.755,-4.615],[25.549,-27.125],[8.305,-37.392]],"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":107,"s":[0.376470625401,0.529411792755,0.023529414088,1]},{"t":179,"s":[0.011764706112,0.40000000596,0.035294119269,1]}]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[196.621,305.948]},"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 93","bm":0,"hd":false},{"ty":"tr","p":{"a":0,"k":[196.621,305.948]},"a":{"a":0,"k":[196.621,305.948]},"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":67,"op":180,"st":-10,"bm":0},{"ddd":0,"ind":16,"ty":4,"nm":"Shape Layer 30","parent":15,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":49,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":70,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":126,"s":[100]},{"t":179,"s":[0]}]},"r":{"a":0,"k":-17.349},"p":{"a":0,"k":[264.425,204.705,0]},"s":{"a":0,"k":[82.512,99.798,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[33.267,1.25],[-7.343,-6.75],[-10.923,-12.5],[-2.681,5],[-5.65,7.25],[7.055,4]],"o":[[-20.289,15.25],[-5.779,16],[7.387,8.454],[1.266,-2.362],[5.65,-7.25],[-7.055,-4]],"v":[[-122.963,20.75],[-133.626,63.25],[-156.071,121.5],[-142.182,113.5],[-77.126,63.25],[-87.722,38.25]],"c":true}},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":0},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.407843167174,0.819607902976,0.992156922583,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":"Shape 1","bm":0,"hd":false}],"ip":49,"op":180,"st":0,"bm":0},{"ddd":0,"ind":17,"ty":4,"nm":"Shape Layer 9","parent":18,"td":1,"sr":1,"ks":{"r":{"a":0,"k":2.143},"p":{"a":0,"k":[238.993,257.168,0]},"s":{"a":0,"k":[82.487,99.765,100]}},"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.156},"t":53,"s":[{"i":[[37.556,11.349],[7.973,-33.347],[-0.062,0.185],[-0.072,0.194],[-0.051,-0.148],[-0.459,-0.086],[0.172,0.053],[0.132,-0.246],[-0.092,-0.112],[0.223,0.001],[0.035,0.19],[0.073,0.031],[0.285,0.183],[0.002,0.05],[22.312,-5.195],[-36.934,-56.911],[-95.085,10.449],[-9.055,25.303]],"o":[[-37.556,-11.349],[-6.226,26.04],[0.117,-0.346],[0.072,-0.194],[0.051,0.148],[0.459,0.086],[-0.172,-0.053],[-0.132,0.246],[0.289,0.35],[-0.223,-0.001],[-0.035,-0.19],[-0.073,-0.031],[-0.285,-0.183],[-0.002,-0.05],[-22.312,5.195],[36.934,56.911],[95.085,-10.449],[9.055,-25.303]],"v":[[-82.609,-144.71],[-225.667,-105.003],[-119.154,-59.086],[-118.304,-59.262],[-117.549,-59.352],[-116.883,-58.688],[-116.571,-58.274],[-117.293,-58.272],[-117.124,-57.96],[-117.656,-57.71],[-118.447,-58.091],[-118.635,-58.677],[-118.927,-58.886],[-119.112,-59.17],[-221.716,-109.376],[-237.187,10.211],[-18.147,45.973],[20.01,-24.271]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":77,"s":[{"i":[[37.556,11.349],[7.973,-33.347],[-1.86,5.51],[-2.138,5.784],[-1.534,-4.427],[-13.716,-2.559],[5.138,1.581],[3.935,-7.331],[-2.749,-3.331],[6.669,0.042],[1.057,5.685],[2.175,0.927],[8.514,5.454],[0.067,1.489],[22.312,-5.195],[-36.934,-56.911],[-95.085,10.449],[-9.055,25.303]],"o":[[-37.556,-11.349],[-6.226,26.04],[3.488,-10.335],[2.138,-5.784],[1.534,4.427],[13.716,2.559],[-5.138,-1.581],[-3.935,7.331],[8.627,10.456],[-6.669,-0.042],[-1.057,-5.685],[-2.175,-0.927],[-8.514,-5.454],[-0.067,-1.489],[-22.312,5.195],[36.934,56.911],[95.085,-10.449],[9.055,-25.303]],"v":[[-82.609,-144.71],[-225.667,-105.003],[-158.004,-74.392],[-132.623,-79.652],[-110.078,-82.338],[-90.22,-62.535],[-80.889,-50.178],[-102.436,-50.103],[-97.39,-40.8],[-113.279,-33.342],[-136.909,-44.716],[-142.5,-62.193],[-151.228,-68.44],[-156.754,-76.916],[-221.716,-109.376],[-237.187,10.211],[-18.147,45.973],[20.01,-24.271]],"c":true}]},{"i":{"x":0.739,"y":0.764},"o":{"x":0.167,"y":0.167},"t":170,"s":[{"i":[[37.556,11.349],[24.54,-8.528],[-6.156,9.367],[-4.127,11.163],[-2.96,-8.545],[-26.472,-4.939],[9.917,3.052],[7.594,-14.149],[-18.731,-17.158],[12.871,0.082],[2.041,10.972],[4.198,1.789],[16.432,10.527],[0.13,2.875],[22.312,-5.195],[-36.934,-56.911],[-95.085,10.449],[-9.055,25.303]],"o":[[-37.556,-11.349],[-24.396,7.928],[6.289,-9.762],[4.127,-11.163],[2.96,8.545],[26.472,4.939],[-9.917,-3.052],[-7.595,14.149],[19.213,17.743],[-12.871,-0.082],[-2.041,-10.972],[-4.198,-1.789],[-16.432,-10.527],[-0.13,-2.875],[-22.312,5.195],[36.934,56.911],[95.085,-10.449],[9.055,-25.303]],"v":[[-82.609,-144.71],[-212.245,-133.211],[-198.518,-102.47],[-148.68,-103.919],[-105.166,-109.104],[-51.582,-81.063],[-48.83,-47.034],[-80.459,-20.836],[-45.694,-18.823],[-101.816,-0.066],[-156.951,-36.491],[-167.742,-70.223],[-196.363,-66.656],[-201.279,-89.725],[-231.975,-97.574],[-237.187,10.211],[-18.147,45.973],[20.01,-24.271]],"c":true}]},{"t":179,"s":[{"i":[[37.556,11.349],[26.02,-6.31],[-6.539,9.711],[-4.305,11.644],[-3.088,-8.913],[-27.612,-5.151],[10.344,3.183],[7.921,-14.758],[-20.159,-18.394],[13.425,0.085],[2.129,11.445],[4.379,1.866],[17.139,10.98],[0.136,2.999],[22.312,-5.195],[-36.934,-56.911],[-95.085,10.449],[-9.055,25.303]],"o":[[-37.556,-11.349],[-26.02,6.31],[6.539,-9.711],[4.305,-11.644],[3.088,8.913],[27.612,5.151],[-10.344,-3.183],[-7.922,14.758],[20.159,18.394],[-13.425,-0.085],[-2.129,-11.445],[-4.379,-1.866],[-17.139,-10.98],[-0.136,-2.999],[-22.312,5.195],[36.934,56.911],[95.085,-10.449],[9.055,-25.303]],"v":[[-82.609,-144.71],[-211.046,-135.731],[-202.138,-104.978],[-150.114,-106.088],[-104.727,-111.496],[-48.13,-82.719],[-45.965,-46.753],[-78.495,-18.221],[-33.343,-5.104],[-96.55,9.863],[-158.741,-35.756],[-169.997,-70.941],[-200.396,-66.497],[-205.257,-90.869],[-232.892,-96.52],[-237.187,10.211],[-18.147,45.973],[20.01,-24.271]],"c":true}]}]},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":0},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.283336983475,0.343620988434,0.368627002192,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":"Shape 1","bm":0,"hd":false}],"ip":53,"op":180,"st":-38,"bm":0},{"ddd":0,"ind":18,"ty":4,"nm":"северная америка","parent":36,"tt":2,"sr":1,"ks":{"p":{"a":1,"k":[{"i":{"x":0.524,"y":1},"o":{"x":0.276,"y":0},"t":94,"s":[99.837,201.706,0],"to":[6.236,0.068,0],"ti":[-6.236,-0.068,0]},{"t":179,"s":[137.254,202.115,0]}]},"a":{"a":0,"k":[137.254,202.115,0]},"s":{"a":1,"k":[{"i":{"x":[0.685,0.685,0.685],"y":[1,1,1]},"o":{"x":[0.395,0.395,0.395],"y":[0,0,0]},"t":94,"s":[121,100,100]},{"t":179,"s":[100,100,100]}]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[3.949,-6.582],[-3.028,1.147],[2.324,-4.079],[8.189,-1.43],[-0.954,-6.095]],"o":[[0.719,-6.45],[7.635,-9.688],[-1.032,1.81],[-1.975,6.146],[-10.322,-11.624]],"v":[[-12.365,3.902],[-4.993,-8.262],[12.065,1.269],[-2.294,-8.262],[7.151,11.444]],"c":true}},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.827450990677,0.854901969433,0.92549020052,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[106.584,174.351]},"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 49","bm":0,"hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[3.817,-4.352],[-0.79,-2.975],[-3.159,-0.395],[-8.868,2.278]],"o":[[-3.441,3.348],[0.79,2.975],[3.159,0.395],[-10.895,-0.93]],"v":[[-10.723,-4.342],[-7.432,3.148],[0.861,6.123],[11.787,-2.96]],"c":true}},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.827450990677,0.854901969433,0.92549020052,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[94.938,156.992]},"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 50","bm":0,"hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[0,0],[-4.099,-3.668],[1.645,1.341],[0.114,3.071],[1.389,-6.155]],"o":[[3.161,4.35],[1.251,1.119],[-0.69,-0.562],[-0.051,-1.373],[0,0]],"v":[[-4.395,-11.496],[4.164,0.423],[-0.388,11.385],[0.412,4.405],[-3.642,8.849]],"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":107,"s":[0.894117712975,0.713725507259,0.011764707044,1]},{"t":179,"s":[0.901960790157,0.615686297417,0,1]}]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[156.993,210.673]},"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 51","bm":0,"hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[-5.769,0.016],[-5.769,2.573],[0,0],[3.428,-4.51],[2.147,-0.96],[3.362,1.523],[1.911,-0.819],[-3.137,-8.441],[-8.389,-15.895],[-1.514,0.876]],"o":[[-4.156,-2.172],[0,0],[0,0],[-3.524,4.637],[-2.147,0.96],[-3.362,-1.523],[-3.554,1.522],[2.706,7.281],[3.474,3.292],[1.514,-0.876]],"v":[[14.891,28.109],[14.891,12.801],[13.925,-13.329],[-6.194,-27.404],[-1.112,-2.298],[-6.444,-11.677],[-11.676,-19.436],[-12.96,-0.521],[5.928,25.559],[4.712,17.697]],"c":true}},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.89411765337,0.713725507259,0.011764706112,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[138.673,212.506]},"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 53","bm":0,"hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[0,0],[0,0],[-2.421,0],[6.763,0.494],[2.32,0.346],[2.809,1.481]],"o":[[15.453,0.263],[0,0],[-3.11,-5.816],[-6.763,-0.494],[-2.32,-0.346],[0,0]],"v":[[-19.795,-1.168],[0.606,8.046],[20.089,7.661],[3.552,5.134],[-10.319,-7.256],[-20.089,-8.046]],"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":107,"s":[0.376470625401,0.529411792755,0.023529414088,1]},{"t":179,"s":[0.06274510175,0.290196090937,0,1]}]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[174.306,248.662]},"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 90","bm":0,"hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[0,0],[-3.088,0.643],[0,0],[5.66,0],[2.501,5.002],[10.136,-5.002],[4.849,-2.928],[9.675,-5.068],[-1.975,-3.423],[-2.238,5.397],[-6.921,-3.081],[-10.399,-9.873],[-10.915,-2.776]],"o":[[-5.731,-3.603],[0,0],[-1.436,1.31],[-5.66,0],[-2.501,-5.002],[-4.408,2.175],[-10.465,6.319],[-1.843,3.949],[1.975,3.423],[10.186,-15.888],[0.527,14.105],[13.284,11.4],[0,0]],"v":[[37.753,41.438],[37.1,26.13],[33.925,-48.316],[23.302,-44.092],[14.745,-41.196],[-9.739,-45.145],[-32.249,-46.528],[-37.778,-28.033],[-29.485,-20.793],[-22.245,-20.924],[5.794,-3.7],[15.798,22.647],[38.047,48.316]],"c":true}},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.376470595598,0.529411792755,0.023529412225,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[116.464,199.177]},"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 91","bm":0,"hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[-3.061,1.185],[-5.035,4.739],[-6.516,0.395],[1.975,1.777],[-5.43,-4.344],[6.22,6.615],[2.527,3.224],[-1.435,-11.32],[0.889,6.22],[-2.647,5.278],[1.817,3.18],[0.472,-9.437],[0,0],[-3.357,-0.889]],"o":[[2.369,-1.975],[5.035,-4.739],[6.516,-0.395],[-1.975,-1.777],[5.43,4.344],[-2.936,-3.123],[-5.234,-6.677],[1.231,9.704],[-0.889,-6.22],[1.356,-2.703],[-3.159,-5.529],[0,0],[0,0],[3.357,0.889]],"v":[[-3.484,41.3],[-0.522,28.861],[10.437,13.262],[12.115,3.389],[18.829,2.5],[18.039,-6.78],[6.896,-14.695],[-0.621,-10.828],[-6.445,-4.608],[-19.774,-20.602],[-12.106,-30.112],[-22.808,-37.891],[-19.632,36.555],[-8.223,35.475]],"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":107,"s":[0.376470625401,0.529411792755,0.023529414088,1]},{"t":179,"s":[0.06274510175,0.290196090937,0,1]}]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[173.196,188.751]},"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 92","bm":0,"hd":false},{"ty":"tr","p":{"a":0,"k":[196.621,305.948]},"a":{"a":0,"k":[196.621,305.948]},"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":53,"op":180,"st":-38,"bm":0},{"ddd":0,"ind":19,"ty":4,"nm":"Shape Layer 31","parent":18,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":60,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":83,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":125,"s":[100]},{"t":150,"s":[0]}]},"r":{"a":0,"k":-2.921},"p":{"a":0,"k":[288.264,256.507,0]},"s":{"a":0,"k":[84.314,101.936,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[16.926,-9],[-6.794,2.25]],"o":[[-16.926,9],[6.794,-2.25]],"v":[[-164.818,-99],[-162.302,-87]],"c":true}},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":0},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.505882352941,0.854902020623,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":"Shape 4","bm":0,"hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[10.059,-3],[-15.873,-6.5],[0.373,6.5],[13.059,-3],[5.148,5.25],[1.893,5.5]],"o":[[-10.059,3],[15.873,6.5],[-0.373,-6.5],[-13.059,3],[-5.148,-5.25],[-1.893,-5.5]],"v":[[-180.203,-79.25],[-167.837,-46.75],[-119.408,-68.75],[-147.858,-58.5],[-151.791,-74.75],[-167.796,-74.5]],"c":true}},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":0},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.505882352941,0.854902020623,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":"Shape 3","bm":0,"hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[3.117,-6],[-7.633,-6],[9.437,3.25]],"o":[[-3.117,6],[7.633,6],[-9.437,-3.25]],"v":[[-208.691,-101.137],[-191.694,-92.5],[-190.749,-102.5]],"c":true}},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":0},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.505882352941,0.854902020623,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":"Shape 2","bm":0,"hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[5.166,-8.5],[-4.503,-3.108],[0.744,-12.5],[-9.646,-0.079],[-7.548,3.054],[10.188,16],[17.197,15.5],[8.756,12.5],[11.863,7]],"o":[[-5.166,8.5],[15.969,11.024],[-0.744,12.5],[10.809,0.089],[7.064,-2.858],[-10.188,-16],[-17.197,-15.5],[-8.756,-12.5],[-11.863,-7]],"v":[[-210.229,-108.843],[-207.896,-81.661],[-192.394,-59.679],[-161.346,-33.5],[-137.709,-40.5],[-115.36,-84],[-141.526,-75.5],[-144.921,-106.5],[-184.941,-105.5]],"c":true}},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":0},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.407843167174,0.819607902976,0.992156922583,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":"Shape 1","bm":0,"hd":false}],"ip":60,"op":180,"st":0,"bm":0},{"ddd":0,"ind":20,"ty":4,"nm":"Shape Layer 8","parent":21,"td":1,"sr":1,"ks":{"p":{"a":0,"k":[250.863,257.423,0]},"s":{"a":0,"k":[83.948,99.787,100]}},"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.156},"t":61,"s":[{"i":[[58.5,9.5],[-2.5,-41.5],[-31.469,2.71],[-0.018,0.136],[1.506,-0.354],[0.092,0.507],[-0.116,0.448],[-1.998,-0.102],[-0.51,-0.51],[-0.679,0.148],[-0.295,-0.118],[-0.11,-0.222],[0.123,-0.261],[0.222,-0.277],[0.325,-0.177],[0.32,0.049],[0.473,0.443],[-3,-12.5],[-42.5,4.5],[11.5,36.5]],"o":[[-58.5,-9.5],[1.73,28.716],[14.009,-1.206],[0.059,-0.443],[-1.279,0.3],[-0.073,-0.401],[0.046,-0.177],[2.15,0.109],[0.51,0.51],[0.679,-0.148],[0.295,0.118],[0.112,0.226],[-0.243,0.519],[-0.312,0.388],[-0.325,0.177],[-0.361,-0.055],[-0.473,-0.443],[3,12.5],[42.5,-4.5],[-11.5,-36.5]],"v":[[-85.5,-200.5],[-181.5,-138],[-90.994,-82.436],[-49.951,-122.818],[-84.048,-141.373],[-86.691,-141.227],[-88.225,-141.482],[-86.352,-141.993],[-85.24,-140.863],[-49.459,-123.689],[-48.612,-123.527],[-48.145,-123.458],[-48.632,-123.056],[-48.254,-122.227],[-49.12,-122.404],[-49.495,-122.05],[-49.921,-122.892],[-98.5,-84],[-11,-57.5],[27,-167.5]],"c":true}]},{"i":{"x":0.739,"y":0.745},"o":{"x":0.167,"y":0.167},"t":85,"s":[{"i":[[58.5,9.5],[-2.5,-41.5],[-31.469,2.71],[-0.308,2.31],[10.336,-2.426],[0.632,3.479],[-0.794,3.074],[-13.712,-0.697],[-3.5,-3.5],[-11.5,2.5],[-5,-2],[-1.867,-3.762],[2.074,-4.426],[3.758,-4.682],[5.5,-3],[5.41,0.824],[8,7.5],[-3,-12.5],[-42.5,4.5],[11.5,36.5]],"o":[[-58.5,-9.5],[1.73,28.716],[14.009,-1.206],[1,-7.5],[-8.775,2.06],[-0.5,-2.75],[0.314,-1.213],[14.75,0.75],[3.5,3.5],[11.5,-2.5],[5,2],[1.898,3.824],[-4.12,8.791],[-5.276,6.574],[-5.5,3],[-6.117,-0.932],[-8,-7.5],[3,12.5],[42.5,-4.5],[-11.5,-36.5]],"v":[[-85.5,-200.5],[-181.5,-138],[-90.994,-82.436],[-61.703,-122.5],[-75.854,-142.25],[-93.984,-141.25],[-104.51,-143],[-91.663,-146.5],[-84.03,-138.75],[-53.368,-137.25],[-39.034,-134.5],[-20.508,-135.5],[-30.262,-127.25],[-32.981,-112.5],[-47.64,-115.5],[-53.982,-109.5],[-61.203,-123.75],[-98.5,-84],[-11,-57.5],[27,-167.5]],"c":true}]},{"i":{"x":0.833,"y":1},"o":{"x":0.344,"y":0.336},"t":115,"s":[{"i":[[58.5,9.5],[-2.5,-41.5],[-31.469,2.71],[-0.308,2.31],[7.75,5.25],[0.632,3.478],[-3.855,7.29],[-13.712,-0.697],[-3.5,-3.5],[-11.5,2.5],[-5,-2],[-0.37,-1.778],[8,-5.5],[3.115,-14.707],[5.5,-3],[6.483,0.58],[14.195,9.33],[-3,-12.5],[-42.5,4.5],[11.5,36.5]],"o":[[-58.5,-9.5],[1.73,28.716],[14.009,-1.206],[1,-7.5],[-7.463,-5.055],[-0.5,-2.75],[1.015,-1.92],[14.75,0.75],[3.5,3.5],[11.5,-2.5],[5,2],[1.006,4.83],[-8,5.5],[-1.416,6.686],[-5.5,3],[-6.544,-0.586],[-9.164,-6.023],[3,12.5],[42.5,-4.5],[-11.5,-36.5]],"v":[[-85.5,-200.5],[-181.5,-138],[-90.994,-82.436],[-68.088,-122],[-105.369,-127.75],[-93.22,-140],[-107.948,-143.75],[-92.154,-145.75],[-75.68,-141.5],[-46,-142.75],[-33.877,-138.75],[-23.455,-137.75],[-29.771,-130.5],[-35.192,-115.5],[-47.885,-107.75],[-56.93,-101.75],[-67.588,-123.25],[-98.5,-84],[-11,-57.5],[27,-167.5]],"c":true}]},{"t":179,"s":[{"i":[[58.5,9.5],[-2.5,-41.5],[-31.469,2.71],[-0.308,2.31],[7.75,5.25],[1.231,3.314],[-6.286,5.338],[-13.712,-0.697],[-3.5,-3.5],[-11.5,2.5],[-5,-2],[-4.5,-8.5],[8,-5.5],[1,-15],[5.5,-3],[17,-2.5],[8,7.5],[-3,-12.5],[-42.5,4.5],[11.5,36.5]],"o":[[-58.5,-9.5],[1.73,28.716],[14.009,-1.206],[1,-7.5],[-7.463,-5.055],[-7.094,-19.102],[12.778,-10.852],[14.75,0.75],[3.5,3.5],[11.5,-2.5],[5,2],[4.5,8.5],[-8,5.5],[-1,15],[-5.5,3],[-17,2.5],[-8,-7.5],[3,12.5],[42.5,-4.5],[-11.5,-36.5]],"v":[[-85.5,-200.5],[-181.5,-138],[-90.994,-82.436],[-85.213,-85.75],[-134.568,-92.5],[-163.911,-113.25],[-157.764,-148.75],[-100.75,-152.5],[-71.75,-149],[-46,-150.5],[-27,-145.5],[-7,-144],[-17,-127.5],[-18,-106.5],[-41.5,-95],[-53,-83],[-84.713,-87],[-98.5,-84],[-11,-57.5],[27,-167.5]],"c":true}]}]},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":0},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.283336983475,0.343620988434,0.368627002192,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":"Shape 1","bm":0,"hd":false}],"ip":61,"op":180,"st":-30,"bm":0},{"ddd":0,"ind":21,"ty":4,"nm":"гренландия","parent":18,"tt":2,"sr":1,"ks":{"r":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0.28]},"t":61,"s":[13.176]},{"t":179,"s":[0]}]},"p":{"a":0,"k":[256,256,0]},"a":{"a":0,"k":[256,256,0]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[2.518,-2.024],[6.808,5.194]],"o":[[-4.699,6.451],[-2.576,-1.193]],"v":[[-3.812,-2.89],[3.059,0.524]],"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":108,"s":[0.964705944061,0.980392217636,0.98431378603,1]},{"t":179,"s":[0.631372570992,0.658823549747,0.690196096897,1]}]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[153.828,120.097]},"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 54","bm":0,"hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[2.304,2.238],[-5.397,-2.304],[0.066,2.172]],"o":[[-2.643,-2.567],[5.397,2.304],[-0.066,-2.172]],"v":[[0.637,-1.711],[-2.851,1.383],[4.981,0.329]],"c":true}},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.964705884457,0.980392158031,0.984313726425,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[142.814,125.269]},"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 55","bm":0,"hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[-1.382,-1.185],[1.185,1.185]],"o":[[1.873,1.606],[-1.185,-1.185]],"v":[[-0.93,0.6],[0.913,-0.782]],"c":true}},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.964705884457,0.980392158031,0.984313726425,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[131.086,127.302]},"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 56","bm":0,"hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[2.172,-2.567],[-1.711,-2.106],[-2.435,2.369],[1.251,1.316]],"o":[[-2.348,2.775],[1.711,2.106],[2.435,-2.369],[-1.251,-1.316]],"v":[[-8.392,-2.542],[-3.193,0.749],[8.589,2.592],[-1.152,-1.225]],"c":true}},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.964705884457,0.980392158031,0.984313726425,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[129.663,133.932]},"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 57","bm":0,"hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[0.921,-2.633],[-2.633,2.962],[-1.251,-3.554],[-4.871,2.238],[1.843,2.567],[2.699,-0.658],[2.238,2.501]],"o":[[-1.439,4.112],[2.633,-2.962],[1.251,3.554],[4.871,-2.238],[-1.843,-2.567],[-2.699,0.658],[-2.238,-2.501]],"v":[[-11.831,-5.93],[-7.751,0.981],[-2.09,0.981],[6.137,6.576],[11.6,2.232],[6.795,-5.93],[-3.143,-4.153]],"c":true}},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.964705884457,0.980392158031,0.984313726425,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[130.864,146.6]},"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 58","bm":0,"hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[6.12,-0.329],[-2.83,0.658]],"o":[[-4.393,0.236],[2.83,-0.658]],"v":[[-2.855,-3.569],[3.07,3.54]],"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":108,"s":[0.964705944061,0.980392217636,0.98431378603,1]},{"t":179,"s":[0.631372570992,0.658823549747,0.690196096897,1]}]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[180.07,163.656]},"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 59","bm":0,"hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[7.554,11.351],[4.739,-5.726],[-1.975,-5.529],[1.58,3.827]],"o":[[-10.281,-12.307],[-4.739,5.726],[1.975,5.529],[-3.405,-6.566]],"v":[[14.596,7.99],[-14.232,-9.189],[-9.691,3.251],[-4.952,-1.413]],"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":108,"s":[0.964705944061,0.980392217636,0.98431378603,1]},{"t":179,"s":[0.631372570992,0.658823549747,0.690196096897,1]}]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[172.69,150.781]},"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 79","bm":0,"hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[-3.291,-3.159],[-5.002,2.369],[-0.397,-8.132],[-2.764,-3.028]],"o":[[3.653,3.507],[5.002,-2.369],[0.137,2.811],[2.764,3.028]],"v":[[-11.371,9.584],[14.166,-7.133],[-14.662,-5.027],[-2.42,-2.395]],"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":108,"s":[0.964705944061,0.980392217636,0.98431378603,1]},{"t":179,"s":[0.631372570992,0.658823549747,0.690196096897,1]}]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[171.014,120.621]},"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 80","bm":0,"hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[0.099,-3.258],[-7.129,-20.154],[-3.357,-1.744],[-0.197,6.911],[-2.172,3.809],[-5.331,4.344],[0.79,1.382],[0.592,3.554],[5.44,-3.309],[5.934,-4.593]],"o":[[4.094,8.006],[0.001,-0.001],[3.357,1.744],[0.197,-6.911],[2.172,-3.809],[5.331,-4.344],[-0.79,-1.382],[-0.592,-3.554],[-11.847,7.207],[-11.354,8.787]],"v":[[-31.462,-13.979],[-8.361,8.401],[-5.2,28.935],[1.908,23.669],[22.246,11.353],[24.023,-13.979],[31.329,-22.074],[17.112,-22.074],[4.771,-28.985],[-15.468,-24.937]],"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":108,"s":[0.964705944061,0.980392217636,0.98431378603,1]},{"t":179,"s":[0.631372570992,0.658823549747,0.690196096897,1]}]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[208.678,140.367]},"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 89","bm":0,"hd":false},{"ty":"tr","p":{"a":0,"k":[196.621,305.948]},"a":{"a":0,"k":[196.621,305.948]},"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":61,"op":180,"st":-30,"bm":0},{"ddd":0,"ind":22,"ty":4,"nm":"Shape Layer 6","parent":23,"td":1,"sr":1,"ks":{"p":{"a":0,"k":[256,246.021,0]},"s":{"a":0,"k":[99.787,99.787,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0.323,"y":0.597},"o":{"x":0.348,"y":0},"t":30,"s":[{"i":[[41.5,16],[9.34,-10.623],[-0.016,0],[-0.009,-0.002],[-0.021,-0.031],[0,0],[0.012,-0.016],[0,0],[0.015,0.001],[0,0],[-0.001,0.01],[0,0],[0.007,0.003],[0,0],[0.004,0.014],[0,0],[-0.004,0.004],[22.153,-11.853],[-15.5,-13],[-41.5,-23.5],[-18,19.5],[-4,29]],"o":[[-22.306,-8.6],[-8.037,9.141],[0.029,0],[0.03,0.007],[0.005,0.008],[0,0],[-0.014,0.019],[0,0],[-0.012,-0.001],[0,0],[0.002,-0.016],[0,0],[-0.007,-0.003],[0,0],[-0.008,-0.028],[0,0],[0.016,-0.016],[-35.456,18.97],[15.5,13],[41.5,23.5],[18,-19.5],[4,-29]],"v":[[42.5,-65.5],[-35.092,-53.106],[17.339,18.438],[17.384,18.458],[17.411,18.494],[17.429,18.517],[17.421,18.551],[17.405,18.607],[17.392,18.642],[17.377,18.598],[17.381,18.559],[17.381,18.517],[17.368,18.505],[17.339,18.51],[17.318,18.495],[17.325,18.449],[17.34,18.438],[-32.727,-49.579],[-54.5,49.5],[-13,112.5],[85,78.5],[88,7.5]],"c":true}]},{"i":{"x":0.833,"y":0.911},"o":{"x":0.167,"y":0.099},"t":74.842,"s":[{"i":[[41.5,16],[9.34,-10.623],[-6.876,0.019],[-3.911,-0.839],[-1.502,-7.352],[2.146,-9.165],[4.052,-5.47],[-4.398,-4.2],[8.103,0.754],[5.128,8.592],[-0.55,3.852],[-5.257,3.006],[4.909,-4.688],[2.455,-7.227],[1.627,5.541],[-2.554,3.193],[-11.145,3.566],[22.153,-11.853],[-15.5,-13],[-41.5,-23.5],[-18,19.5],[-4,29]],"o":[[-22.306,-8.6],[-8.037,9.141],[12.778,-0.035],[13.163,2.825],[1.616,7.907],[-0.73,3.12],[-4.501,6.075],[5.068,4.84],[-5.637,-0.525],[-4.291,-7.189],[0.98,-6.863],[2.31,-1.321],[-5.641,5.387],[-1.156,3.403],[-2.779,-9.466],[2.666,-3.333],[9.392,-3.006],[-35.456,18.97],[15.5,13],[41.5,23.5],[18,-19.5],[4,-29]],"v":[[42.5,-65.5],[-35.092,-53.106],[1.957,-22.941],[21.302,-14.061],[31.244,3.427],[41.807,13.457],[37.351,26.027],[28.716,43.298],[25.043,65.914],[18.581,45.294],[19.972,29.886],[20.224,11.857],[14.256,6.215],[1.449,5.047],[-7.529,1.807],[-0.582,-11.458],[2.431,-22.841],[-32.727,-49.579],[-54.5,49.5],[-13,112.5],[85,78.5],[88,7.5]],"c":true}]},{"i":{"x":0.739,"y":0.965},"o":{"x":0.167,"y":0.089},"t":119.684,"s":[{"i":[[41.5,16],[9.34,-10.623],[-4.404,-3.498],[-15.004,-10.063],[-12.461,-1.046],[0.656,-5.5],[2.701,-8.923],[3.22,-7.19],[9.648,1.08],[-0.926,9.572],[0.106,4.24],[2.248,4.733],[1.837,1.37],[4.171,-2.148],[3.437,3.373],[-4.429,5.6],[0.284,2.538],[19.362,-15.453],[-15.5,-13],[-41.5,-23.5],[-18,19.5],[-4,29]],"o":[[-22.306,-8.6],[-8.037,9.141],[14.57,-10.894],[11.437,8.257],[7.56,0.314],[-0.596,4.993],[-3.124,9.191],[-3.96,8.84],[-7.421,-0.831],[0.617,-6.379],[-0.261,-10.453],[-1.044,-2.199],[-2.213,-1.974],[-3.59,1.849],[-12.018,-16.538],[2.724,-3.445],[0.409,-7.877],[-25.46,18.715],[15.5,13],[41.5,23.5],[18,-19.5],[4,-29]],"v":[[42.5,-65.5],[-29.215,-56.478],[-10.102,-24.43],[24.805,-19.389],[46.259,7.059],[55.132,15.889],[49.077,36.845],[40.382,62.439],[21.499,75.981],[14.751,56.308],[16.404,39.174],[13.215,17.037],[8.951,11.747],[-1.206,15.011],[-12.117,14.64],[-15.949,-15.922],[-10.53,-24.281],[-45.874,-44.662],[-54.5,49.5],[-13,112.5],[85,78.5],[88,7.5]],"c":true}]},{"t":179,"s":[{"i":[[41.5,16],[9.34,-10.623],[-2.313,-6.475],[-30,-15.5],[3.5,-7],[-1.199,-7.208],[0.714,-10.707],[5.962,-6.948],[12.132,1.379],[-0.517,10.43],[-0.6,4.199],[1.591,4.087],[0.952,1.586],[3.177,-1.843],[4.857,1.156],[-6.017,12.677],[1.904,3.237],[17,-18.5],[-15.5,-13],[-41.5,-23.5],[-18,19.5],[-4,29]],"o":[[-22.306,-8.6],[-8.037,9.141],[5,14],[11.961,6.18],[-1.835,3.669],[1.088,6.544],[-0.673,10.092],[-7.33,8.543],[-13.202,-1.5],[0.345,-6.95],[1.024,-7.169],[-0.739,-1.899],[-1.612,-2.687],[-2.735,1.586],[-22.505,-5.358],[3.701,-7.799],[-5,-8.5],[-17,18.5],[15.5,13],[41.5,23.5],[18,-19.5],[4,-29]],"v":[[42.5,-65.5],[-24.24,-59.332],[-24,-40],[29,-26.5],[57,4.5],[57.414,20.42],[59,46],[48.574,72.327],[18.5,84.5],[3.416,62.067],[6,44],[4.593,27.673],[2,22.5],[-4.835,23.445],[-16,25.5],[-27.319,-7.55],[-21.5,-25.5],[-57,-40.5],[-54.5,49.5],[-13,112.5],[85,78.5],[88,7.5]],"c":true}]}]},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":0},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"gf","o":{"a":0,"k":100},"r":1,"bm":0,"g":{"p":3,"k":{"a":0,"k":[0,0.945,0.981,1,0.5,0.576,0.859,0.978,1,0.208,0.737,0.957]}},"s":{"a":0,"k":[0,0]},"e":{"a":0,"k":[100,0]},"t":1,"nm":"Gradient Fill 15","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":30,"op":180,"st":-38,"bm":0},{"ddd":0,"ind":23,"ty":4,"nm":"африка","parent":29,"tt":2,"sr":1,"ks":{"r":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":45,"s":[-13.961]},{"t":179,"s":[0]}]},"p":{"a":1,"k":[{"i":{"x":0.655,"y":1},"o":{"x":0.167,"y":0},"t":45,"s":[276.381,308.463,0],"to":[-12.818,-9.648,0],"ti":[3.397,8.744,0]},{"t":179,"s":[256,256,0]}]},"a":{"a":0,"k":[256,256,0]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[1.78,3.482],[-1.759,-0.586],[-4.805,2.238],[-4.939,-1.222],[4.147,-4.147]],"o":[[-2.537,-4.962],[2.369,0.79],[4.805,-2.238],[4.939,1.222],[-4.147,4.147]],"v":[[-9.478,4.351],[-9.132,-2.827],[-1.629,0.245],[6.464,-7.691],[8.441,5.412]],"c":true}},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.06274510175,0.568627476692,0,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[276.914,269.902]},"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 33","bm":0,"hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[6.73,3.106],[-2.304,-4.476],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[-5.767,-1.966]],"v":[[-5.841,-2.96],[-6.054,2.96],[7,2.833],[7.026,-1.7]],"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":100,"s":[0.090196080506,0.600000023842,0.023529414088,1]},{"t":179,"s":[0,0.368627458811,0,1]}]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[249,252.888]},"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 35","bm":0,"hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[0,0],[-2.424,-7.954],[8.401,4.999],[2.663,1.449],[15.023,-5.152],[0,0]],"o":[[2.314,7.727],[-2.961,5.787],[-2.042,-2.54],[-7.969,-4.858],[0,0],[0,0]],"v":[[20.915,-14.844],[13.177,-1.582],[-3.457,13.819],[-8.07,5.89],[-21.203,-9.431],[-21.203,-14.795]],"c":true}},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.23137255013,0.65098041296,0,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[277.203,270.516]},"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 36","bm":0,"hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[0,0],[0,0],[-8.222,3.387],[-5.265,-2.691],[-6.471,-13.627]],"o":[[0,0],[6.086,1.005],[4.862,1.613],[13.498,11.426],[0,0]],"v":[[-21.057,2.751],[-21.031,-1.782],[-8.661,0.908],[1.553,-2.154],[21.057,2.697]],"c":true}},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.090196080506,0.600000023842,0.023529412225,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[277.057,252.969]},"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 37","bm":0,"hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[2.929,-0.016],[-5.451,3.173],[0,0],[0,0],[0,0],[-9.451,4.049],[-2.666,2.626]],"o":[[-2.907,-0.479],[4.049,-0.296],[0,0],[0,0],[13.314,-5.212],[2.37,-0.692],[1.529,-1.143]],"v":[[9.395,-8.056],[22.18,16.378],[26.196,19.275],[-26.196,19.34],[-25.97,-18.242],[-4.772,-12.252],[9.731,-10.912]],"c":true}},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.921568632126,0.890196084976,0.564705908298,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[282.196,236.38]},"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 84","bm":0,"hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[1.929,-2.319],[0.987,-2.962],[-3.061,-0.099],[-1.777,4.64]],"o":[[-3.068,3.689],[-0.987,2.962],[3.061,0.099],[1.777,-4.64]],"v":[[1.603,-9.095],[-3.333,-2.579],[-1.26,9.762],[3.084,-2.677]],"c":true}},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.980392158031,0.713725507259,0.286274522543,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[306.031,297.988]},"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 85","bm":0,"hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[-0.132,-12.129],[-1.185,-6.45],[-3.291,-2.106],[-4.4,5.334],[1.843,10.926],[-0.263,8.03],[0,0],[0,0],[0.421,-5.047]],"o":[[-1.928,4.381],[1.185,6.45],[13.498,6.659],[1.316,-0.921],[5.002,-8.951],[-2.896,0],[0,0],[5.002,-2.271],[-0.79,9.478]],"v":[[-11.321,-1.873],[-9.609,17.477],[-6.713,31.299],[12.637,7.473],[15.401,-12.141],[26.196,-32.413],[-26.196,-32.347],[-26.196,-26.983],[-16.849,-23.593]],"c":true}},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.980392158031,0.713725507259,0.286274522543,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[282.196,288.068]},"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 86","bm":0,"hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[0,0],[2.716,4.902],[0.012,-0.046]],"o":[[-5.265,2.633],[1.585,0.006],[0,0]],"v":[[6.527,2.195],[-6.527,-3.042],[6.527,-3.17]],"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":100,"s":[0.231372565031,0.65098041296,0,1]},{"t":179,"s":[0.06274510175,0.415686279535,0.015686275437,1]}]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[249.473,258.89]},"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 87","bm":0,"hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[0,0],[1.975,-7.767],[-10.531,-16.586],[0,0]],"o":[[-5.886,1.448],[-6.582,4.871],[2.762,0.167],[0,0]],"v":[[9.298,-18.806],[-0.405,-10.513],[-4.091,18.71],[9.073,18.776]],"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":100,"s":[0.92156869173,0.890196144581,0.564705908298,1]},{"t":179,"s":[0.686274528503,0.631372570992,0.454901963472,1]}]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[246.927,236.945]},"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 88","bm":0,"hd":false},{"ty":"tr","p":{"a":0,"k":[196.621,305.948]},"a":{"a":0,"k":[196.621,305.948]},"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":30,"op":180,"st":-38,"bm":0},{"ddd":0,"ind":24,"ty":4,"nm":"Shape Layer 28","parent":23,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":38,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":58,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":113,"s":[100]},{"t":151,"s":[0]}]},"r":{"a":0,"k":10.055},"p":{"a":0,"k":[286.648,220.781,0]},"s":{"a":0,"k":[91.001,96.159,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[3.379,-4.223],[-13.5,5],[-7.5,-7.5],[13.5,17.5]],"o":[[-6,7.5],[13.5,-5],[7.5,7.5],[-13.5,-17.5]],"v":[[-30,16],[-21,30.5],[5,65.5],[5.5,22.5]],"c":true}},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":0},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.505882352941,0.854902020623,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":"Shape 2","bm":0,"hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[19,-7.5],[-25.687,15.698],[-3.186,-4.883],[-5.928,-16.656],[-5.5,16.5],[15.116,5.441],[16.855,-4.94]],"o":[[-23.407,9.24],[3.919,-2.395],[4.132,6.331],[10.5,29.5],[2.559,-7.676],[-24.532,-8.829],[-29,8.5]],"v":[[-32.883,1.466],[-28,46],[-11.111,47.637],[1.279,90.167],[22,83],[19.672,30.095],[-2.03,2.676]],"c":true}},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":0},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.407843167174,0.819607902976,0.992156922583,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":"Shape 1","bm":0,"hd":false}],"ip":38,"op":151,"st":0,"bm":0},{"ddd":0,"ind":25,"ty":4,"nm":"Shape Layer 7","parent":26,"td":1,"sr":1,"ks":{"r":{"a":0,"k":0.518},"p":{"a":0,"k":[225.048,253.613,0]},"s":{"a":0,"k":[111.108,94.013,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.333,"y":0},"t":42,"s":[{"i":[[29.459,2.093],[-6.554,-3.136],[-0.071,0.087],[-0.021,-0.083],[-0.033,0.05],[-0.034,-0.059],[-0.039,-0.076],[0.046,-0.106],[0.039,0.016],[0.022,0.034],[0.087,-0.066],[0.044,0.132],[-0.101,0.112],[1.134,0.906],[-1.391,-22.073],[-19.747,24.991]],"o":[[-29.459,-2.093],[6.554,3.136],[0.089,-0.109],[0.021,0.083],[0.015,-0.022],[0.042,0.074],[0.071,0.137],[-0.047,0.107],[-0.024,-0.01],[-0.058,-0.087],[-0.087,0.066],[-0.115,-0.346],[0.118,-0.131],[-1.134,-0.906],[2.072,32.862],[19.747,-24.991]],"v":[[159.583,13.299],[134.302,37.365],[153.705,52.912],[153.939,52.749],[153.995,52.743],[154.073,52.816],[154.204,53.077],[154.206,53.399],[154.079,53.517],[154.01,53.447],[153.775,53.39],[153.567,53.356],[153.693,52.927],[135.843,27.882],[117.338,59.455],[196.838,90.787]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0.167},"t":64,"s":[{"i":[[29.459,2.093],[-6.554,-3.136],[-1.582,1.928],[-0.463,-1.852],[-0.741,1.111],[0.36,-3.515],[-0.736,-1.429],[1.031,-2.373],[3.368,-3.36],[0.642,0.962],[4.591,-5.968],[-0.916,6.387],[-5.416,7.68],[1.134,0.906],[-1.391,-22.073],[-19.747,24.991]],"o":[[-29.459,-2.093],[6.554,3.136],[1.989,-2.424],[0.463,1.852],[0.394,-0.592],[-0.198,1.935],[1.574,3.056],[-0.851,1.957],[-2.35,2.344],[-1.297,-1.945],[-3.944,5.128],[1.155,-8.053],[2.259,-3.203],[-1.134,-0.906],[2.072,32.862],[19.747,-24.991]],"v":[[159.583,13.299],[134.302,37.365],[148.007,47.759],[155.555,44.871],[156.802,44.72],[159.847,49.698],[165.1,49.638],[163.014,57.214],[163.026,64.352],[158.038,60.868],[149.662,61.714],[139.059,59.076],[147.857,47.975],[135.843,27.882],[117.338,59.455],[196.838,90.787]],"c":true}]},{"i":{"x":0.833,"y":1},"o":{"x":0.333,"y":0},"t":96,"s":[{"i":[[29.459,2.093],[-6.554,-3.136],[-4.27,5.204],[-1.25,-5],[-2,3],[-2.032,-3.564],[-2.365,-4.59],[2.784,-6.405],[2.334,0.943],[1.346,2.018],[5.25,-4],[2.646,7.953],[-6.065,6.729],[1.134,0.906],[-1.391,-22.073],[-19.747,24.991]],"o":[[-29.459,-2.093],[6.554,3.136],[5.369,-6.544],[1.25,5],[0.887,-1.331],[2.549,4.47],[4.25,8.25],[-2.798,6.436],[-1.458,-0.589],[-3.5,-5.25],[-5.25,4],[-6.933,-20.839],[7.085,-7.86],[-1.134,-0.906],[2.072,32.862],[19.747,-24.991]],"v":[[159.583,13.299],[134.302,37.365],[144.347,40.611],[158.43,30.852],[161.795,30.446],[166.454,34.864],[174.377,50.564],[174.494,69.931],[166.849,77.027],[162.657,72.837],[148.57,69.398],[136.033,67.326],[143.625,41.557],[135.843,27.882],[117.338,59.455],[196.838,90.787]],"c":true}]},{"t":140,"s":[{"i":[[29.459,2.093],[-6.554,-3.136],[-4.27,5.204],[-1.25,-5],[-2,3],[-2.032,-3.564],[-2.365,-4.59],[2.784,-6.405],[2.334,0.943],[1.346,2.018],[5.25,-4],[2.646,7.953],[-6.065,6.729],[1.134,0.906],[-1.391,-22.073],[-19.747,24.991]],"o":[[-29.459,-2.093],[6.554,3.136],[5.369,-6.544],[1.25,5],[0.887,-1.331],[2.549,4.47],[4.25,8.25],[-2.798,6.436],[-1.458,-0.589],[-3.5,-5.25],[-5.25,4],[-6.933,-20.839],[7.085,-7.86],[-1.134,-0.906],[2.072,32.862],[19.747,-24.991]],"v":[[159.583,13.299],[134.302,37.365],[144.347,40.611],[158.43,30.852],[161.795,30.446],[166.454,34.864],[198.75,56.037],[195.528,85.412],[166.133,94.985],[162.063,78.827],[148.57,69.398],[136.033,67.326],[143.625,41.557],[135.843,27.882],[117.338,59.455],[209.534,104.363]],"c":true}]}]},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":0},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.28333716299,0.343620868758,0.36862745098,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":"Shape 1","bm":0,"hd":false}],"ip":42,"op":180,"st":-26,"bm":0},{"ddd":0,"ind":26,"ty":4,"nm":"австралия","parent":29,"tt":2,"sr":1,"ks":{"p":{"a":1,"k":[{"i":{"x":0.455,"y":1},"o":{"x":0.203,"y":0},"t":64,"s":[370.388,361.57,0],"to":[26.015,-11.148,0],"ti":[1.172,10.416,0]},{"t":179,"s":[398.905,303.243,0]}]},"a":{"a":0,"k":[398.905,303.243,0]},"s":{"a":1,"k":[{"i":{"x":[0.703,0.703,0.703],"y":[1,1,1]},"o":{"x":[0.275,0.275,0.275],"y":[0.17,-0.17,-0.17]},"t":103,"s":[80.045,100,100]},{"t":179,"s":[100,100,100]}]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[-3.981,2.299],[-6.055,-5.927],[-3.274,6.377],[-0.095,-6.412],[3.546,2.288]],"o":[[6.202,-3.335],[-2.238,-8.29],[3.274,-6.377],[0.095,6.412],[3.359,6.219]],"v":[[-5.988,8.812],[12.474,10.459],[8.541,-3.697],[0.268,-7.007],[-12.474,-2.075]],"c":true}},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.996078431606,0.541176497936,0.003921568859,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[392.802,309.826]},"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 30","bm":0,"hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[3.455,4.858],[-0.691,-0.494]],"o":[[-1.386,-1.948],[0.691,0.494]],"v":[[3.474,-6.177],[-4.128,6.341]],"c":true}},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.23137255013,0.552941203117,0.396078437567,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[438.924,330.731]},"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 68","bm":0,"hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[1.58,-1.975],[-2.764,1.678]],"o":[[-1.58,1.975],[2.764,-1.678]],"v":[[-1.848,-1.34],[1.508,1.425]],"c":true}},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.23137255013,0.552941203117,0.396078437567,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[413.344,331.303]},"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 69","bm":0,"hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[1.58,-3.423],[0,-3.817],[-11.049,-14.932],[8.398,9.818],[1.316,0.527],[2.764,0.132],[1.773,0.921],[3.159,-3.872]],"o":[[-1.58,3.423],[0.479,10.181],[7.145,13.264],[-6.45,-8.952],[-1.316,-0.527],[-2.764,-0.132],[-1.773,-0.921],[-3.159,3.872]],"v":[[-20.481,-1.687],[-16.701,12.992],[7.783,15.491],[17.788,-2.409],[8.573,-17.416],[3.966,-13.072],[0.21,-19.653],[-13.937,-6.807]],"c":true}},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.949019610882,0.643137276173,0.015686275437,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[397.493,304.795]},"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 81","bm":0,"hd":false},{"ty":"tr","p":{"a":0,"k":[196.621,305.948]},"a":{"a":0,"k":[196.621,305.948]},"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":42,"op":180,"st":-26,"bm":0},{"ddd":0,"ind":27,"ty":4,"nm":"Shape Layer 29","parent":26,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":31,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":46,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":83,"s":[100]},{"t":128,"s":[0]}]},"r":{"a":0,"k":-10.621},"p":{"a":0,"k":[222.929,249.503,0]},"s":{"a":0,"k":[109.841,94.699,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[5.25,-3.25],[-0.75,-16.25],[-6.202,-2.791],[-4.5,4.25],[6,14.75]],"o":[[-14.267,8.832],[0.643,13.936],[5,2.25],[3.341,-3.156],[-8.609,-21.163]],"v":[[143.295,79.5],[129.295,98.75],[143.295,102.25],[154.795,111],[160.795,88.5]],"c":true}},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":0},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.407843167174,0.819607902976,0.992156922583,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":"Shape 1","bm":0,"hd":false}],"ip":31,"op":128,"st":0,"bm":0},{"ddd":0,"ind":28,"ty":4,"nm":"Shape Layer 5","parent":29,"td":1,"sr":1,"ks":{"r":{"a":0,"k":-0.154},"p":{"a":0,"k":[265.658,257.363,0]},"s":{"a":0,"k":[100.269,100.269,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0.598,"y":0.599},"o":{"x":0.348,"y":0},"t":40,"s":[{"i":[[51.5,14.5],[49,-45],[-25.854,-20.183],[0.099,0.025],[-0.144,-0.288],[0.098,0.378],[0.144,-0.047],[0.018,-0.073],[0.084,-0.061],[0.074,0.12],[0.054,0.055],[0.087,-0.069],[0.151,0.016],[0,0],[0,0.054],[0.043,0.036],[0.03,0.119],[-0.057,0.145],[-0.104,0.009],[0.22,0.265],[-0.129,0.015],[-0.144,0.341],[-0.307,-0.051],[-0.077,-0.136],[-0.107,0.011],[-0.151,-0.018],[-0.039,-0.181],[0,0],[-0.029,-0.001],[0,0],[-0.023,0],[-0.094,-0.024],[-0.054,-0.077],[-0.012,-0.089],[-0.098,-0.098],[40.086,7.863],[2.881,-5.187],[-67.673,-33.178],[-11,40.5]],"o":[[-51.5,-14.5],[-22.324,20.502],[30.893,24.117],[-0.182,-0.045],[0.144,0.288],[-0.051,-0.195],[-0.135,0.044],[-0.015,0.059],[-0.132,0.095],[-0.063,-0.102],[-0.05,-0.051],[-0.086,0.068],[-0.092,-0.01],[0,0],[0,-0.138],[-0.028,-0.024],[-0.045,-0.18],[0.039,-0.099],[0.257,-0.023],[-0.22,-0.265],[0.129,-0.015],[0.085,-0.202],[0.211,0.035],[0.078,0.138],[0.152,-0.016],[0.175,0.021],[0.012,0.056],[0,0],[0.033,0.001],[0,0],[0.098,-0.002],[0.086,0.022],[0.037,0.052],[0.061,0.454],[0.035,0.035],[-13.059,-2.561],[-28.202,50.782],[128.5,63],[11,-40.5]],"v":[[188.5,-166.5],[-23.5,-166],[-41.822,-93.425],[71.067,-58.606],[70.598,-58.054],[70.174,-57.895],[69.823,-58.063],[69.545,-57.842],[69.379,-57.645],[69,-57.615],[68.839,-57.873],[68.645,-57.865],[68.24,-57.787],[68.004,-57.863],[67.925,-57.993],[67.849,-58.155],[67.759,-58.341],[67.766,-58.876],[67.978,-59.053],[68.365,-59.477],[68.433,-59.825],[68.206,-60.241],[68.942,-60.456],[69.424,-60.196],[69.709,-60.041],[70.181,-60.136],[70.353,-59.649],[70.421,-59.521],[70.492,-59.5],[70.598,-59.5],[70.667,-59.502],[70.963,-59.479],[71.181,-59.337],[71.256,-59.129],[70.764,-58.41],[-43.783,-112.125],[-66.298,-97.782],[-2,46.5],[211,23.5]],"c":true}]},{"i":{"x":0.703,"y":0.708},"o":{"x":0.253,"y":0.253},"t":83,"s":[{"i":[[51.5,14.5],[49,-45],[-21.734,-19.159],[-1.2,1.154],[2.44,4.879],[-11.081,13.298],[-4.172,0.406],[-4.877,-1.695],[-2.311,2.749],[-5.375,-3.549],[-2.791,-5.558],[-6.58,-4.871],[-4.236,-6.434],[1.561,-2.597],[-0.403,-2.545],[2.306,-1.639],[1.824,-2.715],[1.975,-5.425],[1.772,-0.156],[0.162,-2.092],[-0.654,-4.159],[4.904,-1.516],[4.167,-0.714],[4.306,0.544],[2.198,2.048],[5.593,-1.07],[2.849,0.842],[2.903,-1.85],[2.178,1.954],[0.366,1.625],[4.275,2.762],[2.111,1.073],[1.041,1.123],[-10.299,1.86],[-2.588,3.343],[35.962,5.366],[2.762,-4.973],[-67.673,-33.178],[-11,40.5]],"o":[[-51.5,-14.5],[-22.556,20.715],[25.939,22.591],[3.352,-3.165],[-2.44,-4.879],[2.219,-2.662],[3.912,-0.38],[3.316,1.06],[3.62,-4.306],[10.49,6.927],[2.767,5.508],[7.48,6.428],[2.884,4.381],[-1.279,2.128],[1.624,6.311],[-1.494,1.062],[-1.754,2.611],[-2.01,5.52],[-4.366,0.385],[-0.239,5.886],[0.386,2.25],[-3.478,1.093],[-6.232,1.068],[-2.905,-0.344],[-2.566,-2.39],[-2.953,0.58],[-5.54,-5.098],[-4.613,2.94],[-3.73,-3.346],[-0.507,-2.252],[-4.324,-0.964],[-1.949,-0.99],[-7.744,-8.356],[4.024,-0.454],[0.584,-0.738],[-11.457,-1.863],[-28.202,50.782],[128.5,63],[11,-40.5]],"v":[[188.5,-166.5],[-23.5,-166],[-43.506,-96.42],[19.197,-76.206],[23.416,-82.667],[43.6,-95.668],[53.407,-100.297],[66.773,-98.347],[74.879,-102.247],[87.084,-108.629],[106.213,-101.001],[119.733,-95.461],[135.027,-89.348],[135.102,-79.543],[132.736,-72.896],[130.758,-63.584],[125.521,-58.63],[113.029,-53.508],[105.597,-46.456],[100.036,-42.414],[105.523,-32.105],[98.89,-24.498],[84.864,-25.76],[74.218,-17.618],[68.016,-26.352],[59.411,-26.509],[49.892,-29.205],[40.565,-35.408],[33.068,-32.33],[34.941,-42.217],[17.493,-50.268],[8.139,-53.31],[3.889,-56.47],[13.459,-68.556],[20.756,-77.606],[-46.097,-111.067],[-66.298,-97.782],[-2,46.5],[211,23.5]],"c":true}]},{"i":{"x":0.739,"y":0.903},"o":{"x":0.268,"y":0.263},"t":122,"s":[{"i":[[51.5,14.5],[49,-45],[-19.374,-18.572],[-1.943,1.8],[3.919,7.838],[-12.704,2.808],[-6.894,3.182],[-3.769,-0.375],[-4.054,-0.582],[-11.364,2.029],[-4.42,-8.772],[-4.953,-3.685],[-4.123,-14.645],[2.93,-3.107],[0.89,-1.434],[-2.613,19.292],[-1.424,-5.508],[6.447,-8.26],[3.85,2.728],[-2.796,-7.623],[15.713,-5.86],[12.316,-5.899],[2.821,-3.317],[6.816,0.933],[0.359,16.576],[3.894,-6.269],[4.502,1.428],[4.996,-1.961],[1.716,0.991],[0.575,2.555],[4.047,2.906],[5.547,-0.785],[13.865,9.231],[-16.19,2.976],[-4.014,5.314],[33.601,3.936],[2.693,-4.85],[-67.673,-33.178],[-11,40.5]],"o":[[-51.5,-14.5],[-22.688,20.836],[23.102,21.716],[5.375,-4.951],[-3.919,-7.838],[4.462,0.456],[6.466,-2.984],[4.875,-0.601],[6.349,0.911],[20.311,-3.22],[4.379,8.692],[14.863,11.567],[2.758,10.727],[-2.327,2.468],[-3.169,2.729],[0.689,-5.089],[0.676,11.403],[-5.722,7.331],[-5.745,-4.07],[2.438,8.921],[-3.361,1.253],[-12.502,5.988],[-6.126,2.833],[-4.614,-0.62],[-5.87,-8.083],[-2.548,4.102],[-7.816,-4.194],[-5.843,2.502],[-2.791,-1.693],[-0.798,-3.542],[-15.517,11.997],[-5.441,0.77],[-6.051,-4.864],[6.293,-0.975],[0.898,-1.181],[-10.539,-1.462],[-28.202,50.782],[128.5,63],[11,-40.5]],"v":[[188.5,-166.5],[-23.5,-166],[-44.47,-98.135],[-8.923,-87.978],[-2.02,-98.455],[28.384,-117.298],[46.838,-123.312],[63.36,-128.814],[76.195,-128.378],[102.159,-127.777],[129.285,-118.783],[147.629,-115.977],[184.088,-98.119],[170.672,-81.077],[159.798,-61.474],[151.373,-76.981],[143.884,-69.168],[131.266,-50.096],[123.132,-44.2],[121.46,-34.096],[110.09,-14.138],[106.712,-1.074],[86.585,-8.922],[73.259,9.442],[62.277,-14.804],[53.243,-7.254],[39.607,-2.411],[27.646,-9.763],[22.789,-20.039],[19.096,-29.091],[14.783,-43.396],[-1.92,-46.082],[-24.583,-38.707],[-20.9,-82.564],[-6.298,-90.292],[-47.422,-110.461],[-66.298,-97.782],[-2,46.5],[211,23.5]],"c":true}]},{"t":179,"s":[{"i":[[51.5,14.5],[49,-45],[-17.033,-17.99],[-2.681,2.442],[10.448,5.994],[-14.315,-7.599],[-18.423,-5.261],[-11.05,4.213],[-7.985,4.367],[-18.815,-1.338],[-9.853,-6.418],[-5.356,-16.519],[-2.25,-16.378],[4.314,-3.596],[1.797,-3.305],[2.722,2.149],[1.795,-4.231],[4.293,-11.779],[3.913,-0.345],[0.097,-4.782],[-1.501,-8.882],[13.222,-11.247],[8.937,13.292],[7.815,5.224],[5.916,2.598],[11.882,-3.384],[8.354,9.472],[6.294,8.862],[7.301,5.882],[3.502,0.671],[3.82,3.048],[2.745,-1.568],[6.56,2.1],[-13.401,4.525],[-5.428,7.269],[31.258,2.518],[2.626,-4.728],[-67.673,-33.178],[-11,40.5]],"o":[[-51.5,-14.5],[-22.82,20.957],[20.287,20.849],[7.382,-6.723],[-15.425,-8.848],[5.653,3.001],[13.223,3.776],[22.953,-8.752],[15.77,-8.624],[13.222,0.94],[11.122,7.244],[7.268,22.414],[1.311,9.538],[-3.535,2.947],[-9.311,17.12],[-1.764,-1.393],[-3.968,9.354],[-4.348,11.93],[-9.64,0.851],[-0.261,12.902],[1.902,11.252],[-6.069,5.163],[-9.177,-13.648],[-10.699,-7.152],[-15.782,-6.93],[-12.277,3.497],[-7.012,-7.95],[-4.262,-6],[-6.652,-5.359],[-7.999,-1.532],[-5.66,0.975],[-2.534,1.447],[-4.371,-1.399],[8.545,-1.491],[1.21,-1.621],[-9.629,-1.065],[-28.202,50.782],[128.5,63],[11,-40.5]],"v":[[188.5,-166.5],[-23.5,-166],[-45.426,-99.836],[-6.477,-86.615],[6.362,-115.498],[16.502,-131.534],[28.163,-107.088],[53.097,-124.571],[79.858,-117.127],[99.37,-141.676],[121.472,-123.327],[150.041,-119.194],[184.039,-100.324],[177.278,-82.402],[168.037,-74.003],[152.009,-61.457],[147.22,-59.896],[146.833,-43.112],[135.575,-32.866],[123.485,-25.969],[125.513,-1.379],[143.288,26.673],[93.552,22.66],[87.921,-6.745],[72.561,8.403],[58.392,-14.741],[34.239,-6.295],[21.921,-25.379],[20.464,-39.816],[8.4,-33.968],[0.607,-44.62],[-10.015,-39.569],[-22.093,-39.576],[-16.935,-82.404],[-2.795,-89.836],[-48.737,-109.86],[-66.298,-97.782],[-2,46.5],[211,23.5]],"c":true}]}]},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[1,0,0,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"st","c":{"a":0,"k":[0.917646998985,0.194325002035,0,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":0},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Shape 1","bm":0,"hd":false}],"ip":40,"op":180,"st":-13,"bm":0},{"ddd":0,"ind":29,"ty":4,"nm":"евразия","parent":36,"tt":2,"sr":1,"ks":{"p":{"a":1,"k":[{"i":{"x":0.575,"y":0.54},"o":{"x":0.185,"y":0},"t":78,"s":[349.236,176.97,0],"to":[-0.322,1.738,0],"ti":[0.405,-2.86,0]},{"i":{"x":0.696,"y":1},"o":{"x":0.337,"y":0.535},"t":130.254,"s":[347.305,187.397,0],"to":[-0.405,2.86,0],"ti":[0.083,-1.123,0]},{"t":179,"s":[346.806,194.132,0]}]},"a":{"a":0,"k":[346.806,194.132,0]},"s":{"a":1,"k":[{"i":{"x":[0.703,0.703,0.703],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.208,0.208,-0.208]},"t":104,"s":[112.513,106.441,100]},{"t":179,"s":[100,100,100]}]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[2.05,-1.574],[-1.433,-1.533],[-0.704,-1.751],[1.674,4.991],[-1.568,-1.966],[2.648,2.859],[-8.41,-1.849],[-5.039,0.366],[-1.075,3.83],[-0.133,3.164],[3.148,6.115],[-8.027,-1.238],[-2.171,3.226],[0.308,2.133],[1.847,-1.293],[10.924,1.34],[3.332,-0.008],[3.061,-1.372],[2.871,-4.777],[3.84,-2.456]],"o":[[-2.038,1.843],[1.127,1.514],[1.18,2.921],[4.165,-0.991],[2.952,3.46],[-1.956,-3.153],[2.218,4.014],[0.201,4.536],[1.331,-3.055],[0.347,-4.901],[8.023,-0.233],[4.5,-1.281],[1.401,-1.368],[-0.289,-1.999],[-6.087,4.262],[-2.543,2.156],[2.508,1.001],[-6.14,3.028],[-5.133,-0.146],[-3.027,0.054]],"v":[[-31.634,6.994],[-29.986,11.85],[-28.609,17.286],[-23.946,17.384],[-20.61,23.185],[-17.662,19.357],[-18.443,6.45],[-7.98,12.505],[-0.3,12.477],[-0.155,2.908],[4.782,-7.969],[27.428,-10.046],[30.166,-18.213],[32.399,-23.487],[27.32,-22.659],[3.956,-19.965],[-5.383,-17.699],[-8.3,-10.964],[-16.028,-3.511],[-28.335,1.479]],"c":true}},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.96862745285,0.827450990677,0.29411765933,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[326.682,216.354]},"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,0],[-1.514,-1.116],[-5.161,-1.262],[-0.823,-1.053],[-1.305,-1.015],[2.848,-0.296],[-0.479,7.528],[-9.626,-6.699],[-4.081,1.053],[-2.269,-1.21],[0,0],[-2.152,-2.629],[-4.618,-6.101],[6.911,3.139],[3.949,1.086],[-1.481,2.605],[0.635,-6.516],[-0.395,5.518],[1.58,-0.457],[14.255,3.497]],"o":[[2.656,-1.185],[1.514,1.116],[5.161,1.262],[0.823,1.053],[1.305,1.015],[-6.173,1.975],[10.668,-3.689],[-5.776,2.713],[4.081,-1.053],[2.269,1.21],[0,0],[8.714,9.49],[0.988,2.192],[-6.911,-3.139],[-3.949,-1.086],[1.481,-2.605],[-0.635,6.516],[0.395,-5.518],[-1.58,0.457],[0.098,-2.306]],"v":[[-40.238,-10.544],[-33.37,-11.923],[-19.056,-13.651],[-9.149,-11.531],[-7.953,-7.017],[-10.678,-2.711],[-5.525,-5.859],[16.505,-5.161],[15.204,1.633],[20.36,-3.133],[25.077,-0.605],[37.734,0.386],[35.542,11.88],[21.325,11.88],[10.564,6.767],[9.182,-1.587],[2.906,4.298],[-14.941,-0.748],[-16.389,-8.17],[-40.44,-5.796]],"c":true}},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":1,"k":[{"i":{"x":[0.703],"y":[1]},"o":{"x":[0.167],"y":[-0.001]},"t":104,"s":[0.988235354424,0.988235354424,0.988235354424,1]},{"t":179,"s":[0.654901981354,0.647058844566,0.690196096897,1]}]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[402.84,152.399]},"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 10","bm":0,"hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[0,0],[-0.954,-1.761],[0.419,-0.995],[3.455,-1.376],[2.721,-1.237]],"o":[[-0.02,0.348],[1.185,0.931],[-2.986,-2.559],[-5.635,2.061],[0,0]],"v":[[-8.401,-2.197],[7.177,-3.585],[8.534,2.126],[1.994,1.153],[-8.669,4.083]],"c":true}},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":1,"k":[{"i":{"x":[0.703],"y":[1]},"o":{"x":[0.167],"y":[-0.001]},"t":104,"s":[0.988235354424,0.988235354424,0.988235354424,1]},{"t":179,"s":[0.654901981354,0.647058844566,0.690196096897,1]}]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[371.426,134.126]},"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 11","bm":0,"hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[0,0],[-1.862,-1.142]],"o":[[-4.122,2.292],[0,0]],"v":[[1.198,-2.374],[0.996,2.374]],"c":true}},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.988235294819,0.988235294819,0.988235294819,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[361.404,144.229]},"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 12","bm":0,"hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[0,0],[0,0],[5.272,-5.851],[-2.929,-0.798],[-1.082,-1.21]],"o":[[0,0],[-3.131,-0.506],[1.442,0.026],[2.929,0.798],[1.082,1.21]],"v":[[5.672,2.931],[5.939,-3.35],[-5.939,2.931],[0.669,0.974],[2.121,2.931]],"c":true}},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.988235294819,0.988235294819,0.988235294819,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[357.086,135.279]},"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 13","bm":0,"hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[7.898,2.269],[7.507,-3.609],[3.225,-6.103],[0,0],[-2.615,0.717],[-0.62,-1.617],[2.236,1.426],[0.59,4.075],[-13.62,-2.162],[-6.859,5.38],[0,0]],"o":[[-7.898,-2.269],[-7.507,3.609],[-2.426,4.592],[1.378,0.464],[0.561,0.768],[2.471,1.442],[2.222,-1.467],[9.093,-6.558],[8.293,0.663],[6.859,-5.38],[0,0]],"v":[[12.469,-9.085],[-6.68,-10.027],[-27.022,3.108],[-32.287,10.168],[-26.045,9.645],[-20.248,11.636],[-19.013,7.069],[-12.368,3.687],[10.1,-2.342],[25.428,-3.22],[32.287,-8.6]],"c":true}},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.933333337307,0.717647075653,0.007843137719,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[316.326,201.52]},"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 21","bm":0,"hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[-5.25,-6.727],[3.307,5.43],[0,0],[-6.947,-2.087],[-5.035,3.653],[0.494,-3.653]],"o":[[0,-3.952],[-10.218,0.296],[0.524,4.7],[4.016,-0.198],[5.035,-3.653],[-2.16,8.94]],"v":[[20.518,-1.38],[4.692,-12.934],[-19.963,-7.603],[-16.255,12.934],[-3.946,1.777],[6.914,-1.481]],"c":true}},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":1,"k":[{"i":{"x":[0.703],"y":[1]},"o":{"x":[0.167],"y":[-0.001]},"t":104,"s":[0.600000023842,0.623529434204,0,1]},{"t":179,"s":[0.321568638086,0.407843142748,0,1]}]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[381.118,183.453]},"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 22","bm":0,"hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[0,0],[-0.522,3.455],[0.395,-2.896],[-4.323,12.637],[2.106,1.731],[2.348,7.635],[4.739,-0.263],[8.824,-0.403]],"o":[[1.773,-2.421],[0.522,-3.455],[-0.395,2.896],[4.323,-12.637],[-2.106,-1.731],[-2.348,-7.635],[-4.739,0.263],[-0.208,4.879]],"v":[[-12.172,20.556],[-8.354,11.618],[-6.516,14.185],[10.75,-1.743],[6.253,-4.224],[10.971,-18.855],[-5.331,-5.692],[-10.724,-13.466]],"c":true}},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":1,"k":[{"i":{"x":[0.703],"y":[1]},"o":{"x":[0.167],"y":[-0.002]},"t":104,"s":[0.92156869173,0.890196144581,0.564705908298,1]},{"t":179,"s":[0.686274528503,0.627451002598,0.29411765933,1]}]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[371.379,201.057]},"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 23","bm":0,"hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[0,0],[-1.525,-2.804],[-8.376,2.023],[-6.713,0.667],[-9.011,0.546],[0,0],[0,0],[20.412,3.194],[9.865,-3.592]],"o":[[3.57,2.343],[1.533,2.819],[8.376,-2.023],[6.713,-0.667],[9.011,-0.546],[0,0],[-35.858,-7.961],[-9.339,-2.996],[-9.865,3.592]],"v":[[-44.312,12.922],[-33.107,18.194],[-21.606,12.022],[1.777,1.189],[17.645,4.227],[43.696,-4.923],[44.312,-16.705],[-7.5,-10.928],[-25.875,-1.491]],"c":true}},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.600000023842,0.623529434204,0,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[316.96,192.514]},"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 24","bm":0,"hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[0,0],[0,0],[7.352,-0.59],[1.58,-2.127],[2.48,-2.398],[-5.825,-11.123],[0.671,2.954],[5.035,9.28],[-1.505,-3.357],[-6.022,-0.099],[2.073,-3.455],[1.556,-1.382],[4.45,-0.891],[-1.667,1.583],[0.672,8.197],[-27.616,-9.52]],"o":[[0,0],[0,0],[-13.191,1.058],[-1.58,2.127],[-1.68,1.624],[-0.899,-0.925],[0,0],[-0.691,-1.382],[1.504,3.357],[2.468,-0.296],[-2.073,3.455],[-5.668,4.586],[-1.332,0.279],[11.415,-12.743],[14.074,-13.967],[5.806,-5.978]],"v":[[38.308,-30.784],[36.86,3.238],[30.795,7.952],[13.063,1.014],[23.383,13.714],[11.187,23.194],[4.468,15.064],[-15.502,6.937],[-16.316,9.899],[-7.604,16.119],[-5.63,23.03],[-16.316,30.237],[-30.756,9.95],[-30.262,6.937],[-38.308,-7.576],[17.426,-24.459]],"c":true}},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.921568632126,0.890196084976,0.564705908298,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[322.347,218.375]},"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 26","bm":0,"hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[-2.172,-0.134],[0,0],[0,0]],"o":[[1.728,0.106],[0,0],[0,0]],"v":[[-0.035,2.145],[1.512,-2.112],[-1.352,-2.147]],"c":true}},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":1,"k":[{"i":{"x":[0.703],"y":[1]},"o":{"x":[0.167],"y":[-0.001]},"t":104,"s":[0.427451014519,0.560784339905,0,1]},{"t":179,"s":[0.011764706112,0.40000000596,0.035294119269,1]}]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[385.302,258.181]},"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 60","bm":0,"hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[2.172,-0.395],[-0.099,-2.352],[0,0]],"o":[[-1.374,0.25],[1.088,0.013],[0,0]],"v":[[-1.816,-6.488],[-0.632,6.463],[2.232,6.497]],"c":true}},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":1,"k":[{"i":{"x":[0.703],"y":[1]},"o":{"x":[0.167],"y":[-0.001]},"t":104,"s":[0.427451014519,0.560784339905,0,1]},{"t":179,"s":[0.06274510175,0.290196090937,0,1]}]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[384.582,249.572]},"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 61","bm":0,"hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[-0.32,-2.304],[0,0],[0,0]],"o":[[0.374,2.692],[0,0],[0,0]],"v":[[-2.745,-1.655],[2.508,3.081],[2.758,-2.78]],"c":true}},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.988235294819,0.988235294819,0.988235294819,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[360.904,119.75]},"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 62","bm":0,"hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[0,0],[4.694,3.241]],"o":[[17.113,9.79],[0,0]],"v":[[-4.421,1.084],[-4.172,-4.777]],"c":true}},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":1,"k":[{"i":{"x":[0.703],"y":[1]},"o":{"x":[0.167],"y":[-0.001]},"t":104,"s":[0.988235354424,0.988235354424,0.988235354424,1]},{"t":179,"s":[0.631372570992,0.658823549747,0.690196096897,1]}]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[367.833,121.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 63","bm":0,"hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[-1.975,-1.777],[0.987,3.061],[2.962,0],[-1.678,-1.876],[-0.79,-1.283],[1.59,4.295],[-3.455,-0.79],[-1.58,-1.876]],"o":[[2.202,1.981],[-0.987,-3.061],[-2.962,0],[1.678,1.876],[0.79,1.283],[-1.59,-4.295],[3.455,0.79],[1.58,1.876]],"v":[[1.677,7.532],[5.132,1.214],[1.677,-7.968],[-0.693,-2.143],[3.552,0.424],[-2.954,-0.218],[-3.655,5.558],[1.38,4.472]],"c":true}},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":1,"k":[{"i":{"x":[0.703],"y":[1]},"o":{"x":[0.167],"y":[-0.001]},"t":104,"s":[0.427451014519,0.560784339905,0,1]},{"t":179,"s":[0.06274510175,0.290196090937,0,1]}]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[249.881,185.102]},"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 64","bm":0,"hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[0,0],[0.263,8.425],[-3.159,-0.658],[0.79,2.238],[-2.099,2.351]],"o":[[-2.109,5.53],[-0.263,-8.425],[3.159,0.658],[-0.79,-2.238],[-0.027,4.474]],"v":[[5.755,6.366],[-5.832,5.183],[-1.225,-1.531],[1.671,-6.928],[5.859,-11.009]],"c":true}},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":1,"k":[{"i":{"x":[0.703],"y":[1]},"o":{"x":[0.167],"y":[-0.001]},"t":104,"s":[0.427451014519,0.560784339905,0,1]},{"t":179,"s":[0.06274510175,0.290196090937,0,1]}]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[250.512,204.926]},"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 65","bm":0,"hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[0.856,-2.238],[-1.119,1.843]],"o":[[-0.918,2.401],[1.119,-1.843]],"v":[[-1.079,-0.702],[1.027,0.746]],"c":true}},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":1,"k":[{"i":{"x":[0.703],"y":[1]},"o":{"x":[0.167],"y":[-0.001]},"t":104,"s":[0.427451014519,0.560784339905,0,1]},{"t":179,"s":[0.011764706112,0.40000000596,0.035294119269,1]}]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[383.45,272.088]},"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 70","bm":0,"hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[3.093,-2.541],[-2.567,-4.015],[-2.764,2.962]],"o":[[-1.623,1.333],[2.567,4.015],[2.764,-2.962]],"v":[[-8.046,-5.716],[0.444,2.288],[7.947,4.46]],"c":true}},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":1,"k":[{"i":{"x":[0.703],"y":[1]},"o":{"x":[0.167],"y":[-0.001]},"t":104,"s":[0.427451014519,0.560784339905,0,1]},{"t":179,"s":[0.011764706112,0.40000000596,0.035294119269,1]}]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[401.343,275.548]},"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 71","bm":0,"hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[2.633,-1.975],[-2.435,0.395],[2.106,0.79]],"o":[[-2.567,1.925],[2.435,-0.395],[-2.106,-0.79]],"v":[[-3.877,1.465],[2.31,6.072],[3.165,-6.039]],"c":true}},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":1,"k":[{"i":{"x":[0.703],"y":[1]},"o":{"x":[0.167],"y":[-0.001]},"t":104,"s":[0.427451014519,0.560784339905,0,1]},{"t":179,"s":[0.011764706112,0.40000000596,0.035294119269,1]}]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[375.849,266.432]},"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 72","bm":0,"hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[5.499,-12.561],[-5.829,2.403],[1.678,5.858]],"o":[[0.449,5.661],[0.46,-1.184],[-2.784,-11.416]],"v":[[-8.074,-4.352],[8.052,10.522],[-0.011,2.098]],"c":true}},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":1,"k":[{"i":{"x":[0.703],"y":[1]},"o":{"x":[0.167],"y":[-0.001]},"t":104,"s":[0.427451014519,0.560784339905,0,1]},{"t":179,"s":[0.011764706112,0.40000000596,0.035294119269,1]}]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[367.212,269.88]},"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 73","bm":0,"hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[0.296,-2.567],[0.148,1.975]],"o":[[-0.317,2.748],[-0.148,-1.975]],"v":[[-1.299,-0.591],[1.317,0.643]],"c":true}},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":1,"k":[{"i":{"x":[0.703],"y":[1]},"o":{"x":[0.167],"y":[-0.001]},"t":104,"s":[0.427451014519,0.560784339905,0,1]},{"t":179,"s":[0.06274510175,0.290196090937,0,1]}]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[407.069,202.802]},"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 74","bm":0,"hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[0,0],[1.53,8.545],[0.395,-3.357]],"o":[[-6.049,6.83],[0.199,-5.577],[-0.395,3.357]],"v":[[-5.767,4.368],[6.819,-4.321],[2.23,-2.642]],"c":true}},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":1,"k":[{"i":{"x":[0.703],"y":[1]},"o":{"x":[0.167],"y":[-0.001]},"t":104,"s":[0.427451014519,0.560784339905,0,1]},{"t":179,"s":[0.06274510175,0.290196090937,0,1]}]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[399.294,214.527]},"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 75","bm":0,"hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[1.382,-2.369],[-1.283,1.382]],"o":[[-1.244,2.132],[1.283,-1.382]],"v":[[-2.721,-1.177],[2.709,1.489]],"c":true}},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":1,"k":[{"i":{"x":[0.703],"y":[1]},"o":{"x":[0.167],"y":[-0.001]},"t":104,"s":[0.988235354424,0.988235354424,0.988235354424,1]},{"t":179,"s":[0.631372570992,0.658823549747,0.690196096897,1]}]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[408.59,136.253]},"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 76","bm":0,"hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[-6.22,-3.258],[-5.924,4.048],[1.93,3.452]],"o":[[2.95,1.545],[5.924,-4.048],[-3.258,-5.826]],"v":[[-9.093,7.73],[-0.899,-0.661],[9.863,-6.781]],"c":true}},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.988235294819,0.988235294819,0.988235294819,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[322.355,140.476]},"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 77","bm":0,"hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[-1.119,-2.106],[-0.877,6.377]],"o":[[1.833,7.256],[-0.198,-2.896]],"v":[[-3.668,-0.753],[3.771,-2.333]],"c":true}},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.988235294819,0.988235294819,0.988235294819,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[273.424,129.84]},"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 78","bm":0,"hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[-7.941,2.589],[-1.975,7.372],[-3.159,2.106],[-2.376,7.644],[2.79,12.894],[-0.263,4.739],[-1.316,-0.527],[-3.554,4.081],[4.218,-1.871],[-2.501,0],[-3.159,3.554],[-1.316,4.739],[8.442,7.533],[0,0],[1.448,0],[2.764,1.053],[1.185,0.658],[2.369,1.711],[2.764,0.395],[0,0],[0,0],[-5.726,-0.987]],"o":[[5.778,-2.196],[1.975,-7.372],[6.878,-5.306],[1.61,-9.932],[-1.052,-4.475],[0.263,-4.739],[1.316,0.527],[11.138,-2.409],[-3.159,2.37],[2.501,0],[3.159,-3.554],[15.488,-1.161],[-3.555,-1.184],[0,0],[-1.448,0],[-2.764,-1.053],[-1.185,-0.658],[-2.369,-1.711],[-2.764,-0.395],[0,0],[0,0],[14.013,0.324]],"v":[[-34.96,46.444],[-18.243,37.493],[-21.402,16.958],[-9.949,18.933],[5.056,-3.841],[-0.735,-10.028],[8.348,-17.663],[19.537,-19.769],[17.957,-12.661],[20.195,1.03],[26.777,-8.975],[27.699,-17.663],[40.205,-37.803],[25.592,-39.251],[7.163,-48.465],[-6.132,-44.648],[-9.16,-50.44],[-21.139,-52.678],[-24.693,-60.444],[-39.3,-59.115],[-44.166,55.189],[-35.553,60.497]],"c":true}},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":1,"k":[{"i":{"x":[0.703],"y":[1]},"o":{"x":[0.167],"y":[-0.001]},"t":104,"s":[0.427451014519,0.560784339905,0,1]},{"t":179,"s":[0.06274510175,0.290196090937,0,1]}]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[402.325,191.045]},"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 82","bm":0,"hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[14.446,-3.4],[2.468,3.159],[-5.295,-2.567],[0.027,4.542],[2.863,-1.327],[0,0],[0,0],[-1.481,2.172],[-5.529,0.197],[-4.64,2.172],[4.542,0.197],[2.238,3.511],[0.395,-2.369],[1.086,-1.58],[0.197,2.567],[0.79,3.85],[-0.79,5.337],[-5.331,-2.567],[-0.197,-1.975],[-0.099,-2.666],[-2.567,0.691],[-15.604,0.613],[-0.79,0.987],[0.79,-6.022],[0,5.331],[-2.369,1.185],[-4.762,-1.731],[0,0],[7.446,-14.282],[-0.527,-2.51],[0,0],[2.336,2.404]],"o":[[-0.592,-2.962],[-2.468,-3.159],[-0.826,3.554],[-0.027,-4.541],[-2.863,1.327],[0,0],[0,0],[1.481,-2.172],[5.529,-0.197],[4.64,-2.172],[-10.373,-0.167],[-1.58,-1.777],[-0.395,2.369],[-1.086,1.58],[-0.197,-2.567],[-0.79,-3.85],[0.79,-5.337],[5.331,2.567],[0.197,1.975],[0.099,2.666],[11.337,-12.438],[2.961,-0.692],[0.79,-0.987],[-0.79,6.022],[0,-5.331],[3.043,-1.944],[0,0],[-10.657,-10.93],[-3.061,3.258],[0,0],[0,0],[-18.166,-29.064]],"v":[[-25.607,17.064],[-38.343,10.548],[-33.765,17.854],[-39.034,19.829],[-48.018,9.814],[-53.379,17.557],[-53.275,0.181],[-44.76,-9.79],[-37.356,-6.433],[-30.05,-14.627],[-26.594,-18.971],[-27.088,-30.917],[-35.184,-22.723],[-36.566,-12.85],[-41.996,-16.207],[-48.512,-19.366],[-38.54,-32.984],[-23.731,-42.369],[-11.686,-37.137],[-16.919,-31.608],[-12.18,-27.758],[16.945,-39.11],[21.683,-46.22],[24.645,-40.987],[28.101,-43.159],[35.407,-50.268],[53.379,-61.806],[48.513,52.498],[36.263,51.361],[29.187,61.985],[25.145,61.985],[23.888,47.834]],"c":true}},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.427450984716,0.560784339905,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},{"ty":"tr","p":{"a":0,"k":[309.646,193.736]},"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 83","bm":0,"hd":false},{"ty":"tr","p":{"a":0,"k":[196.621,305.948]},"a":{"a":0,"k":[196.621,305.948]},"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":40,"op":180,"st":-5,"bm":0},{"ddd":0,"ind":30,"ty":4,"nm":"евразия тень","parent":29,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":34,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":57,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":93,"s":[100]},{"t":126,"s":[0]}]},"r":{"a":0,"k":-6.647},"p":{"a":0,"k":[292.821,265.899,0]},"s":{"a":0,"k":[93.302,98.486,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[14.545,-3.5],[18.93,5.5],[3.66,-12.5],[10.538,-3],[-9.904,-7.5],[3.577,-6],[-5.347,-12],[-4.23,18],[-8.968,-2.5],[-14.551,4],[2.821,14],[7.955,3.5]],"o":[[-14.545,3.5],[-18.93,-5.5],[-3.66,12.5],[-10.538,3],[9.904,7.5],[-3.577,6],[5.347,12],[4.23,-18],[8.968,2.5],[14.551,-4],[-2.821,-14],[-7.955,-3.5]],"v":[[115.74,-142.229],[62.512,-119.454],[27.704,-107.729],[2.869,-101.746],[8.197,-80.729],[34.422,-68.037],[66.768,-39.617],[115.72,-49.908],[136.784,-72.537],[146.63,-102.279],[178.212,-114.908],[146.013,-128.375]],"c":true}},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":0},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.505882352941,0.854509779986,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":[79.471,79.471]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Shape 2","bm":0,"hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[14.545,-3.5],[18.93,5.5],[3.66,-12.5],[10.538,-3],[-7.328,-13.5],[-9.904,-7.5],[3.577,-6],[-5.347,-12],[-4.23,18],[-8.968,-2.5],[-14.551,4],[2.821,14],[7.955,3.5]],"o":[[-14.545,3.5],[-18.93,-5.5],[-3.66,12.5],[-10.538,3],[7.328,13.5],[9.904,7.5],[-3.577,6],[5.347,12],[4.23,-18],[8.968,2.5],[14.551,-4],[-2.821,-14],[-7.955,-3.5]],"v":[[89.115,-126.5],[45.372,-107.5],[-3.326,-92],[-26.934,-83.5],[-42.753,-58.5],[-17.17,-65],[7.055,-43.5],[45.781,-22],[102.832,-26],[120.113,-48],[135.008,-79],[145.526,-91.178],[126.898,-109.5]],"c":true}},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":0},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.408535138298,0.820312679515,0.992156862745,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":"Shape 1","bm":0,"hd":false}],"ip":34,"op":126,"st":0,"bm":0},{"ddd":0,"ind":31,"ty":4,"nm":"Shape Layer 3","parent":35,"sr":1,"ks":{"r":{"a":0,"k":1.278},"p":{"a":0,"k":[248.463,269.498,0]},"s":{"a":0,"k":[99.787,99.787,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0.621,"y":0.826},"o":{"x":0.408,"y":0.187},"t":108,"s":[{"i":[[8.65,-7.479],[8.104,-7.944],[12.556,-4.232],[-10.598,9.889],[-8.95,-7.885],[-9.205,0.936],[-11.644,0.184],[12.003,0.368]],"o":[[-8.596,-6.961],[-10.015,9.817],[12.123,-2.373],[7.122,-6.645],[8.208,-7.415],[11.698,-1.19],[-10.896,0.301],[-9.511,-0.292]],"v":[[95.631,123.099],[63.9,117.089],[23.247,129.233],[64.41,117.051],[95.32,123.546],[121.666,112.309],[157.145,112.894],[121.428,112.418]],"c":true}]},{"i":{"x":0.598,"y":1},"o":{"x":0.369,"y":0.169},"t":128.77,"s":[{"i":[[3.673,-1.413],[11.968,-16.244],[8.73,-25.531],[-9.453,13.433],[-7.526,2.092],[-15.369,-8.823],[-15.773,-1.692],[10.678,8.822]],"o":[[-8.088,3.111],[-11.709,15.892],[15.095,-20.422],[12.442,-17.679],[3.117,-0.85],[14.429,8.284],[-16.968,-3.941],[-14.001,-11.566]],"v":[[90.731,105.204],[49.646,97.179],[4.585,122.147],[52.517,105.275],[91.653,116.126],[124.244,103.041],[168.314,97.891],[124.34,95.583]],"c":true}]},{"t":162,"s":[{"i":[[7.28,0.206],[16.238,-43.322],[17.55,-10.309],[-8.132,13.684],[-35.961,-13.288],[-17.45,15.523],[-23.459,11.21],[14.516,-13.002]],"o":[[-14.348,-0.405],[-5.086,13.569],[16.562,-9.786],[5.886,-9.904],[11.612,0.654],[14.26,-12.685],[-25.009,8.994],[-17.859,15.997]],"v":[[95.691,47.329],[49.907,76.66],[4.648,80.135],[50.299,76.953],[95.625,47.521],[124.09,73.176],[186.913,79.722],[124.021,73.713]],"c":true}]}]},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":0},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"gf","o":{"a":0,"k":100},"r":1,"bm":0,"g":{"p":3,"k":{"a":0,"k":[0,0.714,0.902,1,0.5,0.461,0.82,0.978,1,0.208,0.737,0.957]}},"s":{"a":0,"k":[105.059,177.875]},"e":{"a":0,"k":[45.632,-116.623]},"t":1,"nm":"Gradient Fill 16","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 2","bm":0,"hd":false}],"ip":108,"op":162,"st":-28,"bm":0},{"ddd":0,"ind":32,"ty":4,"nm":"Shape Layer 2","parent":35,"sr":1,"ks":{"r":{"a":0,"k":0.939},"p":{"a":0,"k":[250.134,257.639,0]},"s":{"a":0,"k":[99.787,99.787,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.879},"o":{"x":0.292,"y":0},"t":70,"s":[{"i":[[15.594,3.665],[17.913,-1.837],[19.407,-11.034],[-9.276,-1.485],[-15.5,2],[-11.5,-5],[-14.701,-6.768],[-14.5,-5.5],[20.635,10.987]],"o":[[-26.211,-6.161],[-40.848,4.188],[24.416,-5.273],[9.218,1.475],[15.5,-2],[11.5,5],[26.841,12.357],[-11.297,-5.042],[-16.377,-8.72]],"v":[[-78.81,157.618],[-107.785,157.593],[-173.301,160.041],[-138.314,158.052],[-107.292,158.575],[-79.042,158.093],[-43.504,157.03],[24.733,155.556],[-43.27,157.061]],"c":true}]},{"i":{"x":0.698,"y":1},"o":{"x":0.167,"y":0.121},"t":79.625,"s":[{"i":[[17.923,4.412],[17.932,-1.538],[20.546,-7.782],[-9.198,-1.542],[-13.71,1.664],[-14.185,-5.503],[-15.215,-6.54],[-17.577,-7.122],[20.045,9.535]],"o":[[-26.164,-6.349],[-35.736,3.363],[16.144,-0.969],[8.346,1.399],[15.521,-1.785],[14.526,5.609],[24.252,10.748],[-13.915,-6.823],[-16.74,-7.776]],"v":[[-69.902,144.054],[-101.568,146.832],[-165.346,150.242],[-130.347,151.52],[-101.657,153.559],[-70.937,151.773],[-38.705,156.533],[28.932,149.054],[-38.734,149.999]],"c":true}]},{"t":114,"s":[{"i":[[26,7],[18,-0.5],[24.5,3.5],[-9.314,1.226],[-7.5,0.5],[-23.5,-7.25],[-17,-5.75],[-28.25,-12.75],[18,4.5]],"o":[[-26,-7],[-18,0.5],[19.5,5.5],[9.5,-1.25],[15.594,-1.04],[25.024,7.72],[15.269,5.164],[-23,-13],[-18,-4.5]],"v":[[-39,97],[-80,109.5],[-137.75,116.25],[-100.25,113.25],[-79.5,110.5],[-39,97.5],[-22.75,125.75],[43.5,126.5],[-23,125.5]],"c":true}]}]},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":0},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"gf","o":{"a":0,"k":100},"r":1,"bm":0,"g":{"p":3,"k":{"a":0,"k":[0,0.945,0.981,1,0.5,0.586,0.877,1,1,0.227,0.773,1]}},"s":{"a":0,"k":[-82.893,256.833]},"e":{"a":0,"k":[-63.122,-11.125]},"t":1,"nm":"Gradient Fill 17","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":70,"op":114,"st":-16,"bm":0},{"ddd":0,"ind":33,"ty":4,"nm":"карта вторая 2","parent":39,"sr":1,"ks":{"p":{"a":0,"k":[0,5,0]},"a":{"a":0,"k":[256,256,0]},"s":{"a":0,"k":[100.214,100.214,100]}},"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":29,"s":[{"i":[[0,0],[-3.458,36.563],[-0.961,29.385],[-0.006,-0.007],[0.098,0.116],[2.784,3.017],[3.508,-0.435],[11.857,-40.074],[0,0],[0,0],[0,0],[-8.648,-2.185],[-5.689,-0.284],[-7.976,1.382],[0.037,0.033],[-3.993,35.422]],"o":[[0,0],[2.919,-30.862],[0.01,-0.016],[0.057,-0.007],[-1.557,-3.045],[-3.552,-3.849],[-8.184,28.871],[-10.043,33.942],[0,0],[0,0],[2.978,1.427],[8.648,2.185],[5.689,0.284],[7.976,-1.382],[2.921,-34.998],[3.774,-33.487]],"v":[[152.693,9.056],[162.291,-81.447],[174.13,-194.595],[171.502,-201.18],[171.75,-201.259],[164.459,-211.595],[153.962,-217.18],[120.375,-92.034],[94.819,-6.577],[75.948,58.034],[30.726,204.939],[51.671,210.252],[87.361,214.98],[110.418,214.387],[131.823,208.446],[144.576,88.486]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":32.857,"s":[{"i":[[0,0],[0.221,34.415],[-0.961,29.385],[6.075,5.044],[14.478,1.871],[16.804,-2.013],[25.118,-4.066],[9.976,-40.589],[0,0],[0,0],[0,0],[-46.043,-4.892],[-40.533,-0.313],[-10.62,0.554],[-1.715,0.485],[0.354,35.644]],"o":[[0,0],[-0.183,-28.393],[-4.917,-12.583],[-7.389,-6.135],[-14.215,-1.837],[-19.694,2.359],[-9.46,40.387],[-8.448,34.373],[0,0],[0,0],[13.543,2.89],[31.398,3.336],[13.33,0.103],[5.918,-0.309],[-1.113,-37.444],[-0.341,-34.228]],"v":[[172.16,0.572],[171.191,-81.963],[170.601,-201.087],[157.364,-220.211],[125.016,-232.289],[69.116,-231.614],[-3.399,-220.964],[-32.136,-93.339],[-54.801,1.089],[-74.908,102.628],[-94.158,199.626],[7.228,219.928],[104.736,224.497],[151.802,222.562],[171.898,219.528],[172.45,80.039]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":34.99,"s":[{"i":[[0,0],[0.221,34.415],[-0.961,29.385],[13.112,-1.977],[15.896,-9.571],[25.147,-2.013],[38.564,-1.246],[-0.818,-35.107],[0,0],[0,0],[0,0],[0,0],[-25.303,-5.579],[-30.516,-5.988],[-8.383,8.359],[0.354,35.644]],"o":[[0,0],[-0.183,-28.393],[-14.963,-25.056],[-21.87,3.298],[-29.553,17.794],[-12.238,0.98],[0.326,22.698],[0.825,35.387],[0,0],[0,0],[31.444,1.643],[20.108,1.185],[21.94,4.838],[44.197,8.673],[-1.113,-37.444],[-0.341,-34.228]],"v":[[172.16,0.573],[171.19,-81.963],[170.594,-208.571],[81.115,-227.944],[15.999,-204.099],[-71.584,-174.736],[-169.321,-170.513],[-167.179,-66.334],[-166.053,-0.811],[-165.532,72.128],[-165.121,168.547],[-81.513,171.32],[-10.158,184.071],[77.008,212.728],[172.071,205.059],[172.449,80.039]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":37.123,"s":[{"i":[[0,0],[0.221,34.415],[-0.961,29.385],[20.254,-7.679],[16.848,-2.992],[27.763,0.343],[38.564,-1.246],[-0.818,-35.107],[0,0],[0,0],[0,0],[0,0],[-25.803,-2.358],[-29.522,-9.772],[-8.383,8.359],[0.354,35.644]],"o":[[0,0],[-0.183,-28.393],[-32.666,-20.067],[-22.417,8.499],[-25.598,4.546],[-12.276,-0.152],[0.326,22.698],[0.825,35.387],[0,0],[0,0],[31.444,1.643],[22.508,-0.658],[26.304,2.404],[48.809,16.157],[-1.113,-37.444],[-0.341,-34.228]],"v":[[172.16,0.573],[171.19,-81.963],[170.458,-216.554],[56.169,-199.006],[-7.012,-177.656],[-97.528,-172.103],[-195.266,-170.375],[-194.121,-65.664],[-194.992,3.526],[-195.468,72.474],[-195.057,168.893],[-111.232,169.67],[-9.753,171.598],[68.526,189.278],[172.097,205.059],[172.449,80.039]],"c":true}]},{"i":{"x":0.667,"y":0.674},"o":{"x":0.167,"y":0.167},"t":39.254,"s":[{"i":[[0,0],[-2.67,34.312],[-0.961,29.385],[32.865,-3.167],[17.105,-0.457],[27.763,0.343],[38.564,-1.246],[-0.818,-35.107],[0,0],[0,0],[0,0],[0,0],[-25.698,-0.59],[-29.839,-2.149],[-16.057,-10.531],[-2.64,35.548]],"o":[[0,0],[2.203,-28.308],[-28.44,9.37],[-23.864,2.299],[-33.927,0.907],[-12.276,-0.152],[0.326,22.698],[0.825,35.387],[0,0],[0,0],[31.444,1.643],[22.508,-0.657],[26.406,0.606],[29.05,2.092],[3.191,-32.555],[2.535,-34.136]],"v":[[149.6,-2],[156.238,-82.268],[164.805,-194.601],[57.316,-172.563],[-7.283,-169.673],[-96.381,-170.755],[-195.266,-170.375],[-194.121,-65.664],[-194.992,3.527],[-195.468,72.474],[-195.057,168.893],[-111.232,169.67],[-11.324,170.051],[69.61,172.714],[132.257,191.598],[143.177,76.686]],"c":true}]},{"i":{"x":0.383,"y":1},"o":{"x":0.47,"y":0.463},"t":49,"s":[{"i":[[0,0],[-0.739,34.401],[-0.804,17.489],[0,0],[36.962,-0.732],[0,0],[35.645,11.488],[2.139,-29.73],[0,0],[-1.461,-19.597],[0,0],[0,0],[-19.442,0.29],[0,0],[-33.422,-0.974],[0.359,21.469]],"o":[[0,0],[0.809,-33.965],[-30.614,0.119],[0,0],[-64.203,-2.962],[0,0],[-6.258,33.801],[-2.839,27.026],[0,0],[1.461,19.597],[41.798,-8.266],[39.577,-3.264],[29.185,-1.907],[0,0],[-2.073,-42.93],[-0.602,-27.777]],"v":[[193.04,0.825],[194.458,-71.793],[196.335,-160.592],[108.665,-159.577],[16.313,-159.149],[-65.322,-162.465],[-139.235,-178.329],[-160.585,-66.55],[-164.921,-0.432],[-166.229,83.978],[-157.868,178.574],[-81.12,166.431],[17.314,159.492],[109.064,158.453],[197.845,159.411],[194.131,74.823]],"c":true}]},{"i":{"x":0.5,"y":1},"o":{"x":0.383,"y":0},"t":64,"s":[{"i":[[0,0],[0.221,34.415],[0.139,18.618],[0,0],[51.62,0.587],[0,0],[40.241,0.246],[-0.818,-35.107],[0,0],[0,0],[0,0],[0,0],[-18.847,0.083],[0,0],[-34.492,-3.313],[-0.398,30.32]],"o":[[0,0],[-0.183,-28.393],[-29.376,6.459],[0,0],[-39.471,-0.152],[0,0],[0.326,22.698],[0.825,35.387],[0,0],[0,0],[37.911,1.053],[39.747,-0.496],[29.671,-0.915],[0,0],[-0.19,-42.131],[0.351,-27.831]],"v":[[193.95,0.618],[194.469,-71.784],[194.43,-175.222],[121.699,-163.432],[15.315,-161.188],[-108.611,-162.078],[-197.867,-162.526],[-198.219,-63.835],[-197.093,1.688],[-196.572,74.628],[-195.662,165.558],[-108.562,166.515],[12.795,166.333],[123.388,166.39],[193.936,173.791],[193.669,74.061]],"c":true}]},{"i":{"x":0.833,"y":1},"o":{"x":0.31,"y":0},"t":87,"s":[{"i":[[0,0],[0.221,34.415],[-0.217,18.26],[0,0],[34.02,-0.401],[0,0],[40.241,0.246],[-0.818,-35.107],[0,0],[0,0],[0,0],[0,0],[-18.847,0.083],[0,0],[-38.701,1.053],[-0.104,29.373]],"o":[[0,0],[-0.183,-28.393],[-27.658,-1.198],[0,0],[-39.471,-0.152],[0,0],[0.326,22.698],[0.825,35.387],[0,0],[0,0],[37.911,1.053],[39.747,-0.496],[29.671,-0.915],[0,0],[-0.59,-43.418],[0.096,-27.249]],"v":[[213.634,0.866],[213.663,-69.682],[212.301,-161.02],[114.186,-161.175],[0.342,-161.629],[-114.598,-161.753],[-212.835,-162.037],[-213.187,-63.346],[-212.061,2.177],[-211.54,75.116],[-210.63,166.047],[-114.549,166.841],[-0.694,166.435],[114.39,166.113],[213.673,164.594],[213.24,73.585]],"c":true}]},{"i":{"x":0.703,"y":1},"o":{"x":0.275,"y":0.134},"t":103,"s":[{"i":[[0,0],[0.221,34.415],[-0.217,18.26],[0,0],[34.02,-0.401],[0,0],[40.241,0.246],[-0.818,-35.107],[0,0],[0,0],[0,0],[0,0],[-18.847,0.083],[0,0],[-38.701,1.053],[-0.104,29.373]],"o":[[0,0],[-0.183,-28.393],[-27.658,-1.198],[0,0],[-39.471,-0.152],[0,0],[0.326,22.698],[0.825,35.387],[0,0],[0,0],[37.911,1.053],[39.747,-0.496],[29.671,-0.915],[0,0],[-0.59,-43.418],[0.096,-27.249]],"v":[[213.634,0.866],[213.663,-69.682],[212.301,-161.02],[114.186,-161.175],[0.342,-161.629],[-114.598,-161.753],[-212.835,-162.037],[-213.187,-63.346],[-212.061,2.177],[-211.54,75.116],[-210.63,166.047],[-114.549,166.841],[-0.694,166.435],[114.39,166.113],[213.673,164.594],[213.24,73.585]],"c":true}]},{"t":179,"s":[{"i":[[0,0],[-2.73,34.307],[-1.103,17.096],[0,0],[35.508,-1.975],[0,0],[40.379,-1.086],[-2.651,-35.361],[0,0],[0,0],[0,0],[0,0],[-19.745,0.395],[0,0],[-38.701,1.053],[2.895,29.231]],"o":[[0,0],[3.002,-37.719],[-32.119,0.79],[0,0],[-59.01,-2.455],[0,0],[2.699,20.776],[2.646,35.297],[0,0],[0,0],[37.911,1.053],[39.491,-4.673],[26.196,2.172],[0,0],[-2.828,-42.682],[-2.766,-27.925]],"v":[[183.699,1.58],[188.818,-62.114],[196.336,-160.596],[108.402,-166.388],[0.495,-158.885],[-108.666,-165.072],[-197.915,-160.53],[-189.238,-63.813],[-184.62,1.58],[-189.587,74.508],[-195.414,160.07],[-109.061,166.388],[-0.461,158.951],[108.402,166.388],[197.915,159.543],[188.539,47.291]],"c":true}]}]},"nm":"Path 1","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":29,"s":[22]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":32.857,"s":[15]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":39,"s":[14]},{"t":40,"s":[0]}]},"e":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":29,"s":[79]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":32.857,"s":[83.5]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":39,"s":[86.5]},{"t":40,"s":[100]}]},"o":{"a":0,"k":0},"m":1,"nm":"Trim Paths 1","hd":false},{"ty":"st","c":{"a":0,"k":[0.345098048449,0.349019616842,0.35686275363,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":4},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"tr","p":{"a":0,"k":[256.461,255.128]},"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":29,"op":180,"st":0,"bm":0},{"ddd":0,"ind":34,"ty":4,"nm":"антарктида 2","parent":36,"td":1,"sr":1,"ks":{"p":{"a":0,"k":[256,256,0]},"a":{"a":0,"k":[256,256,0]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0.482,"y":1},"o":{"x":0.336,"y":0},"t":56,"s":[{"i":[[43.382,-16.88],[13.643,-9.414],[-0.473,-19.632],[-4.396,-0.25],[-13.153,0.191],[-5.159,-0.108],[-4.687,-0.087],[-5.56,0.137],[-8.761,0.02],[-5.936,0.109],[-2.948,0.113],[-7.26,0.151],[-10.669,-0.329],[-8.169,0.078],[-6.327,-0.109],[-1.104,-0.045],[-11.125,0.044],[-10.866,-0.276],[-6.288,-0.279],[-7.371,-0.14],[-5.568,-0.586],[-3.839,-0.644],[-2.372,-0.679],[0,0]],"o":[[-26.509,10.315],[-0.07,19.207],[3.064,0.544],[7.375,0.419],[5.196,-0.075],[4.663,0.098],[5.452,0.101],[7.312,-0.18],[6.039,-0.014],[3.112,-0.057],[6.76,-0.259],[11.675,-0.243],[5.734,0.177],[8.592,-0.081],[1.347,0.023],[8.043,0.329],[9.363,-0.037],[7.966,0.202],[11.245,0.499],[6.01,0.114],[4.771,0.503],[4.644,0.779],[0.538,-7.664],[0,0]],"v":[[156.88,358.539],[45.883,374.822],[47.263,421.156],[72.81,421.751],[102.966,422.025],[118.481,422.126],[132.492,422.442],[148.991,422.448],[173.592,422.256],[191.716,422.106],[200.829,421.856],[222.028,421.22],[256.252,421.259],[278.2,421.304],[301.85,421.225],[305.539,421.327],[334.551,421.533],[365.049,421.758],[386.346,422.514],[413.79,423.666],[431.379,424.792],[444.434,426.559],[470.426,420.283],[469.424,361.163]],"c":true}]},{"t":179,"s":[{"i":[[43.382,-16.88],[13.643,-9.414],[-0.473,-19.632],[-10.835,2.491],[-12.336,0.029],[-1.045,3.708],[-5.851,-2.828],[-2.122,2.371],[-6.957,-0.226],[-2.554,2.998],[2.662,-5.971],[-8.916,-1.025],[-10.26,3.173],[-9.627,4.927],[-11.211,12.41],[0.037,-1.983],[-5.775,-8.924],[-9.305,2.448],[-7.563,-3.619],[-13.919,-11.304],[-3.165,-5.203],[-4.88,-0.196],[-3.742,-0.731],[0,0]],"o":[[-26.509,10.315],[-0.07,19.207],[1.376,-9.911],[15.457,-3.553],[5.051,-0.017],[1.753,-9.202],[9.376,4.533],[1.934,-11.009],[1.442,0.047],[7.874,-9.242],[-11.876,26.642],[16.88,1.941],[7.163,-2.215],[10.35,-5.297],[4.789,-5.301],[-0.104,5.517],[4.606,-4.688],[6.94,-1.825],[11.118,5.32],[4.986,4.049],[2.954,4.857],[6.208,0.249],[0.538,-7.664],[0,0]],"v":[[156.859,356.969],[55.195,372.362],[54.426,420.737],[75.741,391.59],[114.79,388.863],[134.63,397.243],[148.564,389.522],[158.818,391.982],[170.307,379.622],[184.97,366.216],[201.094,382.86],[215.634,400.351],[254.482,367.087],[290.703,370.641],[315.986,367.024],[331.023,372.415],[342.219,382.177],[363.855,370.081],[392.664,372.424],[429.512,375.915],[456.169,382.411],[457.944,407.482],[462.132,413.198],[460.55,355.311]],"c":true}]}]},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.207843002619,0.737254961799,0.956862984452,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":"Shape 1","bm":0,"hd":false}],"ip":54,"op":180,"st":0,"bm":0},{"ddd":0,"ind":35,"ty":4,"nm":"антарктида","parent":36,"tt":2,"sr":1,"ks":{"p":{"a":0,"k":[256,256,0]},"a":{"a":0,"k":[256,256,0]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0.685,"y":1},"o":{"x":0.395,"y":0},"t":103,"s":[{"i":[[0,0],[1.805,2.135],[-4.648,3.104],[8.897,-0.195],[13.079,5.778],[1.152,-3.836],[0,0],[-27.067,0.421]],"o":[[-8.169,-4.819],[-1.805,-2.135],[4.648,-3.104],[-11.06,-9.75],[-2.924,-1.183],[0,0],[0,0],[0,0]],"v":[[61.239,15.686],[37.919,10.728],[46.091,2.129],[20.562,-7.226],[-23.195,-11.36],[-44.548,-11.655],[-43.952,20.349],[61.337,18.661]],"c":true}]},{"t":179,"s":[{"i":[[0,0],[1.876,2.073],[-4.541,3.258],[8.885,-0.494],[13.266,5.335],[1.152,-3.836],[0,0],[-25.077,0.527]],"o":[[-8.326,-4.541],[-1.876,-2.073],[4.541,-3.258],[-11.381,-9.373],[-2.962,-1.084],[0,0],[0,0],[0,0]],"v":[[45.348,10.385],[25.373,6.345],[32.086,-7.477],[8.984,-16.559],[-30.408,-19.622],[-45.546,-16.644],[-43.952,20.349],[45.546,13.355]],"c":true}]}]},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":1,"k":[{"i":{"x":[0.685],"y":[1]},"o":{"x":[0.395],"y":[0]},"t":103,"s":[0.988235354424,0.988235354424,0.988235354424,1]},{"t":179,"s":[0.850980401039,0.866666674614,0.86274510622,1]}]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[408.83,401.317]},"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.685,"y":1},"o":{"x":0.395,"y":0},"t":103,"s":[{"i":[[0,0],[6.319,-11.452],[3.554,3.949],[4.344,-3.159],[12.063,-3.74],[13.229,-0.658],[0,0],[-41.919,-2.52]],"o":[[0,0],[-6.911,-6.516],[-3.554,-3.949],[-13.172,11.799],[-3.356,2.305],[0,0],[27.959,2.418],[0,0]],"v":[[53.857,-11.101],[31.136,1.824],[8.429,-7.851],[0.136,-7.851],[-23.559,-2.127],[-52.927,3.083],[-54.19,20.3],[54.439,20.753]],"c":true}]},{"t":179,"s":[{"i":[[0,0],[6.319,-11.452],[3.554,3.949],[4.344,-3.159],[12.063,-3.74],[13.229,-0.658],[0,0],[-41.919,-2.52]],"o":[[0,0],[-6.911,-6.516],[-3.554,-3.949],[-13.172,11.799],[-3.356,2.305],[0,0],[27.959,2.418],[0,0]],"v":[[52.86,-16.091],[29.889,-8.404],[7.182,-18.079],[-1.111,-18.079],[-24.806,-12.355],[-54.424,-14.13],[-54.439,13.315],[54.439,20.753]],"c":true}]}]},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.988235294819,0.988235294819,0.988235294819,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[310.439,400.912]},"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.685,"y":1},"o":{"x":0.395,"y":0},"t":103,"s":[{"i":[[0,0],[16.784,1.185],[-7.758,17.361],[2.633,-3.423],[5.397,-0.395],[4.476,-2.106],[8.258,4.486],[0,0],[-37.522,1.208]],"o":[[-17.573,2.567],[-28.812,-1.477],[3.687,-3.158],[-2.633,3.423],[-5.397,0.395],[-4.476,2.106],[-0.269,5.911],[34.751,-0.984],[0,0]],"v":[[55.797,5.257],[11.161,17.954],[-9.441,-16.799],[-17.338,-15.481],[-25.104,-5.872],[-29.185,4.132],[-59.269,5.05],[-60.786,23.177],[54.549,22.475]],"c":true}]},{"t":179,"s":[{"i":[[0,0],[16.784,1.185],[-7.758,17.361],[2.633,-3.423],[5.397,-0.395],[4.476,-2.106],[8.258,4.486],[0,0],[-37.522,1.208]],"o":[[-17.573,2.567],[-28.812,-1.477],[3.687,-3.158],[-2.633,3.423],[-5.397,0.395],[-4.476,2.106],[-0.269,5.911],[34.814,-3.812],[0,0]],"v":[[54.3,-11.956],[10.663,13.713],[-9.94,-21.04],[-17.837,-19.722],[-25.603,-10.113],[-29.684,-0.109],[-53.282,0.56],[-54.3,22.928],[54.3,15.49]],"c":true}]}]},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":1,"k":[{"i":{"x":[0.685],"y":[1]},"o":{"x":[0.395],"y":[0]},"t":103,"s":[0.988235354424,0.988235354424,0.988235354424,1]},{"t":179,"s":[0.850980401039,0.866666674614,0.86274510622,1]}]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[201.707,398.704]},"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.685,"y":1},"o":{"x":0.395,"y":0},"t":103,"s":[{"i":[[5.123,0.391],[0,0],[-9.781,0.938],[-7.342,-7.473],[-16.6,-8.231],[0,0]],"o":[[0,0],[0,0],[10.569,-5.776],[10.38,10.598],[0,0],[-49.065,-0.619]],"v":[[-58.081,11.161],[-57.935,9.001],[-35.764,8.808],[24.518,1.738],[37.625,-5.886],[36.11,12.241]],"c":true}]},{"t":179,"s":[{"i":[[5.123,0.391],[0,0],[-9.781,0.938],[-7.342,-7.473],[-16.6,-8.231],[0,0]],"o":[[0,0],[0,0],[10.569,-5.776],[10.38,10.598],[0,0],[-47.078,-4.581]],"v":[[-43.612,5.673],[-43.465,3.513],[-21.295,3.32],[30.506,-2.752],[43.612,-10.377],[42.596,11.991]],"c":true}]}]},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.964705884457,0.980392158031,0.984313726425,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[104.806,409.525]},"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":"tr","p":{"a":0,"k":[196.621,305.948]},"a":{"a":0,"k":[196.621,305.948]},"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":54,"op":180,"st":0,"bm":0},{"ddd":0,"ind":36,"ty":4,"nm":"карта вторая","parent":39,"sr":1,"ks":{"p":{"a":0,"k":[0,5,0]},"a":{"a":0,"k":[256,256,0]},"s":{"a":0,"k":[100.214,100.214,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"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":29.127,"s":[{"i":[[-3.924,34.104],[4.556,-41.315],[0.605,-24.364],[-0.938,29.123]],"o":[[-0.186,28.457],[-3.39,30.744],[2.942,-22.055],[0.618,-19.195]],"v":[[414.871,191.141],[403.036,268.793],[402.483,336.76],[406.233,271.206]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":32.857,"s":[{"i":[[8.88,31.148],[4.556,-41.315],[13.321,-22.993],[-0.938,29.123]],"o":[[-2.58,35.429],[-3.39,30.744],[28.85,-10.555],[0.618,-19.195]],"v":[[403.552,175.136],[376.398,248.219],[390.951,333.726],[394.836,245.391]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":34.99,"s":[{"i":[[-7.911,24.599],[4.418,-39.602],[0.605,-24.364],[-0.938,29.123]],"o":[[-10.666,17.937],[-3.449,30.737],[11.162,-20.238],[0.618,-19.195]],"v":[[331.673,185.446],[287.267,258.081],[302.492,320.87],[303.714,255.276]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":37.123,"s":[{"i":[[-1.956,26.921],[4.279,-37.889],[0.605,-24.364],[-0.938,29.123]],"o":[[-5.455,21.541],[-3.509,30.73],[9.989,-19.564],[0.618,-19.195]],"v":[[306.826,197.532],[263.482,268.829],[276.173,332.11],[277.937,266.046]],"c":true}]},{"i":{"x":0.667,"y":0.674},"o":{"x":0.167,"y":0.167},"t":39.254,"s":[{"i":[[3.999,29.243],[4.141,-36.176],[0.605,-24.364],[-0.938,29.123]],"o":[[-0.244,25.146],[-3.568,30.723],[8.816,-18.889],[0.618,-19.195]],"v":[[275.673,210.245],[239.696,279.576],[249.853,343.351],[252.159,276.816]],"c":true}]},{"i":{"x":0.383,"y":1},"o":{"x":0.47,"y":0.463},"t":49,"s":[{"i":[[-26.126,41.428],[2.284,-31.749],[-13.066,-22.82],[-1.695,41.313]],"o":[[-22.27,19.885],[-3.248,45.147],[-5.062,-24.974],[1.18,-28.747]],"v":[[189.812,210.565],[117.187,282.823],[150.492,350.625],[131.709,282.804]],"c":true}]},{"t":64,"s":[{"i":[[5.116,37.963],[-0.711,-31.823],[-7.112,-30.887],[1.569,50.957]],"o":[[-0.679,36.872],[1.129,50.541],[-2.097,-32.91],[-0.885,-28.757]],"v":[[62.862,224.718],[62.068,284.697],[64.007,365.126],[63.911,285.502]],"c":true}]}]},"nm":"Path 1","hd":false},{"ty":"gf","o":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":67,"s":[100]},{"t":86,"s":[0]}]},"r":1,"bm":0,"g":{"p":3,"k":{"a":0,"k":[0.235,0.906,0.968,1,0.617,0.551,0.867,1,1,0.196,0.765,1,0.645,1,0.822,0.5,1,0]}},"s":{"a":1,"k":[{"i":{"x":0.833,"y":0.46},"o":{"x":0.081,"y":0.263},"t":33,"s":[143.309,236.702],"to":[0,0],"ti":[31.122,-6.719]},{"t":49,"s":[73.28,278.758]}]},"e":{"a":1,"k":[{"i":{"x":0.833,"y":0.812},"o":{"x":0.132,"y":1},"t":33,"s":[492.147,255.586],"to":[-32.329,3.784],"ti":[32.329,-3.784]},{"t":49,"s":[298.171,278.288]}]},"t":2,"h":{"a":0,"k":0},"a":{"a":0,"k":0},"nm":"Gradient Fill 18","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 4","bm":0,"hd":false},{"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":29.127,"s":[{"i":[[2.373,22.614],[-0.556,-13.839],[1.497,-15.665],[1.627,33.788]],"o":[[-3.106,20.988],[1.231,30.652],[6.968,-17.777],[-0.591,-12.27]],"v":[[418.778,60.747],[419.057,125.749],[413.283,197.84],[421.138,108.176]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":32.857,"s":[{"i":[[-6.818,26.674],[-4.412,-13.128],[1.497,-15.665],[8.525,32.735]],"o":[[-10.331,17.402],[10.415,30.99],[13.197,-16.989],[-4.402,-16.902]],"v":[[356.08,52.708],[361.745,122.474],[339.639,211.171],[376.279,127.895]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":34.99,"s":[{"i":[[1.819,21.492],[-3.735,-13.197],[1.497,-15.665],[7.33,32.848]],"o":[[-6.24,21.648],[8.782,31.433],[11.525,-16.277],[-3.769,-17.19]],"v":[[284.968,75.23],[296.187,146.451],[256.299,230.63],[309.127,151.152]],"c":true}]},{"i":{"x":0.667,"y":0.674},"o":{"x":0.167,"y":0.167},"t":39.254,"s":[{"i":[[0.711,19.248],[-2.38,-13.334],[1.497,-15.665],[4.939,33.075]],"o":[[-5.271,21.207],[5.516,32.318],[8.183,-14.854],[-2.505,-17.767]],"v":[[240.066,101.683],[247.3,168.134],[216.349,246.135],[257.052,171.397]],"c":true}]},{"i":{"x":0.383,"y":1},"o":{"x":0.47,"y":0.463},"t":49,"s":[{"i":[[7.085,29.083],[-4.412,-13.128],[18.106,-37.864],[8.788,32.666]],"o":[[-2.702,24.398],[10.415,30.99],[26.87,-33.075],[-7.351,-27.326]],"v":[[117.577,103.422],[123.313,158.681],[99.728,245.008],[138.433,159.71]],"c":true}]},{"t":64,"s":[{"i":[[5.998,24.729],[-0.487,-23.608],[-0.478,-42.201],[-1.422,33.797]],"o":[[-0.479,24.065],[0.675,32.687],[1.405,-37.909],[1.259,-29.929]],"v":[[60.276,105.942],[58.473,167.86],[60.044,244.954],[59.553,171.017]],"c":true}]}]},"nm":"Path 1","hd":false},{"ty":"gf","o":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":67,"s":[100]},{"t":76,"s":[0]}]},"r":1,"bm":0,"g":{"p":3,"k":{"a":0,"k":[0,1,1,1,0.5,0.631,0.878,0.98,1,0.263,0.757,0.961,0.525,1,0.762,0.5,1,0]}},"s":{"a":1,"k":[{"i":{"x":0.833,"y":0.752},"o":{"x":0.025,"y":0.46},"t":33,"s":[249.072,136.074],"to":[0,0],"ti":[39.024,3.866]},{"t":49,"s":[100.163,174.397]}]},"e":{"a":1,"k":[{"i":{"x":0.833,"y":0.81},"o":{"x":0.127,"y":1},"t":33,"s":[527.807,151.946],"to":[-31.103,5.428],"ti":[31.103,-5.428]},{"t":49,"s":[341.189,184.516]}]},"t":2,"h":{"a":0,"k":0},"a":{"a":0,"k":0},"nm":"Gradient Fill 19","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 2","bm":0,"hd":false},{"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":29.127,"s":[{"i":[[-3.298,26.877],[2.134,-10.565],[0.369,-16.584],[-4.194,17.568]],"o":[[-4.711,13.885],[-5.756,28.494],[5.341,-13.474],[2.028,-8.496]],"v":[[395.147,390.257],[385.162,424.514],[381.841,460.976],[390.443,431.346]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":32.857,"s":[{"i":[[15.863,26.444],[22.373,-25.231],[0.369,-16.584],[-9.447,15.394]],"o":[[7.306,20.298],[-19.287,21.75],[13.295,-11.597],[20.853,-33.979]],"v":[[336.829,297.269],[308.323,370.678],[311.695,463.633],[323.489,377.112]],"c":true}]},{"i":{"x":0.667,"y":0.674},"o":{"x":0.167,"y":0.167},"t":39.254,"s":[{"i":[[11.064,38.461],[15.836,-25.717],[1.244,-20.982],[-7.721,19.779]],"o":[[2.529,35.46],[-14.074,26.253],[10.139,-15.721],[15.557,-33.725]],"v":[[208.642,315.419],[190.752,367.573],[189.036,417.279],[201.566,376.396]],"c":true}]},{"i":{"x":0.383,"y":1},"o":{"x":0.47,"y":0.463},"t":49,"s":[{"i":[[4.195,40.935],[-2.796,-22.208],[0.369,-16.584],[10.207,24.101]],"o":[[-1.459,31.173],[3.631,28.842],[5.341,-13.474],[-8.496,-20.061]],"v":[[98.408,272.892],[94.579,333.365],[106.359,405.695],[107.401,334.018]],"c":true}]},{"t":64,"s":[{"i":[[3.37,21.801],[0.202,-23.603],[-1.195,-25.144],[-1.561,26.127]],"o":[[-0.678,14.457],[-0.249,29.068],[3.28,-15.043],[1.321,-22.117]],"v":[[62.867,281.215],[60.104,332.896],[60.316,392.306],[60.426,332.81]],"c":true}]}]},"nm":"Path 1","hd":false},{"ty":"gf","o":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":67,"s":[100]},{"t":86,"s":[0]}]},"r":1,"bm":0,"g":{"p":3,"k":{"a":0,"k":[0,1,1,1,0.5,0.631,0.878,0.98,1,0.263,0.757,0.961,0.59,1,0.795,0.5,1,0]}},"s":{"a":1,"k":[{"i":{"x":0.833,"y":0.767},"o":{"x":0.025,"y":0.256},"t":33,"s":[198.27,370.064],"to":[0,0],"ti":[29.109,-1.403]},{"t":49,"s":[63.391,336.958]}]},"e":{"a":1,"k":[{"i":{"x":0.833,"y":0.751},"o":{"x":0.049,"y":1},"t":33,"s":[477.557,392.299],"to":[-34.718,-9.414],"ti":[34.718,9.414]},{"t":49,"s":[269.247,335.816]}]},"t":2,"h":{"a":0,"k":0},"a":{"a":0,"k":0},"nm":"Gradient Fill 20","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 3","bm":0,"hd":false},{"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":29.127,"s":[{"i":[[7.013,0.315],[-0.201,-18.633],[1.994,-33.174],[7.009,-19.479],[6.87,-52.835],[0,0],[-5.456,19.637],[0.013,56.612],[1.903,56.354],[-13.331,11.19]],"o":[[-10.707,18.138],[0.553,51.274],[-3.537,58.842],[-12.447,34.59],[5.188,-0.598],[0,0],[7.33,-26.382],[-0.01,-40.079],[-0.837,-24.787],[-4.094,0.42]],"v":[[424.381,50.975],[415.996,123.937],[401.43,266.598],[394.938,389.245],[378.235,465.97],[384.197,464.783],[394.572,390.895],[405.817,266.409],[420.107,123.461],[428.963,56.317]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":32.857,"s":[{"i":[[7.013,0.315],[-8.099,-26.057],[-15.775,-45.246],[30.879,-43.314],[10.302,-35.699],[0,0],[-14.018,14.795],[9.898,55.74],[23.265,51.362],[-13.331,11.19]],"o":[[-29.279,19.547],[12.943,41.639],[19.407,55.663],[-21.34,29.934],[20.869,1.445],[0,0],[59.334,-62.623],[-9.842,-55.427],[-14.345,-31.669],[-4.094,0.42]],"v":[[370.917,23.069],[355.8,123.669],[316.229,258.701],[303.332,367.084],[300.725,477.551],[356.927,478.217],[346.64,378.708],[366.741,257.177],[380.404,123.069],[384.919,22.655]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":34.99,"s":[{"i":[[20.973,-9.072],[-6.828,-22.317],[-12.27,-43.909],[23.305,-35.555],[8.582,-33.799],[0.092,-0.377],[-11.958,15.715],[7.679,53.141],[18.406,52.148],[-12.206,14.773]],"o":[[-24.567,20.326],[10.036,42.444],[15.654,50.06],[-15.804,27.047],[18.735,4.109],[0.83,-5.962],[49.908,-57.855],[-8.877,-64.446],[-17.801,-39.198],[-4.094,0.42]],"v":[[288.395,43.184],[291.001,147.027],[238.251,272.155],[215.168,367.86],[217.089,431.678],[259.526,443.809],[253.123,378.93],[279.882,273.61],[329.57,140.439],[330.503,29.701]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":37.123,"s":[{"i":[[12.765,-4.365],[-6.192,-20.447],[-10.518,-43.241],[19.518,-31.675],[7.722,-32.849],[0.137,-0.565],[-10.928,16.175],[6.57,51.841],[15.977,52.541],[-11.644,16.565]],"o":[[-22.211,20.716],[8.582,42.847],[13.777,47.259],[-13.036,25.603],[14.998,2.603],[1.245,-8.942],[45.194,-55.471],[-8.395,-68.955],[-19.529,-42.963],[-4.094,0.42]],"v":[[264.197,74.008],[267.335,158.04],[219.121,278.931],[197.853,369.53],[199.204,424.925],[240.93,426.77],[233.131,380.324],[256.311,281.875],[312.886,148.458],[310.045,56.834]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":39.254,"s":[{"i":[[4.558,0.342],[-5.556,-18.577],[-8.766,-42.572],[15.73,-27.795],[6.862,-31.898],[0.183,-0.753],[-9.898,16.634],[5.46,50.54],[13.548,52.934],[-11.081,18.356]],"o":[[-19.855,21.106],[7.129,43.25],[11.901,44.458],[-10.269,24.159],[11.262,1.097],[1.66,-11.923],[40.481,-53.087],[-7.913,-73.465],[-21.257,-46.727],[-4.094,0.42]],"v":[[239.694,85.758],[243.669,169.053],[199.991,285.707],[180.538,371.2],[180.895,424.583],[218.544,424.967],[213.139,381.718],[232.74,290.14],[296.202,156.477],[289.587,83.967]],"c":true}]},{"i":{"x":0.667,"y":0.189},"o":{"x":0.167,"y":0.167},"t":45,"s":[{"i":[[6.282,1.769],[3.083,-30.918],[-2.848,-31.352],[5.09,-21.177],[3.399,-21.773],[0.075,-0.31],[6.653,15.79],[-2.57,29.085],[27.603,46.603],[-8.177,25.597]],"o":[[-14.909,40.574],[-0.381,32.142],[3.961,35.341],[-2.268,23.766],[10.146,0.799],[0.683,-4.902],[-10.846,-44.773],[8.237,-50.028],[-18.149,-29.819],[-4.094,0.42]],"v":[[163.301,89.086],[157.64,171.071],[135.722,268.872],[127.066,350.119],[132.597,425.569],[173.526,421.854],[171.21,363.36],[165.112,273.237],[238.59,154.981],[212.116,91.392]],"c":true}]},{"i":{"x":0.383,"y":1},"o":{"x":0.47,"y":0.469},"t":49,"s":[{"i":[[7.485,2.765],[9.114,-39.533],[1.284,-23.519],[-2.339,-16.558],[0.982,-14.705],[0,0],[18.207,15.2],[-8.175,14.107],[37.415,42.184],[-6.149,30.652]],"o":[[-11.456,54.165],[-5.623,24.388],[-1.582,28.977],[3.318,23.491],[9.368,0.591],[0,0],[-46.677,-38.968],[19.511,-33.667],[-15.98,-18.016],[-4.094,0.42]],"v":[[117.562,77.994],[97.585,172.48],[90.858,257.121],[89.739,335.403],[99.588,432.939],[142.807,426.363],[141.939,350.546],[117.903,261.437],[198.371,153.937],[159.414,88.321]],"c":true}]},{"t":64,"s":[{"i":[[7.013,0.315],[0.953,-37.461],[-0.023,-29.884],[-0.674,-16.619],[0.982,-14.705],[0,0],[0.548,26.389],[-0.28,16.302],[-3.913,47.293],[-6.44,16.647]],"o":[[-0.598,18.946],[-1.547,60.821],[0.018,24.317],[-0.898,22.307],[9.368,0.591],[0,0],[-1.262,-60.792],[0.777,-45.335],[1.98,-23.93],[-4.094,0.42]],"v":[[57.706,92.16],[58.771,165.474],[58.794,257.487],[60.355,331.414],[60.03,420.244],[65.742,420.896],[62.247,339.813],[67.085,249.106],[65.13,145.605],[65.703,92.577]],"c":true}]}]},"nm":"Path 1","hd":false},{"ty":"gf","o":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":67,"s":[100]},{"t":86,"s":[0]}]},"r":1,"bm":0,"g":{"p":3,"k":{"a":0,"k":[0,1,1,1,0.5,0.631,0.878,0.98,1,0.263,0.757,0.961,0.635,1,0.817,0.5,1,0]}},"s":{"a":1,"k":[{"i":{"x":0.528,"y":0.998},"o":{"x":0.015,"y":0.171},"t":33,"s":[119.087,252.123],"to":[0,0],"ti":[-2.226,3.754]},{"i":{"x":0.929,"y":0.436},"o":{"x":0.481,"y":0.008},"t":42,"s":[59.208,241.215],"to":[2.549,-4.299],"ti":[4.222,-3.785]},{"t":57,"s":[31.165,232.327]}]},"e":{"a":1,"k":[{"i":{"x":0.569,"y":0.825},"o":{"x":0.11,"y":1},"t":33,"s":[528.948,271.033],"to":[-39.051,-5.735],"ti":[72.62,6.764]},{"i":{"x":0.834,"y":0.728},"o":{"x":0.427,"y":0.461},"t":42,"s":[374.404,234.011],"to":[-15.112,-1.407],"ti":[8.21,-0.824]},{"t":57,"s":[274.662,230.809]}]},"t":2,"h":{"a":0,"k":0},"a":{"a":0,"k":0},"nm":"Gradient Fill 21","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},{"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":29.127,"s":[{"i":[[0,0],[1.39,2.762],[0,0],[0,0],[1.936,0.675],[-2.208,-30.558],[7.833,-48.736],[14.006,-27.214],[11.449,-32.537],[0,0],[0,0],[-0.772,0.814],[0,0],[0,0]],"o":[[0,0],[-0.601,-1.194],[0,0],[0,0],[-8.903,19.468],[2.798,38.721],[-9.556,59.453],[-15.631,30.372],[5.055,0.545],[0,0],[0,0],[1.23,-1.297],[0,0],[0,0]],"v":[[429.76,60.661],[429.317,56.316],[427.695,54.504],[427.92,53.534],[424.193,49.995],[416.089,124.142],[401.041,267.284],[393.037,390.643],[377.687,466.092],[382.045,465.476],[383.017,464.79],[384.974,464.474],[386.483,463.222],[410.354,273.955]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":32.857,"s":[{"i":[[0,0],[9.266,6.104],[0,0],[0,0],[3.988,-0.129],[-11.537,-28.382],[-18.182,-45.891],[27.04,-35.302],[11.449,-32.537],[0,0],[0,0],[-16.485,0.234],[0,0],[0,0]],"o":[[0,0],[-15.3,-10.079],[0,0],[0,0],[-27.279,20.045],[16.868,41.498],[19.11,48.234],[-20.771,27.117],[5.055,0.545],[0,0],[0,0],[22.651,-0.321],[0,0],[0,0]],"v":[[428.787,56.261],[411.672,33.45],[387.136,23.599],[375.48,22.371],[370.27,23.179],[356.3,122.779],[316.478,258.003],[302.905,367.533],[300.871,476.809],[300.841,476.933],[371.915,479.316],[385.729,478.307],[429.607,474.435],[430.578,256.489]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":34.99,"s":[{"i":[[0,0],[24.309,2.324],[18.351,-2.596],[0,0],[3.323,-0.107],[-9.614,-23.652],[-15.152,-38.243],[22.534,-29.418],[9.541,-27.114],[-9.99,-1.398],[-35.072,-11.425],[-21.927,0.01],[0,0],[0,0]],"o":[[0,0],[-15.734,-4.563],[-10.382,1.469],[0,0],[-22.732,16.704],[14.057,34.582],[15.925,40.195],[-17.309,22.598],[4.213,0.455],[9.99,1.399],[9.598,3.127],[37.345,1.896],[0,0],[0,0]],"v":[[428.526,47.659],[389.617,28.355],[339.782,28.023],[308.999,34.993],[289.089,42.658],[291.21,146.345],[238.43,271.224],[216.685,368.52],[216.557,431.979],[236.608,436.62],[317.835,463.51],[376.079,471.247],[429.618,460.298],[428.792,256.818]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":37.123,"s":[{"i":[[0,0],[31.93,-2.673],[25.343,-10.129],[0,0],[2.991,-0.096],[-8.653,-21.287],[-13.637,-34.419],[20.28,-26.476],[8.587,-24.403],[-4.995,-0.699],[-51.292,-17.115],[-16.1,-1.948],[0,0],[0,0]],"o":[[0,0],[-11.498,-1.577],[-14.605,5.837],[0,0],[-20.459,15.034],[12.651,31.124],[14.333,36.176],[-15.578,20.338],[3.791,0.409],[4.995,0.699],[17.794,5.201],[28.411,8.66],[0,0],[0,0]],"v":[[428.306,40.043],[386.859,32.474],[317.07,54.35],[285.106,66.498],[264.529,73.528],[267.399,157.462],[219.265,277.882],[200.343,370.296],[198.787,424.908],[227.818,426.323],[313.925,441.016],[372.185,457.769],[429.44,461.143],[429.617,255.711]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":39.254,"s":[{"i":[[0,0],[39.55,-7.671],[36.703,-5.193],[0,0],[2.659,-0.086],[-7.691,-18.922],[-12.122,-30.594],[18.027,-23.534],[7.633,-21.691],[0,0],[-24.244,-1.725],[-10.274,-3.906],[0,0],[0,0]],"o":[[0,0],[-7.262,1.408],[-20.765,2.938],[0,0],[-18.186,13.363],[11.246,27.665],[12.74,32.156],[-13.847,18.078],[3.37,0.364],[0,0],[20.138,1.433],[19.29,7.335],[0,0],[0,0]],"v":[[421.617,60.955],[365.691,75.571],[294.198,84.409],[260.432,84.814],[239.717,85.85],[243.588,168.58],[200.099,284.541],[184,372.072],[180.593,424.247],[218.918,425.59],[314.005,426.615],[362.938,433.149],[387.553,448.099],[405.326,252.857]],"c":true}]},{"i":{"x":0.667,"y":0.206},"o":{"x":0.167,"y":0.167},"t":45,"s":[{"i":[[0,0],[17.342,-1.245],[49.368,-0.734],[0,0],[12.776,2.197],[-0.326,-30.601],[-6.087,-26.129],[6.145,-17.512],[3.188,-12.377],[0,0],[-9.967,-0.709],[-4.519,0.01],[0,0],[0,0]],"o":[[0,0],[-3.033,0.218],[-42.816,-0.193],[0,0],[-14.598,39.646],[0.195,47.005],[6.332,26.651],[-3.626,20.224],[1.584,0.171],[0,0],[8.279,0.589],[10.008,-0.022],[0,0],[0,0]],"v":[[444.929,85.993],[365.26,90.769],[277.467,93.929],[200.11,91.583],[163.075,88.864],[157.578,171.199],[136.129,268.529],[128.927,350.943],[133.134,425.88],[174.132,421.871],[291.112,416.827],[365.167,417.912],[436.847,423.418],[434.136,254.461]],"c":true}]},{"i":{"x":0.383,"y":1},"o":{"x":0.47,"y":0.463},"t":49,"s":[{"i":[[0,0],[0,0],[58.209,2.379],[0,0],[19.838,3.79],[4.816,-38.754],[-1.875,-23.011],[-2.15,-13.307],[0.086,-5.875],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[-58.209,-2.379],[0,0],[-12.093,57.993],[-7.518,60.505],[1.858,22.808],[3.51,21.722],[0.338,0.036],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[452.195,94.966],[365.19,95.047],[265.715,95.628],[159.38,88.054],[117.161,77.554],[97.536,173.028],[91.473,257.351],[90.481,336.193],[100.711,433.701],[143.575,425.957],[275.602,414.448],[364.663,413.348],[454.641,415.154],[454.248,255.58]],"c":true}]},{"i":{"x":0.558,"y":1},"o":{"x":0.383,"y":0},"t":64,"s":[{"i":[[0,0],[18.974,-1.861],[0,0],[0,0],[12.114,0.227],[2.249,-24.742],[0,0],[0.5,-10.64],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[-5.769,0.566],[0,0],[0,0],[-0.319,9.768],[-3.093,34.035],[0,0],[-0.566,20.781],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[450.552,79.743],[374.712,92.515],[265.061,94.407],[145.243,93.132],[57.959,92.875],[58.647,167.219],[59.559,259.909],[59.749,329.963],[61.936,420.556],[147.418,421.797],[265.485,421.197],[365.222,421.407],[449.873,430.156],[450.254,255.543]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0},"t":86,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[11.142,0.208],[0.75,-22.767],[0,0],[0.46,-9.786],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[-0.293,8.984],[-1.062,32.232],[0,0],[-0.52,19.114],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[468.405,94.216],[374.394,92.557],[264.393,94.366],[144.974,93.115],[43.833,92.679],[43.699,161.781],[45.691,257.356],[45.592,330.934],[46.223,421.178],[147.414,421.782],[265.153,421.222],[375.531,421.164],[469.886,419.659],[469.42,256.687]],"c":true}]},{"i":{"x":0.833,"y":1},"o":{"x":0.167,"y":0.167},"t":94,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[8.768,0.164],[1.48,-17.866],[0,0],[0.362,-7.701],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[-0.231,7.07],[-2.036,24.644],[0,0],[-0.409,15.042],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[468.308,93.685],[372.426,92.805],[262.848,94.281],[145.655,93.212],[43.736,93.155],[43.462,166.471],[45.1,256.433],[45.037,335.391],[45.591,421.361],[147.318,421.765],[263.174,421.299],[373.271,421.196],[470.384,419.956],[469.419,257.392]],"c":true}]},{"i":{"x":0.703,"y":1},"o":{"x":0.275,"y":0.134},"t":103,"s":[{"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]],"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]],"v":[[470.542,93.347],[365.159,93.723],[257.138,93.968],[148.172,93.574],[43.454,94.345],[43.757,189.275],[43.972,256.851],[45.392,351.4],[46.448,421.646],[146.961,421.701],[255.867,421.582],[364.921,421.315],[471.041,420.149],[470.066,256.377]],"c":true}]},{"t":179,"s":[{"i":[[0,0],[12.473,3.493],[45.908,-1.45],[24.446,0.924],[0,0],[0,0],[0,0],[0,0],[0,0],[-10.728,-3.219],[-55.866,1.334],[-34.178,-2.055],[0,0],[0,0]],"o":[[0,0],[-5.468,-0.096],[-35.308,0.731],[-48.398,3.169],[0,0],[0,0],[0,0],[0,0],[0,0],[4.639,-0.009],[31.431,2.909],[41.411,-4.3],[0,0],[0,0]],"v":[[453.079,94.844],[364.768,88.608],[257.241,96.044],[147.733,90.178],[58.422,94.844],[66.443,189.276],[72.153,256.497],[65.707,347.67],[60.917,415.409],[147.98,421.67],[255.503,413.997],[364.519,421.705],[454.326,414.411],[440.271,256.997]],"c":true}]}]},"nm":"Path 1","hd":false},{"ty":"gf","o":{"a":0,"k":100},"r":1,"bm":0,"g":{"p":3,"k":{"a":1,"k":[{"i":{"x":0.833,"y":1},"o":{"x":0.333,"y":0},"t":33,"s":[0,0.376,0.882,1,0.247,0.265,0.722,0.898,0.495,0.153,0.562,0.796]},{"t":49,"s":[0,0.914,0.969,1,0.247,0.596,0.873,0.992,0.495,0.278,0.776,0.984]}]}},"s":{"a":1,"k":[{"i":{"x":0.654,"y":0.734},"o":{"x":0.298,"y":0},"t":33,"s":[330.956,266.879],"to":[0,0],"ti":[44.717,2.52]},{"i":{"x":0.82,"y":1},"o":{"x":0.419,"y":0.344},"t":40,"s":[163.247,250.27],"to":[-65.48,-3.69],"ti":[10.373,0.093]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":49,"s":[-39.245,240.814],"to":[-32.909,-0.297],"ti":[18.461,0.832]},{"t":114,"s":[-589.36,249.779]}]},"e":{"a":1,"k":[{"i":{"x":0.654,"y":0.344},"o":{"x":0.298,"y":0},"t":33,"s":[504.621,271.769],"to":[0,0],"ti":[29.265,1.973]},{"i":{"x":0.82,"y":1},"o":{"x":0.419,"y":0.399},"t":40,"s":[460.89,277.846],"to":[-41.428,-2.792],"ti":[10.169,-0.136]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":49,"s":[347.7,262.099],"to":[-33.25,0.445],"ti":[26.942,0.665]},{"t":114,"s":[100.286,257.401]}]},"t":1,"nm":"Gradient Fill 22","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":1,"k":[{"i":{"x":[0.703],"y":[1]},"o":{"x":[0.275],"y":[0.17]},"t":103,"s":[100]},{"t":179,"s":[0]}]},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"вода 2","bm":0,"hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0.833,"y":1},"o":{"x":0.167,"y":0},"t":64,"s":[{"i":[[0,0],[-38.701,1.053],[0,0],[0,0]],"o":[[0,0],[-0.798,-80.588],[0,0],[0,0]],"v":[[-40.896,80.913],[64.276,81.042],[63.531,-82.043],[-40.827,-83.02]],"c":true}]},{"i":{"x":0.703,"y":1},"o":{"x":0.275,"y":0.134},"t":103,"s":[{"i":[[0,0],[-38.701,1.053],[0,0],[0,0]],"o":[[0,0],[-0.798,-80.588],[0,0],[0,0]],"v":[[-41.202,82.898],[64.276,81.042],[63.531,-82.043],[-40.827,-83.02]],"c":true}]},{"t":179,"s":[{"i":[[0,0],[-38.701,1.053],[0,0],[0,0]],"o":[[0,0],[-5.529,-83.457],[0,0],[0,0]],"v":[[-41.202,82.898],[48.311,76.053],[34.094,-81.911],[-48.311,-82.898]],"c":true}]}]},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.207843139768,0.737254917622,0.956862747669,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[406.066,338.619]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":97,"s":[0]},{"t":103,"s":[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.703,"y":1},"o":{"x":0.275,"y":0.134},"t":103,"s":[{"i":[[0,0],[0,0],[0,0],[-31.899,-0.436]],"o":[[0,0],[0,0],[0,0],[1.779,35.238]],"v":[[64.321,83.852],[-40.037,82.875],[-40.458,-78.995],[62.738,-78.691]],"c":true}]},{"t":179,"s":[{"i":[[0,0],[0,0],[0,0],[-32.119,0.79]],"o":[[0,0],[0,0],[0,0],[-2.106,32.646]],"v":[[34.884,83.984],[-47.521,82.997],[-40.412,-83.984],[47.521,-78.192]],"c":true}]}]},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.180392161012,0.541176497936,0.694117665291,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[405.276,172.724]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":97,"s":[0]},{"t":103,"s":[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.703,"y":1},"o":{"x":0.275,"y":0.134},"t":103,"s":[{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[35.508,-1.975],[0,0],[0,0],[0,0]],"v":[[-53.363,-78.482],[54.386,-78.501],[54.807,83.369],[-54.432,83.49]],"c":true}]},{"t":179,"s":[{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[35.508,-1.975],[0,0],[0,0],[0,0]],"v":[[-53.476,-75.987],[54.432,-83.49],[47.323,83.49],[-54.432,83.49]],"c":true}]}]},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.278431385756,0.776470601559,0.984313726425,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[310.432,172.23]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":97,"s":[0]},{"t":103,"s":[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.833,"y":1},"o":{"x":0.167,"y":0},"t":51,"s":[{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[26.538,-0.416],[0,0],[0,0],[0,0]],"v":[[-54.526,82.945],[54.737,80.913],[54.807,-83.02],[-54.432,-82.898]],"c":true}]},{"i":{"x":0.703,"y":1},"o":{"x":0.275,"y":0.134},"t":103,"s":[{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[26.538,-0.416],[0,0],[0,0],[0,0]],"v":[[-54.526,82.945],[54.432,82.898],[54.807,-83.02],[-54.432,-82.898]],"c":true}]},{"t":179,"s":[{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[26.196,2.172],[0,0],[0,0],[0,0]],"v":[[-54.432,75.461],[54.432,82.898],[47.323,-82.898],[-54.432,-82.898]],"c":true}]}]},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.376470595598,0.882352948189,1,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[310.432,338.619]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":97,"s":[0]},{"t":103,"s":[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.703,"y":1},"o":{"x":0.275,"y":0.134},"t":103,"s":[{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[-57.947,-0.9]],"v":[[-54.574,-79.833],[-54.457,83.283],[53.625,82.339],[54.693,-79.634]],"c":true}]},{"t":179,"s":[{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[-59.01,-2.455]],"v":[[-54.58,-83.326],[-47.472,83.326],[53.625,82.339],[54.58,-77.139]],"c":true}]}]},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.137254908681,0.525490224361,0.690196096897,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[202.376,173.382]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":97,"s":[0]},{"t":103,"s":[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.703,"y":1},"o":{"x":0.275,"y":0.134},"t":103,"s":[{"i":[[-19.745,0.395],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[39.491,-4.673]],"v":[[54.205,82.945],[54.3,-82.898],[-53.782,-81.954],[-54.3,82.898]],"c":true}]},{"t":179,"s":[{"i":[[-19.745,0.395],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[39.491,-4.673]],"v":[[54.3,75.461],[54.3,-82.898],[-46.797,-81.911],[-54.3,82.898]],"c":true}]}]},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.219607844949,0.75686275959,0.972549021244,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[201.7,338.619]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":97,"s":[0]},{"t":103,"s":[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.703,"y":1},"o":{"x":0.275,"y":0.134},"t":103,"s":[{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[37.911,1.053],[0,0],[0,0]],"v":[[-63.825,-82.282],[-62.395,82.322],[39.425,82.404],[39.943,-82.447]],"c":true}]},{"t":179,"s":[{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[37.911,1.053],[0,0],[0,0]],"v":[[-36.134,-82.404],[-46.928,76.086],[39.425,82.404],[46.928,-82.404]],"c":true}]}]},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.376470595598,0.882352948189,1,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[107.975,339.112]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":97,"s":[0]},{"t":103,"s":[100]}]},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Group 7","bm":0,"hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0.703,"y":1},"o":{"x":0.275,"y":0.134},"t":103,"s":[{"i":[[40.789,-0.003],[0,0],[0,0],[0,0]],"o":[[-0.373,43.404],[0,0],[0,0],[0,0]],"v":[[-63.147,-80.281],[-62.574,83.448],[41.194,83.283],[41.077,-79.833]],"c":true}]},{"t":179,"s":[{"i":[[40.379,-1.086],[0,0],[0,0],[0,0]],"o":[[5.394,41.515],[0,0],[0,0],[0,0]],"v":[[-48.179,-78.784],[-34.884,83.326],[48.179,83.326],[41.071,-83.326]],"c":true}]}]},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.223529413342,0.749019622803,0.988235294819,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[106.725,173.382]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":97,"s":[0]},{"t":103,"s":[100]}]},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Group 8","bm":0,"hd":false},{"ty":"tr","p":{"a":0,"k":[106.725,173.382]},"a":{"a":0,"k":[106.725,173.382]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":29.127,"s":[0]},{"t":31.259765625,"s":[100]}]},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"вода 1","bm":0,"hd":false},{"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":29,"s":[{"i":[[0,0],[-3.458,36.563],[-0.961,29.385],[-0.006,-0.007],[0.098,0.116],[2.784,3.017],[3.508,-0.435],[11.857,-40.074],[0,0],[0,0],[0,0],[-8.648,-2.185],[-5.689,-0.284],[-7.976,1.382],[0.037,0.033],[-3.993,35.422]],"o":[[0,0],[2.919,-30.862],[0.01,-0.016],[0.057,-0.007],[-1.557,-3.045],[-3.552,-3.849],[-8.184,28.871],[-10.043,33.942],[0,0],[0,0],[2.978,1.427],[8.648,2.185],[5.689,0.284],[7.976,-1.382],[2.921,-34.998],[3.774,-33.487]],"v":[[152.693,9.056],[162.291,-81.447],[174.13,-194.595],[171.502,-201.18],[171.75,-201.259],[164.459,-211.595],[153.962,-217.18],[120.375,-92.034],[94.819,-6.577],[75.948,58.034],[30.726,204.939],[51.671,210.252],[87.361,214.98],[110.418,214.387],[131.823,208.446],[144.576,88.486]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":32.857,"s":[{"i":[[0,0],[0.221,34.415],[-0.961,29.385],[6.075,5.044],[14.478,1.871],[16.804,-2.013],[25.118,-4.066],[9.976,-40.589],[0,0],[0,0],[0,0],[-46.043,-4.892],[-40.533,-0.313],[-10.62,0.554],[-1.715,0.485],[0.354,35.644]],"o":[[0,0],[-0.183,-28.393],[-4.917,-12.583],[-7.389,-6.135],[-14.215,-1.837],[-19.694,2.359],[-9.46,40.387],[-8.448,34.373],[0,0],[0,0],[13.543,2.89],[31.398,3.336],[13.33,0.103],[5.918,-0.309],[-1.113,-37.444],[-0.341,-34.228]],"v":[[172.16,0.572],[171.191,-81.963],[170.601,-201.087],[157.364,-220.211],[125.016,-232.289],[69.116,-231.614],[-3.399,-220.964],[-32.136,-93.339],[-54.801,1.089],[-74.908,102.628],[-94.158,199.626],[7.228,219.928],[104.736,224.497],[151.802,222.562],[171.898,219.528],[172.45,80.039]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":34.99,"s":[{"i":[[0,0],[0.221,34.415],[-0.961,29.385],[13.112,-1.977],[15.896,-9.571],[25.147,-2.013],[38.564,-1.246],[-0.818,-35.107],[0,0],[0,0],[0,0],[0,0],[-25.303,-5.579],[-30.516,-5.988],[-8.383,8.359],[0.354,35.644]],"o":[[0,0],[-0.183,-28.393],[-14.963,-25.056],[-21.87,3.298],[-29.553,17.794],[-12.238,0.98],[0.326,22.698],[0.825,35.387],[0,0],[0,0],[31.444,1.643],[20.108,1.185],[21.94,4.838],[44.197,8.673],[-1.113,-37.444],[-0.341,-34.228]],"v":[[172.16,0.573],[171.19,-81.963],[170.594,-208.571],[81.115,-227.944],[15.999,-204.099],[-71.584,-174.736],[-169.321,-170.513],[-167.179,-66.334],[-166.053,-0.811],[-165.532,72.128],[-165.121,168.547],[-81.513,171.32],[-10.158,184.071],[77.008,212.728],[172.071,205.059],[172.449,80.039]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":37.123,"s":[{"i":[[0,0],[0.221,34.415],[-0.961,29.385],[20.254,-7.679],[16.848,-2.992],[27.763,0.343],[38.564,-1.246],[-0.818,-35.107],[0,0],[0,0],[0,0],[0,0],[-25.803,-2.358],[-29.523,-9.772],[-8.383,8.359],[0.354,35.644]],"o":[[0,0],[-0.183,-28.393],[-32.666,-20.067],[-22.417,8.499],[-25.598,4.546],[-12.276,-0.152],[0.326,22.698],[0.825,35.387],[0,0],[0,0],[31.444,1.643],[22.508,-0.658],[26.304,2.404],[48.809,16.157],[-1.113,-37.444],[-0.341,-34.228]],"v":[[172.16,0.573],[171.19,-81.963],[170.458,-216.554],[56.169,-199.006],[-7.012,-177.656],[-97.528,-172.103],[-195.266,-170.375],[-194.121,-65.664],[-194.992,3.526],[-195.468,72.474],[-195.057,168.893],[-111.232,169.67],[-9.753,171.598],[68.526,189.278],[172.097,205.059],[172.449,80.039]],"c":true}]},{"i":{"x":0.667,"y":0.674},"o":{"x":0.167,"y":0.167},"t":39.254,"s":[{"i":[[0,0],[-2.67,34.312],[-0.961,29.385],[32.865,-3.167],[17.105,-0.457],[27.763,0.343],[38.564,-1.246],[-0.818,-35.107],[0,0],[0,0],[0,0],[0,0],[-25.698,-0.59],[-29.839,-2.149],[-16.057,-10.531],[-2.64,35.548]],"o":[[0,0],[2.203,-28.308],[-28.44,9.37],[-23.863,2.299],[-33.927,0.907],[-12.276,-0.152],[0.326,22.698],[0.825,35.387],[0,0],[0,0],[31.444,1.643],[22.508,-0.657],[26.406,0.606],[29.05,2.092],[3.191,-32.555],[2.535,-34.136]],"v":[[149.6,-2],[156.238,-82.268],[164.805,-194.601],[57.316,-172.563],[-7.283,-169.673],[-96.381,-170.755],[-195.266,-170.375],[-194.121,-65.664],[-194.992,3.527],[-195.468,72.474],[-195.057,168.893],[-111.232,169.67],[-11.324,170.051],[69.61,172.714],[132.257,191.598],[143.176,76.686]],"c":true}]},{"i":{"x":0.383,"y":1},"o":{"x":0.47,"y":0.463},"t":49,"s":[{"i":[[0,0],[-0.739,34.401],[-0.804,17.489],[0,0],[36.962,-0.732],[0,0],[35.645,11.488],[2.139,-29.73],[0,0],[-1.461,-19.597],[0,0],[0,0],[-19.442,0.29],[0,0],[-33.422,-0.974],[0.359,21.469]],"o":[[0,0],[0.809,-33.965],[-30.614,0.119],[0,0],[-64.203,-2.962],[0,0],[-6.258,33.801],[-2.839,27.026],[0,0],[1.461,19.597],[41.798,-8.266],[39.577,-3.264],[29.185,-1.907],[0,0],[-2.073,-42.93],[-0.602,-27.777]],"v":[[193.04,0.825],[194.458,-71.793],[196.336,-160.592],[108.665,-159.577],[16.313,-159.149],[-65.322,-162.465],[-139.235,-178.329],[-160.585,-66.55],[-164.921,-0.432],[-166.229,83.978],[-157.868,178.574],[-81.12,166.431],[17.314,159.492],[109.064,158.453],[197.845,159.411],[194.131,74.823]],"c":true}]},{"i":{"x":0.5,"y":1},"o":{"x":0.383,"y":0},"t":64,"s":[{"i":[[0,0],[0.221,34.415],[0.139,18.618],[0,0],[51.62,0.587],[0,0],[40.241,0.246],[-0.818,-35.107],[0,0],[0,0],[0,0],[0,0],[-18.847,0.083],[0,0],[-34.492,-3.313],[-0.398,30.32]],"o":[[0,0],[-0.183,-28.393],[-29.376,6.459],[0,0],[-39.471,-0.152],[0,0],[0.326,22.698],[0.825,35.387],[0,0],[0,0],[37.911,1.053],[39.747,-0.496],[29.671,-0.915],[0,0],[-0.19,-42.131],[0.351,-27.831]],"v":[[193.95,0.618],[194.469,-71.784],[194.43,-175.222],[121.699,-163.432],[15.315,-161.188],[-108.611,-162.078],[-197.867,-162.526],[-198.219,-63.835],[-197.093,1.688],[-196.572,74.628],[-195.662,165.558],[-108.562,166.515],[12.795,166.333],[123.388,166.39],[193.936,173.791],[193.669,74.061]],"c":true}]},{"i":{"x":0.833,"y":1},"o":{"x":0.31,"y":0},"t":87,"s":[{"i":[[0,0],[0.221,34.415],[-0.217,18.26],[0,0],[34.02,-0.401],[0,0],[40.241,0.246],[-0.818,-35.107],[0,0],[0,0],[0,0],[0,0],[-18.847,0.083],[0,0],[-38.701,1.053],[-0.104,29.373]],"o":[[0,0],[-0.183,-28.393],[-27.658,-1.198],[0,0],[-39.471,-0.152],[0,0],[0.326,22.698],[0.825,35.387],[0,0],[0,0],[37.911,1.053],[39.747,-0.496],[29.671,-0.915],[0,0],[-0.59,-43.418],[0.096,-27.249]],"v":[[213.634,0.866],[213.663,-69.682],[212.301,-161.02],[114.186,-161.175],[0.342,-161.629],[-114.598,-161.753],[-212.835,-162.037],[-213.187,-63.346],[-212.061,2.177],[-211.54,75.116],[-210.63,166.047],[-114.549,166.841],[-0.694,166.435],[114.39,166.113],[213.673,164.594],[213.24,73.585]],"c":true}]},{"i":{"x":0.703,"y":1},"o":{"x":0.275,"y":0.134},"t":103,"s":[{"i":[[0,0],[0.221,34.415],[-0.217,18.26],[0,0],[34.02,-0.401],[0,0],[40.241,0.246],[-0.818,-35.107],[0,0],[0,0],[0,0],[0,0],[-18.847,0.083],[0,0],[-38.701,1.053],[-0.104,29.373]],"o":[[0,0],[-0.183,-28.393],[-27.658,-1.198],[0,0],[-39.471,-0.152],[0,0],[0.326,22.698],[0.825,35.387],[0,0],[0,0],[37.911,1.053],[39.747,-0.496],[29.671,-0.915],[0,0],[-0.59,-43.418],[0.096,-27.249]],"v":[[213.634,0.866],[213.663,-69.682],[212.301,-161.02],[114.186,-161.175],[0.342,-161.629],[-114.598,-161.753],[-212.835,-162.037],[-213.187,-63.346],[-212.061,2.177],[-211.54,75.116],[-210.63,166.047],[-114.549,166.841],[-0.694,166.435],[114.39,166.113],[213.673,164.594],[213.24,73.585]],"c":true}]},{"t":179,"s":[{"i":[[0,0],[-2.73,34.307],[-1.103,17.096],[0,0],[35.508,-1.975],[0,0],[40.379,-1.086],[-2.651,-35.361],[0,0],[0,0],[0,0],[0,0],[-19.745,0.395],[0,0],[-38.701,1.053],[2.895,29.231]],"o":[[0,0],[3.002,-37.719],[-32.119,0.79],[0,0],[-59.01,-2.455],[0,0],[2.699,20.776],[2.646,35.297],[0,0],[0,0],[37.911,1.053],[39.491,-4.673],[26.196,2.172],[0,0],[-2.828,-42.682],[-2.766,-27.925]],"v":[[183.699,1.58],[188.818,-62.114],[196.336,-160.596],[108.402,-166.388],[0.495,-158.885],[-108.666,-165.072],[-197.915,-160.53],[-189.238,-63.813],[-184.62,1.58],[-189.587,74.508],[-195.414,160.07],[-109.061,166.388],[-0.461,158.951],[108.402,166.388],[197.915,159.543],[188.539,47.291]],"c":true}]}]},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":0,"k":[0.345098048449,0.349019616842,0.35686275363,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":4},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.588235234279,0.922308588963,1,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[256.461,255.128]},"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":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0.703,"y":1},"o":{"x":0.275,"y":0.134},"t":103,"s":[{"i":[[0,0],[-43.655,0.957],[0,0],[0,0]],"o":[[0,0],[-1.63,-82.186],[0,0],[0,0]],"v":[[-52.346,89.887],[71.661,88.981],[69.752,-91.732],[-56.444,-92.49]],"c":true}]},{"t":179,"s":[{"i":[[0,0],[-43.655,0.957],[0,0],[0,0]],"o":[[0,0],[-5.966,-92.147],[0,0],[0,0]],"v":[[-52.595,92.49],[56.444,84.74],[40.565,-91.62],[-56.444,-92.49]],"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":[417.474,348.492]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":10},"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.703,"y":1},"o":{"x":0.275,"y":0.134},"t":103,"s":[{"i":[[0,0],[0,0],[0,0],[-35.1,-0.598]],"o":[[0,0],[0,0],[0,0],[-0.152,34.933]],"v":[[70.865,93.007],[-55.58,92.057],[-51.774,-87.113],[71.297,-86.571]],"c":true}]},{"t":179,"s":[{"i":[[0,0],[0,0],[0,0],[-35.1,-0.598]],"o":[[0,0],[0,0],[0,0],[-2.167,33.319]],"v":[[41.428,92.928],[-55.58,92.057],[-51.434,-92.928],[55.58,-86.571]],"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":[416.61,163.945]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":20},"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.703,"y":1},"o":{"x":0.275,"y":0.134},"t":103,"s":[{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[37.175,0.472],[0,0],[0,0],[0,0]],"v":[[-53.763,-86.101],[54.08,-86.678],[50.273,92.492],[-54.42,92.492]],"c":true}]},{"t":179,"s":[{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[36.533,-2.015],[0,0],[0,0],[0,0]],"v":[[-53.801,-84.355],[54.42,-92.492],[50.273,92.492],[-54.42,92.492]],"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":[310.757,163.51]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":10},"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.703,"y":1},"o":{"x":0.275,"y":0.134},"t":103,"s":[{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[-58.62,-0.526]],"v":[[-54.067,-88.09],[-49.684,92.169],[54.331,91.161],[54.988,-87.432]],"c":true}]},{"t":179,"s":[{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[-60.714,-2.506]],"v":[[-54.95,-92.169],[-49.684,92.169],[54.331,91.161],[54.95,-85.686]],"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":[202.006,164.841]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":20},"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.703,"y":1},"o":{"x":0.275,"y":0.134},"t":103,"s":[{"i":[[-20.316,0.403],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[40.542,-0.558]],"v":[[54.255,90.769],[54.741,-92.456],[-49.274,-91.448],[-54.646,92.207]],"c":true}]},{"t":179,"s":[{"i":[[-20.316,0.403],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[40.631,-4.769]],"v":[[54.218,84.283],[54.741,-92.456],[-49.274,-91.448],[-54.741,92.456]],"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":[201.596,348.458]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":10},"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.703,"y":1},"o":{"x":0.275,"y":0.134},"t":103,"s":[{"i":[[55.265,-0.717],[0,0],[0,0],[0,0]],"o":[[-0.616,53.916],[0,0],[0,0],[0,0]],"v":[[-71.09,-88.239],[-69.365,91.883],[57.12,92.169],[52.737,-88.09]],"c":true}]},{"t":179,"s":[{"i":[[55.766,-3.617],[0,0],[0,0],[0,0]],"o":[[5.076,50.937],[0,0],[0,0],[0,0]],"v":[[-57.12,-87.241],[-42.423,91.867],[57.12,92.169],[51.853,-92.169]],"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":[95.202,164.841]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":10},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Group 6","bm":0,"hd":false},{"ty":"tr","p":{"a":0,"k":[95.202,164.841]},"a":{"a":0,"k":[95.202,164.841]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":1,"k":[{"i":{"x":[0.703],"y":[1]},"o":{"x":[0.275],"y":[0.17]},"t":103,"s":[0]},{"t":179,"s":[100]}]},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"тень карта","bm":0,"hd":false},{"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":29,"s":[{"i":[[0,0],[-4.871,45.467],[-2.197,29.51],[0.096,-0.31],[0.04,0.065],[6.382,3.422],[2.185,0.747],[12.387,-38.818],[0,0],[0,0],[0,0],[-30.794,-3.47],[-0.659,0.311],[-10.172,1.901],[0.038,0.021],[-3.087,32.325]],"o":[[0,0],[2.605,-24.31],[0.063,0.123],[0.096,0.189],[0.04,-8.042],[-7.938,-4.256],[-9.671,31.338],[-12.783,40.057],[0,0],[0,0],[3.981,2.508],[10.248,1.155],[-0.066,-0.032],[19.327,-3.612],[2.987,-30.758],[2.893,-30.29]],"v":[[153.299,9.235],[162.8,-81.939],[177.798,-227.475],[177.766,-227.291],[177.822,-227.292],[162.666,-244.821],[146.182,-251.196],[104.603,-101.117],[77.996,-13.273],[59.757,47.025],[6.843,218.275],[66.72,235.926],[90.536,236.782],[108.992,235.167],[131.493,219.147],[144.608,87.371]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":31.26,"s":[{"i":[[0,0],[-1.97,44.487],[-1.862,28.888],[1.735,1.116],[11.85,3.361],[10.568,-0.26],[18.442,-4.221],[10.272,-37.439],[0,0],[0,0],[0,0],[-21.394,-2.919],[-13.968,0.049],[-12.686,1.923],[-2.884,1.964],[-1.557,32.816]],"o":[[0,0],[1.039,-26.749],[0.063,-3.227],[-5.909,-4.304],[-13.234,-2.981],[-10.808,-0.191],[-7.697,29.299],[-11.145,40.92],[0,0],[0,0],[22.749,9.114],[22.636,3.682],[11.134,0.055],[16.311,-2.617],[1.091,-40.052],[1.436,-28.937]],"v":[[167.414,4.213],[171.113,-80.921],[177.623,-227.915],[172.245,-235.5],[146.633,-245.273],[104.362,-248.021],[53.403,-241.846],[19.267,-99.73],[-4.702,-6.5],[-24.27,76.115],[-61.307,214.517],[32.959,237.872],[97.538,241.538],[134.114,238.93],[157.721,227.4],[163.669,82.212]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":32.857,"s":[{"i":[[0,0],[0.207,43.751],[-1.611,28.421],[2.965,2.185],[26.724,1.872],[13.706,-3.022],[30.635,-7.946],[8.685,-36.406],[0,0],[0,0],[0,0],[-14.344,-2.506],[-23.95,-0.147],[-14.571,1.94],[-5.076,3.421],[-0.409,33.185]],"o":[[0,0],[-0.135,-28.579],[0.063,-5.739],[-10.412,-7.674],[-21.598,-1.513],[-12.961,2.857],[-6.217,27.77],[-9.916,41.567],[0,0],[0,0],[36.826,14.069],[31.927,5.577],[19.534,0.12],[14.049,-1.871],[-0.331,-47.023],[0.344,-27.922]],"v":[[178.001,0.447],[177.348,-80.157],[177.491,-228.245],[168.104,-241.657],[121.384,-253.925],[60.634,-250.421],[-16.182,-234.835],[-44.736,-98.689],[-66.726,-1.421],[-87.291,97.932],[-112.42,211.699],[7.638,239.331],[102.789,245.105],[152.956,241.752],[177.392,233.589],[177.964,78.343]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":34.99,"s":[{"i":[[0,0],[0.207,43.751],[-1.611,28.421],[16.25,-2.811],[27.906,-18.228],[49.49,-4.768],[54.714,-1.086],[-0.478,-37.424],[0,0],[0,0],[0,0],[-23.167,-3.093],[-23.59,-7.382],[-28.053,-6.314],[-6.822,7.412],[-0.409,33.185]],"o":[[0,0],[-0.135,-28.579],[-24.458,-31.684],[-14.073,2.434],[-27.571,18.009],[-28.031,2.701],[-0.21,25.353],[0.457,35.827],[0,0],[0,0],[40.887,1.158],[14.433,1.927],[17.488,5.472],[53.531,12.048],[-0.331,-47.023],[0.344,-27.922]],"v":[[178,0.447],[177.347,-80.157],[177.491,-228.245],[80.79,-250.389],[12.866,-222.243],[-75.575,-189.8],[-182.581,-185.998],[-182.093,-66.868],[-180.599,-1.667],[-180.127,73.303],[-179.774,183.314],[-79.254,186.218],[-12.972,200.486],[77.549,237.934],[177.391,233.589],[177.963,78.343]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":37.123,"s":[{"i":[[0,0],[0.207,43.751],[-1.611,28.421],[14.988,-6.878],[29.53,-7.232],[42.128,-0.416],[54.714,-1.086],[-0.478,-37.424],[0,0],[0,0],[0,0],[-23.373,-0.057],[-28.173,-4.388],[-25.593,-13.108],[-20.919,13.898],[-0.409,33.185]],"o":[[0,0],[-0.135,-28.579],[-24.458,-31.684],[-19.439,8.921],[-23.362,5.721],[-28.16,0.278],[-0.21,25.353],[0.457,35.827],[0,0],[0,0],[40.887,1.158],[21.859,0.053],[18.106,2.82],[36.19,18.535],[-0.331,-47.023],[0.344,-27.922]],"v":[[178,0.447],[177.347,-80.157],[177.491,-236.228],[53.348,-216.96],[-9.586,-193.803],[-101.52,-187.167],[-208.526,-185.86],[-209.035,-66.198],[-209.537,2.671],[-210.063,73.649],[-209.711,183.66],[-109.209,184.069],[-13.256,187.014],[69.067,212.488],[177.417,233.589],[177.963,78.343]],"c":true}]},{"i":{"x":0.667,"y":0.674},"o":{"x":0.167,"y":0.167},"t":39.254,"s":[{"i":[[0,0],[-3.469,43.614],[-1.611,28.421],[47.98,-7.544],[18.715,-0.286],[42.128,-0.416],[54.714,-1.086],[-0.478,-37.424],[0,0],[0,0],[0,0],[-23.373,-0.057],[-28.513,-0.106],[-27.15,-3.087],[-20.489,-23.371],[-3.195,33.033]],"o":[[0,0],[2.266,-28.489],[-21.156,8.231],[-21.129,3.322],[-24.049,0.367],[-28.16,0.278],[-0.21,25.353],[0.457,35.827],[0,0],[0,0],[40.887,1.158],[21.859,0.053],[34.621,0.129],[23.465,2.668],[3.62,-46.884],[2.688,-27.794]],"v":[[150.571,-2.385],[156.69,-82.759],[169.392,-230.241],[56.166,-192.013],[-9.395,-186.344],[-100.373,-185.819],[-208.526,-185.86],[-209.035,-66.198],[-209.537,2.671],[-210.063,73.649],[-209.711,183.66],[-109.209,184.069],[-12.757,184.021],[70.564,189.537],[130.622,228.901],[143.992,75.233]],"c":true}]},{"i":{"x":0.383,"y":1},"o":{"x":0.47,"y":0.463},"t":49,"s":[{"i":[[0,0],[-0.808,34.529],[-0.916,20.3],[0,0],[39.307,1.285],[0,0],[33.647,18.092],[6.712,-47.144],[0,0],[-1.061,-27.185],[0,0],[0,0],[-21.295,0.434],[0,0],[-41.738,1.158],[1.082,32.16]],"o":[[0,0],[0.98,-40.675],[-37.657,0.039],[0,0],[-69.503,-2.07],[-0.301,-0.426],[-3.484,24.031],[-2.272,30.316],[0,0],[1.262,32.315],[36.364,-14.285],[37.207,-4.991],[30.178,-0.52],[0,0],[-2.538,-48.887],[-1.028,-28.814]],"v":[[208.183,-0.527],[209.313,-70.878],[211.745,-174.59],[108.711,-174.736],[16.742,-175.066],[-62.016,-180.499],[-145.971,-204.674],[-169.902,-66.818],[-175.014,0.022],[-176.09,82.041],[-166.531,204.123],[-80.339,182.477],[17.029,173.539],[109.804,170.624],[212.739,170.807],[209.122,73.445]],"c":true}]},{"i":{"x":0.5,"y":1},"o":{"x":0.383,"y":0},"t":64,"s":[{"i":[[0,0],[0.093,35.899],[0.287,22.22],[0,0],[39.01,0.624],[0,0],[44.195,-0.092],[-0.478,-37.424],[0,0],[0,0],[0,0],[0,0],[-21.295,0.434],[0,0],[-39.915,-9.387],[0.324,32.175]],"o":[[0,0],[-0.083,-38.317],[-32.879,9.259],[0,0],[-63.022,-0.499],[-1.096,-0.025],[-0.21,25.353],[0.457,35.827],[0,0],[0,0],[40.887,1.158],[41.836,0.215],[26.733,0.472],[0,0],[-0.714,-49.722],[-0.189,-23.206]],"v":[[209.414,0.206],[209.342,-72.213],[208.82,-194.993],[122.979,-180.41],[14.843,-175.322],[-108.611,-176.145],[-213.4,-176.514],[-213.132,-64.369],[-211.639,0.832],[-211.167,75.802],[-210.998,179.327],[-108.798,179.916],[13.105,180.056],[123.219,184.296],[209.373,196.602],[209.199,75.123]],"c":true}]},{"i":{"x":0.833,"y":1},"o":{"x":0.31,"y":0},"t":87,"s":[{"i":[[0,0],[0.01,34.543],[-0.263,21.434],[0,0],[39.01,0.624],[0,0],[44.195,-0.092],[-0.478,-37.424],[0,0],[0,0],[0,0],[0,0],[-21.295,0.434],[0,0],[-41.739,1.158],[0.535,32.176]],"o":[[0,0],[-0.011,-38.317],[-34.666,-0.823],[0,0],[-63.022,-0.499],[-1.096,-0.025],[-0.21,25.353],[0.457,35.827],[0,0],[0,0],[40.887,1.158],[41.836,0.215],[26.733,0.472],[0,0],[-1.325,-49.508],[-0.367,-22.062]],"v":[[227.785,0.175],[227.857,-69.375],[227.71,-175.028],[114.894,-175.672],[0.839,-174.735],[-114.598,-175.819],[-228.368,-176.026],[-228.1,-63.88],[-226.607,1.321],[-226.135,76.291],[-225.966,179.816],[-114.785,180.242],[-0.355,179.16],[114.798,178.614],[229.272,177.313],[227.57,73.53]],"c":true}]},{"i":{"x":0.703,"y":1},"o":{"x":0.275,"y":0.134},"t":103,"s":[{"i":[[0,0],[0.01,34.543],[-0.263,21.434],[0,0],[39.01,0.624],[0,0],[44.195,-0.092],[-0.478,-37.424],[0,0],[0,0],[0,0],[0,0],[-21.295,0.434],[0,0],[-41.739,1.158],[0.535,32.176]],"o":[[0,0],[-0.011,-38.317],[-34.666,-0.823],[0,0],[-63.022,-0.499],[-1.096,-0.025],[-0.21,25.353],[0.457,35.827],[0,0],[0,0],[40.887,1.158],[41.836,0.215],[26.733,0.472],[0,0],[-1.325,-49.508],[-0.367,-22.062]],"v":[[227.785,0.175],[227.857,-69.375],[227.71,-175.028],[114.894,-175.672],[0.839,-174.735],[-114.598,-175.819],[-228.368,-176.026],[-228.1,-63.88],[-226.607,1.321],[-226.135,76.291],[-225.966,179.816],[-114.785,180.242],[-0.355,179.16],[114.798,178.614],[229.272,177.313],[227.57,73.53]],"c":true}]},{"t":179,"s":[{"i":[[0,0],[-2.802,34.43],[-1.248,19.723],[0,0],[38.294,-2.172],[0,0],[43.779,-2.595],[-3.065,-39.158],[0,0],[0,0],[0,0],[0,0],[-21.295,0.434],[0,0],[-41.739,1.158],[3.24,32.017]],"o":[[0,0],[3.415,-41.97],[-34.666,-0.823],[0,0],[-63.642,-2.7],[0.104,-0.631],[2.437,24.199],[2.796,35.721],[0,0],[0,0],[40.887,1.158],[42.59,-5.139],[28.252,2.389],[0,0],[-3.155,-48.571],[-2.883,-28.484]],"v":[[197.849,0.889],[203.012,-61.887],[211.745,-174.59],[109.11,-180.885],[0.89,-172.74],[-108.666,-179.139],[-213.448,-174.519],[-204.152,-64.346],[-199.166,0.724],[-204.182,75.682],[-210.751,173.839],[-109.258,180.788],[-0.066,172.674],[108.812,180.885],[213.448,173.26],[202.868,47.235]],"c":true}]}]},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":0,"k":[0.72549021244,0.368627458811,0.019607843831,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":8},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 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":[256.066,255.984]},"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}],"ip":29,"op":180,"st":0,"bm":0},{"ddd":0,"ind":37,"ty":4,"nm":"карта вторая 3","parent":39,"sr":1,"ks":{"p":{"a":0,"k":[0,5,0]},"a":{"a":0,"k":[256,256,0]},"s":{"a":0,"k":[100.214,100.214,100]}},"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":29,"s":[{"i":[[0,0],[-3.458,36.563],[-0.961,29.385],[-0.006,-0.007],[0.098,0.116],[2.784,3.017],[3.508,-0.435],[11.857,-40.074],[0,0],[0,0],[0,0],[-8.648,-2.185],[-5.689,-0.284],[-7.976,1.382],[0.037,0.033],[-3.993,35.422]],"o":[[0,0],[2.919,-30.862],[0.01,-0.016],[0.057,-0.007],[-1.557,-3.045],[-3.552,-3.849],[-8.184,28.871],[-10.043,33.942],[0,0],[0,0],[2.978,1.427],[8.648,2.185],[5.689,0.284],[7.976,-1.382],[2.921,-34.998],[3.774,-33.487]],"v":[[152.693,9.056],[162.291,-81.447],[174.13,-194.595],[171.502,-201.18],[171.75,-201.259],[164.459,-211.595],[153.962,-217.18],[120.375,-92.034],[94.819,-6.577],[75.948,58.034],[30.726,204.939],[51.671,210.252],[87.361,214.98],[110.418,214.387],[131.823,208.446],[144.576,88.486]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":32.857,"s":[{"i":[[0,0],[0.221,34.415],[-0.961,29.385],[6.075,5.044],[14.478,1.871],[16.804,-2.013],[25.118,-4.066],[9.976,-40.589],[0,0],[0,0],[0,0],[-46.043,-4.892],[-40.533,-0.313],[-10.62,0.554],[-1.715,0.485],[0.354,35.644]],"o":[[0,0],[-0.183,-28.393],[-4.917,-12.583],[-7.389,-6.135],[-14.215,-1.837],[-19.694,2.359],[-9.46,40.387],[-8.448,34.373],[0,0],[0,0],[13.543,2.89],[31.398,3.336],[13.33,0.103],[5.918,-0.309],[-1.113,-37.444],[-0.341,-34.228]],"v":[[172.16,0.572],[171.191,-81.963],[170.601,-201.087],[157.364,-220.211],[125.016,-232.289],[69.116,-231.614],[-3.399,-220.964],[-32.136,-93.339],[-54.801,1.089],[-74.908,102.628],[-94.158,199.626],[7.228,219.928],[104.736,224.497],[151.802,222.562],[171.898,219.528],[172.45,80.039]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":34.99,"s":[{"i":[[0,0],[0.221,34.415],[-0.961,29.385],[13.112,-1.977],[15.896,-9.571],[25.147,-2.013],[38.564,-1.246],[-0.818,-35.107],[0,0],[0,0],[0,0],[0,0],[-25.303,-5.579],[-30.516,-5.988],[-8.383,8.359],[0.354,35.644]],"o":[[0,0],[-0.183,-28.393],[-14.963,-25.056],[-21.87,3.298],[-29.553,17.794],[-12.238,0.98],[0.326,22.698],[0.825,35.387],[0,0],[0,0],[31.444,1.643],[20.108,1.185],[21.94,4.838],[44.197,8.673],[-1.113,-37.444],[-0.341,-34.228]],"v":[[172.16,0.573],[171.19,-81.963],[170.594,-208.571],[81.115,-227.944],[15.999,-204.099],[-71.584,-174.736],[-169.321,-170.513],[-167.179,-66.334],[-166.053,-0.811],[-165.532,72.128],[-165.121,168.547],[-81.513,171.32],[-10.158,184.071],[77.008,212.728],[172.071,205.059],[172.449,80.039]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":37.123,"s":[{"i":[[0,0],[0.221,34.415],[-0.961,29.385],[20.254,-7.679],[16.848,-2.992],[27.763,0.343],[38.564,-1.246],[-0.818,-35.107],[0,0],[0,0],[0,0],[0,0],[-25.803,-2.358],[-29.522,-9.772],[-8.383,8.359],[0.354,35.644]],"o":[[0,0],[-0.183,-28.393],[-32.666,-20.067],[-22.417,8.499],[-25.598,4.546],[-12.276,-0.152],[0.326,22.698],[0.825,35.387],[0,0],[0,0],[31.444,1.643],[22.508,-0.658],[26.304,2.404],[48.809,16.157],[-1.113,-37.444],[-0.341,-34.228]],"v":[[172.16,0.573],[171.19,-81.963],[170.458,-216.554],[56.169,-199.006],[-7.012,-177.656],[-97.528,-172.103],[-195.266,-170.375],[-194.121,-65.664],[-194.992,3.526],[-195.468,72.474],[-195.057,168.893],[-111.232,169.67],[-9.753,171.598],[68.526,189.278],[172.097,205.059],[172.449,80.039]],"c":true}]},{"i":{"x":0.667,"y":0.674},"o":{"x":0.167,"y":0.167},"t":39.254,"s":[{"i":[[0,0],[-2.67,34.312],[-0.961,29.385],[32.865,-3.167],[17.105,-0.457],[27.763,0.343],[38.564,-1.246],[-0.818,-35.107],[0,0],[0,0],[0,0],[0,0],[-25.698,-0.59],[-29.839,-2.149],[-16.057,-10.531],[-2.64,35.548]],"o":[[0,0],[2.203,-28.308],[-28.44,9.37],[-23.864,2.299],[-33.927,0.907],[-12.276,-0.152],[0.326,22.698],[0.825,35.387],[0,0],[0,0],[31.444,1.643],[22.508,-0.657],[26.406,0.606],[29.05,2.092],[3.191,-32.555],[2.535,-34.136]],"v":[[149.6,-2],[156.238,-82.268],[164.805,-194.601],[57.316,-172.563],[-7.283,-169.673],[-96.381,-170.755],[-195.266,-170.375],[-194.121,-65.664],[-194.992,3.527],[-195.468,72.474],[-195.057,168.893],[-111.232,169.67],[-11.324,170.051],[69.61,172.714],[132.257,191.598],[143.177,76.686]],"c":true}]},{"i":{"x":0.383,"y":1},"o":{"x":0.47,"y":0.463},"t":49,"s":[{"i":[[0,0],[-0.739,34.401],[-0.804,17.489],[0,0],[36.962,-0.732],[0,0],[35.645,11.488],[2.139,-29.73],[0,0],[-1.461,-19.597],[0,0],[0,0],[-19.442,0.29],[0,0],[-33.422,-0.974],[0.359,21.469]],"o":[[0,0],[0.809,-33.965],[-30.614,0.119],[0,0],[-64.203,-2.962],[0,0],[-6.258,33.801],[-2.839,27.026],[0,0],[1.461,19.597],[41.798,-8.266],[39.577,-3.264],[29.185,-1.907],[0,0],[-2.073,-42.93],[-0.602,-27.777]],"v":[[193.04,0.825],[194.458,-71.793],[196.335,-160.592],[108.665,-159.577],[16.313,-159.149],[-65.322,-162.465],[-139.235,-178.329],[-160.585,-66.55],[-164.921,-0.432],[-166.229,83.978],[-157.868,178.574],[-81.12,166.431],[17.314,159.492],[109.064,158.453],[197.845,159.411],[194.131,74.823]],"c":true}]},{"i":{"x":0.5,"y":1},"o":{"x":0.383,"y":0},"t":64,"s":[{"i":[[0,0],[0.221,34.415],[0.139,18.618],[0,0],[51.62,0.587],[0,0],[40.241,0.246],[-0.818,-35.107],[0,0],[0,0],[0,0],[0,0],[-18.847,0.083],[0,0],[-34.492,-3.313],[-0.398,30.32]],"o":[[0,0],[-0.183,-28.393],[-29.376,6.459],[0,0],[-39.471,-0.152],[0,0],[0.326,22.698],[0.825,35.387],[0,0],[0,0],[37.911,1.053],[39.747,-0.496],[29.671,-0.915],[0,0],[-0.19,-42.131],[0.351,-27.831]],"v":[[193.95,0.618],[194.469,-71.784],[194.43,-175.222],[121.699,-163.432],[15.315,-161.188],[-108.611,-162.078],[-197.867,-162.526],[-198.219,-63.835],[-197.093,1.688],[-196.572,74.628],[-195.662,165.558],[-108.562,166.515],[12.795,166.333],[123.388,166.39],[193.936,173.791],[193.669,74.061]],"c":true}]},{"i":{"x":0.833,"y":1},"o":{"x":0.31,"y":0},"t":87,"s":[{"i":[[0,0],[0.221,34.415],[-0.217,18.26],[0,0],[34.02,-0.401],[0,0],[40.241,0.246],[-0.818,-35.107],[0,0],[0,0],[0,0],[0,0],[-18.847,0.083],[0,0],[-38.701,1.053],[-0.104,29.373]],"o":[[0,0],[-0.183,-28.393],[-27.658,-1.198],[0,0],[-39.471,-0.152],[0,0],[0.326,22.698],[0.825,35.387],[0,0],[0,0],[37.911,1.053],[39.747,-0.496],[29.671,-0.915],[0,0],[-0.59,-43.418],[0.096,-27.249]],"v":[[213.634,0.866],[213.663,-69.682],[212.301,-161.02],[114.186,-161.175],[0.342,-161.629],[-114.598,-161.753],[-212.835,-162.037],[-213.187,-63.346],[-212.061,2.177],[-211.54,75.116],[-210.63,166.047],[-114.549,166.841],[-0.694,166.435],[114.39,166.113],[213.673,164.594],[213.24,73.585]],"c":true}]},{"i":{"x":0.703,"y":1},"o":{"x":0.275,"y":0.134},"t":103,"s":[{"i":[[0,0],[0.221,34.415],[-0.217,18.26],[0,0],[34.02,-0.401],[0,0],[40.241,0.246],[-0.818,-35.107],[0,0],[0,0],[0,0],[0,0],[-18.847,0.083],[0,0],[-38.701,1.053],[-0.104,29.373]],"o":[[0,0],[-0.183,-28.393],[-27.658,-1.198],[0,0],[-39.471,-0.152],[0,0],[0.326,22.698],[0.825,35.387],[0,0],[0,0],[37.911,1.053],[39.747,-0.496],[29.671,-0.915],[0,0],[-0.59,-43.418],[0.096,-27.249]],"v":[[213.634,0.866],[213.663,-69.682],[212.301,-161.02],[114.186,-161.175],[0.342,-161.629],[-114.598,-161.753],[-212.835,-162.037],[-213.187,-63.346],[-212.061,2.177],[-211.54,75.116],[-210.63,166.047],[-114.549,166.841],[-0.694,166.435],[114.39,166.113],[213.673,164.594],[213.24,73.585]],"c":true}]},{"t":179,"s":[{"i":[[0,0],[-2.73,34.307],[-1.103,17.096],[0,0],[35.508,-1.975],[0,0],[40.379,-1.086],[-2.651,-35.361],[0,0],[0,0],[0,0],[0,0],[-19.745,0.395],[0,0],[-38.701,1.053],[2.895,29.231]],"o":[[0,0],[3.002,-37.719],[-32.119,0.79],[0,0],[-59.01,-2.455],[0,0],[2.699,20.776],[2.646,35.297],[0,0],[0,0],[37.911,1.053],[39.491,-4.673],[26.196,2.172],[0,0],[-2.828,-42.682],[-2.766,-27.925]],"v":[[183.699,1.58],[188.818,-62.114],[196.336,-160.596],[108.402,-166.388],[0.495,-158.885],[-108.666,-165.072],[-197.915,-160.53],[-189.238,-63.813],[-184.62,1.58],[-189.587,74.508],[-195.414,160.07],[-109.061,166.388],[-0.461,158.951],[108.402,166.388],[197.915,159.543],[188.539,47.291]],"c":true}]}]},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":0,"k":[0.345098048449,0.349019616842,0.35686275363,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":4},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"tr","p":{"a":0,"k":[256.461,255.128]},"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":29,"op":180,"st":0,"bm":0},{"ddd":0,"ind":38,"ty":4,"nm":"карта первая","parent":39,"sr":1,"ks":{"p":{"a":0,"k":[0,5,0]},"a":{"a":0,"k":[256,256,0]},"s":{"a":0,"k":[100.214,100.214,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.642,"y":0},"t":0,"s":[{"i":[[20.942,0.2],[18.028,0.169],[-1.676,-40.002],[0,0],[-31.18,-3.179],[-17.77,26.124]],"o":[[-15.41,-0.147],[2.561,25.116],[-6.426,36.918],[0,0],[31.686,-99.473],[-13.576,-1.069]],"v":[[145.546,81.686],[47.38,85.195],[61.595,256.586],[49.51,425.024],[147.479,431.81],[254.453,89.106]],"c":true}]},{"i":{"x":0.317,"y":1},"o":{"x":0.167,"y":0.167},"t":12,"s":[{"i":[[20.942,0.2],[9.988,-13.184],[5.009,-37.458],[0,0],[-31.896,0.555],[-17.77,26.124]],"o":[[-15.41,-0.147],[-6.386,17.608],[-6.426,36.918],[0,0],[-3.379,-101.809],[-13.576,-1.069]],"v":[[167.363,80.039],[125.684,105.924],[74.356,258.645],[51.98,427.906],[145.009,418.637],[255.688,84.99]],"c":true}]},{"i":{"x":0.833,"y":0.687},"o":{"x":0.696,"y":0},"t":19,"s":[{"i":[[20.942,0.2],[8.283,-16.015],[6.426,-36.918],[0,0],[-32.047,1.346],[-17.77,26.124]],"o":[[-15.41,-0.147],[-8.283,16.015],[-6.426,36.918],[0,0],[-10.815,-102.305],[-13.576,-1.069]],"v":[[171.989,79.69],[130.702,110.142],[77.062,259.081],[52.504,428.517],[144.485,415.844],[255.95,84.117]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.313},"t":23.264,"s":[{"i":[[20.942,0.2],[25.551,-18.828],[4.694,-37.981],[0,0],[-32.047,1.346],[-17.77,26.124]],"o":[[-15.41,-0.147],[-8.283,16.015],[-4.696,37.065],[0,0],[-10.815,-102.305],[-13.576,-1.069]],"v":[[169.019,80.639],[110.95,98.279],[69.631,258.719],[51.793,428.992],[144.267,417.234],[256.339,84.63]],"c":true}]},{"t":26.4609375,"s":[{"i":[[20.942,0.2],[11.38,0.511],[-0.117,-40.931],[0,0],[-32.047,1.346],[-17.77,26.124]],"o":[[-15.41,-0.147],[-8.283,16.015],[0.107,37.473],[0,0],[-10.815,-102.305],[-13.576,-1.069]],"v":[[171.166,84.938],[48.158,83.903],[49.001,257.713],[49.819,430.31],[143.661,421.092],[257.417,86.055]],"c":true}]}]},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":0},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"gf","o":{"a":0,"k":100},"r":1,"bm":0,"g":{"p":3,"k":{"a":0,"k":[0,0,0,0,0.5,0.5,0.5,0.5,1,1,1,1,0,1,0.5,0.5,1,0]}},"s":{"a":0,"k":[124.812,207.817]},"e":{"a":0,"k":[182.663,237.559]},"t":1,"nm":"Gradient Fill 23","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":1,"k":[{"i":{"x":[0.317],"y":[1]},"o":{"x":[0.642],"y":[0]},"t":0,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.696],"y":[0]},"t":19,"s":[40]},{"t":26.4609375,"s":[0]}]},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Shape 2","bm":0,"hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.642,"y":0},"t":0,"s":[{"i":[[0,0],[-2.73,34.307],[-1.103,17.096],[0,0],[35.508,-1.975],[0,0],[40.379,-1.086],[-2.651,-35.361],[0,0],[0,0],[0,0],[0,0],[-19.745,0.395],[0,0],[-38.701,1.053],[2.895,29.231]],"o":[[0,0],[3.002,-37.719],[-32.119,0.79],[0,0],[-59.01,-2.455],[0,0],[2.699,20.776],[2.646,35.297],[0,0],[0,0],[37.911,1.053],[39.491,-4.673],[26.196,2.172],[0,0],[-2.828,-42.682],[-2.766,-27.925]],"v":[[183.698,1.58],[188.818,-62.114],[196.335,-160.596],[108.402,-166.388],[0.495,-158.885],[-108.666,-165.072],[-197.915,-160.53],[-189.238,-63.813],[-184.62,1.58],[-189.587,74.508],[-195.414,160.07],[-109.061,166.388],[-0.461,158.951],[108.402,166.388],[197.915,159.543],[188.538,47.291]],"c":true}]},{"i":{"x":0.317,"y":1},"o":{"x":0.167,"y":0.167},"t":12,"s":[{"i":[[0,0],[-1.491,34.378],[-1.103,17.096],[0,0],[27.327,0.662],[16.117,-0.701],[15.195,-5.609],[11.876,-43.027],[0,0],[10.214,-65.944],[0,0],[0,0],[-19.745,0.395],[0,0],[-33.921,0.255],[0.998,19.507]],"o":[[0,0],[1.609,-36.961],[-32.119,0.79],[0,0],[-36.766,-2.704],[-16.117,0.701],[-13.131,31.54],[-10.526,38.984],[0,0],[-11.254,72.657],[35.93,-5.082],[31.377,-2.744],[29.63,-0.186],[0,0],[-1.185,-32.899],[-1.274,-28.024]],"v":[[215.436,-3.721],[217.265,-75.715],[221.22,-161.859],[97.327,-161.156],[-30.636,-162.03],[-99.492,-166.224],[-128.949,-151.91],[-160.189,-63.194],[-178.507,5.308],[-193.119,88.112],[-201.405,153.652],[-124.279,149.087],[-28.122,145.367],[96.703,148.047],[219.303,148.089],[216.986,65.797]],"c":true}]},{"i":{"x":0.833,"y":0.687},"o":{"x":0.696,"y":0},"t":19,"s":[{"i":[[0,0],[-1.228,34.394],[-1.103,17.096],[0,0],[25.593,1.221],[19.535,-0.85],[9.854,-6.569],[14.957,-44.653],[0,0],[12.38,-79.928],[0,0],[0,0],[-19.745,0.395],[0,0],[-32.908,0.085],[0.595,17.445]],"o":[[0,0],[1.314,-36.801],[-32.119,0.79],[0,0],[-32.049,-2.757],[-19.535,0.85],[-16.488,33.822],[-13.319,39.766],[0,0],[-13.641,88.065],[35.51,-6.383],[29.656,-2.335],[30.359,-0.686],[0,0],[-0.836,-30.825],[-0.957,-28.045]],"v":[[222.167,-4.845],[223.298,-78.6],[226.498,-162.127],[94.978,-160.046],[-37.237,-162.696],[-97.546,-166.469],[-124.274,-153.075],[-157.276,-63.847],[-177.21,6.098],[-193.868,90.998],[-202.675,152.291],[-127.506,145.418],[-33.988,142.487],[94.222,144.158],[223.839,145.66],[223.019,69.722]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.313},"t":23.264,"s":[{"i":[[0,0],[-0.844,34.399],[-0.211,18.065],[0,0],[27.824,0.791],[14.362,-0.625],[15.058,-10.578],[10.779,-42.125],[0,0],[9.102,-58.763],[0,0],[0,0],[-19.508,0.312],[0,0],[-31.355,2.08],[1.089,22.919]],"o":[[0,0],[0.918,-34.574],[-29.884,4.491],[0,0],[-34.014,-2.067],[-14.362,0.625],[-12.035,30.877],[-9.574,38.606],[0,0],[-10.029,64.745],[36.146,-4.414],[32.328,-1.848],[30.177,-0.747],[0,0],[4.724,-27.93],[-1.286,-29.657]],"v":[[213.83,-3.288],[214.669,-80.113],[215.739,-173.388],[98.558,-162.915],[-27.286,-162.414],[-100.476,-165.306],[-144.419,-153.346],[-168.117,-63.844],[-182.475,4.93],[-194.584,86.663],[-200.818,155.804],[-122.489,151.005],[-25.172,148.828],[97.825,152.621],[207.075,153.142],[215.086,74.536]],"c":true}]},{"i":{"x":0.833,"y":0.687},"o":{"x":0.167,"y":0.167},"t":26.461,"s":[{"i":[[0,0],[0.221,34.415],[2.267,20.755],[0,0],[34.02,-0.401],[0,0],[40.241,0.246],[-0.818,-35.107],[0,0],[0,0],[0,0],[0,0],[-18.847,0.083],[0,0],[-27.044,7.616],[2.458,38.116]],"o":[[0,0],[-0.183,-28.393],[-23.678,14.768],[0,0],[-39.471,-0.152],[0,0],[0.326,22.698],[0.825,35.387],[0,0],[0,0],[37.911,1.053],[39.747,-0.496],[29.671,-0.915],[0,0],[20.162,-19.893],[-2.201,-34.131]],"v":[[190.684,1.034],[190.712,-84.314],[185.869,-204.652],[108.499,-170.879],[0.342,-161.629],[-108.611,-162.078],[-197.867,-162.526],[-198.219,-63.835],[-197.093,1.688],[-196.572,74.627],[-195.662,165.558],[-108.562,166.515],[-0.695,166.435],[107.828,176.117],[160.531,173.913],[193.061,87.903]],"c":true}]},{"t":29,"s":[{"i":[[0,0],[0.221,34.415],[-0.714,25.694],[0,0],[29.147,-1.76],[0,0],[40.241,0.246],[-0.818,-35.107],[0,0],[0,0],[0,0],[0,0],[-10.812,-1.166],[0,0],[-33.147,-8.168],[-3.38,33.394]],"o":[[0,0],[-0.183,-28.393],[-23.964,8.187],[0,0],[-22.263,0.279],[0,0],[0.326,22.698],[0.825,35.387],[0,0],[0,0],[38.489,-1.765],[7.106,0.282],[26.205,2.91],[0,0],[-0.939,-39.426],[3.197,-31.583]],"v":[[156.12,-2.695],[163.02,-77.776],[162.175,-187.682],[114.496,-171.028],[72.24,-163.313],[49.645,-162.741],[-112.195,-162.534],[-111.338,-62.397],[-110.49,0.547],[-110.109,81.893],[-109.053,164.435],[49.694,165.852],[75.252,167.799],[116.581,174.875],[136.315,184.761],[149.045,75.672]],"c":true}]}]},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":0,"k":[0.345098048449,0.349019616842,0.35686275363,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":4},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"tr","p":{"a":0,"k":[256.461,255.128]},"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":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[2.05,-1.574],[-1.433,-1.533],[-0.704,-1.751],[1.674,4.991],[-1.568,-1.966],[2.648,2.859],[-8.41,-1.849],[-5.039,0.366],[-1.075,3.83],[-0.133,3.164],[3.148,6.115],[-8.027,-1.238],[-2.171,3.226],[0.308,2.133],[1.847,-1.293],[10.924,1.34],[3.332,-0.008],[3.061,-1.372],[2.871,-4.777],[3.84,-2.456]],"o":[[-2.038,1.843],[1.127,1.514],[1.18,2.921],[4.165,-0.991],[2.952,3.46],[-1.956,-3.153],[2.218,4.014],[0.201,4.536],[1.331,-3.055],[0.347,-4.901],[8.023,-0.233],[4.5,-1.281],[1.401,-1.368],[-0.289,-1.999],[-6.087,4.262],[-2.543,2.156],[2.508,1.001],[-6.14,3.028],[-5.133,-0.146],[-3.027,0.054]],"v":[[-31.634,6.994],[-29.986,11.85],[-28.609,17.286],[-23.946,17.384],[-20.61,23.185],[-17.662,19.357],[-18.443,6.45],[-7.98,12.505],[-0.3,12.477],[-0.155,2.908],[4.782,-7.969],[27.428,-10.046],[30.166,-18.213],[32.399,-23.487],[27.32,-22.659],[3.956,-19.965],[-5.383,-17.699],[-8.3,-10.964],[-16.028,-3.511],[-28.335,1.479]],"c":true}},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.96862745285,0.827450990677,0.29411765933,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[326.682,216.354]},"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,0],[-1.514,-1.116],[-5.161,-1.262],[-0.823,-1.053],[-1.305,-1.015],[2.848,-0.296],[-0.479,7.528],[-9.626,-6.699],[-4.081,1.053],[-2.269,-1.21],[0,0],[-2.152,-2.629],[-4.618,-6.101],[6.911,3.139],[3.949,1.086],[-1.481,2.605],[0.635,-6.516],[-0.395,5.518],[1.58,-0.457],[14.255,3.497]],"o":[[2.656,-1.185],[1.514,1.116],[5.161,1.262],[0.823,1.053],[1.305,1.015],[-6.173,1.975],[10.668,-3.689],[-5.776,2.713],[4.081,-1.053],[2.268,1.21],[0,0],[8.714,9.49],[0.988,2.192],[-6.911,-3.139],[-3.949,-1.086],[1.481,-2.605],[-0.635,6.516],[0.395,-5.518],[-1.58,0.457],[0.098,-2.306]],"v":[[-40.238,-10.544],[-33.37,-11.923],[-19.056,-13.651],[-9.149,-11.531],[-7.953,-7.017],[-10.678,-2.711],[-5.525,-5.859],[16.505,-5.161],[15.204,1.633],[20.36,-3.133],[25.077,-0.605],[37.734,0.386],[35.542,11.88],[21.325,11.88],[10.564,6.767],[9.182,-1.587],[2.906,4.298],[-14.941,-0.748],[-16.389,-8.17],[-40.44,-5.796]],"c":true}},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":1,"k":[{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.642],"y":[0]},"t":0,"s":[0.654901981354,0.647058844566,0.690196096897,1]},{"t":12,"s":[0.988235354424,0.988235354424,0.988235354424,1]}]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[402.84,152.399]},"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 10","bm":0,"hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[0,0],[-0.954,-1.761],[0.419,-0.995],[3.455,-1.376],[2.721,-1.237]],"o":[[-0.02,0.348],[1.185,0.931],[-2.986,-2.559],[-5.635,2.061],[0,0]],"v":[[-8.401,-2.197],[7.177,-3.585],[8.534,2.126],[1.994,1.153],[-8.669,4.083]],"c":true}},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":1,"k":[{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.642],"y":[0]},"t":0,"s":[0.654901981354,0.647058844566,0.690196096897,1]},{"t":12,"s":[0.988235354424,0.988235354424,0.988235354424,1]}]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[371.426,134.126]},"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 11","bm":0,"hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[0,0],[-1.862,-1.142]],"o":[[-4.122,2.292],[0,0]],"v":[[1.198,-2.374],[0.996,2.374]],"c":true}},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.988235294819,0.988235294819,0.988235294819,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[361.404,144.229]},"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 12","bm":0,"hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[0,0],[0,0],[5.272,-5.851],[-2.929,-0.798],[-1.082,-1.21]],"o":[[0,0],[-3.131,-0.506],[1.442,0.026],[2.929,0.798],[1.082,1.21]],"v":[[5.672,2.931],[5.939,-3.35],[-5.939,2.931],[0.669,0.974],[2.121,2.931]],"c":true}},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.988235294819,0.988235294819,0.988235294819,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[357.086,135.279]},"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 13","bm":0,"hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[7.898,2.269],[7.507,-3.609],[3.225,-6.103],[0,0],[-2.615,0.717],[-0.62,-1.617],[2.236,1.426],[0.59,4.075],[-13.62,-2.162],[-6.859,5.38],[0,0]],"o":[[-7.898,-2.269],[-7.507,3.609],[-2.426,4.592],[1.378,0.464],[0.561,0.768],[2.471,1.442],[2.222,-1.467],[9.093,-6.558],[8.293,0.663],[6.859,-5.38],[0,0]],"v":[[12.469,-9.085],[-6.68,-10.027],[-27.022,3.108],[-32.287,10.168],[-26.045,9.645],[-20.248,11.636],[-19.013,7.069],[-12.368,3.687],[10.1,-2.342],[25.428,-3.22],[32.287,-8.6]],"c":true}},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.933333337307,0.717647075653,0.007843137719,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[316.326,201.52]},"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 21","bm":0,"hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[-5.25,-6.727],[3.307,5.43],[0,0],[-6.947,-2.087],[-5.035,3.653],[0.494,-3.653]],"o":[[0,-3.952],[-10.218,0.296],[0.524,4.7],[4.016,-0.198],[5.035,-3.653],[-2.16,8.94]],"v":[[20.518,-1.38],[4.692,-12.934],[-19.963,-7.603],[-16.255,12.934],[-3.946,1.777],[6.914,-1.481]],"c":true}},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":1,"k":[{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.642],"y":[0]},"t":0,"s":[0.321568638086,0.407843142748,0,1]},{"t":12,"s":[0.600000023842,0.623529434204,0,1]}]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[381.118,183.453]},"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 22","bm":0,"hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[0,0],[-0.522,3.455],[0.395,-2.896],[-4.323,12.637],[2.106,1.731],[2.348,7.635],[4.739,-0.263],[8.824,-0.403]],"o":[[1.773,-2.421],[0.522,-3.455],[-0.395,2.896],[4.323,-12.637],[-2.106,-1.731],[-2.348,-7.635],[-4.739,0.263],[-0.208,4.879]],"v":[[-12.172,20.556],[-8.354,11.618],[-6.516,14.185],[10.75,-1.743],[6.253,-4.224],[10.971,-18.855],[-5.331,-5.692],[-10.724,-13.466]],"c":true}},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[0.686274528503,0.627451002598,0.29411765933,1]},{"t":12,"s":[0.92156869173,0.890196144581,0.564705908298,1]}]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[371.379,201.057]},"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 23","bm":0,"hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[0,0],[-1.525,-2.804],[-8.376,2.023],[-6.713,0.667],[-9.011,0.546],[0,0],[0,0],[20.412,3.194],[9.865,-3.592]],"o":[[3.57,2.343],[1.533,2.819],[8.376,-2.023],[6.713,-0.667],[9.011,-0.546],[0,0],[-35.858,-7.961],[-9.339,-2.996],[-9.865,3.592]],"v":[[-44.312,12.922],[-33.107,18.194],[-21.606,12.022],[1.777,1.189],[17.645,4.227],[43.696,-4.923],[44.312,-16.705],[-7.5,-10.928],[-25.875,-1.491]],"c":true}},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.600000023842,0.623529434204,0,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[316.96,192.514]},"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 24","bm":0,"hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[0,0],[0,0],[7.352,-0.59],[1.58,-2.127],[2.48,-2.398],[-5.825,-11.123],[0.671,2.954],[5.035,9.28],[-1.505,-3.357],[-6.022,-0.099],[2.073,-3.455],[1.556,-1.382],[4.45,-0.891],[-1.667,1.583],[0.672,8.197],[-27.616,-9.52]],"o":[[0,0],[0,0],[-13.191,1.058],[-1.58,2.127],[-1.68,1.624],[-0.899,-0.925],[0,0],[-0.691,-1.382],[1.504,3.357],[2.468,-0.296],[-2.073,3.455],[-5.668,4.586],[-1.332,0.279],[11.415,-12.743],[14.074,-13.967],[5.806,-5.978]],"v":[[38.308,-30.784],[36.86,3.238],[30.795,7.952],[13.063,1.014],[23.383,13.714],[11.187,23.194],[4.468,15.064],[-15.502,6.937],[-16.316,9.899],[-7.604,16.119],[-5.63,23.03],[-16.316,30.237],[-30.756,9.95],[-30.262,6.937],[-38.308,-7.576],[17.426,-24.459]],"c":true}},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.921568632126,0.890196084976,0.564705908298,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[322.347,218.375]},"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 26","bm":0,"hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[-3.981,2.299],[-6.055,-5.927],[-3.274,6.377],[-0.095,-6.412],[3.546,2.288]],"o":[[6.202,-3.335],[-2.238,-8.29],[3.274,-6.377],[0.095,6.412],[3.359,6.219]],"v":[[-5.988,8.812],[12.474,10.459],[8.541,-3.697],[0.268,-7.007],[-12.474,-2.075]],"c":true}},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.996078431606,0.541176497936,0.003921568859,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[392.802,309.826]},"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 30","bm":0,"hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[1.78,3.482],[-1.759,-0.586],[-4.805,2.238],[-4.939,-1.223],[4.147,-4.147]],"o":[[-2.537,-4.962],[2.369,0.79],[4.805,-2.238],[4.939,1.222],[-4.147,4.147]],"v":[[-9.478,4.351],[-9.132,-2.827],[-1.629,0.245],[6.464,-7.691],[8.441,5.412]],"c":true}},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.06274510175,0.568627476692,0,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[276.914,269.902]},"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 33","bm":0,"hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[6.73,3.106],[-2.304,-4.476],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[-5.767,-1.966]],"v":[[-5.841,-2.96],[-6.054,2.96],[7,2.833],[7.026,-1.7]],"c":true}},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":1,"k":[{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.642],"y":[0]},"t":0,"s":[0,0.368627458811,0,1]},{"t":12,"s":[0.231372565031,0.65098041296,0,1]}]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[249,252.888]},"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 35","bm":0,"hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[0,0],[-2.424,-7.954],[8.401,4.999],[2.663,1.449],[15.023,-5.152],[0,0]],"o":[[2.314,7.727],[-2.961,5.787],[-2.042,-2.54],[-7.969,-4.858],[0,0],[0,0]],"v":[[20.915,-14.844],[13.177,-1.582],[-3.457,13.819],[-8.07,5.89],[-21.203,-9.431],[-21.203,-14.795]],"c":true}},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.23137255013,0.65098041296,0,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[277.203,270.516]},"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 36","bm":0,"hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[0,0],[0,0],[-8.222,3.387],[-5.265,-2.691],[-6.471,-13.627]],"o":[[0,0],[6.086,1.005],[4.862,1.613],[13.498,11.426],[0,0]],"v":[[-21.057,2.751],[-21.031,-1.782],[-8.661,0.908],[1.553,-2.154],[21.057,2.698]],"c":true}},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":1,"k":[{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.642],"y":[0]},"t":0,"s":[0.090196080506,0.600000023842,0.023529412225,1]},{"t":12,"s":[0.231372565031,0.65098041296,0,1]}]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[277.057,252.969]},"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 37","bm":0,"hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[-2.172,-0.134],[0,0],[0,0]],"o":[[1.728,0.106],[0,0],[0,0]],"v":[[-0.035,2.145],[1.512,-2.112],[-1.352,-2.147]],"c":true}},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":1,"k":[{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.642],"y":[0]},"t":0,"s":[0.011764706112,0.40000000596,0.035294119269,1]},{"t":12,"s":[0.427451014519,0.560784339905,0,1]}]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[385.302,258.181]},"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 60","bm":0,"hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[2.172,-0.395],[-0.099,-2.352],[0,0]],"o":[[-1.374,0.25],[1.088,0.013],[0,0]],"v":[[-1.816,-6.488],[-0.632,6.463],[2.232,6.497]],"c":true}},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":1,"k":[{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.642],"y":[0]},"t":0,"s":[0.06274510175,0.290196090937,0,1]},{"t":12,"s":[0.427451014519,0.560784339905,0,1]}]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[384.582,249.572]},"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 61","bm":0,"hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[-0.32,-2.304],[0,0],[0,0]],"o":[[0.374,2.692],[0,0],[0,0]],"v":[[-2.745,-1.655],[2.508,3.081],[2.758,-2.78]],"c":true}},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.988235294819,0.988235294819,0.988235294819,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[360.904,119.75]},"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 62","bm":0,"hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[0,0],[4.694,3.241]],"o":[[17.113,9.79],[0,0]],"v":[[-4.421,1.084],[-4.172,-4.777]],"c":true}},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":1,"k":[{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.642],"y":[0]},"t":0,"s":[0.631372570992,0.658823549747,0.690196096897,1]},{"t":12,"s":[0.988235354424,0.988235354424,0.988235354424,1]}]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[367.833,121.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 63","bm":0,"hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[-1.975,-1.777],[0.987,3.061],[2.962,0],[-1.678,-1.876],[-0.79,-1.283],[1.59,4.295],[-3.455,-0.79],[-1.58,-1.876]],"o":[[2.202,1.981],[-0.987,-3.061],[-2.962,0],[1.678,1.876],[0.79,1.283],[-1.59,-4.295],[3.455,0.79],[1.58,1.876]],"v":[[1.677,7.532],[5.132,1.214],[1.677,-7.968],[-0.693,-2.143],[3.552,0.424],[-2.954,-0.218],[-3.655,5.558],[1.38,4.472]],"c":true}},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":1,"k":[{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.642],"y":[0]},"t":0,"s":[0.06274510175,0.290196090937,0,1]},{"t":12,"s":[0.427451014519,0.560784339905,0,1]}]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[249.881,185.102]},"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 64","bm":0,"hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[0,0],[0.263,8.425],[-3.159,-0.658],[0.79,2.238],[-2.099,2.351]],"o":[[-2.109,5.53],[-0.263,-8.425],[3.159,0.658],[-0.79,-2.238],[-0.027,4.474]],"v":[[5.755,6.366],[-5.832,5.183],[-1.225,-1.531],[1.671,-6.928],[5.859,-11.009]],"c":true}},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":1,"k":[{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.642],"y":[0]},"t":0,"s":[0.06274510175,0.290196090937,0,1]},{"t":12,"s":[0.427451014519,0.560784339905,0,1]}]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[250.512,204.926]},"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 65","bm":0,"hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[3.455,4.858],[-0.691,-0.494]],"o":[[-1.386,-1.948],[0.691,0.494]],"v":[[3.474,-6.177],[-4.128,6.341]],"c":true}},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.23137255013,0.552941203117,0.396078437567,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[438.924,330.731]},"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 68","bm":0,"hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[1.58,-1.975],[-2.764,1.678]],"o":[[-1.58,1.975],[2.764,-1.678]],"v":[[-1.848,-1.34],[1.508,1.425]],"c":true}},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.23137255013,0.552941203117,0.396078437567,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[413.344,331.303]},"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 69","bm":0,"hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[0.856,-2.238],[-1.119,1.843]],"o":[[-0.918,2.401],[1.119,-1.843]],"v":[[-1.079,-0.702],[1.027,0.746]],"c":true}},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.011764706112,0.40000000596,0.035294119269,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[383.45,272.088]},"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 70","bm":0,"hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[3.093,-2.541],[-2.567,-4.015],[-2.764,2.962]],"o":[[-1.623,1.333],[2.567,4.015],[2.764,-2.962]],"v":[[-8.046,-5.716],[0.444,2.288],[7.947,4.46]],"c":true}},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":1,"k":[{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.642],"y":[0]},"t":0,"s":[0.011764706112,0.40000000596,0.035294119269,1]},{"t":12,"s":[0.427451014519,0.560784339905,0,1]}]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[401.343,275.548]},"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 71","bm":0,"hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[2.633,-1.975],[-2.435,0.395],[2.106,0.79]],"o":[[-2.567,1.925],[2.435,-0.395],[-2.106,-0.79]],"v":[[-3.877,1.465],[2.31,6.072],[3.165,-6.039]],"c":true}},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":1,"k":[{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.642],"y":[0]},"t":0,"s":[0.011764706112,0.40000000596,0.035294119269,1]},{"t":12,"s":[0.427451014519,0.560784339905,0,1]}]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[375.849,266.432]},"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 72","bm":0,"hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[5.499,-12.561],[-5.829,2.403],[1.678,5.858]],"o":[[0.449,5.661],[0.46,-1.185],[-2.784,-11.416]],"v":[[-8.074,-4.352],[8.052,10.522],[-0.011,2.098]],"c":true}},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[0.011764707044,0.400000035763,0.035294119269,1]},{"t":12,"s":[0.427451014519,0.560784339905,0,1]}]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[367.212,269.88]},"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 73","bm":0,"hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[0.296,-2.567],[0.148,1.975]],"o":[[-0.317,2.748],[-0.148,-1.975]],"v":[[-1.299,-0.591],[1.317,0.643]],"c":true}},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.06274510175,0.290196090937,0,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[407.069,202.802]},"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 74","bm":0,"hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[0,0],[1.53,8.545],[0.395,-3.357]],"o":[[-6.049,6.83],[0.199,-5.577],[-0.395,3.357]],"v":[[-5.767,4.368],[6.819,-4.321],[2.23,-2.642]],"c":true}},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":1,"k":[{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.642],"y":[0]},"t":0,"s":[0.06274510175,0.290196090937,0,1]},{"t":12,"s":[0.427451014519,0.560784339905,0,1]}]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[399.294,214.527]},"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 75","bm":0,"hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[1.382,-2.369],[-1.283,1.382]],"o":[[-1.244,2.132],[1.283,-1.382]],"v":[[-2.721,-1.177],[2.709,1.489]],"c":true}},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":1,"k":[{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.642],"y":[0]},"t":0,"s":[0.631372570992,0.658823549747,0.690196096897,1]},{"t":12,"s":[0.988235354424,0.988235354424,0.988235354424,1]}]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[408.59,136.253]},"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 76","bm":0,"hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[-6.22,-3.258],[-5.924,4.048],[1.93,3.452]],"o":[[2.95,1.545],[5.924,-4.048],[-3.258,-5.826]],"v":[[-9.093,7.73],[-0.899,-0.661],[9.863,-6.781]],"c":true}},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.988235294819,0.988235294819,0.988235294819,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[322.355,140.476]},"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 77","bm":0,"hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[-1.119,-2.106],[-0.877,6.377]],"o":[[1.833,7.256],[-0.198,-2.896]],"v":[[-3.668,-0.753],[3.771,-2.333]],"c":true}},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.988235294819,0.988235294819,0.988235294819,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[273.424,129.84]},"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 78","bm":0,"hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[1.58,-3.423],[0,-3.817],[-11.049,-14.932],[8.398,9.818],[1.316,0.527],[2.764,0.132],[1.773,0.921],[3.159,-3.872]],"o":[[-1.58,3.423],[0.479,10.181],[7.145,13.264],[-6.45,-8.952],[-1.316,-0.527],[-2.764,-0.132],[-1.773,-0.921],[-3.159,3.872]],"v":[[-20.481,-1.687],[-16.701,12.992],[7.783,15.491],[17.788,-2.409],[8.573,-17.416],[3.966,-13.072],[0.21,-19.653],[-13.937,-6.807]],"c":true}},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.949019610882,0.643137276173,0.015686275437,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[397.493,304.795]},"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 81","bm":0,"hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[-7.941,2.589],[-1.975,7.372],[-3.159,2.106],[-2.376,7.644],[2.79,12.894],[-0.263,4.739],[-1.316,-0.527],[-3.554,4.081],[4.218,-1.871],[-2.501,0],[-3.159,3.554],[-1.316,4.739],[8.443,7.533],[0,0],[1.448,0],[2.764,1.053],[1.185,0.658],[2.369,1.711],[2.764,0.395],[0,0],[0,0],[-5.726,-0.987]],"o":[[5.778,-2.196],[1.975,-7.372],[6.878,-5.306],[1.61,-9.932],[-1.052,-4.475],[0.263,-4.739],[1.316,0.527],[11.138,-2.409],[-3.159,2.37],[2.501,0],[3.159,-3.554],[15.488,-1.161],[-3.555,-1.184],[0,0],[-1.448,0],[-2.764,-1.053],[-1.185,-0.658],[-2.369,-1.711],[-2.764,-0.395],[0,0],[0,0],[14.013,0.324]],"v":[[-34.96,46.444],[-18.242,37.493],[-21.402,16.958],[-9.949,18.933],[5.056,-3.841],[-0.735,-10.028],[8.348,-17.663],[19.537,-19.769],[17.957,-12.661],[20.195,1.03],[26.777,-8.975],[27.699,-17.663],[40.205,-37.803],[25.592,-39.251],[7.163,-48.465],[-6.132,-44.648],[-9.16,-50.44],[-21.138,-52.678],[-24.693,-60.444],[-39.3,-59.115],[-44.166,55.189],[-35.553,60.497]],"c":true}},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":1,"k":[{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.642],"y":[0]},"t":0,"s":[0.06274510175,0.290196090937,0,1]},{"t":12,"s":[0.427451014519,0.560784339905,0,1]}]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[402.325,191.045]},"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 82","bm":0,"hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[14.446,-3.4],[2.468,3.159],[-5.295,-2.567],[0.027,4.542],[2.863,-1.327],[0,0],[0,0],[-1.481,2.172],[-5.529,0.197],[-4.64,2.172],[4.542,0.197],[2.238,3.511],[0.395,-2.369],[1.086,-1.58],[0.197,2.567],[0.79,3.85],[-0.79,5.337],[-5.331,-2.567],[-0.197,-1.975],[-0.099,-2.666],[-2.567,0.691],[-15.604,0.613],[-0.79,0.987],[0.79,-6.022],[0,5.331],[-2.369,1.185],[-4.762,-1.731],[0,0],[7.446,-14.282],[-0.527,-2.51],[0,0],[2.336,2.404]],"o":[[-0.592,-2.962],[-2.468,-3.159],[-0.826,3.554],[-0.027,-4.541],[-2.863,1.327],[0,0],[0,0],[1.481,-2.172],[5.529,-0.197],[4.64,-2.172],[-10.373,-0.167],[-1.58,-1.777],[-0.395,2.369],[-1.086,1.58],[-0.197,-2.567],[-0.79,-3.85],[0.79,-5.337],[5.331,2.567],[0.197,1.975],[0.099,2.666],[11.337,-12.438],[2.961,-0.692],[0.79,-0.987],[-0.79,6.022],[0,-5.331],[3.043,-1.944],[0,0],[-10.657,-10.93],[-3.061,3.258],[0,0],[0,0],[-18.166,-29.064]],"v":[[-25.607,17.064],[-38.343,10.548],[-33.765,17.854],[-39.034,19.829],[-48.018,9.814],[-53.379,17.557],[-53.275,0.181],[-44.76,-9.79],[-37.356,-6.433],[-30.05,-14.627],[-26.594,-18.971],[-27.088,-30.917],[-35.184,-22.723],[-36.566,-12.85],[-41.996,-16.207],[-48.512,-19.366],[-38.54,-32.984],[-23.731,-42.369],[-11.686,-37.137],[-16.919,-31.608],[-12.18,-27.758],[16.945,-39.11],[21.683,-46.22],[24.645,-40.987],[28.101,-43.159],[35.407,-50.268],[53.379,-61.806],[48.513,52.498],[36.263,51.361],[29.187,61.985],[25.145,61.985],[23.888,47.834]],"c":true}},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.427450984716,0.560784339905,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},{"ty":"tr","p":{"a":0,"k":[309.646,193.736]},"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 83","bm":0,"hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[2.929,-0.016],[-5.451,3.173],[0,0],[0,0],[0,0],[-9.451,4.049],[-2.666,2.626]],"o":[[-2.907,-0.479],[4.049,-0.296],[0,0],[0,0],[13.314,-5.212],[2.37,-0.692],[1.529,-1.143]],"v":[[9.395,-8.056],[22.18,16.378],[26.196,19.275],[-26.196,19.34],[-25.97,-18.242],[-4.772,-12.252],[9.731,-10.912]],"c":true}},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.921568632126,0.890196084976,0.564705908298,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[282.196,236.38]},"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 84","bm":0,"hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[1.929,-2.319],[0.987,-2.962],[-3.061,-0.099],[-1.777,4.64]],"o":[[-3.068,3.689],[-0.987,2.962],[3.061,0.099],[1.777,-4.64]],"v":[[1.603,-9.095],[-3.333,-2.579],[-1.26,9.762],[3.084,-2.677]],"c":true}},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.980392158031,0.713725507259,0.286274522543,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[306.031,297.988]},"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 85","bm":0,"hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[-0.132,-12.129],[-1.185,-6.45],[-3.291,-2.106],[-4.4,5.334],[1.843,10.926],[-0.263,8.03],[0,0],[0,0],[0.421,-5.047]],"o":[[-1.928,4.381],[1.185,6.45],[13.498,6.659],[1.316,-0.921],[5.002,-8.951],[-2.896,0],[0,0],[5.002,-2.271],[-0.79,9.478]],"v":[[-11.321,-1.873],[-9.609,17.477],[-6.713,31.299],[12.637,7.473],[15.401,-12.141],[26.196,-32.413],[-26.196,-32.347],[-26.196,-26.983],[-16.849,-23.593]],"c":true}},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.980392158031,0.713725507259,0.286274522543,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[282.196,288.068]},"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 86","bm":0,"hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[0,0],[2.716,4.902],[0.012,-0.046]],"o":[[-5.265,2.633],[1.585,0.006],[0,0]],"v":[[6.527,2.195],[-6.527,-3.042],[6.527,-3.17]],"c":true}},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":1,"k":[{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.642],"y":[0]},"t":0,"s":[0.06274510175,0.415686279535,0.015686275437,1]},{"t":12,"s":[0.231372565031,0.65098041296,0,1]}]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[249.473,258.89]},"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 87","bm":0,"hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[0,0],[1.975,-7.767],[-10.531,-16.586],[0,0]],"o":[[-5.886,1.448],[-6.582,4.871],[2.762,0.167],[0,0]],"v":[[9.298,-18.806],[-0.405,-10.513],[-4.091,18.71],[9.073,18.776]],"c":true}},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":1,"k":[{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.642],"y":[0]},"t":0,"s":[0.686274528503,0.631372570992,0.454901963472,1]},{"t":12,"s":[0.92156869173,0.890196144581,0.564705908298,1]}]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[246.927,236.945]},"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 88","bm":0,"hd":false},{"ty":"tr","p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":19,"s":[348.256,224.52],"to":[1.873,-0.192],"ti":[-1.873,0.192]},{"t":26.4609375,"s":[359.494,223.37]}]},"a":{"a":0,"k":[348.256,224.52]},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":0,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":19,"s":[109,100]},{"t":26.4609375,"s":[107.45,116.911]}]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"евразия и африка","bm":0,"hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[-8.688,17.032],[-2.801,3.159],[-12.637,-0.059],[4.047,-5.902]],"o":[[1.33,-0.921],[3.488,5.27],[-9.45,7.072],[0,0]],"v":[[-4.316,-17.032],[0.65,-20.455],[9.769,-6.633],[-8.707,20.455]],"c":true}},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.517647087574,0.639215707779,0,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[194.498,320.076]},"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 47","bm":0,"hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[-4.081,2.896],[3.096,1.43],[1.777,-2.369],[4.739,-0.064],[4.677,20.506],[2.569,10.439],[-9.238,-7.249],[6.224,-9.205],[-0.397,-0.794],[-1.58,0.922],[0.263,3.423],[-3.336,8.437],[0,0],[-6.977,3.159]],"o":[[-3.643,-3.517],[-0.226,3.418],[-1.777,2.37],[-6.496,0.686],[-4.047,-3.455],[-0.168,5.656],[-0.948,12.594],[-0.872,5.23],[1.316,2.633],[1.58,-0.922],[-0.124,-1.611],[3.336,-8.437],[0,0],[2.106,-11.716]],"v":[[25.516,-35.033],[15.022,-42.081],[10.115,-36.613],[8.14,-25.886],[-10.915,-19.139],[-25.504,-38.195],[-14.962,-17.46],[-20.657,25.256],[-21.61,34.997],[-14.238,41.974],[-14.238,32.891],[-4.694,15.021],[7.613,-0.413],[14.722,-12.524]],"c":true}},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.901960790157,0.615686297417,0,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[196.654,313.856]},"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 48","bm":0,"hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[2.959,3.061],[-6.291,-0.061],[0.143,-3.061],[4.174,0]],"o":[[-7.366,-10.676],[2.561,-0.065],[-0.428,3.061],[-4.174,0]],"v":[[-10.949,6.118],[3.713,-6.811],[12.869,2.009],[0.677,1.121]],"c":true}},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.999]},"o":{"x":[0.642],"y":[0]},"t":0,"s":[0.007843137719,0.321568638086,0.027450980619,1]},{"t":12,"s":[0.06274510175,0.568627476692,0,1]}]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[187.71,265.475]},"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 52","bm":0,"hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[0.658,-2.501],[-1.185,1.777]],"o":[[-0.727,2.761],[1.185,-1.777]],"v":[[-1.7,-0.896],[1.591,1.013]],"c":true}},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.843137264252,0.584313750267,0.003921568859,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[193.33,349.947]},"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 67","bm":0,"hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[22.564,0.641],[-21.239,-18.329],[-1.316,-2.633],[2.603,12.357],[-11.189,4.114],[-6.977,3.159],[-4.081,2.896],[1.448,1.711]],"o":[[1.689,10.748],[-0.394,15.533],[5.521,8.855],[-0.263,-3.422],[0.033,-4.114],[2.106,-11.716],[-7.635,-7.372],[-14.765,-17.42]],"v":[[-21.708,-49.24],[-14.206,-10.012],[-21.577,42.906],[-14.206,40.799],[6.495,7.43],[14.755,-4.615],[25.549,-27.125],[8.305,-37.392]],"c":true}},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":1,"k":[{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.642],"y":[0]},"t":0,"s":[0.011764706112,0.40000000596,0.035294119269,1]},{"t":12,"s":[0.376470625401,0.529411792755,0.023529414088,1]}]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[196.621,305.948]},"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 93","bm":0,"hd":false},{"ty":"tr","p":{"a":1,"k":[{"i":{"x":0.534,"y":1},"o":{"x":0.388,"y":0},"t":0,"s":[196.58,303.352],"to":[0.416,-1.562],"ti":[-0.27,1.015]},{"t":19,"s":[198.599,304.762]}]},"a":{"a":0,"k":[196.58,303.352]},"s":{"a":0,"k":[100,100]},"r":{"a":1,"k":[{"i":{"x":[0.534],"y":[1]},"o":{"x":[0.388],"y":[0]},"t":0,"s":[0]},{"t":19,"s":[6.905]}]},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"южная америка","bm":0,"hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[3.949,-6.582],[-3.028,1.147],[2.324,-4.079],[8.189,-1.43],[-0.954,-6.095]],"o":[[0.719,-6.45],[7.635,-9.688],[-1.032,1.81],[-1.975,6.146],[-10.322,-11.624]],"v":[[-12.365,3.902],[-4.993,-8.262],[12.065,1.269],[-2.294,-8.262],[7.151,11.444]],"c":true}},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.827450990677,0.854901969433,0.92549020052,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[106.584,174.351]},"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 49","bm":0,"hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[3.817,-4.352],[-0.79,-2.975],[-3.159,-0.395],[-8.868,2.278]],"o":[[-3.441,3.348],[0.79,2.975],[3.159,0.395],[-10.895,-0.93]],"v":[[-10.723,-4.342],[-7.432,3.148],[0.861,6.123],[11.787,-2.96]],"c":true}},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.827450990677,0.854901969433,0.92549020052,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[94.938,156.992]},"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 50","bm":0,"hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[0,0],[-4.099,-3.668],[1.645,1.341],[0.114,3.071],[1.389,-6.155]],"o":[[3.161,4.35],[1.251,1.119],[-0.69,-0.562],[-0.051,-1.373],[0,0]],"v":[[-4.395,-11.496],[4.164,0.423],[-0.388,11.385],[0.412,4.405],[-3.642,8.849]],"c":true}},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.901960790157,0.615686297417,0,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[156.993,210.673]},"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 51","bm":0,"hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[-5.769,0.016],[-5.769,2.573],[0,0],[3.428,-4.51],[2.147,-0.96],[3.362,1.523],[1.911,-0.819],[-3.137,-8.441],[-8.389,-15.895],[-1.514,0.876]],"o":[[-4.156,-2.172],[0,0],[0,0],[-3.524,4.637],[-2.147,0.96],[-3.362,-1.523],[-3.554,1.522],[2.706,7.281],[3.474,3.292],[1.514,-0.876]],"v":[[14.891,28.109],[14.891,12.801],[13.925,-13.329],[-6.194,-27.404],[-1.112,-2.298],[-6.444,-11.677],[-11.676,-19.436],[-12.96,-0.521],[5.928,25.559],[4.712,17.697]],"c":true}},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.89411765337,0.713725507259,0.011764706112,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[138.673,212.506]},"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 53","bm":0,"hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[2.518,-2.024],[6.808,5.194]],"o":[[-4.699,6.451],[-2.576,-1.193]],"v":[[-3.812,-2.89],[3.059,0.524]],"c":true}},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":1,"k":[{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.642],"y":[0]},"t":0,"s":[0.631372570992,0.658823549747,0.690196096897,1]},{"t":12,"s":[0.964705944061,0.980392217636,0.98431378603,1]}]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[153.828,120.097]},"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 54","bm":0,"hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[2.304,2.238],[-5.397,-2.304],[0.066,2.172]],"o":[[-2.643,-2.567],[5.397,2.304],[-0.066,-2.172]],"v":[[0.637,-1.711],[-2.851,1.383],[4.981,0.329]],"c":true}},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.964705884457,0.980392158031,0.984313726425,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[142.814,125.269]},"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 55","bm":0,"hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[-1.382,-1.185],[1.185,1.185]],"o":[[1.873,1.606],[-1.185,-1.185]],"v":[[-0.93,0.6],[0.913,-0.782]],"c":true}},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.964705884457,0.980392158031,0.984313726425,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[131.086,127.302]},"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 56","bm":0,"hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[2.172,-2.567],[-1.711,-2.106],[-2.435,2.369],[1.251,1.316]],"o":[[-2.348,2.775],[1.711,2.106],[2.435,-2.369],[-1.251,-1.316]],"v":[[-8.392,-2.542],[-3.193,0.749],[8.589,2.592],[-1.152,-1.225]],"c":true}},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.964705884457,0.980392158031,0.984313726425,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[129.663,133.932]},"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 57","bm":0,"hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[0.921,-2.633],[-2.633,2.962],[-1.251,-3.554],[-4.871,2.238],[1.843,2.567],[2.699,-0.658],[2.238,2.501]],"o":[[-1.439,4.112],[2.633,-2.962],[1.251,3.554],[4.871,-2.238],[-1.843,-2.567],[-2.699,0.658],[-2.238,-2.501]],"v":[[-11.831,-5.93],[-7.751,0.981],[-2.09,0.981],[6.137,6.576],[11.6,2.232],[6.795,-5.93],[-3.143,-4.153]],"c":true}},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.964705884457,0.980392158031,0.984313726425,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[130.864,146.6]},"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 58","bm":0,"hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[6.12,-0.329],[-2.83,0.658]],"o":[[-4.393,0.236],[2.83,-0.658]],"v":[[-2.855,-3.569],[3.07,3.54]],"c":true}},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":1,"k":[{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.642],"y":[0]},"t":0,"s":[0.631372570992,0.658823549747,0.690196096897,1]},{"t":12,"s":[0.964705944061,0.980392217636,0.98431378603,1]}]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[180.07,163.656]},"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 59","bm":0,"hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[7.554,11.351],[4.739,-5.726],[-1.975,-5.529],[1.58,3.827]],"o":[[-10.281,-12.307],[-4.739,5.726],[1.975,5.529],[-3.405,-6.566]],"v":[[14.596,7.99],[-14.232,-9.189],[-9.691,3.251],[-4.952,-1.413]],"c":true}},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":1,"k":[{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.642],"y":[0]},"t":0,"s":[0.631372570992,0.658823549747,0.690196096897,1]},{"t":12,"s":[0.964705944061,0.980392217636,0.98431378603,1]}]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[172.69,150.781]},"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 79","bm":0,"hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[-3.291,-3.159],[-5.002,2.369],[-0.397,-8.132],[-2.764,-3.028]],"o":[[3.653,3.507],[5.002,-2.369],[0.137,2.811],[2.764,3.028]],"v":[[-11.371,9.584],[14.166,-7.133],[-14.662,-5.027],[-2.42,-2.395]],"c":true}},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":1,"k":[{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.642],"y":[0]},"t":0,"s":[0.631372570992,0.658823549747,0.690196096897,1]},{"t":12,"s":[0.964705944061,0.980392217636,0.98431378603,1]}]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[171.014,120.621]},"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 80","bm":0,"hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[0.099,-3.258],[-7.129,-20.154],[-3.357,-1.744],[-0.197,6.911],[-2.172,3.809],[-5.331,4.344],[0.79,1.382],[0.592,3.554],[5.44,-3.309],[5.934,-4.593]],"o":[[4.094,8.006],[0.001,-0.001],[3.357,1.744],[0.197,-6.911],[2.172,-3.809],[5.331,-4.344],[-0.79,-1.382],[-0.592,-3.554],[-11.847,7.207],[-11.354,8.787]],"v":[[-31.462,-13.979],[-8.361,8.401],[-5.2,28.935],[1.908,23.669],[22.246,11.353],[24.023,-13.979],[31.329,-22.074],[17.112,-22.074],[4.771,-28.985],[-15.468,-24.937]],"c":true}},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":1,"k":[{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.642],"y":[0]},"t":0,"s":[0.631372570992,0.658823549747,0.690196096897,1]},{"t":12,"s":[0.964705944061,0.980392217636,0.98431378603,1]}]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[208.678,140.367]},"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 89","bm":0,"hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[0,0],[0,0],[-2.421,0],[6.763,0.494],[2.32,0.346],[2.809,1.481]],"o":[[15.453,0.263],[0,0],[-3.11,-5.816],[-6.763,-0.494],[-2.32,-0.346],[0,0]],"v":[[-19.795,-1.168],[0.606,8.046],[20.089,7.661],[3.552,5.134],[-10.319,-7.256],[-20.089,-8.046]],"c":true}},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":1,"k":[{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.642],"y":[0]},"t":0,"s":[0.06274510175,0.290196090937,0,1]},{"t":12,"s":[0.376470625401,0.529411792755,0.023529414088,1]}]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[174.306,248.662]},"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 90","bm":0,"hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[0,0],[-3.088,0.643],[0,0],[5.66,0],[2.501,5.002],[10.136,-5.002],[4.849,-2.928],[9.675,-5.068],[-1.975,-3.423],[-2.238,5.397],[-6.921,-3.081],[-10.399,-9.873],[-10.915,-2.776]],"o":[[-5.731,-3.603],[0,0],[-1.436,1.31],[-5.66,0],[-2.501,-5.002],[-4.408,2.175],[-10.465,6.319],[-1.843,3.949],[1.975,3.423],[10.186,-15.888],[0.527,14.105],[13.284,11.4],[0,0]],"v":[[37.753,41.438],[37.1,26.13],[33.925,-48.316],[23.302,-44.092],[14.745,-41.196],[-9.739,-45.145],[-32.249,-46.528],[-37.778,-28.033],[-29.485,-20.793],[-22.245,-20.924],[5.794,-3.7],[15.798,22.647],[38.047,48.316]],"c":true}},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.376470595598,0.529411792755,0.023529412225,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[116.464,199.177]},"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 91","bm":0,"hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[-3.061,1.185],[-5.035,4.739],[-6.516,0.395],[1.975,1.777],[-5.43,-4.344],[6.22,6.615],[2.527,3.224],[-1.435,-11.32],[0.889,6.22],[-2.647,5.278],[1.817,3.18],[0.472,-9.437],[0,0],[-3.357,-0.889]],"o":[[2.369,-1.975],[5.035,-4.739],[6.516,-0.395],[-1.975,-1.777],[5.43,4.344],[-2.936,-3.123],[-5.234,-6.677],[1.231,9.704],[-0.889,-6.22],[1.356,-2.703],[-3.159,-5.529],[0,0],[0,0],[3.357,0.889]],"v":[[-3.484,41.3],[-0.522,28.861],[10.437,13.262],[12.115,3.389],[18.829,2.5],[18.039,-6.78],[6.896,-14.695],[-0.621,-10.828],[-6.445,-4.608],[-19.774,-20.602],[-12.106,-30.112],[-22.808,-37.891],[-19.632,36.555],[-8.223,35.475]],"c":true}},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":1,"k":[{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.642],"y":[0]},"t":0,"s":[0.06274510175,0.290196090937,0,1]},{"t":12,"s":[0.376470625401,0.529411792755,0.023529414088,1]}]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[173.196,188.751]},"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 92","bm":0,"hd":false},{"ty":"tr","p":{"a":1,"k":[{"i":{"x":0.534,"y":1},"o":{"x":0.388,"y":0},"t":0,"s":[159.534,184.577],"to":[1.771,-0.383],"ti":[-1.151,0.249]},{"t":19,"s":[182.056,182.031]}]},"a":{"a":0,"k":[159.659,184.606]},"s":{"a":1,"k":[{"i":{"x":[0.317,0.317],"y":[1,1]},"o":{"x":[0.642,0.642],"y":[0,0]},"t":0,"s":[100,100]},{"t":19,"s":[80,102]}]},"r":{"a":1,"k":[{"i":{"x":[0.534],"y":[1]},"o":{"x":[0.388],"y":[0]},"t":0,"s":[0]},{"t":19,"s":[8]}]},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"северная америка","bm":0,"hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0.534,"y":1},"o":{"x":0.388,"y":0},"t":0,"s":[{"i":[[0,0],[1.876,2.073],[-4.541,3.258],[8.885,-0.494],[13.266,5.335],[1.152,-3.836],[0,0],[-25.077,0.527]],"o":[[-8.326,-4.541],[-1.876,-2.073],[4.541,-3.258],[-11.381,-9.373],[-2.962,-1.084],[0,0],[0,0],[0,0]],"v":[[45.348,10.385],[25.373,6.345],[32.086,-7.477],[8.984,-16.559],[-30.408,-19.622],[-45.546,-16.644],[-43.952,20.349],[45.546,13.355]],"c":true}]},{"t":19,"s":[{"i":[[0,0],[1.656,2.303],[-7.606,3.106],[9.167,-0.494],[13.686,5.335],[1.188,-3.836],[0,0],[-25.871,0.527]],"o":[[-8.59,-4.541],[-4.153,-5.775],[5.283,-2.158],[-11.742,-9.373],[-3.056,-1.084],[0,0],[0,0],[0,0]],"v":[[45.313,-3.386],[28.475,-7.699],[31.131,-22.281],[9.811,-32.269],[-30.829,-35.331],[-52.746,-34.298],[-52.785,-2.432],[45.518,-0.417]],"c":true}]}]},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[0.850980460644,0.866666734219,0.862745165825,1]},{"t":12,"s":[0.988235354424,0.988235354424,0.988235354424,1]}]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[408.83,401.317]},"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.317,"y":1},"o":{"x":0.642,"y":0},"t":0,"s":[{"i":[[0,0],[6.319,-11.452],[3.554,3.949],[4.344,-3.159],[12.063,-3.74],[13.229,-0.658],[0,0],[-41.919,-2.52]],"o":[[0,0],[-6.911,-6.516],[-3.554,-3.949],[-13.172,11.799],[-3.356,2.305],[0,0],[27.959,2.418],[0,0]],"v":[[52.86,-16.091],[29.889,-8.404],[7.182,-18.079],[-1.111,-18.079],[-24.806,-12.355],[-54.424,-14.13],[-54.439,13.315],[54.439,20.753]],"c":true}]},{"t":19,"s":[{"i":[[0,0],[6.519,-11.452],[3.667,3.949],[4.482,-3.159],[12.445,-3.74],[13.649,-0.658],[0,0],[-43.247,-2.52]],"o":[[0,0],[-7.13,-6.516],[-3.667,-3.949],[-13.589,11.799],[-3.463,2.305],[0,0],[28.845,2.418],[0,0]],"v":[[45.661,-33.744],[27.628,-22.789],[11.99,-31.493],[3.434,-31.493],[-21.012,-25.769],[-50.114,-26.941],[-50.733,-3.809],[45.606,-2.027]],"c":true}]}]},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.988235294819,0.988235294819,0.988235294819,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[310.439,400.912]},"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.317,"y":1},"o":{"x":0.642,"y":0},"t":0,"s":[{"i":[[0,0],[16.784,1.185],[-7.758,17.361],[2.633,-3.423],[5.397,-0.395],[4.476,-2.106],[8.258,4.486],[0,0],[-37.522,1.208]],"o":[[-17.573,2.567],[-28.812,-1.477],[3.687,-3.158],[-2.633,3.423],[-5.397,0.395],[-4.476,2.106],[-0.269,5.911],[34.814,-3.812],[0,0]],"v":[[54.3,-11.956],[10.663,13.713],[-9.94,-21.04],[-17.837,-19.722],[-25.603,-10.113],[-29.684,-0.109],[-53.282,0.56],[-54.3,22.928],[54.3,15.49]],"c":true}]},{"t":19,"s":[{"i":[[0,0],[17.315,1.185],[-8.004,17.362],[2.716,-3.423],[5.568,-0.395],[4.617,-2.106],[8.52,4.486],[0,0],[-38.711,1.208]],"o":[[-18.13,2.567],[-29.725,-1.477],[3.804,-3.158],[-2.716,3.423],[-5.568,0.395],[-4.617,2.106],[-0.278,5.911],[35.917,-3.812],[0,0]],"v":[[58.61,-24.767],[15.059,-5.008],[-3.341,-40.069],[-11.488,-38.752],[-19.501,-29.142],[-23.711,-19.138],[-48.056,-18.469],[-49.698,0.224],[58.007,-1.634]],"c":true}]}]},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[0.850980460644,0.866666734219,0.862745165825,1]},{"t":12,"s":[0.988235354424,0.988235354424,0.988235354424,1]}]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[201.707,398.704]},"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.317,"y":1},"o":{"x":0.642,"y":0},"t":0,"s":[{"i":[[5.123,0.391],[0,0],[-9.781,0.938],[-7.342,-7.473],[-16.6,-8.231],[0,0]],"o":[[0,0],[0,0],[10.569,-5.776],[10.38,10.598],[0,0],[-47.078,-4.581]],"v":[[-43.612,5.673],[-43.465,3.513],[-21.295,3.32],[30.506,-2.752],[43.612,-10.377],[42.596,11.991]],"c":true}]},{"t":19,"s":[{"i":[[5.286,0.391],[0,0],[-10.091,0.938],[-7.563,-7.485],[-17.126,-8.231],[0,0]],"o":[[0,0],[0,0],[10.904,-5.776],[10.709,10.598],[0,0],[-49.506,2.57]],"v":[[-38.042,-2.106],[-37.891,-4.266],[-16.895,-13.499],[35.316,-21.781],[48.838,-29.406],[47.198,-10.713]],"c":true}]}]},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.964705884457,0.980392158031,0.984313726425,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[104.806,409.525]},"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":"tr","p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":19,"s":[196.621,305.948],"to":[0,1.833],"ti":[-7.833,-3.167]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":26.461,"s":[196.621,316.948],"to":[7.833,3.167],"ti":[-7.833,-1.333]},{"t":29,"s":[243.621,324.948]}]},"a":{"a":0,"k":[196.621,305.948]},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.967,1.033]},"o":{"x":[0.642,0.642],"y":[0,0]},"t":0,"s":[100,100]},{"i":{"x":[0.317,0.317],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[-0.019,-0.019]},"t":12,"s":[110,100]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.696,0.696],"y":[0,0]},"t":19,"s":[110,100]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":26.461,"s":[91,111]},{"t":29,"s":[52,101.982]}]},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":19,"s":[0]},{"t":26.4609375,"s":[2]}]},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"суша","bm":0,"hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0.317,"y":1},"o":{"x":0.642,"y":0},"t":0,"s":[{"i":[[0,0],[-38.701,1.053],[0,0],[0,0]],"o":[[0,0],[-5.529,-83.457],[0,0],[0,0]],"v":[[-41.202,82.898],[48.311,76.053],[34.094,-81.911],[-48.311,-82.898]],"c":true}]},{"t":19,"s":[{"i":[[0,0],[-39.927,1.053],[0,0],[0,0]],"o":[[0,0],[-3.367,-68.787],[0,0],[0,0]],"v":[[-33.889,60.295],[74.269,62.118],[77.672,-88.035],[-29.826,-87.939]],"c":true}]}]},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.207843139768,0.737254917622,0.956862747669,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[406.066,338.619]},"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.317,"y":1},"o":{"x":0.642,"y":0},"t":0,"s":[{"i":[[0,0],[0,0],[0,0],[-32.119,0.79]],"o":[[0,0],[0,0],[0,0],[-2.106,32.646]],"v":[[34.884,83.984],[-47.521,82.997],[-40.412,-83.984],[47.521,-78.192]],"c":true}]},{"t":19,"s":[{"i":[[0,0],[0,0],[0,0],[-33.686,-1.126]],"o":[[0,0],[0,0],[0,0],[-2.173,32.646]],"v":[[78.462,77.86],[-29.036,77.956],[-25.12,-78.46],[82.836,-76.771]],"c":true}]}]},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.180392161012,0.541176497936,0.694117665291,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[405.276,172.724]},"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.317,"y":1},"o":{"x":0.642,"y":0},"t":0,"s":[{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[35.508,-1.975],[0,0],[0,0],[0,0]],"v":[[-53.476,-75.987],[54.432,-83.49],[47.323,83.49],[-54.432,83.49]],"c":true}]},{"t":19,"s":[{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[36.265,-0.441],[0,0],[0,0],[0,0]],"v":[[-33.507,-77.038],[69.724,-77.966],[65.808,78.449],[-40.184,78.147]],"c":true}]}]},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.278431385756,0.776470601559,0.984313726425,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[310.432,172.23]},"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.317,"y":1},"o":{"x":0.642,"y":0},"t":0,"s":[{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[26.196,2.172],[0,0],[0,0],[0,0]],"v":[[-54.432,75.461],[54.432,82.898],[47.323,-82.898],[-54.432,-82.898]],"c":true}]},{"t":19,"s":[{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[27.026,2.172],[0,0],[0,0],[0,0]],"v":[[-44.38,58.446],[61.745,60.295],[65.808,-87.939],[-40.185,-88.241]],"c":true}]}]},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.376470595598,0.882352948189,1,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[310.432,338.619]},"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.317,"y":1},"o":{"x":0.642,"y":0},"t":0,"s":[{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[-59.01,-2.455]],"v":[[-54.58,-83.326],[-47.472,83.326],[53.625,82.339],[54.58,-77.139]],"c":true}]},{"t":19,"s":[{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[-58.601,-0.112]],"v":[[-30.378,-78.982],[-44.165,78.081],[67.872,76.995],[74.549,-78.19]],"c":true}]}]},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.137254908681,0.525490224361,0.690196096897,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[202.376,173.382]},"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.317,"y":1},"o":{"x":0.642,"y":0},"t":0,"s":[{"i":[[-19.745,0.395],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[39.491,-4.673]],"v":[[54.3,75.461],[54.3,-82.898],[-46.797,-81.911],[-54.3,82.898]],"c":true}]},{"t":19,"s":[{"i":[[-20.371,0.395],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[39.698,-2.377]],"v":[[64.351,58.446],[68.547,-88.241],[-43.49,-87.155],[-53.784,60.664]],"c":true}]}]},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.219607844949,0.75686275959,0.972549021244,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[201.7,338.619]},"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.317,"y":1},"o":{"x":0.642,"y":0},"t":0,"s":[{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[37.911,1.053],[0,0],[0,0]],"v":[[-36.134,-82.404],[-46.928,76.086],[39.425,82.404],[46.928,-82.404]],"c":true}]},{"t":19,"s":[{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[37.312,-5.796],[0,0],[0,0]],"v":[[-29.621,-81.351],[-54.132,68.789],[39.941,60.17],[50.235,-87.649]],"c":true}]}]},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.376470595598,0.882352948189,1,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[107.975,339.112]},"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":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.642,"y":0},"t":0,"s":[{"i":[[40.379,-1.086],[0,0],[0,0],[0,0]],"o":[[5.394,41.515],[0,0],[0,0],[0,0]],"v":[[-48.179,-78.784],[-34.884,83.326],[48.179,83.326],[41.071,-83.326]],"c":true}]},{"i":{"x":0.317,"y":1},"o":{"x":0.167,"y":0.167},"t":12,"s":[{"i":[[29.293,-5.463],[0,0],[0,0],[0,0]],"o":[[-21.022,51.435],[0,0],[0,0],[0,0]],"v":[[19.683,-71.171],[-29.51,84.195],[50.907,78.999],[61.039,-79.742]],"c":true}]},{"t":19,"s":[{"i":[[26.942,-6.391],[0,0],[0,0],[0,0]],"o":[[-26.623,53.538],[0,0],[0,0],[0,0]],"v":[[24.124,-72.55],[-28.37,84.38],[51.486,78.081],[65.273,-78.982]],"c":true}]}]},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.223529413342,0.749019622803,0.988235294819,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[106.725,173.382]},"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 8","bm":0,"hd":false},{"ty":"tr","p":{"a":0,"k":[106.725,173.382]},"a":{"a":0,"k":[106.725,173.382]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.967]},"o":{"x":[0.642],"y":[0]},"t":0,"s":[100]},{"t":12,"s":[0]}]},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"вода","bm":0,"hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.642,"y":0},"t":0,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-0.125,-16.714],[-0.873,0.125],[0,0],[-23.45,-1.247],[0,0],[0,0],[0,0],[-0.624,5.613]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[20.332,-0.374],[24.323,-3.991],[0,0],[33.553,-4.989],[0,0],[0,0],[0,0],[-23.575,1.247]],"v":[[365.267,88.857],[256.499,96.341],[147.232,90.354],[58.422,94.844],[58.666,97.806],[71.769,256.748],[61.042,415.285],[147.357,421.521],[256.125,414.037],[365.017,421.397],[454.451,414.91],[447.508,338.474],[440.107,256.998],[453.079,94.345]],"c":true}]},{"i":{"x":0.317,"y":1},"o":{"x":0.167,"y":0.167},"t":12,"s":[{"i":[[0,0],[0,0],[13.609,-0.927],[2.858,-3.89],[0.876,-2.21],[0,0],[-0.125,-16.714],[-0.873,0.125],[0,0],[-24.565,-0.986],[0,0],[0,0],[0,0],[-0.624,5.613]],"o":[[0,0],[0,0],[-13.609,0.927],[-0.395,0.497],[-10.036,25.325],[0,0],[36.408,-5.62],[26.459,-1.028],[0,0],[34.305,0.663],[0,0],[0,0],[0,0],[-32.934,-0.94]],"v":[[370.231,94.119],[270.031,95.566],[156.82,88.862],[128.013,101.564],[126.084,105.7],[77.405,258.799],[51.606,409.534],[145.38,402.429],[260.371,400.024],[367.222,403.527],[473.841,402.707],[471.826,329.073],[469.942,250.349],[475.001,95.518]],"c":true}]},{"i":{"x":0.833,"y":0.687},"o":{"x":0.696,"y":0},"t":19,"s":[{"i":[[0,0],[0,0],[7.329,0.439],[11.37,-1.416],[8.894,-16.076],[0,0],[-0.125,-16.714],[-0.873,0.125],[0,0],[-24.565,-0.986],[0,0],[0,0],[0,0],[-0.624,5.613]],"o":[[0,0],[0,0],[-7.329,-0.439],[-0.773,0.97],[-21.093,38.124],[0,0],[36.408,-5.62],[26.459,-1.028],[0,0],[34.305,0.663],[0,0],[0,0],[0,0],[-23.575,1.247]],"v":[[370.086,94.357],[272.442,93.636],[219.471,92.413],[158.989,88.586],[130.771,102.104],[77.03,257.266],[54.027,407.48],[145.356,399.674],[260.576,397.538],[368.066,399.341],[480.216,401.17],[479.396,327.756],[478.521,249.501],[483.019,93.094]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.313},"t":23.264,"s":[{"i":[[2.838,-0.459],[0,0],[5.388,0.323],[8.359,-1.041],[6.539,-11.819],[0,0],[-0.125,-16.714],[-0.873,0.125],[0,0],[-30.278,-2.603],[0,0],[0.678,14.528],[0,0],[0.851,16.093]],"o":[[-5.191,0.84],[0,0],[-5.388,-0.323],[-0.568,0.713],[-15.508,28.029],[0,0],[32.151,-4.231],[26.749,-0.76],[0,0],[34.804,1.864],[0,0],[-0.223,-4.773],[0,0],[-21.692,3.115]],"v":[[368.713,91.814],[268.363,93.654],[205.962,92.666],[155.914,89.528],[111.596,102.344],[72.486,257.137],[55.876,410.986],[146.164,405.503],[259.233,403.908],[367.014,407.807],[463.499,408.298],[471.453,331.895],[470.246,251.248],[472.277,81.895]],"c":true}]},{"i":{"x":0.833,"y":0.687},"o":{"x":0.167,"y":0.167},"t":26.461,"s":[{"i":[[10.717,-1.735],[0,0],[0,0],[0,0],[0,0],[0,0],[-0.125,-16.714],[-0.873,0.125],[0,0],[-46.141,-7.091],[0,0],[2.559,54.865],[0,0],[4.946,45.189]],"o":[[-19.604,3.174],[0,0],[0,0],[0,0],[0,0],[0,0],[20.332,-0.374],[27.556,-0.016],[0,0],[36.188,5.198],[0,0],[-0.841,-18.026],[0,0],[-16.465,8.302]],"v":[[364.899,84.751],[257.039,93.706],[168.456,93.369],[58.495,92.768],[58.356,103.008],[59.872,256.779],[61.011,420.72],[148.407,421.687],[255.507,421.595],[364.094,431.31],[417.086,428.087],[449.4,343.386],[447.27,256.098],[442.454,50.802]],"c":true}]},{"t":29,"s":[{"i":[[10.344,-3.294],[0,0],[0,0],[0,0],[0,0],[0,0],[-0.125,-16.714],[-0.873,0.125],[0,0],[-31.061,-8.247],[0,0],[-3.23,55.311],[0,0],[-0.671,46.412]],"o":[[-21.05,6.704],[0,0],[0,0],[0,0],[0,0],[0,0],[20.332,-0.374],[27.555,-0.016],[0,0],[4.031,1.671],[0,0],[1.052,-18.015],[0,0],[-16.465,8.302]],"v":[[373.888,80.087],[314.259,91.21],[270.723,92.858],[151.787,92.173],[151.838,96.854],[152.903,256.212],[154.535,419.836],[272.246,420.688],[318.942,422.91],[375.669,433.487],[390.526,440.98],[401.316,330.39],[409.726,252.774],[430.365,56.065]],"c":true}]}]},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":0,"k":[0.917646998985,0.194325002035,0,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":0},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.207843137255,0.737254901961,0.956862745098,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":"Shape 1","bm":0,"hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.642,"y":0},"t":0,"s":[{"i":[[0,0],[-43.655,0.957],[0,0],[0,0]],"o":[[0,0],[-5.966,-92.147],[0,0],[0,0]],"v":[[-52.595,92.49],[56.444,84.74],[40.565,-91.62],[-56.444,-92.49]],"c":true}]},{"t":12,"s":[{"i":[[0,0],[-43.655,0.957],[0,0],[0,0]],"o":[[0,0],[-1.942,-71.042],[0,0],[0,0]],"v":[[-50.082,74.611],[75.941,73.659],[70.99,-98.168],[-51.05,-97.83]],"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":[417.474,348.492]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":10},"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.833,"y":0.833},"o":{"x":0.642,"y":0},"t":0,"s":[{"i":[[0,0],[0,0],[0,0],[-35.1,-0.598]],"o":[[0,0],[0,0],[0,0],[-2.167,33.319]],"v":[[41.428,92.928],[-55.58,92.057],[-51.434,-92.928],[55.58,-86.571]],"c":true}]},{"t":12,"s":[{"i":[[0,0],[0,0],[0,0],[-35.646,0.48]],"o":[[0,0],[0,0],[0,0],[-2.167,33.319]],"v":[[71.854,86.38],[-50.186,86.718],[-46.31,-88.107],[78.937,-87.503]],"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":[416.61,163.945]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":20},"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.833,"y":0.833},"o":{"x":0.642,"y":0},"t":0,"s":[{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[36.533,-2.015],[0,0],[0,0],[0,0]],"v":[[-53.801,-84.355],[54.42,-92.492],[50.273,92.492],[-54.42,92.492]],"c":true}]},{"t":12,"s":[{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[40.75,0.38],[0,0],[0,0],[0,0]],"v":[[-40.473,-87.714],[59.543,-87.672],[55.667,87.153],[-47.317,86.467]],"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":[310.757,163.51]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":10},"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.833,"y":0.833},"o":{"x":0.642,"y":0},"t":0,"s":[{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[-60.714,-2.506]],"v":[[-54.95,-92.169],[-49.684,92.169],[54.331,91.161],[54.95,-85.686]],"c":true}]},{"t":12,"s":[{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[-59.962,-1.604]],"v":[[-31.306,-91.08],[-47.572,86.56],[61.434,85.135],[68.278,-89.046]],"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":[202.006,164.841]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":20},"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.833,"y":0.833},"o":{"x":0.642,"y":0},"t":0,"s":[{"i":[[-20.316,0.403],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[40.631,-4.769]],"v":[[54.218,84.283],[54.741,-92.456],[-49.274,-91.448],[-54.741,92.456]],"c":true}]},{"t":12,"s":[{"i":[[-20.316,0.403],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[40.631,-4.769]],"v":[[57.74,71.562],[60.956,-97.729],[-47.983,-97.125],[-58.332,78.325]],"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":[201.596,348.458]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":10},"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.833,"y":0.833},"o":{"x":0.642,"y":0},"t":0,"s":[{"i":[[55.766,-3.617],[0,0],[0,0],[0,0]],"o":[[5.076,50.937],[0,0],[0,0],[0,0]],"v":[[-57.12,-87.241],[-42.423,91.867],[57.12,92.169],[51.853,-92.169]],"c":true}]},{"i":{"x":0.833,"y":1},"o":{"x":0.167,"y":0.167},"t":12,"s":[{"i":[[15.795,-25.783],[0,0],[0,0],[0,0]],"o":[[-18.152,51.21],[0,0],[0,0],[0,0]],"v":[[29.454,-66.354],[-19.972,85.035],[59.232,86.56],[74.61,-90.327]],"c":true}]},{"t":19,"s":[{"i":[[15.794,-25.783],[0,0],[0,0],[0,0]],"o":[[-18.153,51.21],[0,0],[0,0],[0,0]],"v":[[37.447,-63.254],[-19.972,85.035],[59.232,86.56],[74.61,-90.327]],"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":[95.202,164.841]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":10},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Group 6","bm":0,"hd":false},{"ty":"tr","p":{"a":0,"k":[95.202,164.841]},"a":{"a":0,"k":[95.202,164.841]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":1,"k":[{"i":{"x":[0.317],"y":[1]},"o":{"x":[0.642],"y":[0]},"t":0,"s":[100]},{"t":12,"s":[0]}]},"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.833,"y":0.833},"o":{"x":0.642,"y":0},"t":0,"s":[{"i":[[0,0],[-2.802,34.43],[-1.248,19.723],[0,0],[38.294,-2.172],[0,0],[43.779,-2.595],[-3.065,-39.158],[0,0],[0,0],[0,0],[0,0],[-21.295,0.434],[0,0],[-41.738,1.158],[3.24,32.017]],"o":[[0,0],[3.415,-41.97],[-34.666,-0.823],[0,0],[-63.642,-2.7],[0.104,-0.631],[2.437,24.199],[2.796,35.721],[0,0],[0,0],[40.887,1.158],[42.59,-5.139],[28.252,2.389],[0,0],[-3.155,-48.571],[-2.883,-28.484]],"v":[[197.849,0.889],[203.011,-61.887],[211.745,-174.59],[109.11,-180.885],[0.89,-172.74],[-108.666,-179.139],[-213.448,-174.519],[-204.152,-64.346],[-199.166,0.724],[-204.182,75.682],[-210.751,173.839],[-109.258,180.788],[-0.066,172.674],[108.812,180.885],[213.448,173.26],[202.868,47.235]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":10,"s":[{"i":[[0,0],[-1.827,34.486],[-1.248,19.723],[0,0],[39.013,0.173],[0,0],[19.735,-10.775],[7.51,-43.624],[0,0],[5.837,-35.723],[0,0],[0,0],[-27.102,1.202],[0,0],[-41.738,1.158],[1.406,28.007]],"o":[[0,0],[2.222,-41.911],[-37.456,-0.019],[0,0],[-34.305,0.081],[-3.013,-0.054],[-3.15,18.802],[-3.852,29.889],[0,0],[-7.021,42.969],[35.407,-4.887],[34.101,-4.159],[32.796,0.358],[0,0],[-1.523,-44.334],[-1.314,-30.829]],"v":[[221.939,-3.75],[224.942,-71.46],[230.39,-175.536],[100.195,-177.582],[-22.523,-176.179],[-90.662,-175.565],[-157.958,-162.313],[-174.722,-65.229],[-185.273,3.296],[-198.061,84.052],[-206.721,175.951],[-119.861,171.212],[-21.766,163.703],[100.255,166.831],[229.32,164.722],[223.952,58.87]],"c":true}]},{"i":{"x":0.317,"y":1},"o":{"x":0.167,"y":0.167},"t":12,"s":[{"i":[[0,0],[-1.577,34.501],[-1.248,19.723],[0,0],[39.197,0.773],[0,0],[12.833,-22.786],[10.952,-35.558],[0,0],[7.331,-44.864],[0,0],[0,0],[-28.588,1.398],[0,0],[-41.738,1.158],[0.937,26.981]],"o":[[0,0],[1.917,-41.896],[-38.17,0.187],[0,0],[-27.508,-0.521],[-1.722,-0.293],[-5.837,15.687],[-5.553,28.396],[0,0],[-8.818,53.965],[34.005,-6.434],[19.932,-1.346],[33.959,-0.161],[0,0],[-1.105,-43.25],[-0.913,-31.43]],"v":[[228.103,-4.937],[230.554,-73.91],[235.161,-175.778],[97.914,-176.736],[-28.514,-177.059],[-85.918,-177.992],[-127.83,-155.714],[-157.289,-64.421],[-179.45,3.576],[-196.494,86.194],[-205.69,176.491],[-112.712,166.541],[-27.318,161.407],[98.065,163.234],[233.381,162.537],[229.348,61.847]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.696,"y":0},"t":19,"s":[{"i":[[0,0],[-1.224,34.522],[-1.248,19.723],[0,0],[39.458,1.621],[0,0],[14.555,-28.853],[14.043,-46.383],[0,0],[9.443,-57.789],[0,0],[0,0],[-30.689,1.676],[0,0],[-41.738,1.158],[0.273,25.531]],"o":[[0,0],[1.485,-41.875],[-39.18,0.478],[0,0],[-17.897,-1.374],[0.104,-0.631],[-6.602,15.467],[-7.958,26.286],[0,0],[-11.359,69.512],[32.023,-8.621],[28.857,-3.554],[35.603,-0.896],[0,0],[-0.515,-41.717],[-0.345,-32.278]],"v":[[236.82,-6.616],[238.49,-77.374],[241.907,-176.121],[94.688,-175.541],[-36.985,-178.303],[-79.208,-181.423],[-123.68,-154.773],[-156.543,-65.773],[-176.692,4.885],[-194.279,89.222],[-204.232,177.256],[-126.41,165.297],[-35.17,158.161],[94.968,158.149],[239.124,159.448],[236.977,66.057]],"c":true}]},{"i":{"x":0.833,"y":0.687},"o":{"x":0.167,"y":0.167},"t":26.461,"s":[{"i":[[0,0],[0.589,44.007],[3.574,26.922],[0,0],[39.01,0.624],[0,0],[44.195,-0.092],[-0.478,-37.424],[0,0],[0,0],[0,0],[0,0],[-32.506,-0.113],[0,0],[-16.073,10.001],[-0.937,32.167]],"o":[[0,0],[-0.513,-38.314],[-30.353,20.935],[0,0],[-63.022,-0.499],[-1.096,-0.025],[-0.21,25.353],[0.457,35.827],[0,0],[0,0],[40.887,1.158],[41.836,0.215],[54.551,1.405],[0,0],[25.678,-20.642],[0.876,-30.045]],"v":[[208.826,0.517],[207.899,-89.058],[201.921,-230.634],[109.207,-185.376],[0.839,-174.735],[-108.611,-176.145],[-213.4,-176.514],[-213.132,-64.369],[-211.639,0.832],[-211.167,75.802],[-210.998,179.327],[-108.798,179.916],[-0.355,179.16],[109.239,185.874],[164.97,176.572],[208.611,84.781]],"c":true}]},{"i":{"x":0.833,"y":0.687},"o":{"x":0.167,"y":0.313},"t":27.529,"s":[{"i":[[0,0],[-1.954,44.338],[2.239,0.278],[0,0],[39.01,-0.666],[0,0],[44.195,-0.092],[-0.478,-37.424],[0,0],[0,0],[0,0],[0,0],[-24.76,-0.5],[0,0],[-11.839,1.427],[-2.137,34.127]],"o":[[0,0],[1.333,-35.738],[-23.495,15.947],[0,0],[-42.246,-0.108],[-1.096,-0.025],[-0.21,25.353],[0.457,35.827],[0,0],[0,0],[42.574,1.049],[31.576,0.382],[44.715,1.771],[0,0],[16.94,-28.73],[1.694,-29.037]],"v":[[186.874,-1.069],[189.713,-85.613],[191.869,-228.79],[112.146,-187.564],[23.798,-175.831],[-59.1,-176.417],[-175.981,-176.812],[-175.714,-64.667],[-174.22,0.534],[-173.748,75.504],[-173.58,179.029],[-59.286,179.644],[23.527,180.462],[111.62,189.841],[151.947,191.72],[183.573,80.546]],"c":true}]},{"t":29,"s":[{"i":[[0,0],[-5.769,44.835],[-1.555,28.131],[0,0],[39.01,-2.601],[0,0],[44.195,-0.092],[-0.478,-37.424],[0,0],[0,0],[0,0],[0,0],[-13.142,-1.08],[0,0],[-5.488,-11.433],[-3.935,37.067]],"o":[[0,0],[4.101,-31.874],[-13.208,8.466],[0,0],[-11.081,0.478],[-1.096,-0.025],[-0.21,25.353],[0.457,35.827],[0,0],[0,0],[45.105,0.885],[16.185,0.631],[29.961,2.321],[0,0],[3.833,-40.864],[2.922,-27.526]],"v":[[153.945,-3.448],[162.434,-80.446],[176.791,-226.024],[116.556,-190.846],[58.238,-177.475],[15.167,-176.825],[-119.853,-177.259],[-119.586,-65.113],[-118.092,0.088],[-117.621,75.057],[-117.452,178.582],[14.98,179.235],[59.349,182.415],[115.192,195.791],[132.413,214.443],[146.018,74.193]],"c":true}]}]},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":0,"k":[0.72549021244,0.368627458811,0.019607843831,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":8},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 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":[256.066,255.984]},"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}],"ip":0,"op":33,"st":0,"bm":0},{"ddd":0,"ind":39,"ty":3,"nm":"Null 1","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":0,"s":[0]},{"i":{"x":[0.667],"y":[0.89]},"o":{"x":[0.333],"y":[0]},"t":19.725,"s":[-12.928]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[22.335]},"t":27,"s":[5.117]},{"i":{"x":[0.667],"y":[9.048]},"o":{"x":[0.333],"y":[0]},"t":36,"s":[5.227]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0.402]},"t":55,"s":[5.473]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":83,"s":[-1.771]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":108,"s":[0]},{"t":179,"s":[0]}]},"p":{"a":1,"k":[{"i":{"x":0.33,"y":0.458},"o":{"x":0.292,"y":0},"t":0,"s":[256,261,0],"to":[-12,0,0],"ti":[-6.333,0,0]},{"i":{"x":0.316,"y":1},"o":{"x":0.241,"y":0.078},"t":21.176,"s":[184,261,0],"to":[6.333,0,0],"ti":[0,0,0]},{"i":{"x":0,"y":1},"o":{"x":0.394,"y":0},"t":34,"s":[294,261,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.361,"y":1},"o":{"x":0.541,"y":0},"t":55,"s":[223,250,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.673,"y":1},"o":{"x":0.308,"y":0},"t":85,"s":[267,249.5,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.591,"y":1},"o":{"x":0.311,"y":0},"t":106,"s":[254.5,254.875,0],"to":[0,0,0],"ti":[0,0,0]},{"t":179,"s":[256,261,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":19.725,"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":36,"s":[94,94,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":83,"s":[100,100,100]},{"t":108,"s":[100,100,100]}]}},"ao":0,"ip":0,"op":180,"st":0,"bm":0}]} \ No newline at end of file diff --git a/TMessagesProj/src/main/res/raw/filled_premium_dollar.svg b/TMessagesProj/src/main/res/raw/filled_premium_dollar.svg new file mode 100644 index 00000000000..1119985e15f --- /dev/null +++ b/TMessagesProj/src/main/res/raw/filled_premium_dollar.svg @@ -0,0 +1,7 @@ + + + Filled / Premium / filled_premium_dollar + + + + \ No newline at end of file diff --git a/TMessagesProj/src/main/res/raw/instant_lanczos_frag.glsl b/TMessagesProj/src/main/res/raw/instant_lanczos_frag.glsl index 0379a2928bc..a16f788fca8 100644 --- a/TMessagesProj/src/main/res/raw/instant_lanczos_frag.glsl +++ b/TMessagesProj/src/main/res/raw/instant_lanczos_frag.glsl @@ -27,5 +27,5 @@ void main() { fragmentColor += texture2D(sTexture, fourStepsLeftTextureCoordinate) * -0.02143; fragmentColor += texture2D(sTexture, fourStepsRightTextureCoordinate) * -0.02143; - gl_FragColor = texture2D(sTexture, centerTextureCoordinate); + gl_FragColor = fragmentColor; } \ No newline at end of file diff --git a/TMessagesProj/src/main/res/raw/instant_lanczos_vert.glsl b/TMessagesProj/src/main/res/raw/instant_lanczos_vert.glsl index a9b77d6811c..6da5f03bed5 100644 --- a/TMessagesProj/src/main/res/raw/instant_lanczos_vert.glsl +++ b/TMessagesProj/src/main/res/raw/instant_lanczos_vert.glsl @@ -4,8 +4,7 @@ uniform mat4 uSTMatrix; attribute vec4 aPosition; attribute vec4 aTextureCoord; -uniform float texelWidthOffset; -uniform float texelHeightOffset; +uniform vec2 texelSize; varying vec2 centerTextureCoordinate; varying vec2 oneStepLeftTextureCoordinate; @@ -20,10 +19,10 @@ varying vec2 fourStepsRightTextureCoordinate; void main() { gl_Position = uMVPMatrix * aPosition; - vec2 firstOffset = vec2(texelWidthOffset, texelHeightOffset); - vec2 secondOffset = vec2(2.0 * texelWidthOffset, 2.0 * texelHeightOffset); - vec2 thirdOffset = vec2(3.0 * texelWidthOffset, 3.0 * texelHeightOffset); - vec2 fourthOffset = vec2(4.0 * texelWidthOffset, 4.0 * texelHeightOffset); + vec2 firstOffset = texelSize; + vec2 secondOffset = 2.0 * texelSize; + vec2 thirdOffset = 3.0 * texelSize; + vec2 fourthOffset = 4.0 * texelSize; centerTextureCoordinate = (uSTMatrix * aTextureCoord).xy; oneStepLeftTextureCoordinate = centerTextureCoordinate - firstOffset; diff --git a/TMessagesProj/src/main/res/values-night/styles.xml b/TMessagesProj/src/main/res/values-night/styles.xml index 4d619334d32..0729d80ec08 100644 --- a/TMessagesProj/src/main/res/values-night/styles.xml +++ b/TMessagesProj/src/main/res/values-night/styles.xml @@ -24,7 +24,7 @@ false @drawable/tg_splash_320 @integer/splash_screen_duration - ?android:windowBackground + #1f2732