update to 10.13.1 (4845)

This commit is contained in:
dkaraush 2024-06-03 10:21:03 +04:00
parent d494ea8cb5
commit 5bc1c3dce0
580 changed files with 23071 additions and 5933 deletions

View file

@ -39,13 +39,15 @@ dependencies {
implementation 'com.google.android.gms:play-services-wearable:18.0.0'
implementation 'com.google.android.gms:play-services-location:21.0.1'
implementation 'com.google.android.gms:play-services-wallet:19.1.0'
implementation 'com.google.android.gms:play-services-safetynet:18.0.1'
implementation 'com.googlecode.mp4parser:isoparser:1.0.6'
implementation 'com.stripe:stripe-android:2.0.2'
implementation 'com.google.mlkit:language-id:16.1.1'
implementation 'com.android.billingclient:billing:5.1.0'
implementation 'com.google.code.gson:gson:2.10'
implementation 'com.google.guava:guava:31.1-android'
implementation 'com.airbnb.android:lottie:6.4.0'
implementation 'com.google.android.play:integrity:1.3.0'
implementation 'com.google.android.gms:play-services-safetynet:18.0.1'
implementation 'com.google.android.gms:play-services-mlkit-subject-segmentation:16.0.0-beta1'
implementation 'com.google.android.gms:play-services-mlkit-image-labeling:16.0.8'

View file

@ -6,6 +6,12 @@
#include "tgnet/MTProtoScheme.h"
#include "tgnet/ConnectionSocket.h"
#include "tgnet/FileLog.h"
#include "tgnet/Handshake.h"
#include <openssl/rand.h>
#include <openssl/sha.h>
#include <openssl/bn.h>
#include <openssl/pem.h>
#include <openssl/aes.h>
JavaVM *java;
@ -31,6 +37,7 @@ jmethodID jclass_ConnectionsManager_onProxyError;
jmethodID jclass_ConnectionsManager_getHostByName;
jmethodID jclass_ConnectionsManager_getInitFlags;
jmethodID jclass_ConnectionsManager_onPremiumFloodWait;
jmethodID jclass_ConnectionsManager_onIntegrityCheckClassic;
bool check_utf8(const char *data, size_t len);
@ -133,6 +140,40 @@ void failNotRunningRequest(JNIEnv *env, jclass c, jint instanceNum, jint token)
return ConnectionsManager::getInstance(instanceNum).failNotRunningRequest(token);
}
void receivedIntegrityCheckClassic(JNIEnv *env, jclass c, jint instanceNum, jint requestToken, jstring nonce, jstring token) {
const char* nonceStr = env->GetStringUTFChars(nonce, 0);
const char* tokenStr = env->GetStringUTFChars(token, 0);
std::string nonceString = nonceStr;
std::string tokenString = tokenStr;
ConnectionsManager::getInstance(instanceNum).receivedIntegrityCheckClassic(requestToken, nonceString, tokenString);
if (nonceStr != nullptr) {
env->ReleaseStringUTFChars(nonce, nonceStr);
}
if (tokenStr != nullptr) {
env->ReleaseStringUTFChars(token, tokenStr);
}
}
jboolean isGoodPrime(JNIEnv *env, jclass c, jbyteArray prime, jint g) {
jsize length = env->GetArrayLength(prime);
jbyte *bytes = env->GetByteArrayElements(prime, NULL);
if (bytes == NULL) {
DEBUG_E("isGoodPrime: failed to get byte array");
return false;
}
unsigned char *unsignedBytes = (unsigned char *)bytes;
BIGNUM *bn = BN_bin2bn(unsignedBytes, length, NULL);
if (bn == NULL) {
env->ReleaseByteArrayElements(prime, bytes, 0);
DEBUG_E("isGoodPrime: failed to convert byte array into BIGNUM");
return false;
}
bool result = Handshake::isGoodPrime(bn, g);
BN_free(bn);
env->ReleaseByteArrayElements(prime, bytes, 0);
return result;
}
void cleanUp(JNIEnv *env, jclass c, jint instanceNum, jboolean resetKeys) {
return ConnectionsManager::getInstance(instanceNum).cleanUp(resetKeys, -1);
}
@ -324,6 +365,13 @@ class Delegate : public ConnectiosManagerDelegate {
void onPremiumFloodWait(int32_t instanceNum, int32_t requestToken, bool isUpload) {
jniEnv[instanceNum]->CallStaticVoidMethod(jclass_ConnectionsManager, jclass_ConnectionsManager_onPremiumFloodWait, instanceNum, requestToken, isUpload);
}
void onIntegrityCheckClassic(int32_t instanceNum, int32_t requestToken, std::string nonce) {
jstring nonceStr = jniEnv[instanceNum]->NewStringUTF(nonce.c_str());
jniEnv[instanceNum]->CallStaticVoidMethod(jclass_ConnectionsManager, jclass_ConnectionsManager_onIntegrityCheckClassic, instanceNum, requestToken, nonceStr);
jniEnv[instanceNum]->DeleteLocalRef(nonceStr);
}
};
void onHostNameResolved(JNIEnv *env, jclass c, jstring host, jlong address, jstring ip) {
@ -465,6 +513,8 @@ static JNINativeMethod ConnectionsManagerMethods[] = {
{"native_onHostNameResolved", "(Ljava/lang/String;JLjava/lang/String;)V", (void *) onHostNameResolved},
{"native_discardConnection", "(III)V", (void *) discardConnection},
{"native_failNotRunningRequest", "(II)V", (void *) failNotRunningRequest},
{"native_receivedIntegrityCheckClassic", "(IILjava/lang/String;Ljava/lang/String;)V", (void *) receivedIntegrityCheckClassic},
{"native_isGoodPrime", "([BI)Z", (void *) isGoodPrime},
};
inline int registerNativeMethods(JNIEnv *env, const char *className, JNINativeMethod *methods, int methodsCount) {
@ -577,6 +627,10 @@ extern "C" int registerNativeTgNetFunctions(JavaVM *vm, JNIEnv *env) {
if (jclass_ConnectionsManager_onPremiumFloodWait == 0) {
return JNI_FALSE;
}
jclass_ConnectionsManager_onIntegrityCheckClassic = env->GetStaticMethodID(jclass_ConnectionsManager, "onIntegrityCheckClassic", "(IILjava/lang/String;)V");
if (jclass_ConnectionsManager_onIntegrityCheckClassic == 0) {
return JNI_FALSE;
}
return JNI_TRUE;
}

View file

@ -810,6 +810,9 @@ MessageEntity *MessageEntity::TLdeserialize(NativeByteBuffer *stream, uint32_t c
result = new TL_messageEntityStrike();
break;
case 0x20df5d0:
result = new TL_messageEntityBlockquote_layer180();
break;
case 0xf1ccaaac:
result = new TL_messageEntityBlockquote();
break;
case 0x9c4e7e8b:
@ -1001,11 +1004,24 @@ void TL_messageEntityStrike::serializeToStream(NativeByteBuffer *stream) {
}
void TL_messageEntityBlockquote::readParams(NativeByteBuffer *stream, int32_t instanceNum, bool &error) {
flags = stream->readInt32(&error);
offset = stream->readInt32(&error);
length = stream->readInt32(&error);
}
void TL_messageEntityBlockquote_layer180::readParams(NativeByteBuffer *stream, int32_t instanceNum, bool &error) {
offset = stream->readInt32(&error);
length = stream->readInt32(&error);
}
void TL_messageEntityBlockquote::serializeToStream(NativeByteBuffer *stream) {
stream->writeInt32(constructor);
stream->writeInt32(flags);
stream->writeInt32(offset);
stream->writeInt32(length);
}
void TL_messageEntityBlockquote_layer180::serializeToStream(NativeByteBuffer *stream) {
stream->writeInt32(constructor);
stream->writeInt32(offset);
stream->writeInt32(length);

View file

@ -537,6 +537,7 @@ public:
class MessageEntity : public TLObject {
public:
int32_t flags;
int32_t offset;
int32_t length;
std::string url;
@ -685,6 +686,15 @@ public:
class TL_messageEntityBlockquote : public MessageEntity {
public:
static const uint32_t constructor = 0xf1ccaaac;
void readParams(NativeByteBuffer *stream, int32_t instanceNum, bool &error);
void serializeToStream(NativeByteBuffer *stream);
};
class TL_messageEntityBlockquote_layer180 : public MessageEntity {
public:
static const uint32_t constructor = 0x20df5d0;

View file

@ -57,6 +57,7 @@ void Connection::suspendConnection(bool idle) {
connectionState = idle ? TcpConnectionStageIdle : TcpConnectionStageSuspended;
dropConnection();
ConnectionsManager::getInstance(currentDatacenter->instanceNum).onConnectionClosed(this, 0);
generation++;
firstPacketSent = false;
if (restOfTheData != nullptr) {
restOfTheData->reuse();
@ -243,7 +244,11 @@ void Connection::onReceivedData(NativeByteBuffer *buffer) {
uint32_t old = buffer->limit();
buffer->limit(buffer->position() + currentPacketLength);
uint32_t current_generation = generation;
ConnectionsManager::getInstance(currentDatacenter->instanceNum).onConnectionDataReceived(this, buffer, currentPacketLength);
if (current_generation != generation) {
break;
}
buffer->position(buffer->limit());
buffer->limit(old);
@ -350,6 +355,7 @@ void Connection::connect() {
reconnectTimer->stop();
if (LOGS_ENABLED) DEBUG_D("connection(%p, account%u, dc%u, type %d) connecting (%s:%hu)", this, currentDatacenter->instanceNum, currentDatacenter->getDatacenterId(), connectionType, hostAddress.c_str(), hostPort);
generation++;
firstPacketSent = false;
if (restOfTheData != nullptr) {
restOfTheData->reuse();
@ -657,6 +663,7 @@ void Connection::onDisconnectedInternal(int32_t reason, int32_t error) {
currentTimeout += 2;
}
}
generation++;
firstPacketSent = false;
if (restOfTheData != nullptr) {
restOfTheData->reuse();

View file

@ -101,6 +101,7 @@ private:
int64_t usefullDataReceiveTime;
uint32_t currentTimeout = 4;
uint32_t receivedDataAmount = 0;
uint32_t generation = 0;
uint8_t temp[64];

View file

@ -891,8 +891,11 @@ void ConnectionsManager::onConnectionDataReceived(Connection *connection, Native
TLObject *request;
if (datacenter->isHandshaking(connection->isMediaConnection)) {
request = datacenter->getCurrentHandshakeRequest(connection->isMediaConnection);
if (request == nullptr) {
return;
}
} else {
request = getRequestWithMessageId(messageId);
return;
}
deserializingDatacenter = datacenter;
@ -1287,6 +1290,7 @@ void ConnectionsManager::processServerResponse(TLObject *message, int64_t messag
static std::string authRestart = "AUTH_RESTART";
static std::string authKeyPermEmpty = "AUTH_KEY_PERM_EMPTY";
static std::string workerBusy = "WORKER_BUSY_TOO_LONG_RETRY";
static std::string integrityCheckClassic = "INTEGRITY_CHECK_CLASSIC_";
bool processEvenFailed = error->error_code == 500 && error->error_message.find(authRestart) != std::string::npos;
bool isWorkerBusy = error->error_code == 500 && error->error_message.find(workerBusy) != std::string::npos;
if (LOGS_ENABLED) DEBUG_E("request %p rpc error %d: %s", request, error->error_code, error->error_message.c_str());
@ -1301,8 +1305,19 @@ void ConnectionsManager::processServerResponse(TLObject *message, int64_t messag
saveConfig();
datacenter->beginHandshake(connection->isMediaConnection ? HandshakeTypeMediaTemp : HandshakeTypeTemp, false);
}
} else if ((request->requestFlags & RequestFlagFailOnServerErrors) == 0 || processEvenFailed) {
if (error->error_code == 500 || error->error_code < 0) {
} else if (error->error_code == 403 && error->error_message.find(integrityCheckClassic) != std::string::npos) {
discardResponse = true;
std::string nonce = error->error_message.substr(integrityCheckClassic.size(), error->error_message.size() - integrityCheckClassic.size());
request->awaitingIntegrityCheck = true;
request->startTime = 0;
request->startTimeMillis = 0;
if (delegate != nullptr) {
delegate->onIntegrityCheckClassic(instanceNum, request->requestToken, nonce);
}
} else {
bool failServerErrors = (request->requestFlags & RequestFlagFailOnServerErrors) == 0 || processEvenFailed;
bool exceptFloodWait = (request->requestFlags & RequestFlagFailOnServerErrorsExceptFloodWait) != 0;
if (failServerErrors && (error->error_code == 500 || error->error_code < 0)) {
static std::string waitFailed = "MSG_WAIT_FAILED";
static std::string waitTimeout = "MSG_WAIT_TIMEOUT";
if (error->error_message.find(waitFailed) != std::string::npos) {
@ -1318,13 +1333,14 @@ void ConnectionsManager::processServerResponse(TLObject *message, int64_t messag
request->serverFailureCount++;
}
discardResponse = true;
} else if (error->error_code == -504) {
} else if (failServerErrors && error->error_code == -504) {
discardResponse = (request->requestFlags & RequestFlagIgnoreFloodWait) == 0;
request->failedByFloodWait = 2;
request->startTime = 0;
request->startTimeMillis = 0;
request->minStartTime = (int32_t) (getCurrentTimeMonotonicMillis() / 1000 + 2);
} else if (
(failServerErrors || exceptFloodWait) &&
error->error_code == 420 && (request->requestFlags & RequestFlagIgnoreFloodWait) == 0 &&
error->error_message.find("STORY_SEND_FLOOD") == std::string::npos
) {
@ -1363,7 +1379,7 @@ void ConnectionsManager::processServerResponse(TLObject *message, int64_t messag
if (isPremiumFloodWait && delegate != nullptr) {
delegate->onPremiumFloodWait(instanceNum, request->requestToken, (request->connectionType & ConnectionTypeUpload) != 0);
}
} else if (error->error_code == 400) {
} else if (failServerErrors && error->error_code == 400) {
static std::string waitFailed = "MSG_WAIT_FAILED";
static std::string bindFailed = "ENCRYPTED_MESSAGE_INVALID";
static std::string waitTimeout = "MSG_WAIT_TIMEOUT";
@ -2154,6 +2170,32 @@ void ConnectionsManager::failNotRunningRequest(int32_t token) {
});
}
void ConnectionsManager::receivedIntegrityCheckClassic(int32_t requestToken, std::string nonce, std::string token) {
scheduleTask([&, requestToken, nonce, token] {
for (auto iter = runningRequests.begin(); iter != runningRequests.end(); iter++) {
Request *request = iter->get();
if (requestToken != 0 && request->requestToken == requestToken) {
auto invokeIntegrity = new invokeWithGooglePlayIntegrity();
invokeIntegrity->nonce = nonce;
invokeIntegrity->token = token;
invokeIntegrity->query = std::move(request->rpcRequest);
request->rpcRequest = std::unique_ptr<invokeWithGooglePlayIntegrity>(invokeIntegrity);
request->awaitingIntegrityCheck = false;
request->requestFlags &=~ RequestFlagFailOnServerErrors;
if (LOGS_ENABLED) DEBUG_D("account%d: received integrity token, wrapping %s", instanceNum, token.c_str());
processRequestQueue(request->connectionType, request->datacenterId);
return;
}
}
if (LOGS_ENABLED) DEBUG_E("account%d: received integrity token but no request %d found", instanceNum, requestToken);
});
}
void ConnectionsManager::onDatacenterHandshakeComplete(Datacenter *datacenter, HandshakeType type, int32_t timeDiff) {
saveConfig();
uint32_t datacenterId = datacenter->getDatacenterId();
@ -2474,13 +2516,13 @@ void ConnectionsManager::processRequestQueue(uint32_t connectionTypes, uint32_t
forceThisRequest = false;
}
if (forceThisRequest || (
if ((forceThisRequest || (
abs(currentTime - request->startTime) > maxTimeout && (
currentTime >= request->minStartTime ||
(request->failedByFloodWait != 0 && (request->minStartTime - currentTime) > request->failedByFloodWait) ||
(request->failedByFloodWait == 0 && abs(currentTime - request->minStartTime) >= 60)
)
)) {
)) && !request->awaitingIntegrityCheck) {
if (!forceThisRequest && request->connectionToken > 0) {
if ((request->connectionType & ConnectionTypeGeneric || request->connectionType & ConnectionTypeTemp) && request->connectionToken == connection->getConnectionToken()) {
if (LOGS_ENABLED) DEBUG_D("request token is valid, not retrying %s (%p)", typeInfo.name(), request->rawRequest);
@ -3519,12 +3561,9 @@ void ConnectionsManager::applyDnsConfig(NativeByteBuffer *buffer, std::string ph
if (LOGS_ENABLED) DEBUG_D("can't decrypt dns config");
} else {
delete config;
if (LOGS_ENABLED) DEBUG_D("dns config not valid due to date or expire");
if (LOGS_ENABLED) DEBUG_D("dns config not valid due to date or expire, current date = %d, config date = %d, config expired = %d", currentDate, config->date, config->expires);
}
if (requestingSecondAddress == 2) {
requestingSecondAddress = 3;
delegate->onRequestNewServerIpAndPort(requestingSecondAddress, instanceNum);
} else if (requestingSecondAddress == 1) {
if (requestingSecondAddress == 1) {
requestingSecondAddress = 2;
delegate->onRequestNewServerIpAndPort(requestingSecondAddress, instanceNum);
} else if (requestingSecondAddress == 0) {

View file

@ -82,6 +82,7 @@ public:
void reconnect(int32_t datacentrId, int32_t connectionType);
void failNotRunningRequest(int32_t token);
void receivedIntegrityCheckClassic(int32_t requestToken, std::string nonce, std::string token);
private:
static void *ThreadProc(void *data);

View file

@ -593,14 +593,26 @@ void Datacenter::serializeToStream(NativeByteBuffer *stream) {
}
stream->writeInt64(authKeyMediaTempId);
stream->writeInt32(authorized ? 1 : 0);
stream->writeInt32((int32_t) (size = serverSalts.size()));
for (uint32_t a = 0; a < size; a++) {
size = 0;
for (uint32_t a = 0; a < serverSalts.size(); a++) {
if (serverSalts[a] != nullptr) size++;
}
stream->writeInt32((int32_t) size);
for (uint32_t a = 0; a < serverSalts.size(); a++) {
if (serverSalts[a] == nullptr) continue;
stream->writeInt32(serverSalts[a]->valid_since);
stream->writeInt32(serverSalts[a]->valid_until);
stream->writeInt64(serverSalts[a]->salt);
}
stream->writeInt32((int32_t) (size = mediaServerSalts.size()));
for (uint32_t a = 0; a < size; a++) {
size = 0;
for (uint32_t a = 0; a < mediaServerSalts.size(); a++) {
if (mediaServerSalts[a] != nullptr) size++;
}
stream->writeInt32((int32_t) size);
for (uint32_t a = 0; a < mediaServerSalts.size(); a++) {
if (mediaServerSalts[a] == nullptr) continue;
stream->writeInt32(mediaServerSalts[a]->valid_since);
stream->writeInt32(mediaServerSalts[a]->valid_until);
stream->writeInt64(mediaServerSalts[a]->salt);

View file

@ -154,6 +154,7 @@ typedef struct ConnectiosManagerDelegate {
virtual void getHostByName(std::string domain, int32_t instanceNum, ConnectionSocket *socket) = 0;
virtual int32_t getInitFlags(int32_t instanceNum) = 0;
virtual void onPremiumFloodWait(int32_t instanceNum, int32_t requestToken, bool isUpload) = 0;
virtual void onIntegrityCheckClassic(int32_t instanceNum, int32_t requestToken, std::string nonce) = 0;
} ConnectiosManagerDelegate;
typedef struct HandshakeDelegate {
@ -175,7 +176,8 @@ enum RequestFlag {
RequestFlagResendAfter = 512,
RequestFlagIgnoreFloodWait = 1024,
RequestFlagListenAfterCancel = 2048,
RequestFlagIsCancel = 32768
RequestFlagIsCancel = 32768,
RequestFlagFailOnServerErrorsExceptFloodWait = 65536
};
inline std::string to_string_int32(int32_t value) {

View file

@ -206,10 +206,13 @@ inline bool check_prime(BIGNUM *p) {
return result != 0;
}
inline bool isGoodPrime(BIGNUM *p, uint32_t g) {
bool Handshake::isGoodPrime(BIGNUM *p, uint32_t g) {
if (g < 2 || g > 7 || BN_num_bits(p) != 2048) {
return false;
}
if (bnContext == nullptr) {
bnContext = BN_CTX_new();
}
BIGNUM *t = BN_new();
BIGNUM *dh_g = BN_new();
@ -657,7 +660,7 @@ void Handshake::processHandshakeResponse_serverDHParams(TLObject *message, int64
if (LOGS_ENABLED) DEBUG_E("can't allocate BIGNUM p");
exit(1);
}
if (!isGoodPrime(p, dhInnerData->g)) {
if (!Handshake::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);
@ -826,9 +829,11 @@ void Handshake::processHandshakeResponse_serverDHParamsAnswer(TLObject *message,
handshakeRequest = nullptr;
}
std::unique_ptr<TL_future_salt> salt = std::unique_ptr<TL_future_salt>(handshakeServerSalt);
currentDatacenter->clearServerSalts(handshakeType == HandshakeTypeMediaTemp);
currentDatacenter->addServerSalt(salt, handshakeType == HandshakeTypeMediaTemp);
if (handshakeServerSalt != nullptr) {
std::unique_ptr<TL_future_salt> salt = std::unique_ptr<TL_future_salt>(handshakeServerSalt);
currentDatacenter->addServerSalt(salt, handshakeType == HandshakeTypeMediaTemp);
}
handshakeServerSalt = nullptr;
if (handshakeType == HandshakeTypePerm) {

View file

@ -11,6 +11,7 @@
#include <stdint.h>
#include "Defines.h"
#include <openssl/bn.h>
class Datacenter;
class ByteArray;
@ -37,6 +38,7 @@ public:
ByteArray *getPendingAuthKey();
int64_t getPendingAuthKeyId();
TLObject *getCurrentHandshakeRequest();
static bool isGoodPrime(BIGNUM *p, uint32_t g);
private:

View file

@ -941,6 +941,13 @@ void invokeWithLayer::serializeToStream(NativeByteBuffer *stream) {
query->serializeToStream(stream);
}
void invokeWithGooglePlayIntegrity::serializeToStream(NativeByteBuffer *stream) {
stream->writeInt32(constructor);
stream->writeString(nonce);
stream->writeString(token);
query->serializeToStream(stream);
}
void TL_inputClientProxy::serializeToStream(NativeByteBuffer *stream) {
stream->writeInt32(constructor);
stream->writeString(address);

View file

@ -730,6 +730,18 @@ public:
void serializeToStream(NativeByteBuffer *stream);
};
class invokeWithGooglePlayIntegrity : public TLObject {
public:
static const uint32_t constructor = 0x1df92984;
std::string nonce;
std::string token;
std::unique_ptr<TLObject> query;
void serializeToStream(NativeByteBuffer *stream);
};
class TL_inputClientProxy : public TLObject {
public:

View file

@ -35,6 +35,7 @@ public:
uint32_t retryCount = 0;
bool failedBySalt = false;
int32_t failedByFloodWait = 0;
bool awaitingIntegrityCheck = false;
bool premiumFloodWait = false;
ConnectionType connectionType;
uint32_t requestFlags;

View file

@ -803,7 +803,7 @@ JNIEXPORT void JNICALL Java_org_telegram_messenger_voip_NativeInstance_setBuffer
extern "C"
JNIEXPORT void JNICALL Java_org_telegram_messenger_voip_NativeInstance_setNetworkType(JNIEnv *env, jobject obj, jint networkType) {
InstanceHolder *instance = getInstanceHolder(env, obj);
if (instance->nativeInstance == nullptr) {
if (instance == nullptr || instance->nativeInstance == nullptr) {
return;
}
instance->nativeInstance->setNetworkType(parseNetworkType(networkType));
@ -830,7 +830,7 @@ JNIEXPORT void JNICALL Java_org_telegram_messenger_voip_NativeInstance_setVolume
extern "C"
JNIEXPORT void JNICALL Java_org_telegram_messenger_voip_NativeInstance_setAudioOutputGainControlEnabled(JNIEnv *env, jobject obj, jboolean enabled) {
InstanceHolder *instance = getInstanceHolder(env, obj);
if (instance->nativeInstance == nullptr) {
if (instance == nullptr || instance->nativeInstance == nullptr) {
return;
}
instance->nativeInstance->setAudioOutputGainControlEnabled(enabled);
@ -839,7 +839,7 @@ JNIEXPORT void JNICALL Java_org_telegram_messenger_voip_NativeInstance_setAudioO
extern "C"
JNIEXPORT void JNICALL Java_org_telegram_messenger_voip_NativeInstance_setEchoCancellationStrength(JNIEnv *env, jobject obj, jint strength) {
InstanceHolder *instance = getInstanceHolder(env, obj);
if (instance->nativeInstance == nullptr) {
if (instance == nullptr || instance->nativeInstance == nullptr) {
return;
}
instance->nativeInstance->setEchoCancellationStrength(strength);
@ -848,7 +848,7 @@ JNIEXPORT void JNICALL Java_org_telegram_messenger_voip_NativeInstance_setEchoCa
extern "C"
JNIEXPORT jstring JNICALL Java_org_telegram_messenger_voip_NativeInstance_getLastError(JNIEnv *env, jobject obj) {
InstanceHolder *instance = getInstanceHolder(env, obj);
if (instance->nativeInstance == nullptr) {
if (instance == nullptr || instance->nativeInstance == nullptr) {
return nullptr;
}
return env->NewStringUTF(instance->nativeInstance->getLastError().c_str());
@ -857,7 +857,7 @@ JNIEXPORT jstring JNICALL Java_org_telegram_messenger_voip_NativeInstance_getLas
extern "C"
JNIEXPORT jstring JNICALL Java_org_telegram_messenger_voip_NativeInstance_getDebugInfo(JNIEnv *env, jobject obj) {
InstanceHolder *instance = getInstanceHolder(env, obj);
if (instance->nativeInstance == nullptr) {
if (instance == nullptr || instance->nativeInstance == nullptr) {
return nullptr;
}
return env->NewStringUTF(instance->nativeInstance->getDebugInfo().c_str());
@ -866,7 +866,7 @@ JNIEXPORT jstring JNICALL Java_org_telegram_messenger_voip_NativeInstance_getDeb
extern "C"
JNIEXPORT jlong JNICALL Java_org_telegram_messenger_voip_NativeInstance_getPreferredRelayId(JNIEnv *env, jobject obj) {
InstanceHolder *instance = getInstanceHolder(env, obj);
if (instance->nativeInstance == nullptr) {
if (instance == nullptr || instance->nativeInstance == nullptr) {
return 0;
}
return instance->nativeInstance->getPreferredRelayId();
@ -875,7 +875,7 @@ JNIEXPORT jlong JNICALL Java_org_telegram_messenger_voip_NativeInstance_getPrefe
extern "C"
JNIEXPORT jobject JNICALL Java_org_telegram_messenger_voip_NativeInstance_getTrafficStats(JNIEnv *env, jobject obj) {
InstanceHolder *instance = getInstanceHolder(env, obj);
if (instance->nativeInstance == nullptr) {
if (instance == nullptr || instance->nativeInstance == nullptr) {
return nullptr;
}
return asJavaTrafficStats(env, instance->nativeInstance->getTrafficStats());
@ -884,7 +884,7 @@ JNIEXPORT jobject JNICALL Java_org_telegram_messenger_voip_NativeInstance_getTra
extern "C"
JNIEXPORT jbyteArray JNICALL Java_org_telegram_messenger_voip_NativeInstance_getPersistentState(JNIEnv *env, jobject obj) {
InstanceHolder *instance = getInstanceHolder(env, obj);
if (instance->nativeInstance == nullptr) {
if (instance == nullptr || instance->nativeInstance == nullptr) {
return nullptr;
}
return copyVectorToJavaByteArray(env, instance->nativeInstance->getPersistentState().value);
@ -893,7 +893,7 @@ JNIEXPORT jbyteArray JNICALL Java_org_telegram_messenger_voip_NativeInstance_get
extern "C"
JNIEXPORT void JNICALL Java_org_telegram_messenger_voip_NativeInstance_stopNative(JNIEnv *env, jobject obj) {
InstanceHolder *instance = getInstanceHolder(env, obj);
if (instance->nativeInstance == nullptr) {
if (instance == nullptr || instance->nativeInstance == nullptr) {
return;
}
instance->nativeInstance->stop([instance](const FinalState& finalState) {
@ -920,7 +920,7 @@ JNIEXPORT void JNICALL Java_org_telegram_messenger_voip_NativeInstance_stopGroup
extern "C"
JNIEXPORT void JNICALL Java_org_telegram_messenger_voip_NativeInstance_onStreamPartAvailable(JNIEnv *env, jobject obj, jlong ts, jobject byteBuffer, jint size, jlong responseTs, jint videoChannel, jint quality) {
InstanceHolder *instance = getInstanceHolder(env, obj);
if (instance->groupNativeInstance == nullptr) {
if (instance == nullptr || instance->groupNativeInstance == nullptr) {
return;
}
auto context = (AndroidContext *) instance->_platformContext.get();
@ -1099,7 +1099,7 @@ JNIEXPORT void JNICALL Java_org_telegram_messenger_voip_NativeInstance_setupOutg
extern "C"
JNIEXPORT void JNICALL Java_org_telegram_messenger_voip_NativeInstance_onSignalingDataReceive(JNIEnv *env, jobject obj, jbyteArray value) {
InstanceHolder *instance = getInstanceHolder(env, obj);
if (instance->nativeInstance == nullptr) {
if (instance == nullptr || instance->nativeInstance == nullptr) {
return;
}

View file

@ -1,4 +1,5 @@
chat_BlurAlpha=-1056964608
chat_BlurAlpha=-872415232
chat_BlurAlphaSlow=-1056964608
chat_unreadMessagesStartText=-14512671
chat_inFileBackgroundSelected=-2823172
radioBackgroundChecked=-14638337

View file

@ -182,3 +182,5 @@ chat_outReplyMediaMessageSelectedText=-8674357
chats_attachMessage=-14843710
chat_outSentClock=-594761027
chat_searchPanelText=-12609056
table_background=-526345
table_border=-2039584

View file

@ -398,7 +398,8 @@ windowBackgroundWhiteGrayText4=-931296359
chat_inTimeText=-645885536
dialogRadioBackground=-11245959
statisticChartRipple=748994002
chat_BlurAlpha=-520093696
chat_BlurAlpha=-1308622848
chat_BlurAlphaSlow=-872415232
chat_outReplyMessageText=-1
chat_recordedVoiceDot=-1221292
chat_messagePanelBackground=-14602949
@ -439,4 +440,6 @@ code_function=-27776
code_string=-7806088
code_operator=2147483647
code_number=-10887465
code_comment=2147483647
code_comment=2147483647
table_background=177390847
table_border=436207615

View file

@ -48,6 +48,8 @@ chat_outSentCheckRead=-167772161
chat_unreadMessagesStartArrowIcon=-3741702
chat_stickerReplyLine=-13527843
windowBackgroundWhiteBlackText=-13421773
table_background=-526345
table_border=-2039584
avatar_backgroundActionBarBlue=-1
dialogTextLink=-14317077
chat_status=-16284199

View file

@ -421,7 +421,8 @@ windowBackgroundWhiteGrayText4=-9803158
chat_inTimeText=-8552575
dialogRadioBackground=-10855846
statisticChartRipple=748994002
chat_BlurAlpha=-1056964608
chat_BlurAlpha=-1308622848
chat_BlurAlphaSlow=-1056964608
chat_outBubbleGradient=-12874567
chat_outReplyMessageText=-1
chat_recordedVoiceDot=-1221292
@ -464,4 +465,6 @@ code_function=-27776
code_string=-7806088
code_operator=2147483647
code_number=-10887465
code_comment=2147483647
code_comment=2147483647
table_background=177390847
table_border=436207615

View file

@ -6,10 +6,10 @@ uniform sampler2D u_BackgroundTexture;
uniform float f_xOffset;
uniform float f_alpha;
uniform mat4 world;
uniform vec3 modelViewVertex;
varying vec3 vNormal;
varying vec2 vUV;
varying vec3 modelViewVertex;
vec3 cameraPosition = vec3(0, 0, 100);
@ -38,7 +38,7 @@ void main() {
vec3 finalNormal = normalize(vNormalW + vTextureNormal);
vec3 color = texture2D(u_Texture, vUV ).xyz;
vec3 viewDirectionW = normalize(cameraPosition - modelViewVertex);
vec3 viewDirectionW = normalize(cameraPosition);
vec3 angleW = normalize(viewDirectionW + vLightPosition2);
float specComp2 = max(0., dot(vNormalW, angleW));

View file

@ -0,0 +1,93 @@
precision highp float;
uniform sampler2D u_Texture;
uniform sampler2D u_NormalMap;
uniform sampler2D u_BackgroundTexture;
uniform float f_xOffset;
uniform float f_alpha;
uniform mat4 world;
varying vec3 vNormal;
varying vec2 vUV;
varying vec3 modelViewVertex;
uniform float spec1;
uniform float spec2;
uniform float u_diffuse;
uniform float normalSpec;
uniform vec3 gradientColor1;
uniform vec3 gradientColor2;
uniform vec3 normalSpecColor;
uniform vec3 specColor;
uniform vec2 resolution;
uniform vec4 gradientPosition;
uniform int modelIndex;
void main() {
vec3 pos = modelViewVertex / 100.0 + .5;
float specTexture = texture2D(u_Texture, vUV).y * clamp(vNormal.z, 0.0, 1.0);
float gradientMix = distance(pos.xy, vec2(1, 1));
gradientMix -= .05 * specTexture;
gradientMix = clamp(gradientMix, 0.0, 1.0);
vec4 color = vec4(mix(gradientColor1, gradientColor2, gradientMix), 1.0);
vec3 norm = normalize(vec3(world * vec4(vNormal, 0.0)));
// vec3 flecksLightPos = vec3(.5, .5, 0.0);
// vec3 flecksLightDir = normalize(flecksLightPos - pos);
// vec3 flecksReflectDir = reflect(-flecksLightDir, norm);
// float flecksSpec = pow(max(dot(normalize(vec3(0.0) - pos), flecksReflectDir), 0.0), 8.0);
vec3 flecksNormal = normalize(1.0 - texture2D(u_NormalMap, vUV + .7 * vec2(-f_xOffset, f_xOffset)).xyz);
float flecks = clamp(flecksNormal.x, 0.0, 1.0);
// norm = normalize(norm + flecksSpec * abs(vNormal.z) * flecksNormal);
vec3 lightPos = vec3(-3., -3., 20.);
vec3 lightDir = normalize(lightPos - pos);
float diffuse = max(dot(norm, lightDir), 0.0);
float spec = 0.0;
lightPos = vec3(-1., .7, .2);
spec += specTexture * clamp(2.0 * pow(max(dot(normalize(vec3(0.0) - pos), reflect(-normalize(lightPos - pos), norm)), 0.0), 2.0), 0.0, 1.0) / 6.0;
lightPos = vec3(8., .7, .5);
spec += specTexture * clamp(2.0 * pow(max(dot(normalize(vec3(0.0) - pos), reflect(-normalize(lightPos - pos), norm)), 0.0), 2.0), 0.0, 1.0) / 6.0;
float notSpecTexture = mix(1.0, 0.3, specTexture);
lightPos = vec3(-3., -3., .5);
spec += clamp(2.0 * pow(max(dot(normalize(vec3(0.0) - pos), reflect(-normalize(lightPos - pos), norm)), 0.0), 2.0), 0.0, 1.0) / 4.0;
lightPos = vec3(4., 3., 2.5);
spec += clamp(1.5 * pow(max(dot(normalize(vec3(0.0) - pos), reflect(-normalize(lightPos - pos), norm)), 0.0), 2.0), 0.0, 1.0) / 6.0;
lightPos = vec3(-33., .5, 30.);
spec += clamp(2.0 * pow(max(dot(normalize(vec3(0.0) - pos), reflect(-normalize(lightPos - pos), norm)), 0.0), 2.0), 0.0, 1.0) / 12.0;
spec = clamp(spec, 0.0, 0.7);
lightPos = vec3(10., .5, 3.3);
spec += mix(0.8, 1.0, specTexture) * clamp(2.0 * pow(max(dot(normalize(vec3(0.0) - pos), reflect(-normalize(lightPos - pos), norm)), 0.0), 2.0), 0.0, 1.0) / 8.0;
lightPos = vec3(-10., .5, 3.7);
spec += mix(0.8, 1.0, specTexture) * clamp(2.0 * pow(max(dot(normalize(vec3(0.0) - pos), reflect(-normalize(lightPos - pos), norm)), 0.0), 2.0), 0.0, 1.0) / 8.0;
lightPos = vec3(.5, 12., 1.5);
spec += mix(0.8, 1.0, specTexture) * clamp(2.0 * pow(max(dot(normalize(vec3(0.0) - pos), reflect(-normalize(lightPos - pos), norm)), 0.0), 2.0), 0.0, 1.0) / 8.0;
spec = clamp(spec, 0.0, 0.9);
color = mix(vec4(vec3(0.0), 1.0), color, .8 + .3 * diffuse);
vec4 specColor = vec4(mix(1.8, 2.0, specTexture) * gradientColor1, 1.0);
color = mix(color, specColor, spec);
float flecksSpec = 0.0;
lightPos = vec3(1.2, -.2, .5);
flecksSpec += clamp(2.0 * pow(max(dot(normalize(vec3(0.0) - pos), reflect(-normalize(lightPos - pos), norm)), 0.0), 2.0), 0.0, 1.0);
color = mix(color, specColor,
clamp(flecksSpec * abs(vNormal.z) * (flecksNormal.z), 0.2, 0.3) - .2
);
gl_FragColor = color * f_alpha;
}

View file

@ -2,15 +2,15 @@ uniform mat4 uMVPMatrix;
attribute vec2 a_TexCoordinate;
attribute vec3 a_Normal;
attribute vec4 vPosition;
attribute vec3 vPosition;
varying vec3 vNormal;
varying vec2 vUV;
varying vec3 modelViewVertex;
void main() {
modelViewVertex = vec3(uMVPMatrix * vPosition);
vUV = a_TexCoordinate;
vNormal = a_Normal;
gl_Position = uMVPMatrix * vPosition;
gl_Position = uMVPMatrix * vec4(vPosition, 1.0);
modelViewVertex = vec3(gl_Position);
}

View file

@ -45,6 +45,7 @@ public class ChatListItemAnimator extends DefaultItemAnimator {
public static final long DEFAULT_DURATION = 250;
public static final Interpolator DEFAULT_INTERPOLATOR = new CubicBezierInterpolator(0.19919472913616398, 0.010644531250000006, 0.27920937042459737, 0.91025390625);
@Nullable
private final ChatActivity activity;
private final RecyclerListView recyclerListView;
@ -347,7 +348,7 @@ public class ChatListItemAnimator extends DefaultItemAnimator {
if (!(chatMessageCell != null && chatMessageCell.getTransitionParams().ignoreAlpha)) {
holder.itemView.setAlpha(1);
}
if (chatMessageCell != null && activity.animatingMessageObjects.contains(chatMessageCell.getMessageObject())) {
if (activity != null && chatMessageCell != null && activity.animatingMessageObjects.contains(chatMessageCell.getMessageObject())) {
activity.animatingMessageObjects.remove(chatMessageCell.getMessageObject());
if (activity.getChatActivityEnterView().canShowMessageTransition()) {
if (chatMessageCell.getMessageObject().isVoice()) {

View file

@ -27,6 +27,7 @@ import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.Signature;
import android.content.res.AssetFileDescriptor;
import android.content.res.AssetManager;
import android.content.res.Configuration;
import android.database.Cursor;
import android.graphics.Bitmap;
@ -43,6 +44,9 @@ import android.graphics.Typeface;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.fonts.Font;
import android.graphics.fonts.FontFamily;
import android.graphics.fonts.SystemFonts;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
@ -50,7 +54,6 @@ import android.os.Environment;
import android.os.PowerManager;
import android.os.SystemClock;
import android.os.Vibrator;
import android.os.VibratorManager;
import android.provider.CallLog;
import android.provider.DocumentsContract;
import android.provider.MediaStore;
@ -90,7 +93,6 @@ import android.view.TextureView;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.ViewGroup;
import android.view.ViewParent;
import android.view.ViewPropertyAnimator;
import android.view.Window;
import android.view.WindowInsets;
@ -117,7 +119,9 @@ import androidx.annotation.RequiresApi;
import androidx.core.content.ContextCompat;
import androidx.core.content.FileProvider;
import androidx.core.graphics.ColorUtils;
import androidx.core.graphics.TypefaceCompatUtil;
import androidx.core.math.MathUtils;
import androidx.core.provider.FontRequest;
import androidx.core.widget.NestedScrollView;
import androidx.dynamicanimation.animation.DynamicAnimation;
import androidx.dynamicanimation.animation.SpringAnimation;
@ -160,8 +164,6 @@ import org.telegram.ui.Components.LayoutHelper;
import org.telegram.ui.Components.MotionBackgroundDrawable;
import org.telegram.ui.Components.PickerBottomLayout;
import org.telegram.ui.Components.PipRoundVideoView;
import org.telegram.ui.Components.PipVideoOverlay;
import org.telegram.ui.Components.RLottieImageView;
import org.telegram.ui.Components.RecyclerListView;
import org.telegram.ui.Components.ShareAlert;
import org.telegram.ui.Components.TypefaceSpan;
@ -233,6 +235,30 @@ public class AndroidUtilities {
public final static String TYPEFACE_MERRIWEATHER_BOLD = "fonts/mw_bold.ttf";
public final static String TYPEFACE_COURIER_NEW_BOLD = "fonts/courier_new_bold.ttf";
private static Typeface mediumTypeface;
public static Typeface bold() {
if (mediumTypeface == null) {
// so system Roboto with 500 weight doesn't support Hebrew (but 700 Roboto does)
// there must be a way to take system font 500 and fallback it with system font 700
// I haven't found the way, even through private API :(
// if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
// mediumTypeface = Typeface.create(null, 500, false);
//
// final String text = "Sample text";
// final TextPaint normalPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG);
// final TextPaint mediumPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG);
// mediumPaint.setTypeface(mediumTypeface);
// if (Math.abs(normalPaint.measureText(text) - mediumPaint.measureText(text)) < 0.1f) {
// mediumTypeface = Typeface.create(null, 700, false);
// }
// }
if (mediumTypeface == null) {
mediumTypeface = getTypeface(TYPEFACE_ROBOTO_MEDIUM);
}
}
return mediumTypeface;
}
private static final Hashtable<String, Typeface> typefaceCache = new Hashtable<>();
public static float touchSlop;
private static int prevOrientation = -10;
@ -512,7 +538,7 @@ public class AndroidUtilities {
ds.setColor(Theme.getColor(colorKey, resourcesProvider));
}
if (type == REPLACING_TAG_TYPE_LINKBOLD) {
ds.setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM));
ds.setTypeface(AndroidUtilities.bold());
}
}
@ -527,7 +553,7 @@ public class AndroidUtilities {
spannableStringBuilder.setSpan(new CharacterStyle() {
@Override
public void updateDrawState(TextPaint textPaint) {
textPaint.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf"));
textPaint.setTypeface(AndroidUtilities.bold());
int wasAlpha = textPaint.getAlpha();
textPaint.setColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlueText, resourcesProvider));
textPaint.setAlpha(wasAlpha);
@ -979,11 +1005,32 @@ public class AndroidUtilities {
}
public static boolean addLinksSafe(Spannable text, int mask, boolean internalOnly, boolean removeOldReplacements) {
if (text == null)
return false;
SpannableStringBuilder newText = new SpannableStringBuilder(text);
boolean success = doSafe(() -> addLinks(newText, mask, internalOnly, removeOldReplacements));
if (success) {
URLSpan[] oldSpans = text.getSpans(0, text.length(), URLSpan.class);
for (int i = 0; i < oldSpans.length; ++i) {
text.removeSpan(oldSpans[i]);
}
URLSpan[] newSpans = newText.getSpans(0, newText.length(), URLSpan.class);
for (int i = 0; i < newSpans.length; ++i) {
text.setSpan(newSpans[i], newText.getSpanStart(newSpans[i]), newText.getSpanEnd(newSpans[i]), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
}
}
return success;
}
public static boolean doSafe(Utilities.Callback0Return<Boolean> runnable) {
return doSafe(runnable, 200);
}
public static boolean doSafe(Utilities.Callback0Return<Boolean> runnable, int timeout) {
ExecutorService executor = Executors.newSingleThreadExecutor();
Callable<Boolean> task = () -> {
try {
return addLinks(newText, mask, internalOnly, removeOldReplacements);
return runnable.run();
} catch (Exception e) {
FileLog.e(e);
return false;
@ -993,7 +1040,7 @@ public class AndroidUtilities {
Future<Boolean> future = null;
try {
future = executor.submit(task);
success = future.get(200, TimeUnit.MILLISECONDS);
success = future.get(timeout, TimeUnit.MILLISECONDS);
} catch (TimeoutException ex) {
if (future != null) {
future.cancel(true);
@ -1003,18 +1050,7 @@ public class AndroidUtilities {
} finally {
executor.shutdownNow();
}
if (success && text != null) {
URLSpan[] oldSpans = text.getSpans(0, text.length(), URLSpan.class);
for (int i = 0; i < oldSpans.length; ++i) {
text.removeSpan(oldSpans[i]);
}
URLSpan[] newSpans = newText.getSpans(0, newText.length(), URLSpan.class);
for (int i = 0; i < newSpans.length; ++i) {
text.setSpan(newSpans[i], newText.getSpanStart(newSpans[i]), newText.getSpanEnd(newSpans[i]), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
}
return true;
}
return false;
return success;
}
@Deprecated // use addLinksSafe
@ -2967,7 +3003,7 @@ public class AndroidUtilities {
}
SpannableStringBuilder spannableStringBuilder = new SpannableStringBuilder(stringBuilder);
for (int a = 0; a < bolds.size() / 2; a++) {
spannableStringBuilder.setSpan(new TypefaceSpan(AndroidUtilities.getTypeface("fonts/rmedium.ttf")), bolds.get(a * 2), bolds.get(a * 2 + 1), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
spannableStringBuilder.setSpan(new TypefaceSpan(AndroidUtilities.bold()), bolds.get(a * 2), bolds.get(a * 2 + 1), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
}
return spannableStringBuilder;
} catch (Exception e) {
@ -3164,7 +3200,7 @@ public class AndroidUtilities {
}
public static boolean shouldShowClipboardToast() {
return (Build.VERSION.SDK_INT < Build.VERSION_CODES.S || !OneUIUtilities.hasBuiltInClipboardToasts()) && Build.VERSION.SDK_INT < 32 /* TODO: Update to TIRAMISU when compileSdkVersion would be 32 */;
return (Build.VERSION.SDK_INT < Build.VERSION_CODES.S || !OneUIUtilities.hasBuiltInClipboardToasts()) && Build.VERSION.SDK_INT < 32;
}
public static boolean addToClipboard(CharSequence str) {
@ -4638,8 +4674,18 @@ public class AndroidUtilities {
}
}
public static void lerp(int[] a, int[] b, float f, int[] to) {
if (to == null) return;
for (int i = 0; i < to.length; ++i) {
int av = a == null || i >= a.length ? 0 : a[i];
int bv = b == null || i >= b.length ? 0 : b[i];
to[i] = lerp(av, bv, f);
}
}
public static float cascade(float fullAnimationT, float position, float count, float waveLength) {
final float waveDuration = 1f / count * waveLength;
if (count <= 0) return fullAnimationT;
final float waveDuration = 1f / count * Math.min(waveLength, count);
final float waveOffset = position / count * (1f - waveDuration);
return MathUtils.clamp((fullAnimationT - waveOffset) / waveDuration, 0, 1);
}
@ -5308,7 +5354,30 @@ public class AndroidUtilities {
return null;
}
public static boolean hasDialogOnTop(BaseFragment fragment) {
if (fragment == null) return false;
if (fragment.visibleDialog != null) return true;
if (fragment.getParentLayout() == null) return false;
List<View> globalViews = allGlobalViews();
if (globalViews == null || globalViews.isEmpty()) return false;
View lastGlobalView = globalViews.get(globalViews.size() - 1);
return lastGlobalView != getRootView(fragment.getParentLayout().getView());
}
public static View getRootView(View v) {
View view = v;
while (view != null && view.getParent() instanceof View) {
view = ((View) view.getParent());
}
return view;
}
public static boolean makingGlobalBlurBitmap;
public static void makeGlobalBlurBitmap(Utilities.Callback<Bitmap> onBitmapDone, float amount) {
makeGlobalBlurBitmap(onBitmapDone, amount, (int) amount, null, null);
}
public static void makeGlobalBlurBitmap(Utilities.Callback<Bitmap> onBitmapDone, float downscale, int amount, View forView, List<View> exclude) {
if (onBitmapDone == null) {
return;
}
@ -5319,20 +5388,32 @@ public class AndroidUtilities {
onBitmapDone.run(null);
return;
}
makingGlobalBlurBitmap = true;
final List<View> finalViews = views;
//Utilities.themeQueue.postRunnable(() -> {
try {
int w = (int) (AndroidUtilities.displaySize.x / amount);
int h = (int) ((AndroidUtilities.displaySize.y + AndroidUtilities.statusBarHeight) / amount);
int w;
int h;
if (forView == null) {
w = (int) (AndroidUtilities.displaySize.x / downscale);
h = (int) ((AndroidUtilities.displaySize.y + AndroidUtilities.statusBarHeight) / downscale);
} else {
w = (int) (forView.getWidth() / downscale);
h = (int) (forView.getHeight() / downscale);
}
int[] location = new int[2];
Bitmap bitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
canvas.scale(1.0f / amount, 1.0f / amount);
if (forView != null) {
forView.getLocationOnScreen(location);
canvas.translate(-location[0] / downscale, -location[1] / downscale);
}
canvas.scale(1.0f / downscale, 1.0f / downscale);
canvas.drawColor(Theme.getColor(Theme.key_windowBackgroundWhite));
int[] location = new int[2];
for (int i = 0; i < finalViews.size(); ++i) {
View view = finalViews.get(i);
if (view instanceof PipRoundVideoView.PipFrameLayout || view instanceof PipRoundVideoView.PipFrameLayout) {
if (view instanceof PipRoundVideoView.PipFrameLayout || view instanceof PipRoundVideoView.PipFrameLayout || (exclude != null && exclude.contains(view))) {
continue;
}
@ -5346,7 +5427,7 @@ public class AndroidUtilities {
canvas.save();
view.getLocationOnScreen(location);
canvas.translate(location[0] / amount, location[1] / amount);
canvas.translate(location[0] / downscale, location[1] / downscale);
try {
view.draw(canvas);
} catch (Exception e) {
@ -5354,7 +5435,7 @@ public class AndroidUtilities {
}
canvas.restore();
}
Utilities.stackBlurBitmap(bitmap, Math.max((int) amount, Math.max(w, h) / 180));
Utilities.stackBlurBitmap(bitmap, Math.max(amount, Math.max(w, h) / 180));
// AndroidUtilities.runOnUIThread(() -> {
onBitmapDone.run(bitmap);
// });
@ -5363,6 +5444,8 @@ public class AndroidUtilities {
// AndroidUtilities.runOnUIThread(() -> {
onBitmapDone.run(null);
// });
} finally {
makingGlobalBlurBitmap = false;
}
// });
}
@ -5507,6 +5590,12 @@ public class AndroidUtilities {
}
}
public static boolean isSafeToShow(Context context) {
Activity activity = findActivity(context);
if (activity == null) return true;
return isActivityRunning(activity);
}
public static Pair<Integer, Integer> getImageOrientation(InputStream is) {
try {
return getImageOrientation(new ExifInterface(is));

View file

@ -6,6 +6,8 @@ public class AnimationNotificationsLocker {
int notificationsIndex = -1;
int globalNotificationsIndex = -1;
boolean disabled;
final int[] allowedNotifications;
public AnimationNotificationsLocker() {
@ -17,6 +19,9 @@ public class AnimationNotificationsLocker {
}
public void lock() {
if (disabled) {
return;
}
int currentAccount = UserConfig.selectedAccount;
if (this.currentAccount != currentAccount) {
NotificationCenter.getInstance(currentAccount).onAnimationFinish(notificationsIndex);
@ -28,8 +33,15 @@ public class AnimationNotificationsLocker {
}
public void unlock() {
if (disabled) {
return;
}
NotificationCenter.getInstance(currentAccount).onAnimationFinish(notificationsIndex);
NotificationCenter.getGlobalInstance().onAnimationFinish(globalNotificationsIndex);
}
public void disable() {
disabled = true;
}
}

View file

@ -28,6 +28,7 @@ import com.android.billingclient.api.QueryPurchasesParams;
import org.telegram.messenger.utils.BillingUtilities;
import org.telegram.tgnet.ConnectionsManager;
import org.telegram.tgnet.TLRPC;
import org.telegram.ui.ActionBar.AlertDialog;
import org.telegram.ui.PremiumPreviewFragment;
import java.text.NumberFormat;
@ -96,6 +97,7 @@ public class BillingController implements PurchasesUpdatedListener, BillingClien
return formatCurrency(amount, currency, exp, false);
}
private static NumberFormat currencyInstance;
public String formatCurrency(long amount, String currency, int exp, boolean rounded) {
if (currency == null || currency.isEmpty()) {
return String.valueOf(amount);
@ -105,12 +107,14 @@ public class BillingController implements PurchasesUpdatedListener, BillingClien
}
Currency cur = Currency.getInstance(currency);
if (cur != null) {
NumberFormat numberFormat = NumberFormat.getCurrencyInstance();
numberFormat.setCurrency(cur);
if (rounded) {
return numberFormat.format(Math.round(amount / Math.pow(10, exp)));
if (currencyInstance == null) {
currencyInstance = NumberFormat.getCurrencyInstance();
}
return numberFormat.format(amount / Math.pow(10, exp));
currencyInstance.setCurrency(cur);
if (rounded) {
return currencyInstance.format(Math.round(amount / Math.pow(10, exp)));
}
return currencyInstance.format(amount / Math.pow(10, exp));
}
return amount + " " + currency;
}
@ -187,7 +191,7 @@ public class BillingController implements PurchasesUpdatedListener, BillingClien
return;
}
if (paymentPurpose instanceof TLRPC.TL_inputStorePaymentGiftPremium && !checkedConsume) {
if ((paymentPurpose instanceof TLRPC.TL_inputStorePaymentGiftPremium || paymentPurpose instanceof TLRPC.TL_inputStorePaymentStars) && !checkedConsume) {
queryPurchases(BillingClient.ProductType.INAPP, (billingResult, list) -> {
if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK) {
Runnable callback = () -> launchBillingFlow(activity, accountInstance, paymentPurpose, productDetails, subscriptionUpdateParams, true);
@ -281,8 +285,13 @@ public class BillingController implements PurchasesUpdatedListener, BillingClien
req.receipt.data = purchase.getOriginalJson();
req.purpose = payload.second;
final AlertDialog progressDialog = new AlertDialog(ApplicationLoader.applicationContext, AlertDialog.ALERT_TYPE_SPINNER);
AndroidUtilities.runOnUIThread(() -> progressDialog.showDelayed(500));
AccountInstance acc = payload.first;
acc.getConnectionsManager().sendRequest(req, (response, error) -> {
AndroidUtilities.runOnUIThread(progressDialog::dismiss);
requestingTokens.remove(purchase.getPurchaseToken());
if (response instanceof TLRPC.Updates) {
@ -303,7 +312,7 @@ public class BillingController implements PurchasesUpdatedListener, BillingClien
}
NotificationCenter.getGlobalInstance().postNotificationNameOnUIThread(NotificationCenter.billingConfirmPurchaseError, req, error);
}
}, ConnectionsManager.RequestFlagFailOnServerErrors | ConnectionsManager.RequestFlagInvokeAfter);
}, ConnectionsManager.RequestFlagFailOnServerErrors | ConnectionsManager.RequestFlagFailOnServerErrorsExceptFloodWait | ConnectionsManager.RequestFlagInvokeAfter);
} else {
consumeGiftPurchase(purchase, payload.second);
}
@ -318,6 +327,7 @@ public class BillingController implements PurchasesUpdatedListener, BillingClien
private void consumeGiftPurchase(Purchase purchase, TLRPC.InputStorePaymentPurpose purpose) {
if (purpose instanceof TLRPC.TL_inputStorePaymentGiftPremium
|| purpose instanceof TLRPC.TL_inputStorePaymentPremiumGiftCode
|| purpose instanceof TLRPC.TL_inputStorePaymentStars
|| purpose instanceof TLRPC.TL_inputStorePaymentPremiumGiveaway) {
billingClient.consumeAsync(
ConsumeParams.newBuilder()
@ -340,6 +350,11 @@ public class BillingController implements PurchasesUpdatedListener, BillingClien
AndroidUtilities.runOnUIThread(() -> startConnection(), delay);
}
private ArrayList<Runnable> setupListeners = new ArrayList<>();
public void whenSetuped(Runnable listener) {
setupListeners.add(listener);
}
private int triesLeft = 0;
@Override
@ -355,6 +370,12 @@ public class BillingController implements PurchasesUpdatedListener, BillingClien
}
queryPurchases(BillingClient.ProductType.INAPP, this::onPurchasesUpdated);
queryPurchases(BillingClient.ProductType.SUBS, this::onPurchasesUpdated);
if (!setupListeners.isEmpty()) {
for (int i = 0; i < setupListeners.size(); ++i) {
AndroidUtilities.runOnUIThread(setupListeners.get(i));
}
setupListeners.clear();
}
} else {
if (!isDisconnected) {
switchToInvoice();
@ -396,4 +417,22 @@ public class BillingController implements PurchasesUpdatedListener, BillingClien
}
}
}
public static String getResponseCodeString(int code) {
switch (code) {
case -3: return "SERVICE_TIMEOUT";
case -2: return "FEATURE_NOT_SUPPORTED";
case -1: return "SERVICE_DISCONNECTED";
case 0: return "OK";
case 1: return "USER_CANCELED";
case 2: return "SERVICE_UNAVAILABLE";
case 3: return "BILLING_UNAVAILABLE";
case 4: return "ITEM_UNAVAILABLE";
case 5: return "DEVELOPER_ERROR";
case 6: return "ERROR";
case 7: return "ITEM_ALREADY_OWNED";
case 8: return "ITEM_NOT_OWNED";
}
return null;
}
}

View file

@ -1,5 +1,7 @@
package org.telegram.messenger;
import android.content.SharedPreferences;
import android.os.Looper;
import android.util.Pair;
import java.util.ArrayList;
@ -21,11 +23,31 @@ public abstract class CacheFetcher<Args, R> {
// Implement this function
}
public CacheFetcher() {
this(4 * 60 * 1000);
}
public CacheFetcher(int timeout) {
requestRemotelyTimeout = timeout;
}
protected boolean useCache(Args arguments) {
return true;
}
private final long requestRemotelyTimeout = 4 * 60 * 1000;
protected boolean emitLocal(Args arguments) {
return false;
}
protected boolean saveLastTimeRequested() {
return false;
}
protected long getSavedLastTimeRequested(int hashCode) { return 0; }
protected void setSavedLastTimeRequested(int hashCode, long time) {}
private final long requestRemotelyTimeout;
private HashMap<Pair<Integer, Args>, R> cachedResults;
private HashMap<Pair<Integer, Args>, ArrayList<Utilities.Callback<R>>> loadingCallbacks;
@ -50,24 +72,28 @@ public abstract class CacheFetcher<Args, R> {
saveCallback(key, onResult);
getLocal(currentAccount, arguments, (hash, data) -> {
if (shouldRequest(key)) {
if (data != null && emitLocal(arguments)) {
cacheResult(key, data);
callCallbacks(key, data, false);
}
getRemote(currentAccount, arguments, hash, (notModified, remoteData, newHash, requestSuccess) -> {
if (requestSuccess) {
saveLastRequested(key);
}
if (notModified) {
cacheResult(key, data);
callCallbacks(key, data);
callCallbacks(key, data, true);
} else {
if (remoteData != null) {
setLocal(currentAccount, arguments, remoteData, newHash);
cacheResult(key, remoteData);
}
callCallbacks(key, remoteData);
callCallbacks(key, remoteData, true);
}
});
} else {
cacheResult(key, data);
callCallbacks(key, data);
callCallbacks(key, data, true);
}
});
}
@ -93,11 +119,18 @@ public abstract class CacheFetcher<Args, R> {
if (lastRequestedRemotely == null) {
lastRequestedRemotely = new HashMap<>();
}
lastRequestedRemotely.put(key, System.currentTimeMillis());
final long now = System.currentTimeMillis();
lastRequestedRemotely.put(key, now);
if (saveLastTimeRequested()) {
setSavedLastTimeRequested(key.hashCode(), now);
}
}
private boolean shouldRequest(Pair<Integer, Args> key) {
Long lastRequested = lastRequestedRemotely != null ? lastRequestedRemotely.get(key) : null;
if (saveLastTimeRequested() && lastRequested == null) {
lastRequested = getSavedLastTimeRequested(key.hashCode());
}
return lastRequested == null || System.currentTimeMillis() - lastRequested >= requestRemotelyTimeout;
}
@ -105,7 +138,11 @@ public abstract class CacheFetcher<Args, R> {
if (lastRequestedRemotely == null) {
return;
}
lastRequestedRemotely.remove(new Pair<>(currentAccount, args));
Pair<Integer, Args> key = new Pair<>(currentAccount, args);
lastRequestedRemotely.remove(key);
if (saveLastTimeRequested()) {
setSavedLastTimeRequested(key.hashCode(), 0);
}
}
private boolean isLoading(Pair<Integer, Args> key) {
@ -116,33 +153,38 @@ public abstract class CacheFetcher<Args, R> {
if (callback == null) {
return;
}
if (loadingCallbacks == null) {
loadingCallbacks = new HashMap<>();
}
ArrayList<Utilities.Callback<R>> callbacks = loadingCallbacks.get(key);
if (callbacks == null) {
loadingCallbacks.put(key, callbacks = new ArrayList<>());
}
callbacks.add(callback);
AndroidUtilities.runOnUIThread(() -> {
if (loadingCallbacks == null) {
loadingCallbacks = new HashMap<>();
}
ArrayList<Utilities.Callback<R>> callbacks = loadingCallbacks.get(key);
if (callbacks == null) {
loadingCallbacks.put(key, callbacks = new ArrayList<>());
}
callbacks.add(callback);
});
}
private void callCallbacks(Pair<Integer, Args> key, R result) {
if (loadingCallbacks == null) {
return;
}
final ArrayList<Utilities.Callback<R>> callbacks = loadingCallbacks.get(key);
if (callbacks == null) {
return;
}
private void callCallbacks(Pair<Integer, Args> key, R result, boolean remove) {
AndroidUtilities.runOnUIThread(() -> {
if (loadingCallbacks == null) {
return;
}
final ArrayList<Utilities.Callback<R>> callbacks = loadingCallbacks.get(key);
if (callbacks == null) {
return;
}
for (Utilities.Callback<R> callback: callbacks) {
callback.run(result);
}
callbacks.clear();
});
if (remove) {
callbacks.clear();
}
loadingCallbacks.remove(key);
if (remove) {
loadingCallbacks.remove(key);
}
});
}
}

View file

@ -43,17 +43,19 @@ public class ChannelBoostsController {
} else {
BaseFragment fragment = LaunchActivity.getLastFragment();
if (error != null && fragment != null && "CHANNEL_PRIVATE".equals(error.text)) {
AlertDialog.Builder builder = new AlertDialog.Builder(fragment.getContext(), fragment.getResourceProvider());
builder.setTitle(LocaleController.getString(R.string.AppName));
Map<String, Integer> colorsReplacement = new HashMap<>();
colorsReplacement.put("info1.**", Theme.getColor(Theme.key_dialogTopBackground));
colorsReplacement.put("info2.**", Theme.getColor(Theme.key_dialogTopBackground));
builder.setTopAnimation(R.raw.not_available, AlertsCreator.NEW_DENY_DIALOG_TOP_ICON_SIZE, false, Theme.getColor(Theme.key_dialogTopBackground), colorsReplacement);
builder.setTopAnimationIsNew(true);
builder.setTitle(LocaleController.getString(R.string.ChannelPrivate));
builder.setMessage(LocaleController.getString("ChannelCantOpenPrivate2", R.string.ChannelCantOpenPrivate2));
builder.setPositiveButton(LocaleController.getString(R.string.Close), null);
builder.show();
if (!(LaunchActivity.instance != null && LaunchActivity.instance.isFinishing())) {
AlertDialog.Builder builder = new AlertDialog.Builder(fragment.getContext(), fragment.getResourceProvider());
builder.setTitle(LocaleController.getString(R.string.AppName));
Map<String, Integer> colorsReplacement = new HashMap<>();
colorsReplacement.put("info1.**", Theme.getColor(Theme.key_dialogTopBackground));
colorsReplacement.put("info2.**", Theme.getColor(Theme.key_dialogTopBackground));
builder.setTopAnimation(R.raw.not_available, AlertsCreator.NEW_DENY_DIALOG_TOP_ICON_SIZE, false, Theme.getColor(Theme.key_dialogTopBackground), colorsReplacement);
builder.setTopAnimationIsNew(true);
builder.setTitle(LocaleController.getString(R.string.ChannelPrivate));
builder.setMessage(LocaleController.getString("ChannelCantOpenPrivate2", R.string.ChannelCantOpenPrivate2));
builder.setPositiveButton(LocaleController.getString(R.string.Close), null);
builder.show();
}
} else {
BulletinFactory.global().showForError(error);
}

View file

@ -2975,7 +2975,7 @@ public class ContactsController extends BaseController {
TLRPC.Chat chat = (TLRPC.Chat) object;
return chat.title;
} else {
return "DELETED";
return LocaleController.getString(R.string.HiddenName);
}
}

View file

@ -1504,6 +1504,18 @@ public class DatabaseMigrationHelper {
version = 153;
}
if (version == 153) {
database.executeFast("CREATE TABLE effects(data BLOB)").stepThis().dispose();
database.executeFast("PRAGMA user_version = 154").stepThis().dispose();
version = 154;
}
if (version == 154) {
database.executeFast("CREATE TABLE fact_checks(hash INTEGER PRIMARY KEY, data BLOB, expires INTEGER);").stepThis().dispose();
database.executeFast("PRAGMA user_version = 155").stepThis().dispose();
version = 155;
}
return version;
}

View file

@ -32,6 +32,7 @@ import org.checkerframework.checker.units.qual.A;
import org.telegram.tgnet.TLRPC;
import org.telegram.ui.Components.AnimatedEmojiDrawable;
import org.telegram.ui.Components.AnimatedEmojiSpan;
import org.telegram.ui.Components.ColoredImageSpan;
import java.io.InputStream;
import java.util.ArrayList;
@ -586,13 +587,14 @@ public class Emoji {
}
AnimatedEmojiSpan[] animatedEmojiSpans = s.getSpans(0, s.length(), AnimatedEmojiSpan.class);
ColoredImageSpan[] imageSpans = s.getSpans(0, s.length(), ColoredImageSpan.class);
EmojiSpan span;
Drawable drawable;
int limitCount = SharedConfig.getDevicePerformanceClass() >= SharedConfig.PERFORMANCE_CLASS_HIGH ? 100 : 50;
for (int i = 0; i < emojis.size(); ++i) {
try {
EmojiSpanRange emojiRange = emojis.get(i);
if (animatedEmojiSpans != null) {
if (animatedEmojiSpans != null && animatedEmojiSpans.length > 0) {
boolean hasAnimated = false;
for (int j = 0; j < animatedEmojiSpans.length; ++j) {
AnimatedEmojiSpan animatedSpan = animatedEmojiSpans[j];
@ -605,6 +607,19 @@ public class Emoji {
continue;
}
}
if (imageSpans != null && imageSpans.length > 0) {
boolean hasImage = false;
for (int j = 0; j < imageSpans.length; ++j) {
ColoredImageSpan imageSpan = imageSpans[j];
if (imageSpan != null && s.getSpanStart(imageSpan) == emojiRange.start && s.getSpanEnd(imageSpan) == emojiRange.end) {
hasImage = true;
break;
}
}
if (hasImage) {
continue;
}
}
drawable = Emoji.getEmojiDrawable(emojiRange.code);
if (drawable != null) {
span = new EmojiSpan(drawable, alignment, fontMetrics);

View file

@ -0,0 +1,590 @@
package org.telegram.messenger;
import static org.telegram.messenger.AndroidUtilities.dp;
import static org.telegram.messenger.LocaleController.getString;
import android.app.Activity;
import android.content.Context;
import android.content.DialogInterface;
import android.graphics.Canvas;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.text.Editable;
import android.text.InputType;
import android.text.SpannableStringBuilder;
import android.text.Spanned;
import android.text.TextUtils;
import android.text.TextWatcher;
import android.util.LongSparseArray;
import android.util.TypedValue;
import android.view.ActionMode;
import android.view.Gravity;
import android.view.HapticFeedbackConstants;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.View;
import android.view.inputmethod.EditorInfo;
import android.widget.LinearLayout;
import android.widget.TextView;
import androidx.annotation.NonNull;
import org.telegram.SQLite.SQLiteCursor;
import org.telegram.SQLite.SQLiteDatabase;
import org.telegram.SQLite.SQLitePreparedStatement;
import org.telegram.tgnet.ConnectionsManager;
import org.telegram.tgnet.NativeByteBuffer;
import org.telegram.tgnet.TLObject;
import org.telegram.tgnet.TLRPC;
import org.telegram.ui.ActionBar.AlertDialog;
import org.telegram.ui.ActionBar.AlertDialogDecor;
import org.telegram.ui.ActionBar.BaseFragment;
import org.telegram.ui.ActionBar.Theme;
import org.telegram.ui.Components.AnimatedColor;
import org.telegram.ui.Components.AnimatedTextView;
import org.telegram.ui.Components.BulletinFactory;
import org.telegram.ui.Components.CubicBezierInterpolator;
import org.telegram.ui.Components.EditTextCaption;
import org.telegram.ui.Components.LayoutHelper;
import org.telegram.ui.Components.SizeNotifierFrameLayout;
import org.telegram.ui.Components.TypefaceSpan;
import org.telegram.ui.LaunchActivity;
import java.util.ArrayList;
import java.util.HashMap;
public class FactCheckController {
private static volatile FactCheckController[] Instance = new FactCheckController[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 FactCheckController getInstance(int num) {
FactCheckController localInstance = Instance[num];
if (localInstance == null) {
synchronized (lockObjects[num]) {
localInstance = Instance[num];
if (localInstance == null) {
Instance[num] = localInstance = new FactCheckController(num);
}
}
}
return localInstance;
}
public final int currentAccount;
private FactCheckController(int account) {
currentAccount = account;
}
private final LongSparseArray<TLRPC.TL_factCheck> localCache = new LongSparseArray<>();
private final LongSparseArray<HashMap<Key, Utilities.Callback<TLRPC.TL_factCheck>>> toload = new LongSparseArray<>();
private final ArrayList<Key> loading = new ArrayList<>();
public TLRPC.TL_factCheck getFactCheck(MessageObject messageObject) {
if (messageObject == null || messageObject.messageOwner == null) {
return null;
}
if (messageObject.messageOwner.factcheck == null) {
return null;
}
if (!messageObject.messageOwner.factcheck.need_check) {
if (localCache.get(messageObject.messageOwner.factcheck.hash) == null) {
localCache.put(messageObject.messageOwner.factcheck.hash, messageObject.messageOwner.factcheck);
saveToDatabase(messageObject.messageOwner.factcheck);
}
return messageObject.messageOwner.factcheck;
}
final Key key = Key.of(messageObject);
if (key == null) return null;
if (key.messageId < 0) return null;
TLRPC.TL_factCheck cached = localCache.get(key.hash);
if (cached != null) {
return messageObject.messageOwner.factcheck = cached;
}
if (loading.contains(key)) {
return messageObject.messageOwner.factcheck;
}
HashMap<Key, Utilities.Callback<TLRPC.TL_factCheck>> msgs = toload.get(key.dialogId);
if (msgs == null) {
toload.put(key.dialogId, msgs = new HashMap<>());
}
if (!msgs.containsKey(key)) {
msgs.put(key, factCheck -> {
localCache.put(key.hash, factCheck);
messageObject.messageOwner.factcheck = factCheck;
});
scheduleLoadMissing();
}
return messageObject.messageOwner.factcheck;
}
private void scheduleLoadMissing() {
AndroidUtilities.cancelRunOnUIThread(loadMissingRunnable);
AndroidUtilities.runOnUIThread(loadMissingRunnable, 80);
}
private final Runnable loadMissingRunnable = this::loadMissing;
private void loadMissing() {
for (int i = 0; i < this.toload.size(); ++i) {
long dialogId = this.toload.keyAt(i);
HashMap<Key, Utilities.Callback<TLRPC.TL_factCheck>> msgs = this.toload.valueAt(i);
this.toload.removeAt(i);
i--;
ArrayList<Key> keys = new ArrayList<>(msgs.keySet());
loading.addAll(keys);
getFromDatabase(keys, results -> {
TLRPC.TL_getFactCheck req = new TLRPC.TL_getFactCheck();
req.peer = MessagesController.getInstance(currentAccount).getInputPeer(dialogId);
ArrayList<Key> reqKeys = new ArrayList<>();
int processed = 0;
for (int k = 0; k < results.size(); ++k) {
final Key key = keys.get(k);
final TLRPC.TL_factCheck factCheck = results.get(k);
if (factCheck == null) {
reqKeys.add(key);
req.msg_id.add(key.messageId);
} else {
loading.remove(key);
final Utilities.Callback<TLRPC.TL_factCheck> callback = msgs.get(key);
if (callback != null) {
callback.run(factCheck);
processed++;
}
}
}
if (processed > 0) {
NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.factCheckLoaded);
}
if (!req.msg_id.isEmpty()) {
ConnectionsManager.getInstance(currentAccount).sendRequest(req, (res, err) -> AndroidUtilities.runOnUIThread(() -> {
ArrayList<TLRPC.TL_factCheck> factChecks = new ArrayList<>();
if (res instanceof TLRPC.Vector) {
ArrayList<Object> objects = ((TLRPC.Vector) res).objects;
for (int k = 0; k < objects.size(); ++k) {
if (objects.get(k) instanceof TLRPC.TL_factCheck) {
factChecks.add((TLRPC.TL_factCheck) objects.get(k));
}
}
}
HashMap<Integer, TLRPC.TL_factCheck> map = new HashMap<>();
for (int k = 0; k < Math.min(req.msg_id.size(), factChecks.size()); ++k) {
final int messageId = req.msg_id.get(k);
final TLRPC.TL_factCheck factCheck = factChecks.get(k);
map.put(messageId, factCheck);
}
int processed2 = 0;
for (int k = 0; k < req.msg_id.size(); ++k) {
final Key key = reqKeys.get(k);
final int messageId = req.msg_id.get(k);
final TLRPC.TL_factCheck factCheck = map.get(messageId);
final Utilities.Callback<TLRPC.TL_factCheck> callback = msgs.get(key);
if (factCheck != null && !factCheck.need_check && callback != null) {
callback.run(factCheck);
processed2++;
loading.remove(key);
}
}
if (processed2 > 0) {
NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.factCheckLoaded);
}
}));
}
});
}
this.toload.clear();
}
private static class Key {
public final long dialogId;
public final int messageId;
public final long hash;
private Key(long did, int mid, long hash) {
dialogId = did;
messageId = mid;
this.hash = hash;
}
@Override
public int hashCode() {
return Long.hashCode(hash);
}
public static Key of(MessageObject msg) {
if (msg == null) return null;
if (msg.messageOwner == null) return null;
if (msg.messageOwner.factcheck == null) return null;
return new Key(msg.getDialogId(), msg.getId(), msg.messageOwner.factcheck.hash);
}
}
private void getFromDatabase(ArrayList<Key> keys, Utilities.Callback<ArrayList<TLRPC.TL_factCheck>> whenGot) {
if (whenGot == null) {
return;
}
if (keys == null || keys.isEmpty()) {
whenGot.run(new ArrayList<>());
return;
}
final MessagesStorage storage = MessagesStorage.getInstance(currentAccount);
storage.getStorageQueue().postRunnable(() -> {
ArrayList<TLRPC.TL_factCheck> result = new ArrayList<>();
SQLiteCursor cursor = null;
try {
SQLiteDatabase db = storage.getDatabase();
ArrayList<Long> hashes = new ArrayList<>();
for (Key key : keys) {
hashes.add(key.hash);
result.add(null);
}
cursor = db.queryFinalized("SELECT data FROM fact_checks WHERE hash IN (" + TextUtils.join(", ", hashes) + ")");
while (cursor.next()) {
NativeByteBuffer data = cursor.byteBufferValue(0);
TLRPC.TL_factCheck factCheck = TLRPC.TL_factCheck.TLdeserialize(data, data.readInt32(false), false);
if (factCheck == null) {
continue;
}
int index = -1;
for (int i = 0; i < keys.size(); ++i) {
final Key key = keys.get(i);
if (factCheck.hash == key.hash) {
index = i;
}
}
if (index >= 0 && index < result.size()) {
result.set(index, factCheck);
}
break;
}
cursor.dispose();
cursor = null;
} catch (Exception e) {
FileLog.e(e);
} finally {
if (cursor != null) {
cursor.dispose();
}
}
AndroidUtilities.runOnUIThread(() -> {
whenGot.run(result);
});
});
}
private void saveToDatabase(TLRPC.TL_factCheck factCheck) {
if (factCheck == null) return;
final MessagesStorage storage = MessagesStorage.getInstance(currentAccount);
storage.getStorageQueue().postRunnable(() -> {
SQLitePreparedStatement state = null;
try {
SQLiteDatabase db = storage.getDatabase();
state = db.executeFast("REPLACE INTO fact_checks VALUES(?, ?, ?)");
state.requery();
state.bindLong(1, factCheck.hash);
NativeByteBuffer buffer = new NativeByteBuffer(factCheck.getObjectSize());
factCheck.serializeToStream(buffer);
state.bindByteBuffer(2, buffer);
state.bindLong(3, System.currentTimeMillis() + 1000 * 60 * 60 * 24 * 60);
state.step();
state.dispose();
state = null;
} catch (Exception e) {
FileLog.e(e);
} finally {
if (state != null) {
state.dispose();
}
}
});
clearExpiredInDatabase();
}
private boolean clearedExpiredInDatabase;
private void clearExpiredInDatabase() {
if (clearedExpiredInDatabase) return;
clearedExpiredInDatabase = true;
final MessagesStorage storage = MessagesStorage.getInstance(currentAccount);
storage.getStorageQueue().postRunnable(() -> {
try {
SQLiteDatabase db = storage.getDatabase();
db.executeFast("DELETE FROM fact_checks WHERE expires > " + System.currentTimeMillis()).stepThis().dispose();
} catch (Exception e) {
FileLog.e(e);
}
});
}
private static AlertDialog currentDialog;
public void openFactCheckEditor(Context context, Theme.ResourcesProvider resourcesProvider, MessageObject messageObject, boolean forceNotAdaptive) {
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);
}
TextView[] positiveButton = new TextView[1];
final boolean creating = messageObject == null || messageObject.messageOwner == null || messageObject.messageOwner.factcheck == null;
builder.setTitle(getString(R.string.FactCheckDialog));
final int MAX_LENGTH = MessagesController.getInstance(currentAccount).factcheckLengthLimit;
EditTextCaption editText = new EditTextCaption(context, resourcesProvider) {
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_LENGTH - text.length();
limit.cancelAnimation();
limit.setText(limitCount > 4 ? "" : "" + limitCount);
}
}
@Override
protected void extendActionMode(ActionMode actionMode, Menu menu) {
if (menu.findItem(R.id.menu_bold) != null) {
return;
}
if (Build.VERSION.SDK_INT >= 23) {
menu.removeItem(android.R.id.shareText);
}
int order = 6;
SpannableStringBuilder stringBuilder = new SpannableStringBuilder(getString("Bold", R.string.Bold));
stringBuilder.setSpan(new TypefaceSpan(AndroidUtilities.bold()), 0, stringBuilder.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
menu.add(R.id.menu_groupbolditalic, R.id.menu_bold, order++, stringBuilder);
stringBuilder = new SpannableStringBuilder(getString("Italic", R.string.Italic));
stringBuilder.setSpan(new TypefaceSpan(AndroidUtilities.getTypeface("fonts/ritalic.ttf")), 0, stringBuilder.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
menu.add(R.id.menu_groupbolditalic, R.id.menu_italic, order++, stringBuilder);
menu.add(R.id.menu_groupbolditalic, R.id.menu_link, order++, getString("CreateLink", R.string.CreateLink));
menu.add(R.id.menu_groupbolditalic, R.id.menu_regular, order++, getString("Regular", R.string.Regular));
}
@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);
}
};
editText.lineYFix = true;
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() > MAX_LENGTH) {
AndroidUtilities.shakeView(editText);
return true;
}
TLRPC.TL_textWithEntities textObj = new TLRPC.TL_textWithEntities();
CharSequence[] message = new CharSequence[] { editText.getText() };
textObj.entities = MediaDataController.getInstance(currentAccount).getEntities(message, true);
textObj.text = message[0] == null ? "" : message[0].toString();
applyFactCheck(messageObject, textObj, creating);
if (dialog[0] != null) {
dialog[0].dismiss();
}
if (dialog[0] == currentDialog) {
currentDialog = null;
}
if (currentFocus != null) {
currentFocus.requestFocus();
}
return true;
}
return false;
}
});
MediaDataController.getInstance(currentAccount).fetchNewEmojiKeywords(AndroidUtilities.getCurrentKeyboardLanguage(), true);
editText.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 18);
editText.setTextColor(Theme.getColor(Theme.key_dialogTextBlack, resourcesProvider));
editText.setHintColor(Theme.getColor(Theme.key_groupcreate_hintText, resourcesProvider));
editText.setHintText(getString(R.string.FactCheckPlaceholder));
editText.setFocusable(true);
editText.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_FLAG_MULTI_LINE | InputType.TYPE_TEXT_FLAG_CAP_SENTENCES);
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, dp(6), 0, dp(6));
TLRPC.TL_factCheck factCheck = messageObject.getFactCheck();
if (factCheck != null && factCheck.text != null) {
CharSequence text = SpannableStringBuilder.valueOf(factCheck.text.text);
MessageObject.addEntitiesToText(text, factCheck.text.entities, false, true, false, false);
editText.setText(text);
}
editText.addTextChangedListener(new TextWatcher() {
boolean ignoreTextChange;
@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 (ignoreTextChange) {
return;
}
if (s.length() > MAX_LENGTH) {
ignoreTextChange = true;
s.delete(MAX_LENGTH, s.length());
AndroidUtilities.shakeView(editText);
editText.performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP, HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING);
ignoreTextChange = false;
}
if (positiveButton[0] != null) {
final boolean showDone = s.length() > 0 || factCheck == null;
positiveButton[0].setText(getString(showDone ? R.string.Done : R.string.Remove));
positiveButton[0].setTextColor(Theme.getColor(showDone ? Theme.key_dialogButton : Theme.key_text_RedBold));
}
}
});
LinearLayout container = new LinearLayout(context);
container.setOrientation(LinearLayout.VERTICAL);
container.addView(editText, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, 24, 0, 24, 10));
builder.makeCustomMaxHeight();
builder.setView(container);
builder.setWidth(dp(292));
builder.setPositiveButton(getString(R.string.Done), (dialogInterface, i) -> {
String text = editText.getText().toString();
if (text.length() > MAX_LENGTH) {
AndroidUtilities.shakeView(editText);
return;
}
TLRPC.TL_textWithEntities textObj = new TLRPC.TL_textWithEntities();
CharSequence[] message = new CharSequence[] { editText.getText() };
textObj.entities = MediaDataController.getInstance(currentAccount).getEntities(message, true);
textObj.text = message[0] == null ? "" : message[0].toString();
applyFactCheck(messageObject, textObj, creating);
dialogInterface.dismiss();
});
builder.setNegativeButton(getString("Cancel", R.string.Cancel), (dialogInterface, i) -> {
dialogInterface.dismiss();
});
if (adaptive) {
dialog[0] = currentDialog = builder.create();
currentDialog.setOnDismissListener(d -> {
currentDialog = null;
currentFocus.requestFocus();
});
currentDialog.setOnShowListener(d -> {
editText.requestFocus();
AndroidUtilities.showKeyboard(editText);
});
currentDialog.showDelayed(250);
} else {
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);
View button = dialog[0].getButton(DialogInterface.BUTTON_POSITIVE);
if (button instanceof TextView) {
positiveButton[0] = (TextView) button;
}
editText.setSelection(editText.getText().length());
}
public void applyFactCheck(MessageObject messageObject, TLRPC.TL_textWithEntities text, boolean created) {
TLObject req;
if (text == null || TextUtils.isEmpty(text.text)) {
if (created) {
return;
}
TLRPC.TL_deleteFactCheck r = new TLRPC.TL_deleteFactCheck();
r.peer = MessagesController.getInstance(currentAccount).getInputPeer(messageObject.getDialogId());
r.msg_id = messageObject.getId();
req = r;
} else {
TLRPC.TL_editFactCheck r = new TLRPC.TL_editFactCheck();
r.peer = MessagesController.getInstance(currentAccount).getInputPeer(messageObject.getDialogId());
r.msg_id = messageObject.getId();
r.text = text;
req = r;
}
final Context context = LaunchActivity.instance != null ? LaunchActivity.instance : ApplicationLoader.applicationContext;
final AlertDialog progressDialog = new AlertDialog(context, AlertDialog.ALERT_TYPE_SPINNER);
progressDialog.showDelayed(320);
ConnectionsManager.getInstance(currentAccount).sendRequest(req, (res, err) -> AndroidUtilities.runOnUIThread(() -> {
if (res instanceof TLRPC.Updates) {
MessagesController.getInstance(currentAccount).processUpdates((TLRPC.Updates) res, false);
BaseFragment fragment = LaunchActivity.getSafeLastFragment();
if (fragment != null) {
final boolean deleted = text == null || TextUtils.isEmpty(text.text);
if (deleted || !created) {
BulletinFactory.of(fragment).createSimpleBulletin(deleted ? R.raw.ic_delete : R.raw.contact_check, getString(deleted ? R.string.FactCheckDeleted : R.string.FactCheckEdited)).show();
}
}
}
progressDialog.dismiss();
}));
}
}

View file

@ -880,6 +880,9 @@ public class FileLoadOperation {
return wasPaused;
}
if (location == null && webLocation == null) {
if (BuildVars.DEBUG_VERSION) {
FileLog.d("loadOperation: no location, failing");
}
onFail(true, 0);
return false;
}

View file

@ -312,6 +312,7 @@ public class FileLoader extends BaseController {
String key = getAttachFileName(document);
if (loadingVideos.containsKey(key + (player ? "" : "p"))) {
loadingVideos.put(key + (player ? "p" : ""), true);
getNotificationCenter().postNotificationName(NotificationCenter.videoLoadingStateChanged, key);
}
}

View file

@ -13,6 +13,7 @@ import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CountDownLatch;
public class FilePathDatabase {
@ -26,6 +27,8 @@ public class FilePathDatabase {
private File cacheFile;
private File shmCacheFile;
private final ConcurrentHashMap<String, String> cache = new ConcurrentHashMap<>();
private final static int LAST_DB_VERSION = 7;
private final static String DATABASE_NAME = "file_to_path";
@ -159,6 +162,15 @@ public class FilePathDatabase {
}
public String getPath(long documentId, int dc, int type, boolean useQueue) {
final long start = System.currentTimeMillis();
final String key = documentId + "_" + dc + "_" + type;
String path = cache.get(key);
if (path != null) {
if (BuildVars.DEBUG_VERSION) {
FileLog.d("get file path cached id=" + documentId + " dc=" + dc + " type=" + type + " path=" + path + " in " + (System.currentTimeMillis() - start) + "ms");
}
return path;
}
if (useQueue) {
if (BuildVars.DEBUG_PRIVATE_VERSION) {
if (dispatchQueue != null && dispatchQueue.getHandler() != null && Thread.currentThread() == dispatchQueue.getHandler().getLooper().getThread()) {
@ -178,7 +190,7 @@ public class FilePathDatabase {
if (cursor.next()) {
res[0] = cursor.stringValue(0);
if (BuildVars.DEBUG_VERSION) {
FileLog.d("get file path id=" + documentId + " dc=" + dc + " type=" + type + " path=" + res[0]);
FileLog.d("get file path id=" + documentId + " dc=" + dc + " type=" + type + " path=" + res[0] + " in " + (System.currentTimeMillis() - start) + "ms");
}
}
} catch (Throwable e) {
@ -195,6 +207,9 @@ public class FilePathDatabase {
syncLatch.await();
} catch (Exception ignore) {
}
if (res[0] != null) {
cache.put(key, res[0]);
}
return res[0];
} else {
if (database == null) {
@ -207,7 +222,7 @@ public class FilePathDatabase {
if (cursor.next()) {
res = cursor.stringValue(0);
if (BuildVars.DEBUG_VERSION) {
FileLog.d("get file path id=" + documentId + " dc=" + dc + " type=" + type + " path=" + res);
FileLog.d("get file path id=" + documentId + " dc=" + dc + " type=" + type + " path=" + res + " in " + (System.currentTimeMillis() - start) + "ms");
}
}
} catch (SQLiteException e) {
@ -217,6 +232,9 @@ public class FilePathDatabase {
cursor.dispose();
}
}
if (res != null) {
cache.put(key, res);
}
return res;
}
}
@ -268,8 +286,10 @@ public class FilePathDatabase {
state.bindInteger(5, flags);
state.step();
state.dispose();
cache.put(id + "_" + dc + "_" + type, path);
} else {
database.executeFast("DELETE FROM paths WHERE document_id = " + id + " AND dc_id = " + dc + " AND type = " + type).stepThis().dispose();
cache.remove(id + "_" + dc + "_" + type);
}
} catch (SQLiteException e) {
FileLog.e(e);
@ -326,6 +346,7 @@ public class FilePathDatabase {
}
public void clear() {
cache.clear();
postRunnable(() -> {
ensureDatabaseCreated();
try {

View file

@ -248,7 +248,7 @@ public class FilesMigrationService extends Service {
title.setGravity(Gravity.START);
title.setTextColor(Theme.getColor(Theme.key_dialogTextBlack));
title.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 20);
title.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf"));
title.setTypeface(AndroidUtilities.bold());
title.setText(LocaleController.getString("MigrateOldFolderTitle", R.string.MigrateOldFolderTitle));
linearLayout.addView(title, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, 0, 21, 30, 21, 0));
@ -264,7 +264,7 @@ public class FilesMigrationService extends Service {
buttonTextView.setPadding(AndroidUtilities.dp(34), 0, AndroidUtilities.dp(34), 0);
buttonTextView.setGravity(Gravity.CENTER);
buttonTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14);
buttonTextView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf"));
buttonTextView.setTypeface(AndroidUtilities.bold());
buttonTextView.setText(LocaleController.getString("MigrateOldFolderButton", R.string.MigrateOldFolderButton));
buttonTextView.setTextColor(Theme.getColor(Theme.key_featuredStickers_buttonText));

View file

@ -0,0 +1,308 @@
package org.telegram.messenger;
import android.app.Activity;
import android.content.SharedPreferences;
import android.text.TextUtils;
import androidx.annotation.NonNull;
import org.telegram.tgnet.ConnectionsManager;
import org.telegram.tgnet.TLObject;
import org.telegram.tgnet.TLRPC;
import org.telegram.ui.ChatActivity;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Objects;
public class HashtagSearchController {
private static volatile HashtagSearchController[] Instance = new HashtagSearchController[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 HashtagSearchController getInstance(int num) {
HashtagSearchController localInstance = Instance[num];
if (localInstance == null) {
synchronized (lockObjects[num]) {
localInstance = Instance[num];
if (localInstance == null) {
Instance[num] = localInstance = new HashtagSearchController(num);
}
}
}
return localInstance;
}
public final int currentAccount;
private final SearchResult myMessagesSearch = new SearchResult();
private final SearchResult channelPostsSearch = new SearchResult();
private final SharedPreferences historyPreferences;
public final ArrayList<String> history = new ArrayList<>();
public final static int HISTORY_LIMIT = 100;
private HashtagSearchController(int currentAccount) {
this.currentAccount = currentAccount;
historyPreferences = ApplicationLoader.applicationContext.getSharedPreferences("hashtag_search_history" + currentAccount, Activity.MODE_PRIVATE);
loadHistoryFromPref();
}
private void loadHistoryFromPref() {
int count = historyPreferences.getInt("count", 0);
history.clear();
history.ensureCapacity(count);
for (int i = 0; i < count; ++i) {
String value = historyPreferences.getString("e_" + i, "");
if (!value.startsWith("#") && !value.startsWith("$")) {
value = "#" + value;
}
history.add(value);
}
}
private void saveHistoryToPref() {
SharedPreferences.Editor editor = historyPreferences.edit();
editor.clear();
editor.putInt("count", history.size());
for (int i = 0; i < history.size(); ++i) {
editor.putString("e_" + i, history.get(i));
}
editor.apply();
}
public void putToHistory(String hashtag) {
if (!hashtag.startsWith("#") && !hashtag.startsWith("$")) {
return;
}
int index = history.indexOf(hashtag);
if (index != -1) {
if (index == 0) {
return;
}
history.remove(index);
}
history.add(0, hashtag);
if (history.size() >= HISTORY_LIMIT) {
history.subList(HISTORY_LIMIT - 1, history.size()).clear();
}
saveHistoryToPref();
}
public void clearHistory() {
history.clear();
saveHistoryToPref();
}
public void removeHashtagFromHistory(String hashtag) {
int index = history.indexOf(hashtag);
if (index != -1) {
history.remove(index);
saveHistoryToPref();
}
}
@NonNull
private SearchResult getSearchResult(int searchType) {
if (searchType == ChatActivity.SEARCH_MY_MESSAGES) {
return myMessagesSearch;
} else if (searchType == ChatActivity.SEARCH_PUBLIC_POSTS) {
return channelPostsSearch;
}
throw new RuntimeException("Unknown search type");
}
public ArrayList<MessageObject> getMessages(int searchType) {
return getSearchResult(searchType).messages;
}
public int getCount(int searchType) {
return getSearchResult(searchType).count;
}
public boolean isEndReached(int searchType) {
return getSearchResult(searchType).endReached;
}
public void searchHashtag(String hashtag, int guid, int searchType, int loadIndex) {
SearchResult search = getSearchResult(searchType);
if (search.lastHashtag == null && hashtag == null) {
return;
}
if (hashtag != null && hashtag.isEmpty()) {
return;
}
if (hashtag == null) {
hashtag = search.lastHashtag;
} else if (!TextUtils.equals(hashtag, search.lastHashtag)) {
search.clear();
}
search.lastHashtag = hashtag;
final String query = hashtag;
int limit = 30;
TLObject request;
if (searchType == ChatActivity.SEARCH_MY_MESSAGES) {
TLRPC.TL_messages_searchGlobal req = new TLRPC.TL_messages_searchGlobal();
req.limit = limit;
req.q = query;
req.filter = new TLRPC.TL_inputMessagesFilterEmpty();
req.offset_peer = new TLRPC.TL_inputPeerEmpty();
if (search.lastOffsetPeer != null) {
req.offset_rate = search.lastOffsetRate;
req.offset_id = search.lastOffsetId;
req.offset_peer = MessagesController.getInstance(currentAccount).getInputPeer(search.lastOffsetPeer);
}
request = req;
} else {
TLRPC.TL_channels_searchPosts req = new TLRPC.TL_channels_searchPosts();
req.limit = limit;
req.hashtag = query;
req.offset_peer = new TLRPC.TL_inputPeerEmpty();
if (search.lastOffsetPeer != null) {
req.offset_rate = search.lastOffsetRate;
req.offset_id = search.lastOffsetId;
req.offset_peer = MessagesController.getInstance(currentAccount).getInputPeer(search.lastOffsetPeer);
}
request = req;
}
ConnectionsManager.getInstance(currentAccount).sendRequest(request, (res, err) -> {
if (res instanceof TLRPC.messages_Messages) {
TLRPC.messages_Messages messages = (TLRPC.messages_Messages) res;
ArrayList<MessageObject> messageObjects = new ArrayList<>();
for (TLRPC.Message msg : messages.messages) {
MessageObject obj = new MessageObject(currentAccount, msg, null, null, null, null, null, true, true, 0, false, false, false, searchType);
if (obj.hasValidGroupId()) {
obj.isPrimaryGroupMessage = true;
}
obj.setQuery(query);
messageObjects.add(obj);
}
AndroidUtilities.runOnUIThread(() -> {
search.lastOffsetRate = messages.next_rate;
for (MessageObject msg : messageObjects) {
MessageCompositeID compositeId = new MessageCompositeID(msg.messageOwner);
Integer id = search.generatedIds.get(compositeId);
if (id == null) {
id = search.lastGeneratedId--;
search.generatedIds.put(compositeId, id);
search.messages.add(msg);
}
msg.messageOwner.realId = msg.messageOwner.id;
msg.messageOwner.id = id;
}
if (!messages.messages.isEmpty()) {
TLRPC.Message lastMsg = messages.messages.get(messages.messages.size() - 1);
search.lastOffsetId = lastMsg.id;
search.lastOffsetPeer = lastMsg.peer_id;
}
MessagesStorage.getInstance(currentAccount).putUsersAndChats(messages.users, messages.chats, true, true);
MessagesController.getInstance(currentAccount).putUsers(messages.users, false);
MessagesController.getInstance(currentAccount).putChats(messages.chats, false);
search.endReached = messages.messages.size() < limit;
search.count = Math.max(messages.count, messages.messages.size());
NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.messagesDidLoad, 0L, messageObjects.size(), messageObjects, false, 0, 0, 0, 0, 2, true, guid, loadIndex, 0, 0, ChatActivity.MODE_SEARCH);
NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.hashtagSearchUpdated, guid, search.count, search.endReached, search.getMask(), search.selectedIndex, 0);
});
}
});
}
public void jumpToMessage(int guid, int index, int searchType) {
SearchResult search = getSearchResult(searchType);
if (index < 0 || index >= search.messages.size()) {
return;
}
search.selectedIndex = index;
NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.hashtagSearchUpdated, guid, search.count, search.endReached, search.getMask(), search.selectedIndex, search.messages.get(index).messageOwner.id);
}
public void clearSearchResults() {
myMessagesSearch.clear();
channelPostsSearch.clear();
}
public void clearSearchResults(int searchType) {
getSearchResult(searchType).clear();
}
private final static class MessageCompositeID {
final long dialog_id;
final int id;
MessageCompositeID(TLRPC.Message msg) {
this(MessageObject.getDialogId(msg), msg.id);
}
MessageCompositeID(long dialogId, int id) {
dialog_id = dialogId;
this.id = id;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
MessageCompositeID that = (MessageCompositeID) o;
return dialog_id == that.dialog_id && id == that.id;
}
@Override
public int hashCode() {
return Objects.hash(dialog_id, id);
}
}
private static class SearchResult {
ArrayList<MessageObject> messages = new ArrayList<>();
HashMap<MessageCompositeID, Integer> generatedIds = new HashMap<>();
int lastOffsetRate;
int lastOffsetId;
TLRPC.Peer lastOffsetPeer;
int lastGeneratedId = Integer.MAX_VALUE;
String lastHashtag;
int selectedIndex;
int count;
boolean endReached;
int getMask() {
int mask = 0;
if (selectedIndex < messages.size() - 1) {
mask |= 1;
}
if (selectedIndex > 0) {
mask |= 2;
}
return mask;
}
void clear() {
messages.clear();
generatedIds.clear();
lastOffsetRate = 0;
lastOffsetId = 0;
lastOffsetPeer = null;
lastGeneratedId = Integer.MAX_VALUE - 10;
lastHashtag = null;
selectedIndex = 0;
count = 0;
endReached = false;
}
}
}

View file

@ -79,6 +79,7 @@ import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Locale;
@ -100,6 +101,7 @@ import java.util.zip.GZIPInputStream;
* firstframe - return firstframe for Lottie or Video animation
* ignoreOrientation - do not extract EXIF orientation and do not apply it to an imagereceiver
* exif check exif contents of invert/orientation
* bnb airbnb canvas lottie impl
*/
public class ImageLoader {
@ -117,7 +119,8 @@ public class ImageLoader {
ArrayList<AnimatedFileDrawable> cachedAnimatedFileDrawables = new ArrayList<>();
private HashMap<String, CacheImage> imageLoadingByUrl = new HashMap<>();
private HashMap<String, CacheImage> imageLoadingByUrlPframe = new HashMap<>();
private HashMap<String, CacheImage> imageLoadingByKeys = new HashMap<>();
public ConcurrentHashMap<String, CacheImage> imageLoadingByKeys = new ConcurrentHashMap<>();
public HashSet<String> imageLoadingKeys = new HashSet<>();
private SparseArray<CacheImage> imageLoadingByTag = new SparseArray<>();
private HashMap<String, ThumbGenerateInfo> waitingForQualityThumb = new HashMap<>();
private SparseArray<String> waitingForQualityThumbByTag = new SparseArray<>();
@ -1019,10 +1022,11 @@ public class ImageLoader {
cacheOptions.firstFrame = true;
}
}
final boolean airbnb = cacheImage.filter != null && cacheImage.filter.contains("bnb");
if (compressed) {
lottieDrawable = new RLottieDrawable(cacheImage.finalFilePath, decompressGzip(cacheImage.finalFilePath), w, h, cacheOptions, limitFps, null, fitzModifier);
lottieDrawable = new RLottieDrawable(cacheImage.finalFilePath, decompressGzip(cacheImage.finalFilePath), w, h, cacheOptions, limitFps, null, fitzModifier, airbnb);
} else {
lottieDrawable = new RLottieDrawable(cacheImage.finalFilePath, w, h, cacheOptions, limitFps, null, fitzModifier);
lottieDrawable = new RLottieDrawable(cacheImage.finalFilePath, w, h, cacheOptions, limitFps, null, fitzModifier, airbnb);
}
}
if (lastFrameBitmap || firstFrameBitmap) {
@ -2004,6 +2008,7 @@ public class ImageLoader {
}
if (key != null) {
imageLoadingByKeys.remove(key);
imageLoadingKeys.remove(cutFilter(key));
}
}
}
@ -2078,6 +2083,7 @@ public class ImageLoader {
}
if (key != null) {
imageLoadingByKeys.remove(key);
imageLoadingKeys.remove(cutFilter(key));
}
}
}
@ -2315,6 +2321,7 @@ public class ImageLoader {
cacheImage.imageType = img.imageType;
cacheImage.cacheType = img.cacheType;
imageLoadingByKeys.put(key, cacheImage);
imageLoadingKeys.add(cutFilter(key));
tasks.add(cacheImage.cacheTask);
}
cacheImage.addImageReceiver(imageReceiver, key, filter, type, guid);
@ -2948,6 +2955,14 @@ public class ImageLoader {
}
}
private static String cutFilter(String key) {
if (key == null) return null;
int index = key.indexOf('@');
if (index >= 0)
return key.substring(0, index);
return key;
}
public void replaceImageInCache(final String oldKey, final String newKey, final ImageLocation newLocation, boolean post) {
if (post) {
AndroidUtilities.runOnUIThread(() -> replaceImageInCacheInternal(oldKey, newKey, newLocation));
@ -3272,6 +3287,7 @@ public class ImageLoader {
img.cacheTask = new CacheOutTask(img);
imageLoadingByKeys.put(key, img);
imageLoadingKeys.add(cutFilter(key));
if (thumb != 0) {
cacheThumbOutQueue.postRunnable(img.cacheTask);
} else {
@ -3779,6 +3795,7 @@ public class ImageLoader {
cacheImage.filter = filter;
cacheImage.imageType = img.imageType;
imageLoadingByKeys.put(key, cacheImage);
imageLoadingKeys.add(cutFilter(key));
tasks.add(cacheImage.cacheTask);
}
cacheImage.addImageReceiver(imageReceiver, key, filter, type, guid);

View file

@ -315,7 +315,9 @@ public class ImageReceiver implements NotificationCenter.NotificationCenterDeleg
private boolean isAspectFit;
private boolean forcePreview;
private boolean forceCrossfade;
private boolean useRoundRadius = true;
private final int[] roundRadius = new int[4];
private int[] emptyRoundRadius;
private boolean isRoundRect = true;
private Object mark;
@ -1009,18 +1011,19 @@ public class ImageReceiver implements NotificationCenter.NotificationCenterDeleg
if (drawable == null) {
return;
}
int[] r = getRoundRadius(true);
if (drawable instanceof ClipRoundedDrawable) {
((ClipRoundedDrawable) drawable).setRadii(roundRadius[0], roundRadius[1], roundRadius[2], roundRadius[3]);
((ClipRoundedDrawable) drawable).setRadii(r[0], r[1], r[2], r[3]);
} else if ((hasRoundRadius() || gradientShader != null) && (drawable instanceof BitmapDrawable || drawable instanceof AvatarDrawable)) {
if (drawable instanceof AvatarDrawable) {
((AvatarDrawable) drawable).setRoundRadius(roundRadius[0]);
((AvatarDrawable) drawable).setRoundRadius(r[0]);
} else {
BitmapDrawable bitmapDrawable = (BitmapDrawable) drawable;
if (bitmapDrawable instanceof RLottieDrawable) {
} else if (bitmapDrawable instanceof AnimatedFileDrawable) {
AnimatedFileDrawable animatedFileDrawable = (AnimatedFileDrawable) drawable;
animatedFileDrawable.setRoundRadius(roundRadius);
animatedFileDrawable.setRoundRadius(r);
} else if (bitmapDrawable.getBitmap() != null && !bitmapDrawable.getBitmap().isRecycled()) {
setDrawableShader(drawable, new BitmapShader(bitmapDrawable.getBitmap(), Shader.TileMode.CLAMP, Shader.TileMode.CLAMP));
}
@ -1209,6 +1212,7 @@ public class ImageReceiver implements NotificationCenter.NotificationCenterDeleg
colorFilter = this.colorFilter;
roundRadius = this.roundRadius;
}
if (!useRoundRadius) roundRadius = emptyRoundRadius;
if (drawable instanceof BitmapDrawable) {
BitmapDrawable bitmapDrawable = (BitmapDrawable) drawable;
if (drawable instanceof RLottieDrawable) {
@ -1323,7 +1327,7 @@ public class ImageReceiver implements NotificationCenter.NotificationCenterDeleg
roundPaint.setAlpha(alpha);
roundRect.set(drawRegion);
if (isRoundRect) {
if (isRoundRect && useRoundRadius) {
try {
if (canvas != null) {
if (roundRadius[0] == 0) {
@ -1433,7 +1437,7 @@ public class ImageReceiver implements NotificationCenter.NotificationCenterDeleg
roundPaint.setAlpha(alpha);
if (isRoundRect) {
if (isRoundRect && useRoundRadius) {
try {
if (canvas != null) {
if (roundRadius[0] == 0) {
@ -1874,6 +1878,7 @@ public class ImageReceiver implements NotificationCenter.NotificationCenterDeleg
animationNotReady = animation != null && !animation.hasBitmap() || lottieDrawable != null && !lottieDrawable.hasBitmap();
colorFilter = this.colorFilter;
}
if (!useRoundRadius) roundRadius = emptyRoundRadius;
if (animation != null) {
animation.setRoundRadius(roundRadius);
@ -2483,6 +2488,28 @@ public class ImageReceiver implements NotificationCenter.NotificationCenterDeleg
}
}
public void setRoundRadiusEnabled(boolean enabled) {
if (useRoundRadius != enabled) {
useRoundRadius = enabled;
if (!useRoundRadius && emptyRoundRadius == null) {
emptyRoundRadius = new int[4];
emptyRoundRadius[0] = emptyRoundRadius[1] = emptyRoundRadius[2] = emptyRoundRadius[3] = 0;
}
if (currentImageDrawable != null && imageShader == null) {
updateDrawableRadius(currentImageDrawable);
}
if (currentMediaDrawable != null && mediaShader == null) {
updateDrawableRadius(currentMediaDrawable);
}
if (currentThumbDrawable != null) {
updateDrawableRadius(currentThumbDrawable);
}
if (staticThumbDrawable != null) {
updateDrawableRadius(staticThumbDrawable);
}
}
}
public void setMark(Object mark) {
this.mark = mark;
}
@ -2499,6 +2526,10 @@ public class ImageReceiver implements NotificationCenter.NotificationCenterDeleg
return roundRadius;
}
public int[] getRoundRadius(boolean includingEmpty) {
return !useRoundRadius && includingEmpty ? emptyRoundRadius : roundRadius;
}
public Object getParentObject() {
return currentParentObject;
}
@ -2618,12 +2649,27 @@ public class ImageReceiver implements NotificationCenter.NotificationCenterDeleg
animation.stop();
} else {
RLottieDrawable rLottieDrawable = getLottieAnimation();
if (rLottieDrawable != null && !rLottieDrawable.isRunning()) {
if (rLottieDrawable != null) {
rLottieDrawable.stop();
}
}
}
private boolean emojiPaused;
public void setEmojiPaused(boolean paused) {
if (emojiPaused == paused) return;
emojiPaused = paused;
RLottieDrawable rLottieDrawable = getLottieAnimation();
allowStartLottieAnimation = !paused;
if (rLottieDrawable != null) {
if (paused) {
rLottieDrawable.stop();
} else if (!rLottieDrawable.isRunning()) {
rLottieDrawable.start();
}
}
}
public boolean isAnimationRunning() {
AnimatedFileDrawable animation = getAnimation();
return animation != null && animation.isRunning();

View file

@ -23,6 +23,8 @@ import android.util.Xml;
import androidx.annotation.StringRes;
import org.telegram.messenger.time.FastDateFormat;
import org.telegram.ui.Stars.StarsController;
import org.telegram.ui.Stars.StarsIntroActivity;
import org.telegram.tgnet.ConnectionsManager;
import org.telegram.tgnet.TLObject;
import org.telegram.tgnet.TLRPC;
@ -1168,7 +1170,17 @@ public class LocaleController {
return formatPluralStringComma(key, plural, ',');
}
public static String formatPluralStringComma(String key, int plural, Object... args) {
return formatPluralStringComma(key, plural, ',', args);
}
public static String formatPluralStringComma(String key, int plural, char symbol) {
return formatPluralStringComma(key, plural, symbol, new Object[] {});
}
public static String formatPluralStringComma(String key, int plural, char symbol, Object... args) {
try {
if (key == null || key.length() == 0 || getInstance().currentPluralRules == null) {
return "LOC_ERR:" + key;
@ -1195,10 +1207,14 @@ public class LocaleController {
value = value.replace("%d", "%1$s");
value = value.replace("%1$d", "%1$s");
Object[] a = new Object[(args == null ? 0 : args.length) + 1];
for (int i = 0; i < a.length; ++i) {
a[i] = i == 0 ? stringBuilder : args[i - 1];
}
if (getInstance().currentLocale != null) {
return String.format(getInstance().currentLocale, value, stringBuilder);
return String.format(getInstance().currentLocale, value, a);
} else {
return String.format(value, stringBuilder);
return String.format(value, a);
}
} catch (Exception e) {
FileLog.e(e);
@ -1206,6 +1222,14 @@ public class LocaleController {
}
}
public static String formatNumber(long count, char symbol) {
StringBuilder stringBuilder = new StringBuilder(String.format("%d", count));
for (int a = stringBuilder.length() - 3; a > 0; a -= 3) {
stringBuilder.insert(a, symbol);
}
return stringBuilder.toString();
}
public static String formatString(@StringRes int res, Object... args) {
String key = resourcesCacheMap.get(res);
if (key == null) {
@ -1324,6 +1348,11 @@ public class LocaleController {
amount = Math.abs(amount);
Currency currency = Currency.getInstance(type);
switch (type) {
case StarsController.currency:
customFormat = " %.0f";
doubleAmount = amount;
break;
case "CLF":
customFormat = " %.4f";
doubleAmount = amount / 10000.0;

View file

@ -682,9 +682,7 @@ public class LocationController extends BaseController implements NotificationCe
if (!chatsToLoad.isEmpty()) {
getMessagesStorage().getChatsInternal(TextUtils.join(",", chatsToLoad), chats);
}
if (!usersToLoad.isEmpty()) {
getMessagesStorage().getUsersInternal(TextUtils.join(",", usersToLoad), users);
}
getMessagesStorage().getUsersInternal(usersToLoad, users);
} catch (Exception e) {
FileLog.e(e);
}

View file

@ -29,6 +29,7 @@ import android.graphics.BitmapFactory;
import android.graphics.Matrix;
import android.graphics.Point;
import android.graphics.SurfaceTexture;
import android.graphics.drawable.BitmapDrawable;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
@ -388,6 +389,7 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener,
public boolean isPainted;
public boolean isCropped;
public int ttl;
public long effectId;
public CropState cropState;
@ -457,12 +459,16 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener,
public boolean hasSpoiler;
public String emoji;
public int videoOrientation = -1;
public boolean isChatPreviewSpoilerRevealed;
public boolean isAttachSpoilerRevealed;
public TLRPC.VideoSize emojiMarkup;
public int gradientTopColor, gradientBottomColor;
public BitmapDrawable thumb;
public PhotoEntry(int bucketId, int imageId, long dateTaken, String path, int orientationOrDuration, boolean isVideo, int width, int height, long size) {
this.bucketId = bucketId;
this.imageId = imageId;
@ -479,6 +485,19 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener,
this.isVideo = isVideo;
}
public PhotoEntry(int bucketId, int imageId, long dateTaken, String path, int orientation, int duration, boolean isVideo, int width, int height, long size) {
this.bucketId = bucketId;
this.imageId = imageId;
this.dateTaken = dateTaken;
this.path = path;
this.width = width;
this.height = height;
this.size = size;
this.duration = duration;
this.orientation = orientation;
this.isVideo = isVideo;
}
public PhotoEntry setOrientation(Pair<Integer, Integer> rotationAndInvert) {
this.orientation = rotationAndInvert.first;
this.invert = rotationAndInvert.second;
@ -498,7 +517,7 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener,
}
public PhotoEntry clone() {
PhotoEntry photoEntry = new PhotoEntry(bucketId, imageId, dateTaken, path, isVideo ? duration : orientation, isVideo, width, height, size);
PhotoEntry photoEntry = new PhotoEntry(bucketId, imageId, dateTaken, path, orientation, duration, isVideo, width, height, size);
photoEntry.invert = invert;
photoEntry.isMuted = isMuted;
photoEntry.canDeleteAfter = canDeleteAfter;
@ -5120,7 +5139,7 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener,
int height = cursor.getInt(heightColumn);
long size = cursor.getLong(sizeColumn);
PhotoEntry photoEntry = new PhotoEntry(bucketId, imageId, dateTaken, path, orientation, false, width, height, size);
PhotoEntry photoEntry = new PhotoEntry(bucketId, imageId, dateTaken, path, orientation, 0, false, width, height, size);
if (allPhotosAlbum == null) {
allPhotosAlbum = new AlbumEntry(0, LocaleController.getString("AllPhotos", R.string.AllPhotos), photoEntry);
@ -5196,6 +5215,7 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener,
int widthColumn = cursor.getColumnIndex(MediaStore.Video.Media.WIDTH);
int heightColumn = cursor.getColumnIndex(MediaStore.Video.Media.HEIGHT);
int sizeColumn = cursor.getColumnIndex(MediaStore.Video.Media.SIZE);
int orientationColumn = cursor.getColumnIndex(MediaStore.Video.Media.ORIENTATION);
while (cursor.moveToNext()) {
String path = cursor.getString(dataColumn);
@ -5211,8 +5231,9 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener,
int width = cursor.getInt(widthColumn);
int height = cursor.getInt(heightColumn);
long size = cursor.getLong(sizeColumn);
int orientation = 0;
PhotoEntry photoEntry = new PhotoEntry(bucketId, imageId, dateTaken, path, (int) (duration / 1000), true, width, height, size);
PhotoEntry photoEntry = new PhotoEntry(bucketId, imageId, dateTaken, path, orientation, (int) (duration / 1000), true, width, height, size);
if (allVideosAlbum == null) {
allVideosAlbum = new AlbumEntry(0, LocaleController.getString("AllVideos", R.string.AllVideos), photoEntry);

View file

@ -2049,7 +2049,7 @@ public class MediaDataController extends BaseController {
}
state.dispose();
database.commitTransaction();
if (documents.size() >= maxCount) {
if (!replace && documents.size() >= maxCount) {
database.beginTransaction();
for (int a = maxCount; a < documents.size(); a++) {
database.executeFast("DELETE FROM web_recent_v3 WHERE id = '" + documents.get(a).id + "' AND type = " + cacheType).stepThis().dispose();
@ -2067,22 +2067,22 @@ public class MediaDataController extends BaseController {
if (gif) {
loadingRecentGifs = false;
recentGifsLoaded = true;
editor.putLong("lastGifLoadTime", System.currentTimeMillis()).commit();
editor.putLong("lastGifLoadTime", System.currentTimeMillis()).apply();
} else {
loadingRecentStickers[type] = false;
recentStickersLoaded[type] = true;
if (type == TYPE_IMAGE) {
editor.putLong("lastStickersLoadTime", System.currentTimeMillis()).commit();
editor.putLong("lastStickersLoadTime", System.currentTimeMillis()).apply();
} else if (type == TYPE_MASK) {
editor.putLong("lastStickersLoadTimeMask", System.currentTimeMillis()).commit();
editor.putLong("lastStickersLoadTimeMask", System.currentTimeMillis()).apply();
} else if (type == TYPE_GREETINGS) {
editor.putLong("lastStickersLoadTimeGreet", System.currentTimeMillis()).commit();
editor.putLong("lastStickersLoadTimeGreet", System.currentTimeMillis()).apply();
} else if (type == TYPE_EMOJIPACKS) {
editor.putLong("lastStickersLoadTimeEmojiPacks", System.currentTimeMillis()).commit();
editor.putLong("lastStickersLoadTimeEmojiPacks", System.currentTimeMillis()).apply();
} else if (type == TYPE_PREMIUM_STICKERS) {
editor.putLong("lastStickersLoadTimePremiumStickers", System.currentTimeMillis()).commit();
editor.putLong("lastStickersLoadTimePremiumStickers", System.currentTimeMillis()).apply();
} else {
editor.putLong("lastStickersLoadTimeFavs", System.currentTimeMillis()).commit();
editor.putLong("lastStickersLoadTimeFavs", System.currentTimeMillis()).apply();
}
}
@ -4689,7 +4689,7 @@ public class MediaDataController extends BaseController {
}
if (!usersToLoad.isEmpty()) {
getMessagesStorage().getUsersInternal(TextUtils.join(",", usersToLoad), res.users);
getMessagesStorage().getUsersInternal(usersToLoad, res.users);
}
if (!chatsToLoad.isEmpty()) {
getMessagesStorage().getChatsInternal(TextUtils.join(",", chatsToLoad), res.chats);
@ -5062,7 +5062,7 @@ public class MediaDataController extends BaseController {
}
cursor.dispose();
if (!usersToLoad.isEmpty()) {
getMessagesStorage().getUsersInternal(TextUtils.join(",", usersToLoad), users);
getMessagesStorage().getUsersInternal(usersToLoad, users);
}
if (!chatsToLoad.isEmpty()) {
@ -5839,7 +5839,7 @@ public class MediaDataController extends BaseController {
}
if (!results.isEmpty()) {
if (!usersToLoad.isEmpty()) {
getMessagesStorage().getUsersInternal(TextUtils.join(",", usersToLoad), users);
getMessagesStorage().getUsersInternal(usersToLoad, users);
}
if (!chatsToLoad.isEmpty()) {
getMessagesStorage().getChatsInternal(TextUtils.join(",", chatsToLoad), chats);
@ -6249,7 +6249,7 @@ public class MediaDataController extends BaseController {
}
if (!usersToLoad.isEmpty()) {
getMessagesStorage().getUsersInternal(TextUtils.join(",", usersToLoad), users);
getMessagesStorage().getUsersInternal(usersToLoad, users);
}
if (!chatsToLoad.isEmpty()) {
getMessagesStorage().getChatsInternal(TextUtils.join(",", chatsToLoad), chats);
@ -7036,6 +7036,7 @@ public class MediaDataController extends BaseController {
TLRPC.TL_messageEntityBlockquote entity = new TLRPC.TL_messageEntityBlockquote();
entity.offset = spannable.getSpanStart(span);
entity.length = Math.min(spannable.getSpanEnd(span), message[0].length()) - entity.offset;
entity.collapsed = span.isCollapsing;
entities.add(entity);
} catch (Exception e) {
FileLog.e(e);
@ -7045,8 +7046,9 @@ public class MediaDataController extends BaseController {
}
if (spannable instanceof Spannable) {
AndroidUtilities.addLinksSafe((Spannable) spannable, Linkify.WEB_URLS, false, false);
URLSpan[] spansUrl = spannable.getSpans(0, message[0].length(), URLSpan.class);
Spannable s = (Spannable) spannable;
AndroidUtilities.addLinksSafe(s, Linkify.WEB_URLS, false, false);
URLSpan[] spansUrl = s.getSpans(0, message[0].length(), URLSpan.class);
if (spansUrl != null && spansUrl.length > 0) {
if (entities == null) {
entities = new ArrayList<>();
@ -7060,8 +7062,28 @@ public class MediaDataController extends BaseController {
entity.length = Math.min(spannable.getSpanEnd(spansUrl[b]), message[0].length()) - entity.offset;
entity.url = spansUrl[b].getURL();
entities.add(entity);
s.removeSpan(spansUrl[b]);
}
}
//
// AndroidUtilities.doSafe(() -> Linkify.addLinks(s, Linkify.PHONE_NUMBERS));
// spansUrl = s.getSpans(0, message[0].length(), URLSpan.class);
// if (spansUrl != null && spansUrl.length > 0) {
// if (entities == null) {
// entities = new ArrayList<>();
// }
// for (int b = 0; b < spansUrl.length; b++) {
// if (spansUrl[b] instanceof URLSpanReplacement || spansUrl[b] instanceof URLSpanUserMention) {
// continue;
// }
// TLRPC.TL_messageEntityTextUrl entity = new TLRPC.TL_messageEntityTextUrl();
// entity.offset = spannable.getSpanStart(spansUrl[b]);
// entity.length = Math.min(spannable.getSpanEnd(spansUrl[b]), message[0].length()) - entity.offset;
// entity.url = spansUrl[b].getURL();
// entities.add(entity);
// s.removeSpan(spansUrl[b]);
// }
// }
}
}
@ -7119,6 +7141,17 @@ public class MediaDataController extends BaseController {
return true;
}
public static boolean stringsEqual(CharSequence a, CharSequence b) {
if (a == null && b == null) return true;
if (a == null || b == null) return false;
if (!TextUtils.equals(a, b)) return false;
CharSequence[] A = new CharSequence[] { a };
CharSequence[] B = new CharSequence[] { b };
ArrayList<TLRPC.MessageEntity> ae = getInstance(UserConfig.selectedAccount).getEntities(A, true);
ArrayList<TLRPC.MessageEntity> be = getInstance(UserConfig.selectedAccount).getEntities(B, true);
return entitiesEqual(ae, be);
}
public static boolean entitiesEqual(ArrayList<TLRPC.MessageEntity> entities1, ArrayList<TLRPC.MessageEntity> entities2) {
if (entities1.size() != entities2.size()) {
return false;
@ -8057,6 +8090,7 @@ public class MediaDataController extends BaseController {
checkPremiumPromo();
checkPremiumGiftStickers();
checkGenericAnimations();
getMessagesController().getAvailableEffects();
}
public void moveStickerSetToTop(long setId, boolean emojis, boolean masks) {

View file

@ -53,6 +53,7 @@ import org.telegram.ui.ChatActivity;
import org.telegram.ui.Components.AnimatedEmojiDrawable;
import org.telegram.ui.Components.AnimatedEmojiSpan;
import org.telegram.ui.Components.AvatarDrawable;
import org.telegram.ui.Components.ButtonBounce;
import org.telegram.ui.Components.ColoredImageSpan;
import org.telegram.ui.Components.Forum.ForumBubbleDrawable;
import org.telegram.ui.Components.Forum.ForumUtilities;
@ -72,6 +73,8 @@ import org.telegram.ui.Components.URLSpanReplacement;
import org.telegram.ui.Components.URLSpanUserMention;
import org.telegram.ui.Components.spoilers.SpoilerEffect;
import org.telegram.ui.PeerColorActivity;
import org.telegram.ui.Stars.StarsController;
import org.telegram.ui.Stars.StarsIntroActivity;
import java.io.BufferedReader;
import java.io.File;
@ -84,6 +87,7 @@ import java.util.Calendar;
import java.util.Collections;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.TreeSet;
@ -167,6 +171,7 @@ public class MessageObject {
private int isRoundVideoCached;
public long eventId;
public int contentType;
public int realDate;
public String dateKey;
public int dateKeyInt;
public String monthKey;
@ -193,6 +198,8 @@ public class MessageObject {
public int wantedBotKeyboardWidth;
public boolean attachPathExists;
public boolean mediaExists;
public MediaController.PhotoEntry sendPreviewEntry;
public boolean sendPreview;
public boolean resendAsIs;
public String customReplyName;
public boolean useCustomPhoto;
@ -201,6 +208,7 @@ public class MessageObject {
public long loadedFileSize;
public boolean forceExpired;
public long actionDeleteGroupEventId = -1;
public HashSet<Integer> expandedQuotes;
public boolean isSpoilersRevealed;
public boolean isMediaSpoilersRevealed;
@ -242,6 +250,8 @@ public class MessageObject {
public boolean preview;
public boolean previewForward;
public boolean notime;
public int getChatMode() {
if (scheduled) {
return ChatActivity.MODE_SCHEDULED;
@ -327,6 +337,7 @@ public class MessageObject {
public boolean isSaved;
public boolean isSavedFiltered;
public String quick_reply_shortcut;
public int searchType;
private byte[] randomWaveform;
public boolean drawServiceWithDefaultTypeface;
@ -572,7 +583,7 @@ public class MessageObject {
}
for (int i = 0; i < messageOwner.reactions.results.size(); i++) {
if (messageOwner.reactions.results.get(i).chosen) {
choosenReactions.add(ReactionsLayoutInBubble.VisibleReaction.fromTLReaction(messageOwner.reactions.results.get(i).reaction));
choosenReactions.add(ReactionsLayoutInBubble.VisibleReaction.fromTL(messageOwner.reactions.results.get(i).reaction));
}
}
return choosenReactions;
@ -600,6 +611,9 @@ public class MessageObject {
public float currentY;
public float timeAlpha;
public float progress;
public boolean fromPreview;
public ChatMessageCell.TransitionParams fromParams;
}
public static class VCardData {
@ -726,15 +740,23 @@ public class MessageObject {
}
}
public static boolean expandedQuotesEquals(HashSet<Integer> a, HashSet<Integer> b) {
if (a == null && b == null)
return true;
if ((a == null ? 0 : a.size()) != (b == null ? 0 : b.size()))
return false;
return a != null && a.equals(b);
}
public static class TextLayoutBlock {
public final static int FLAG_RTL = 1, FLAG_NOT_RTL = 2;
public boolean first, last;
public int index;
public AtomicReference<Layout> spoilersPatchedTextLayout = new AtomicReference<>();
public StaticLayout textLayout;
public int padTop, padBottom;
public float textYOffset;
public int charactersOffset;
public int charactersEnd;
public int height;
@ -743,8 +765,13 @@ public class MessageObject {
public List<SpoilerEffect> spoilers = new ArrayList<>();
public float maxRight;
public MessageObject messageObject;
public int collapsedHeight;
public ButtonBounce collapsedBounce;
public boolean code;
public boolean quote;
public boolean quoteCollapse;
public String language;
public Text languageLayout;
@ -758,10 +785,51 @@ public class MessageObject {
public Drawable copySelector;
public Paint copySeparator;
public int height() {
return quoteCollapse && collapsed() ? collapsedHeight : height;
}
public int height(ChatMessageCell.TransitionParams tp) {
if (!quoteCollapse)
return height;
return AndroidUtilities.lerp(height, collapsedHeight, collapsed(tp));
}
public float collapsed(ChatMessageCell.TransitionParams tp) {
final boolean pastCollapsed = tp.animateExpandedQuotes ? (tp.animateExpandedQuotesFrom == null ? true : !tp.animateExpandedQuotesFrom.contains(index)) : collapsed();
return AndroidUtilities.lerp(pastCollapsed ? 1f : 0f, collapsed() ? 1f : 0f, tp.animateChangeProgress);
}
public boolean collapsed() {
return messageObject == null || messageObject.expandedQuotes == null || !messageObject.expandedQuotes.contains(index);
}
public float textYOffset(ArrayList<TextLayoutBlock> blocks) {
if (blocks == null) return 0;
int h = 0;
for (int i = 0; i < blocks.size(); ++i) {
TextLayoutBlock block = blocks.get(i);
if (block == this) break;
h += block.padTop + block.height() + block.padBottom;
}
return h;
}
public float textYOffset(ArrayList<TextLayoutBlock> blocks, ChatMessageCell.TransitionParams tp) {
if (blocks == null) return 0;
int h = 0;
for (int i = 0; i < blocks.size(); ++i) {
TextLayoutBlock block = blocks.get(i);
if (block == this) break;
h += block.padTop + block.height(tp) + block.padBottom;
}
return h;
}
public void layoutCode(String lng, int codeLength, boolean noforwards) {
hasCodeCopyButton = codeLength >= 75 && !noforwards;
if (hasCodeCopyButton) {
copyText = new Text(LocaleController.getString(R.string.CopyCode).toUpperCase(), SharedConfig.fontSize - 3, AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM));
copyText = new Text(LocaleController.getString(R.string.CopyCode).toUpperCase(), SharedConfig.fontSize - 3, AndroidUtilities.bold());
copyIcon = ApplicationLoader.applicationContext.getResources().getDrawable(R.drawable.msg_copy).mutate();
copyIcon.setColorFilter(new PorterDuffColorFilter(copyIconColor, PorterDuff.Mode.SRC_IN));
copySelector = Theme.createRadSelectorDrawable(copySelectorColor, 0, 0, Math.min(5, SharedConfig.bubbleRadius), 0);
@ -776,7 +844,7 @@ public class MessageObject {
languageLayout = new Text(
capitalizeLanguage(lng),
SharedConfig.fontSize - 1 - CodeHighlighting.getTextSizeDecrement(codeLength) / 2,
AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)
AndroidUtilities.bold()
);
languageHeight = (int) (languageLayout.getTextSize() * 1.714f) + dp(4);
}
@ -792,7 +860,9 @@ public class MessageObject {
}
copySelector.setBounds((int) bounds.left + dp(3), (int) (bounds.bottom - dp(38)), (int) bounds.right, (int) bounds.bottom);
copySelector.setAlpha((int) (0xFF * alpha));
copySelector.draw(canvas);
if (copySelector.getCallback() != null) {
copySelector.draw(canvas);
}
copySeparator.setColor(ColorUtils.setAlphaComponent(backgroundColor, 0x26));
canvas.drawRect(bounds.left + dp(10), bounds.bottom - dp(38) - AndroidUtilities.getShadowHeight(), bounds.right - dp(6.66f), bounds.bottom - dp(38), copySeparator);
@ -949,6 +1019,7 @@ public class MessageObject {
public LongSparseArray<GroupedMessagePosition> positionsArray = new LongSparseArray<>();
public MessageObject captionMessage;
public boolean isDocuments;
public boolean captionAbove;
public GroupedMessagePosition getPosition(MessageObject msg) {
if (msg == null) {
@ -1026,6 +1097,7 @@ public class MessageObject {
hasCaption = false;
boolean checkCaption = true;
captionAbove = false;
for (int a = (reversed ? count - 1 : 0); (reversed ? a >= 0 : a < count);) {
MessageObject messageObject = messages.get(a);
if (a == (reversed ? count - 1 : 0)) {
@ -1040,6 +1112,9 @@ public class MessageObject {
isDocuments = true;
}
}
if (messageObject.messageOwner != null && messageObject.messageOwner.invert_media) {
captionAbove = true;
}
TLRPC.PhotoSize photoSize = FileLoader.getClosestPhotoSizeWithSize(messageObject.photoThumbs, AndroidUtilities.getPhotoSize());
GroupedMessagePosition position = new GroupedMessagePosition();
position.last = (reversed ? a == 0 : a == count - 1);
@ -1490,7 +1565,6 @@ public class MessageObject {
public int lastLineWidth;
public int textWidth;
public int textHeight;
public boolean hasRtl;
public float textXOffset;
public ArrayList<TextLayoutBlock> textLayoutBlocks;
@ -1568,11 +1642,16 @@ public class MessageObject {
}
public MessageObject(int accountNum, TLRPC.Message message, MessageObject replyToMessage, AbstractMap<Long, TLRPC.User> users, AbstractMap<Long, TLRPC.Chat> chats, LongSparseArray<TLRPC.User> sUsers, LongSparseArray<TLRPC.Chat> sChats, boolean generateLayout, boolean checkMediaExists, long eid, boolean isRepostPreview, boolean isRepostVideoPreview, boolean isSavedMessages) {
this(accountNum, message, replyToMessage, users, chats, sUsers, sChats, generateLayout, checkMediaExists, eid, isRepostPreview, isRepostVideoPreview, isSavedMessages, 0);
}
public MessageObject(int accountNum, TLRPC.Message message, MessageObject replyToMessage, AbstractMap<Long, TLRPC.User> users, AbstractMap<Long, TLRPC.Chat> chats, LongSparseArray<TLRPC.User> sUsers, LongSparseArray<TLRPC.Chat> sChats, boolean generateLayout, boolean checkMediaExists, long eid, boolean isRepostPreview, boolean isRepostVideoPreview, boolean isSavedMessages, int searchType) {
Theme.createCommonMessageResources();
this.isRepostPreview = isRepostPreview;
this.isRepostVideoPreview = isRepostVideoPreview;
this.isSaved = isSavedMessages || getDialogId(message) == UserConfig.getInstance(accountNum).getClientUserId();
this.searchType = searchType;
currentAccount = accountNum;
messageOwner = message;
@ -1832,6 +1911,33 @@ public class MessageObject {
}
}
public TextPaint getTextPaint() {
if (emojiOnlyCount >= 1 && messageOwner != null && !hasNonEmojiEntities()) {
boolean large = emojiOnlyCount == animatedEmojiCount;
switch (Math.max(emojiOnlyCount, animatedEmojiCount)) {
case 0:
case 1:
case 2:
return large ? Theme.chat_msgTextPaintEmoji[0] : Theme.chat_msgTextPaintEmoji[2];
case 3:
return large ? Theme.chat_msgTextPaintEmoji[1] : Theme.chat_msgTextPaintEmoji[3];
case 4:
return large ? Theme.chat_msgTextPaintEmoji[2] : Theme.chat_msgTextPaintEmoji[4];
case 5:
return large ? Theme.chat_msgTextPaintEmoji[3] : Theme.chat_msgTextPaintEmoji[5];
case 6:
return large ? Theme.chat_msgTextPaintEmoji[4] : Theme.chat_msgTextPaintEmoji[5];
case 7:
case 8:
case 9:
default:
return Theme.chat_msgTextPaintEmoji[5];
}
} else {
return Theme.chat_msgTextPaint;
}
}
public MessageObject(int accountNum, TLRPC.TL_channelAdminLogEvent event, ArrayList<MessageObject> messageObjects, HashMap<String, ArrayList<MessageObject>> messagesByDays, TLRPC.Chat chat, int[] mid, boolean addToEnd) {
currentEvent = event;
currentAccount = accountNum;
@ -2426,6 +2532,13 @@ public class MessageObject {
message.date = event.date;
TLRPC.Message newMessage = ((TLRPC.TL_channelAdminLogEventActionEditMessage) event.action).new_message;
TLRPC.Message oldMessage = ((TLRPC.TL_channelAdminLogEventActionEditMessage) event.action).prev_message;
if (oldMessage != null) {
message.reply_to = oldMessage.reply_to;
message.id = oldMessage.id;
} else if (newMessage != null) {
message.reply_to = newMessage.reply_to;
message.id = newMessage.id;
}
if (newMessage != null && newMessage.from_id != null) {
message.from_id = newMessage.from_id;
} else {
@ -2994,7 +3107,13 @@ public class MessageObject {
message.id = mid[0]++;
message.flags = message.flags & ~TLRPC.MESSAGE_FLAG_EDITED;
message.dialog_id = -chat.id;
int realDate = 0;
if (event.action instanceof TLRPC.TL_channelAdminLogEventActionDeleteMessage) {
realDate = message.date;
message.date = event.date;
}
MessageObject messageObject = new MessageObject(currentAccount, message, null, null, true, true, eventId);
messageObject.realDate = realDate;
messageObject.currentEvent = event;
if (messageObject.contentType >= 0) {
if (mediaController.isPlayingMessage(messageObject)) {
@ -3282,7 +3401,11 @@ public class MessageObject {
}
String currency;
try {
currency = LocaleController.getInstance().formatCurrencyString(messageOwner.action.total_amount, messageOwner.action.currency);
if (StarsController.currency.equals(messageOwner.action.currency)) {
currency = StarsController.currency + " " + messageOwner.action.total_amount;
} else {
currency = LocaleController.getInstance().formatCurrencyString(messageOwner.action.total_amount, messageOwner.action.currency);
}
} catch (Exception e) {
currency = "<error>";
FileLog.e(e);
@ -3300,6 +3423,7 @@ public class MessageObject {
messageText = LocaleController.formatString("PaymentSuccessfullyPaidNoItem", R.string.PaymentSuccessfullyPaidNoItem, currency, name);
}
}
messageText = StarsIntroActivity.replaceStars(messageText);
}
public void generatePinMessageText(TLRPC.User fromUser, TLRPC.Chat chat) {
@ -3844,14 +3968,14 @@ public class MessageObject {
} else if (wallPaper.for_both && partner != null) {
messageText = LocaleController.getString(R.string.ActionSetWallpaperForThisChatSelfBoth);
CharSequence partnerName = new SpannableString(UserObject.getFirstName(partner));
((SpannableString) partnerName).setSpan(new TypefaceSpan(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)), 0, partnerName.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
((SpannableString) partnerName).setSpan(new TypefaceSpan(AndroidUtilities.bold()), 0, partnerName.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
messageText = AndroidUtilities.replaceCharSequence("%s", messageText, partnerName);
} else {
messageText = LocaleController.getString(R.string.ActionSetWallpaperForThisChatSelf);
}
} else {
CharSequence userName = new SpannableString(UserObject.getFirstName(user));
((SpannableString) userName).setSpan(new TypefaceSpan(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)), 0, userName.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
((SpannableString) userName).setSpan(new TypefaceSpan(AndroidUtilities.bold()), 0, userName.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
if (wallPaper.same) {
type = TYPE_DATE;
messageText = LocaleController.getString(R.string.ActionSetSameWallpaperForThisChat);
@ -5901,7 +6025,7 @@ public class MessageObject {
// only set in searching with tags
public boolean isPrimaryGroupMessage;
public boolean hasValidGroupId() {
return getGroupId() != 0 && (photoThumbs != null && !photoThumbs.isEmpty() || isMusic() || isDocument());
return getGroupId() != 0 && (photoThumbs != null && !photoThumbs.isEmpty() || sendPreview && (type == TYPE_VIDEO || type == TYPE_PHOTO) || isMusic() || isDocument());
}
public long getGroupIdForUse() {
@ -5922,23 +6046,35 @@ public class MessageObject {
public static void addLinks(boolean isOut, CharSequence messageText, boolean botCommands, boolean check, boolean internalOnly) {
if (messageText instanceof Spannable && containsUrls(messageText)) {
if (messageText.length() < 1000) {
try {
AndroidUtilities.addLinksSafe((Spannable) messageText, Linkify.WEB_URLS | Linkify.PHONE_NUMBERS, internalOnly, false);
} catch (Exception e) {
FileLog.e(e);
}
} else {
try {
AndroidUtilities.addLinksSafe((Spannable) messageText, Linkify.WEB_URLS, internalOnly, false);
} catch (Exception e) {
FileLog.e(e);
}
try {
AndroidUtilities.addLinksSafe((Spannable) messageText, Linkify.WEB_URLS, internalOnly, false);
} catch (Exception e) {
FileLog.e(e);
}
addPhoneLinks(messageText);
addUrlsByPattern(isOut, messageText, botCommands, 0, 0, check);
}
}
public static void addPhoneLinks(CharSequence messageText) {
// if (messageText == null || !(messageText instanceof Spannable))
// return;
// Spannable spannable = (Spannable) messageText;
// SpannableString otherText = new SpannableString(spannable);
// AndroidUtilities.doSafe(() -> Linkify.addLinks(otherText, Linkify.PHONE_NUMBERS));
// URLSpan[] spans = otherText.getSpans(0, otherText.length(), URLSpan.class);
// for (int i = 0; spans != null && i < spans.length; ++i) {
// if (spans[i].getURL().startsWith("tel:")) {
// spannable.setSpan(
// new URLSpanNoUnderline(spans[i].getURL()),
// otherText.getSpanStart(spans[i]),
// otherText.getSpanEnd(spans[i]),
// Spanned.SPAN_EXCLUSIVE_EXCLUSIVE
// );
// }
// }
}
public void resetPlayingProgress() {
audioProgress = 0.0f;
audioProgressSec = 0;
@ -6281,7 +6417,7 @@ public class MessageObject {
if (url.startsWith("+")) {
tel = "+" + tel;
}
spannable.setSpan(new URLSpanBrowser("tel:" + tel, run), run.start, run.end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
spannable.setSpan(new URLSpanNoUnderline("tel:" + tel, run), run.start, run.end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
} else if (run.urlEntity instanceof TLRPC.TL_messageEntityTextUrl) {
url = run.urlEntity.url;
if (url != null) {
@ -6311,7 +6447,7 @@ public class MessageObject {
}
if (entity instanceof TLRPC.TL_messageEntityBlockquote) {
QuoteSpan.putQuote(spannable, entity.offset, entity.offset + entity.length);
QuoteSpan.putQuote(spannable, entity.offset, entity.offset + entity.length, entity.collapsed);
} else if (entity instanceof TLRPC.TL_messageEntityPre) {
final int start = entity.offset;
final int end = entity.offset + entity.length;
@ -6352,6 +6488,8 @@ public class MessageObject {
return false;
} else if (eventId != 0) {
return false;
} else if (searchType == ChatActivity.SEARCH_PUBLIC_POSTS) {
return true;
} else if (messageOwner.noforwards) {
return false;
} else if (messageOwner.fwd_from != null && !isOutOwner() && messageOwner.fwd_from.saved_from_peer != null && getDialogId() == UserConfig.getInstance(currentAccount).getClientUserId()) {
@ -6429,7 +6567,7 @@ public class MessageObject {
maxWidth -= dp(52);
}
if (needDrawShareButton() && (isSaved || !isOutOwner())) {
maxWidth -= dp(isSaved && isOutOwner() ? 40 : 10);
maxWidth -= dp(isSaved && isOutOwner() ? 40 : 14);
}
if (getMedia(messageOwner) instanceof TLRPC.TL_messageMediaGame) {
maxWidth -= dp(10);
@ -6490,13 +6628,7 @@ public class MessageObject {
if (useManualParse) {
addLinks(isOutOwner(), messageText, true, true);
} else {
// if (messageText instanceof Spannable && messageText.length() < 1000) {
// try {
// AndroidUtilities.addLinks((Spannable) messageText, Linkify.PHONE_NUMBERS);
// } catch (Throwable e) {
// FileLog.e(e);
// }
// }
addPhoneLinks(messageText);
}
if (isYouTubeVideo()) {
addUrlsByPattern(isOutOwner(), messageText, false, 3, Integer.MAX_VALUE, false);
@ -6664,7 +6796,7 @@ public class MessageObject {
maxWidth += AndroidUtilities.dp(15);
}
textHeight = 0;
// textHeight = 0;
int linesCount = textLayout.getLineCount();
int linesPreBlock = totalAnimatedEmojiCount >= 50 ? LINES_PER_BLOCK_WITH_EMOJI : LINES_PER_BLOCK;
@ -6711,7 +6843,6 @@ public class MessageObject {
hasQuoteAtBottom = false;
hasSingleQuote = false;
hasSingleCode = false;
float offset = 0;
for (int a = 0; a < textRanges.size(); a++) {
TextLayoutBlock block = new TextLayoutBlock();
@ -6719,7 +6850,12 @@ public class MessageObject {
block.code = range.code;
block.quote = range.quote;
block.quoteCollapse = range.collapse;
if (block.quoteCollapse) {
block.messageObject = this;
}
block.index = a;
block.first = a == 0;
block.last = a == textRanges.size() - 1;
@ -6777,25 +6913,21 @@ public class MessageObject {
}
block.textLayout = textLayout;
block.textYOffset = 0;
block.charactersOffset = 0;
block.charactersEnd = textLayout.getText().length();
block.height = textLayout.getHeight();
textHeight = block.padTop + block.height + block.padBottom;
block.collapsedHeight = (int) Math.min(paint.getTextSize() * 1.4f * 3, block.height);
if (emojiOnlyCount != 0) {
switch (emojiOnlyCount) {
case 1:
textHeight -= dp(5.3f);
block.textYOffset -= dp(5.3f);
block.padTop -= dp(5.3f);
break;
case 2:
textHeight -= dp(4.5f);
block.textYOffset -= dp(4.5f);
block.padTop -= dp(4.5f);
break;
case 3:
textHeight -= dp(4.2f);
block.textYOffset -= dp(4.2f);
block.padTop -= dp(4.2f);
break;
}
}
@ -6816,21 +6948,14 @@ public class MessageObject {
}
block.textLayout = makeStaticLayout(sb, layoutPaint, blockMaxWidth, 1f, totalAnimatedEmojiCount >= 4 ? -1 : 0, false);
block.textYOffset = offset;
if (a != 0 && emojiOnlyCount <= 0) {
block.height = (int) (block.textYOffset - prevOffset);
}
block.height = block.textLayout.getHeight();//Math.max(block.height, block.textLayout.getLineBottom(block.textLayout.getLineCount() - 1));
textHeight += block.padTop + block.height + block.padBottom;
prevOffset = block.textYOffset;
block.collapsedHeight = (int) Math.min(paint.getTextSize() * 1.4f * 3, block.height);
} catch (Exception e) {
FileLog.e(e);
continue;
}
}
offset += block.padTop + block.height + block.padBottom;
textLayoutBlocks.add(block);
final int currentBlockLinesCount = block.textLayout.getLineCount();
@ -6976,6 +7101,25 @@ public class MessageObject {
}
hasWideCode = hasCode && textWidth > generatedWithMinSize - dp(80 + (needDrawAvatarInternal() && !isOutOwner() && !messageOwner.isThreadMessage ? 52 : 0));
factCheckText = null;
}
public int textHeight() {
if (textLayoutBlocks == null) return 0;
int h = 0;
for (int i = 0; i < textLayoutBlocks.size(); ++i) {
h += textLayoutBlocks.get(i).padTop + textLayoutBlocks.get(i).height() + textLayoutBlocks.get(i).padBottom;
}
return h;
}
public int textHeight(ChatMessageCell.TransitionParams tp) {
if (textLayoutBlocks == null) return 0;
int h = 0;
for (int i = 0; i < textLayoutBlocks.size(); ++i) {
h += textLayoutBlocks.get(i).padTop + textLayoutBlocks.get(i).height(tp) + textLayoutBlocks.get(i).padBottom;
}
return h;
}
public static class TextLayoutBlocks {
@ -6983,13 +7127,35 @@ public class MessageObject {
public final CharSequence text;
public int lastLineWidth;
public int textWidth;
public int textHeight;
public boolean hasRtl;
public float textXOffset;
public final ArrayList<TextLayoutBlock> textLayoutBlocks = new ArrayList<>();
public boolean hasCode, hasCodeAtTop, hasCodeAtBottom, hasSingleCode;
public boolean hasQuote, hasQuoteAtBottom, hasSingleQuote;
public int textHeight() {
int h = 0;
for (int i = 0; i < textLayoutBlocks.size(); ++i) {
h += textLayoutBlocks.get(i).padTop + textLayoutBlocks.get(i).height() + textLayoutBlocks.get(i).padBottom;
}
return h;
}
public int textHeight(ChatMessageCell.TransitionParams tp) {
int h = 0;
for (int i = 0; i < textLayoutBlocks.size(); ++i) {
h += textLayoutBlocks.get(i).padTop + textLayoutBlocks.get(i).height(tp) + textLayoutBlocks.get(i).padBottom;
}
return h;
}
public void bounceFrom(TextLayoutBlocks from) {
if (from == null) return;
for (int i = 0; i < Math.min(textLayoutBlocks.size(), from.textLayoutBlocks.size()); ++i) {
textLayoutBlocks.get(i).collapsedBounce = from.textLayoutBlocks.get(i).collapsedBounce;
}
}
public TextLayoutBlocks(MessageObject messageObject, @NonNull CharSequence text, TextPaint textPaint, int width) {
this.text = text;
textWidth = 0;
@ -7086,7 +7252,6 @@ public class MessageObject {
width += AndroidUtilities.dp(15);
}
textHeight = 0;
int linesCount = textLayout.getLineCount();
int linesPreBlock = LINES_PER_BLOCK;
@ -7127,7 +7292,6 @@ public class MessageObject {
hasCodeAtBottom = false;
hasQuoteAtBottom = false;
hasSingleQuote = false;
float offset = 0;
for (int a = 0; a < textRanges.size(); a++) {
TextLayoutBlock block = new TextLayoutBlock();
@ -7135,7 +7299,12 @@ public class MessageObject {
block.code = range.code;
block.quote = range.quote;
block.quoteCollapse = range.collapse;
if (block.quoteCollapse) {
block.messageObject = messageObject;
}
block.index = a;
block.first = a == 0;
block.last = a == textRanges.size() - 1;
@ -7191,12 +7360,11 @@ public class MessageObject {
}
block.textLayout = textLayout;
block.textYOffset = 0;
block.charactersOffset = 0;
block.charactersEnd = textLayout.getText().length();
block.height = textLayout.getHeight();
textHeight = block.padTop + block.height + block.padBottom;
block.collapsedHeight = (int) Math.min(textPaint.getTextSize() * 1.4f * 3, block.height);
} else {
int startCharacter = range.start;
int endCharacter = range.end;
@ -7214,13 +7382,8 @@ public class MessageObject {
}
block.textLayout = makeStaticLayout(sb, layoutPaint, blockMaxWidth, 1f, 0f, false);
block.textYOffset = offset;
if (a != 0) {
block.height = (int) (block.textYOffset - prevOffset);
}
block.height = block.textLayout.getHeight(); // Math.max(block.height, block.textLayout.getLineBottom(block.textLayout.getLineCount() - 1));
textHeight += block.padTop + block.height + block.padBottom;
prevOffset = block.textYOffset;
block.height = block.textLayout.getHeight();
block.collapsedHeight = (int) Math.min(textPaint.getTextSize() * 1.4f * 3, block.height);
} catch (Exception e) {
FileLog.e(e);
continue;
@ -7231,8 +7394,6 @@ public class MessageObject {
CodeHighlighting.highlight((Spannable) block.textLayout.getText(), 0, block.textLayout.getText().length(), range.language, 0, null, true);
}
offset += block.padTop + block.height + block.padBottom;
textLayoutBlocks.add(block);
final int currentBlockLinesCount = block.textLayout.getLineCount();
@ -7417,6 +7578,9 @@ public class MessageObject {
if (forceAvatar || customAvatarDrawable != null) {
return true;
}
if (searchType != 0) {
return true;
}
return !isSponsored() && (isFromUser() || isFromGroup() || eventId != 0 || messageOwner.fwd_from != null && messageOwner.fwd_from.saved_from_peer != null);
}
@ -7430,6 +7594,9 @@ public class MessageObject {
if (forceAvatar || customAvatarDrawable != null) {
return true;
}
if (searchType != 0) {
return true;
}
return !isSponsored() && (isFromChat() && isFromUser() || isFromGroup() || eventId != 0 || messageOwner.fwd_from != null && messageOwner.fwd_from.saved_from_peer != null);
}
@ -7585,6 +7752,26 @@ public class MessageObject {
return null;
}
public TLObject getPeerObject() {
if (messageOwner != null) {
if (messageOwner.peer_id instanceof TLRPC.TL_peerChannel_layer131 ||
messageOwner.peer_id instanceof TLRPC.TL_peerChannel) {
return MessagesController.getInstance(currentAccount).getChat(messageOwner.peer_id.channel_id);
} else if (
messageOwner.peer_id instanceof TLRPC.TL_peerUser_layer131 ||
messageOwner.peer_id instanceof TLRPC.TL_peerUser
) {
return MessagesController.getInstance(currentAccount).getUser(messageOwner.peer_id.user_id);
} else if (
messageOwner.peer_id instanceof TLRPC.TL_peerChat_layer131 ||
messageOwner.peer_id instanceof TLRPC.TL_peerChat
) {
return MessagesController.getInstance(currentAccount).getChat(messageOwner.peer_id.chat_id);
}
}
return null;
}
public static String getPeerObjectName(TLObject object) {
if (object instanceof TLRPC.User) {
return UserObject.getUserName((TLRPC.User) object);
@ -8460,7 +8647,7 @@ public class MessageObject {
public int getApproximateHeight() {
if (type == TYPE_TEXT) {
int height = textHeight + (getMedia(messageOwner) instanceof TLRPC.TL_messageMediaWebPage && getMedia(messageOwner).webpage instanceof TLRPC.TL_webPage ? dp(100) : 0);
int height = textHeight() + (getMedia(messageOwner) instanceof TLRPC.TL_messageMediaWebPage && getMedia(messageOwner).webpage instanceof TLRPC.TL_webPage ? dp(100) : 0);
if (isReply()) {
height += dp(42);
}
@ -8484,7 +8671,7 @@ public class MessageObject {
} else if (type == TYPE_ROUND_VIDEO) {
return AndroidUtilities.roundMessageSize;
} else if (type == TYPE_EMOJIS) {
return textHeight + dp(30);
return textHeight() + dp(30);
} else if (type == TYPE_STICKER || type == TYPE_ANIMATED_STICKER) {
float maxHeight = AndroidUtilities.displaySize.y * 0.4f;
float maxWidth;
@ -9978,6 +10165,7 @@ public class MessageObject {
!"telegram_megagroup".equals(webpageType) && // drawInstantViewType = 2
!"telegram_background".equals(webpageType) && // drawInstantViewType = 6
!"telegram_voicechat".equals(webpageType) && // drawInstantViewType = 9
!"telegram_videochat".equals(webpageType) &&
!"telegram_livestream".equals(webpageType) && // drawInstantViewType = 11
!"telegram_user".equals(webpageType) && // drawInstantViewType = 13
!"telegram_story".equals(webpageType) && // drawInstantViewType = 17
@ -9995,7 +10183,7 @@ public class MessageObject {
"app".equals(webpageType) || "profile".equals(webpageType) ||
"article".equals(webpageType) || "telegram_bot".equals(webpageType) ||
"telegram_user".equals(webpageType) || "telegram_channel".equals(webpageType) ||
"telegram_megagroup".equals(webpageType) || "telegram_voicechat".equals(webpageType) ||
"telegram_megagroup".equals(webpageType) || "telegram_voicechat".equals(webpageType) || "telegram_videochat".equals(webpageType) ||
"telegram_livestream".equals(webpageType) || "telegram_channel_boost".equals(webpageType) || "telegram_group_boost".equals(webpageType) ||
"telegram_chat".equals(webpageType)
);
@ -10007,17 +10195,19 @@ public class MessageObject {
public boolean quote;
public boolean code;
public boolean collapse;
public String language;
public TextRange(int start, int end) {
this.start = start;
this.end = end;
}
public TextRange(int start, int end, boolean quote, boolean code, String language) {
public TextRange(int start, int end, boolean quote, boolean code, boolean collapse, String language) {
this.start = start;
this.end = end;
this.quote = quote;
this.code = code;
this.collapse = quote && collapse;
this.language = language;
}
}
@ -10035,6 +10225,7 @@ public class MessageObject {
final int QUOTE_END = 2;
final int CODE_START = 4;
final int CODE_END = 8;
final int QUOTE_START_COLLAPSE = 16;
final TreeSet<Integer> cutIndexes = new TreeSet<>();
final HashMap<Integer, Integer> cutToType = new HashMap<>();
@ -10048,12 +10239,27 @@ public class MessageObject {
int end = spanned.getSpanEnd(quoteSpans[i]);
cutIndexes.add(start);
cutToType.put(start, (cutToType.containsKey(start) ? cutToType.get(start) : 0) | QUOTE_START);
cutToType.put(start, (cutToType.containsKey(start) ? cutToType.get(start) : 0) | (quoteSpans[i].span.isCollapsing ? QUOTE_START_COLLAPSE : QUOTE_START));
cutIndexes.add(end);
cutToType.put(end, (cutToType.containsKey(end) ? cutToType.get(end) : 0) | QUOTE_END);
}
// join quotes: some clients cut their quotes when formatting is inside :|
final Iterator<Integer> I = cutIndexes.iterator();
while (I.hasNext()) {
final int index = I.next();
if (index < 0 || index >= spanned.length()) continue;
if (!cutToType.containsKey(index)) continue;
final int type = cutToType.get(index);
if ((type & QUOTE_START) != 0 && (type & QUOTE_END) != 0) {
if (spanned.charAt(index) == '\n') continue;
if (index - 1 > 0 && spanned.charAt(index - 1) == '\n') continue;
I.remove();
cutToType.remove(index);
}
}
int codeSpanIndex = 0;
CodeHighlighting.Span[] codeSpans = spanned.getSpans(0, spanned.length(), CodeHighlighting.Span.class);
for (int i = 0; i < codeSpans.length; ++i) {
@ -10068,6 +10274,7 @@ public class MessageObject {
}
int from = 0;
boolean quoteCollapse = false;
int quoteCount = 0, codeCount = 0;
for (Iterator<Integer> i = cutIndexes.iterator(); i.hasNext(); ) {
int cutIndex = i.next();
@ -10084,7 +10291,7 @@ public class MessageObject {
codeSpanIndex++;
}
ranges.add(new TextRange(from, cutIndex, quoteCount > 0, codeCount > 0, lng));
ranges.add(new TextRange(from, cutIndex, quoteCount > 0, codeCount > 0, quoteCollapse, lng));
from = cutIndex;
if (from + 1 < text.length() && text.charAt(from) == '\n') {
from++;
@ -10092,12 +10299,15 @@ public class MessageObject {
}
if ((type & QUOTE_END) != 0) quoteCount--;
if ((type & QUOTE_START) != 0) quoteCount++;
if ((type & QUOTE_START) != 0 || (type & QUOTE_START_COLLAPSE) != 0) {
quoteCount++;
quoteCollapse = (type & QUOTE_START_COLLAPSE) != 0;
}
if ((type & CODE_END) != 0) codeCount--;
if ((type & CODE_START) != 0) codeCount++;
}
if (from < text.length()) {
ranges.add(new TextRange(from, text.length(), quoteCount > 0, codeCount > 0, null));
ranges.add(new TextRange(from, text.length(), quoteCount > 0, codeCount > 0, quoteCollapse, null));
}
}
@ -10211,4 +10421,60 @@ public class MessageObject {
public boolean isQuickReply() {
return isQuickReply(messageOwner);
}
public TLRPC.TL_availableEffect getEffect() {
if (messageOwner == null || (messageOwner.flags2 & 4) == 0)
return null;
return MessagesController.getInstance(currentAccount).getEffect(messageOwner.effect);
}
public long getEffectId() {
if (messageOwner == null || (messageOwner.flags2 & 4) == 0)
return 0;
return messageOwner.effect;
}
public TLRPC.TL_factCheck getFactCheck() {
return FactCheckController.getInstance(currentAccount).getFactCheck(this);
}
public boolean factCheckExpanded;
private CharSequence factCheckText;
public CharSequence getFactCheckText() {
if (!isFactCheckable())
return null;
TLRPC.TL_factCheck factCheck = getFactCheck();
if (factCheck == null || factCheck.text == null)
return factCheckText = null;
// if (factCheckText == null) {
SpannableStringBuilder stringBuilder = new SpannableStringBuilder(factCheck.text.text);
addEntitiesToText(stringBuilder, factCheck.text.entities, isOutOwner(), false, false, false);
factCheckText = stringBuilder;
// }
return factCheckText;
}
public boolean isFactCheckable() {
return getId() >= 0 && !isSponsored() && (
type == TYPE_TEXT ||
type == TYPE_VOICE ||
type == TYPE_PHOTO ||
type == TYPE_VIDEO ||
type == TYPE_GIF ||
type == TYPE_FILE
);
}
public boolean hasEntitiesFromServer() {
if (messageOwner == null) return false;
if (messageOwner.entities == null) return false;
for (int i = 0; i < messageOwner.entities.size(); ++i) {
final TLRPC.MessageEntity e = messageOwner.entities.get(i);
if (e instanceof TLRPC.TL_messageEntityPhone || e instanceof TLRPC.TL_messageEntityBankCard)
return true;
}
return false;
}
}

View file

@ -28,7 +28,6 @@ import android.os.SystemClock;
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;
@ -72,20 +71,17 @@ import org.telegram.ui.Components.BulletinFactory;
import org.telegram.ui.Components.ImageUpdater;
import org.telegram.ui.Components.JoinCallAlert;
import org.telegram.ui.Components.MotionBackgroundDrawable;
import org.telegram.ui.Components.Premium.GiftPremiumBottomSheet;
import org.telegram.ui.Components.Premium.LimitReachedBottomSheet;
import org.telegram.ui.Components.Premium.boosts.BoostRepository;
import org.telegram.ui.Components.Premium.boosts.PremiumPreviewGiftToUsersBottomSheet;
import org.telegram.ui.Components.Reactions.ReactionsLayoutInBubble;
import org.telegram.ui.Components.SwipeGestureSettingsView;
import org.telegram.ui.Components.TranscribeButton;
import org.telegram.ui.DialogsActivity;
import org.telegram.ui.EditWidgetActivity;
import org.telegram.ui.LaunchActivity;
import org.telegram.ui.NotificationsSettingsActivity;
import org.telegram.ui.PremiumPreviewFragment;
import org.telegram.ui.ProfileActivity;
import org.telegram.ui.SecretMediaViewer;
import org.telegram.ui.Stars.StarsController;
import org.telegram.ui.Stories.StoriesController;
import org.telegram.ui.TopicsFragment;
@ -109,7 +105,7 @@ public class MessagesController extends BaseController implements NotificationCe
public int lastKnownSessionsCount;
private ConcurrentHashMap<Long, TLRPC.Chat> chats = new ConcurrentHashMap<>(100, 1.0f, 2);
private ConcurrentHashMap<Integer, TLRPC.EncryptedChat> encryptedChats = new ConcurrentHashMap<>(10, 1.0f, 2);
private ConcurrentHashMap<Long, TLRPC.User> users = new ConcurrentHashMap<>(100, 1.0f, 2);
private ConcurrentHashMap<Long, TLRPC.User> users = new ConcurrentHashMap<>(100, 1.0f, 3);
private ConcurrentHashMap<String, TLObject> objectsByUsernames = new ConcurrentHashMap<>(100, 1.0f, 2);
public static int stableIdPointer = 100;
@ -611,6 +607,8 @@ public class MessagesController extends BaseController implements NotificationCe
public boolean androidDisableRoundCamera2;
public int storiesPinnedToTopCountMax;
public boolean showAnnualPerMonth = false;
public boolean canEditFactcheck;
public int factcheckLengthLimit;
public int savedDialogsPinnedLimitDefault;
public int savedDialogsPinnedLimitPremium;
@ -631,7 +629,11 @@ public class MessagesController extends BaseController implements NotificationCe
public volatile boolean ignoreSetOnline;
public boolean premiumLocked;
public int transcribeButtonPressed;
public boolean starsLocked;
public boolean starsPurchaseAvailable() {
return !starsLocked;
}
public boolean premiumFeaturesBlocked() {
return premiumLocked && !getUserConfig().isPremium();
}
@ -1462,6 +1464,7 @@ public class MessagesController extends BaseController implements NotificationCe
premiumInvoiceSlug = mainPreferences.getString("premiumInvoiceSlug", null);
premiumBotUsername = mainPreferences.getString("premiumBotUsername", null);
premiumLocked = mainPreferences.getBoolean("premiumLocked", false);
starsLocked = mainPreferences.getBoolean("starsLocked", true);
transcribeButtonPressed = mainPreferences.getInt("transcribeButtonPressed", 0);
forumUpgradeParticipantsMin = mainPreferences.getInt("forumUpgradeParticipantsMin", 200);
topicsPinnedLimit = mainPreferences.getInt("topicsPinnedLimit", 3);
@ -1544,6 +1547,8 @@ public class MessagesController extends BaseController implements NotificationCe
androidDisableRoundCamera2 = mainPreferences.getBoolean("androidDisableRoundCamera2", false);
storiesPinnedToTopCountMax = mainPreferences.getInt("storiesPinnedToTopCountMax", 3);
showAnnualPerMonth = mainPreferences.getBoolean("showAnnualPerMonth", false);
canEditFactcheck = mainPreferences.getBoolean("canEditFactcheck", false);
factcheckLengthLimit = mainPreferences.getInt("factcheckLengthLimit", 1024);
scheduleTranscriptionUpdate();
BuildVars.GOOGLE_AUTH_CLIENT_ID = mainPreferences.getString("googleAuthClientId", BuildVars.GOOGLE_AUTH_CLIENT_ID);
if (mainPreferences.contains("dcDomainName2")) {
@ -2535,6 +2540,16 @@ public class MessagesController extends BaseController implements NotificationCe
}
break;
}
case "stars_purchase_blocked": {
if (value.value instanceof TLRPC.TL_jsonBool) {
if (starsLocked != ((TLRPC.TL_jsonBool) value.value).value) {
starsLocked = ((TLRPC.TL_jsonBool) value.value).value;
editor.putBoolean("starsLocked", starsLocked);
changed = true;
}
}
break;
}
case "premium_bot_username": {
if (value.value instanceof TLRPC.TL_jsonString) {
String string = ((TLRPC.TL_jsonString) value.value).value;
@ -4085,6 +4100,28 @@ public class MessagesController extends BaseController implements NotificationCe
}
break;
}
case "can_edit_factcheck": {
if (value.value instanceof TLRPC.TL_jsonBool) {
TLRPC.TL_jsonBool bool = (TLRPC.TL_jsonBool) value.value;
if (bool.value != canEditFactcheck) {
canEditFactcheck = bool.value;
editor.putBoolean("canEditFactcheck", canEditFactcheck);
changed = true;
}
}
break;
}
case "factcheck_length_limit": {
if (value.value instanceof TLRPC.TL_jsonNumber) {
TLRPC.TL_jsonNumber num = (TLRPC.TL_jsonNumber) value.value;
if ((int) num.value != factcheckLengthLimit) {
factcheckLengthLimit = (int) num.value;
editor.putInt("factcheckLengthLimit", factcheckLengthLimit);
changed = true;
}
}
break;
}
}
}
@ -4617,7 +4654,10 @@ public class MessagesController extends BaseController implements NotificationCe
collectDeviceStats = false;
smsjobsStickyNotificationEnabled = false;
showAnnualPerMonth = false;
mainPreferences.edit().remove("getfileExperimentalParams").remove("smsjobsStickyNotificationEnabled").remove("channelRevenueWithdrawalEnabled").remove("showAnnualPerMonth").apply();
canEditFactcheck = false;
starsLocked = true;
factcheckLengthLimit = 1024;
mainPreferences.edit().remove("starsLocked").remove("getfileExperimentalParams").remove("smsjobsStickyNotificationEnabled").remove("channelRevenueWithdrawalEnabled").remove("showAnnualPerMonth").remove("canEditFactcheck").remove("factcheckLengthLimit").apply();
}
private boolean savePremiumFeaturesPreviewOrder(String key, SparseIntArray array, SharedPreferences.Editor editor, ArrayList<TLRPC.JSONValue> value) {
@ -5602,6 +5642,7 @@ public class MessagesController extends BaseController implements NotificationCe
statusSettingState = 0;
Utilities.stageQueue.postRunnable(() -> {
FileLog.d("cleanup: isUpdating = false");
getConnectionsManager().setIsUpdating(false);
updatesQueueChannels.clear();
updatesStartWaitTimeChannels.clear();
@ -9704,7 +9745,7 @@ public class MessagesController extends BaseController implements NotificationCe
Paint paint = Theme.dialogs_messageNamePaint;
if (paint == null) {
paint = new Paint();
paint.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf"));
paint.setTypeface(AndroidUtilities.bold());
paint.setTextSize(AndroidUtilities.dp(14));
}
text = Emoji.replaceEmoji(text, paint.getFontMetricsInt(), false);
@ -14793,6 +14834,7 @@ public class MessagesController extends BaseController implements NotificationCe
}
if (BuildVars.LOGS_ENABLED) {
FileLog.d("start getDifference with date = " + date + " pts = " + pts + " qts = " + qts);
FileLog.d("getDifference: isUpdating = true");
}
getConnectionsManager().setIsUpdating(true);
getConnectionsManager().sendRequest(req, (response, error) -> {
@ -14973,6 +15015,7 @@ public class MessagesController extends BaseController implements NotificationCe
getMessagesStorage().setLastDateValue(res.state.date);
getMessagesStorage().setLastPtsValue(res.state.pts);
getMessagesStorage().setLastQtsValue(res.state.qts);
FileLog.d("received difference: isUpdating = false");
getConnectionsManager().setIsUpdating(false);
for (int a = 0; a < 3; a++) {
processUpdatesQueue(a, 1);
@ -14986,6 +15029,7 @@ public class MessagesController extends BaseController implements NotificationCe
getMessagesStorage().setLastSeqValue(res.seq);
getMessagesStorage().setLastDateValue(res.date);
getConnectionsManager().setIsUpdating(false);
FileLog.d("received differenceEmpty: isUpdating = false");
for (int a = 0; a < 3; a++) {
processUpdatesQueue(a, 1);
}
@ -15000,6 +15044,7 @@ public class MessagesController extends BaseController implements NotificationCe
} else {
gettingDifference = false;
getConnectionsManager().setIsUpdating(false);
FileLog.d("received: isUpdating = false");
}
});
}
@ -17683,7 +17728,7 @@ public class MessagesController extends BaseController implements NotificationCe
msg.date = getConnectionsManager().getCurrentTime();
TLRPC.User user = getMessagesController().getUser(msg.dialog_id);
if (user != null && getNotificationsSettings(currentAccount).getBoolean("EnableReactionsPreview", true)) {
ReactionsLayoutInBubble.VisibleReaction reaction = ReactionsLayoutInBubble.VisibleReaction.fromTLReaction(update.reaction).flatten();
ReactionsLayoutInBubble.VisibleReaction reaction = ReactionsLayoutInBubble.VisibleReaction.fromTL(update.reaction).flatten();
if (reaction.emojicon != null) {
msg.message = LocaleController.formatString(R.string.PushReactStory, UserObject.getFirstName(user), reaction.emojicon);
} else {
@ -17703,10 +17748,14 @@ public class MessagesController extends BaseController implements NotificationCe
getNotificationsController().processNewMessages(messageObjects, true, false, null);
} else if (baseUpdate instanceof TLRPC.TL_updateBroadcastRevenueTransactions) {
TLRPC.TL_updateBroadcastRevenueTransactions update = (TLRPC.TL_updateBroadcastRevenueTransactions) baseUpdate;
if (ChannelMonetizationLayout.instance != null) {
if (ChannelMonetizationLayout.instance != null && ChannelMonetizationLayout.instance.dialogId == DialogObject.getPeerDialogId(update.peer)) {
ChannelMonetizationLayout.instance.setupBalances(update.balances);
ChannelMonetizationLayout.instance.reloadTransactions();
}
} else if (baseUpdate instanceof TLRPC.TL_updateStarsBalance) {
TLRPC.TL_updateStarsBalance update = (TLRPC.TL_updateStarsBalance) baseUpdate;
StarsController.getInstance(currentAccount).updateBalance(update.balance);
StarsController.getInstance(currentAccount).invalidateTransactions(false);
} else if (baseUpdate instanceof TLRPC.TL_updateUser) {
TLRPC.TL_updateUser update = (TLRPC.TL_updateUser) baseUpdate;
TLRPC.User currentUser = getUser(update.user_id);
@ -20704,7 +20753,7 @@ public class MessagesController extends BaseController implements NotificationCe
long topic_id = MessageObject.getSavedDialogId(getUserConfig().getClientUserId(), message);
boolean changed = false;
for (int i = 0; i < message.reactions.results.size(); ++i) {
if (updateSavedReactionTags(topic_id, ReactionsLayoutInBubble.VisibleReaction.fromTLReaction(message.reactions.results.get(i).reaction), false, false)) {
if (updateSavedReactionTags(topic_id, ReactionsLayoutInBubble.VisibleReaction.fromTL(message.reactions.results.get(i).reaction), false, false)) {
changed = true;
}
}
@ -21023,8 +21072,13 @@ public class MessagesController extends BaseController implements NotificationCe
});
}
private boolean loadingPeerColors, loadingProfilePeerColors;
public void checkPeerColors(boolean force) {
if (peerColors == null || peerColors.needUpdate() || force) {
if (getUserConfig().getCurrentUser() == null) {
return;
}
if (!loadingPeerColors && (peerColors == null || peerColors.needUpdate() || force)) {
loadingPeerColors = true;
TLRPC.TL_help_getPeerColors req = new TLRPC.TL_help_getPeerColors();
req.hash = peerColors != null ? peerColors.hash : 0;
if (peerColors != null && peerColors.needUpdate()) {
@ -21033,13 +21087,15 @@ public class MessagesController extends BaseController implements NotificationCe
getConnectionsManager().sendRequest(req, (res, err) -> {
if (res instanceof TLRPC.TL_help_peerColors) {
AndroidUtilities.runOnUIThread(() -> {
loadingPeerColors = false;
peerColors = PeerColors.fromTL(PeerColors.TYPE_NAME, (TLRPC.TL_help_peerColors) res);
mainPreferences.edit().putString("peerColors", peerColors.toString()).apply();
});
}
});
}
if (profilePeerColors == null || profilePeerColors.needUpdate() || force) {
if (!loadingProfilePeerColors && (profilePeerColors == null || profilePeerColors.needUpdate() || force)) {
loadingProfilePeerColors = true;
TLRPC.TL_help_getPeerProfileColors req = new TLRPC.TL_help_getPeerProfileColors();
req.hash = profilePeerColors != null ? profilePeerColors.hash : 0;
if (profilePeerColors != null && profilePeerColors.needUpdate()) {
@ -21048,6 +21104,7 @@ public class MessagesController extends BaseController implements NotificationCe
getConnectionsManager().sendRequest(req, (res, err) -> {
if (res instanceof TLRPC.TL_help_peerColors) {
AndroidUtilities.runOnUIThread(() -> {
loadingProfilePeerColors = false;
profilePeerColors = PeerColors.fromTL(PeerColors.TYPE_PROFILE, (TLRPC.TL_help_peerColors) res);
mainPreferences.edit().putString("profilePeerColors", profilePeerColors.toString()).apply();
});
@ -21087,7 +21144,7 @@ public class MessagesController extends BaseController implements NotificationCe
return isUserPremiumBlocked(userId, false);
}
public boolean isUserPremiumBlocked(long userId, boolean cache) {
if (getUserConfig().isPremium()) {
if (getUserConfig().isPremium() || getUserConfig().getClientUserId() == userId) {
return false;
}
Boolean cached = cachedIsUserPremiumBlocked.get(userId);
@ -21183,4 +21240,145 @@ public class MessagesController extends BaseController implements NotificationCe
if (userFull == null) return false;
return !userFull.sponsored_enabled;
}
private boolean loadingAvailableEffects;
private TLRPC.messages_AvailableEffects availableEffects;
public TLRPC.messages_AvailableEffects getAvailableEffects() {
if (!loadingAvailableEffects) {
loadingAvailableEffects = true;
effectsFetcher.fetch(currentAccount, 0, effects -> {
if (availableEffects != effects) {
availableEffects = effects;
if (availableEffects != null) {
AnimatedEmojiDrawable.getDocumentFetcher(currentAccount).putDocuments(availableEffects.documents);
}
getNotificationCenter().postNotificationName(NotificationCenter.availableEffectsUpdate);
}
loadingAvailableEffects = false;
});
}
return availableEffects;
}
public boolean hasAvailableEffects() {
return availableEffects != null && !availableEffects.effects.isEmpty();
}
public TLRPC.TL_availableEffect getEffect(long id) {
getAvailableEffects();
if (availableEffects != null) {
for (int i = 0; i < availableEffects.effects.size(); ++i) {
if (availableEffects.effects.get(i).id == id)
return availableEffects.effects.get(i);
}
}
return null;
}
public TLRPC.Document getEffectDocument(long documentId) {
if (availableEffects != null) {
for (int i = 0; i < availableEffects.documents.size(); ++i) {
if (availableEffects.documents.get(i).id == documentId)
return availableEffects.documents.get(i);
}
}
return null;
}
private final CacheFetcher<Integer, TLRPC.messages_AvailableEffects> effectsFetcher = new CacheFetcher<Integer, TLRPC.messages_AvailableEffects>() {
@Override
protected void getRemote(int currentAccount, Integer arguments, long hash, Utilities.Callback4<Boolean, TLRPC.messages_AvailableEffects, Long, Boolean> onResult) {
TLRPC.TL_messages_getAvailableEffects req = new TLRPC.TL_messages_getAvailableEffects();
req.hash = (int) hash;
getConnectionsManager().sendRequest(req, (res, err) -> {
if (res instanceof TLRPC.TL_messages_availableEffectsNotModified) {
onResult.run(true, null, 0L, true);
} else if (res instanceof TLRPC.TL_messages_availableEffects) {
onResult.run(false, (TLRPC.TL_messages_availableEffects) res, (long) ((TLRPC.TL_messages_availableEffects) res).hash, true);
} else {
FileLog.e("getting available effects error " + (err != null ? err.code + " " + err.text : ""));
onResult.run(false, null, 0L, err == null || !(err.code == -2000 || err.code == -2001));
}
});
}
@Override
protected void getLocal(int currentAccount, Integer arguments, Utilities.Callback2<Long, TLRPC.messages_AvailableEffects> onResult) {
getMessagesStorage().getStorageQueue().postRunnable(() -> {
SQLiteCursor cursor = null;
try {
SQLiteDatabase database = MessagesStorage.getInstance(currentAccount).getDatabase();
if (database != null) {
TLRPC.messages_AvailableEffects maybeResult = null;
cursor = database.queryFinalized("SELECT data FROM effects");
if (cursor.next()) {
NativeByteBuffer data = cursor.byteBufferValue(0);
if (data != null) {
maybeResult = TLRPC.messages_AvailableEffects.TLdeserialize(data, data.readInt32(false), true);
data.reuse();
}
}
if (maybeResult instanceof TLRPC.TL_messages_availableEffects) {
TLRPC.TL_messages_availableEffects result = (TLRPC.TL_messages_availableEffects) maybeResult;
onResult.run((long) result.hash, result);
} else {
onResult.run(0L, null);
}
}
} catch (Exception e) {
FileLog.e(e);
onResult.run(0L, null);
} finally {
if (cursor != null) {
cursor.dispose();
}
}
});
}
@Override
protected void setLocal(int currentAccount, Integer arguments, TLRPC.messages_AvailableEffects data, long hash) {
MessagesStorage.getInstance(currentAccount).getStorageQueue().postRunnable(() -> {
try {
SQLiteDatabase database = MessagesStorage.getInstance(currentAccount).getDatabase();
if (database != null) {
database.executeFast("DELETE FROM effects").stepThis().dispose();
if (data != null) {
SQLitePreparedStatement state = database.executeFast("INSERT INTO effects VALUES(?)");
state.requery();
NativeByteBuffer buffer = new NativeByteBuffer(data.getObjectSize());
data.serializeToStream(buffer);
state.bindByteBuffer(1, buffer);
state.step();
buffer.reuse();
state.dispose();
}
}
} catch (Exception e) {
FileLog.e(e);
}
});
}
@Override
protected boolean saveLastTimeRequested() {
return true;
}
@Override
protected long getSavedLastTimeRequested(int hashCode) {
return mainPreferences.getLong("effects_last_" + hashCode, 0);
}
@Override
protected void setSavedLastTimeRequested(int hashCode, long time) {
mainPreferences.edit().putLong("effects_last_" + hashCode, time).apply();
}
@Override
protected boolean emitLocal(Integer arguments) {
return true;
}
};
}

View file

@ -104,7 +104,7 @@ public class MessagesStorage extends BaseController {
}
}
public final static int LAST_DB_VERSION = 153;
public final static int LAST_DB_VERSION = 155;
private boolean databaseMigrationInProgress;
public boolean showClearDatabaseAlert;
private LongSparseIntArray dialogIsForum = new LongSparseIntArray();
@ -694,6 +694,7 @@ public class MessagesStorage extends BaseController {
database.executeFast("CREATE TABLE emoji_groups(type INTEGER PRIMARY KEY, data BLOB)").stepThis().dispose();
database.executeFast("CREATE TABLE app_config(data BLOB)").stepThis().dispose();
database.executeFast("CREATE TABLE effects(data BLOB)").stepThis().dispose();
database.executeFast("CREATE TABLE stories (dialog_id INTEGER, story_id INTEGER, data BLOB, custom_params BLOB, PRIMARY KEY (dialog_id, story_id));").stepThis().dispose();
database.executeFast("CREATE TABLE stories_counter (dialog_id INTEGER PRIMARY KEY, count INTEGER, max_read INTEGER);").stepThis().dispose();
@ -721,7 +722,7 @@ public class MessagesStorage extends BaseController {
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("CREATE TABLE business_links(data BLOB, order_value INTEGER);").stepThis().dispose();
database.executeFast("CREATE TABLE fact_checks(hash INTEGER PRIMARY KEY, data BLOB, expires INTEGER);").stepThis().dispose();
database.executeFast("PRAGMA user_version = " + MessagesStorage.LAST_DB_VERSION).stepThis().dispose();
@ -1402,6 +1403,7 @@ public class MessagesStorage extends BaseController {
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();
database.executeFast("DELETE FROM effects").stepThis().dispose();
cursor = database.queryFinalized("SELECT did FROM dialogs WHERE 1");
@ -1833,7 +1835,7 @@ public class MessagesStorage extends BaseController {
getChatsInternal(TextUtils.join(",", chatsToLoad), chats);
}
if (!usersToLoad.isEmpty()) {
getUsersInternal(TextUtils.join(",", usersToLoad), users);
getUsersInternal(usersToLoad, users);
}
AndroidUtilities.runOnUIThread(() -> {
@ -2169,7 +2171,7 @@ public class MessagesStorage extends BaseController {
getEncryptedChatsInternal(TextUtils.join(",", encryptedChatIds), encryptedChats, usersToLoad);
}
if (!usersToLoad.isEmpty()) {
getUsersInternal(TextUtils.join(",", usersToLoad), users);
getUsersInternal(usersToLoad, users);
}
if (!chatsToLoad.isEmpty()) {
getChatsInternal(TextUtils.join(",", chatsToLoad), chats);
@ -2544,7 +2546,7 @@ public class MessagesStorage extends BaseController {
getEncryptedChatsInternal(TextUtils.join(",", encryptedToLoad), encryptedChats, usersToLoad);
}
if (!usersToLoad.isEmpty()) {
getUsersInternal(TextUtils.join(",", usersToLoad), users);
getUsersInternal(usersToLoad, users);
}
if (!chatsToLoad.isEmpty()) {
getChatsInternal(TextUtils.join(",", chatsToLoad), chats);
@ -2652,7 +2654,7 @@ public class MessagesStorage extends BaseController {
LongSparseArray<Boolean> mutedDialogs = new LongSparseArray<>();
LongSparseArray<Boolean> archivedDialogs = new LongSparseArray<>();
if (!usersToLoad.isEmpty()) {
getUsersInternal(TextUtils.join(",", usersToLoad), users);
getUsersInternal(usersToLoad, users, true);
for (int a = 0, N = users.size(); a < N; a++) {
TLRPC.User user = users.get(a);
boolean muted = getMessagesController().isDialogMuted(user.id, 0);
@ -2679,7 +2681,7 @@ public class MessagesStorage extends BaseController {
ArrayList<TLRPC.EncryptedChat> encryptedChats = new ArrayList<>();
getEncryptedChatsInternal(TextUtils.join(",", encryptedToLoad), encryptedChats, encUsersToLoad);
if (!encUsersToLoad.isEmpty()) {
getUsersInternal(TextUtils.join(",", encUsersToLoad), encUsers);
getUsersInternal(encUsersToLoad, encUsers, true);
for (int a = 0, N = encUsers.size(); a < N; a++) {
TLRPC.User user = encUsers.get(a);
encUsersDict.put(user.id, user);
@ -3333,7 +3335,7 @@ public class MessagesStorage extends BaseController {
}
ArrayList<TLRPC.User> users = new ArrayList<>();
if (!usersToLoad.isEmpty()) {
getUsersInternal(TextUtils.join(",", usersToLoad), users);
getUsersInternal(usersToLoad, users);
for (int a = 0, N = users.size(); a < N; a++) {
TLRPC.User user = users.get(a);
usersToLoadMap.remove(user.id);
@ -3744,7 +3746,7 @@ public class MessagesStorage extends BaseController {
}
if (!usersToLoad.isEmpty()) {
getUsersInternal(TextUtils.join(",", usersToLoad), users);
getUsersInternal(usersToLoad, users);
}
if (!chatsToLoad.isEmpty()) {
@ -3809,7 +3811,7 @@ public class MessagesStorage extends BaseController {
cursor = null;
if (!usersToLoad.isEmpty()) {
getUsersInternal(TextUtils.join(",", usersToLoad), users);
getUsersInternal(usersToLoad, users);
}
if (!chatsToLoad.isEmpty()) {
@ -4761,7 +4763,7 @@ public class MessagesStorage extends BaseController {
// loadReplyMessages(replyMessageOwners, dialogReplyMessagesIds, usersToLoad, chatsToLoad, false);
if (!usersToLoad.isEmpty()) {
getUsersInternal(TextUtils.join(",", usersToLoad), users);
getUsersInternal(usersToLoad, users);
}
if (!chatsToLoad.isEmpty()) {
getChatsInternal(TextUtils.join(",", chatsToLoad), chats);
@ -4891,7 +4893,7 @@ public class MessagesStorage extends BaseController {
if (a != null && a.results != null && a.reactions_as_tags) {
for (int j = 0; j < a.results.size(); ++j) {
ReactionsLayoutInBubble.VisibleReaction reaction = ReactionsLayoutInBubble.VisibleReaction.fromTLReaction(a.results.get(j).reaction);
ReactionsLayoutInBubble.VisibleReaction reaction = ReactionsLayoutInBubble.VisibleReaction.fromTL(a.results.get(j).reaction);
if (reaction != null) {
oldTags.put(reaction.hash, reaction);
}
@ -4899,7 +4901,7 @@ public class MessagesStorage extends BaseController {
}
if (b != null && b.results != null && b.reactions_as_tags) {
for (int j = 0; j < b.results.size(); ++j) {
ReactionsLayoutInBubble.VisibleReaction reaction = ReactionsLayoutInBubble.VisibleReaction.fromTLReaction(b.results.get(j).reaction);
ReactionsLayoutInBubble.VisibleReaction reaction = ReactionsLayoutInBubble.VisibleReaction.fromTL(b.results.get(j).reaction);
if (reaction != null) {
newTags.put(reaction.hash, reaction);
}
@ -4943,13 +4945,13 @@ public class MessagesStorage extends BaseController {
LongSparseArray<ReactionsLayoutInBubble.VisibleReaction> newTags = new LongSparseArray<>();
if (a != null && a.results != null && a.reactions_as_tags) {
for (int i = 0; i < a.results.size(); ++i) {
ReactionsLayoutInBubble.VisibleReaction reaction = ReactionsLayoutInBubble.VisibleReaction.fromTLReaction(a.results.get(i).reaction);
ReactionsLayoutInBubble.VisibleReaction reaction = ReactionsLayoutInBubble.VisibleReaction.fromTL(a.results.get(i).reaction);
oldTags.put(reaction.hash, reaction);
}
}
if (b != null && b.results != null && b.reactions_as_tags) {
for (int i = 0; i < b.results.size(); ++i) {
ReactionsLayoutInBubble.VisibleReaction reaction = ReactionsLayoutInBubble.VisibleReaction.fromTLReaction(b.results.get(i).reaction);
ReactionsLayoutInBubble.VisibleReaction reaction = ReactionsLayoutInBubble.VisibleReaction.fromTL(b.results.get(i).reaction);
newTags.put(reaction.hash, reaction);
}
}
@ -5663,7 +5665,7 @@ public class MessagesStorage extends BaseController {
LongSparseArray<Boolean> mutedDialogs = new LongSparseArray<>();
LongSparseArray<Boolean> archivedDialogs = new LongSparseArray<>();
if (!usersToLoad.isEmpty()) {
getUsersInternal(TextUtils.join(",", usersToLoad), users);
getUsersInternal(usersToLoad, users);
for (int a = 0, N = users.size(); a < N; a++) {
TLRPC.User user = users.get(a);
boolean muted = getMessagesController().isDialogMuted(user.id, 0);
@ -5691,7 +5693,7 @@ public class MessagesStorage extends BaseController {
ArrayList<TLRPC.EncryptedChat> encryptedChats = new ArrayList<>();
getEncryptedChatsInternal(TextUtils.join(",", encryptedToLoad), encryptedChats, encUsersToLoad);
if (!encUsersToLoad.isEmpty()) {
getUsersInternal(TextUtils.join(",", encUsersToLoad), encUsers);
getUsersInternal(encUsersToLoad, encUsers);
for (int a = 0, N = encUsers.size(); a < N; a++) {
TLRPC.User user = encUsers.get(a);
encUsersDict.put(user.id, user);
@ -7405,17 +7407,11 @@ public class MessagesStorage extends BaseController {
cursor.dispose();
cursor = null;
ArrayList<Long> usersToLoad = new ArrayList<Long>();
if (info instanceof TLRPC.TL_chatFull) {
StringBuilder usersToLoad = new StringBuilder();
for (int a = 0; a < info.participants.participants.size(); a++) {
TLRPC.ChatParticipant c = info.participants.participants.get(a);
if (usersToLoad.length() != 0) {
usersToLoad.append(",");
}
usersToLoad.append(c.user_id);
}
if (usersToLoad.length() != 0) {
getUsersInternal(usersToLoad.toString(), loadedUsers);
usersToLoad.add(c.user_id);
}
} else if (info instanceof TLRPC.TL_channelFull) {
cursor = database.queryFinalized("SELECT us.data, us.status, cu.data, cu.date FROM channel_users_v2 as cu LEFT JOIN users as us ON us.uid = cu.uid WHERE cu.did = " + (-chatId) + " ORDER BY cu.date DESC");
@ -7456,34 +7452,20 @@ public class MessagesStorage extends BaseController {
}
cursor.dispose();
cursor = null;
StringBuilder usersToLoad = new StringBuilder();
for (int a = 0; a < info.bot_info.size(); a++) {
TLRPC.BotInfo botInfo = info.bot_info.get(a);
if (usersToLoad.length() != 0) {
usersToLoad.append(",");
}
usersToLoad.append(botInfo.user_id);
}
if (usersToLoad.length() != 0) {
getUsersInternal(usersToLoad.toString(), loadedUsers);
usersToLoad.add(botInfo.user_id);
}
}
if (info != null && info.inviterId != 0) {
getUsersInternal("" + info.inviterId, loadedUsers);
usersToLoad.add(info.inviterId);
}
if (info != null && info.recent_requesters != null && !info.recent_requesters.isEmpty()) {
StringBuilder usersToLoad = new StringBuilder();
for (int i = 0; i < Math.min(3, info.recent_requesters.size()); ++i) {
long uid = info.recent_requesters.get(info.recent_requesters.size() - 1 - i);
if (i > 0) {
usersToLoad.append(',');
}
usersToLoad.append(uid);
}
if (usersToLoad.length() > 0) {
getUsersInternal(usersToLoad.toString(), loadedUsers);
usersToLoad.add(info.recent_requesters.get(info.recent_requesters.size() - 1 - i));
}
}
getUsersInternal(usersToLoad, loadedUsers);
cursor = getMessagesStorage().getDatabase().queryFinalized(String.format(Locale.US, "SELECT mid FROM chat_pinned_v2 WHERE uid = %d ORDER BY mid DESC", -chatId));
while (cursor.next()) {
@ -7956,23 +7938,20 @@ public class MessagesStorage extends BaseController {
SQLiteCursor cursor = null;
try {
cursor = database.queryFinalized("SELECT * FROM contacts WHERE 1");
StringBuilder uids = new StringBuilder();
ArrayList<Long> uids = new ArrayList<>();
while (cursor.next()) {
long userId = cursor.intValue(0);
TLRPC.TL_contact contact = new TLRPC.TL_contact();
contact.user_id = userId;
contact.mutual = cursor.intValue(1) == 1;
if (uids.length() != 0) {
uids.append(",");
}
contacts.add(contact);
uids.append(contact.user_id);
uids.add(contact.user_id);
}
cursor.dispose();
cursor = null;
if (uids.length() != 0) {
getUsersInternal(uids.toString(), users);
if (!uids.isEmpty()) {
getUsersInternal(uids, users);
}
} catch (Exception e) {
contacts.clear();
@ -8161,7 +8140,7 @@ public class MessagesStorage extends BaseController {
}
if (!usersToLoad.isEmpty()) {
getUsersInternal(TextUtils.join(",", usersToLoad), users);
getUsersInternal(usersToLoad, users);
}
if (!chatsToLoad.isEmpty()) {
@ -9203,7 +9182,7 @@ public class MessagesStorage extends BaseController {
loadReplyMessages(replyMessageOwners, dialogReplyMessagesIds, usersToLoad, chatsToLoad, mode);
}
if (!usersToLoad.isEmpty()) {
getUsersInternal(TextUtils.join(",", usersToLoad), res.users);
getUsersInternal(usersToLoad, res.users);
}
if (!chatsToLoad.isEmpty()) {
getChatsInternal(TextUtils.join(",", chatsToLoad), res.chats);
@ -9478,7 +9457,7 @@ public class MessagesStorage extends BaseController {
getChatsInternal(TextUtils.join(",", chatsToLoad), chats);
}
if (!usersToLoad.isEmpty()) {
getUsersInternal(TextUtils.join(",", usersToLoad), users);
getUsersInternal(usersToLoad, users);
}
}
} catch (Exception e) {
@ -9600,7 +9579,7 @@ public class MessagesStorage extends BaseController {
getChatsInternal(TextUtils.join(",", chatsToLoad), chats);
}
if (!usersToLoad.isEmpty()) {
getUsersInternal(TextUtils.join(",", usersToLoad), users);
getUsersInternal(usersToLoad, users);
}
} catch (Exception e) {
checkSQLException(e);
@ -9855,7 +9834,7 @@ public class MessagesStorage extends BaseController {
getEncryptedChatsInternal("" + chatId, encryptedChats, usersToLoad);
if (!encryptedChats.isEmpty() && !usersToLoad.isEmpty()) {
ArrayList<TLRPC.User> users = new ArrayList<>();
getUsersInternal(TextUtils.join(",", usersToLoad), users);
getUsersInternal(usersToLoad, users);
if (!users.isEmpty()) {
result.add(encryptedChats.get(0));
result.add(users.get(0));
@ -10197,29 +10176,87 @@ public class MessagesStorage extends BaseController {
state.dispose();
}
public void getUsersInternal(String usersToLoad, ArrayList<TLRPC.User> result) throws Exception {
if (usersToLoad == null || usersToLoad.length() == 0 || result == null) {
public void getUsersInternal(ArrayList<Long> userIds, ArrayList<TLRPC.User> result) throws Exception {
getUsersInternal(userIds, result, false);
}
public void getUsersInternal(ArrayList<Long> userIds, ArrayList<TLRPC.User> result, boolean putUnknown) throws Exception {
if (userIds == null || userIds.isEmpty() || result == null) {
return;
}
SQLiteCursor cursor = database.queryFinalized(String.format(Locale.US, "SELECT data, status FROM users WHERE uid IN(%s)", usersToLoad));
while (cursor.next()) {
try {
NativeByteBuffer data = cursor.byteBufferValue(0);
if (data != null) {
TLRPC.User user = TLRPC.User.TLdeserialize(data, data.readInt32(false), false);
data.reuse();
if (user != null) {
if (user.status != null) {
user.status.expires = cursor.intValue(1);
}
result.add(user);
}
if (userIds.size() > 50) {
for (int i = 0; i < userIds.size(); ++i) {
long userId = userIds.get(i);
TLRPC.User user = getMessagesController().getUser(userId);
if (user != null) {
result.add(user);
userIds.remove(i);
i--;
}
} catch (Exception e) {
checkSQLException(e);
}
}
cursor.dispose();
if (!userIds.isEmpty()) {
SQLiteCursor cursor = database.queryFinalized(String.format(Locale.US, "SELECT data, status FROM users WHERE uid IN(%s)", TextUtils.join(",", userIds)));
while (cursor.next()) {
try {
NativeByteBuffer data = cursor.byteBufferValue(0);
if (data != null) {
TLRPC.User user = TLRPC.User.TLdeserialize(data, data.readInt32(false), false);
data.reuse();
if (user != null) {
if (user.status != null) {
user.status.expires = cursor.intValue(1);
}
result.add(user);
if (userIds.size() > 50 && putUnknown) {
getMessagesController().putUser(user, true, false);
}
}
}
} catch (Exception e) {
checkSQLException(e);
}
}
cursor.dispose();
}
}
public void getUsersInternal(HashSet<Long> userIds, ArrayList<TLRPC.User> result) throws Exception {
if (userIds == null || userIds.isEmpty() || result == null) {
return;
}
if (userIds.size() > 50) {
Iterator<Long> iterator = userIds.iterator();
while (iterator.hasNext()) {
Long userId = iterator.next();
TLRPC.User user = getMessagesController().getUser(userId);
if (user != null) {
result.add(user);
iterator.remove();
}
}
}
if (!userIds.isEmpty()) {
SQLiteCursor cursor = database.queryFinalized(String.format(Locale.US, "SELECT data, status FROM users WHERE uid IN(%s)", TextUtils.join(",", userIds)));
while (cursor.next()) {
try {
NativeByteBuffer data = cursor.byteBufferValue(0);
if (data != null) {
TLRPC.User user = TLRPC.User.TLdeserialize(data, data.readInt32(false), false);
data.reuse();
if (user != null) {
if (user.status != null) {
user.status.expires = cursor.intValue(1);
}
result.add(user);
}
}
} catch (Exception e) {
checkSQLException(e);
}
}
cursor.dispose();
}
}
public void getChatsInternal(String chatsToLoad, ArrayList<TLRPC.Chat> result) throws Exception {
@ -12760,18 +12797,15 @@ public class MessagesStorage extends BaseController {
database.commitTransaction();
}
} else {
StringBuilder ids = new StringBuilder();
ArrayList<Long> ids = new ArrayList<Long>();
LongSparseArray<TLRPC.User> usersDict = new LongSparseArray<>();
for (int a = 0, N = users.size(); a < N; a++) {
TLRPC.User user = users.get(a);
if (ids.length() != 0) {
ids.append(",");
}
ids.append(user.id);
ids.add(user.id);
usersDict.put(user.id, user);
}
ArrayList<TLRPC.User> loadedUsers = new ArrayList<>();
getUsersInternal(ids.toString(), loadedUsers);
getUsersInternal(ids, loadedUsers);
for (int a = 0, N = loadedUsers.size(); a < N; a++) {
TLRPC.User user = loadedUsers.get(a);
TLRPC.User updateUser = usersDict.get(user.id);
@ -13795,7 +13829,7 @@ public class MessagesStorage extends BaseController {
}
if (!usersToLoad.isEmpty()) {
getUsersInternal(TextUtils.join(",", usersToLoad), dialogs.users);
getUsersInternal(usersToLoad, dialogs.users);
}
getMessagesController().getTopicsController().updateTopicsWithDeletedMessages(originalDialogId, messages);
@ -15648,7 +15682,7 @@ public class MessagesStorage extends BaseController {
getChatsInternal(TextUtils.join(",", chatsToLoad), dialogs.chats);
}
if (!usersToLoad.isEmpty()) {
getUsersInternal(TextUtils.join(",", usersToLoad), dialogs.users);
getUsersInternal(usersToLoad, dialogs.users);
}
ArrayList<TLRPC.UserFull> fullUsers = null;
if (!dialogUsers.isEmpty()) {
@ -16489,7 +16523,9 @@ public class MessagesStorage extends BaseController {
TLRPC.User user = null;
try {
ArrayList<TLRPC.User> users = new ArrayList<>();
getUsersInternal("" + userId, users);
ArrayList<Long> userIds = new ArrayList<>();
userIds.add(userId);
getUsersInternal(userIds, users);
if (!users.isEmpty()) {
user = users.get(0);
}
@ -16502,7 +16538,7 @@ public class MessagesStorage extends BaseController {
public ArrayList<TLRPC.User> getUsers(ArrayList<Long> uids) {
ArrayList<TLRPC.User> users = new ArrayList<>();
try {
getUsersInternal(TextUtils.join(",", uids), users);
getUsersInternal(uids, users);
} catch (Exception e) {
users.clear();
checkSQLException(e);

View file

@ -221,7 +221,7 @@ public class MusicBrowserService extends MediaBrowserService implements Notifica
cursor.dispose();
if (!usersToLoad.isEmpty()) {
ArrayList<TLRPC.User> usersArrayList = new ArrayList<>();
messagesStorage.getUsersInternal(TextUtils.join(",", usersToLoad), usersArrayList);
messagesStorage.getUsersInternal(usersToLoad, usersArrayList);
for (int a = 0; a < usersArrayList.size(); a++) {
TLRPC.User user = usersArrayList.get(a);
users.put(user.id, user);

View file

@ -643,7 +643,7 @@ public class MusicPlayerService extends Service implements NotificationCenter.No
private float getPlaybackSpeed(boolean isPlaying, MessageObject messageObject) {
if (isPlaying) {
if (messageObject.isVoice() || messageObject.isRoundVideo()) {
if (messageObject != null && (messageObject.isVoice() || messageObject.isRoundVideo())) {
return MediaController.getInstance().getPlaybackSpeed(false);
}
return 1;

View file

@ -93,6 +93,7 @@ public class NotificationCenter {
public static final int pinnedInfoDidLoad = totalEvents++;
public static final int botKeyboardDidLoad = totalEvents++;
public static final int chatSearchResultsAvailable = totalEvents++;
public static final int hashtagSearchUpdated = totalEvents++;
public static final int chatSearchResultsLoading = totalEvents++;
public static final int musicDidLoad = totalEvents++;
public static final int moreMusicDidLoad = totalEvents++;
@ -247,6 +248,11 @@ public class NotificationCenter {
public static final int timezonesUpdated = totalEvents++;
public static final int customStickerCreated = totalEvents++;
public static final int premiumFloodWaitReceived = totalEvents++;
public static final int availableEffectsUpdate = totalEvents++;
public static final int starOptionsLoaded = totalEvents++;
public static final int starBalanceUpdated = totalEvents++;
public static final int starTransactionsLoaded = totalEvents++;
public static final int factCheckLoaded = totalEvents++;
//global
public static final int pushMessagesUpdated = totalEvents++;

View file

@ -3933,7 +3933,8 @@ public class NotificationsController extends BaseController {
chatName = UserObject.getUserName(user);
}
boolean passcode = AndroidUtilities.needShowPasscode() || SharedConfig.isWaitingForPasscodeEnter;
if (DialogObject.isEncryptedDialog(dialog_id) || pushDialogs.size() > 1 || passcode) {
final boolean allowSummary = !"samsung".equalsIgnoreCase(Build.MANUFACTURER);
if (DialogObject.isEncryptedDialog(dialog_id) || allowSummary && pushDialogs.size() > 1 || passcode) {
if (passcode) {
if (chatId != 0) {
name = LocaleController.getString("NotificationHiddenChatName", R.string.NotificationHiddenChatName);
@ -3952,29 +3953,33 @@ public class NotificationsController extends BaseController {
}
String detailText;
if (UserConfig.getActivatedAccountsCount() > 1) {
if (pushDialogs.size() == 1) {
detailText = UserObject.getFirstName(getUserConfig().getCurrentUser());
if (allowSummary) {
if (UserConfig.getActivatedAccountsCount() > 1) {
if (pushDialogs.size() == 1) {
detailText = UserObject.getFirstName(getUserConfig().getCurrentUser());
} else {
detailText = UserObject.getFirstName(getUserConfig().getCurrentUser()) + "";
}
} else {
detailText = UserObject.getFirstName(getUserConfig().getCurrentUser()) + "";
detailText = "";
}
if (pushDialogs.size() != 1 || Build.VERSION.SDK_INT < 23) {
if (pushDialogs.size() == 1) {
detailText += LocaleController.formatPluralString("NewMessages", total_unread_count);
} else {
detailText += LocaleController.formatString("NotificationMessagesPeopleDisplayOrder", R.string.NotificationMessagesPeopleDisplayOrder, LocaleController.formatPluralString("NewMessages", total_unread_count), LocaleController.formatPluralString("FromChats", pushDialogs.size()));
}
}
} else {
detailText = "";
}
if (pushDialogs.size() != 1 || Build.VERSION.SDK_INT < 23) {
if (pushDialogs.size() == 1) {
detailText += LocaleController.formatPluralString("NewMessages", total_unread_count);
} else {
detailText += LocaleController.formatString("NotificationMessagesPeopleDisplayOrder", R.string.NotificationMessagesPeopleDisplayOrder, LocaleController.formatPluralString("NewMessages", total_unread_count), LocaleController.formatPluralString("FromChats", pushDialogs.size()));
}
}
NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(ApplicationLoader.applicationContext);
int silent = 2;
String lastMessage = null;
boolean hasNewMessages = false;
if (pushMessages.size() <= 1) {
if (pushMessages.size() <= 1 || !allowSummary) {
boolean[] text = new boolean[1];
String message = lastMessage = getStringForMessage(lastMessageObject, false, text, null);
silent = isSilentMessage(lastMessageObject) ? 1 : 0;
@ -3993,6 +3998,9 @@ public class NotificationsController extends BaseController {
}
}
mBuilder.setContentText(message);
if (!allowSummary) {
detailText = message;
}
mBuilder.setStyle(new NotificationCompat.BigTextStyle().bigText(message));
} else {
mBuilder.setContentText(detailText);
@ -5043,11 +5051,19 @@ public class NotificationsController extends BaseController {
Uri uriFinal = uri;
ApplicationLoader.applicationContext.grantUriPermission("com.android.systemui", uri, Intent.FLAG_GRANT_READ_URI_PERMISSION);
AndroidUtilities.runOnUIThread(() -> {
ApplicationLoader.applicationContext.revokeUriPermission(uriFinal, Intent.FLAG_GRANT_READ_URI_PERMISSION);
if (blurredAttach != null) {
blurredAttach.delete();
try {
ApplicationLoader.applicationContext.revokeUriPermission(uriFinal, Intent.FLAG_GRANT_READ_URI_PERMISSION);
} catch (Exception e) {
FileLog.e(e);
}
}, 20000);
try {
if (blurredAttach != null) {
blurredAttach.delete();
}
} catch (Exception e) {
FileLog.e(e);
}
}, 20_000);
if (!TextUtils.isEmpty(messageObject.caption)) {
messagingStyle.addMessage(messageObject.caption, ((long) messageObject.messageOwner.date) * 1000, person);
@ -5438,7 +5454,7 @@ public class NotificationsController extends BaseController {
if (textPaint == null) {
textPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG);
textPaint.setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM));
textPaint.setTypeface(AndroidUtilities.bold());
textPaint.setTextSize(sz * .25f);
textPaint.setColor(0xFFFFFFFF);
}

View file

@ -811,7 +811,7 @@ public class SavedMessagesController {
}
if (!usersToLoad.isEmpty()) {
messagesStorage.getUsersInternal(TextUtils.join(",", usersToLoad), users);
messagesStorage.getUsersInternal(usersToLoad, users);
}
if (!chatsToLoad.isEmpty()) {
messagesStorage.getChatsInternal(TextUtils.join(",", chatsToLoad), chats);
@ -886,7 +886,7 @@ public class SavedMessagesController {
}
if (!usersToLoad.isEmpty()) {
messagesStorage.getUsersInternal(TextUtils.join(",", usersToLoad), users);
messagesStorage.getUsersInternal(usersToLoad, users);
}
if (!chatsToLoad.isEmpty()) {
messagesStorage.getChatsInternal(TextUtils.join(",", chatsToLoad), chats);

View file

@ -960,7 +960,7 @@ public class SecretChatHelper extends BaseController {
}
newMessage.media.document.thumbs.add(photoSize);
newMessage.media.document.flags |= 1;
TLRPC.TL_documentAttributeVideo attributeVideo = new TLRPC.TL_documentAttributeVideo();
TLRPC.TL_documentAttributeVideo_layer159 attributeVideo = new TLRPC.TL_documentAttributeVideo_layer159();
attributeVideo.w = decryptedMessage.media.w;
attributeVideo.h = decryptedMessage.media.h;
attributeVideo.duration = decryptedMessage.media.duration;

View file

@ -66,6 +66,9 @@ import org.telegram.ui.ChatActivity;
import org.telegram.ui.Components.AlertsCreator;
import org.telegram.ui.Components.AnimatedEmojiSpan;
import org.telegram.ui.Components.AnimatedFileDrawable;
import org.telegram.ui.LaunchActivity;
import org.telegram.ui.Stars.StarsController;
import org.telegram.ui.Stars.StarsIntroActivity;
import org.telegram.ui.bots.BotWebViewSheet;
import org.telegram.ui.Components.Bulletin;
import org.telegram.ui.Components.LayoutHelper;
@ -1672,7 +1675,22 @@ public class SendMessagesHelper extends BaseController implements NotificationCe
}
newDocument.size = document.size;
newDocument.dc_id = document.dc_id;
newDocument.attributes = new ArrayList<>(document.attributes);
newDocument.attributes = new ArrayList<>();
for (int i = 0; i < document.attributes.size(); ++i) {
TLRPC.DocumentAttribute attr = document.attributes.get(i);
if (attr instanceof TLRPC.TL_documentAttributeVideo) {
TLRPC.TL_documentAttributeVideo_layer159 attr2 = new TLRPC.TL_documentAttributeVideo_layer159();
attr2.flags = attr.flags;
attr2.round_message = attr.round_message;
attr2.supports_streaming = attr.supports_streaming;
attr2.duration = attr.duration;
attr2.w = attr.w;
attr2.h = attr.h;
newDocument.attributes.add(attr2);
} else {
newDocument.attributes.add(attr);
}
}
if (newDocument.mime_type == null) {
newDocument.mime_type = "";
}
@ -1993,6 +2011,7 @@ public class SendMessagesHelper extends BaseController implements NotificationCe
} else {
newMsg.media = msgObj.messageOwner.media;
}
newMsg.invert_media = msgObj.messageOwner.invert_media;
if (newMsg.media != null) {
newMsg.flags |= TLRPC.MESSAGE_FLAG_HAS_MEDIA;
}
@ -3154,12 +3173,20 @@ public class SendMessagesHelper extends BaseController implements NotificationCe
AlertsCreator.showOpenUrlAlert(parentFragment, button.url, false, true);
}
} else if (button instanceof TLRPC.TL_keyboardButtonBuy) {
if (response instanceof TLRPC.TL_payments_paymentForm) {
final TLRPC.TL_payments_paymentForm form = (TLRPC.TL_payments_paymentForm) response;
if (response instanceof TLRPC.TL_payments_paymentFormStars) {
TLRPC.InputInvoice inputInvoice = ((TLRPC.TL_payments_getPaymentForm) request[0]).invoice;
StarsController.getInstance(currentAccount).openPaymentForm(inputInvoice, (TLRPC.TL_payments_paymentFormStars) response, () -> {
waitingForCallback.remove(key);
finalKeys.remove(key);
}, status -> {});
} else if (response instanceof TLRPC.PaymentForm) {
final TLRPC.PaymentForm form = (TLRPC.PaymentForm) response;
getMessagesController().putUsers(form.users, false);
parentFragment.presentFragment(new PaymentFormActivity(form, messageObject, parentFragment));
} else if (response instanceof TLRPC.TL_payments_paymentReceipt) {
parentFragment.presentFragment(new PaymentFormActivity((TLRPC.TL_payments_paymentReceipt) response));
} else if (response instanceof TLRPC.TL_payments_paymentReceiptStars) {
StarsIntroActivity.showTransactionSheet(LaunchActivity.instance != null ? LaunchActivity.instance : ApplicationLoader.applicationContext, currentAccount, (TLRPC.TL_payments_paymentReceiptStars) response, null);
} else if (response instanceof TLRPC.PaymentReceipt) {
parentFragment.presentFragment(new PaymentFormActivity((TLRPC.PaymentReceipt) response));
}
} else {
TLRPC.TL_messages_botCallbackAnswer res = (TLRPC.TL_messages_botCallbackAnswer) response;
@ -3333,11 +3360,13 @@ public class SendMessagesHelper extends BaseController implements NotificationCe
req.theme_params.data = themeParams.toString();
req.flags |= 1;
}
request[0] = req;
getConnectionsManager().sendRequest(req, requestDelegate, ConnectionsManager.RequestFlagFailOnServerErrors);
} else {
TLRPC.TL_payments_getPaymentReceipt req = new TLRPC.TL_payments_getPaymentReceipt();
req.msg_id = messageObject.messageOwner.media.receipt_msg_id;
req.peer = getMessagesController().getInputPeer(messageObject.messageOwner.peer_id);
request[0] = req;
getConnectionsManager().sendRequest(req, requestDelegate, ConnectionsManager.RequestFlagFailOnServerErrors);
}
} else {
@ -3866,6 +3895,10 @@ public class SendMessagesHelper extends BaseController implements NotificationCe
newMsg.flags |= 1073741824;
}
}
if (sendMessageParams.effect_id != 0) {
newMsg.flags2 |= 4;
newMsg.effect = sendMessageParams.effect_id;
}
if (params != null && params.containsKey("bot")) {
if (encryptedChat != null) {
newMsg.via_bot_name = params.get("bot_name");
@ -4203,6 +4236,10 @@ public class SendMessagesHelper extends BaseController implements NotificationCe
reqSend.flags |= 131072;
reqSend.quick_reply_shortcut = newMsg.quick_reply_shortcut;
}
if (sendMessageParams.effect_id != 0) {
reqSend.flags |= 262144;
reqSend.effect = sendMessageParams.effect_id;
}
reqSend.invert_media = newMsg.invert_media;
performSendMessageRequest(reqSend, newMsgObj, null, null, parentObject, params, scheduleDate != 0);
if (retryMessageObject == null) {
@ -4243,6 +4280,10 @@ public class SendMessagesHelper extends BaseController implements NotificationCe
reqSend.schedule_date = scheduleDate;
reqSend.flags |= 1024;
}
if (sendMessageParams.effect_id != 0) {
reqSend.flags |= 262144;
reqSend.effect = sendMessageParams.effect_id;
}
reqSend.invert_media = newMsg.invert_media;
performSendMessageRequest(reqSend, newMsgObj, null, null, parentObject, params, scheduleDate != 0);
if (retryMessageObject == null) {
@ -4581,6 +4622,11 @@ public class SendMessagesHelper extends BaseController implements NotificationCe
request.quick_reply_shortcut = newMsg.quick_reply_shortcut;
request.flags |= 131072;
}
if (newMsg.effect != 0) {
request.flags |= 262144;
request.effect = newMsg.effect;
}
request.invert_media = sendMessageParams.invert_media;
delayedMessage.sendRequest = request;
}
delayedMessage.messageObjects.add(newMsgObj);
@ -4637,6 +4683,11 @@ public class SendMessagesHelper extends BaseController implements NotificationCe
request.flags |= 131072;
request.quick_reply_shortcut = newMsg.quick_reply_shortcut;
}
if (sendMessageParams.effect_id != 0) {
request.flags |= 262144;
request.effect = sendMessageParams.effect_id;
}
request.invert_media = newMsg.invert_media;
if (delayedMessage != null) {
delayedMessage.sendRequest = request;
@ -6738,7 +6789,7 @@ public class SendMessagesHelper extends BaseController implements NotificationCe
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<TLRPC.MessageEntity> entities, final MessageObject editingMessageObject, long[] groupId, boolean isGroupFinal, CharSequence caption, boolean notify, int scheduleDate, Integer[] docType, boolean forceDocument, String quickReplyShortcut, int quickReplyShortcutId) {
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<TLRPC.MessageEntity> entities, final MessageObject editingMessageObject, long[] groupId, boolean isGroupFinal, CharSequence caption, boolean notify, int scheduleDate, Integer[] docType, boolean forceDocument, String quickReplyShortcut, int quickReplyShortcutId, long effectId, boolean invertMedia) {
if ((path == null || path.length() == 0) && uri == null) {
return ERROR_TYPE_UNSUPPORTED;
}
@ -7023,6 +7074,8 @@ public class SendMessagesHelper extends BaseController implements NotificationCe
sendMessageParams.replyQuote = quote;
sendMessageParams.quick_reply_shortcut = quickReplyShortcut;
sendMessageParams.quick_reply_shortcut_id = quickReplyShortcutId;
sendMessageParams.effect_id = effectId;
sendMessageParams.invert_media = invertMedia;
accountInstance.getSendMessagesHelper().sendMessage(sendMessageParams);
}
});
@ -7054,7 +7107,7 @@ public class SendMessagesHelper extends BaseController implements NotificationCe
}
@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, String quickReplyShortcut, int quickReplyShortcutId) {
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, boolean invertMedia) {
if ((path == null || originalPath == null) && uri == null) {
return;
}
@ -7069,11 +7122,11 @@ public class SendMessagesHelper extends BaseController implements NotificationCe
paths.add(path);
originalPaths.add(originalPath);
}
prepareSendingDocuments(accountInstance, paths, originalPaths, uris, caption, mine, dialogId, replyToMsg, replyToTopMsg, storyItem, quote, editingMessageObject, notify, scheduleDate, inputContent, quickReplyShortcut, quickReplyShortcutId);
prepareSendingDocuments(accountInstance, paths, originalPaths, uris, caption, mine, dialogId, replyToMsg, replyToTopMsg, storyItem, quote, editingMessageObject, notify, scheduleDate, inputContent, quickReplyShortcut, quickReplyShortcutId, 0, invertMedia);
}
@UiThread
public static void prepareSendingAudioDocuments(AccountInstance accountInstance, ArrayList<MessageObject> messageObjects, CharSequence caption, long dialogId, MessageObject replyToMsg, MessageObject replyToTopMsg, TL_stories.StoryItem storyItem, boolean notify, int scheduleDate, MessageObject editingMessageObject, String quickReplyShortcut, int quickReplyShortcutId) {
public static void prepareSendingAudioDocuments(AccountInstance accountInstance, ArrayList<MessageObject> messageObjects, CharSequence caption, long dialogId, MessageObject replyToMsg, MessageObject replyToTopMsg, TL_stories.StoryItem storyItem, boolean notify, int scheduleDate, MessageObject editingMessageObject, String quickReplyShortcut, int quickReplyShortcutId, long effectId, boolean invertMedia) {
new Thread(() -> {
int count = messageObjects.size();
long groupId = 0;
@ -7140,6 +7193,8 @@ public class SendMessagesHelper extends BaseController implements NotificationCe
sendMessageParams.replyToStoryItem = storyItem;
sendMessageParams.quick_reply_shortcut = quickReplyShortcut;
sendMessageParams.quick_reply_shortcut_id = quickReplyShortcutId;
sendMessageParams.effect_id = effectId;
sendMessageParams.invert_media = invertMedia;
accountInstance.getSendMessagesHelper().sendMessage(sendMessageParams);
}
});
@ -7168,7 +7223,7 @@ public class SendMessagesHelper extends BaseController implements NotificationCe
}
@UiThread
public static void prepareSendingDocuments(AccountInstance accountInstance, ArrayList<String> paths, ArrayList<String> originalPaths, ArrayList<Uri> 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) {
public static void prepareSendingDocuments(AccountInstance accountInstance, ArrayList<String> paths, ArrayList<String> originalPaths, ArrayList<Uri> 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, long effectId, boolean invertMedia) {
if (paths == null && originalPaths == null && uris == null || paths != null && originalPaths != null && paths.size() != originalPaths.size()) {
return;
}
@ -7179,7 +7234,7 @@ public class SendMessagesHelper extends BaseController implements NotificationCe
Integer[] docType = new Integer[1];
boolean isEncrypted = DialogObject.isEncryptedDialog(dialogId);
boolean first = true;
if (paths != null) {
int count = paths.size();
for (int a = 0; a < count; a++) {
@ -7193,7 +7248,8 @@ public class SendMessagesHelper extends BaseController implements NotificationCe
}
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, quickReplyShortcut, quickReplyShortcutId);
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, first ? effectId : 0, invertMedia);
first = false;
if (prevGroupId != groupId[0] || groupId[0] == -1) {
mediaCount = 1;
}
@ -7214,7 +7270,8 @@ public class SendMessagesHelper extends BaseController implements NotificationCe
}
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, quickReplyShortcut, quickReplyShortcutId);
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, first ? effectId : 0, invertMedia);
first = false;
if (prevGroupId != groupId[0] || groupId[0] == -1) {
mediaCount = 1;
}
@ -7246,11 +7303,11 @@ public class SendMessagesHelper extends BaseController implements NotificationCe
@UiThread
public static void prepareSendingPhoto(AccountInstance accountInstance, String imageFilePath, Uri imageUri, long dialogId, MessageObject replyToMsg, MessageObject replyToTopMsg, ChatActivity.ReplyQuote quote, CharSequence caption, ArrayList<TLRPC.MessageEntity> entities, ArrayList<TLRPC.InputDocument> 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);
prepareSendingPhoto(accountInstance, imageFilePath, null, imageUri, dialogId, replyToMsg, replyToTopMsg, null, null, entities, stickers, inputContent, ttl, editingMessageObject, null, notify, scheduleDate, mode, false, caption, quickReplyShortcut, quickReplyShortcutId, 0);
}
@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<TLRPC.MessageEntity> entities, ArrayList<TLRPC.InputDocument> stickers, InputContentInfoCompat inputContent, int ttl, MessageObject editingMessageObject, VideoEditedInfo videoEditedInfo, boolean notify, int scheduleDate, int mode, boolean forceDocument, CharSequence caption, String quickReplyShortcut, int quickReplyShortcutId) {
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<TLRPC.MessageEntity> entities, ArrayList<TLRPC.InputDocument> stickers, InputContentInfoCompat inputContent, int ttl, MessageObject editingMessageObject, VideoEditedInfo videoEditedInfo, boolean notify, int scheduleDate, int mode, boolean forceDocument, CharSequence caption, String quickReplyShortcut, int quickReplyShortcutId, long effectId) {
SendingMediaInfo info = new SendingMediaInfo();
info.path = imageFilePath;
info.thumbPath = thumbFilePath;
@ -7266,7 +7323,7 @@ public class SendMessagesHelper extends BaseController implements NotificationCe
info.videoEditedInfo = videoEditedInfo;
ArrayList<SendingMediaInfo> infos = new ArrayList<>();
infos.add(info);
prepareSendingMedia(accountInstance, infos, dialogId, replyToMsg, replyToTopMsg, null, quote, forceDocument, false, editingMessageObject, notify, scheduleDate, mode, false, inputContent, quickReplyShortcut, quickReplyShortcutId);
prepareSendingMedia(accountInstance, infos, dialogId, replyToMsg, replyToTopMsg, null, quote, forceDocument, false, editingMessageObject, notify, scheduleDate, mode, false, inputContent, quickReplyShortcut, quickReplyShortcutId, effectId, false);
}
@UiThread
@ -7517,6 +7574,22 @@ public class SendMessagesHelper extends BaseController implements NotificationCe
final Bitmap[] precahcedThumb = new Bitmap[1];
final String[] precachedKey = new String[1];
if (isEncrypted && document != null) {
for (int i = 0; i < document.attributes.size(); ++i) {
if (document.attributes.get(i) instanceof TLRPC.TL_documentAttributeVideo) {
TLRPC.TL_documentAttributeVideo attr = (TLRPC.TL_documentAttributeVideo) document.attributes.get(i);
TLRPC.TL_documentAttributeVideo_layer159 attr2 = new TLRPC.TL_documentAttributeVideo_layer159();
attr2.flags = attr.flags;
attr2.round_message = attr.round_message;
attr2.supports_streaming = attr.supports_streaming;
attr2.duration = attr.duration;
attr2.w = attr.w;
attr2.h = attr.h;
document.attributes.set(i, attr2);
}
}
}
if (MessageObject.isGifDocument(document)) {
TLRPC.PhotoSize photoSizeThumb = FileLoader.getClosestPhotoSizeWithSize(document.thumbs, 320);
File gifFile = FileLoader.getInstance(accountInstance.getCurrentAccount()).getPathToAttach(document);
@ -7668,12 +7741,12 @@ public class SendMessagesHelper extends BaseController implements NotificationCe
}
@UiThread
public static void prepareSendingText(AccountInstance accountInstance, String text, long dialogId, boolean notify, int scheduleDate) {
prepareSendingText(accountInstance, text, dialogId, 0, notify, scheduleDate);
public static void prepareSendingText(AccountInstance accountInstance, String text, long dialogId, boolean notify, int scheduleDate, long effectId) {
prepareSendingText(accountInstance, text, dialogId, 0, notify, scheduleDate, effectId);
}
@UiThread
public static void prepareSendingText(AccountInstance accountInstance, String text, long dialogId, long topicId, boolean notify, int scheduleDate) {
public static void prepareSendingText(AccountInstance accountInstance, String text, long dialogId, long topicId, boolean notify, int scheduleDate, long effectId) {
accountInstance.getMessagesStorage().getStorageQueue().postRunnable(() -> Utilities.stageQueue.postRunnable(() -> AndroidUtilities.runOnUIThread(() -> {
String textFinal = getTrimmedString(text);
if (textFinal.length() != 0) {
@ -7688,7 +7761,11 @@ public class SendMessagesHelper extends BaseController implements NotificationCe
}
for (int a = 0; a < count; a++) {
String mess = textFinal.substring(a * 4096, Math.min((a + 1) * 4096, textFinal.length()));
accountInstance.getSendMessagesHelper().sendMessage(SendMessagesHelper.SendMessageParams.of(mess, dialogId, replyToMsg, replyToMsg, null, true, null, null, null, notify, scheduleDate, null, false));
SendMessagesHelper.SendMessageParams params = SendMessagesHelper.SendMessageParams.of(mess, dialogId, replyToMsg, replyToMsg, null, true, null, null, null, notify, scheduleDate, null, false);
if (a == 0) {
params.effect_id = effectId;
}
accountInstance.getSendMessagesHelper().sendMessage(params);
}
}
})));
@ -7821,7 +7898,7 @@ public class SendMessagesHelper extends BaseController implements NotificationCe
}
@UiThread
public static void prepareSendingMedia(AccountInstance accountInstance, ArrayList<SendingMediaInfo> 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) {
public static void prepareSendingMedia(AccountInstance accountInstance, ArrayList<SendingMediaInfo> 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, long effectId, boolean invertMedia) {
if (media.isEmpty()) {
return;
}
@ -7926,6 +8003,7 @@ public class SendMessagesHelper extends BaseController implements NotificationCe
int mediaCount = 0;
for (int a = 0; a < count; a++) {
final SendingMediaInfo info = media.get(a);
final boolean last = mediaCount == 0;
if (groupMediaFinal && count > 1 && mediaCount % 10 == 0) {
lastGroupId = groupId = Utilities.random.nextLong();
mediaCount = 0;
@ -8030,6 +8108,10 @@ public class SendMessagesHelper extends BaseController implements NotificationCe
sendMessageParams.replyQuote = quote;
sendMessageParams.quick_reply_shortcut = quickReplyShortcut;
sendMessageParams.quick_reply_shortcut_id = quickReplyShortcutId;
if (last) {
sendMessageParams.effect_id = effectId;
}
sendMessageParams.invert_media = invertMedia;
accountInstance.getSendMessagesHelper().sendMessage(sendMessageParams);
}
});
@ -8106,6 +8188,8 @@ public class SendMessagesHelper extends BaseController implements NotificationCe
sendMessageParams.replyQuote = quote;
sendMessageParams.quick_reply_shortcut_id = quickReplyShortcutId;
sendMessageParams.quick_reply_shortcut = quickReplyShortcut;
sendMessageParams.effect_id = effectId;
sendMessageParams.invert_media = invertMedia;
accountInstance.getSendMessagesHelper().sendMessage(sendMessageParams);
}
});
@ -8301,6 +8385,8 @@ public class SendMessagesHelper extends BaseController implements NotificationCe
sendMessageParams.replyQuote = quote;
sendMessageParams.quick_reply_shortcut = quickReplyShortcut;
sendMessageParams.quick_reply_shortcut_id = quickReplyShortcutId;
sendMessageParams.effect_id = effectId;
sendMessageParams.invert_media = invertMedia;
accountInstance.getSendMessagesHelper().sendMessage(sendMessageParams);
}
});
@ -8503,6 +8589,8 @@ public class SendMessagesHelper extends BaseController implements NotificationCe
sendMessageParams.replyQuote = quote;
sendMessageParams.quick_reply_shortcut = quickReplyShortcut;
sendMessageParams.quick_reply_shortcut_id = quickReplyShortcutId;
sendMessageParams.effect_id = effectId;
sendMessageParams.invert_media = invertMedia;
accountInstance.getSendMessagesHelper().sendMessage(sendMessageParams);
}
});
@ -8539,7 +8627,7 @@ public class SendMessagesHelper extends BaseController implements NotificationCe
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, quickReplyShortcut, quickReplyShortcutId);
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, effectId, invertMedia);
handleError(error, accountInstance);
}
}
@ -8804,7 +8892,7 @@ public class SendMessagesHelper extends BaseController implements NotificationCe
}
@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<TLRPC.MessageEntity> entities, int ttl, MessageObject editingMessageObject, boolean notify, int scheduleDate, boolean forceDocument, boolean hasMediaSpoilers, CharSequence caption, String quickReplyShortcut, int quickReplyShortcutId) {
public static void prepareSendingVideo(AccountInstance accountInstance, String videoPath, VideoEditedInfo info, long dialogId, MessageObject replyToMsg, MessageObject replyToTopMsg, TL_stories.StoryItem storyItem, ChatActivity.ReplyQuote quote, ArrayList<TLRPC.MessageEntity> entities, int ttl, MessageObject editingMessageObject, boolean notify, int scheduleDate, boolean forceDocument, boolean hasMediaSpoilers, CharSequence caption, String quickReplyShortcut, int quickReplyShortcutId, long effectId) {
if (videoPath == null || videoPath.length() == 0) {
return;
}
@ -8966,11 +9054,12 @@ public class SendMessagesHelper extends BaseController implements NotificationCe
sendMessageParams.replyQuote = quote;
sendMessageParams.quick_reply_shortcut_id = quickReplyShortcutId;
sendMessageParams.quick_reply_shortcut = quickReplyShortcut;
sendMessageParams.effect_id = effectId;
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, quickReplyShortcut, quickReplyShortcutId);
prepareSendingDocumentInternal(accountInstance, videoPath, videoPath, null, null, dialogId, replyToMsg, replyToTopMsg, storyItem, quote, entities, editingMessageObject, null, false, caption, notify, scheduleDate, null, forceDocument, quickReplyShortcut, quickReplyShortcutId, 0, false);
}
}).start();
}
@ -9010,6 +9099,7 @@ public class SendMessagesHelper extends BaseController implements NotificationCe
public boolean invert_media;
public String quick_reply_shortcut;
public int quick_reply_shortcut_id;
public long effect_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);

View file

@ -232,7 +232,8 @@ public class SharedConfig {
public static boolean allowScreenCapture;
public static int lastPauseTime;
public static boolean isWaitingForPasscodeEnter;
public static boolean useFingerprint = true;
public static boolean useFingerprintLock = true;
public static boolean useFaceLock = true;
public static int suggestStickers;
public static boolean suggestAnimatedEmoji;
public static int keepMedia = CacheByChatsController.KEEP_MEDIA_ONE_MONTH; //deprecated
@ -255,6 +256,7 @@ public class SharedConfig {
public static boolean updateStickersOrderOnSend = true;
public static boolean bigCameraForRound;
public static Boolean useCamera2Force;
public static boolean useNewBlur;
public static boolean useSurfaceInStories;
public static boolean photoViewerBlur = true;
public static boolean payByInvoice;
@ -430,7 +432,7 @@ public class SharedConfig {
editor.putInt("badPasscodeTries", badPasscodeTries);
editor.putInt("autoLockIn", autoLockIn);
editor.putInt("lastPauseTime", lastPauseTime);
editor.putBoolean("useFingerprint", useFingerprint);
editor.putBoolean("useFingerprint", useFingerprintLock);
editor.putBoolean("allowScreenCapture", allowScreenCapture);
editor.putString("pushString2", pushString);
editor.putInt("pushType", pushType);
@ -508,7 +510,7 @@ public class SharedConfig {
badPasscodeTries = preferences.getInt("badPasscodeTries", 0);
autoLockIn = preferences.getInt("autoLockIn", 60 * 60);
lastPauseTime = preferences.getInt("lastPauseTime", 0);
useFingerprint = preferences.getBoolean("useFingerprint", true);
useFingerprintLock = preferences.getBoolean("useFingerprint", true);
allowScreenCapture = preferences.getBoolean("allowScreenCapture", false);
lastLocalId = preferences.getInt("lastLocalId", -210000);
pushString = preferences.getString("pushString2", "");
@ -643,6 +645,7 @@ public class SharedConfig {
updateStickersOrderOnSend = preferences.getBoolean("updateStickersOrderOnSend", true);
dayNightWallpaperSwitchHint = preferences.getInt("dayNightWallpaperSwitchHint", 0);
bigCameraForRound = preferences.getBoolean("bigCameraForRound", false);
useNewBlur = preferences.getBoolean("useNewBlur", true);
useCamera2Force = !preferences.contains("useCamera2Force") ? null : preferences.getBoolean("useCamera2Force", false);
useSurfaceInStories = preferences.getBoolean("useSurfaceInStories", Build.VERSION.SDK_INT >= 30);
payByInvoice = preferences.getBoolean("payByInvoice", false);
@ -851,7 +854,7 @@ public class SharedConfig {
passcodeSalt = new byte[0];
autoLockIn = 60 * 60;
lastPauseTime = 0;
useFingerprint = true;
useFingerprintLock = true;
isWaitingForPasscodeEnter = false;
allowScreenCapture = false;
textSelectionHintShows = 0;
@ -1671,7 +1674,7 @@ public class SharedConfig {
}
public static boolean canBlurChat() {
return getDevicePerformanceClass() == PERFORMANCE_CLASS_HIGH;
return getDevicePerformanceClass() >= (Build.VERSION.SDK_INT >= 31 ? PERFORMANCE_CLASS_AVERAGE : PERFORMANCE_CLASS_HIGH) || BuildVars.DEBUG_PRIVATE_VERSION;
}
public static boolean chatBlurEnabled() {
@ -1739,6 +1742,14 @@ public class SharedConfig {
.apply();
}
public static void toggleUseNewBlur() {
useNewBlur = !useNewBlur;
ApplicationLoader.applicationContext.getSharedPreferences("mainconfig", Activity.MODE_PRIVATE)
.edit()
.putBoolean("useNewBlur", useNewBlur)
.apply();
}
public static boolean isUsingCamera2(int currentAccount) {
return useCamera2Force == null ? !MessagesController.getInstance(currentAccount).androidDisableRoundCamera2 : useCamera2Force;
}

View file

@ -267,6 +267,7 @@ public class UnconfirmedAuthController {
public String device;
public String location;
public UnconfirmedAuth(AbstractSerializedData stream) {
int magic = stream.readInt32(true);
if (magic != 0x7ab6618c) {

View file

@ -112,7 +112,7 @@ public class UserObject {
public static String getForcedFirstName(TLRPC.User user) {
if (user == null || isDeleted(user)) {
return "DELETED";
return LocaleController.getString(R.string.HiddenName);
}
String name = user.first_name;
if (TextUtils.isEmpty(name)) {

View file

@ -17,6 +17,8 @@ import android.graphics.Rect;
import com.carrotsearch.randomizedtesting.Xoroshiro128PlusRandom;
import org.telegram.tgnet.ConnectionsManager;
import java.io.File;
import java.io.FileInputStream;
import java.math.BigInteger;
@ -254,53 +256,7 @@ public class Utilities {
}
public static boolean isGoodPrime(byte[] prime, int g) {
if (!(g >= 2 && g <= 7)) {
return false;
}
if (prime.length != 256 || prime[0] >= 0) {
return false;
}
BigInteger dhBI = new BigInteger(1, prime);
if (g == 2) { // p mod 8 = 7 for g = 2;
BigInteger res = dhBI.mod(BigInteger.valueOf(8));
if (res.intValue() != 7) {
return false;
}
} else if (g == 3) { // p mod 3 = 2 for g = 3;
BigInteger res = dhBI.mod(BigInteger.valueOf(3));
if (res.intValue() != 2) {
return false;
}
} else if (g == 5) { // p mod 5 = 1 or 4 for g = 5;
BigInteger res = dhBI.mod(BigInteger.valueOf(5));
int val = res.intValue();
if (val != 1 && val != 4) {
return false;
}
} else if (g == 6) { // p mod 24 = 19 or 23 for g = 6;
BigInteger res = dhBI.mod(BigInteger.valueOf(24));
int val = res.intValue();
if (val != 19 && val != 23) {
return false;
}
} else if (g == 7) { // p mod 7 = 3, 5 or 6 for g = 7.
BigInteger res = dhBI.mod(BigInteger.valueOf(7));
int val = res.intValue();
if (val != 3 && val != 5 && val != 6) {
return false;
}
}
String hex = bytesToHex(prime);
if (hex.equals("C71CAEB9C6B1C9048E6C522F70F13F73980D40238E3E21C14934D037563D930F48198A0AA7C14058229493D22530F4DBFA336F6E0AC925139543AED44CCE7C3720FD51F69458705AC68CD4FE6B6B13ABDC9746512969328454F18FAF8C595F642477FE96BB2A941D5BCD1D4AC8CC49880708FA9B378E3C4F3A9060BEE67CF9A4A4A695811051907E162753B56B0F6B410DBA74D8A84B2A14B3144E0EF1284754FD17ED950D5965B4B9DD46582DB1178D169C6BC465B0D6FF9CA3928FEF5B9AE4E418FC15E83EBEA0F87FA9FF5EED70050DED2849F47BF959D956850CE929851F0D8115F635B105EE2E4E15D04B2454BF6F4FADF034B10403119CD8E3B92FCC5B")) {
return true;
}
BigInteger dhBI2 = dhBI.subtract(BigInteger.valueOf(1)).divide(BigInteger.valueOf(2));
return !(!dhBI.isProbablePrime(30) || !dhBI2.isProbablePrime(30));
return ConnectionsManager.native_isGoodPrime(prime, g);
}
public static boolean isGoodGaAndGb(BigInteger g_a, BigInteger p) {
@ -481,6 +437,24 @@ public class Utilities {
return null;
}
public static String SHA256(String x) {
if (x == null) {
return null;
}
try {
java.security.MessageDigest md = java.security.MessageDigest.getInstance("SHA-256");
byte[] array = md.digest(AndroidUtilities.getStringBytes(x));
StringBuilder sb = new StringBuilder();
for (int a = 0; a < array.length; a++) {
sb.append(Integer.toHexString((array[a] & 0xFF) | 0x100).substring(1, 3));
}
return sb.toString();
} catch (java.security.NoSuchAlgorithmException e) {
FileLog.e(e);
}
return null;
}
public static int clamp(int value, int maxValue, int minValue) {
return Math.max(Math.min(value, maxValue), minValue);
}

View file

@ -768,10 +768,10 @@ public class CameraView extends FrameLayout implements TextureView.SurfaceTextur
cameraThread.postRunnable(() -> this.cameraThread = null);
}
if (cameraSession[0] != null) {
cameraSession[0].destroy(false, null, null);
cameraSession[0].destroy(true, null, null);
}
if (cameraSession[1] != null) {
cameraSession[1].destroy(false, null, null);
cameraSession[1].destroy(true, null, null);
}
return false;
}

View file

@ -60,7 +60,11 @@ public class BillingUtilities {
paymentPurpose.serializeToStream(serializedData);
String obfuscatedData = Base64.encodeToString(serializedData.toByteArray(), Base64.DEFAULT);
serializedData.cleanup();
if (paymentPurpose instanceof TLRPC.TL_inputStorePaymentPremiumGiftCode || paymentPurpose instanceof TLRPC.TL_inputStorePaymentPremiumGiveaway) {
if (
paymentPurpose instanceof TLRPC.TL_inputStorePaymentPremiumGiftCode ||
paymentPurpose instanceof TLRPC.TL_inputStorePaymentStars ||
paymentPurpose instanceof TLRPC.TL_inputStorePaymentPremiumGiveaway
) {
remPaymentPurpose = paymentPurpose;
return Pair.create(obfuscatedAccountId, obfuscatedAccountId);
} else {
@ -97,10 +101,15 @@ public class BillingUtilities {
try {
TLRPC.InputStorePaymentPurpose purpose;
if (remPaymentPurpose == null) {
byte[] obfuscatedDataBytes = Base64.decode(obfuscatedData, Base64.DEFAULT);
SerializedData data = new SerializedData(obfuscatedDataBytes);
purpose = TLRPC.InputStorePaymentPurpose.TLdeserialize(data, data.readInt32(true), true);
data.cleanup();
try {
byte[] obfuscatedDataBytes = Base64.decode(obfuscatedData, Base64.DEFAULT);
SerializedData data = new SerializedData(obfuscatedDataBytes);
purpose = TLRPC.InputStorePaymentPurpose.TLdeserialize(data, data.readInt32(true), true);
data.cleanup();
} catch (Exception e) {
FileLog.e(e);
purpose = null;
}
} else {
purpose = remPaymentPurpose;
remPaymentPurpose = null;

View file

@ -4,6 +4,8 @@ import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Build;
import com.google.common.util.concurrent.AtomicDouble;
import org.telegram.messenger.AndroidUtilities;
import org.telegram.messenger.BuildVars;
import org.telegram.messenger.DispatchQueuePoolBackground;
@ -27,6 +29,7 @@ import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
public class BitmapsCache {
@ -38,6 +41,7 @@ public class BitmapsCache {
String fileName;
int w;
int h;
public final AtomicInteger framesProcessed = new AtomicInteger(0);
ArrayList<FrameOffset> frameOffsets = new ArrayList<>();
@ -111,6 +115,7 @@ public class BitmapsCache {
if (frameOffsets.size() == 0) {
cacheCreated = false;
fileExist = false;
checked = true;
file.delete();
} else {
if (cachedFile != randomAccessFile) {
@ -123,6 +128,7 @@ public class BitmapsCache {
e.printStackTrace();
file.delete();
fileExist = false;
checked = true;
} finally {
try {
if (cachedFile != randomAccessFile && randomAccessFile != null) {
@ -133,12 +139,14 @@ public class BitmapsCache {
}
}
}
checked = true;
} else {
fileExist = false;
cacheCreated = false;
}
}
public volatile boolean checked;
volatile boolean checkCache;
volatile boolean cacheCreated;
volatile boolean recycled;
@ -189,10 +197,12 @@ public class BitmapsCache {
}
cachedFile = randomAccessFile;
fileExist = true;
checked = true;
return;
} else {
fileExist = false;
cacheCreated = false;
checked = true;
}
}
if (!cacheCreated) {
@ -322,6 +332,7 @@ public class BitmapsCache {
if (index >= N) {
index = 0;
}
framesProcessed.set(framePosition);
}
for (int i = 0; i < N; i++) {
if (countDownLatch[i] != null) {
@ -357,6 +368,7 @@ public class BitmapsCache {
cachedFile = new RandomAccessFile(file, "r");
cacheCreated = true;
fileExist = true;
checked = true;
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
@ -411,6 +423,7 @@ public class BitmapsCache {
framesCount = randomAccessFile.readInt();
if (framesCount <= 0) {
cacheCreated = false;
checked = true;
}
}
} catch (Exception e) {
@ -449,6 +462,7 @@ public class BitmapsCache {
}
if (frameOffsets.size() == 0) {
cacheCreated = false;
checked = true;
}
if (!cacheCreated) {

View file

@ -6,6 +6,7 @@ import android.text.Editable;
import android.text.Html;
import android.text.Spannable;
import android.text.SpannableString;
import android.text.SpannableStringBuilder;
import android.text.Spanned;
import android.text.TextUtils;
import android.text.style.StrikethroughSpan;
@ -34,6 +35,7 @@ public class CopyUtilities {
private final static int TYPE_SPOILER = 0;
private final static int TYPE_MONO = 1;
private final static int TYPE_QUOTE = 2;
private final static int TYPE_COLLAPSE = 3;
public static Spannable fromHTML(String html) {
Spanned spanned;
@ -81,7 +83,7 @@ public class CopyUtilities {
} else {
entities.add(setEntityStartEnd(new TLRPC.TL_messageEntityPre(), start, end));
}
} else if (parsedSpan.type == TYPE_QUOTE) {
} else if (parsedSpan.type == TYPE_QUOTE || parsedSpan.type == TYPE_COLLAPSE) {
quotes.add(parsedSpan);
}
} else if (span instanceof AnimatedEmojiSpan) {
@ -92,7 +94,7 @@ public class CopyUtilities {
}
}
SpannableString spannable = new SpannableString(spanned.toString());
SpannableStringBuilder spannable = new SpannableStringBuilder(spanned.toString());
MediaDataController.addTextStyleRuns(entities, spannable, spannable);
for (int i = 0; i < spans.length; ++i) {
Object span = spans[i];
@ -126,7 +128,7 @@ public class CopyUtilities {
}
for (int i = 0; i < quotes.size(); ++i) {
ParsedSpan span = quotes.get(i);
QuoteSpan.putQuote(spannable, spanned.getSpanStart(span), spanned.getSpanEnd(span));
QuoteSpan.putQuoteToEditable(spannable, spanned.getSpanStart(span), spanned.getSpanEnd(span), span.type == TYPE_COLLAPSE);
}
return spannable;
}
@ -302,6 +304,21 @@ public class CopyUtilities {
return true;
}
}
} else if (tag.equals("details")) {
if (opening) {
output.setSpan(new ParsedSpan(TYPE_COLLAPSE), output.length(), output.length(), Spanned.SPAN_MARK_MARK);
return true;
} else {
ParsedSpan obj = getLast(output, ParsedSpan.class, TYPE_COLLAPSE);
if (obj != null) {
int where = output.getSpanStart(obj);
output.removeSpan(obj);
if (where != output.length()) {
output.setSpan(obj, where, output.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
}
return true;
}
}
}
return false;
}

View file

@ -16,10 +16,36 @@ public class CustomHtml {
public static String toHtml(Spanned text) {
StringBuilder out = new StringBuilder();
toHTML_1_wrapTextStyle(out, text, 0, text.length());
toHTML_0_wrapQuote(out, text, 0, text.length());
return out.toString();
}
private static void toHTML_0_wrapQuote(StringBuilder out, Spanned text, int start, int end) {
int next;
for (int i = start; i < end; i = next) {
next = text.nextSpanTransition(i, end, QuoteSpan.class);
if (next < 0) {
next = end;
}
QuoteSpan[] spans = text.getSpans(i, next, QuoteSpan.class);
if (spans != null) {
for (int j = 0; j < spans.length; ++j) {
out.append(spans[j].isCollapsing ? "<details>" : "<blockquote>");
}
}
toHTML_1_wrapTextStyle(out, text, i, next);
if (spans != null) {
for (int j = spans.length - 1; j >= 0; --j) {
out.append(spans[j].isCollapsing ? "</details>" : "</blockquote>");
}
}
}
}
private static void toHTML_1_wrapTextStyle(StringBuilder out, Spanned text, int start, int end) {
int next;
for (int i = start; i < end; i = next) {
@ -174,7 +200,7 @@ public class CustomHtml {
}
}
toHTML_5_wrapQuote(out, text, i, next);
toHTML_6_wrapAnimatedEmoji(out, text, i, next);
if (spans != null) {
for (int j = 0; j < spans.length; ++j) {
@ -187,32 +213,6 @@ public class CustomHtml {
}
}
private static void toHTML_5_wrapQuote(StringBuilder out, Spanned text, int start, int end) {
int next;
for (int i = start; i < end; i = next) {
next = text.nextSpanTransition(i, end, QuoteSpan.class);
if (next < 0) {
next = end;
}
QuoteSpan[] spans = text.getSpans(i, next, QuoteSpan.class);
if (spans != null) {
for (int j = 0; j < spans.length; ++j) {
out.append("<blockquote>");
}
}
toHTML_6_wrapAnimatedEmoji(out, text, i, next);
if (spans != null) {
for (int j = 0; j < spans.length; ++j) {
out.append("</blockquote>");
}
}
}
}
private static void toHTML_6_wrapAnimatedEmoji(StringBuilder out, Spanned text, int start, int end) {
int next;
for (int i = start; i < end; i = next) {

View file

@ -15,6 +15,11 @@ import android.util.LongSparseArray;
import android.util.SparseIntArray;
import com.google.android.exoplayer2.util.Log;
import com.google.android.gms.tasks.Task;
import com.google.android.play.core.integrity.IntegrityManager;
import com.google.android.play.core.integrity.IntegrityManagerFactory;
import com.google.android.play.core.integrity.IntegrityTokenRequest;
import com.google.android.play.core.integrity.IntegrityTokenResponse;
import com.google.firebase.remoteconfig.FirebaseRemoteConfig;
import org.json.JSONArray;
@ -46,6 +51,7 @@ import org.telegram.ui.Components.BulletinFactory;
import org.telegram.ui.Components.TypefaceSpan;
import org.telegram.ui.DialogsActivity;
import org.telegram.ui.LaunchActivity;
import org.telegram.ui.LoginActivity;
import org.telegram.ui.PremiumPreviewFragment;
import java.io.ByteArrayOutputStream;
@ -100,6 +106,7 @@ public class ConnectionsManager extends BaseController {
public final static int RequestFlagNeedQuickAck = 128;
public final static int RequestFlagDoNotWaitFloodWait = 1024;
public final static int RequestFlagListenAfterCancel = 2048;
public final static int RequestFlagFailOnServerErrorsExceptFloodWait = 65536;
public final static int ConnectionStateConnecting = 1;
public final static int ConnectionStateWaitingForNetwork = 2;
@ -786,6 +793,7 @@ public class ConnectionsManager extends BaseController {
Utilities.globalQueue.postRunnable(() -> {
boolean networkOnline = ApplicationLoader.isNetworkOnline();
Utilities.stageQueue.postRunnable(() -> {
FileLog.d("13. currentTask == " + currentTask);
if (currentTask != null || second == 0 && Math.abs(lastDnsRequestTime - System.currentTimeMillis()) < 10000 || !networkOnline) {
if (BuildVars.LOGS_ENABLED) {
FileLog.d("don't start task, current task = " + currentTask + " next task = " + second + " time diff = " + Math.abs(lastDnsRequestTime - System.currentTimeMillis()) + " network = " + ApplicationLoader.isNetworkOnline());
@ -793,26 +801,21 @@ public class ConnectionsManager extends BaseController {
return;
}
lastDnsRequestTime = System.currentTimeMillis();
if (second == 3) {
if (second == 2) {
if (BuildVars.LOGS_ENABLED) {
FileLog.d("start mozilla txt task");
}
MozillaDnsLoadTask task = new MozillaDnsLoadTask(currentAccount);
task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, null, null, null);
FileLog.d("9. currentTask = mozilla");
currentTask = task;
} else if (second == 2) {
} else if (second == 1) {
if (BuildVars.LOGS_ENABLED) {
FileLog.d("start google txt task");
}
GoogleDnsLoadTask task = new GoogleDnsLoadTask(currentAccount);
task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, null, null, null);
currentTask = task;
} else if (second == 1) {
if (BuildVars.LOGS_ENABLED) {
FileLog.d("start dns txt task");
}
DnsTxtLoadTask task = new DnsTxtLoadTask(currentAccount);
task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, null, null, null);
FileLog.d("11. currentTask = dnstxt");
currentTask = task;
} else {
if (BuildVars.LOGS_ENABLED) {
@ -820,6 +823,7 @@ public class ConnectionsManager extends BaseController {
}
FirebaseTask task = new FirebaseTask(currentAccount);
task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, null, null, null);
FileLog.d("12. currentTask = firebase");
currentTask = task;
}
});
@ -937,6 +941,9 @@ public class ConnectionsManager extends BaseController {
public static native void native_onHostNameResolved(String host, long address, String ip);
public static native void native_discardConnection(int currentAccount, int datacenterId, int connectionType);
public static native void native_failNotRunningRequest(int currentAccount, int token);
public static native void native_receivedIntegrityCheckClassic(int currentAccount, int requestToken, String nonce, String token);
public static native boolean native_isGoodPrime(byte[] prime, int g);
public static int generateClassGuid() {
return lastClassGuid++;
@ -1143,135 +1150,6 @@ public class ConnectionsManager extends BaseController {
}
}
private static class DnsTxtLoadTask extends AsyncTask<Void, Void, NativeByteBuffer> {
private int currentAccount;
private int responseDate;
public DnsTxtLoadTask(int instance) {
super();
currentAccount = instance;
}
protected NativeByteBuffer doInBackground(Void... voids) {
ByteArrayOutputStream outbuf = null;
InputStream httpConnectionStream = null;
for (int i = 0; i < 3; i++) {
try {
String googleDomain;
if (i == 0) {
googleDomain = "www.google.com";
} else if (i == 1) {
googleDomain = "www.google.ru";
} else {
googleDomain = "google.com";
}
String domain = native_isTestBackend(currentAccount) != 0 ? "tapv3.stel.com" : AccountInstance.getInstance(currentAccount).getMessagesController().dcDomainName;
int len = Utilities.random.nextInt(116) + 13;
final String characters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
StringBuilder padding = new StringBuilder(len);
for (int a = 0; a < len; a++) {
padding.append(characters.charAt(Utilities.random.nextInt(characters.length())));
}
URL downloadUrl = new URL("https://" + googleDomain + "/resolve?name=" + domain + "&type=ANY&random_padding=" + padding);
URLConnection httpConnection = downloadUrl.openConnection();
httpConnection.addRequestProperty("User-Agent", "Mozilla/5.0 (iPhone; CPU iPhone OS 10_0 like Mac OS X) AppleWebKit/602.1.38 (KHTML, like Gecko) Version/10.0 Mobile/14A5297c Safari/602.1");
httpConnection.addRequestProperty("Host", "dns.google.com");
httpConnection.setConnectTimeout(5000);
httpConnection.setReadTimeout(5000);
httpConnection.connect();
httpConnectionStream = httpConnection.getInputStream();
responseDate = (int) (httpConnection.getDate() / 1000);
outbuf = new ByteArrayOutputStream();
byte[] data = new byte[1024 * 32];
while (true) {
if (isCancelled()) {
break;
}
int read = httpConnectionStream.read(data);
if (read > 0) {
outbuf.write(data, 0, read);
} else if (read == -1) {
break;
} else {
break;
}
}
JSONObject jsonObject = new JSONObject(new String(outbuf.toByteArray()));
JSONArray array = jsonObject.getJSONArray("Answer");
len = array.length();
ArrayList<String> arrayList = new ArrayList<>(len);
for (int a = 0; a < len; a++) {
JSONObject object = array.getJSONObject(a);
int type = object.getInt("type");
if (type != 16) {
continue;
}
arrayList.add(object.getString("data"));
}
Collections.sort(arrayList, (o1, o2) -> {
int l1 = o1.length();
int l2 = o2.length();
if (l1 > l2) {
return -1;
} else if (l1 < l2) {
return 1;
}
return 0;
});
StringBuilder builder = new StringBuilder();
for (int a = 0; a < arrayList.size(); a++) {
builder.append(arrayList.get(a).replace("\"", ""));
}
byte[] bytes = Base64.decode(builder.toString(), Base64.DEFAULT);
NativeByteBuffer buffer = new NativeByteBuffer(bytes.length);
buffer.writeBytes(bytes);
return buffer;
} catch (Throwable e) {
FileLog.e(e, false);
} finally {
try {
if (httpConnectionStream != null) {
httpConnectionStream.close();
}
} catch (Throwable e) {
FileLog.e(e, false);
}
try {
if (outbuf != null) {
outbuf.close();
}
} catch (Exception ignore) {
}
}
}
return null;
}
@Override
protected void onPostExecute(final NativeByteBuffer result) {
Utilities.stageQueue.postRunnable(() -> {
currentTask = null;
if (result != null) {
native_applyDnsConfig(currentAccount, result.address, AccountInstance.getInstance(currentAccount).getUserConfig().getClientPhone(), responseDate);
} else {
if (BuildVars.LOGS_ENABLED) {
FileLog.d("failed to get dns txt result");
FileLog.d("start google task");
}
GoogleDnsLoadTask task = new GoogleDnsLoadTask(currentAccount);
task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, null, null, null);
currentTask = task;
}
});
}
}
private static class GoogleDnsLoadTask extends AsyncTask<Void, Void, NativeByteBuffer> {
private int currentAccount;
@ -1374,6 +1252,7 @@ public class ConnectionsManager extends BaseController {
@Override
protected void onPostExecute(final NativeByteBuffer result) {
Utilities.stageQueue.postRunnable(() -> {
FileLog.d("3. currentTask = null, result = " + result);
currentTask = null;
if (result != null) {
native_applyDnsConfig(currentAccount, result.address, AccountInstance.getInstance(currentAccount).getUserConfig().getClientPhone(), responseDate);
@ -1384,6 +1263,7 @@ public class ConnectionsManager extends BaseController {
}
MozillaDnsLoadTask task = new MozillaDnsLoadTask(currentAccount);
task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, null, null, null);
FileLog.d("4. currentTask = mozilla");
currentTask = task;
}
});
@ -1493,6 +1373,7 @@ public class ConnectionsManager extends BaseController {
@Override
protected void onPostExecute(final NativeByteBuffer result) {
Utilities.stageQueue.postRunnable(() -> {
FileLog.d("5. currentTask = null");
currentTask = null;
if (result != null) {
native_applyDnsConfig(currentAccount, result.address, AccountInstance.getInstance(currentAccount).getUserConfig().getClientPhone(), responseDate);
@ -1531,6 +1412,7 @@ public class ConnectionsManager extends BaseController {
Utilities.stageQueue.postRunnable(() -> {
if (success) {
firebaseRemoteConfig.activate().addOnCompleteListener(finishedTask2 -> {
FileLog.d("6. currentTask = null");
currentTask = null;
String config = firebaseRemoteConfig.getString("ipconfigv3");
if (!TextUtils.isEmpty(config)) {
@ -1548,11 +1430,21 @@ public class ConnectionsManager extends BaseController {
FileLog.d("failed to get firebase result");
FileLog.d("start dns txt task");
}
DnsTxtLoadTask task = new DnsTxtLoadTask(currentAccount);
GoogleDnsLoadTask task = new GoogleDnsLoadTask(currentAccount);
task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, null, null, null);
FileLog.d("7. currentTask = GoogleDnsLoadTask");
currentTask = task;
}
});
} else {
if (BuildVars.LOGS_ENABLED) {
FileLog.d("failed to get firebase result 2");
FileLog.d("start dns txt task");
}
GoogleDnsLoadTask task = new GoogleDnsLoadTask(currentAccount);
task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, null, null, null);
FileLog.d("7. currentTask = GoogleDnsLoadTask");
currentTask = task;
}
});
});
@ -1562,8 +1454,9 @@ public class ConnectionsManager extends BaseController {
FileLog.d("failed to get firebase result");
FileLog.d("start dns txt task");
}
DnsTxtLoadTask task = new DnsTxtLoadTask(currentAccount);
GoogleDnsLoadTask task = new GoogleDnsLoadTask(currentAccount);
task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, null, null, null);
FileLog.d("8. currentTask = GoogleDnsLoadTask");
currentTask = task;
});
FileLog.e(e, false);
@ -1604,4 +1497,34 @@ public class ConnectionsManager extends BaseController {
}
});
}
public static void onIntegrityCheckClassic(final int currentAccount, final int requestToken, final String nonce) {
AndroidUtilities.runOnUIThread(() -> {
long start = System.currentTimeMillis();
FileLog.d("account"+currentAccount+": server requests integrity classic check with nonce = " + nonce);
IntegrityManager integrityManager = IntegrityManagerFactory.create(ApplicationLoader.applicationContext);
Task<IntegrityTokenResponse> integrityTokenResponse = integrityManager.requestIntegrityToken(IntegrityTokenRequest.builder().setNonce(nonce).setCloudProjectNumber(760348033671L).build());
integrityTokenResponse
.addOnSuccessListener(r -> {
final String token = r.token();
if (token == null) {
FileLog.e("account"+currentAccount+": integrity check gave null token in " + (System.currentTimeMillis() - start) + "ms");
native_receivedIntegrityCheckClassic(currentAccount, requestToken, nonce, "PLAYINTEGRITY_FAILED_EXCEPTION_NULL");
return;
}
FileLog.d("account"+currentAccount+": integrity check successfully gave token: " + token + " in " + (System.currentTimeMillis() - start) + "ms");
try {
native_receivedIntegrityCheckClassic(currentAccount, requestToken, nonce, token);
} catch (Exception e) {
FileLog.e("receivedIntegrityCheckClassic failed", e);
}
})
.addOnFailureListener(e -> {
FileLog.e("account"+currentAccount+": integrity check failed to give a token in " + (System.currentTimeMillis() - start) + "ms", e);
native_receivedIntegrityCheckClassic(currentAccount, requestToken, nonce, "PLAYINTEGRITY_FAILED_EXCEPTION_" + LoginActivity.errorString(e));
});
});
}
}

File diff suppressed because it is too large Load diff

View file

@ -187,6 +187,7 @@ public class TL_stories {
public TLRPC.Peer peer;
public int max_read_id;
public ArrayList<StoryItem> stories = new ArrayList<>();
public boolean checkedExpired; //custom
public static PeerStories TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) {
PeerStories result = null;

View file

@ -420,7 +420,7 @@ public class ActionBar extends FrameLayout {
} else {
titleTextView[i].setTextColor(getThemedColor(Theme.key_actionBarDefaultTitle));
}
titleTextView[i].setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf"));
titleTextView[i].setTypeface(AndroidUtilities.bold());
titleTextView[i].setDrawablePadding(dp(4));
titleTextView[i].setPadding(0, dp(8), 0, dp(8));
titleTextView[i].setRightDrawableTopPadding(-dp(1));

View file

@ -32,7 +32,6 @@ import android.transition.TransitionManager;
import android.transition.TransitionSet;
import android.transition.TransitionValues;
import android.transition.Visibility;
import android.util.Log;
import android.util.TypedValue;
import android.view.ActionMode;
import android.view.Gravity;
@ -52,7 +51,6 @@ import android.widget.FrameLayout;
import android.widget.HorizontalScrollView;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.PopupWindow;
import android.widget.TextView;
import androidx.annotation.Nullable;
@ -62,7 +60,6 @@ import androidx.core.graphics.ColorUtils;
import org.telegram.messenger.AndroidUtilities;
import org.telegram.messenger.AnimationNotificationsLocker;
import org.telegram.messenger.LocaleController;
import org.telegram.messenger.NotificationCenter;
import org.telegram.messenger.R;
import org.telegram.messenger.UserConfig;
import org.telegram.messenger.Utilities;
@ -126,6 +123,10 @@ public class ActionBarMenuItem extends FrameLayout {
public void onSearchPressed(EditText editText) {
}
public boolean canClearCaption() {
return true;
}
public void onCaptionCleared() {
}
@ -133,6 +134,10 @@ public class ActionBarMenuItem extends FrameLayout {
return false;
}
public boolean showClearForCaption() {
return true;
}
public Animator getCustomToggleTransition() {
return null;
}
@ -238,7 +243,7 @@ public class ActionBarMenuItem extends FrameLayout {
if (text) {
textView = new TextView(context);
textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 15);
textView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf"));
textView.setTypeface(AndroidUtilities.bold());
textView.setGravity(Gravity.CENTER);
textView.setPadding(AndroidUtilities.dp(4), 0, AndroidUtilities.dp(4), 0);
textView.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO);
@ -591,7 +596,30 @@ public class ActionBarMenuItem extends FrameLayout {
return cell;
}
public ActionBarMenuSubItem addSwipeBackItem(int icon, Drawable iconDrawable, String text, View viewToSwipeBack) {
public View addSubItem(int id, View cell) {
createPopupLayout();
cell.setMinimumWidth(AndroidUtilities.dp(196));
cell.setTag(id);
popupLayout.addView(cell);
LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams) cell.getLayoutParams();
if (LocaleController.isRTL) {
layoutParams.gravity = Gravity.RIGHT;
}
layoutParams.width = LayoutHelper.MATCH_PARENT;
layoutParams.height = AndroidUtilities.dp(48);
cell.setLayoutParams(layoutParams);
cell.setOnClickListener(view -> {
if (parentMenu != null) {
parentMenu.onItemClick((Integer) view.getTag());
} else if (delegate != null) {
delegate.onItemClick((Integer) view.getTag());
}
});
return cell;
}
public ActionBarMenuSubItem addSwipeBackItem(int icon, Drawable iconDrawable, String text, View viewToSwipeBack) {
createPopupLayout();
ActionBarMenuSubItem cell = new ActionBarMenuSubItem(getContext(), false, false, false, resourcesProvider);
@ -1580,7 +1608,7 @@ public class ActionBarMenuItem extends FrameLayout {
}
}
clearSearchFilters();
} else if (searchFieldCaption != null && searchFieldCaption.getVisibility() == VISIBLE) {
} else if (searchFieldCaption != null && searchFieldCaption.getVisibility() == VISIBLE && (listener == null || listener.canClearCaption())) {
searchFieldCaption.setVisibility(GONE);
if (listener != null) {
listener.onCaptionCleared();
@ -1611,7 +1639,7 @@ public class ActionBarMenuItem extends FrameLayout {
if (clearButton != null) {
if (!hasRemovableFilters() && TextUtils.isEmpty(searchField.getText()) &&
(listener == null || !listener.forceShowClear()) &&
(searchFieldCaption == null || searchFieldCaption.getVisibility() != VISIBLE)) {
(searchFieldCaption == null || searchFieldCaption.getVisibility() != VISIBLE || listener != null && !listener.showClearForCaption())) {
if (clearButton.getTag() != null) {
clearButton.setTag(null);
if (clearButtonAnimator != null) {

View file

@ -33,7 +33,6 @@ import android.view.ViewConfiguration;
import android.view.accessibility.AccessibilityNodeInfo;
import android.widget.FrameLayout;
import androidx.annotation.NonNull;
import androidx.core.graphics.ColorUtils;
import androidx.core.math.MathUtils;
@ -47,10 +46,8 @@ import org.telegram.ui.Components.AnimatedFloat;
import org.telegram.ui.Components.AnimatedTextView;
import org.telegram.ui.Components.CubicBezierInterpolator;
import org.telegram.ui.Components.FloatSeekBarAccessibilityDelegate;
import org.telegram.ui.Components.LayoutHelper;
import org.telegram.ui.Components.MotionBackgroundDrawable;
import org.telegram.ui.Components.SeekBarAccessibilityDelegate;
import org.telegram.ui.Components.SeekBarView;
import org.telegram.ui.Components.SpeedIconDrawable;
public class ActionBarMenuSlider extends FrameLayout {
@ -111,7 +108,7 @@ public class ActionBarMenuSlider extends FrameLayout {
}
};
textDrawable.setCallback(this);
textDrawable.setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM));
textDrawable.setTypeface(AndroidUtilities.bold());
textDrawable.setAnimationProperties(.3f, 0, 165, CubicBezierInterpolator.EASE_OUT_QUINT);
textDrawable.setTextSize(AndroidUtilities.dpf2(14));
textDrawable.getPaint().setStyle(Paint.Style.FILL_AND_STROKE);

View file

@ -27,6 +27,7 @@ public class ActionBarMenuSubItem extends FrameLayout {
private TextView textView;
private TextView subtextView;
public RLottieImageView imageView;
private boolean checkViewLeft;
private CheckBox2 checkView;
private ImageView rightIcon;
@ -86,13 +87,16 @@ public class ActionBarMenuSubItem extends FrameLayout {
textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16);
addView(textView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.CENTER_VERTICAL));
checkViewLeft = LocaleController.isRTL;
if (needCheck > 0) {
checkView = new CheckBox2(context, 26, resourcesProvider);
checkView.setDrawUnchecked(false);
checkView.setColor(-1, -1, Theme.key_radioBackgroundChecked);
checkView.setDrawBackgroundAsArc(-1);
if (needCheck == 1) {
checkViewLeft = !LocaleController.isRTL;
addView(checkView, LayoutHelper.createFrame(26, LayoutHelper.MATCH_PARENT, Gravity.CENTER_VERTICAL | (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT)));
textView.setPadding(!LocaleController.isRTL ? dp(34) : 0, 0, !LocaleController.isRTL ? 0 : dp(34), 0);
} else {
addView(checkView, LayoutHelper.createFrame(26, LayoutHelper.MATCH_PARENT, Gravity.CENTER_VERTICAL | (LocaleController.isRTL ? Gravity.LEFT : Gravity.RIGHT)));
textView.setPadding(LocaleController.isRTL ? dp(34) : 0, 0, LocaleController.isRTL ? 0 : dp(34), 0);
@ -185,7 +189,7 @@ public class ActionBarMenuSubItem extends FrameLayout {
imageView.setImageResource(icon);
}
imageView.setVisibility(VISIBLE);
textView.setPadding(LocaleController.isRTL ? (checkView != null ? dp(34) : 0) : dp(43), 0, LocaleController.isRTL ? dp(43) : (checkView != null ? dp(34) : 0), 0);
textView.setPadding(checkViewLeft ? (checkView != null ? dp(43) : 0) : dp(icon != 0 || iconDrawable != null ? 43 : 0), 0, checkViewLeft ? dp(icon != 0 || iconDrawable != null ? 43 : 0) : (checkView != null ? dp(43) : 0), 0);
} else {
imageView.setVisibility(INVISIBLE);
textView.setPadding(0, 0, 0, 0);

View file

@ -97,7 +97,9 @@ public class ActionBarPopupWindow extends PopupWindow {
public final static int FLAG_USE_SWIPEBACK = 1;
public final static int FLAG_SHOWN_FROM_BOTTOM = 2;
public boolean updateAnimation;
public boolean clipChildren;
public boolean swipeBackGravityRight;
public boolean swipeBackGravityBottom;
private OnDispatchKeyEventListener mOnDispatchKeyEventListener;
private float backScaleX = 1;
@ -281,6 +283,9 @@ public class ActionBarPopupWindow extends PopupWindow {
@Keep
public void setBackAlpha(int value) {
if (backAlpha != value) {
invalidate();
}
backAlpha = value;
}
@ -440,6 +445,9 @@ public class ActionBarPopupWindow extends PopupWindow {
setTranslationY(yOffset);
}
}
if (swipeBackGravityBottom) {
setTranslationY(getMeasuredHeight() * (1f - backScaleY));
}
if (backgroundDrawable != null) {
int start = gapStartY - scrollView.getScrollY();
int end = gapEndY - scrollView.getScrollY();
@ -454,14 +462,12 @@ public class ActionBarPopupWindow extends PopupWindow {
if (a == 1 && start < -AndroidUtilities.dp(16)) {
break;
}
boolean needRestore = false;
int saveCount = canvas.getSaveCount();
boolean applyAlpha = true;
if (hasGap && backAlpha != 255) {
canvas.saveLayerAlpha(0, bgPaddings.top, getMeasuredWidth(), getMeasuredHeight(), backAlpha, Canvas.ALL_SAVE_FLAG);
needRestore = true;
applyAlpha = false;
} else if (gapStartY != -1000000) {
needRestore = true;
canvas.save();
canvas.clipRect(0, bgPaddings.top, getMeasuredWidth(), getMeasuredHeight());
}
@ -508,6 +514,13 @@ public class ActionBarPopupWindow extends PopupWindow {
}
backgroundDrawable.setBounds(AndroidUtilities.rectTmp2);
backgroundDrawable.draw(canvas);
if (clipChildren) {
AndroidUtilities.rectTmp2.left += bgPaddings.left;
AndroidUtilities.rectTmp2.top += bgPaddings.top;
AndroidUtilities.rectTmp2.right -= bgPaddings.right;
AndroidUtilities.rectTmp2.bottom -= bgPaddings.bottom;
canvas.clipRect(AndroidUtilities.rectTmp2);
}
if (hasGap) {
canvas.save();
AndroidUtilities.rectTmp.set(backgroundDrawable.getBounds());
@ -540,9 +553,7 @@ public class ActionBarPopupWindow extends PopupWindow {
}
canvas.restore();
}
if (needRestore) {
canvas.restore();
}
canvas.restoreToCount(saveCount);
}
}
if (reactionsEnterProgress != 1f) {
@ -845,10 +856,11 @@ public class ActionBarPopupWindow extends PopupWindow {
}
float at = AndroidUtilities.cascade(t, content.shownFromBottom ? count2 - 1 - a : a, count2, 4);
child.setTranslationY((1f - at) * AndroidUtilities.dp(-6));
// child.setAlpha(at * (child.isEnabled() ? 1f : 0.5f));
child.setAlpha(at * (child.isEnabled() ? 1f : 0.5f));
}
});
content.updateAnimation = true;
content.updateAnimation = false;
content.clipChildren = true;
windowAnimatorSet.playTogether(
ObjectAnimator.ofFloat(content, "backScaleY", 0.0f, finalScaleY),
ObjectAnimator.ofInt(content, "backAlpha", 0, 255),
@ -865,6 +877,7 @@ public class ActionBarPopupWindow extends PopupWindow {
if (child instanceof GapView) {
continue;
}
child.setTranslationY(0);
child.setAlpha(child.isEnabled() ? 1f : 0.5f);
}
}

View file

@ -12,7 +12,7 @@ import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.app.Activity;
import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
@ -20,7 +20,6 @@ import android.graphics.Bitmap;
import android.graphics.BitmapShader;
import android.graphics.Canvas;
import android.graphics.ColorFilter;
import android.graphics.CornerPathEffect;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.PorterDuff;
@ -55,10 +54,7 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.graphics.ColorUtils;
import com.google.android.exoplayer2.util.Log;
import org.telegram.messenger.AndroidUtilities;
import org.telegram.messenger.Emoji;
import org.telegram.messenger.FileLog;
import org.telegram.messenger.LiteMode;
import org.telegram.messenger.LocaleController;
@ -71,12 +67,10 @@ import org.telegram.ui.Components.AnimatedFloat;
import org.telegram.ui.Components.EffectsTextView;
import org.telegram.ui.Components.LayoutHelper;
import org.telegram.ui.Components.LineProgressView;
import org.telegram.ui.Components.LinkSpanDrawable;
import org.telegram.ui.Components.RLottieDrawable;
import org.telegram.ui.Components.RLottieImageView;
import org.telegram.ui.Components.RadialProgressView;
import org.telegram.ui.Components.spoilers.SpoilersTextView;
import org.telegram.ui.LaunchActivity;
import java.util.ArrayList;
import java.util.Map;
@ -88,6 +82,7 @@ public class AlertDialog extends Dialog implements Drawable.Callback, Notificati
public static final int ALERT_TYPE_SPINNER = 3;
private int customWidth = -1;
private boolean customMaxHeight;
private View customView;
private View bottomView;
private View aboveMessageView;
@ -302,6 +297,7 @@ public class AlertDialog extends Dialog implements Drawable.Callback, Notificati
@Override
public void show() {
if (!AndroidUtilities.isSafeToShow(getContext())) return;
super.show();
if (progressViewContainer != null && progressViewStyle == ALERT_TYPE_SPINNER) {
progressViewContainer.setScaleX(0);
@ -690,7 +686,7 @@ public class AlertDialog extends Dialog implements Drawable.Callback, Notificati
titleTextView.setText(title);
titleTextView.setTextColor(getThemedColor(Theme.key_dialogTextBlack));
titleTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 20);
titleTextView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf"));
titleTextView.setTypeface(AndroidUtilities.bold());
titleTextView.setGravity((topAnimationIsNew ? Gravity.CENTER_HORIZONTAL : LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.TOP);
titleContainer.addView(titleTextView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, (topAnimationIsNew ? Gravity.CENTER_HORIZONTAL : LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.TOP, 0, 19, 0, topAnimationIsNew ? 4 : (subtitle != null ? 2 : (items != null ? 14 : 10))));
}
@ -766,7 +762,7 @@ public class AlertDialog extends Dialog implements Drawable.Callback, Notificati
containerView.addView(lineProgressView, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 4, Gravity.LEFT | Gravity.CENTER_VERTICAL, 24, 0, 24, 0));
lineProgressViewPercent = new TextView(getContext());
lineProgressViewPercent.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf"));
lineProgressViewPercent.setTypeface(AndroidUtilities.bold());
lineProgressViewPercent.setGravity((LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.TOP);
lineProgressViewPercent.setTextColor(getThemedColor(Theme.key_dialogTextGray2));
lineProgressViewPercent.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14);
@ -962,7 +958,7 @@ public class AlertDialog extends Dialog implements Drawable.Callback, Notificati
textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16);
textView.setTextColor(getThemedColor(dialogButtonColorKey));
textView.setGravity(Gravity.CENTER);
textView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf"));
textView.setTypeface(AndroidUtilities.bold());
// textView.setLines(1);
// textView.setSingleLine(true); //TODO
textView.setText(positiveButtonText.toString());
@ -1002,7 +998,7 @@ public class AlertDialog extends Dialog implements Drawable.Callback, Notificati
textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16);
textView.setTextColor(getThemedColor(dialogButtonColorKey));
textView.setGravity(Gravity.CENTER);
textView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf"));
textView.setTypeface(AndroidUtilities.bold());
textView.setEllipsize(TextUtils.TruncateAt.END);
textView.setSingleLine(true);
textView.setText(negativeButtonText.toString());
@ -1042,7 +1038,7 @@ public class AlertDialog extends Dialog implements Drawable.Callback, Notificati
textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16);
textView.setTextColor(getThemedColor(dialogButtonColorKey));
textView.setGravity(Gravity.CENTER);
textView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf"));
textView.setTypeface(AndroidUtilities.bold());
textView.setEllipsize(TextUtils.TruncateAt.END);
textView.setSingleLine(true);
textView.setText(neutralButtonText.toString());
@ -1741,5 +1737,10 @@ public class AlertDialog extends Dialog implements Drawable.Callback, Notificati
alertDialog.additioanalHorizontalPadding = padding;
return this;
}
public Builder makeCustomMaxHeight() {
alertDialog.customMaxHeight = true;
return this;
}
}
}

View file

@ -1,5 +1,7 @@
package org.telegram.ui.ActionBar;
import static org.telegram.messenger.AndroidUtilities.dp;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.app.Activity;
@ -118,7 +120,7 @@ public class AlertDialogDecor extends AlertDialog {
} else {
rect.set(insets.getStableInsetLeft(), insets.getStableInsetTop(), insets.getStableInsetRight(), insets.getStableInsetBottom());
}
contentWrapper.setPadding(rect.left, rect.top, rect.right, rect.bottom);
contentWrapper.setPadding(rect.left, rect.top, rect.right, rect.bottom + AndroidUtilities.navigationBarHeight);
contentWrapper.requestLayout();
return insets;
});

View file

@ -13,6 +13,7 @@ import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.app.Activity;
import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
@ -29,7 +30,6 @@ import android.graphics.drawable.Drawable;
import android.os.Build;
import android.os.Bundle;
import android.text.TextUtils;
import android.util.Log;
import android.util.TypedValue;
import android.view.Gravity;
import android.view.KeyEvent;
@ -75,6 +75,7 @@ public class BottomSheet extends Dialog {
protected ViewGroup containerView;
public ContainerView container;
protected boolean keyboardVisible;
private int lastKeyboardHeight;
protected int keyboardHeight;
private WindowInsets lastInsets;
public boolean drawNavigationBar;
@ -502,6 +503,8 @@ public class BottomSheet extends Dialog {
keyboardHeight = Math.max(0, usableViewHeight - (rect.bottom - rect.top));
if (keyboardHeight < AndroidUtilities.dp(20)) {
keyboardHeight = 0;
} else {
lastKeyboardHeight = keyboardHeight;
}
bottomInset -= keyboardHeight;
} else {
@ -933,13 +936,13 @@ public class BottomSheet extends Dialog {
textView.setGravity(Gravity.CENTER);
textView.setTextColor(getThemedColor(Theme.key_dialogTextBlack));
textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14);
textView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf"));
textView.setTypeface(AndroidUtilities.bold());
addView(textView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT));
} else if (type == 2) {
textView.setGravity(Gravity.CENTER);
textView.setTextColor(getThemedColor(Theme.key_featuredStickers_buttonText));
textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14);
textView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf"));
textView.setTypeface(AndroidUtilities.bold());
textView.setBackground(Theme.AdaptiveRipple.filledRect(getThemedColor(Theme.key_featuredStickers_addButton), 6));
addView(textView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, 0, 16, 16, 16, 16));
}
@ -1178,6 +1181,9 @@ public class BottomSheet extends Dialog {
@Override
public void setTranslationY(float translationY) {
super.setTranslationY(translationY);
if (topBulletinContainer != null) {
topBulletinContainer.setTranslationY(-getHeight() + translationY - getPaddingTop() - AndroidUtilities.statusBarHeight + backgroundPaddingTop);
}
onContainerTranslationYChanged(translationY);
}
};
@ -1187,6 +1193,11 @@ public class BottomSheet extends Dialog {
containerView.setVisibility(View.INVISIBLE);
container.addView(containerView, 0, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.BOTTOM));
if (topBulletinContainer == null) {
topBulletinContainer = new FrameLayout(getContext());
container.addView(topBulletinContainer, container.indexOfChild(containerView) + 1, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.BOTTOM));
}
int topOffset = 0;
if (title != null) {
titleView = new TextView(getContext()) {
@ -1214,7 +1225,7 @@ public class BottomSheet extends Dialog {
if (bigTitle) {
titleView.setTextColor(getThemedColor(Theme.key_dialogTextBlack));
titleView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 20);
titleView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf"));
titleView.setTypeface(AndroidUtilities.bold());
titleView.setPadding(AndroidUtilities.dp(21), AndroidUtilities.dp(multipleLinesTitle ? 14 : 6), AndroidUtilities.dp(21), AndroidUtilities.dp(8));
} else {
titleView.setTextColor(getThemedColor(Theme.key_dialogTextGray2));
@ -1345,6 +1356,7 @@ public class BottomSheet extends Dialog {
@Override
public void show() {
if (!AndroidUtilities.isSafeToShow(getContext())) return;
super.show();
setShowing(true);
if (focusable) {
@ -1720,6 +1732,11 @@ public class BottomSheet extends Dialog {
return false;
}
private boolean forceKeyboardOnDismiss;
public void forceKeyboardOnDismiss() {
forceKeyboardOnDismiss = true;
}
@Override
public void dismiss() {
if (delegate != null && !delegate.canDismiss()) {
@ -1763,7 +1780,7 @@ public class BottomSheet extends Dialog {
animators.add(ObjectAnimator.ofFloat(containerView, View.TRANSLATION_X, AndroidUtilities.dp(48)));
animators.add(ObjectAnimator.ofFloat(containerView, View.ALPHA, 0));
} else {
animators.add(ObjectAnimator.ofFloat(containerView, View.TRANSLATION_Y, getContainerViewHeight() + keyboardHeight + AndroidUtilities.dp(10) + (scrollNavBar ? getBottomInset() : 0)));
animators.add(ObjectAnimator.ofFloat(containerView, View.TRANSLATION_Y, getContainerViewHeight() + (forceKeyboardOnDismiss ? lastKeyboardHeight : keyboardHeight) + AndroidUtilities.dp(10) + (scrollNavBar ? getBottomInset() : 0)));
}
}
animators.add(ObjectAnimator.ofInt(backDrawable, AnimationProperties.COLOR_DRAWABLE_ALPHA, 0));

View file

@ -46,6 +46,7 @@ import org.telegram.messenger.BuildVars;
import org.telegram.messenger.FileLog;
import org.telegram.messenger.R;
import org.telegram.messenger.Utilities;
import org.telegram.ui.Components.PasscodeView;
public class DrawerLayoutContainer extends FrameLayout {

View file

@ -590,6 +590,7 @@ public class EmojiThemes {
}
private int getOrDefault(SparseIntArray colorsMap, int key) {
if (colorsMap == null) return Theme.getDefaultColor(key);
int index = colorsMap.indexOfKey(key);
if (index >= 0) {
return colorsMap.valueAt(index);

View file

@ -34,7 +34,6 @@ import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.GradientDrawable;
import android.text.TextUtils;
import android.util.Log;
import android.util.Size;
import android.util.TypedValue;
import android.view.Gravity;
@ -70,7 +69,6 @@ import org.telegram.messenger.NotificationCenter;
import org.telegram.messenger.R;
import org.telegram.messenger.UserConfig;
import org.telegram.messenger.Utilities;
import org.telegram.ui.Components.CubicBezierInterpolator;
import org.telegram.ui.Components.LayoutHelper;
import java.util.ArrayList;
@ -1315,7 +1313,7 @@ public final class FloatingToolbar {
textView.setGravity(Gravity.CENTER);
textView.setSingleLine(true);
textView.setEllipsize(TextUtils.TruncateAt.END);
textView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf"));
textView.setTypeface(AndroidUtilities.bold());
textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14);
textView.setFocusable(false);
textView.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO);

View file

@ -152,6 +152,17 @@ public interface INavigationLayout {
return getFragmentStack().isEmpty() ? null : getFragmentStack().get(getFragmentStack().size() - 1);
}
default BaseFragment getSafeLastFragment() {
if (getFragmentStack().isEmpty()) return null;
for (int i = getFragmentStack().size() - 1; i >= 0; --i) {
BaseFragment fragment = getFragmentStack().get(i);
if (fragment == null || fragment.isFinishing() || fragment.isRemovingFromStack())
continue;
return fragment;
}
return null;
}
default void animateThemedValues(Theme.ThemeInfo theme, int accentId, boolean nightTheme, boolean instant) {
animateThemedValues(new ThemeAnimationSettings(theme, accentId, nightTheme, instant), null);
}

View file

@ -103,11 +103,11 @@ public class OKLCH {
}
public static double[] oklch2rgb(double[] lch) {
return srgbLinear2rgb(xyz2rgbLinear(oklab2xyz(oklch2oklab(lch))));
return xyz2rgbLinear(oklab2xyz(oklch2oklab(lch)));
}
public static double[] rgb2oklch(double[] rgb) {
return oklab2oklch(xyz2oklab(rgbLinear2xyz(rgb2srgbLinear(rgb))));
return oklab2oklch(xyz2oklab(rgbLinear2xyz(rgb)));
}
public static double[] rgb(int color) {

View file

@ -101,6 +101,7 @@ import org.telegram.tgnet.ConnectionsManager;
import org.telegram.tgnet.SerializedData;
import org.telegram.tgnet.TLRPC;
import org.telegram.ui.BlurSettingsBottomSheet;
import org.telegram.ui.Cells.BaseCell;
import org.telegram.ui.ChatActivity;
import org.telegram.ui.Components.AudioVisualizerDrawable;
import org.telegram.ui.Components.BackgroundGradientDrawable;
@ -3912,6 +3913,7 @@ public class Theme {
public static final int key_chat_TextSelectionCursor = colorsCount++;
public static final int key_chat_inBubbleLocationPlaceholder = colorsCount++;
public static final int key_chat_BlurAlpha = colorsCount++;
public static final int key_chat_BlurAlphaSlow = colorsCount++;
public static final int key_chat_editMediaButton = colorsCount++;
public static final int key_voipgroup_listSelector = colorsCount++;
@ -3977,6 +3979,9 @@ public class Theme {
public static final int key_voipgroup_windowBackgroundWhiteInputField = colorsCount++;
public static final int key_voipgroup_windowBackgroundWhiteInputFieldActivated = colorsCount++;
public static final int key_table_background = colorsCount++;
public static final int key_table_border = colorsCount++;
public static final int key_passport_authorizeBackground = colorsCount++;
public static final int key_passport_authorizeBackgroundSelected = colorsCount++;
public static final int key_passport_authorizeText = colorsCount++;
@ -4135,6 +4140,8 @@ public class Theme {
public static final int key_premiumGradientBottomSheet3 = colorsCount++;
public static final int key_topics_unreadCounter = colorsCount++;
public static final int key_topics_unreadCounterMuted = colorsCount++;
public static final int key_starsGradient1 = colorsCount++;
public static final int key_starsGradient2 = colorsCount++;
public static final int key_stories_circle1 = colorsCount++;
public static final int key_stories_circle2 = colorsCount++;
@ -4406,6 +4413,9 @@ public class Theme {
fallbackKeys.put(key_actionBarActionModeReaction, key_windowBackgroundGray);
fallbackKeys.put(key_actionBarActionModeReactionText, key_chat_inReactionButtonText);
fallbackKeys.put(key_table_background, key_graySection);
fallbackKeys.put(key_table_border, key_divider);
for (int i = 0; i < keys_avatar_background.length; i++) {
themeAccentExclusionKeys.add(keys_avatar_background[i]);
}
@ -5293,7 +5303,7 @@ public class Theme {
new int[][]{StateSet.WILD_CARD},
new int[]{pressedColor}
);
return new RippleDrawable(colorStateList, defaultDrawable, pressedDrawable);
return new BaseCell.RippleDrawableSafe(colorStateList, defaultDrawable, pressedDrawable);
} else {
pressedDrawable.getPaint().setColor(pressedColor);
StateListDrawable stateListDrawable = new StateListDrawable();
@ -5375,7 +5385,7 @@ public class Theme {
new int[][]{StateSet.WILD_CARD},
new int[]{pressedColor}
);
return new RippleDrawable(colorStateList, defaultDrawable, pressedDrawable);
return new BaseCell.RippleDrawableSafe(colorStateList, defaultDrawable, pressedDrawable);
} else {
StateListDrawable stateListDrawable = new StateListDrawable();
stateListDrawable.addState(new int[]{android.R.attr.state_pressed}, pressedDrawable);
@ -5404,7 +5414,7 @@ public class Theme {
new int[][]{StateSet.WILD_CARD},
new int[]{(color & 0x00ffffff) | 0x19000000}
);
return new RippleDrawable(colorStateList, null, maskDrawable);
return new BaseCell.RippleDrawableSafe(colorStateList, null, maskDrawable);
} else {
StateListDrawable stateListDrawable = new StateListDrawable();
stateListDrawable.addState(new int[]{android.R.attr.state_pressed}, createRoundRectDrawable(corners, (color & 0x00ffffff) | 0x19000000));
@ -5421,7 +5431,7 @@ public class Theme {
new int[][]{StateSet.WILD_CARD},
new int[]{color}
);
return new RippleDrawable(colorStateList, new ColorDrawable(backgroundColor), maskDrawable);
return new BaseCell.RippleDrawableSafe(colorStateList, new ColorDrawable(backgroundColor), maskDrawable);
} else {
StateListDrawable stateListDrawable = new StateListDrawable();
stateListDrawable.addState(new int[]{android.R.attr.state_pressed}, new ColorDrawable(color));
@ -5454,7 +5464,7 @@ public class Theme {
new int[][]{StateSet.WILD_CARD},
new int[]{color}
);
return new RippleDrawable(colorStateList, new ColorDrawable(getColor(backgroundColor)), maskDrawable);
return new BaseCell.RippleDrawableSafe(colorStateList, new ColorDrawable(getColor(backgroundColor)), maskDrawable);
} else {
StateListDrawable stateListDrawable = new StateListDrawable();
stateListDrawable.addState(new int[]{android.R.attr.state_pressed}, new ColorDrawable(color));
@ -5547,7 +5557,7 @@ public class Theme {
new int[][]{ StateSet.WILD_CARD },
new int[]{ color }
);
RippleDrawable rippleDrawable = new RippleDrawable(colorStateList, null, maskDrawable);
RippleDrawable rippleDrawable = new BaseCell.RippleDrawableSafe(colorStateList, null, maskDrawable);
if (Build.VERSION.SDK_INT >= 23) {
if (maskType == RIPPLE_MASK_CIRCLE_20DP) {
rippleDrawable.setRadius(radius <= 0 ? dp(20) : radius);
@ -5594,7 +5604,7 @@ public class Theme {
new int[][]{StateSet.WILD_CARD},
new int[]{color}
);
return new RippleDrawable(colorStateList, null, maskDrawable);
return new BaseCell.RippleDrawableSafe(colorStateList, null, maskDrawable);
} else {
StateListDrawable stateListDrawable = new StateListDrawable();
stateListDrawable.addState(new int[]{android.R.attr.state_pressed}, new ColorDrawable(color));
@ -5760,7 +5770,7 @@ public class Theme {
maskDrawable = new ShapeDrawable(new RectShape());
((ShapeDrawable) maskDrawable).getPaint().setColor(0xffffffff);
}
return new RippleDrawable(
return new BaseCell.RippleDrawableSafe(
new ColorStateList(
new int[][]{ StateSet.WILD_CARD },
new int[]{ rippleColor }
@ -5801,7 +5811,7 @@ public class Theme {
}
private static Drawable createCircle(Drawable background, int rippleColor, float radius) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
return new RippleDrawable(
return new BaseCell.RippleDrawableSafe(
new ColorStateList(
new int[][]{ StateSet.WILD_CARD },
new int[]{ rippleColor }
@ -6004,7 +6014,6 @@ public class Theme {
}
}
public static Drawable createRadSelectorDrawable(int color, int topRad, int bottomRad) {
if (Build.VERSION.SDK_INT >= 21) {
maskPaint.setColor(0xffffffff);
@ -6013,7 +6022,7 @@ public class Theme {
new int[][]{StateSet.WILD_CARD},
new int[]{color}
);
return new RippleDrawable(colorStateList, null, maskDrawable);
return new BaseCell.RippleDrawableSafe(colorStateList, null, maskDrawable);
} else {
StateListDrawable stateListDrawable = new StateListDrawable();
stateListDrawable.addState(new int[]{android.R.attr.state_pressed}, new ColorDrawable(color));
@ -6031,7 +6040,7 @@ public class Theme {
new int[][]{StateSet.WILD_CARD},
new int[]{rippleColor}
);
return new RippleDrawable(colorStateList, createRoundRectDrawable(dp(topRad), dp(bottomRad), color), maskDrawable);
return new BaseCell.RippleDrawableSafe(colorStateList, createRoundRectDrawable(dp(topRad), dp(bottomRad), color), maskDrawable);
} else {
Drawable backgroundDrawable = createRoundRectDrawable(dp(topRad), dp(bottomRad), color);
Drawable pressedDrawable = new LayerDrawable(new Drawable[]{backgroundDrawable, createRoundRectDrawable(dp(topRad), dp(bottomRad), rippleColor)});
@ -6051,7 +6060,7 @@ public class Theme {
new int[][]{StateSet.WILD_CARD},
new int[]{color}
);
return new RippleDrawable(colorStateList, null, maskDrawable);
return new BaseCell.RippleDrawableSafe(colorStateList, null, maskDrawable);
} else {
StateListDrawable stateListDrawable = new StateListDrawable();
stateListDrawable.addState(new int[]{android.R.attr.state_pressed}, new ColorDrawable(color));
@ -8283,7 +8292,7 @@ public class Theme {
public static void createCommonDialogResources(Context context) {
if (dialogs_countTextPaint == null) {
dialogs_countTextPaint = new TextPaint(TextPaint.ANTI_ALIAS_FLAG);
dialogs_countTextPaint.setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM));
dialogs_countTextPaint.setTypeface(AndroidUtilities.bold());
dialogs_countPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
dialogs_reactionsCountPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
dialogs_onlineCirclePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
@ -8305,27 +8314,27 @@ public class Theme {
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(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM));
dialogs_namePaint[a].setTypeface(AndroidUtilities.bold());
dialogs_nameEncryptedPaint[a] = new TextPaint(TextPaint.ANTI_ALIAS_FLAG);
dialogs_nameEncryptedPaint[a].setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM));
dialogs_nameEncryptedPaint[a].setTypeface(AndroidUtilities.bold());
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(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM));
dialogs_searchNamePaint.setTypeface(AndroidUtilities.bold());
dialogs_searchNameEncryptedPaint = new TextPaint(TextPaint.ANTI_ALIAS_FLAG);
dialogs_searchNameEncryptedPaint.setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM));
dialogs_searchNameEncryptedPaint.setTypeface(AndroidUtilities.bold());
dialogs_messageNamePaint = new TextPaint(TextPaint.ANTI_ALIAS_FLAG);
dialogs_messageNamePaint.setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM));
dialogs_messageNamePaint.setTypeface(AndroidUtilities.bold());
dialogs_timePaint = new TextPaint(TextPaint.ANTI_ALIAS_FLAG);
dialogs_archiveTextPaint = new TextPaint(TextPaint.ANTI_ALIAS_FLAG);
dialogs_archiveTextPaint.setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM));
dialogs_archiveTextPaint.setTypeface(AndroidUtilities.bold());
dialogs_archiveTextPaintSmall = new TextPaint(TextPaint.ANTI_ALIAS_FLAG);
dialogs_archiveTextPaintSmall.setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM));
dialogs_archiveTextPaintSmall.setTypeface(AndroidUtilities.bold());
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_tagTextPaint.setTypeface(AndroidUtilities.bold());
dialogs_tabletSeletedPaint = new Paint();
dialogs_pinnedPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
@ -8466,16 +8475,16 @@ public class Theme {
chat_msgTextPaintTwoEmoji = new TextPaint(Paint.ANTI_ALIAS_FLAG);
chat_msgTextPaintThreeEmoji = new TextPaint(Paint.ANTI_ALIAS_FLAG);
chat_msgBotButtonPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG);
chat_msgBotButtonPaint.setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM));
chat_msgBotButtonPaint.setTypeface(AndroidUtilities.bold());
chat_namePaint = new TextPaint(TextPaint.ANTI_ALIAS_FLAG);
chat_namePaint.setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM));
chat_namePaint.setTypeface(AndroidUtilities.bold());
chat_replyNamePaint = new TextPaint(TextPaint.ANTI_ALIAS_FLAG);
chat_replyNamePaint.setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM));
chat_replyNamePaint.setTypeface(AndroidUtilities.bold());
chat_replyTextPaint = new TextPaint(TextPaint.ANTI_ALIAS_FLAG);
chat_quoteTextPaint = new TextPaint(TextPaint.ANTI_ALIAS_FLAG);
chat_titleLabelTextPaint = new TextPaint(TextPaint.ANTI_ALIAS_FLAG);
chat_topicTextPaint = new TextPaint(TextPaint.ANTI_ALIAS_FLAG);
chat_topicTextPaint.setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM));
chat_topicTextPaint.setTypeface(AndroidUtilities.bold());
chat_forwardNamePaint = new TextPaint(TextPaint.ANTI_ALIAS_FLAG);
chat_adminPaint = new TextPaint(TextPaint.ANTI_ALIAS_FLAG);
chat_timePaint = new TextPaint(TextPaint.ANTI_ALIAS_FLAG);
@ -8520,17 +8529,17 @@ public class Theme {
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(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM));
chat_infoBoldPaint.setTypeface(AndroidUtilities.bold());
chat_stickerCommentCountPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG);
chat_stickerCommentCountPaint.setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM));
chat_stickerCommentCountPaint.setTypeface(AndroidUtilities.bold());
chat_docNamePaint = new TextPaint(Paint.ANTI_ALIAS_FLAG);
chat_docNamePaint.setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM));
chat_docNamePaint.setTypeface(AndroidUtilities.bold());
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(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM));
chat_locationTitlePaint.setTypeface(AndroidUtilities.bold());
chat_locationAddressPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG);
chat_urlPaint = new Paint();
chat_urlPaint.setPathEffect(LinkPath.getRoundedEffect());
@ -8549,31 +8558,31 @@ public class Theme {
chat_livePaint = new TextPaint(Paint.ANTI_ALIAS_FLAG);
chat_livePaint.setTypeface(Typeface.DEFAULT_BOLD);
chat_audioTitlePaint = new TextPaint(Paint.ANTI_ALIAS_FLAG);
chat_audioTitlePaint.setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM));
chat_audioTitlePaint.setTypeface(AndroidUtilities.bold());
chat_audioPerformerPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG);
chat_botButtonPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG);
chat_botButtonPaint.setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM));
chat_botButtonPaint.setTypeface(AndroidUtilities.bold());
chat_contactNamePaint = new TextPaint(Paint.ANTI_ALIAS_FLAG);
chat_contactNamePaint.setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM));
chat_contactNamePaint.setTypeface(AndroidUtilities.bold());
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(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM));
chat_gamePaint.setTypeface(AndroidUtilities.bold());
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(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM));
chat_namePaint.setTypeface(AndroidUtilities.bold());
chat_forwardNamePaint = new TextPaint(TextPaint.ANTI_ALIAS_FLAG);
chat_replyNamePaint = new TextPaint(TextPaint.ANTI_ALIAS_FLAG);
chat_replyNamePaint.setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM));
chat_replyNamePaint.setTypeface(AndroidUtilities.bold());
chat_replyTextPaint = new TextPaint(TextPaint.ANTI_ALIAS_FLAG);
chat_topicTextPaint = new TextPaint(TextPaint.ANTI_ALIAS_FLAG);
chat_topicTextPaint.setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM));
chat_topicTextPaint.setTypeface(AndroidUtilities.bold());
chat_titleLabelTextPaint = new TextPaint(TextPaint.ANTI_ALIAS_FLAG);
chat_commentTextPaint = new TextPaint(TextPaint.ANTI_ALIAS_FLAG);
chat_instantViewPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG);
chat_instantViewPaint.setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM));
chat_instantViewPaint.setTypeface(AndroidUtilities.bold());
chat_instantViewRectPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
chat_instantViewRectPaint.setStyle(Paint.Style.STROKE);
chat_instantViewRectPaint.setStrokeCap(Paint.Cap.ROUND);
@ -8589,14 +8598,14 @@ public class Theme {
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(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM));
chat_actionTextPaint.setTypeface(AndroidUtilities.bold());
chat_unlockExtendedMediaTextPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG);
chat_unlockExtendedMediaTextPaint.setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM));
chat_unlockExtendedMediaTextPaint.setTypeface(AndroidUtilities.bold());
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(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM));
chat_contextResult_titleTextPaint.setTypeface(AndroidUtilities.bold());
chat_contextResult_descriptionTextPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG);
chat_composeBackgroundPaint = new Paint();
chat_radialProgressPausedPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
@ -8880,7 +8889,7 @@ public class Theme {
chat_radialProgressPaint.setStrokeWidth(dp(3));
chat_radialProgress2Paint.setStrokeWidth(dp(2.33f));
chat_commentTextPaint.setTextSize(dp(14));
chat_commentTextPaint.setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM));
chat_commentTextPaint.setTypeface(AndroidUtilities.bold());
}
}

View file

@ -195,9 +195,11 @@ public class ThemeColors {
defaultColors[key_actionBarTabUnactiveText] = 0xffd5e8f7;
defaultColors[key_actionBarTabLine] = 0xffffffff;
defaultColors[key_actionBarTabSelector] = 0xff406d94;
defaultColors[key_actionBarBrowser] = 0xffffffff;
defaultColors[key_table_background] = 0xfff7f7f7;
defaultColors[key_table_border] = 0xffE0E0E0;
defaultColors[key_actionBarDefaultArchived] = 0xff6f7a87;
defaultColors[key_actionBarDefaultArchivedSelector] = 0xff5e6772;
defaultColors[key_actionBarDefaultArchivedIcon] = 0xffffffff;
@ -768,6 +770,8 @@ public class ThemeColors {
defaultColors[key_premiumGradientBottomSheet3] = 0xffE794BE;
defaultColors[key_topics_unreadCounter] = 0xff4ecc5e;
defaultColors[key_topics_unreadCounterMuted] = 0xff8b8d8f;
defaultColors[key_starsGradient1] = 0xffFEC846;
defaultColors[key_starsGradient2] = 0xffEC920A;
defaultColors[key_stories_circle1] = 0xFF39DF3C;
defaultColors[key_stories_circle2] = 0xFF4DBBFF;
@ -974,6 +978,8 @@ public class ThemeColors {
colorKeysMap.put(key_actionBarTabUnactiveText, "actionBarTabUnactiveText");
colorKeysMap.put(key_actionBarTabLine, "actionBarTabLine");
colorKeysMap.put(key_actionBarTabSelector, "actionBarTabSelector");
colorKeysMap.put(key_table_background, "table_background");
colorKeysMap.put(key_table_border, "table_border");
colorKeysMap.put(key_actionBarDefaultArchived, "actionBarDefaultArchived");
colorKeysMap.put(key_actionBarDefaultArchivedSelector, "actionBarDefaultArchivedSelector");
colorKeysMap.put(key_actionBarDefaultArchivedIcon, "actionBarDefaultArchivedIcon");
@ -1316,6 +1322,7 @@ public class ThemeColors {
colorKeysMap.put(key_chat_inBubbleLocationPlaceholder, "chat_inBubbleLocationPlaceholder");
colorKeysMap.put(key_chat_outBubbleLocationPlaceholder, "chat_outBubbleLocationPlaceholder");
colorKeysMap.put(key_chat_BlurAlpha, "chat_BlurAlpha");
colorKeysMap.put(key_chat_BlurAlphaSlow, "chat_BlurAlphaSlow");
colorKeysMap.put(key_chat_editMediaButton, "chat_editMediaButton");
colorKeysMap.put(key_voipgroup_listSelector, "voipgroup_listSelector");

View file

@ -526,7 +526,7 @@ public class ActionIntroActivity extends BaseFragment implements LocationControl
descriptionLines[a * 2].setGravity(LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT);
descriptionLines[a * 2].setTextSize(TypedValue.COMPLEX_UNIT_DIP, 15);
descriptionLines[a * 2].setText(String.format(LocaleController.isRTL ? ".%d" : "%d.", a + 1));
descriptionLines[a * 2].setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM));
descriptionLines[a * 2].setTypeface(AndroidUtilities.bold());
descriptionLines[a * 2 + 1] = new TextView(context);
descriptionLines[a * 2 + 1].setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlackText));
@ -601,7 +601,7 @@ public class ActionIntroActivity extends BaseFragment implements LocationControl
buttonTextView.setGravity(Gravity.CENTER);
buttonTextView.setTextColor(Theme.getColor(Theme.key_featuredStickers_buttonText));
buttonTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14);
buttonTextView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf"));
buttonTextView.setTypeface(AndroidUtilities.bold());
int buttonRadiusDp = currentType == ACTION_TYPE_SET_PASSCODE || currentType == ACTION_TYPE_CHANGE_PHONE_NUMBER || currentType == ACTION_TYPE_CHANNEL_CREATE ? 6 : 4;
buttonTextView.setBackground(Theme.AdaptiveRipple.filledRectByKey(Theme.key_featuredStickers_addButton, buttonRadiusDp));
viewGroup.addView(buttonTextView);

View file

@ -603,7 +603,7 @@ public class DialogsAdapter extends RecyclerListView.SelectionAdapter implements
TextView textView = new TextView(mContext);
textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 15);
textView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf"));
textView.setTypeface(AndroidUtilities.bold());
textView.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlueHeader));
textView.setText(LocaleController.getString("RecentlyViewedHide", R.string.RecentlyViewedHide));
textView.setGravity((LocaleController.isRTL ? Gravity.LEFT : Gravity.RIGHT) | Gravity.CENTER_VERTICAL);
@ -734,7 +734,7 @@ public class DialogsAdapter extends RecyclerListView.SelectionAdapter implements
break;
}
case VIEW_TYPE_FOLDER_UPDATE_HINT:
view = new DialogsHintCell(mContext);
view = new DialogsHintCell(mContext, null);
break;
case VIEW_TYPE_STORIES: {
view = new View(mContext) {

View file

@ -719,7 +719,7 @@ public class DialogsSearchAdapter extends RecyclerListView.SelectionAdapter {
}
if (!usersToLoad.isEmpty()) {
MessagesStorage.getInstance(currentAccount).getUsersInternal(TextUtils.join(",", usersToLoad), users);
MessagesStorage.getInstance(currentAccount).getUsersInternal(usersToLoad, users);
for (int a = 0; a < users.size(); a++) {
TLRPC.User user = users.get(a);
RecentSearchObject recentSearchObject = hashMap.get(user.id);

View file

@ -14,12 +14,14 @@ import android.view.ViewGroup;
import androidx.recyclerview.widget.RecyclerView;
import org.telegram.messenger.HashtagSearchController;
import org.telegram.messenger.MediaDataController;
import org.telegram.messenger.MessageObject;
import org.telegram.messenger.UserConfig;
import org.telegram.messenger.Utilities;
import org.telegram.ui.ActionBar.Theme;
import org.telegram.ui.Cells.DialogCell;
import org.telegram.ui.Cells.LoadingCell;
import org.telegram.ui.Components.FlickerLoadingView;
import org.telegram.ui.Components.RecyclerListView;
import java.util.ArrayList;
@ -31,20 +33,28 @@ public class MessagesSearchAdapter extends RecyclerListView.SelectionAdapter {
private HashSet<Integer> messageIds = new HashSet<>();
private ArrayList<MessageObject> searchResultMessages = new ArrayList<>();
public int loadedCount;
public int flickerCount;
private int currentAccount = UserConfig.selectedAccount;
private final Theme.ResourcesProvider resourcesProvider;
private int searchType;
public MessagesSearchAdapter(Context context, Theme.ResourcesProvider resourcesProvider) {
private boolean isSavedMessages;
public MessagesSearchAdapter(Context context, Theme.ResourcesProvider resourcesProvider, int searchType, boolean isSavedMessages) {
this.resourcesProvider = resourcesProvider;
mContext = context;
this.searchType = searchType;
this.isSavedMessages = isSavedMessages;
}
@Override
public void notifyDataSetChanged() {
final int oldItemsCount = getItemCount();
searchResultMessages.clear();
messageIds.clear();
ArrayList<MessageObject> searchResults = MediaDataController.getInstance(currentAccount).getFoundMessageObjects();
ArrayList<MessageObject> searchResults = searchType == 0 ? MediaDataController.getInstance(currentAccount).getFoundMessageObjects() : HashtagSearchController.getInstance(currentAccount).getMessages(searchType);
for (int i = 0; i < searchResults.size(); ++i) {
MessageObject m = searchResults.get(i);
if ((!m.hasValidGroupId() || m.isPrimaryGroupMessage) && !messageIds.contains(m.getId())) {
@ -52,13 +62,32 @@ public class MessagesSearchAdapter extends RecyclerListView.SelectionAdapter {
messageIds.add(m.getId());
}
}
final int oldLoadedCount = loadedCount;
final int oldFlickerCount = flickerCount;
loadedCount = searchResultMessages.size();
super.notifyDataSetChanged();
if (searchType != 0) {
boolean hasMore = !HashtagSearchController.getInstance(currentAccount).isEndReached(searchType);
flickerCount = hasMore && loadedCount != 0 ? Utilities.clamp(HashtagSearchController.getInstance(currentAccount).getCount(searchType) - loadedCount, 3, 0) : 0;
} else {
boolean hasMore = !MediaDataController.getInstance(currentAccount).searchEndReached();
flickerCount = hasMore && loadedCount != 0 ? Utilities.clamp(MediaDataController.getInstance(currentAccount).getSearchCount() - loadedCount, 3, 0) : 0;
}
final int newItemsCount = getItemCount();
if (oldItemsCount < newItemsCount) {
notifyItemRangeChanged(oldItemsCount - oldFlickerCount, oldFlickerCount);
notifyItemRangeInserted(oldItemsCount, newItemsCount - oldItemsCount);
} else {
super.notifyDataSetChanged();
}
}
@Override
public int getItemCount() {
return searchResultMessages.size();
return searchResultMessages.size() + flickerCount;
}
public Object getItem(int i) {
@ -68,11 +97,6 @@ public class MessagesSearchAdapter extends RecyclerListView.SelectionAdapter {
return searchResultMessages.get(i);
}
@Override
public long getItemId(int i) {
return i;
}
@Override
public boolean isEnabled(RecyclerView.ViewHolder holder) {
return holder.getItemViewType() == 0;
@ -86,7 +110,10 @@ public class MessagesSearchAdapter extends RecyclerListView.SelectionAdapter {
view = new DialogCell(null, mContext, false, true, currentAccount, resourcesProvider);
break;
case 1:
view = new LoadingCell(mContext);
FlickerLoadingView flickerLoadingView = new FlickerLoadingView(mContext, resourcesProvider);
flickerLoadingView.setIsSingleCell(true);
flickerLoadingView.setViewType(FlickerLoadingView.DIALOG_CELL_TYPE);
view = flickerLoadingView;
break;
}
view.setLayoutParams(new RecyclerView.LayoutParams(RecyclerView.LayoutParams.MATCH_PARENT, RecyclerView.LayoutParams.WRAP_CONTENT));
@ -98,12 +125,14 @@ public class MessagesSearchAdapter extends RecyclerListView.SelectionAdapter {
if (holder.getItemViewType() == 0) {
DialogCell cell = (DialogCell) holder.itemView;
cell.useSeparator = true;
cell.isSavedDialog = true;
MessageObject messageObject = (MessageObject) getItem(position);
int date;
boolean useMe = false;
long did;
if (messageObject.getDialogId() == UserConfig.getInstance(currentAccount).getClientUserId()) {
boolean useMe = false;
did = messageObject.getDialogId();
date = messageObject.messageOwner.date;
if (isSavedMessages) {
cell.isSavedDialog = true;
did = messageObject.getSavedDialogId();
if (messageObject.messageOwner.fwd_from != null && (messageObject.messageOwner.fwd_from.date != 0 || messageObject.messageOwner.fwd_from.saved_date != 0)) {
date = messageObject.messageOwner.fwd_from.date;
@ -114,8 +143,10 @@ public class MessagesSearchAdapter extends RecyclerListView.SelectionAdapter {
date = messageObject.messageOwner.date;
}
} else {
did = messageObject.getDialogId();
date = messageObject.messageOwner.date;
if (messageObject.isOutOwner()) {
did = messageObject.getFromChatId();
}
useMe = true;
}
cell.setDialog(did, messageObject, date, useMe, false);
}

View file

@ -9,6 +9,7 @@
package org.telegram.ui;
import android.content.Context;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
@ -36,6 +37,7 @@ import org.telegram.ui.Components.RecyclerListView;
import org.telegram.ui.Components.StickersAlert;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
public class ArchivedStickersActivity extends BaseFragment implements NotificationCenter.NotificationCenterDelegate {
@ -47,6 +49,7 @@ public class ArchivedStickersActivity extends BaseFragment implements Notificati
private LinearLayoutManager layoutManager;
private RecyclerListView listView;
private HashSet<Long> loadedSets = new HashSet<>();
private ArrayList<TLRPC.StickerSetCovered> sets = new ArrayList<>();
private boolean firstLoaded;
private boolean endReached;
@ -221,8 +224,14 @@ public class ArchivedStickersActivity extends BaseFragment implements Notificati
private void processResponse(TLRPC.TL_messages_archivedStickers res) {
if (!isInTransition) {
sets.addAll(res.sets);
endReached = res.sets.size() != 15;
int added = 0;
for (TLRPC.StickerSetCovered s : res.sets) {
if (loadedSets.contains(s.set.id)) continue;
loadedSets.add(s.set.id);
sets.add(s);
added++;
}
endReached = added <= 0;
loadingStickers = false;
firstLoaded = true;
if (emptyView != null) {

View file

@ -8,6 +8,7 @@
package org.telegram.ui;
import static org.telegram.messenger.LocaleController.getString;
import static org.telegram.messenger.MessageObject.POSITION_FLAG_BOTTOM;
import static org.telegram.messenger.MessageObject.POSITION_FLAG_LEFT;
import static org.telegram.messenger.MessageObject.POSITION_FLAG_RIGHT;
@ -81,6 +82,7 @@ import android.view.animation.DecelerateInterpolator;
import android.view.inputmethod.EditorInfo;
import android.webkit.CookieManager;
import android.webkit.JavascriptInterface;
import android.webkit.RenderProcessGoneDetail;
import android.webkit.WebChromeClient;
import android.webkit.WebSettings;
import android.webkit.WebView;
@ -138,6 +140,7 @@ import org.telegram.tgnet.TLRPC;
import org.telegram.ui.ActionBar.ActionBar;
import org.telegram.ui.ActionBar.ActionBarMenuItem;
import org.telegram.ui.ActionBar.ActionBarPopupWindow;
import org.telegram.ui.ActionBar.AlertDialog;
import org.telegram.ui.ActionBar.BackDrawable;
import org.telegram.ui.ActionBar.BaseFragment;
import org.telegram.ui.ActionBar.BottomSheet;
@ -1325,7 +1328,7 @@ public class ArticleViewer implements NotificationCenter.NotificationCenterDeleg
deleteView.setGravity(Gravity.CENTER_VERTICAL);
deleteView.setPadding(AndroidUtilities.dp(20), 0, AndroidUtilities.dp(20), 0);
deleteView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 15);
deleteView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf"));
deleteView.setTypeface(AndroidUtilities.bold());
deleteView.setText(LocaleController.getString("Copy", R.string.Copy).toUpperCase());
deleteView.setOnClickListener(v -> {
if (pressedLinkOwnerLayout != null) {
@ -1728,7 +1731,7 @@ public class ArticleViewer implements NotificationCenter.NotificationCenterDeleg
}
};
textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16);
textView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf"));
textView.setTypeface(AndroidUtilities.bold());
textView.setText(LocaleController.getString("InstantViewReference", R.string.InstantViewReference));
textView.setGravity((adapter[0].isRtl ? Gravity.RIGHT : Gravity.LEFT) | Gravity.CENTER_VERTICAL);
textView.setTextColor(getTextColor());
@ -2391,7 +2394,7 @@ public class ArticleViewer implements NotificationCenter.NotificationCenterDeleg
paint.setTypeface(AndroidUtilities.getTypeface("fonts/rmono.ttf"));
} else {
if (parentBlock instanceof TLRPC.TL_pageBlockRelatedArticles) {
paint.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf"));
paint.setTypeface(AndroidUtilities.bold());
} else if (selectedFont == 1 || parentBlock instanceof TLRPC.TL_pageBlockTitle || parentBlock instanceof TLRPC.TL_pageBlockKicker || parentBlock instanceof TLRPC.TL_pageBlockHeader || parentBlock instanceof TLRPC.TL_pageBlockSubtitle || parentBlock instanceof TLRPC.TL_pageBlockSubheader) {
if (parentBlock instanceof TLRPC.TL_pageBlockTitle || parentBlock instanceof TLRPC.TL_pageBlockHeader || parentBlock instanceof TLRPC.TL_pageBlockSubtitle || parentBlock instanceof TLRPC.TL_pageBlockSubheader) {
paint.setTypeface(AndroidUtilities.getTypeface("fonts/mw_bold.ttf"));
@ -2410,7 +2413,7 @@ public class ArticleViewer implements NotificationCenter.NotificationCenterDeleg
if ((flags & TEXT_FLAG_MEDIUM) != 0 && (flags & TEXT_FLAG_ITALIC) != 0) {
paint.setTypeface(AndroidUtilities.getTypeface("fonts/rmediumitalic.ttf"));
} else if ((flags & TEXT_FLAG_MEDIUM) != 0) {
paint.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf"));
paint.setTypeface(AndroidUtilities.bold());
} else if ((flags & TEXT_FLAG_ITALIC) != 0) {
paint.setTypeface(AndroidUtilities.getTypeface("fonts/ritalic.ttf"));
}
@ -2487,10 +2490,10 @@ public class ArticleViewer implements NotificationCenter.NotificationCenterDeleg
} else if (parentBlock instanceof TLRPC.TL_pageBlockChannel) {
if (channelNamePaint == null) {
channelNamePaint = new TextPaint(Paint.ANTI_ALIAS_FLAG);
channelNamePaint.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf"));
channelNamePaint.setTypeface(AndroidUtilities.bold());
channelNamePhotoPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG);
channelNamePhotoPaint.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf"));
channelNamePhotoPaint.setTypeface(AndroidUtilities.bold());
}
channelNamePaint.setColor(getTextColor());
channelNamePaint.setTextSize(AndroidUtilities.dp(15));
@ -2504,7 +2507,7 @@ public class ArticleViewer implements NotificationCenter.NotificationCenterDeleg
if (plainText == pageBlockRelatedArticlesChild.parent.articles.get(pageBlockRelatedArticlesChild.num).title) {
if (relatedArticleHeaderPaint == null) {
relatedArticleHeaderPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG);
relatedArticleHeaderPaint.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf"));
relatedArticleHeaderPaint.setTypeface(AndroidUtilities.bold());
}
relatedArticleHeaderPaint.setColor(getTextColor());
relatedArticleHeaderPaint.setTextSize(AndroidUtilities.dp(15) + additionalSize);
@ -2901,7 +2904,7 @@ public class ArticleViewer implements NotificationCenter.NotificationCenterDeleg
ApplicationLoader.applicationContext.getSharedPreferences("articles", Activity.MODE_PRIVATE).edit().putInt("font_type", selectedFont).commit();
Typeface typefaceNormal = selectedFont == 0 ? Typeface.DEFAULT : Typeface.SERIF;
Typeface typefaceItalic = selectedFont == 0 ? AndroidUtilities.getTypeface("fonts/ritalic.ttf") : Typeface.create("serif", Typeface.ITALIC);
Typeface typefaceBold = selectedFont == 0 ? AndroidUtilities.getTypeface("fonts/rmedium.ttf") : Typeface.create("serif", Typeface.BOLD);
Typeface typefaceBold = selectedFont == 0 ? AndroidUtilities.bold() : Typeface.create("serif", Typeface.BOLD);
Typeface typefaceBoldItalic = selectedFont == 0 ? AndroidUtilities.getTypeface("fonts/rmediumitalic.ttf") : Typeface.create("serif", Typeface.BOLD_ITALIC);
for (int a = 0; a < quoteTextPaints.size(); a++) {
@ -3371,7 +3374,7 @@ public class ArticleViewer implements NotificationCenter.NotificationCenterDeleg
titleTextView = new SimpleTextView(activity);
titleTextView.setGravity(Gravity.CENTER_VERTICAL | Gravity.LEFT);
titleTextView.setTextSize(20);
titleTextView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf"));
titleTextView.setTypeface(AndroidUtilities.bold());
titleTextView.setTextColor(0xffb3b3b3);
titleTextView.setPivotX(0.0f);
titleTextView.setPivotY(AndroidUtilities.dp(28));
@ -3710,7 +3713,7 @@ public class ArticleViewer implements NotificationCenter.NotificationCenterDeleg
searchCountText = new SimpleTextView(parentActivity);
searchCountText.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlackText));
searchCountText.setTextSize(15);
searchCountText.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf"));
searchCountText.setTypeface(AndroidUtilities.bold());
searchCountText.setGravity(Gravity.LEFT);
searchPanel.addView(searchCountText, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.LEFT | Gravity.CENTER_VERTICAL, 18, 0, 108, 0));
@ -6796,7 +6799,7 @@ public class ArticleViewer implements NotificationCenter.NotificationCenterDeleg
stringBuilder = new SpannableStringBuilder(author);
}
if (!TextUtils.isEmpty(author)) {
TypefaceSpan span = new TypefaceSpan(AndroidUtilities.getTypeface("fonts/rmedium.ttf"));
TypefaceSpan span = new TypefaceSpan(AndroidUtilities.bold());
stringBuilder.setSpan(span, 0, author.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
}
CharSequence stringFinal = TextUtils.ellipsize(stringBuilder, Theme.chat_audioTitlePaint, w, TextUtils.TruncateAt.END);
@ -7520,6 +7523,19 @@ public class ArticleViewer implements NotificationCenter.NotificationCenterDeleg
});
webView.setWebViewClient(new WebViewClient() {
@Override
public boolean onRenderProcessGone(WebView view, RenderProcessGoneDetail detail) {
if (LaunchActivity.instance != null && LaunchActivity.instance.isFinishing()) {
return true;
}
new AlertDialog.Builder(getContext(), null)
.setTitle(getString(R.string.ChromeCrashTitle))
.setMessage(AndroidUtilities.replaceSingleTag(getString(R.string.ChromeCrashMessage), () -> Browser.openUrl(getContext(), "https://play.google.com/store/apps/details?id=com.google.android.webview")))
.setPositiveButton(getString(R.string.OK), null)
.show();
return true;
}
@Override
public void onLoadResource(WebView view, String url) {
super.onLoadResource(view, url);
@ -10728,7 +10744,7 @@ public class ArticleViewer implements NotificationCenter.NotificationCenterDeleg
textView = new TextView(context);
textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14);
textView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf"));
textView.setTypeface(AndroidUtilities.bold());
textView.setText(LocaleController.getString("ChannelJoin", R.string.ChannelJoin));
textView.setGravity(Gravity.CENTER_VERTICAL | Gravity.LEFT);
addView(textView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, 39, Gravity.RIGHT | Gravity.TOP));
@ -11691,7 +11707,7 @@ public class ArticleViewer implements NotificationCenter.NotificationCenterDeleg
object.parentView = listView[0];
object.imageReceiver = imageReceiver;
object.thumb = imageReceiver.getBitmapSafe();
object.radius = imageReceiver.getRoundRadius();
object.radius = imageReceiver.getRoundRadius(true);
object.clipTopAddition = currentHeaderHeight;
return object;
}

View file

@ -1,50 +1,63 @@
package org.telegram.ui;
import static org.telegram.messenger.AndroidUtilities.dp;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ValueAnimator;
import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.text.TextUtils;
import android.view.HapticFeedbackConstants;
import android.view.Gravity;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowInsets;
import android.view.WindowManager;
import android.view.animation.AccelerateDecelerateInterpolator;
import android.view.animation.AnimationUtils;
import android.view.animation.Interpolator;
import android.view.animation.OvershootInterpolator;
import android.widget.FrameLayout;
import androidx.annotation.NonNull;
import androidx.core.content.ContextCompat;
import androidx.core.math.MathUtils;
import androidx.core.util.Consumer;
import androidx.core.util.Preconditions;
import org.telegram.messenger.AndroidUtilities;
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.MessagesController;
import org.telegram.messenger.NotificationCenter;
import org.telegram.messenger.R;
import org.telegram.messenger.UserConfig;
import org.telegram.tgnet.TLRPC;
import org.telegram.ui.ActionBar.BottomSheet;
import org.telegram.ui.ActionBar.ActionBarMenuItem;
import org.telegram.ui.ActionBar.ActionBarMenuSubItem;
import org.telegram.ui.ActionBar.ActionBarPopupWindow;
import org.telegram.ui.ActionBar.Theme;
import org.telegram.ui.Components.AnimatedFileDrawable;
import org.telegram.ui.Components.BackupImageView;
import org.telegram.ui.Components.CubicBezierInterpolator;
import org.telegram.ui.Components.LayoutHelper;
import org.telegram.ui.Components.MediaActionDrawable;
import org.telegram.ui.Components.RadialProgress2;
import org.telegram.ui.Stories.RoundRectOutlineProvider;
import java.util.Collections;
import java.util.Objects;
public class AvatarPreviewer {
@SuppressLint("StaticFieldLeak")
private static AvatarPreviewer INSTANCE;
public static AvatarPreviewer getInstance() {
@ -63,28 +76,35 @@ public class AvatarPreviewer {
}
private ViewGroup view;
private Context context;
private WindowManager windowManager;
private Callback callback;
private Layout layout;
private boolean visible;
public void show(ViewGroup parentContainer, Data data, Callback callback) {
Preconditions.checkNotNull(parentContainer);
Preconditions.checkNotNull(data);
Preconditions.checkNotNull(callback);
public void show(ViewGroup parentContainer, Theme.ResourcesProvider resourcesProvider, Data data, Callback callback) {
Objects.requireNonNull(parentContainer);
Objects.requireNonNull(data);
Objects.requireNonNull(callback);
final Context context = parentContainer.getContext();
if (this.view != parentContainer) {
close();
this.view = parentContainer;
this.context = context;
this.windowManager = ContextCompat.getSystemService(context, WindowManager.class);
this.layout = new Layout(context, callback) {
this.layout = new Layout(context, resourcesProvider, callback) {
@Override
protected void onHide() {
close();
protected void onHideFinish() {
if (visible) {
visible = false;
if (layout.getParent() != null) {
windowManager.removeView(layout);
}
layout.recycle();
layout = null;
view.requestDisallowInterceptTouchEvent(false);
view = null;
windowManager = null;
}
}
};
}
@ -97,12 +117,11 @@ public class AvatarPreviewer {
}
final WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT,
WindowManager.LayoutParams.LAST_APPLICATION_WINDOW,
WindowManager.LayoutParams.TYPE_APPLICATION_PANEL,
0, PixelFormat.TRANSLUCENT
);
if (Build.VERSION.SDK_INT >= 21) {
layoutParams.flags = WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS |
WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR |
layoutParams.flags = WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR |
WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN |
WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
}
@ -114,17 +133,7 @@ public class AvatarPreviewer {
public void close() {
if (visible) {
visible = false;
if (layout.getParent() != null) {
windowManager.removeView(layout);
}
layout.recycle();
layout = null;
view.requestDisallowInterceptTouchEvent(false);
view = null;
context = null;
windowManager = null;
callback = null;
this.layout.setShowing(false);
}
}
@ -142,12 +151,13 @@ public class AvatarPreviewer {
void onMenuClick(MenuItem item);
}
public static enum MenuItem {
public enum MenuItem {
OPEN_PROFILE("OpenProfile", R.string.OpenProfile, R.drawable.msg_openprofile),
OPEN_CHANNEL("OpenChannel2", R.string.OpenChannel2, R.drawable.msg_channel),
OPEN_GROUP("OpenGroup2", R.string.OpenGroup2, R.drawable.msg_discussion),
SEND_MESSAGE("SendMessage", R.string.SendMessage, R.drawable.msg_discussion),
MENTION("Mention", R.string.Mention, R.drawable.msg_mention);
MENTION("Mention", R.string.Mention, R.drawable.msg_mention),
SEARCH_MESSAGES("AvatarPreviewSearchMessages", R.string.AvatarPreviewSearchMessages, R.drawable.msg_search);
private final String labelKey;
private final int labelResId;
@ -166,17 +176,22 @@ public class AvatarPreviewer {
final ImageLocation imageLocation = ImageLocation.getForUserOrChat(user, ImageLocation.TYPE_BIG);
final ImageLocation thumbImageLocation = ImageLocation.getForUserOrChat(user, ImageLocation.TYPE_SMALL);
final String thumbFilter = thumbImageLocation != null && thumbImageLocation.photoSize instanceof TLRPC.TL_photoStrippedSize ? "b" : null;
return new Data(imageLocation, thumbImageLocation, null, null, thumbFilter, null, null, user, menuItems, new UserInfoLoadTask(user, classGuid));
final BitmapDrawable thumb = user != null && user.photo != null ? user.photo.strippedBitmap : null;
return new Data(imageLocation, thumbImageLocation, null, null, thumbFilter, null, null, thumb, user, menuItems, new UserInfoLoadTask(user, classGuid));
}
public static Data of(TLRPC.UserFull userFull, MenuItem... menuItems) {
final ImageLocation imageLocation = ImageLocation.getForUserOrChat(userFull.user, ImageLocation.TYPE_BIG);
public static Data of(TLRPC.User user, TLRPC.UserFull userFull, MenuItem... menuItems) {
ImageLocation imageLocation = ImageLocation.getForUserOrChat(userFull.user, ImageLocation.TYPE_BIG);
if (imageLocation == null && userFull.profile_photo != null) {
imageLocation = ImageLocation.getForPhoto(FileLoader.getClosestPhotoSizeWithSize(userFull.profile_photo.sizes, 500), userFull.profile_photo);
}
final ImageLocation thumbImageLocation = ImageLocation.getForUserOrChat(userFull.user, ImageLocation.TYPE_SMALL);
final String thumbFilter = thumbImageLocation != null && thumbImageLocation.photoSize instanceof TLRPC.TL_photoStrippedSize ? "b" : null;
final ImageLocation videoLocation;
final String videoFileName;
final BitmapDrawable thumb = user != null && user.photo != null ? user.photo.strippedBitmap : null;
if (userFull.profile_photo != null && !userFull.profile_photo.video_sizes.isEmpty()) {
final TLRPC.VideoSize videoSize = userFull.profile_photo.video_sizes.get(0);
final TLRPC.VideoSize videoSize = FileLoader.getClosestVideoSizeWithSize(userFull.profile_photo.video_sizes, 1000);
videoLocation = ImageLocation.getForPhoto(videoSize, userFull.profile_photo);
videoFileName = FileLoader.getAttachFileName(videoSize);
} else {
@ -184,14 +199,15 @@ public class AvatarPreviewer {
videoFileName = null;
}
final String videoFilter = videoLocation != null && videoLocation.imageType == FileLoader.IMAGE_TYPE_ANIMATION ? ImageLoader.AUTOPLAY_FILTER : null;
return new Data(imageLocation, thumbImageLocation, videoLocation, null, thumbFilter, videoFilter, videoFileName, userFull.user, menuItems, null);
return new Data(imageLocation, thumbImageLocation, videoLocation, null, thumbFilter, videoFilter, videoFileName, thumb, userFull.user, menuItems, null);
}
public static Data of(TLRPC.Chat chat, int classGuid, MenuItem... menuItems) {
final ImageLocation imageLocation = ImageLocation.getForUserOrChat(chat, ImageLocation.TYPE_BIG);
final ImageLocation thumbImageLocation = ImageLocation.getForUserOrChat(chat, ImageLocation.TYPE_SMALL);
final String thumbFilter = thumbImageLocation != null && thumbImageLocation.photoSize instanceof TLRPC.TL_photoStrippedSize ? "b" : null;
return new Data(imageLocation, thumbImageLocation, null, null, thumbFilter, null, null, chat, menuItems, new ChatInfoLoadTask(chat, classGuid));
final BitmapDrawable thumb = chat != null && chat.photo != null ? chat.photo.strippedBitmap : null;
return new Data(imageLocation, thumbImageLocation, null, null, thumbFilter, null, null, thumb, chat, menuItems, new ChatInfoLoadTask(chat, classGuid));
}
public static Data of(TLRPC.Chat chat, TLRPC.ChatFull chatFull, MenuItem... menuItems) {
@ -200,8 +216,9 @@ public class AvatarPreviewer {
final String thumbFilter = thumbImageLocation != null && thumbImageLocation.photoSize instanceof TLRPC.TL_photoStrippedSize ? "b" : null;
final ImageLocation videoLocation;
final String videoFileName;
final BitmapDrawable thumb = chat != null && chat.photo != null ? chat.photo.strippedBitmap : null;
if (chatFull.chat_photo != null && !chatFull.chat_photo.video_sizes.isEmpty()) {
final TLRPC.VideoSize videoSize = chatFull.chat_photo.video_sizes.get(0);
final TLRPC.VideoSize videoSize = FileLoader.getClosestVideoSizeWithSize(chatFull.chat_photo.video_sizes, 1000);
videoLocation = ImageLocation.getForPhoto(videoSize, chatFull.chat_photo);
videoFileName = FileLoader.getAttachFileName(videoSize);
} else {
@ -209,7 +226,7 @@ public class AvatarPreviewer {
videoFileName = null;
}
final String videoFilter = videoLocation != null && videoLocation.imageType == FileLoader.IMAGE_TYPE_ANIMATION ? ImageLoader.AUTOPLAY_FILTER : null;
return new Data(imageLocation, thumbImageLocation, videoLocation, null, thumbFilter, videoFilter, videoFileName, chat, menuItems, null);
return new Data(imageLocation, thumbImageLocation, videoLocation, null, thumbFilter, videoFilter, videoFileName, thumb, chat, menuItems, null);
}
private final ImageLocation imageLocation;
@ -219,11 +236,12 @@ public class AvatarPreviewer {
private final String thumbImageFilter;
private final String videoFilter;
private final String videoFileName;
private final BitmapDrawable thumb;
private final Object parentObject;
private final MenuItem[] menuItems;
private final InfoLoadTask<?, ?> infoLoadTask;
private Data(ImageLocation imageLocation, ImageLocation thumbImageLocation, ImageLocation videoLocation, String imageFilter, String thumbImageFilter, String videoFilter, String videoFileName, Object parentObject, MenuItem[] menuItems, InfoLoadTask<?, ?> infoLoadTask) {
private Data(ImageLocation imageLocation, ImageLocation thumbImageLocation, ImageLocation videoLocation, String imageFilter, String thumbImageFilter, String videoFilter, String videoFileName, BitmapDrawable thumb, Object parentObject, MenuItem[] menuItems, InfoLoadTask<?, ?> infoLoadTask) {
this.imageLocation = imageLocation;
this.thumbImageLocation = thumbImageLocation;
this.videoLocation = videoLocation;
@ -231,6 +249,7 @@ public class AvatarPreviewer {
this.thumbImageFilter = thumbImageFilter;
this.videoFilter = videoFilter;
this.videoFileName = videoFileName;
this.thumb = thumb;
this.parentObject = parentObject;
this.menuItems = menuItems;
this.infoLoadTask = infoLoadTask;
@ -334,56 +353,81 @@ public class AvatarPreviewer {
private static abstract class Layout extends FrameLayout implements NotificationCenter.NotificationCenterDelegate {
private static final float ANIM_DURATION = 150f;
private final int radialProgressSize = AndroidUtilities.dp(64f);
private final int[] coords = new int[2];
private final Rect rect = new Rect();
private final Interpolator interpolator = new AccelerateDecelerateInterpolator();
private final ColorDrawable backgroundDrawable = new ColorDrawable(0x71000000);
private final ImageReceiver imageReceiver = new ImageReceiver();
private final RadialProgress2 radialProgress;
private final Drawable arrowDrawable;
private final Interpolator openInterpolator = new OvershootInterpolator(1.02f);
private final FrameLayout container;
private final AvatarView avatarView;
private final ActionBarPopupWindow.ActionBarPopupWindowLayout menu;
private final Callback callback;
private final Theme.ResourcesProvider resourcesProvider;
private float progress;
private AnimatorSet openAnimator;
private boolean showing;
private long lastUpdateTime;
private MenuItem[] menuItems;
private WindowInsets insets;
private BottomSheet visibleSheet;
private ValueAnimator moveAnimator;
private float moveProgress; // [-1; 0]
private float downY = -1;
private View blurView;
private boolean preparingBlur;
private String videoFileName;
private InfoLoadTask<?, ?> infoLoadTask;
private ValueAnimator progressHideAnimator;
private ValueAnimator progressShowAnimator;
private boolean showProgress;
private boolean recycled;
public Layout(@NonNull Context context, Callback callback) {
public Layout(@NonNull Context context, Theme.ResourcesProvider resourcesProvider, Callback callback) {
super(context);
this.callback = callback;
this.resourcesProvider = resourcesProvider;
setWillNotDraw(false);
setFitsSystemWindows(true);
imageReceiver.setAspectFit(true);
imageReceiver.setInvalidateAll(true);
imageReceiver.setRoundRadius(AndroidUtilities.dp(6));
imageReceiver.setParentView(this);
radialProgress = new RadialProgress2(this);
radialProgress.setOverrideAlpha(0.0f);
radialProgress.setIcon(MediaActionDrawable.ICON_EMPTY, false, false);
radialProgress.setColors(0x42000000, 0x42000000, Color.WHITE, Color.WHITE);
arrowDrawable = ContextCompat.getDrawable(context, R.drawable.preview_arrow);
blurView = new View(context);
blurView.setOnClickListener(v -> setShowing(false));
addView(blurView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT));
container = new FrameLayout(context) {
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.getSize(heightMeasureSpec));
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
int width = right - left - getPaddingLeft() - getPaddingRight();
int height = bottom - top - getPaddingTop() - getPaddingBottom();
int maxAvatarSize = Math.min(width, height) - dp(16);
int minAvatarSize = Math.min(dp(60), maxAvatarSize);
int maxMenuHeight = height - minAvatarSize - dp(16 + 24);
menu.measure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.AT_MOST), MeasureSpec.makeMeasureSpec(maxMenuHeight, MeasureSpec.AT_MOST));
int avatarSize = MathUtils.clamp(height - menu.getMeasuredHeight() - dp(16 + 24), minAvatarSize, maxAvatarSize);
avatarView.measure(MeasureSpec.makeMeasureSpec(avatarSize, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(avatarSize, MeasureSpec.EXACTLY));
int verticalOffset = (height - avatarSize - menu.getMeasuredHeight() - dp(16 + 24)) / 2;
FrameLayout.LayoutParams avatarLayoutParams = (LayoutParams) avatarView.getLayoutParams();
FrameLayout.LayoutParams menuLayoutParams = (LayoutParams) menu.getLayoutParams();
avatarLayoutParams.topMargin = verticalOffset + dp(8);
menuLayoutParams.topMargin = verticalOffset + dp(8) + avatarSize;
super.onLayout(changed, left, top, right, bottom);
}
};
container.setFitsSystemWindows(true);
addView(container, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT));
avatarView = new AvatarView(context, resourcesProvider);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
avatarView.setElevation(dp(4));
avatarView.setClipToOutline(true);
}
container.addView(avatarView, LayoutHelper.createFrame(0, 0, Gravity.CENTER_HORIZONTAL));
menu = new ActionBarPopupWindow.ActionBarPopupWindowLayout(context, R.drawable.popup_fixed_alert, resourcesProvider, 0);
container.addView(menu, LayoutHelper.createFrameRelatively(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.START));
}
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
imageReceiver.onAttachedToWindow();
NotificationCenter.getInstance(UserConfig.selectedAccount).addObserver(this, NotificationCenter.fileLoaded);
NotificationCenter.getInstance(UserConfig.selectedAccount).addObserver(this, NotificationCenter.fileLoadProgressChanged);
}
@ -391,186 +435,241 @@ public class AvatarPreviewer {
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
imageReceiver.onDetachedFromWindow();
NotificationCenter.getInstance(UserConfig.selectedAccount).removeObserver(this, NotificationCenter.fileLoaded);
NotificationCenter.getInstance(UserConfig.selectedAccount).removeObserver(this, NotificationCenter.fileLoadProgressChanged);
}
@Override
public void didReceivedNotification(int id, int account, Object... args) {
if (!showProgress || TextUtils.isEmpty(videoFileName)) {
if (!avatarView.getShowProgress() || TextUtils.isEmpty(videoFileName)) {
return;
}
if (id == NotificationCenter.fileLoaded) {
final String fileName = (String) args[0];
if (TextUtils.equals(fileName, videoFileName)) {
radialProgress.setProgress(1f, true);
avatarView.setProgress(1f);
}
} else if (id == NotificationCenter.fileLoadProgressChanged) {
String fileName = (String) args[0];
if (TextUtils.equals(fileName, videoFileName)) {
if (radialProgress != null) {
Long loadedSize = (Long) args[1];
Long totalSize = (Long) args[2];
float progress = Math.min(1f, loadedSize / (float) totalSize);
radialProgress.setProgress(progress, true);
}
avatarView.setProgress(progress);
}
}
}
@Override
public boolean onTouchEvent(MotionEvent event) {
if (!showing) {
return false;
}
if (moveAnimator == null) {
if (event.getActionMasked() == MotionEvent.ACTION_UP) {
downY = -1;
setShowing(false);
} else if (event.getActionMasked() == MotionEvent.ACTION_MOVE) {
if (downY < 0) {
downY = event.getY();
} else {
moveProgress = Math.max(-1, Math.min(0f, (event.getY() - downY) / AndroidUtilities.dp(56)));
if (moveProgress == -1) {
performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
moveAnimator = ValueAnimator.ofFloat(moveProgress, 0);
moveAnimator.setDuration(200);
moveAnimator.addUpdateListener(a -> {
moveProgress = (float) a.getAnimatedValue();
invalidate();
});
moveAnimator.start();
showBottomSheet();
}
invalidate();
}
public boolean dispatchKeyEvent(KeyEvent event) {
if (event.getKeyCode() == KeyEvent.KEYCODE_BACK || event.getKeyCode() == KeyEvent.KEYCODE_ESCAPE) {
if (getKeyDispatcherState() == null) {
return super.dispatchKeyEvent(event);
}
}
return true;
}
private void showBottomSheet() {
final CharSequence[] labels = new CharSequence[menuItems.length];
final int[] icons = new int[menuItems.length];
for (int i = 0; i < menuItems.length; i++) {
labels[i] = LocaleController.getString(menuItems[i].labelKey, menuItems[i].labelResId);
icons[i] = menuItems[i].iconResId;
}
visibleSheet = new BottomSheet.Builder(getContext())
.setItems(labels, icons, (dialog, which) -> {
callback.onMenuClick(menuItems[which]);
if (event.getAction() == KeyEvent.ACTION_DOWN && event.getRepeatCount() == 0) {
final KeyEvent.DispatcherState state = getKeyDispatcherState();
if (state != null) {
state.startTracking(event, this);
}
return true;
} else if (event.getAction() == KeyEvent.ACTION_UP) {
final KeyEvent.DispatcherState state = getKeyDispatcherState();
if (state != null && state.isTracking(event) && !event.isCanceled()) {
setShowing(false);
})
.setDimBehind(false);
visibleSheet.setOnDismissListener(dialog -> {
visibleSheet = null;
setShowing(false);
});
visibleSheet.show();
}
@Override
public WindowInsets onApplyWindowInsets(WindowInsets insets) {
this.insets = insets;
invalidateSize();
return insets.consumeStableInsets();
return true;
}
}
return super.dispatchKeyEvent(event);
} else {
return super.dispatchKeyEvent(event);
}
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
invalidateSize();
if (w != 0 && h != 0 && showing) {
blurView.setBackground(null);
AndroidUtilities.runOnUIThread(this::prepareBlurBitmap);
}
}
public void invalidateSize() {
final int width = getWidth();
final int height = getHeight();
private void prepareBlurBitmap() {
if (preparingBlur) {
return;
}
preparingBlur = true;
AndroidUtilities.makeGlobalBlurBitmap(bitmap -> {
//noinspection deprecation
blurView.setBackground(new BitmapDrawable(bitmap));
preparingBlur = false;
}, 6f, 7, this, Collections.singletonList(this));
}
if (width == 0 || height == 0) {
public void setData(Data data) {
menuItems = data.menuItems;
avatarView.setShowProgress(data.videoLocation != null);
videoFileName = data.videoFileName;
recycleInfoLoadTask();
if (data.infoLoadTask != null) {
infoLoadTask = data.infoLoadTask;
infoLoadTask.load(result -> {
if (!recycled) {
if (result instanceof TLRPC.UserFull) {
setData(Data.of((TLRPC.User) data.infoLoadTask.argument, (TLRPC.UserFull) result, data.menuItems));
} else if (result instanceof TLRPC.ChatFull) {
setData(Data.of((TLRPC.Chat) data.infoLoadTask.argument, (TLRPC.ChatFull) result, data.menuItems));
}
}
});
}
avatarView.setImage(UserConfig.selectedAccount, data.videoLocation, data.videoFilter, data.imageLocation, data.imageFilter, data.thumbImageLocation, data.thumbImageFilter, data.thumb, data.parentObject);
menu.removeInnerViews();
for (int i = 0; i < menuItems.length; i++) {
final MenuItem menuItem = menuItems[i];
CharSequence label = LocaleController.getString(menuItem.labelKey, menuItem.labelResId);
ActionBarMenuSubItem item = ActionBarMenuItem.addItem(i == 0, i == menuItems.length - 1, menu, menuItem.iconResId, label, false, resourcesProvider);
item.setTag(i);
item.setOnClickListener(v -> {
setShowing(false);
callback.onMenuClick(menuItem);
});
}
setShowing(true);
}
private void setShowing(boolean showing) {
if (this.showing == showing) {
return;
}
backgroundDrawable.setBounds(0, 0, width, height);
this.showing = showing;
final int padding = AndroidUtilities.dp(8);
ValueAnimator foregroundAnimator = ValueAnimator.ofFloat(0f, 1f);
foregroundAnimator.setInterpolator(showing ? openInterpolator : CubicBezierInterpolator.EASE_OUT_QUINT);
foregroundAnimator.addUpdateListener(animation -> {
float value = (float) animation.getAnimatedValue();
if (!showing) {
value = 1f - value;
}
float clampedValue = MathUtils.clamp(value, 0f, 1f);
int lPadding = padding, rPadding = padding, vPadding = padding;
container.setScaleX(0.7f + 0.3f * value);
container.setScaleY(0.7f + 0.3f * value);
container.setAlpha(clampedValue);
avatarView.setTranslationY(dp(40) * (1f - value));
menu.setTranslationY(-dp(40 + 30) * (1f - value));
menu.setScaleX(0.95f + 0.05f * value);
menu.setScaleY(0.95f + 0.05f * value);
});
if (Build.VERSION.SDK_INT >= 21) {
lPadding += insets.getStableInsetLeft();
rPadding += insets.getStableInsetRight();
vPadding += Math.max(insets.getStableInsetTop(), insets.getStableInsetBottom());
ValueAnimator blurAnimator = ValueAnimator.ofFloat(0f, 1f);
blurAnimator.addUpdateListener(animation -> {
float value = (float) animation.getAnimatedValue();
if (!showing) {
value = 1f - value;
}
blurView.setAlpha(value); // Linear value
invalidate();
});
if (openAnimator != null) {
openAnimator.cancel();
}
openAnimator = new AnimatorSet();
openAnimator.setDuration(showing ? 190 : 150);
openAnimator.playTogether(foregroundAnimator, blurAnimator);
openAnimator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
if (!showing) {
setVisibility(INVISIBLE);
onHideFinish();
}
}
});
openAnimator.start();
}
public void recycle() {
recycled = true;
recycleInfoLoadTask();
}
private void recycleInfoLoadTask() {
if (infoLoadTask != null) {
infoLoadTask.cancel();
infoLoadTask = null;
}
}
protected abstract void onHideFinish();
}
private static class AvatarView extends FrameLayout {
private BackupImageView backupImageView;
private final RadialProgress2 radialProgress;
private boolean showProgress;
private ValueAnimator progressHideAnimator;
private ValueAnimator progressShowAnimator;
private final int radialProgressSize = dp(64f);
public AvatarView(Context context, Theme.ResourcesProvider resourcesProvider) {
super(context);
setWillNotDraw(false);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
setOutlineProvider(new RoundRectOutlineProvider(6));
}
final int arrowWidth = arrowDrawable.getIntrinsicWidth();
final int arrowHeight = arrowDrawable.getIntrinsicHeight();
final int arrowPadding = AndroidUtilities.dp(24);
backupImageView = new BackupImageView(context);
backupImageView.setAspectFit(true);
backupImageView.setRoundRadius(dp(6));
addView(backupImageView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT));
final int w = width - (lPadding + rPadding);
final int h = height - vPadding * 2;
radialProgress = new RadialProgress2(this, resourcesProvider);
radialProgress.setOverrideAlpha(0.0f);
radialProgress.setIcon(MediaActionDrawable.ICON_EMPTY, false, false);
radialProgress.setColors(0x42000000, 0x42000000, Color.WHITE, Color.WHITE);
}
final int size = Math.min(w, h);
final int vOffset = arrowPadding + arrowHeight / 2;
final int x = (w - size) / 2 + lPadding;
final int y = (h - size) / 2 + vPadding + (w > h ? vOffset : 0);
imageReceiver.setImageCoords(x, y, size, size - (w > h ? vOffset : 0));
public void setImage(int currentAccount, ImageLocation mediaLocation, String mediaFilter, ImageLocation imageLocation, String imageFilter, ImageLocation thumbLocation, String thumbFilter, BitmapDrawable thumb, Object parentObject) {
backupImageView.getImageReceiver().setCurrentAccount(currentAccount);
backupImageView.getImageReceiver().setImage(mediaLocation, mediaFilter, imageLocation, imageFilter, thumbLocation, thumbFilter, thumb, 0, null, parentObject, 1);
backupImageView.onNewImageSet();
}
final int cx = (int) imageReceiver.getCenterX();
final int cy = (int) imageReceiver.getCenterY();
radialProgress.setProgressRect(cx - radialProgressSize / 2, cy - radialProgressSize / 2, cx + radialProgressSize / 2, cy + radialProgressSize / 2);
public void setProgress(float progress) {
radialProgress.setProgress(progress, true);
}
final int arrowX = x + size / 2;
final int arrowY = y - arrowPadding;
arrowDrawable.setBounds(arrowX - arrowWidth / 2, arrowY - arrowHeight / 2, arrowX + arrowWidth / 2, arrowY + arrowHeight / 2);
public boolean getShowProgress() {
return showProgress;
}
public void setShowProgress(boolean showProgress) {
this.showProgress = showProgress;
invalidate();
}
@Override
protected void onDraw(Canvas canvas) {
long newTime = AnimationUtils.currentAnimationTimeMillis();
long dt = newTime - lastUpdateTime;
lastUpdateTime = newTime;
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
int cx = getWidth() / 2;
int cy = getHeight() / 2;
radialProgress.setProgressRect(cx - radialProgressSize, cy - radialProgressSize, cx + radialProgressSize, cy + radialProgressSize);
}
if (showing && progress < 1f) {
progress += dt / ANIM_DURATION;
if (progress < 1f) {
postInvalidateOnAnimation();
} else {
progress = 1f;
}
} else if (!showing && progress > 0f) {
progress -= dt / ANIM_DURATION;
if (progress > 0f) {
postInvalidateOnAnimation();
} else {
progress = 0f;
onHide();
}
}
final float interpolatedProgress = interpolator.getInterpolation(progress);
backgroundDrawable.setAlpha((int) (180 * interpolatedProgress));
backgroundDrawable.draw(canvas);
if (interpolatedProgress < 1.0f) {
canvas.scale(AndroidUtilities.lerp(0.95f, 1.0f, interpolatedProgress), AndroidUtilities.lerp(0.95f, 1.0f, interpolatedProgress), imageReceiver.getCenterX(), imageReceiver.getCenterY());
}
final int statusBarHeight = Build.VERSION.SDK_INT >= 21 ? AndroidUtilities.statusBarHeight : 0;
final int navBarHeight = Build.VERSION.SDK_INT >= 21 ? insets.getStableInsetBottom() : 0;
final int sheetHeight = menuItems.length * AndroidUtilities.dp(48) + AndroidUtilities.dp(16);
final float maxBottom = getHeight() - (navBarHeight + sheetHeight + AndroidUtilities.dp(16));
final float translationY = Math.min(0, maxBottom - imageReceiver.getImageY2());
if (imageReceiver.getImageY() + translationY < statusBarHeight) {
canvas.translate(0, moveProgress * AndroidUtilities.dp(16));
} else {
canvas.translate(0, translationY + moveProgress * AndroidUtilities.dp(16));
}
imageReceiver.setAlpha(interpolatedProgress);
imageReceiver.draw(canvas);
@Override
protected void dispatchDraw(Canvas canvas) {
super.dispatchDraw(canvas);
if (showProgress) {
final Drawable drawable = imageReceiver.getDrawable();
final Drawable drawable = backupImageView.getImageReceiver().getDrawable();
if (drawable instanceof AnimatedFileDrawable && ((AnimatedFileDrawable) drawable).getDurationMs() > 0) {
if (progressShowAnimator != null) {
progressShowAnimator.cancel();
@ -606,64 +705,6 @@ public class AvatarPreviewer {
radialProgress.draw(canvas);
}
}
if (moveAnimator != null) {
arrowDrawable.setAlpha((int) ((1f - moveAnimator.getAnimatedFraction()) * 255));
} else {
arrowDrawable.setAlpha((int) (255 * interpolatedProgress));
}
arrowDrawable.draw(canvas);
}
public void setData(Data data) {
menuItems = data.menuItems;
showProgress = data.videoLocation != null;
videoFileName = data.videoFileName;
recycleInfoLoadTask();
if (data.infoLoadTask != null) {
infoLoadTask = data.infoLoadTask;
infoLoadTask.load(result -> {
if (!recycled) {
if (result instanceof TLRPC.UserFull) {
setData(Data.of((TLRPC.UserFull) result, data.menuItems));
} else if (result instanceof TLRPC.ChatFull) {
setData(Data.of((TLRPC.Chat) data.infoLoadTask.argument, (TLRPC.ChatFull) result, data.menuItems));
}
}
});
}
imageReceiver.setCurrentAccount(UserConfig.selectedAccount);
imageReceiver.setImage(data.videoLocation, data.videoFilter, data.imageLocation, data.imageFilter, data.thumbImageLocation, data.thumbImageFilter, null, 0, null, data.parentObject, 1);
setShowing(true);
}
private void setShowing(boolean showing) {
if (this.showing != showing) {
this.showing = showing;
lastUpdateTime = AnimationUtils.currentAnimationTimeMillis();
invalidate();
}
}
public void recycle() {
recycled = true;
if (moveAnimator != null) {
moveAnimator.cancel();
}
if (visibleSheet != null) {
visibleSheet.cancel();
}
recycleInfoLoadTask();
}
private void recycleInfoLoadTask() {
if (infoLoadTask != null) {
infoLoadTask.cancel();
infoLoadTask = null;
}
}
protected abstract void onHide();
}
}

View file

@ -53,6 +53,7 @@ import org.telegram.ui.Charts.view_data.ChartHeaderView;
import org.telegram.ui.Components.Bulletin;
import org.telegram.ui.Components.CircularProgressDrawable;
import org.telegram.ui.Components.CombinedDrawable;
import org.telegram.ui.Components.FillLastLinearLayoutManager;
import org.telegram.ui.Components.LayoutHelper;
import org.telegram.ui.Components.LinkActionView;
import org.telegram.ui.Components.ListView.AdapterWithDiffUtils;
@ -133,8 +134,11 @@ public class BoostsActivity extends GradientHeaderActivity implements Notificati
view = new View(getContext()) {
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int h = Math.max(0, layoutManager.getLastItemHeight()) ;
super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(h, MeasureSpec.EXACTLY));
int lastItemHeight = 0;
if (layoutManager instanceof FillLastLinearLayoutManager) {
lastItemHeight = ((FillLastLinearLayoutManager) layoutManager).getLastItemHeight();
}
super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(Math.max(0, lastItemHeight), MeasureSpec.EXACTLY));
}
};
view.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundGray));
@ -765,7 +769,7 @@ public class BoostsActivity extends GradientHeaderActivity implements Notificati
imageView = new ImageView(context);
textView = new TextView(context);
textView.setTextColor(Color.WHITE);
textView.setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM));
textView.setTypeface(AndroidUtilities.bold());
textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 12);
addView(imageView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_HORIZONTAL));
addView(textView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_HORIZONTAL, 0, 25, 0, 0));

View file

@ -16,7 +16,6 @@ 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.browser.Browser;
import org.telegram.tgnet.ConnectionsManager;
@ -68,7 +67,7 @@ public class BusinessBotButton extends FrameLayout {
titleView = new AnimatedTextView(context);
titleView.adaptWidth = false;
titleView.getDrawable().setHacks(true, true, false);
titleView.setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM));
titleView.setTypeface(AndroidUtilities.bold());
titleView.setTextSize(dp(14));
titleView.setText(UserObject.getUserName(user));
titleView.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlackText, resourcesProvider));
@ -90,7 +89,7 @@ public class BusinessBotButton extends FrameLayout {
pauseButton.getDrawable().setHacks(true, true, true);
pauseButton.setAnimationProperties(.75f, 0, 350, CubicBezierInterpolator.EASE_OUT_QUINT);
pauseButton.setScaleProperty(.6f);
pauseButton.setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM));
pauseButton.setTypeface(AndroidUtilities.bold());
pauseButton.setBackgroundDrawable(Theme.createSimpleSelectorRoundRectDrawable(dp(14), Theme.getColor(Theme.key_featuredStickers_addButton, resourcesProvider), Theme.blendOver(Theme.getColor(Theme.key_featuredStickers_addButton, resourcesProvider), Theme.multAlpha(Color.WHITE, .12f))));
pauseButton.setTextSize(dp(14));
pauseButton.setGravity(Gravity.RIGHT);

View file

@ -543,7 +543,7 @@ public class BusinessIntroActivity extends UniversalFragment implements Notifica
};
chatAttachAlert.setDelegate(new ChatAttachAlert.ChatAttachViewDelegate() {
@Override
public void didPressedButton(int button, boolean arg, boolean notify, int scheduleDate, boolean forceDocument) {
public void didPressedButton(int button, boolean arg, boolean notify, int scheduleDate, long effectId, boolean invertMedia, boolean forceDocument) {
}
@Override

View file

@ -116,7 +116,7 @@ public class BusinessLinksController {
}
}
if (!usersToLoad.isEmpty()) {
storage.getUsersInternal(TextUtils.join(",", usersToLoad), users);
storage.getUsersInternal(usersToLoad, users);
}
if (!chatsToLoad.isEmpty()) {
storage.getChatsInternal(TextUtils.join(",", chatsToLoad), chats);

View file

@ -107,7 +107,7 @@ public class ChatAttachAlertQuickRepliesLayout extends ChatAttachAlert.AttachAle
};
NotificationCenter.listenEmojiLoading(nameTextView);
nameTextView.setTextColor(getThemedColor(Theme.key_dialogTextBlack));
nameTextView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf"));
nameTextView.setTypeface(AndroidUtilities.bold());
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));
@ -446,7 +446,7 @@ public class ChatAttachAlertQuickRepliesLayout extends ChatAttachAlert.AttachAle
}
@Override
public void sendSelectedItems(boolean notify, int scheduleDate) {
public void sendSelectedItems(boolean notify, int scheduleDate, long effectId, boolean invertMedia) {
}

View file

@ -18,7 +18,6 @@ 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;
@ -69,7 +68,6 @@ 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;
@ -136,7 +134,7 @@ public class QuickRepliesActivity extends BaseFragment implements NotificationCe
ActionBarMenu actionModeMenu = actionBar.createActionMode();
countText = new NumberTextView(getContext());
countText.setTextSize(18);
countText.setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM));
countText.setTypeface(AndroidUtilities.bold());
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);
@ -528,7 +526,7 @@ public class QuickRepliesActivity extends BaseFragment implements NotificationCe
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));
text = new Text(formatPluralString("BusinessRepliesMore", count), 9.33f, AndroidUtilities.bold());
}
public static CharSequence of(int count, int[] width) {
SpannableString ss = new SpannableString("+");
@ -623,7 +621,7 @@ public class QuickRepliesActivity extends BaseFragment implements NotificationCe
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 TypefaceSpan(AndroidUtilities.bold()), 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);
@ -737,7 +735,7 @@ public class QuickRepliesActivity extends BaseFragment implements NotificationCe
titleView.setSingleLine();
titleView.setEllipsize(TextUtils.TruncateAt.END);
titleView.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlackText, resourcesProvider));
titleView.setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM));
titleView.setTypeface(AndroidUtilities.bold());
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));

View file

@ -173,7 +173,7 @@ public class QuickRepliesController {
storage.getChatsInternal(TextUtils.join(",", chatsToLoad), chats);
}
if (!usersToLoad.isEmpty()) {
storage.getUsersInternal(TextUtils.join(",", usersToLoad), users);
storage.getUsersInternal(usersToLoad, users);
}
} catch (Exception e) {
@ -531,7 +531,7 @@ public class QuickRepliesController {
storage.getChatsInternal(TextUtils.join(",", chatsToLoad), chats);
}
if (!usersToLoad.isEmpty()) {
storage.getUsersInternal(TextUtils.join(",", usersToLoad), users);
storage.getUsersInternal(usersToLoad, users);
}
final MessageObject finalMessageObject = messageObject;
AndroidUtilities.runOnUIThread(() -> {

View file

@ -52,7 +52,7 @@ public class QuickRepliesEmptyView extends LinearLayout {
titleView = new TextView(context);
titleView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14);
titleView.setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM));
titleView.setTypeface(AndroidUtilities.bold());
titleView.setTextAlignment(TEXT_ALIGNMENT_CENTER);
titleView.setGravity(Gravity.CENTER);

View file

@ -113,7 +113,6 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.Locale;
import java.util.Objects;
public class CacheControlActivity extends BaseFragment implements NotificationCenter.NotificationCenterDelegate {
@ -519,7 +518,7 @@ public class CacheControlActivity extends BaseFragment implements NotificationCe
ArrayList<TLRPC.Chat> chats = new ArrayList<>();
if (!unknownUsers.isEmpty()) {
try {
getMessagesStorage().getUsersInternal(TextUtils.join(",", unknownUsers), users);
getMessagesStorage().getUsersInternal(unknownUsers, users);
} catch (Exception e) {
FileLog.e(e);
}
@ -683,7 +682,7 @@ public class CacheControlActivity extends BaseFragment implements NotificationCe
String percentString = percent <= 0 ? String.format("<%.1f%%", 1f) : String.format("%d%%", percent);
SpannableString percentStr = new SpannableString(percentString);
percentStr.setSpan(new RelativeSizeSpan(.834f), 0, percentStr.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
percentStr.setSpan(new TypefaceSpan(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)), 0, percentStr.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
percentStr.setSpan(new TypefaceSpan(AndroidUtilities.bold()), 0, percentStr.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
SpannableStringBuilder string = new SpannableStringBuilder(header);
string.append(" ");
string.append(percentStr);
@ -1268,7 +1267,7 @@ public class CacheControlActivity extends BaseFragment implements NotificationCe
actionModeTitle = new AnimatedTextView(context, true, true, true);
actionModeTitle.setAnimationProperties(.35f, 0, 350, CubicBezierInterpolator.EASE_OUT_QUINT);
actionModeTitle.setTextSize(AndroidUtilities.dp(18));
actionModeTitle.setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM));
actionModeTitle.setTypeface(AndroidUtilities.bold());
actionModeTitle.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlackText));
actionModeLayout.addView(actionModeTitle, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 18, Gravity.LEFT | Gravity.CENTER_VERTICAL, 0, -11, 18, 0));
@ -1283,7 +1282,7 @@ public class CacheControlActivity extends BaseFragment implements NotificationCe
actionModeClearButton.setPadding(AndroidUtilities.dp(14), 0, AndroidUtilities.dp(14), 0);
actionModeClearButton.setTextColor(Theme.getColor(Theme.key_featuredStickers_buttonText));
actionModeClearButton.setBackground(Theme.AdaptiveRipple.filledRectByKey(Theme.key_featuredStickers_addButton, 6));
actionModeClearButton.setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM));
actionModeClearButton.setTypeface(AndroidUtilities.bold());
actionModeClearButton.setGravity(Gravity.CENTER);
actionModeClearButton.setText(LocaleController.getString("CacheClear", R.string.CacheClear));
actionModeClearButton.setOnClickListener(e -> clearSelectedFiles());
@ -1717,7 +1716,7 @@ public class CacheControlActivity extends BaseFragment implements NotificationCe
title = new AnimatedTextView(context);
title.setAnimationProperties(.35f, 0, 350, CubicBezierInterpolator.EASE_OUT_QUINT);
title.setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM));
title.setTypeface(AndroidUtilities.bold());
title.setTextSize(AndroidUtilities.dp(20));
title.setText(LocaleController.getString("StorageUsage", R.string.StorageUsage));
title.setGravity(Gravity.CENTER);
@ -1941,7 +1940,7 @@ public class CacheControlActivity extends BaseFragment implements NotificationCe
percentsTextView.setGravity(Gravity.CENTER_HORIZONTAL);
percentsTextView.setTextColor(Theme.getColor(Theme.key_dialogTextBlack));
percentsTextView.setTextSize(AndroidUtilities.dp(24));
percentsTextView.setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM));
percentsTextView.setTypeface(AndroidUtilities.bold());
addView(percentsTextView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 32, Gravity.CENTER_HORIZONTAL | Gravity.TOP, 0, 16 + 150 + 16 - 6, 0, 0));
progressView = new ProgressView(context);
@ -1951,7 +1950,7 @@ public class CacheControlActivity extends BaseFragment implements NotificationCe
title.setGravity(Gravity.CENTER_HORIZONTAL);
title.setTextColor(Theme.getColor(Theme.key_dialogTextBlack));
title.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16);
title.setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM));
title.setTypeface(AndroidUtilities.bold());
title.setText(LocaleController.getString("ClearingCache", R.string.ClearingCache));
addView(title, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_HORIZONTAL | Gravity.TOP, 0, 16 + 150 + 16 + 28 + 16 + 5 + 30, 0, 0));
@ -2171,7 +2170,7 @@ public class CacheControlActivity extends BaseFragment implements NotificationCe
rtlTextView.setText(LocaleController.getString("ClearCache", R.string.ClearCache));
rtlTextView.setGravity(Gravity.CENTER);
rtlTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14);
rtlTextView.setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM));
rtlTextView.setTypeface(AndroidUtilities.bold());
rtlTextView.setTextColor(Theme.getColor(Theme.key_featuredStickers_buttonText));
button.addView(rtlTextView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.MATCH_PARENT, Gravity.CENTER));
}
@ -2182,14 +2181,14 @@ public class CacheControlActivity extends BaseFragment implements NotificationCe
textView.setTextSize(AndroidUtilities.dp(14));
textView.setText(LocaleController.getString("ClearCache", R.string.ClearCache));
textView.setGravity(Gravity.RIGHT);
textView.setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM));
textView.setTypeface(AndroidUtilities.bold());
textView.setTextColor(Theme.getColor(Theme.key_featuredStickers_buttonText));
valueTextView = new AnimatedTextView.AnimatedTextDrawable(true, true, true);
valueTextView.setAnimationProperties(.25f, 0, 300, CubicBezierInterpolator.EASE_OUT_QUINT);
valueTextView.setCallback(button);
valueTextView.setTextSize(AndroidUtilities.dp(14));
valueTextView.setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM));
valueTextView.setTypeface(AndroidUtilities.bold());
valueTextView.setTextColor(Theme.blendOver(Theme.getColor(Theme.key_featuredStickers_addButton), Theme.multAlpha(Theme.getColor(Theme.key_featuredStickers_buttonText), .7f)));
valueTextView.setText("");

View file

@ -285,7 +285,7 @@ public class CachedMediaLayout extends FrameLayout implements NestedSizeNotifier
selectedMessagesCountTextView = new AnimatedTextView(context, true, true, true);
selectedMessagesCountTextView.setTextSize(AndroidUtilities.dp(18));
selectedMessagesCountTextView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf"));
selectedMessagesCountTextView.setTypeface(AndroidUtilities.bold());
selectedMessagesCountTextView.setTextColor(Theme.getColor(Theme.key_actionBarActionModeDefaultIcon));
actionModeLayout.addView(selectedMessagesCountTextView, LayoutHelper.createLinear(0, LayoutHelper.MATCH_PARENT, 1.0f, 18, 0, 0, 0));
actionModeViews.add(selectedMessagesCountTextView);

View file

@ -0,0 +1,184 @@
package org.telegram.ui;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.graphics.RenderNode;
import android.graphics.Typeface;
import android.os.Build;
import android.text.Spanned;
import android.text.StaticLayout;
import android.text.TextPaint;
import android.util.Log;
import androidx.core.graphics.ColorUtils;
import org.telegram.messenger.Emoji;
import org.telegram.ui.ActionBar.Theme;
public class CachedStaticLayout {
public final StaticLayout layout;
private boolean disabled;
public CachedStaticLayout(StaticLayout source) {
this.layout = source;
}
public CachedStaticLayout disableCache() {
disabled = true;
return this;
}
private RenderNode renderNode;
public void draw(Canvas canvas) {
if (!disabled && canvas.isHardwareAccelerated() && Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R && canvas.quickReject(0, 0, layout.getWidth(), layout.getHeight())) {
return;
}
if (hasChanges() || renderNode == null || !renderNode.hasDisplayList()) {
if (renderNode == null) {
renderNode = new RenderNode("CachedStaticLayout");
renderNode.setClipToBounds(false);
}
renderNode.setPosition(getLayoutBounds());
Canvas cacheCanvas = renderNode.beginRecording();
int color = layout.getPaint().getColor();
layout.getPaint().setColor(ColorUtils.setAlphaComponent(color, 0xFF));
layout.draw(cacheCanvas);
layout.getPaint().setColor(color);
renderNode.endRecording();
}
renderNode.setAlpha(layout.getPaint().getAlpha() / 255.0f);
canvas.drawRenderNode(renderNode);
return;
}
layout.draw(canvas);
}
private int textColor;
private int linkColor;
private Typeface typeface;
private float textSize;
private final Rect lastLayoutBounds = new Rect();
private boolean[] lastEmojiLoaded;
private boolean[] tempEmojiLoaded;
private boolean[] getEmojiLoaded() {
if (!(getText() instanceof Spanned)) {
return null;
}
Emoji.EmojiSpan[] spans = ((Spanned) getText()).getSpans(0, getText().length(), Emoji.EmojiSpan.class);
if (spans == null || spans.length <= 0)
return null;
if (tempEmojiLoaded == null || tempEmojiLoaded.length != spans.length) {
tempEmojiLoaded = new boolean[spans.length];
}
for (int i = 0; i < spans.length; ++i) {
tempEmojiLoaded[i] = spans[i].getDrawable() instanceof Emoji.EmojiDrawable && ((Emoji.EmojiDrawable) spans[i].getDrawable()).isLoaded();
}
return tempEmojiLoaded;
}
private boolean emojiLoadedEquals(boolean[] a, boolean[] b) {
if (a == null && b == null) {
return true;
}
if ((a == null ? 0 : a.length) != (b == null ? 0 : b.length)) {
return false;
}
int n = a == null ? 0 : a.length;
for (int i = 0; i < n; ++i) {
if (a[i] != b[i]) return false;
}
return true;
}
private boolean hasChanges() {
boolean a = false, b = false, c = false, d = false, e = false, f = false;
boolean[] emojiLoaded = null;
if (
(a = (ColorUtils.setAlphaComponent(textColor, 0xFF) != ColorUtils.setAlphaComponent(layout.getPaint().getColor(), 0xFF))) ||
(b = (ColorUtils.setAlphaComponent(linkColor, 0xFF) != ColorUtils.setAlphaComponent(layout.getPaint().linkColor, 0xFF))) ||
(c = (Math.abs(textSize - layout.getPaint().getTextSize()) > 0.1f)) ||
(d = (typeface != layout.getPaint().getTypeface())) ||
(e = (!lastLayoutBounds.equals(getLayoutBounds()))) ||
(f = (!emojiLoadedEquals(emojiLoaded = getEmojiLoaded(), lastEmojiLoaded)))
) {
// Log.i("lolkek", "draw \"" + getText() + "\" because " + (renderNode == null ? "first" : a ? "textcolor ["+Integer.toHexString(textColor) + " => "+Integer.toHexString(layout.getPaint().getColor())+"]" : (b ? "linkcolor" : (c ? "textsize" : (d ? "typeface" : (e ? "bounds" : (f ? "emojis" : "???")))))));
textColor = layout.getPaint().getColor();
linkColor = layout.getPaint().linkColor;
textSize = layout.getPaint().getTextSize();
typeface = layout.getPaint().getTypeface();
lastLayoutBounds.set(getLayoutBounds());
if (emojiLoaded != null) {
lastEmojiLoaded = emojiLoaded.clone();
}
return true;
}
return false;
}
private final Rect bounds = new Rect();
private Rect getLayoutBounds() {
bounds.set(0, 0, layout.getWidth(), layout.getHeight());
return bounds;
}
public CharSequence getText() {
return layout.getText();
}
public TextPaint getPaint() {
return layout.getPaint();
}
public int getWidth() {
return layout.getWidth();
}
public int getHeight() {
return layout.getHeight();
}
public int getLineCount() {
return layout.getLineCount();
}
public int getLineTop(int line) {
return layout.getLineTop(line);
}
public int getLineBottom(int line) {
return layout.getLineBottom(line);
}
public float getLineLeft(int line) {
return layout.getLineLeft(line);
}
public float getLineRight(int line) {
return layout.getLineRight(line);
}
public float getLineWidth(int line) {
return layout.getLineWidth(line);
}
public float getPrimaryHorizontal(int x) {
return layout.getPrimaryHorizontal(x);
}
public int getLineEnd(int line) {
return layout.getLineEnd(line);
}
public int getLineStart(int line) {
return layout.getLineStart(line);
}
}

Some files were not shown because too many files have changed in this diff Show more