Update to 5.10.0

This commit is contained in:
DrKLO 2019-08-22 01:53:26 +02:00
parent 9f48ec7ea2
commit 53e04b55fb
252 changed files with 11412 additions and 5153 deletions

View file

@ -242,7 +242,7 @@ android {
}
}
defaultConfig.versionCode = 1648
defaultConfig.versionCode = 1684
applicationVariants.all { variant ->
variant.outputs.all { output ->
@ -276,7 +276,7 @@ android {
defaultConfig {
minSdkVersion 16
targetSdkVersion 27
versionName "5.9.0"
versionName "5.10.0"
vectorDrawables.generatedDensities = ['mdpi', 'hdpi', 'xhdpi', 'xxhdpi']

View file

@ -16,6 +16,7 @@
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.CALL_PHONE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.READ_CALL_LOG" />
<permission android:name="org.telegram.messenger.permission.MAPS_RECEIVE" android:protectionLevel="signature"/>

View file

@ -16,6 +16,7 @@
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.CALL_PHONE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.READ_CALL_LOG" />
<permission android:name="org.telegram.messenger.permission.MAPS_RECEIVE" android:protectionLevel="signature"/>

View file

@ -101,7 +101,7 @@ LOCAL_PATH := $(MY_LOCAL_PATH) # restore local path after include
include $(CLEAR_VARS)
LOCAL_CPPFLAGS := -Wall -std=c++11 -DANDROID -frtti -DHAVE_PTHREAD -finline-functions -ffast-math -Os
LOCAL_CPPFLAGS := -Wall -std=c++14 -DANDROID -frtti -DHAVE_PTHREAD -finline-functions -ffast-math -Os
LOCAL_C_INCLUDES += ./jni/boringssl/include/
LOCAL_ARM_MODE := arm
@ -351,7 +351,7 @@ LOCAL_MODULE := tmessages.30
LOCAL_CFLAGS := -w -std=c11 -Os -DNULL=0 -DSOCKLEN_T=socklen_t -DLOCALE_NOT_USED -D_LARGEFILE_SOURCE=1
LOCAL_CFLAGS += -Drestrict='' -D__EMX__ -DOPUS_BUILD -DFIXED_POINT -DUSE_ALLOCA -DHAVE_LRINT -DHAVE_LRINTF -fno-math-errno
LOCAL_CFLAGS += -DANDROID_NDK -DDISABLE_IMPORTGL -fno-strict-aliasing -fprefetch-loop-arrays -DAVOID_TABLES -DANDROID_TILE_BASED_DECODE -DANDROID_ARMV6_IDCT -ffast-math -D__STDC_CONSTANT_MACROS
LOCAL_CPPFLAGS := -DBSD=1 -ffast-math -Os -funroll-loops -std=c++11
LOCAL_CPPFLAGS := -DBSD=1 -ffast-math -Os -funroll-loops -std=c++14
LOCAL_LDLIBS := -ljnigraphics -llog -lz -lEGL -lGLESv2 -landroid
LOCAL_STATIC_LIBRARIES := webp sqlite lz4 rlottie tgnet swscale avformat avcodec avresample avutil voip flac

View file

@ -215,10 +215,10 @@ void setPushConnectionEnabled(JNIEnv *env, jclass c, jint instanceNum, jboolean
ConnectionsManager::getInstance(instanceNum).setPushConnectionEnabled(value);
}
void applyDnsConfig(JNIEnv *env, jclass c, jint instanceNum, jlong address, jstring phone) {
void applyDnsConfig(JNIEnv *env, jclass c, jint instanceNum, jlong address, jstring phone, jint date) {
const char *phoneStr = env->GetStringUTFChars(phone, 0);
ConnectionsManager::getInstance(instanceNum).applyDnsConfig((NativeByteBuffer *) (intptr_t) address, phoneStr);
ConnectionsManager::getInstance(instanceNum).applyDnsConfig((NativeByteBuffer *) (intptr_t) address, phoneStr, date);
if (phoneStr != 0) {
env->ReleaseStringUTFChars(phone, phoneStr);
}
@ -436,7 +436,7 @@ static JNINativeMethod ConnectionsManagerMethods[] = {
{"native_setNetworkAvailable", "(IZIZ)V", (void *) setNetworkAvailable},
{"native_setPushConnectionEnabled", "(IZ)V", (void *) setPushConnectionEnabled},
{"native_setJava", "(Z)V", (void *) setJava},
{"native_applyDnsConfig", "(IJLjava/lang/String;)V", (void *) applyDnsConfig},
{"native_applyDnsConfig", "(IJLjava/lang/String;I)V", (void *) applyDnsConfig},
{"native_checkProxy", "(ILjava/lang/String;ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;Lorg/telegram/tgnet/RequestTimeDelegate;)J", (void *) checkProxy},
{"native_onHostNameResolved", "(Ljava/lang/String;JLjava/lang/String;)V", (void *) onHostNameResolved}
};

View file

@ -338,7 +338,7 @@ void Java_org_telegram_ui_Components_AnimatedFileDrawable_getVideoInfo(JNIEnv *e
}
}
jlong Java_org_telegram_ui_Components_AnimatedFileDrawable_createDecoder(JNIEnv *env, jclass clazz, jstring src, jintArray data, jint account, jlong streamFileSize, jobject stream) {
jlong Java_org_telegram_ui_Components_AnimatedFileDrawable_createDecoder(JNIEnv *env, jclass clazz, jstring src, jintArray data, jint account, jlong streamFileSize, jobject stream, jboolean preview) {
VideoInfo *info = new VideoInfo();
char const *srcString = env->GetStringUTFChars(src, 0);
@ -377,6 +377,9 @@ jlong Java_org_telegram_ui_Components_AnimatedFileDrawable_createDecoder(JNIEnv
return 0;
}
info->fmt_ctx->flags |= AVFMT_FLAG_FAST_SEEK;
if (preview) {
info->fmt_ctx->flags |= AVFMT_FLAG_NOBUFFER;
}
} else {
if ((ret = avformat_open_input(&info->fmt_ctx, info->src, NULL, NULL)) < 0) {
LOGE("can't open source file %s, %s", info->src, av_err2str(ret));
@ -478,7 +481,7 @@ void Java_org_telegram_ui_Components_AnimatedFileDrawable_prepareToSeek(JNIEnv *
info->seeking = true;
}
void Java_org_telegram_ui_Components_AnimatedFileDrawable_seekToMs(JNIEnv *env, jclass clazz, jlong ptr, jlong ms) {
void Java_org_telegram_ui_Components_AnimatedFileDrawable_seekToMs(JNIEnv *env, jclass clazz, jlong ptr, jlong ms, jboolean precise) {
if (ptr == NULL) {
return;
}
@ -491,6 +494,9 @@ void Java_org_telegram_ui_Components_AnimatedFileDrawable_seekToMs(JNIEnv *env,
return;
} else {
avcodec_flush_buffers(info->video_dec_ctx);
if (!precise) {
return;
}
int got_frame = 0;
int32_t tries = 1000;
while (tries > 0) {
@ -544,7 +550,7 @@ void Java_org_telegram_ui_Components_AnimatedFileDrawable_seekToMs(JNIEnv *env,
}
}
jint Java_org_telegram_ui_Components_AnimatedFileDrawable_getVideoFrame(JNIEnv *env, jclass clazz, jlong ptr, jobject bitmap, jintArray data, jint stride) {
jint Java_org_telegram_ui_Components_AnimatedFileDrawable_getVideoFrame(JNIEnv *env, jclass clazz, jlong ptr, jobject bitmap, jintArray data, jint stride, jboolean preview) {
if (ptr == NULL || bitmap == nullptr) {
return 0;
}
@ -552,7 +558,8 @@ jint Java_org_telegram_ui_Components_AnimatedFileDrawable_getVideoFrame(JNIEnv *
VideoInfo *info = (VideoInfo *) (intptr_t) ptr;
int ret = 0;
int got_frame = 0;
int32_t triesCount = 6;
int32_t triesCount = preview ? 50 : 6;
//info->has_decoded_frames = false;
while (!info->stopped && triesCount != 0) {
if (info->pkt.size == 0) {
ret = av_read_frame(info->fmt_ctx, &info->pkt);
@ -586,7 +593,7 @@ jint Java_org_telegram_ui_Components_AnimatedFileDrawable_getVideoFrame(JNIEnv *
LOGE("can't decode packet flushed %s", info->src);
return 0;
}
if (got_frame == 0) {
if (!preview && got_frame == 0) {
if (info->has_decoded_frames) {
if ((ret = av_seek_frame(info->fmt_ctx, info->video_stream_idx, 0, AVSEEK_FLAG_BACKWARD | AVSEEK_FLAG_FRAME)) < 0) {
LOGE("can't seek to begin of file %s, %s", info->src, av_err2str(ret));

View file

@ -5,6 +5,7 @@
#include <lz4.h>
#include <unistd.h>
#include <pthread.h>
#include <map>
#include <tgnet/ConnectionsManager.h>
#include <tgnet/FileLog.h>
#include "c_utils.h"
@ -35,12 +36,24 @@ typedef struct LottieInfo {
bool nextFrameIsCacheFrame = false;
};
jlong Java_org_telegram_ui_Components_RLottieDrawable_create(JNIEnv *env, jclass clazz, jstring src, jintArray data, jboolean precache) {
jlong Java_org_telegram_ui_Components_RLottieDrawable_create(JNIEnv *env, jclass clazz, jstring src, jintArray data, jboolean precache, jintArray colorReplacement) {
LottieInfo *info = new LottieInfo();
std::map<int32_t, int32_t> colors;
if (colorReplacement != nullptr) {
jint *arr = env->GetIntArrayElements(colorReplacement, 0);
if (arr != nullptr) {
jsize len = env->GetArrayLength(colorReplacement);
for (int32_t a = 0; a < len / 2; a++) {
colors[arr[a * 2]] = arr[a * 2 + 1];
}
env->ReleaseIntArrayElements(colorReplacement, arr, 0);
}
}
char const *srcString = env->GetStringUTFChars(src, 0);
info->path = srcString;
info->animation = rlottie::Animation::loadFromFile(info->path);
info->animation = rlottie::Animation::loadFromFile(info->path, colors);
if (srcString != 0) {
env->ReleaseStringUTFChars(src, srcString);
}

View file

@ -22,6 +22,7 @@
#include <future>
#include <vector>
#include <memory>
#include <map>
#ifdef _WIN32
#ifdef LOT_BUILD
@ -257,7 +258,7 @@ public:
* @internal
*/
static std::unique_ptr<Animation>
loadFromFile(const std::string &path);
loadFromFile(const std::string &path, std::map<int32_t, int32_t> &colorReplacement);
/**
* @brief Constructs an animation object from JSON string data.

View file

@ -136,7 +136,7 @@ std::unique_ptr<Animation> Animation::loadFromData(
return nullptr;
}
std::unique_ptr<Animation> Animation::loadFromFile(const std::string &path)
std::unique_ptr<Animation> Animation::loadFromFile(const std::string &path, std::map<int32_t, int32_t> &colorReplacement)
{
if (path.empty()) {
vWarning << "File path is empty";
@ -144,7 +144,7 @@ std::unique_ptr<Animation> Animation::loadFromFile(const std::string &path)
}
LottieLoader loader;
if (loader.load(path)) {
if (loader.load(path, colorReplacement)) {
auto animation = std::unique_ptr<Animation>(new Animation);
animation->d->init(loader.model());
return animation;

View file

@ -75,7 +75,7 @@ static std::string dirname(const std::string &path)
return std::string(path, 0, len);
}
bool LottieLoader::load(const std::string &path)
bool LottieLoader::load(const std::string &path, std::map<int32_t, int32_t> &colorReplacement)
{
mModel = LottieFileCache::instance().find(path);
if (mModel) return true;
@ -90,7 +90,7 @@ bool LottieLoader::load(const std::string &path)
std::stringstream buf;
buf << f.rdbuf();
LottieParser parser(const_cast<char *>(buf.str().data()), dirname(path).c_str());
LottieParser parser(const_cast<char *>(buf.str().data()), dirname(path).c_str(), colorReplacement);
if (parser.hasParsingError()) {
f.close();
return false;
@ -110,8 +110,8 @@ bool LottieLoader::loadFromData(std::string &&jsonData, const std::string &key,
mModel = LottieFileCache::instance().find(key);
if (mModel) return true;
LottieParser parser(const_cast<char *>(jsonData.c_str()),
resourcePath.c_str());
std::map<int32_t, int32_t> colors;
LottieParser parser(const_cast<char *>(jsonData.c_str()), resourcePath.c_str(), colors);
mModel = parser.model();
LottieFileCache::instance().add(key, mModel);

View file

@ -19,14 +19,15 @@
#ifndef LOTTIELOADER_H
#define LOTTIELOADER_H
#include<sstream>
#include<memory>
#include <sstream>
#include <memory>
#include <map>
class LOTModel;
class LottieLoader
{
public:
bool load(const std::string &filePath);
bool load(const std::string &filePath, std::map<int32_t, int32_t> &colorReplacement);
bool loadFromData(std::string &&jsonData, const std::string &key, const std::string &resourcePath);
std::shared_ptr<LOTModel> model();
private:

View file

@ -210,7 +210,7 @@ void LOTGradient::populate(VGradientStops &stops, int frameNo)
int j = 0;
for (int i = 0; i < colorPoints; i++) {
float colorStop = ptr[0];
LottieColor color = LottieColor(ptr[1], ptr[2], ptr[3]);
LottieColor color = LottieColor(ptr[3], ptr[2], ptr[1]);
if (opacityArraySize) {
if (j == opacityArraySize) {
// already reached the end

View file

@ -55,6 +55,7 @@
#include <array>
#include <sstream>
#include <tgnet/FileLog.h>
#include "lottiemodel.h"
#include "rapidjson/document.h"
@ -181,8 +182,8 @@ protected:
class LottieParserImpl : protected LookaheadParserHandler {
public:
LottieParserImpl(char *str, const char *dir_path)
: LookaheadParserHandler(str), mDirPath(dir_path)
LottieParserImpl(char *str, const char *dir_path, std::map<int32_t, int32_t> &colorReplacement)
: LookaheadParserHandler(str), mDirPath(dir_path), colorMap(colorReplacement)
{
}
@ -286,6 +287,8 @@ protected:
std::vector<std::shared_ptr<LOTLayerData>> mLayersToUpdate;
std::string mDirPath;
std::vector<LayerInfo> mLayerInfoList;
std::map<int32_t, int32_t> colorMap;
void SkipOut(int depth);
bool parsingError{false};
};
@ -840,17 +843,31 @@ LottieColor LottieParserImpl::toColor(const char *str)
}
char tmp[3] = {'\0', '\0', '\0'};
tmp[0] = str[1];
tmp[1] = str[2];
color.b = std::strtol(tmp, NULL, 16) / 255.0;
long b = std::strtol(tmp, NULL, 16);
tmp[0] = str[3];
tmp[1] = str[4];
color.g = std::strtol(tmp, NULL, 16) / 255.0;
long g = std::strtol(tmp, NULL, 16);
tmp[0] = str[5];
tmp[1] = str[6];
color.r = std::strtol(tmp, NULL, 16) / 255.0;
long r = std::strtol(tmp, NULL, 16);
if (!colorMap.empty()) {
int32_t c = (int32_t) (((b & 0xff) << 16) | ((g & 0xff) << 8) | (r & 0xff));
std::map<int32_t, int32_t>::iterator iter = colorMap.find(c);
if (iter != colorMap.end()) {
c = iter->second;
b = (c >> 16) & 0xff;
g = (c >> 8) & 0xff;
r = (c) & 0xff;
}
}
color.r = r / 255.0f;
color.g = g / 255.0f;
color.b = b / 255.0f;
return color;
}
@ -1095,6 +1112,10 @@ std::shared_ptr<LOTMaskData> LottieParserImpl::parseMaskObject()
obj->mInv = GetBool();
} else if (0 == strcmp(key, "mode")) {
const char *str = GetString();
if (str == nullptr) {
parsingError = true;
return sharedMask;
}
switch (str[0]) {
case 'n':
obj->mMode = LOTMaskData::Mode::None;
@ -1260,7 +1281,9 @@ std::shared_ptr<LOTData> LottieParserImpl::parseGroupObject() {
staticFlag &= child.get()->isStatic();
}
group->setStatic(staticFlag && group->mTransform->isStatic());
if (group->mTransform) {
group->setStatic(staticFlag && group->mTransform->isStatic());
}
return sharedGroup;
}
@ -2005,6 +2028,20 @@ void LottieParserImpl::getValue(LottieColor &color)
parsingError = true;
return;
}
if (!colorMap.empty()) {
int32_t r = (int32_t) (val[2] * 255);
int32_t g = (int32_t) (val[1] * 255);
int32_t b = (int32_t) (val[0] * 255);
int32_t c = (int32_t) (((b & 0xff) << 16) | ((g & 0xff) << 8) | (r & 0xff));
std::map<int32_t, int32_t>::iterator iter = colorMap.find(c);
if (iter != colorMap.end()) {
c = iter->second;
val[0] = ((c >> 16) & 0xff) / 255.0f;
val[1] = ((c >> 8) & 0xff) / 255.0f;
val[2] = ((c) & 0xff) / 255.0f;
}
}
color.r = val[2];
color.g = val[1];
color.b = val[0];
@ -2590,8 +2627,8 @@ LottieParser::~LottieParser()
delete d;
}
LottieParser::LottieParser(char *str, const char *dir_path)
: d(new LottieParserImpl(str, dir_path))
LottieParser::LottieParser(char *str, const char *dir_path, std::map<int32_t, int32_t> &colorReplacement)
: d(new LottieParserImpl(str, dir_path, colorReplacement))
{
d->parseComposition();
if (d->hasParsingError()) {

View file

@ -20,12 +20,13 @@
#define LOTTIEPARSER_H
#include "lottiemodel.h"
#include <map>
class LottieParserImpl;
class LottieParser {
public:
~LottieParser();
LottieParser(char* str, const char *dir_path);
LottieParser(char* str, const char *dir_path, std::map<int32_t, int32_t> &colorReplacement);
std::shared_ptr<LOTModel> model();
bool hasParsingError();
private:

View file

@ -209,6 +209,9 @@ VPath VDasher::dashed(const VPath &path)
}
}
}
if (mResult.points().size() > SHRT_MAX) {
mResult.reset();
}
return std::move(mResult);
}

View file

@ -19,6 +19,7 @@
#include "vraster.h"
#include <cstring>
#include <memory>
#include <tgnet/FileLog.h>
#include "config.h"
#include "v_ft_raster.h"
#include "v_ft_stroker.h"
@ -102,6 +103,9 @@ void FTOutline::convert(const VPath &path)
{
const std::vector<VPath::Element> &elements = path.elements();
const std::vector<VPointF> & points = path.points();
if (points.size() > SHRT_MAX) {
return;
}
grow(points.size(), path.segments());

View file

@ -443,17 +443,537 @@ void TL_user::serializeToStream(NativeByteBuffer *stream) {
}
}
TL_auth_authorization *TL_auth_authorization::TLdeserialize(NativeByteBuffer *stream, uint32_t constructor, int32_t instanceNum, bool &error) {
if (TL_auth_authorization::constructor != constructor) {
error = true;
if (LOGS_ENABLED) DEBUG_E("can't parse magic %x in TL_auth_authorization", constructor);
return nullptr;
InputPeer *InputPeer::TLdeserialize(NativeByteBuffer *stream, uint32_t constructor, int32_t instanceNum, bool &error) {
InputPeer *result = nullptr;
switch (constructor) {
case 0x7da07ec9:
result = new TL_inputPeerSelf();
break;
case 0x7b8e7de6:
result = new TL_inputPeerUser();
break;
case 0x179be863:
result = new TL_inputPeerChat();
break;
case 0x17bae2e6:
result = new TL_inputPeerUserFromMessage();
break;
case 0x9c95f7bb:
result = new TL_inputPeerChannelFromMessage();
break;
case 0x20adaef8:
result = new TL_inputPeerChannel();
break;
case 0x7f3b18ea:
result = new TL_inputPeerEmpty();
break;
default:
error = true;
if (LOGS_ENABLED) DEBUG_E("can't parse magic %x in InputPeer", constructor);
return nullptr;
}
TL_auth_authorization *result = new TL_auth_authorization();
result->readParams(stream, instanceNum, error);
return result;
}
void TL_inputPeerSelf::serializeToStream(NativeByteBuffer *stream) {
stream->writeInt32(constructor);
}
void TL_inputPeerUser::readParams(NativeByteBuffer *stream, int32_t instanceNum, bool &error) {
user_id = stream->readInt32(&error);
access_hash = stream->readInt64(&error);
}
void TL_inputPeerUser::serializeToStream(NativeByteBuffer *stream) {
stream->writeInt32(constructor);
stream->writeInt32(user_id);
stream->writeInt64(access_hash);
}
void TL_inputPeerChat::readParams(NativeByteBuffer *stream, int32_t instanceNum, bool &error) {
chat_id = stream->readInt32(&error);
}
void TL_inputPeerChat::serializeToStream(NativeByteBuffer *stream) {
stream->writeInt32(constructor);
stream->writeInt32(chat_id);
}
void TL_inputPeerUserFromMessage::readParams(NativeByteBuffer *stream, int32_t instanceNum, bool &error) {
peer = std::unique_ptr<InputPeer>(InputPeer::TLdeserialize(stream, stream->readUint32(&error), instanceNum, error));
msg_id = stream->readInt32(&error);
user_id = stream->readInt32(&error);
}
void TL_inputPeerUserFromMessage::serializeToStream(NativeByteBuffer *stream) {
stream->writeInt32(constructor);
peer->serializeToStream(stream);
stream->writeInt32(msg_id);
stream->writeInt32(user_id);
}
void TL_inputPeerChannelFromMessage::readParams(NativeByteBuffer *stream, int32_t instanceNum, bool &error) {
peer = std::unique_ptr<InputPeer>(InputPeer::TLdeserialize(stream, stream->readUint32(&error), instanceNum, error));
msg_id = stream->readInt32(&error);
channel_id = stream->readInt32(&error);
}
void TL_inputPeerChannelFromMessage::serializeToStream(NativeByteBuffer *stream) {
stream->writeInt32(constructor);
peer->serializeToStream(stream);
stream->writeInt32(msg_id);
stream->writeInt32(channel_id);
}
void TL_inputPeerChannel::readParams(NativeByteBuffer *stream, int32_t instanceNum, bool &error) {
channel_id = stream->readInt32(&error);
access_hash = stream->readInt64(&error);
}
void TL_inputPeerChannel::serializeToStream(NativeByteBuffer *stream) {
stream->writeInt32(constructor);
stream->writeInt32(channel_id);
stream->writeInt64(access_hash);
}
void TL_inputPeerEmpty::serializeToStream(NativeByteBuffer *stream) {
stream->writeInt32(constructor);
}
InputUser *InputUser::TLdeserialize(NativeByteBuffer *stream, uint32_t constructor, int32_t instanceNum, bool &error) {
InputUser *result = nullptr;
switch (constructor) {
case 0xf7c1b13f:
result = new TL_inputUserSelf();
break;
case 0xd8292816:
result = new TL_inputUser();
break;
case 0xb98886cf:
result = new TL_inputUserEmpty();
break;
case 0x2d117597:
result = new TL_inputUserFromMessage();
break;
default:
error = true;
if (LOGS_ENABLED) DEBUG_E("can't parse magic %x in InputUser", constructor);
return nullptr;
}
result->readParams(stream, instanceNum, error);
return result;
}
void TL_inputUserSelf::serializeToStream(NativeByteBuffer *stream) {
stream->writeInt32(constructor);
}
void TL_inputUser::readParams(NativeByteBuffer *stream, int32_t instanceNum, bool &error) {
user_id = stream->readInt32(&error);
access_hash = stream->readInt64(&error);
}
void TL_inputUser::serializeToStream(NativeByteBuffer *stream) {
stream->writeInt32(constructor);
stream->writeInt32(user_id);
stream->writeInt64(access_hash);
}
void TL_inputUserEmpty::serializeToStream(NativeByteBuffer *stream) {
stream->writeInt32(constructor);
}
void TL_inputUserFromMessage::readParams(NativeByteBuffer *stream, int32_t instanceNum, bool &error) {
peer = std::unique_ptr<InputPeer>(InputPeer::TLdeserialize(stream, stream->readUint32(&error), instanceNum, error));
msg_id = stream->readInt32(&error);
user_id = stream->readInt32(&error);
}
void TL_inputUserFromMessage::serializeToStream(NativeByteBuffer *stream) {
stream->writeInt32(constructor);
peer->serializeToStream(stream);
stream->writeInt32(msg_id);
stream->writeInt32(user_id);
}
MessageEntity *MessageEntity::TLdeserialize(NativeByteBuffer *stream, uint32_t constructor, int32_t instanceNum, bool &error) {
MessageEntity *result = nullptr;
switch (constructor) {
case 0x76a6d327:
result = new TL_messageEntityTextUrl();
break;
case 0x6cef8ac7:
result = new TL_messageEntityBotCommand();
break;
case 0x64e475c2:
result = new TL_messageEntityEmail();
break;
case 0x73924be0:
result = new TL_messageEntityPre();
break;
case 0xbb92ba95:
result = new TL_messageEntityUnknown();
break;
case 0x6ed02538:
result = new TL_messageEntityUrl();
break;
case 0x826f8b60:
result = new TL_messageEntityItalic();
break;
case 0xfa04579d:
result = new TL_messageEntityMention();
break;
case 0x352dca58:
result = new TL_messageEntityMentionName();
break;
case 0x208e68c9:
result = new TL_inputMessageEntityMentionName();
break;
case 0x4c4e743f:
result = new TL_messageEntityCashtag();
break;
case 0xbd610bc9:
result = new TL_messageEntityBold();
break;
case 0x6f635b0d:
result = new TL_messageEntityHashtag();
break;
case 0x28a20571:
result = new TL_messageEntityCode();
break;
case 0xbf0693d4:
result = new TL_messageEntityStrike();
break;
case 0x20df5d0:
result = new TL_messageEntityBlockquote();
break;
case 0x9c4e7e8b:
result = new TL_messageEntityUnderline();
break;
case 0x9b69e34b:
result = new TL_messageEntityPhone();
break;
default:
error = true;
if (LOGS_ENABLED) DEBUG_E("can't parse magic %x in MessageEntity", constructor);
return nullptr;
}
result->readParams(stream, instanceNum, error);
return result;
}
void TL_messageEntityTextUrl::readParams(NativeByteBuffer *stream, int32_t instanceNum, bool &error) {
offset = stream->readInt32(&error);
length = stream->readInt32(&error);
url = stream->readString(&error);
}
void TL_messageEntityTextUrl::serializeToStream(NativeByteBuffer *stream) {
stream->writeInt32(constructor);
stream->writeInt32(offset);
stream->writeInt32(length);
stream->writeString(url);
}
void TL_messageEntityBotCommand::readParams(NativeByteBuffer *stream, int32_t instanceNum, bool &error) {
offset = stream->readInt32(&error);
length = stream->readInt32(&error);
}
void TL_messageEntityBotCommand::serializeToStream(NativeByteBuffer *stream) {
stream->writeInt32(constructor);
stream->writeInt32(offset);
stream->writeInt32(length);
}
void TL_messageEntityEmail::readParams(NativeByteBuffer *stream, int32_t instanceNum, bool &error) {
offset = stream->readInt32(&error);
length = stream->readInt32(&error);
}
void TL_messageEntityEmail::serializeToStream(NativeByteBuffer *stream) {
stream->writeInt32(constructor);
stream->writeInt32(offset);
stream->writeInt32(length);
}
void TL_messageEntityPre::readParams(NativeByteBuffer *stream, int32_t instanceNum, bool &error) {
offset = stream->readInt32(&error);
length = stream->readInt32(&error);
language = stream->readString(&error);
}
void TL_messageEntityPre::serializeToStream(NativeByteBuffer *stream) {
stream->writeInt32(constructor);
stream->writeInt32(offset);
stream->writeInt32(length);
stream->writeString(language);
}
void TL_messageEntityUnknown::readParams(NativeByteBuffer *stream, int32_t instanceNum, bool &error) {
offset = stream->readInt32(&error);
length = stream->readInt32(&error);
}
void TL_messageEntityUnknown::serializeToStream(NativeByteBuffer *stream) {
stream->writeInt32(constructor);
stream->writeInt32(offset);
stream->writeInt32(length);
}
void TL_messageEntityUrl::readParams(NativeByteBuffer *stream, int32_t instanceNum, bool &error) {
offset = stream->readInt32(&error);
length = stream->readInt32(&error);
}
void TL_messageEntityUrl::serializeToStream(NativeByteBuffer *stream) {
stream->writeInt32(constructor);
stream->writeInt32(offset);
stream->writeInt32(length);
}
void TL_messageEntityItalic::readParams(NativeByteBuffer *stream, int32_t instanceNum, bool &error) {
offset = stream->readInt32(&error);
length = stream->readInt32(&error);
}
void TL_messageEntityItalic::serializeToStream(NativeByteBuffer *stream) {
stream->writeInt32(constructor);
stream->writeInt32(offset);
stream->writeInt32(length);
}
void TL_messageEntityMention::readParams(NativeByteBuffer *stream, int32_t instanceNum, bool &error) {
offset = stream->readInt32(&error);
length = stream->readInt32(&error);
}
void TL_messageEntityMention::serializeToStream(NativeByteBuffer *stream) {
stream->writeInt32(constructor);
stream->writeInt32(offset);
stream->writeInt32(length);
}
void TL_messageEntityMentionName::readParams(NativeByteBuffer *stream, int32_t instanceNum, bool &error) {
offset = stream->readInt32(&error);
length = stream->readInt32(&error);
user_id = stream->readInt32(&error);
}
void TL_messageEntityMentionName::serializeToStream(NativeByteBuffer *stream) {
stream->writeInt32(constructor);
stream->writeInt32(offset);
stream->writeInt32(length);
stream->writeInt32(user_id);
}
void TL_inputMessageEntityMentionName::readParams(NativeByteBuffer *stream, int32_t instanceNum, bool &error) {
offset = stream->readInt32(&error);
length = stream->readInt32(&error);
user_id = std::unique_ptr<InputUser>(InputUser::TLdeserialize(stream, stream->readUint32(&error), instanceNum, error));
}
void TL_inputMessageEntityMentionName::serializeToStream(NativeByteBuffer *stream) {
stream->writeInt32(constructor);
stream->writeInt32(offset);
stream->writeInt32(length);
user_id->serializeToStream(stream);
}
void TL_messageEntityCashtag::readParams(NativeByteBuffer *stream, int32_t instanceNum, bool &error) {
offset = stream->readInt32(&error);
length = stream->readInt32(&error);
}
void TL_messageEntityCashtag::serializeToStream(NativeByteBuffer *stream) {
stream->writeInt32(constructor);
stream->writeInt32(offset);
stream->writeInt32(length);
}
void TL_messageEntityBold::readParams(NativeByteBuffer *stream, int32_t instanceNum, bool &error) {
offset = stream->readInt32(&error);
length = stream->readInt32(&error);
}
void TL_messageEntityBold::serializeToStream(NativeByteBuffer *stream) {
stream->writeInt32(constructor);
stream->writeInt32(offset);
stream->writeInt32(length);
}
void TL_messageEntityHashtag::readParams(NativeByteBuffer *stream, int32_t instanceNum, bool &error) {
offset = stream->readInt32(&error);
length = stream->readInt32(&error);
}
void TL_messageEntityHashtag::serializeToStream(NativeByteBuffer *stream) {
stream->writeInt32(constructor);
stream->writeInt32(offset);
stream->writeInt32(length);
}
void TL_messageEntityCode::readParams(NativeByteBuffer *stream, int32_t instanceNum, bool &error) {
offset = stream->readInt32(&error);
length = stream->readInt32(&error);
}
void TL_messageEntityCode::serializeToStream(NativeByteBuffer *stream) {
stream->writeInt32(constructor);
stream->writeInt32(offset);
stream->writeInt32(length);
}
void TL_messageEntityStrike::readParams(NativeByteBuffer *stream, int32_t instanceNum, bool &error) {
offset = stream->readInt32(&error);
length = stream->readInt32(&error);
}
void TL_messageEntityStrike::serializeToStream(NativeByteBuffer *stream) {
stream->writeInt32(constructor);
stream->writeInt32(offset);
stream->writeInt32(length);
}
void TL_messageEntityBlockquote::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(offset);
stream->writeInt32(length);
}
void TL_messageEntityUnderline::readParams(NativeByteBuffer *stream, int32_t instanceNum, bool &error) {
offset = stream->readInt32(&error);
length = stream->readInt32(&error);
}
void TL_messageEntityUnderline::serializeToStream(NativeByteBuffer *stream) {
stream->writeInt32(constructor);
stream->writeInt32(offset);
stream->writeInt32(length);
}
void TL_messageEntityPhone::readParams(NativeByteBuffer *stream, int32_t instanceNum, bool &error) {
offset = stream->readInt32(&error);
length = stream->readInt32(&error);
}
void TL_messageEntityPhone::serializeToStream(NativeByteBuffer *stream) {
stream->writeInt32(constructor);
stream->writeInt32(offset);
stream->writeInt32(length);
}
TL_dataJSON *TL_dataJSON::TLdeserialize(NativeByteBuffer *stream, uint32_t constructor, int32_t instanceNum, bool &error) {
if (TL_dataJSON::constructor != constructor) {
error = true;
if (LOGS_ENABLED) DEBUG_E("can't parse magic %x in TL_dataJSON", constructor);
return nullptr;
}
TL_dataJSON *result = new TL_dataJSON();
result->readParams(stream, instanceNum, error);
return result;
}
void TL_dataJSON::readParams(NativeByteBuffer *stream, int32_t instanceNum, bool &error) {
data = stream->readString(&error);
}
void TL_dataJSON::serializeToStream(NativeByteBuffer *stream) {
stream->writeInt32(constructor);
stream->writeString(data);
}
TL_help_termsOfService *TL_help_termsOfService::TLdeserialize(NativeByteBuffer *stream, uint32_t constructor, int32_t instanceNum, bool &error) {
if (TL_help_termsOfService::constructor != constructor) {
error = true;
if (LOGS_ENABLED) DEBUG_E("can't parse magic %x in TL_help_termsOfService", constructor);
return nullptr;
}
TL_help_termsOfService *result = new TL_help_termsOfService();
result->readParams(stream, instanceNum, error);
return result;
}
void TL_help_termsOfService::readParams(NativeByteBuffer *stream, int32_t instanceNum, bool &error) {
flags = stream->readInt32(&error);
popup = (flags & 1) != 0;
id = std::unique_ptr<TL_dataJSON>(TL_dataJSON::TLdeserialize(stream, stream->readUint32(&error), instanceNum, error));
text = stream->readString(&error);
int magic = stream->readInt32(&error);
if (magic != 0x1cb5c415) {
error = true;
if (LOGS_ENABLED) DEBUG_E("wrong Vector magic, got %x", magic);
return;
}
int count = stream->readInt32(&error);
for (int a = 0; a < count; a++) {
MessageEntity *object = MessageEntity::TLdeserialize(stream, stream->readUint32(&error), instanceNum, error);
if (object == nullptr) {
return;
}
entities.push_back(std::unique_ptr<MessageEntity>(object));
}
if ((flags & 2) != 0) {
min_age_confirm = stream->readInt32(&error);
}
}
void TL_help_termsOfService::serializeToStream(NativeByteBuffer *stream) {
stream->writeInt32(constructor);
flags = popup ? (flags | 1) : (flags & ~1);
stream->writeInt32(flags);
id->serializeToStream(stream);
stream->writeString(text);
stream->writeInt32(0x1cb5c415);
int32_t count = (int32_t) entities.size();
stream->writeInt32(count);
for (int a = 0; a < count; a++) {
entities[a]->serializeToStream(stream);
}
if ((flags & 2) != 0) {
stream->writeInt32(min_age_confirm);
}
}
auth_Authorization *auth_Authorization::TLdeserialize(NativeByteBuffer *stream, uint32_t constructor, int32_t instanceNum, bool &error) {
auth_Authorization *result = nullptr;
switch (constructor) {
case 0x44747e9a:
result = new TL_auth_authorizationSignUpRequired();
break;
case 0xcd050916:
result = new TL_auth_authorization();
break;
default:
error = true;
if (LOGS_ENABLED) DEBUG_E("can't parse magic %x in auth_Authorization", constructor);
return nullptr;
}
result->readParams(stream, instanceNum, error);
return result;
}
void TL_auth_authorizationSignUpRequired::readParams(NativeByteBuffer *stream, int32_t instanceNum, bool &error) {
flags = stream->readInt32(&error);
if ((flags & 1) != 0) {
terms_of_service = std::unique_ptr<TL_help_termsOfService>(TL_help_termsOfService::TLdeserialize(stream, stream->readUint32(&error), instanceNum, error));
}
}
void TL_auth_authorizationSignUpRequired::serializeToStream(NativeByteBuffer *stream) {
stream->writeInt32(constructor);
stream->writeInt32(flags);
if ((flags & 1) != 0) {
terms_of_service->serializeToStream(stream);
}
}
void TL_auth_authorization::readParams(NativeByteBuffer *stream, int32_t instanceNum, bool &error) {
flags = stream->readInt32(&error);
if ((flags & 1) != 0) {
@ -462,6 +982,15 @@ void TL_auth_authorization::readParams(NativeByteBuffer *stream, int32_t instanc
user = std::unique_ptr<User>(User::TLdeserialize(stream, stream->readUint32(&error), instanceNum, error));
}
void TL_auth_authorization::serializeToStream(NativeByteBuffer *stream) {
stream->writeInt32(constructor);
stream->writeInt32(flags);
if ((flags & 1) != 0) {
stream->writeInt32(tmp_sessions);
}
user->serializeToStream(stream);
}
TL_auth_exportedAuthorization *TL_auth_exportedAuthorization::TLdeserialize(NativeByteBuffer *stream, uint32_t constructor, int32_t instanceNum, bool &error) {
if (TL_auth_exportedAuthorization::constructor != constructor) {
error = true;
@ -496,7 +1025,7 @@ bool TL_auth_importAuthorization::isNeedLayer() {
}
TLObject *TL_auth_importAuthorization::deserializeResponse(NativeByteBuffer *stream, uint32_t constructor, int32_t instanceNum, bool &error) {
return TL_auth_authorization::TLdeserialize(stream, constructor, instanceNum, error);
return auth_Authorization::TLdeserialize(stream, constructor, instanceNum, error);
}
void TL_auth_importAuthorization::serializeToStream(NativeByteBuffer *stream) {

View file

@ -315,7 +315,354 @@ public:
void serializeToStream(NativeByteBuffer *stream);
};
class TL_auth_authorization : public TLObject {
class InputPeer : public TLObject {
public:
int32_t user_id;
int32_t chat_id;
int32_t channel_id;
int64_t access_hash;
static InputPeer *TLdeserialize(NativeByteBuffer *stream, uint32_t constructor, int32_t instanceNum, bool &error);
};
class TL_inputPeerSelf : public InputPeer {
public:
static const uint32_t constructor = 0x7da07ec9;
void serializeToStream(NativeByteBuffer *stream);
};
class TL_inputPeerUser : public InputPeer {
public:
static const uint32_t constructor = 0x7b8e7de6;
void readParams(NativeByteBuffer *stream, int32_t instanceNum, bool &error);
void serializeToStream(NativeByteBuffer *stream);
};
class TL_inputPeerChat : public InputPeer {
public:
static const uint32_t constructor = 0x179be863;
void readParams(NativeByteBuffer *stream, int32_t instanceNum, bool &error);
void serializeToStream(NativeByteBuffer *stream);
};
class TL_inputPeerUserFromMessage : public InputPeer {
public:
static const uint32_t constructor = 0x17bae2e6;
std::unique_ptr<InputPeer> peer;
int32_t msg_id;
void readParams(NativeByteBuffer *stream, int32_t instanceNum, bool &error);
void serializeToStream(NativeByteBuffer *stream);
};
class TL_inputPeerChannelFromMessage : public InputPeer {
public:
static const uint32_t constructor = 0x9c95f7bb;
std::unique_ptr<InputPeer> peer;
int32_t msg_id;
void readParams(NativeByteBuffer *stream, int32_t instanceNum, bool &error);
void serializeToStream(NativeByteBuffer *stream);
};
class TL_inputPeerChannel : public InputPeer {
public:
static const uint32_t constructor = 0x20adaef8;
void readParams(NativeByteBuffer *stream, int32_t instanceNum, bool &error);
void serializeToStream(NativeByteBuffer *stream);
};
class TL_inputPeerEmpty : public InputPeer {
public:
static const uint32_t constructor = 0x7f3b18ea;
void serializeToStream(NativeByteBuffer *stream);
};
class InputUser : public TLObject {
public:
int32_t user_id;
int64_t access_hash;
static InputUser *TLdeserialize(NativeByteBuffer *stream, uint32_t constructor, int32_t instanceNum, bool &error);
};
class TL_inputUserSelf : public InputUser {
public:
static const uint32_t constructor = 0xf7c1b13f;
void serializeToStream(NativeByteBuffer *stream);
};
class TL_inputUser : public InputUser {
public:
static const uint32_t constructor = 0xd8292816;
void readParams(NativeByteBuffer *stream, int32_t instanceNum, bool &error);
void serializeToStream(NativeByteBuffer *stream);
};
class TL_inputUserEmpty : public InputUser {
public:
static const uint32_t constructor = 0xb98886cf;
void serializeToStream(NativeByteBuffer *stream);
};
class TL_inputUserFromMessage : public InputUser {
public:
static const uint32_t constructor = 0x2d117597;
std::unique_ptr<InputPeer> peer;
int32_t msg_id;
void readParams(NativeByteBuffer *stream, int32_t instanceNum, bool &error);
void serializeToStream(NativeByteBuffer *stream);
};
class MessageEntity : public TLObject {
public:
int32_t offset;
int32_t length;
std::string url;
std::string language;
static MessageEntity *TLdeserialize(NativeByteBuffer *stream, uint32_t constructor, int32_t instanceNum, bool &error);
};
class TL_messageEntityTextUrl : public MessageEntity {
public:
static const uint32_t constructor = 0x76a6d327;
void readParams(NativeByteBuffer *stream, int32_t instanceNum, bool &error);
void serializeToStream(NativeByteBuffer *stream);
};
class TL_messageEntityBotCommand : public MessageEntity {
public:
static const uint32_t constructor = 0x6cef8ac7;
void readParams(NativeByteBuffer *stream, int32_t instanceNum, bool &error);
void serializeToStream(NativeByteBuffer *stream);
};
class TL_messageEntityEmail : public MessageEntity {
public:
static const uint32_t constructor = 0x64e475c2;
void readParams(NativeByteBuffer *stream, int32_t instanceNum, bool &error);
void serializeToStream(NativeByteBuffer *stream);
};
class TL_messageEntityPre : public MessageEntity {
public:
static const uint32_t constructor = 0x73924be0;
void readParams(NativeByteBuffer *stream, int32_t instanceNum, bool &error);
void serializeToStream(NativeByteBuffer *stream);
};
class TL_messageEntityUnknown : public MessageEntity {
public:
static const uint32_t constructor = 0xbb92ba95;
void readParams(NativeByteBuffer *stream, int32_t instanceNum, bool &error);
void serializeToStream(NativeByteBuffer *stream);
};
class TL_messageEntityUrl : public MessageEntity {
public:
static const uint32_t constructor = 0x6ed02538;
void readParams(NativeByteBuffer *stream, int32_t instanceNum, bool &error);
void serializeToStream(NativeByteBuffer *stream);
};
class TL_messageEntityItalic : public MessageEntity {
public:
static const uint32_t constructor = 0x826f8b60;
void readParams(NativeByteBuffer *stream, int32_t instanceNum, bool &error);
void serializeToStream(NativeByteBuffer *stream);
};
class TL_messageEntityMention : public MessageEntity {
public:
static const uint32_t constructor = 0xfa04579d;
void readParams(NativeByteBuffer *stream, int32_t instanceNum, bool &error);
void serializeToStream(NativeByteBuffer *stream);
};
class TL_messageEntityMentionName : public MessageEntity {
public:
static const uint32_t constructor = 0x352dca58;
int32_t user_id;
void readParams(NativeByteBuffer *stream, int32_t instanceNum, bool &error);
void serializeToStream(NativeByteBuffer *stream);
};
class TL_inputMessageEntityMentionName : public MessageEntity {
public:
static const uint32_t constructor = 0x208e68c9;
std::unique_ptr<InputUser> user_id;
void readParams(NativeByteBuffer *stream, int32_t instanceNum, bool &error);
void serializeToStream(NativeByteBuffer *stream);
};
class TL_messageEntityCashtag : public MessageEntity {
public:
static const uint32_t constructor = 0x4c4e743f;
void readParams(NativeByteBuffer *stream, int32_t instanceNum, bool &error);
void serializeToStream(NativeByteBuffer *stream);
};
class TL_messageEntityBold : public MessageEntity {
public:
static const uint32_t constructor = 0xbd610bc9;
void readParams(NativeByteBuffer *stream, int32_t instanceNum, bool &error);
void serializeToStream(NativeByteBuffer *stream);
};
class TL_messageEntityHashtag : public MessageEntity {
public:
static const uint32_t constructor = 0x6f635b0d;
void readParams(NativeByteBuffer *stream, int32_t instanceNum, bool &error);
void serializeToStream(NativeByteBuffer *stream);
};
class TL_messageEntityCode : public MessageEntity {
public:
static const uint32_t constructor = 0x28a20571;
void readParams(NativeByteBuffer *stream, int32_t instanceNum, bool &error);
void serializeToStream(NativeByteBuffer *stream);
};
class TL_messageEntityStrike : public MessageEntity {
public:
static const uint32_t constructor = 0xbf0693d4;
void readParams(NativeByteBuffer *stream, int32_t instanceNum, bool &error);
void serializeToStream(NativeByteBuffer *stream);
};
class TL_messageEntityBlockquote : public MessageEntity {
public:
static const uint32_t constructor = 0x20df5d0;
void readParams(NativeByteBuffer *stream, int32_t instanceNum, bool &error);
void serializeToStream(NativeByteBuffer *stream);
};
class TL_messageEntityUnderline : public MessageEntity {
public:
static const uint32_t constructor = 0x9c4e7e8b;
void readParams(NativeByteBuffer *stream, int32_t instanceNum, bool &error);
void serializeToStream(NativeByteBuffer *stream);
};
class TL_messageEntityPhone : public MessageEntity {
public:
static const uint32_t constructor = 0x9b69e34b;
void readParams(NativeByteBuffer *stream, int32_t instanceNum, bool &error);
void serializeToStream(NativeByteBuffer *stream);
};
class TL_dataJSON : public TLObject {
public:
static const uint32_t constructor = 0x7d748d04;
std::string data;
static TL_dataJSON *TLdeserialize(NativeByteBuffer *stream, uint32_t constructor, int32_t instanceNum, bool &error);
void readParams(NativeByteBuffer *stream, int32_t instanceNum, bool &error);
void serializeToStream(NativeByteBuffer *stream);
};
class TL_help_termsOfService : public TLObject {
public:
static const uint32_t constructor = 0x780a0310;
int32_t flags;
bool popup;
std::unique_ptr<TL_dataJSON> id;
std::string text;
std::vector<std::unique_ptr<MessageEntity>> entities;
int32_t min_age_confirm;
static TL_help_termsOfService *TLdeserialize(NativeByteBuffer *stream, uint32_t constructor, int32_t instanceNum, bool &error);
void readParams(NativeByteBuffer *stream, int32_t instanceNum, bool &error);
void serializeToStream(NativeByteBuffer *stream);
};
class auth_Authorization : public TLObject {
public:
static auth_Authorization *TLdeserialize(NativeByteBuffer *stream, uint32_t constructor, int32_t instanceNum, bool &error);
};
class TL_auth_authorizationSignUpRequired : public auth_Authorization {
public:
static const uint32_t constructor = 0x44747e9a;
int32_t flags;
std::unique_ptr<TL_help_termsOfService> terms_of_service;
void readParams(NativeByteBuffer *stream, int32_t instanceNum, bool &error);
void serializeToStream(NativeByteBuffer *stream);
};
class TL_auth_authorization : public auth_Authorization {
public:
static const uint32_t constructor = 0xcd050916;
@ -324,8 +671,8 @@ public:
int32_t tmp_sessions;
std::unique_ptr<User> user;
static TL_auth_authorization *TLdeserialize(NativeByteBuffer *stream, uint32_t constructor, int32_t instanceNum, bool &error);
void readParams(NativeByteBuffer *stream, int32_t instanceNum, bool &error);
void serializeToStream(NativeByteBuffer *stream);
};
class TL_auth_exportedAuthorization : public TLObject {

View file

@ -10,6 +10,7 @@
#include <stdlib.h>
#include <cstring>
#include <openssl/sha.h>
#include <algorithm>
#include "Connection.h"
#include "ConnectionsManager.h"
#include "BuffersStorage.h"
@ -219,7 +220,7 @@ void Connection::onReceivedData(NativeByteBuffer *buffer) {
len = currentPacketLength + 4;
}
if (currentProtocolType != ProtocolTypeDD && currentPacketLength % 4 != 0 || currentPacketLength > 2 * 1024 * 1024) {
if (currentProtocolType != ProtocolTypeDD && currentProtocolType != ProtocolTypeTLS && currentPacketLength % 4 != 0 || currentPacketLength > 2 * 1024 * 1024) {
if (LOGS_ENABLED) DEBUG_D("connection(%p, account%u, dc%u, type %d) received invalid packet length", this, currentDatacenter->instanceNum, currentDatacenter->getDatacenterId(), connectionType);
reconnect();
return;
@ -348,7 +349,7 @@ void Connection::connect() {
lastPacketLength = 0;
wasConnected = false;
hasSomeDataSinceLastConnect = false;
openConnection(hostAddress, hostPort, ipv6 != 0, ConnectionsManager::getInstance(currentDatacenter->instanceNum).currentNetworkType);
openConnection(hostAddress, hostPort, secret, ipv6 != 0, ConnectionsManager::getInstance(currentDatacenter->instanceNum).currentNetworkType);
if (connectionType == ConnectionTypeProxy) {
setTimeout(5);
} else if (connectionType == ConnectionTypePush) {
@ -408,7 +409,7 @@ void Connection::setHasUsefullData() {
}
bool Connection::allowsCustomPadding() {
return currentProtocolType == ProtocolTypeDD || currentProtocolType == ProtocolTypeEF;
return currentProtocolType == ProtocolTypeTLS || currentProtocolType == ProtocolTypeDD || currentProtocolType == ProtocolTypeEF;
}
void Connection::sendData(NativeByteBuffer *buff, bool reportAck, bool encrypted) {
@ -444,8 +445,10 @@ void Connection::sendData(NativeByteBuffer *buff, bool reportAck, bool encrypted
}
if (useSecret != 0) {
std::string *currentSecret = getCurrentSecret(useSecret);
if (currentSecret->length() == 34 && (*currentSecret)[0] == 'd' && (*currentSecret)[1] == 'd') {
if (currentSecret->length() >= 17 && (*currentSecret)[0] == '\xdd') {
currentProtocolType = ProtocolTypeDD;
} else if (currentSecret->length() > 17 && (*currentSecret)[0] == '\xee') {
currentProtocolType = ProtocolTypeTLS;
} else {
currentProtocolType = ProtocolTypeEF;
}
@ -464,7 +467,7 @@ void Connection::sendData(NativeByteBuffer *buff, bool reportAck, bool encrypted
}
} else {
packetLength = buff->limit();
if (currentProtocolType == ProtocolTypeDD) {
if (currentProtocolType == ProtocolTypeDD || currentProtocolType == ProtocolTypeTLS) {
RAND_bytes((uint8_t *) &additinalPacketSize, 4);
if (!encrypted) {
additinalPacketSize = additinalPacketSize % 257;
@ -506,10 +509,10 @@ void Connection::sendData(NativeByteBuffer *buff, bool reportAck, bool encrypted
RAND_bytes(bytes, 64);
uint32_t val = (bytes[3] << 24) | (bytes[2] << 16) | (bytes[1] << 8) | (bytes[0]);
uint32_t val2 = (bytes[7] << 24) | (bytes[6] << 16) | (bytes[5] << 8) | (bytes[4]);
if (bytes[0] != 0xef && val != 0x44414548 && val != 0x54534f50 && val != 0x20544547 && val != 0x4954504f && val != 0xeeeeeeee && val != 0xdddddddd && val2 != 0x00000000) {
if (currentProtocolType == ProtocolTypeTLS || bytes[0] != 0xef && val != 0x44414548 && val != 0x54534f50 && val != 0x20544547 && val != 0x4954504f && val != 0xeeeeeeee && val != 0xdddddddd && val != 0x02010316 && val2 != 0x00000000) {
if (currentProtocolType == ProtocolTypeEF) {
bytes[56] = bytes[57] = bytes[58] = bytes[59] = 0xef;
} else if (currentProtocolType == ProtocolTypeDD) {
} else if (currentProtocolType == ProtocolTypeDD || currentProtocolType == ProtocolTypeTLS) {
bytes[56] = bytes[57] = bytes[58] = bytes[59] = 0xdd;
} else if (currentProtocolType == ProtocolTypeEE) {
bytes[56] = bytes[57] = bytes[58] = bytes[59] = 0xee;
@ -603,17 +606,6 @@ void Connection::sendData(NativeByteBuffer *buff, bool reportAck, bool encrypted
}
}
inline char char2int(char input) {
if (input >= '0' && input <= '9') {
return input - '0';
} else if (input >= 'A' && input <= 'F') {
return (char) (input - 'A' + 10);
} else if (input >= 'a' && input <= 'f') {
return (char) (input - 'a' + 10);
}
return 0;
}
inline std::string *Connection::getCurrentSecret(uint8_t secretType) {
if (secretType == 2) {
return &secret;
@ -630,16 +622,18 @@ inline void Connection::encryptKeyWithSecret(uint8_t *bytes, uint8_t secretType)
}
std::string *currentSecret = getCurrentSecret(secretType);
size_t a = 0;
if (currentSecret->length() == 34 && (*currentSecret)[0] == 'd' && (*currentSecret)[1] == 'd') {
size_t size = std::min((size_t) 16, currentSecret->length());
if (currentSecret->length() >= 17 && ((*currentSecret)[0] == '\xdd' || (*currentSecret)[0] == '\xee')) {
a = 1;
size = 17;
}
SHA256_CTX sha256Ctx;
SHA256_Init(&sha256Ctx);
SHA256_Update(&sha256Ctx, bytes, 32);
char b[1];
for (; a < currentSecret->size() / 2; a++) {
b[0] = (char) (char2int((*currentSecret)[a * 2]) * 16 + char2int((*currentSecret)[a * 2 + 1]));
for (; a < size; a++) {
b[0] = (char) (*currentSecret)[a];
SHA256_Update(&sha256Ctx, b, 1);
}
SHA256_Final(bytes, &sha256Ctx);

View file

@ -64,7 +64,8 @@ private:
enum ProtocolType {
ProtocolTypeEF,
ProtocolTypeEE,
ProtocolTypeDD
ProtocolTypeDD,
ProtocolTypeTLS
};
inline void encryptKeyWithSecret(uint8_t *array, uint8_t secretType);

View file

@ -8,12 +8,15 @@
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <cerrno>
#include <sys/socket.h>
#include <memory.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <openssl/rand.h>
#include <openssl/hmac.h>
#include <algorithm>
#include "ByteStream.h"
#include "ConnectionSocket.h"
#include "FileLog.h"
@ -23,11 +26,197 @@
#include "Timer.h"
#include "NativeByteBuffer.h"
#include "BuffersStorage.h"
#include "Connection.h"
#ifndef EPOLLRDHUP
#define EPOLLRDHUP 0x2000
#endif
#define MAX_GREASE 8
class TlsHello {
public:
TlsHello() {
RAND_bytes(grease, MAX_GREASE);
for (int a = 0; a < MAX_GREASE; a++) {
grease[a] = (uint8_t) ((grease[a] & 0xf0) + 0x0A);
}
for (size_t i = 1; i < MAX_GREASE; i += 2) {
if (grease[i] == grease[i - 1]) {
grease[i] ^= 0x10;
}
}
}
struct Op {
enum class Type {
String, Random, Zero, Domain, Grease, BeginScope, EndScope
};
Type type;
size_t length;
int seed;
std::string data;
static Op string(const char str[], size_t len) {
Op res;
res.type = Type::String;
res.data = std::string(str, len);
return res;
}
static Op random(size_t length) {
Op res;
res.type = Type::Random;
res.length = length;
return res;
}
static Op zero(size_t length) {
Op res;
res.type = Type::Zero;
res.length = length;
return res;
}
static Op domain() {
Op res;
res.type = Type::Domain;
return res;
}
static Op grease(int seed) {
Op res;
res.type = Type::Grease;
res.seed = seed;
return res;
}
static Op begin_scope() {
Op res;
res.type = Type::BeginScope;
return res;
}
static Op end_scope() {
Op res;
res.type = Type::EndScope;
return res;
}
};
static const TlsHello &getDefault() {
static TlsHello result = [] {
TlsHello res;
res.ops = {
Op::string("\x16\x03\x01\x02\x00\x01\x00\x01\xfc\x03\x03", 11),
Op::zero(32),
Op::string("\x20", 1),
Op::random(32),
Op::string("\x00\x22", 2),
Op::grease(0),
Op::string("\x13\x01\x13\x02\x13\x03\xc0\x2b\xc0\x2f\xc0\x2c\xc0\x30\xcc\xa9\xcc\xa8\xc0\x13\xc0\x14\x00\x9c"
"\x00\x9d\x00\x2f\x00\x35\x00\x0a\x01\x00\x01\x91", 36),
Op::grease(2),
Op::string("\x00\x00\x00\x00", 4),
Op::begin_scope(),
Op::begin_scope(),
Op::string("\x00", 1),
Op::begin_scope(),
Op::domain(),
Op::end_scope(),
Op::end_scope(),
Op::end_scope(),
Op::string("\x00\x17\x00\x00\xff\x01\x00\x01\x00\x00\x0a\x00\x0a\x00\x08", 15),
Op::grease(4),
Op::string(
"\x00\x1d\x00\x17\x00\x18\x00\x0b\x00\x02\x01\x00\x00\x23\x00\x00\x00\x10\x00\x0e\x00\x0c\x02\x68\x32\x08"
"\x68\x74\x74\x70\x2f\x31\x2e\x31\x00\x05\x00\x05\x01\x00\x00\x00\x00\x00\x0d\x00\x14\x00\x12\x04\x03\x08"
"\x04\x04\x01\x05\x03\x08\x05\x05\x01\x08\x06\x06\x01\x02\x01\x00\x12\x00\x00\x00\x33\x00\x2b\x00\x29", 77),
Op::grease(4),
Op::string("\x00\x01\x00\x00\x1d\x00\x20", 7),
Op::random(32),
Op::string("\x00\x2d\x00\x02\x01\x01\x00\x2b\x00\x0b\x0a", 11),
Op::grease(6),
Op::string("\x03\x04\x03\x03\x03\x02\x03\x01\x00\x1b\x00\x03\x02\x00\x02", 15),
Op::grease(3),
Op::string("\x00\x01\x00\x00\x15", 5)};
return res;
}();
return result;
}
uint32_t writeToBuffer(uint8_t *data) {
uint32_t offset = 0;
for (auto op : ops) {
writeOp(op, data, offset);
}
return offset;
}
uint32_t writePadding(uint8_t *data, uint32_t length) {
if (length > 515) {
return 0;
}
uint32_t size = 515 - length;
memset(data + length + 2, 0, size);
data[length] = static_cast<uint8_t>((size >> 8) & 0xff);
data[length + 1] = static_cast<uint8_t>(size & 0xff);
return length + size + 2;
}
void setDomain(std::string value) {
domain = std::move(value);
}
private:
std::vector<Op> ops;
uint8_t grease[MAX_GREASE];
std::vector<size_t> scopeOffset;
std::string domain;
void writeOp(const TlsHello::Op &op, uint8_t *data, uint32_t &offset) {
using Type = TlsHello::Op::Type;
switch (op.type) {
case Type::String:
memcpy(data + offset, op.data.data(), op.data.size());
offset += op.data.size();
break;
case Type::Random:
RAND_bytes(data + offset, (size_t) op.length);
offset += op.length;
break;
case Type::Zero:
std::memset(data + offset, 0, op.length);
offset += op.length;
break;
case Type::Domain: {
memcpy(data + offset, domain.data(), domain.size());
offset += domain.size();
break;
}
case Type::Grease: {
data[offset] = grease[op.seed];
data[offset + 1] = grease[op.seed];
offset += 2;
break;
}
case Type::BeginScope:
scopeOffset.push_back(offset);
offset += 2;
break;
case Type::EndScope: {
auto begin_offset = scopeOffset.back();
scopeOffset.pop_back();
size_t size = offset - begin_offset - 2;
data[begin_offset] = static_cast<uint8_t>((size >> 8) & 0xff);
data[begin_offset + 1] = static_cast<uint8_t>(size & 0xff);
break;
}
}
}
};
ConnectionSocket::ConnectionSocket(int32_t instance) {
instanceNum = instance;
outgoingByteStream = new ByteStream();
@ -44,15 +233,24 @@ ConnectionSocket::~ConnectionSocket() {
delete eventObject;
eventObject = nullptr;
}
if (tempBuffer != nullptr) {
delete tempBuffer;
tempBuffer = nullptr;
}
if (tlsBuffer != nullptr) {
tlsBuffer->reuse();
tlsBuffer = nullptr;
}
}
void ConnectionSocket::openConnection(std::string address, uint16_t port, bool ipv6, int32_t networkType) {
void ConnectionSocket::openConnection(std::string address, uint16_t port, std::string secret, bool ipv6, int32_t networkType) {
currentNetworkType = networkType;
isIpv6 = ipv6;
currentAddress = address;
currentPort = port;
waitingForHostResolve = "";
adjustWriteOpAfterResolve = false;
tlsState = 0;
ConnectionsManager::getInstance(instanceNum).attachConnection(this);
memset(&socketAddress, 0, sizeof(sockaddr_in));
@ -67,16 +265,33 @@ void ConnectionSocket::openConnection(std::string address, uint16_t port, bool i
proxySecret = &ConnectionsManager::getInstance(instanceNum).proxySecret;
}
if (proxyAddress != nullptr && !proxyAddress->empty()) {
if (!proxyAddress->empty()) {
if (LOGS_ENABLED) DEBUG_D("connection(%p) connecting via proxy %s:%d secret[%d]", this, proxyAddress->c_str(), proxyPort, (int) proxySecret->size());
if ((socketFd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
if (LOGS_ENABLED) DEBUG_E("connection(%p) can't create proxy socket", this);
closeSocket(1, -1);
return;
}
uint32_t tempBuffLength;
if (proxySecret->empty()) {
proxyAuthState = 1;
tempBuffLength = 1024;
} else if (proxySecret->size() > 17 && (*proxySecret)[0] == '\xee') {
proxyAuthState = 10;
currentSecret = proxySecret->substr(1, 16);
currentSecretDomain = proxySecret->substr(17);
tempBuffLength = 65 * 1024;
} else {
proxyAuthState = 0;
tempBuffLength = 0;
}
if (tempBuffLength > 0) {
if (tempBuffer == nullptr || tempBuffer->length < tempBuffLength) {
if (tempBuffer != nullptr) {
delete tempBuffer;
}
tempBuffer = new ByteArray(tempBuffLength);
}
}
socketAddress.sin_family = AF_INET;
socketAddress.sin_port = htons(proxyPort);
@ -145,6 +360,24 @@ void ConnectionSocket::openConnection(std::string address, uint16_t port, bool i
return;
}
}
uint32_t tempBuffLength;
if (secret.size() > 17 && secret[0] == '\xee') {
proxyAuthState = 10;
currentSecret = secret.substr(1, 16);
currentSecretDomain = secret.substr(17);
tempBuffLength = 65 * 1024;
} else {
proxyAuthState = 0;
tempBuffLength = 0;
}
if (tempBuffLength > 0) {
if (tempBuffer == nullptr || tempBuffer->length < tempBuffLength) {
if (tempBuffer != nullptr) {
delete tempBuffer;
}
tempBuffer = new ByteArray(tempBuffLength);
}
}
}
openConnectionInternal(ipv6);
@ -197,7 +430,7 @@ void ConnectionSocket::closeSocket(int32_t reason, int32_t error) {
lastEventTime = ConnectionsManager::getInstance(instanceNum).getCurrentTimeMonotonicMillis();
ConnectionsManager::getInstance(instanceNum).detachConnection(this);
if (socketFd >= 0) {
epoll_ctl(ConnectionsManager::getInstance(instanceNum).epolFd, EPOLL_CTL_DEL, socketFd, NULL);
epoll_ctl(ConnectionsManager::getInstance(instanceNum).epolFd, EPOLL_CTL_DEL, socketFd, nullptr);
if (close(socketFd) != 0) {
if (LOGS_ENABLED) DEBUG_E("connection(%p) unable to close socket", this);
}
@ -206,8 +439,13 @@ void ConnectionSocket::closeSocket(int32_t reason, int32_t error) {
waitingForHostResolve = "";
adjustWriteOpAfterResolve = false;
proxyAuthState = 0;
tlsState = 0;
onConnectedSent = false;
outgoingByteStream->clean();
if (tlsBuffer != nullptr) {
tlsBuffer->reuse();
tlsBuffer = nullptr;
}
onDisconnected(reason, error);
}
@ -222,6 +460,7 @@ void ConnectionSocket::onEvent(uint32_t events) {
NativeByteBuffer *buffer = ConnectionsManager::getInstance(instanceNum).networkBuffer;
while (true) {
buffer->rewind();
Connection *connection = (Connection *) this;
readCount = recv(socketFd, buffer->bytes(), READ_BUFFER_SIZE, 0);
if (readCount < 0) {
closeSocket(1, -1);
@ -231,7 +470,75 @@ void ConnectionSocket::onEvent(uint32_t events) {
if (readCount > 0) {
buffer->limit((uint32_t) readCount);
lastEventTime = ConnectionsManager::getInstance(instanceNum).getCurrentTimeMonotonicMillis();
if (proxyAuthState == 2) {
if (proxyAuthState == 11) {
if (LOGS_ENABLED) DEBUG_D("connection(%p) TLS received %d", this, (int) readCount);
size_t newBytesRead = bytesRead + readCount;
if (newBytesRead > 64 * 1024) {
closeSocket(1, -1);
if (LOGS_ENABLED) DEBUG_E("connection(%p) TLS client hello too much data", this);
return;
}
if (newBytesRead >= 16) {
std::memcpy(tempBuffer->bytes + bytesRead, buffer->bytes(), (size_t) readCount);
static std::string hello1 = std::string("\x16\x03\x03", 3);
if (std::memcmp(hello1.data(), tempBuffer->bytes, hello1.size()) != 0) {
closeSocket(1, -1);
if (LOGS_ENABLED) DEBUG_E("connection(%p) TLS hello1 mismatch", this);
return;
}
size_t len1 = (tempBuffer->bytes[3] << 8) + tempBuffer->bytes[4];
if (len1 > 64 * 1024 - 5) {
closeSocket(1, -1);
if (LOGS_ENABLED) DEBUG_E("connection(%p) TLS len1 invalid", this);
return;
} else if (newBytesRead < len1 + 5) {
if (LOGS_ENABLED) DEBUG_D("connection(%p) TLS client hello wait for more data", this);
bytesRead = newBytesRead;
return;
}
static std::string hello2 = std::string("\x14\x03\x03\x00\x01\x01\x17\x03\x03", 9);
if (std::memcmp(hello2.data(), tempBuffer->bytes + 5 + len1, hello2.size()) != 0) {
closeSocket(1, -1);
if (LOGS_ENABLED) DEBUG_E("connection(%p) TLS hello2 mismatch", this);
return;
}
size_t len2 = (tempBuffer->bytes[5 + 9 + len1] << 8) + tempBuffer->bytes[5 + 9 + len1 + 1];
if (len2 > 64 * 1024 - len1 - 5 - 11) {
closeSocket(1, -1);
if (LOGS_ENABLED) DEBUG_E("connection(%p) TLS len2 invalid", this);
return;
} else if (newBytesRead < len2 + len1 + 5 + 11) {
if (LOGS_ENABLED) DEBUG_D("connection(%p) TLS client hello wait for more data", this);
bytesRead = newBytesRead;
return;
}
std::memcpy(tempBuffer->bytes + 64 * 1024 + 32, tempBuffer->bytes + 11, 32);
std::memset(tempBuffer->bytes + 11, 0, 32);
uint8_t *temp = new uint8_t[32 + newBytesRead];
memcpy(temp, tempBuffer->bytes + 64 * 1024, 32);
memcpy(temp + 32, tempBuffer->bytes, newBytesRead);
uint32_t outLength;
HMAC(EVP_sha256(), currentSecret.data(), currentSecret.size(), temp, 32 + newBytesRead, tempBuffer->bytes + 64 * 1024, &outLength);
delete[] temp;
if (std::memcmp(tempBuffer->bytes + 64 * 1024, tempBuffer->bytes + 64 * 1024 + 32, 32) != 0) {
tlsHashMismatch = true;
closeSocket(1, -1);
if (LOGS_ENABLED) DEBUG_E("connection(%p) TLS hash mismatch", this);
return;
}
if (LOGS_ENABLED) DEBUG_D("connection(%p) TLS hello complete", this);
tlsState = 1;
proxyAuthState = 0;
bytesRead = 0;
adjustWriteOp();
} else {
std::memcpy(tempBuffer->bytes + bytesRead, buffer->bytes(), (size_t) readCount);
bytesRead = newBytesRead;
}
} else if (proxyAuthState == 2) {
if (readCount == 2) {
uint8_t auth_method = buffer->bytes()[1];
if (auth_method == 0xff) {
@ -281,7 +588,65 @@ void ConnectionSocket::onEvent(uint32_t events) {
if (ConnectionsManager::getInstance(instanceNum).delegate != nullptr) {
ConnectionsManager::getInstance(instanceNum).delegate->onBytesReceived((int32_t) readCount, currentNetworkType, instanceNum);
}
onReceivedData(buffer);
if (tlsState != 0) {
while (buffer->hasRemaining()) {
size_t newBytesRead = (tlsBuffer != nullptr ? tlsBuffer->position() : 0) + buffer->remaining();
if (newBytesRead >= 5) {
if (tlsBuffer == nullptr || tlsBuffer->limit() < 5) {
uint32_t pos = buffer->position();
uint8_t offset = 0;
uint8_t header[5];
if (tlsBuffer != nullptr) {
offset = (uint8_t) tlsBuffer->position();
memcpy(header, tlsBuffer->bytes(), offset);
tlsBuffer->reuse();
}
memcpy(header + offset, buffer->bytes() + pos, (uint8_t) (5 - offset));
static std::string header1 = std::string("\x17\x03\x03", 3);
if (std::memcmp(header1.data(), header, header1.size()) != 0) {
closeSocket(1, -1);
if (LOGS_ENABLED) DEBUG_E("connection(%p) TLS response header1 mismatch", this);
return;
}
uint32_t len1 = (header[3] << 8) + header[4];
if (len1 > 64 * 1024) {
closeSocket(1, -1);
if (LOGS_ENABLED) DEBUG_E("connection(%p) TLS response len1 invalid", this);
return;
} else {
tlsBuffer = BuffersStorage::getInstance().getFreeBuffer(len1);
buffer->position(pos + (5 - offset));
}
} else {
if (LOGS_ENABLED) DEBUG_D("connection(%p) TLS response new data %d", this, buffer->remaining());
}
buffer->limit(std::min(buffer->position() + tlsBuffer->remaining(), buffer->limit()));
tlsBuffer->writeBytes(buffer);
buffer->limit((uint32_t) readCount);
if (tlsBuffer->remaining() == 0) {
tlsBuffer->rewind();
onReceivedData(tlsBuffer);
if (tlsBuffer == nullptr) {
return;
}
tlsBuffer->reuse();
tlsBuffer = nullptr;
} else {
if (LOGS_ENABLED) DEBUG_D("connection(%p) TLS response wait for more data, total size %d, left %d", this, tlsBuffer->limit(), tlsBuffer->remaining());
}
} else {
if (tlsBuffer == nullptr) {
tlsBuffer = BuffersStorage::getInstance().getFreeBuffer(4);
}
tlsBuffer->writeBytes(buffer);
if (LOGS_ENABLED) DEBUG_D("connection(%p) TLS response wait for more data, not enough bytes for header, total = %d", this, (int) tlsBuffer->position());
}
}
} else {
onReceivedData(buffer);
}
}
}
if (readCount != READ_BUFFER_SIZE) {
@ -297,58 +662,90 @@ void ConnectionSocket::onEvent(uint32_t events) {
return;
} else {
if (proxyAuthState != 0) {
if (proxyAuthState == 1) {
lastEventTime = ConnectionsManager::getInstance(instanceNum).getCurrentTimeMonotonicMillis();
proxyAuthState = 2;
buffer[0] = 0x05;
buffer[1] = 0x02;
buffer[2] = 0x00;
buffer[3] = 0x02;
if (send(socketFd, buffer, 4, 0) < 0) {
if (LOGS_ENABLED) DEBUG_E("connection(%p) send failed", this);
closeSocket(1, -1);
return;
if (proxyAuthState >= 10) {
if (proxyAuthState == 10) {
lastEventTime = ConnectionsManager::getInstance(instanceNum).getCurrentTimeMonotonicMillis();
tlsHashMismatch = false;
proxyAuthState = 11;
TlsHello hello = TlsHello::getDefault();
hello.setDomain(currentSecretDomain);
uint32_t size = hello.writeToBuffer(tempBuffer->bytes);
if (!(size = hello.writePadding(tempBuffer->bytes, size))) {
if (LOGS_ENABLED) DEBUG_E("connection(%p) too much data for padding", this);
closeSocket(1, -1);
return;
}
uint32_t outLength;
HMAC(EVP_sha256(), currentSecret.data(), currentSecret.size(), tempBuffer->bytes, size, tempBuffer->bytes + 64 * 1024, &outLength);
int32_t currentTime = ConnectionsManager::getInstance(instanceNum).getCurrentTime();
int32_t old = ((int32_t *) (tempBuffer->bytes + 64 * 1024 + 28))[0];
((int32_t *) (tempBuffer->bytes + 64 * 1024 + 28))[0] = old ^ currentTime;
memcpy(tempBuffer->bytes + 11, tempBuffer->bytes + 64 * 1024, 32);
bytesRead = 0;
if (send(socketFd, tempBuffer->bytes, size, 0) < 0) {
if (LOGS_ENABLED) DEBUG_E("connection(%p) send failed", this);
closeSocket(1, -1);
return;
}
adjustWriteOp();
}
adjustWriteOp();
} else if (proxyAuthState == 3) {
buffer[0] = 0x01;
std::string *proxyUser;
std::string *proxyPassword;
if (!overrideProxyAddress.empty()) {
proxyUser = &overrideProxyUser;
proxyPassword = &overrideProxyPassword;
} else {
proxyUser = &ConnectionsManager::getInstance(instanceNum).proxyUser;
proxyPassword = &ConnectionsManager::getInstance(instanceNum).proxyPassword;
} else {
if (proxyAuthState == 1) {
lastEventTime = ConnectionsManager::getInstance(instanceNum).getCurrentTimeMonotonicMillis();
proxyAuthState = 2;
tempBuffer->bytes[0] = 0x05;
tempBuffer->bytes[1] = 0x02;
tempBuffer->bytes[2] = 0x00;
tempBuffer->bytes[3] = 0x02;
if (send(socketFd, tempBuffer->bytes, 4, 0) < 0) {
if (LOGS_ENABLED) DEBUG_E("connection(%p) send failed", this);
closeSocket(1, -1);
return;
}
adjustWriteOp();
} else if (proxyAuthState == 3) {
tempBuffer->bytes[0] = 0x01;
std::string *proxyUser;
std::string *proxyPassword;
if (!overrideProxyAddress.empty()) {
proxyUser = &overrideProxyUser;
proxyPassword = &overrideProxyPassword;
} else {
proxyUser = &ConnectionsManager::getInstance(instanceNum).proxyUser;
proxyPassword = &ConnectionsManager::getInstance(instanceNum).proxyPassword;
}
uint8_t len1 = (uint8_t) proxyUser->length();
uint8_t len2 = (uint8_t) proxyPassword->length();
tempBuffer->bytes[1] = len1;
memcpy(tempBuffer->bytes + 2, proxyUser->c_str(), len1);
tempBuffer->bytes[2 + len1] = len2;
memcpy(tempBuffer->bytes + 3 + len1, proxyPassword->c_str(), len2);
proxyAuthState = 4;
if (send(socketFd, tempBuffer->bytes, 3 + len1 + len2, 0) < 0) {
if (LOGS_ENABLED) DEBUG_E("connection(%p) send failed", this);
closeSocket(1, -1);
return;
}
adjustWriteOp();
} else if (proxyAuthState == 5) {
tempBuffer->bytes[0] = 0x05;
tempBuffer->bytes[1] = 0x01;
tempBuffer->bytes[2] = 0x00;
tempBuffer->bytes[3] = (uint8_t) (isIpv6 ? 0x04 : 0x01);
uint16_t networkPort = ntohs(currentPort);
inet_pton(isIpv6 ? AF_INET6 : AF_INET, currentAddress.c_str(), tempBuffer->bytes + 4);
memcpy(tempBuffer->bytes + 4 + (isIpv6 ? 16 : 4), &networkPort, sizeof(uint16_t));
proxyAuthState = 6;
if (send(socketFd, tempBuffer->bytes, 4 + (isIpv6 ? 16 : 4) + 2, 0) < 0) {
if (LOGS_ENABLED) DEBUG_E("connection(%p) send failed", this);
closeSocket(1, -1);
return;
}
adjustWriteOp();
}
uint8_t len1 = (uint8_t) proxyUser->length();
uint8_t len2 = (uint8_t) proxyPassword->length();
buffer[1] = len1;
memcpy(&buffer[2], proxyUser->c_str(), len1);
buffer[2 + len1] = len2;
memcpy(&buffer[3 + len1], proxyPassword->c_str(), len2);
proxyAuthState = 4;
if (send(socketFd, buffer, 3 + len1 + len2, 0) < 0) {
if (LOGS_ENABLED) DEBUG_E("connection(%p) send failed", this);
closeSocket(1, -1);
return;
}
adjustWriteOp();
} else if (proxyAuthState == 5) {
buffer[0] = 0x05;
buffer[1] = 0x01;
buffer[2] = 0x00;
buffer[3] = (uint8_t) (isIpv6 ? 0x04 : 0x01);
uint16_t networkPort = ntohs(currentPort);
inet_pton(isIpv6 ? AF_INET6 : AF_INET, currentAddress.c_str(), &buffer[4]);
memcpy(&buffer[4 + (isIpv6 ? 16 : 4)], &networkPort, sizeof(uint16_t));
proxyAuthState = 6;
if (send(socketFd, buffer, 4 + (isIpv6 ? 16 : 4) + 2, 0) < 0) {
if (LOGS_ENABLED) DEBUG_E("connection(%p) send failed", this);
closeSocket(1, -1);
return;
}
adjustWriteOp();
}
} else {
if (!onConnectedSent) {
@ -365,16 +762,50 @@ void ConnectionSocket::onEvent(uint32_t events) {
uint32_t remaining = buffer->remaining();
if (remaining) {
ssize_t sentLength;
if ((sentLength = send(socketFd, buffer->bytes(), remaining, 0)) < 0) {
if (LOGS_ENABLED) DEBUG_E("connection(%p) send failed", this);
closeSocket(1, -1);
return;
} else {
if (ConnectionsManager::getInstance(instanceNum).delegate != nullptr) {
ConnectionsManager::getInstance(instanceNum).delegate->onBytesSent((int32_t) sentLength, currentNetworkType, instanceNum);
if (tlsState != 0) {
if (remaining > 2878) {
remaining = 2878;
}
size_t headersSize = 0;
if (tlsState == 1) {
static std::string header1 = std::string("\x14\x03\x03\x00\x01\x01", 6);
std::memcpy(tempBuffer->bytes, header1.data(), header1.size());
headersSize += header1.size();
tlsState = 2;
}
static std::string header2 = std::string("\x17\x03\x03", 3);
std::memcpy(tempBuffer->bytes + headersSize, header2.data(), header2.size());
headersSize += header2.size();
tempBuffer->bytes[headersSize] = static_cast<uint8_t>((remaining >> 8) & 0xff);
tempBuffer->bytes[headersSize + 1] = static_cast<uint8_t>(remaining & 0xff);
headersSize += 2;
std::memcpy(tempBuffer->bytes + headersSize, buffer->bytes(), remaining);
if ((sentLength = send(socketFd, tempBuffer->bytes, headersSize + remaining, 0)) < headersSize) {
if (LOGS_ENABLED) DEBUG_E("connection(%p) send failed", this);
closeSocket(1, -1);
return;
} else {
if (ConnectionsManager::getInstance(instanceNum).delegate != nullptr) {
ConnectionsManager::getInstance(instanceNum).delegate->onBytesSent((int32_t) sentLength, currentNetworkType, instanceNum);
}
outgoingByteStream->discard((uint32_t) (sentLength - headersSize));
adjustWriteOp();
}
} else {
if ((sentLength = send(socketFd, buffer->bytes(), remaining, 0)) < 0) {
if (LOGS_ENABLED) DEBUG_D("connection(%p) send failed", this);
closeSocket(1, -1);
return;
} else {
if (ConnectionsManager::getInstance(instanceNum).delegate != nullptr) {
ConnectionsManager::getInstance(instanceNum).delegate->onBytesSent((int32_t) sentLength, currentNetworkType, instanceNum);
}
outgoingByteStream->discard((uint32_t) sentLength);
adjustWriteOp();
}
outgoingByteStream->discard((uint32_t) sentLength);
adjustWriteOp();
}
}
}
@ -413,7 +844,7 @@ void ConnectionSocket::adjustWriteOp() {
return;
}
eventMask.events = EPOLLIN | EPOLLRDHUP | EPOLLERR | EPOLLET;
if (proxyAuthState == 0 && (outgoingByteStream->hasData() || !onConnectedSent) || proxyAuthState == 1 || proxyAuthState == 3 || proxyAuthState == 5) {
if (proxyAuthState == 0 && (outgoingByteStream->hasData() || !onConnectedSent) || proxyAuthState == 1 || proxyAuthState == 3 || proxyAuthState == 5 || proxyAuthState == 10) {
eventMask.events |= EPOLLOUT;
}
eventMask.data.ptr = eventObject;
@ -444,6 +875,10 @@ void ConnectionSocket::checkTimeout(int64_t now) {
}
}
bool ConnectionSocket::hasTlsHashMismatch() {
return tlsHashMismatch;
}
void ConnectionSocket::resetLastEventTime() {
lastEventTime = ConnectionsManager::getInstance(instanceNum).getCurrentTimeMonotonicMillis();
}

View file

@ -17,6 +17,7 @@ class NativeByteBuffer;
class ConnectionsManager;
class ByteStream;
class EventObject;
class ByteArray;
class ConnectionSocket {
@ -26,7 +27,7 @@ public:
void writeBuffer(uint8_t *data, uint32_t size);
void writeBuffer(NativeByteBuffer *buffer);
void openConnection(std::string address, uint16_t port, bool ipv6, int32_t networkType);
void openConnection(std::string address, uint16_t port, std::string secret, bool ipv6, int32_t networkType);
void setTimeout(time_t timeout);
time_t getTimeout();
bool isDisconnected();
@ -39,6 +40,7 @@ protected:
void onEvent(uint32_t events);
void checkTimeout(int64_t now);
void resetLastEventTime();
bool hasTlsHashMismatch();
virtual void onReceivedData(NativeByteBuffer *buffer) = 0;
virtual void onDisconnected(int32_t reason, int32_t error) = 0;
virtual void onConnected() = 0;
@ -68,7 +70,14 @@ private:
std::string waitingForHostResolve;
bool adjustWriteOpAfterResolve;
uint8_t buffer[1024];
std::string currentSecret;
std::string currentSecretDomain;
bool tlsHashMismatch = false;
NativeByteBuffer *tlsBuffer = nullptr;
ByteArray *tempBuffer = nullptr;
size_t bytesRead = 0;
int8_t tlsState = 0;
uint8_t proxyAuthState;

View file

@ -625,7 +625,7 @@ void ConnectionsManager::onConnectionClosed(Connection *connection, int reason)
if (connection->getConnectionType() == ConnectionTypeGeneric) {
if (datacenter->getDatacenterId() == currentDatacenterId) {
sendingPing = false;
if (!connection->isSuspended() && proxyAddress.empty()) {
if (!connection->isSuspended() && (proxyAddress.empty() || connection->hasTlsHashMismatch())) {
if (reason == 2) {
disconnectTimeoutAmount += connection->getTimeout();
} else {
@ -641,6 +641,7 @@ void ConnectionsManager::onConnectionClosed(Connection *connection, int reason)
if (disconnectTimeoutAmount >= maxTimeout) {
if (!connection->hasUsefullData()) {
if (LOGS_ENABLED) DEBUG_D("start requesting new address and port due to timeout reach");
requestingSecondAddressByTlsHashMismatch = connection->hasTlsHashMismatch();
requestingSecondAddress = 0;
delegate->onRequestNewServerIpAndPort(requestingSecondAddress, instanceNum);
} else {
@ -976,7 +977,7 @@ TLObject *ConnectionsManager::TLdeserialize(TLObject *request, uint32_t bytes, N
if (request != nullptr) {
TL_api_request *apiRequest = dynamic_cast<TL_api_request *>(request);
if (apiRequest != nullptr) {
object = apiRequest->deserializeResponse(data, bytes, error);
object = apiRequest->deserializeResponse(data, bytes, instanceNum, error);
if (LOGS_ENABLED) DEBUG_D("api request constructor 0x%x, don't parse", constructor);
} else {
object = request->deserializeResponse(data, constructor, instanceNum, error);
@ -1230,15 +1231,22 @@ void ConnectionsManager::processServerResponse(TLObject *message, int64_t messag
} else if (error->error_code == 420) {
int32_t waitTime = 2;
static std::string floodWait = "FLOOD_WAIT_";
static std::string slowmodeWait = "SLOWMODE_WAIT_";
discardResponse = true;
if (error->error_message.find(floodWait) != std::string::npos) {
std::string num = error->error_message.substr(floodWait.size(), error->error_message.size() - floodWait.size());
waitTime = atoi(num.c_str());
if (waitTime <= 0) {
waitTime = 2;
}
} else if (error->error_message.find(slowmodeWait) != std::string::npos) {
std::string num = error->error_message.substr(slowmodeWait.size(), error->error_message.size() - slowmodeWait.size());
waitTime = atoi(num.c_str());
if (waitTime <= 0) {
waitTime = 2;
}
discardResponse = false;
}
discardResponse = true;
request->failedByFloodWait = waitTime;
request->startTime = 0;
request->startTimeMillis = 0;
@ -1431,7 +1439,7 @@ void ConnectionsManager::processServerResponse(TLObject *message, int64_t messag
datacenter->addServerSalt(salt);
saveConfig();
requestSaltsForDatacenter(datacenter);
requestSaltsForDatacenter(datacenter, connection->getConnectionType() == ConnectionTypeTemp);
if (datacenter->hasAuthKey(ConnectionTypeGeneric, 1)) {
processRequestQueue(AllConnectionTypes, datacenter->getDatacenterId());
}
@ -1873,7 +1881,7 @@ void ConnectionsManager::cancelRequest(int32_t token, bool notifyServer) {
void ConnectionsManager::onDatacenterHandshakeComplete(Datacenter *datacenter, HandshakeType type, int32_t timeDiff) {
saveConfig();
uint32_t datacenterId = datacenter->getDatacenterId();
if (datacenterId == currentDatacenterId || datacenterId == movingToDatacenterId) {
if (datacenterId == currentDatacenterId || datacenterId == movingToDatacenterId || updatingDcSettingsWorkaround || updatingDcSettings) {
timeDifference = timeDiff;
datacenter->recreateSessions(type);
clearRequestsForDatacenter(datacenter, type);
@ -1953,15 +1961,19 @@ void ConnectionsManager::sendMessagesToConnectionWithConfirmation(std::vector<st
sendMessagesToConnection(messages, connection, reportAck);
}
void ConnectionsManager::requestSaltsForDatacenter(Datacenter *datacenter) {
if (std::find(requestingSaltsForDc.begin(), requestingSaltsForDc.end(), datacenter->getDatacenterId()) != requestingSaltsForDc.end()) {
void ConnectionsManager::requestSaltsForDatacenter(Datacenter *datacenter, bool useTempConnection) {
uint32_t id = datacenter->getDatacenterId();
if (useTempConnection) {
id |= 0x80000000;
}
if (std::find(requestingSaltsForDc.begin(), requestingSaltsForDc.end(), id) != requestingSaltsForDc.end()) {
return;
}
requestingSaltsForDc.push_back(datacenter->getDatacenterId());
TL_get_future_salts *request = new TL_get_future_salts();
request->num = 32;
sendRequest(request, [&, datacenter](TLObject *response, TL_error *error, int32_t networkType) {
std::vector<uint32_t>::iterator iter = std::find(requestingSaltsForDc.begin(), requestingSaltsForDc.end(), datacenter->getDatacenterId());
sendRequest(request, [&, datacenter, id](TLObject *response, TL_error *error, int32_t networkType) {
std::vector<uint32_t>::iterator iter = std::find(requestingSaltsForDc.begin(), requestingSaltsForDc.end(), id);
if (iter != requestingSaltsForDc.end()) {
requestingSaltsForDc.erase(iter);
}
@ -1970,7 +1982,7 @@ void ConnectionsManager::requestSaltsForDatacenter(Datacenter *datacenter) {
datacenter->mergeServerSalts(res->salts);
saveConfig();
}
}, nullptr, RequestFlagWithoutLogin | RequestFlagEnableUnauthorized | RequestFlagUseUnboundKey, datacenter->getDatacenterId(), ConnectionTypeGeneric, true);
}, nullptr, RequestFlagWithoutLogin | RequestFlagEnableUnauthorized | RequestFlagUseUnboundKey, datacenter->getDatacenterId(), useTempConnection ? ConnectionTypeTemp : ConnectionTypeGeneric, true);
}
void ConnectionsManager::clearRequestsForDatacenter(Datacenter *datacenter, HandshakeType type) {
@ -2374,7 +2386,7 @@ void ConnectionsManager::processRequestQueue(uint32_t connectionTypes, uint32_t
} else {
currentCount = 0;
}
if (!networkAvailable || currentCount >= 10) {
if (!networkAvailable || currentCount >= 12) {
iter++;
continue;
}
@ -2691,14 +2703,85 @@ std::unique_ptr<TLObject> ConnectionsManager::wrapInLayer(TLObject *object, Data
return std::unique_ptr<TLObject>(object);
}
inline std::string hexStr(unsigned char *data, uint32_t len) {
constexpr char hexmap[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
std::string s(len * 2, ' ');
for (uint32_t i = 0; i < len; ++i) {
s[2 * i] = hexmap[(data[i] & 0xF0) >> 4];
s[2 * i + 1] = hexmap[data[i] & 0x0F];
static const char *const url_symbols64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
static unsigned char url_char_to_value[256];
static void init_base64url_table() {
static bool is_inited = []() {
std::fill(std::begin(url_char_to_value), std::end(url_char_to_value), static_cast<unsigned char>(64));
for (unsigned char i = 0; i < 64; i++) {
url_char_to_value[static_cast<size_t>(url_symbols64[i])] = i;
}
return true;
}();
assert(is_inited);
}
std::string base64UrlDecode(std::string base64) {
init_base64url_table();
size_t padding_length = 0;
while (!base64.empty() && base64.back() == '=') {
padding_length++;
}
return s;
if (padding_length >= 3 || (padding_length > 0 && ((base64.size() + padding_length) & 3) != 0)) {
return "";
}
if ((base64.size() & 3) == 1) {
return "";
}
std::string output;
size_t size = base64.size() - padding_length;
output.reserve(((base64.size() + 3) >> 2) * 3);
for (size_t i = 0; i < size;) {
size_t left = std::min(size - i, static_cast<size_t>(4));
int c = 0;
for (size_t t = 0; t < left; t++) {
auto value = url_char_to_value[base64.c_str()[i++]];
if (value == 64) {
return "";
}
c |= value << ((3 - t) * 6);
}
output += static_cast<char>(static_cast<unsigned char>(c >> 16));
if (left == 2) {
if ((c & ((1 << 16) - 1)) != 0) {
return "";
}
} else {
output += static_cast<char>(static_cast<unsigned char>(c >> 8));
if (left == 3) {
if ((c & ((1 << 8) - 1)) != 0) {
return "";
}
} else {
output += static_cast<char>(static_cast<unsigned char>(c));
}
}
}
return output;
}
inline std::string decodeSecret(std::string secret) {
bool allHex = true;
for (size_t i = 0; i < secret.size(); i++) {
if (!(secret[i] >= '0' && secret[i] <= '9' || secret[i] >= 'a' && secret[i] <= 'f' || secret[i] >= 'A' && secret[i] <= 'F')) {
allHex = false;
break;
}
}
if (allHex) {
size_t size = secret.size() / 2;
char *result = new char[size];
for (int32_t i = 0; i < size; i++) {
result[i] = (char) (char2int(secret[i * 2]) * 16 + char2int(secret[i * 2 + 1]));
}
secret = std::string(result, size);
delete[] result;
return secret;
}
return base64UrlDecode(secret);
}
void ConnectionsManager::updateDcSettings(uint32_t dcNum, bool workaround) {
@ -2764,7 +2847,7 @@ void ConnectionsManager::updateDcSettings(uint32_t dcNum, bool workaround) {
}
std::string secret;
if (dcOption->secret != nullptr) {
secret = hexStr(dcOption->secret->bytes, dcOption->secret->length);
secret = std::string((const char *) dcOption->secret->bytes, dcOption->secret->length);
}
if (LOGS_ENABLED) DEBUG_D("getConfig add %s:%d to dc%d, flags %d, has secret = %d[%d]", dcOption->ip_address.c_str(), dcOption->port, dcOption->id, dcOption->flags, dcOption->secret != nullptr ? 1 : 0, dcOption->secret != nullptr ? dcOption->secret->length : 0);
addresses->push_back(TcpAddress(dcOption->ip_address, dcOption->port, dcOption->flags, secret));
@ -2946,12 +3029,20 @@ inline bool checkPhoneByPrefixesRules(std::string phone, std::string rules) {
return found;
}
void ConnectionsManager::applyDnsConfig(NativeByteBuffer *buffer, std::string phone) {
scheduleTask([&, buffer, phone] {
void ConnectionsManager::applyDnsConfig(NativeByteBuffer *buffer, std::string phone, int32_t date) {
scheduleTask([&, buffer, phone, date] {
int32_t realDate = date;
if (LOGS_ENABLED) DEBUG_D("trying to decrypt config %d", requestingSecondAddress);
TL_help_configSimple *config = Datacenter::decodeSimpleConfig(buffer);
if (config != nullptr && realDate == 0) {
realDate = config->date;
}
int currentDate = getCurrentTime();
if (config != nullptr && config->date <= currentDate && currentDate <= config->expires) {
if (realDate > 0 && requestingSecondAddressByTlsHashMismatch) {
timeDifference = realDate - currentDate;
requestingSecondAddressByTlsHashMismatch = false;
}
for (std::vector<std::unique_ptr<TL_accessPointRule>>::iterator iter = config->rules.begin(); iter != config->rules.end(); iter++) {
TL_accessPointRule *rule = iter->get();
if (!checkPhoneByPrefixesRules(phone, rule->phone_prefix_rules)) {
@ -2969,7 +3060,7 @@ void ConnectionsManager::applyDnsConfig(NativeByteBuffer *buffer, std::string ph
if (LOGS_ENABLED) DEBUG_D("got address %s and port %d for dc%d", ipPort->ipv4.c_str(), ipPort->port, rule->dc_id);
} else if (typeInfo == typeid(TL_ipPortSecret)) {
TL_ipPortSecret *ipPort = (TL_ipPortSecret *) port;
addresses.push_back(TcpAddress(ipPort->ipv4, ipPort->port, 0, hexStr(ipPort->secret->bytes, ipPort->secret->length)));
addresses.push_back(TcpAddress(ipPort->ipv4, ipPort->port, 0, std::string((const char *) ipPort->secret->bytes, ipPort->secret->length)));
if (LOGS_ENABLED) DEBUG_D("got address %s and port %d for dc%d with secret", ipPort->ipv4.c_str(), ipPort->port, rule->dc_id);
}
}
@ -2999,9 +3090,6 @@ void ConnectionsManager::applyDnsConfig(NativeByteBuffer *buffer, std::string ph
if (requestingSecondAddress == 0) {
requestingSecondAddress = 1;
delegate->onRequestNewServerIpAndPort(requestingSecondAddress, instanceNum);
} else if (requestingSecondAddress == 1) {
requestingSecondAddress = 2;
delegate->onRequestNewServerIpAndPort(requestingSecondAddress, instanceNum);
} else {
requestingSecondAddress = 0;
}
@ -3060,13 +3148,14 @@ void ConnectionsManager::init(uint32_t version, int32_t layer, int32_t apiId, st
void ConnectionsManager::setProxySettings(std::string address, uint16_t port, std::string username, std::string password, std::string secret) {
scheduleTask([&, address, port, username, password, secret] {
bool secretChanged = proxySecret != secret;
std::string newSecret = decodeSecret(secret);
bool secretChanged = proxySecret != newSecret;
bool reconnect = proxyAddress != address || proxyPort != port || username != proxyUser || proxyPassword != password || secretChanged;
proxyAddress = address;
proxyPort = port;
proxyUser = username;
proxyPassword = password;
proxySecret = secret;
proxySecret = std::move(newSecret);
if (!proxyAddress.empty() && connectionState == ConnectionStateConnecting) {
connectionState = ConnectionStateConnectingViaProxy;
if (delegate != nullptr) {
@ -3119,6 +3208,7 @@ void ConnectionsManager::setRegId(std::string regId) {
for (std::map<uint32_t, Datacenter *>::iterator iter = datacenters.begin(); iter != datacenters.end(); iter++) {
iter->second->resetInitVersion();
}
updateDcSettings(0, false);
saveConfig();
});
}
@ -3206,7 +3296,7 @@ int64_t ConnectionsManager::checkProxy(std::string address, uint16_t port, std::
proxyCheckInfo->port = port;
proxyCheckInfo->username = username;
proxyCheckInfo->password = password;
proxyCheckInfo->secret = secret;
proxyCheckInfo->secret = decodeSecret(secret);
proxyCheckInfo->onRequestTime = requestTimeFunc;
proxyCheckInfo->pingId = ++lastPingProxyId;
proxyCheckInfo->instanceNum = instanceNum;

View file

@ -69,7 +69,7 @@ public:
void setSystemLangCode(std::string langCode);
void updateDcSettings(uint32_t datacenterId, bool workaround);
void setPushConnectionEnabled(bool value);
void applyDnsConfig(NativeByteBuffer *buffer, std::string phone);
void applyDnsConfig(NativeByteBuffer *buffer, std::string phone, int32_t date);
void setMtProtoVersion(int version);
int32_t getMtProtoVersion();
int64_t checkProxy(std::string address, uint16_t port, std::string username, std::string password, std::string secret, onRequestTimeFunc requestTimeFunc, jobject ptr1);
@ -92,7 +92,7 @@ private:
void sendPing(Datacenter *datacenter, bool usePushConnection);
void sendMessagesToConnection(std::vector<std::unique_ptr<NetworkMessage>> &messages, Connection *connection, bool reportAck);
void sendMessagesToConnectionWithConfirmation(std::vector<std::unique_ptr<NetworkMessage>> &messages, Connection *connection, bool reportAck);
void requestSaltsForDatacenter(Datacenter *datacenter);
void requestSaltsForDatacenter(Datacenter *datacenter, bool useTempConnection);
void clearRequestsForDatacenter(Datacenter *datacenter, HandshakeType type);
void registerForInternalPushUpdates();
void processRequestQueue(uint32_t connectionType, uint32_t datacenterId);
@ -153,6 +153,7 @@ private:
bool updatingDcSettings = false;
bool updatingDcSettingsWorkaround = false;
int32_t disconnectTimeoutAmount = 0;
bool requestingSecondAddressByTlsHashMismatch = false;
int32_t requestingSecondAddress = 0;
int32_t updatingDcStartTime = 0;
int32_t lastDcUpdateTime = 0;

View file

@ -43,17 +43,6 @@ Datacenter::Datacenter(int32_t instance, uint32_t id) {
}
}
inline char char2int(char input) {
if (input >= '0' && input <= '9') {
return input - '0';
} else if (input >= 'A' && input <= 'F') {
return (char) (input - 'A' + 10);
} else if (input >= 'a' && input <= 'f') {
return (char) (input - 'a' + 10);
}
return 0;
}
Datacenter::Datacenter(int32_t instance, NativeByteBuffer *data) {
instanceNum = instance;
for (uint32_t a = 0; a < UPLOAD_CONNECTIONS_COUNT; a++) {
@ -108,8 +97,19 @@ Datacenter::Datacenter(int32_t instance, NativeByteBuffer *data) {
} else {
flags = 0;
}
if (currentVersion >= 9) {
if (currentVersion >= 11) {
secret = data->readString(nullptr);
} else if (currentVersion >= 9) {
secret = data->readString(nullptr);
if (!secret.empty()) {
size_t size = secret.size() / 2;
char *result = new char[size];
for (int32_t i = 0; i < size; i++) {
result[i] = (char) (char2int(secret[i * 2]) * 16 + char2int(secret[i * 2 + 1]));
}
secret = std::string(result, size);
delete[] result;
}
}
(*array).push_back(TcpAddress(address, port, flags, secret));
}

View file

@ -122,7 +122,7 @@ private:
std::vector<std::unique_ptr<Handshake>> handshakes;
const uint32_t configVersion = 10;
const uint32_t configVersion = 11;
const uint32_t paramsConfigVersion = 1;
Connection *createProxyConnection(uint8_t num);

View file

@ -179,4 +179,15 @@ inline std::string to_string_uint64(uint64_t value) {
return std::string(buf, (uint32_t) len);
}
inline int32_t char2int(char input) {
if (input >= '0' && input <= '9') {
return input - '0';
} else if (input >= 'A' && input <= 'F') {
return (char) (input - 'A' + 10);
} else if (input >= 'a' && input <= 'f') {
return (char) (input - 'a' + 10);
}
return 0;
}
#endif

View file

@ -92,7 +92,7 @@ bool TL_api_request::isNeedLayer() {
return true;
}
TLObject *TL_api_request::deserializeResponse(NativeByteBuffer *stream, uint32_t bytes, bool &error) {
TLObject *TL_api_request::deserializeResponse(NativeByteBuffer *stream, uint32_t bytes, int32_t instanceNum, bool &error) {
TL_api_response *result = new TL_api_response();
result->readParamsEx(stream, bytes, error);
return result;

View file

@ -21,7 +21,6 @@ class TLClassStore {
public:
static TLObject *TLdeserialize(NativeByteBuffer *stream, uint32_t bytes, uint32_t constructor, int32_t instanceNum, bool &error);
};
class TL_api_request : public TLObject {
@ -31,7 +30,7 @@ public:
~TL_api_request();
bool isNeedLayer();
TLObject *deserializeResponse(NativeByteBuffer *stream, uint32_t bytes, bool &error);
TLObject *deserializeResponse(NativeByteBuffer *stream, uint32_t bytes, int32_t instanceNum, bool &error);
void serializeToStream(NativeByteBuffer *stream);
};

View file

@ -229,14 +229,6 @@
</intent-filter>
</receiver>
<receiver
android:name=".SmsReceiver"
android:exported="true">
<intent-filter>
<action android:name="com.google.android.gms.auth.api.phone.SMS_RETRIEVED"/>
</intent-filter>
</receiver>
<receiver android:name=".CallReceiver">
<intent-filter>
<action android:name="android.intent.action.PHONE_STATE"/>
@ -276,7 +268,6 @@
<service android:name=".BringAppForegroundService" android:enabled="true"/>
<service android:name=".NotificationsService" android:enabled="true"/>
<service android:name=".NotificationRepeat" android:exported="false"/>
<service android:name=".ClearCacheService" android:exported="false"/>
<service android:name=".VideoEncodingService" android:enabled="true"/>
<service android:name=".LocationSharingService" android:enabled="true"/>
<service android:name=".voip.VoIPService" android:enabled="true"/>

View file

@ -22,7 +22,7 @@ key_chat_messagePanelVoiceLock=-1
chat_secretChatStatusText=-9997953
switchTrack=-11314335
chat_inPreviewInstantSelectedText=-11099429
chat_attachAudioBackground=-1267376
chat_attachAudioBackground=-1282464
actionBarDefaultSubmenuBackground=-13749706
switchTrackBlueThumb=-14473945
avatar_nameInMessageViolet=-5925398
@ -49,7 +49,7 @@ switch2Track=-2135965
chats_menuPhoneCats=-8287602
chat_outPreviewLine=-5515009
dialogScrollGlow=-1708041
chat_messagePanelHint=-10459539
chat_messagePanelHint=-10064780
windowBackgroundGray=-15197927
chat_inViaBotNameText=-9456666
chat_outVoiceSeekbar=-1300913456
@ -95,7 +95,7 @@ chat_topPanelLine=-9456666
chat_inReplyMessageText=-251658241
windowBackgroundWhiteInputFieldActivated=-10636041
dialogInputField=-11248027
chat_attachGalleryBackground=-6192928
chat_attachGalleryBackground=-11037210
chat_outInstantSelected=-1
chat_outSentCheck=-7156228
key_graySectionText=-9075309
@ -158,6 +158,7 @@ dialogTextRed2=-892058
chats_nameMessageArchived=-9011322
avatar_nameInMessageOrange=-1265812
chats_pinnedIcon=-10524305
chat_attachActiveTab=-12341003
chat_replyPanelLine=1907997
avatar_subtitleInProfileOrange=-7697782
chat_outSentCheckSelected=-7156228
@ -220,6 +221,7 @@ dialogRoundCheckBox=-9912583
chat_emojiPanelTrendingTitle=-2167820
actionBarTabLine=-10510610
switchThumbChecked=-13600600
chat_stickersHintPanel=-13748673
chats_nameMessageArchived_threeLines=-1644826
chat_outSiteNameText=-5515009
windowBackgroundWhite=-14737118
@ -283,12 +285,13 @@ avatar_nameInMessagePink=-1215324
windowBackgroundWhiteGrayText=-9603715
musicPicker_buttonBackground=-11035162
avatar_actionBarSelectorViolet=-11972268
chat_attachPollBackground=-1263011
avatar_nameInMessageBlue=-9456666
dialogTextBlack=-328966
actionBarDefault=-14276309
profile_actionIcon=-1
windowBackgroundUnchecked=-14473945
actionBarDefaultSelector=-196521644
actionBarDefaultSelector=-1102491308
chats_menuTopShadow=-1558504677
chat_outAudioPerfomerText=-6965025
sharedMedia_startStopLoadIcon=-11164432
@ -307,6 +310,7 @@ dialogBadgeBackground=-10371847
chat_outBubbleSelected=-12487769
avatar_backgroundInProfileBlue=-11232035
chat_inFileNameText=-1
chat_attachEmptyImage=-11840420
inappPlayerPerformer=-1
chat_inInstantSelected=-9456666
chat_outFileInfoText=-6965025
@ -341,7 +345,7 @@ key_player_progressCachedBackground=-12433330
chat_outTimeText=-6965025
chat_outBubble=-12687992
avatar_backgroundActionBarCyan=-14605274
chat_attachFileBackground=-10706196
chat_attachFileBackground=-11291668
chat_attachHideBackground=-14078156
chats_menuItemText=-986896
chats_message=-9011322
@ -371,7 +375,7 @@ player_background=-14407896
inappPlayerClose=-10525075
chat_outMediaIcon=-1
player_actionBarSubtitle=-9339518
chat_attachContactBackground=-10438416
chat_attachContactBackground=-1265579
chat_outAudioCacheSeekbar=-1218212423
chats_sentClock=-8740661
chat_inAudioSeekbar=-581869200
@ -382,7 +386,7 @@ chat_inPreviewInstantText=-9456666
chats_archiveBackground=-10642482
chat_inViews=-8812137
chat_outLoaderSelected=-9194520
dialogButtonSelector=352321535
dialogButtonSelector=1229541716
chats_archivePinBackground=-13749706
player_actionBarItems=-1
chat_sentError=-1551526

View file

@ -20,7 +20,7 @@ key_chat_messagePanelVoiceLock=-1
chat_secretChatStatusText=-8812137
switchTrack=-10984850
chat_inPreviewInstantSelectedText=-5648402
chat_attachAudioBackground=-619421
chat_attachAudioBackground=-626837
location_sendLocationBackground=-9919529
actionBarDefaultSubmenuBackground=-14075831
switchTrackBlueThumb=-14866637
@ -47,7 +47,7 @@ key_sheet_other=1140850687
chat_inContactNameText=-8796932
chats_menuPhoneCats=-11049613
chat_outPreviewLine=-6631937
chat_messagePanelHint=-11180684
chat_messagePanelHint=-9798256
windowBackgroundGray=-15393241
chat_inViaBotNameText=-8796932
chat_outVoiceSeekbar=-429551165
@ -62,6 +62,7 @@ chat_emojiPanelBackspace=-9996665
chat_replyPanelClose=-10062202
chat_inContactPhoneSelectedText=-7490861
dialogSearchText=-1
actionBarTabUnactiveText=-7628894
chat_outAudioTitleText=-1
chat_emojiPanelBackground=-14866637
chats_unreadCounter=-10177041
@ -84,6 +85,7 @@ files_folderIconBackground=-13286315
passport_authorizeBackgroundSelected=-11627561
switchTrackBlueChecked=-8333825
player_seekBarBackground=1196577362
dialogShadowLine=335544320
groupcreate_onlineText=-10177041
profile_status=-9192457
divider=-1795162112
@ -91,6 +93,7 @@ chat_topPanelLine=-11108183
chat_inReplyMessageText=-1
dialogInputField=-8549479
windowBackgroundWhiteInputFieldActivated=-9522449
chat_attachGalleryBackground=-11692299
chat_outInstantSelected=-4268038
chat_outSentCheck=-7878657
key_graySectionText=-8549479
@ -153,6 +156,7 @@ dialogTextRed2=-1152913
chats_nameMessageArchived=-8549479
avatar_nameInMessageOrange=-13984
chats_pinnedIcon=-10982016
chat_attachActiveTab=-9781249
chat_replyPanelLine=1779898909
avatar_subtitleInProfileOrange=-7628894
chat_outSentCheckSelected=-4268038
@ -163,6 +167,7 @@ avatar_backgroundGroupCreateSpanBlue=-13803892
dialogTextBlue3=-10177041
switchTrackBlueThumbChecked=-11632213
dialogTextBlue4=-10177041
chat_attachUnactiveTab=-9596506
windowBackgroundWhiteGreenText=-10371737
actionBarTabActiveText=-9781249
chat_emojiPanelIcon=-9996665
@ -221,6 +226,7 @@ chat_inVoiceSeekbarSelected=-9203285
dialogTextGray=-8549479
chat_messageLinkOut=-6631937
avatar_backgroundArchived=-13087910
picker_badge=-11097097
chat_outFileInfoSelectedText=-4268038
chats_tabletSelectedOverlay=268435455
chat_outAudioDurationSelectedText=-4268038
@ -269,10 +275,12 @@ profile_verifiedCheck=-1
listSelectorSDK21=301989887
key_chat_messagePanelVoiceLockBackground=-13548712
chat_outFileNameText=-1
picker_enabledButton=-9781249
inappPlayerBackground=-14602949
avatar_nameInMessagePink=-624741
windowBackgroundWhiteGrayText=-8549479
avatar_actionBarSelectorViolet=-12758164
chat_attachPollBackground=-2183099
avatar_nameInMessageBlue=-8796932
dialogTextBlack=-592138
actionBarDefault=-14602949
@ -334,7 +342,7 @@ key_player_progressCachedBackground=-11245182
chat_outTimeText=-7357217
chat_outBubble=-12689014
avatar_backgroundActionBarCyan=-14602949
chat_attachFileBackground=-11359756
chat_attachFileBackground=-10830604
chat_attachHideBackground=-14074026
chats_menuItemText=-369098753
chats_message=-8549479
@ -365,6 +373,7 @@ chat_outMediaIcon=-1
chats_message_threeLines=-8549479
player_actionBarSubtitle=-8549479
chat_outAudioCacheSeekbar=-10120765
chat_attachContactBackground=-2183099
chats_sentClock=-11772054
chat_inAudioSeekbar=-11443856
avatar_subtitleInProfileRed=-7628894
@ -375,7 +384,7 @@ chats_archiveBackground=-11036980
dialog_liveLocationProgress=-9919529
chat_inViews=-8812137
chat_outLoaderSelected=-9919529
dialogButtonSelector=352321535
dialogButtonSelector=-13483690
chats_archivePinBackground=-13746613
player_actionBarItems=-1
chat_sentError=-633010

View file

@ -24,6 +24,7 @@ import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.content.res.AssetFileDescriptor;
import android.content.res.Configuration;
import android.database.ContentObserver;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.Color;
@ -40,6 +41,7 @@ import android.net.Uri;
import android.os.Build;
import android.os.Environment;
import android.os.PowerManager;
import android.provider.CallLog;
import android.provider.DocumentsContract;
import android.provider.MediaStore;
import android.provider.Settings;
@ -1317,6 +1319,8 @@ public class AndroidUtilities {
}
}*/
private static ContentObserver callLogContentObserver;
private static Runnable unregisterRunnable;
private static boolean hasCallPermissions = Build.VERSION.SDK_INT >= 23;
@SuppressWarnings("unchecked")
@ -1333,9 +1337,38 @@ public class AndroidUtilities {
telephonyService = (ITelephony) m.invoke(tm);
telephonyService.silenceRinger();
telephonyService.endCall();
} catch (Throwable e) {
FileLog.e(e);
}
}
public static String obtainLoginPhoneCall(String pattern) {
if (!hasCallPermissions) {
return null;
}
try (Cursor cursor = ApplicationLoader.applicationContext.getContentResolver().query(
CallLog.Calls.CONTENT_URI,
new String[]{CallLog.Calls.NUMBER, CallLog.Calls.DATE},
CallLog.Calls.TYPE + " IN (" + CallLog.Calls.MISSED_TYPE + "," + CallLog.Calls.INCOMING_TYPE + "," + CallLog.Calls.REJECTED_TYPE + ")",
null,
"date DESC LIMIT 5")) {
while (cursor.moveToNext()) {
String number = cursor.getString(0);
long date = cursor.getLong(1);
if (BuildVars.LOGS_ENABLED) {
FileLog.e("number = " + number);
}
if (Math.abs(System.currentTimeMillis() - date) >= 60 * 60 * 1000) {
continue;
}
if (checkPhonePattern(pattern, number)) {
return number;
}
}
} catch (Exception e) {
FileLog.e(e);
}
return null;
}
public static boolean checkPhonePattern(String pattern, String phone) {

View file

@ -15,12 +15,14 @@ public class AnimatedFileDrawableStream implements FileLoadOperationStream {
private final Object sync = new Object();
private int lastOffset;
private boolean waitingForLoad;
private boolean preview;
public AnimatedFileDrawableStream(TLRPC.Document d, Object p, int a) {
public AnimatedFileDrawableStream(TLRPC.Document d, Object p, int a, boolean prev) {
document = d;
parentObject = p;
currentAccount = a;
loadOperation = FileLoader.getInstance(currentAccount).loadStreamFile(this, document, parentObject, 0);
preview = prev;
loadOperation = FileLoader.getInstance(currentAccount).loadStreamFile(this, document, parentObject, 0, preview);
}
public int read(int offset, int readLength) {
@ -37,8 +39,8 @@ public class AnimatedFileDrawableStream implements FileLoadOperationStream {
while (availableLength == 0) {
availableLength = loadOperation.getDownloadedLengthFromOffset(offset, readLength);
if (availableLength == 0) {
if (loadOperation.isPaused() || lastOffset != offset) {
FileLoader.getInstance(currentAccount).loadStreamFile(this, document, parentObject, offset);
if (loadOperation.isPaused() || lastOffset != offset || preview) {
FileLoader.getInstance(currentAccount).loadStreamFile(this, document, parentObject, offset, preview);
}
synchronized (sync) {
if (canceled) {
@ -46,7 +48,9 @@ public class AnimatedFileDrawableStream implements FileLoadOperationStream {
}
countDownLatch = new CountDownLatch(1);
}
FileLoader.getInstance(currentAccount).setLoadingVideo(document, false, true);
if (!preview) {
FileLoader.getInstance(currentAccount).setLoadingVideo(document, false, true);
}
waitingForLoad = true;
countDownLatch.await();
waitingForLoad = false;
@ -68,7 +72,7 @@ public class AnimatedFileDrawableStream implements FileLoadOperationStream {
synchronized (sync) {
if (countDownLatch != null) {
countDownLatch.countDown();
if (removeLoading && !canceled) {
if (removeLoading && !canceled && !preview) {
FileLoader.getInstance(currentAccount).removeLoadingVideo(document, false, true);
}
}
@ -90,6 +94,10 @@ public class AnimatedFileDrawableStream implements FileLoadOperationStream {
return document;
}
public boolean isPreview() {
return preview;
}
public int getCurrentAccount() {
return currentAccount;
}

View file

@ -53,6 +53,8 @@ public class ApplicationLoader extends Application {
public static volatile boolean mainInterfacePausedStageQueue = true;
public static volatile long mainInterfacePausedStageQueueTime;
public static boolean hasPlayServices;
public static File getFilesDirFixed() {
for (int a = 0; a < 10; a++) {
File path = ApplicationLoader.applicationContext.getFilesDir();
@ -140,7 +142,6 @@ public class ApplicationLoader extends Application {
TLRPC.User user = UserConfig.getInstance(a).getCurrentUser();
if (user != null) {
MessagesController.getInstance(a).putUser(user, true);
MessagesController.getInstance(a).getBlockedUsers(true);
SendMessagesHelper.getInstance(a).checkUnsentMessages();
}
}
@ -221,7 +222,7 @@ public class ApplicationLoader extends Application {
private void initPlayServices() {
AndroidUtilities.runOnUIThread(() -> {
if (checkPlayServices()) {
if (hasPlayServices = checkPlayServices()) {
final String currentPushString = SharedConfig.pushString;
if (!TextUtils.isEmpty(currentPushString)) {
if (BuildVars.DEBUG_PRIVATE_VERSION && BuildVars.LOGS_ENABLED) {

View file

@ -23,6 +23,7 @@ public class BringAppForegroundService extends IntentService {
protected void onHandleIntent(Intent intent) {
Intent intent2 = new Intent(this, LaunchActivity.class);
intent2.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent2.setAction(Intent.ACTION_MAIN);
startActivity(intent2);
}
}

View file

@ -18,8 +18,8 @@ public class BuildVars {
public static boolean LOGS_ENABLED = false;
public static boolean USE_CLOUD_STRINGS = true;
public static boolean CHECK_UPDATES = false;
public static int BUILD_VERSION = 1648;
public static String BUILD_VERSION_STRING = "5.9.0";
public static int BUILD_VERSION = 1684;
public static String BUILD_VERSION_STRING = "5.10.0";
public static int APP_ID = 0; //obtain your own APP_ID at https://core.telegram.org/api/obtaining_api_id
public static String APP_HASH = ""; //obtain your own APP_HASH at https://core.telegram.org/api/obtaining_api_id
public static String HOCKEY_APP_HASH = "your-hockeyapp-api-key-here";

View file

@ -1,56 +0,0 @@
/*
* This is the source code of Telegram for Android v. 5.x.x.
* It is licensed under GNU GPL v. 2 or later.
* You should have received a copy of the license in this archive (see LICENSE).
*
* Copyright Nikolai Kudashov, 2013-2018.
*/
package org.telegram.messenger;
import android.app.IntentService;
import android.content.Intent;
import android.content.SharedPreferences;
import android.util.SparseArray;
import java.io.File;
public class ClearCacheService extends IntentService {
public ClearCacheService() {
super("ClearCacheService");
}
@Override
protected void onHandleIntent(Intent intent) {
ApplicationLoader.postInitApplication();
SharedPreferences preferences = MessagesController.getGlobalMainSettings();
final int keepMedia = preferences.getInt("keep_media", 2);
if (keepMedia == 2) {
return;
}
Utilities.globalQueue.postRunnable(() -> {
int days;
if (keepMedia == 0) {
days = 7;
} else if (keepMedia == 1) {
days = 30;
} else {
days = 3;
}
long currentTime = System.currentTimeMillis() / 1000 - 60 * 60 * 24 * days;
final SparseArray<File> paths = ImageLoader.getInstance().createMediaPaths();
for (int a = 0; a < paths.size(); a++) {
if (paths.keyAt(a) == FileLoader.MEDIA_DIR_CACHE) {
continue;
}
try {
Utilities.clearDir(paths.valueAt(a).getAbsolutePath(), 0, currentTime);
} catch (Throwable e) {
FileLog.e(e);
}
}
});
}
}

View file

@ -211,7 +211,7 @@ public class DownloadController extends BaseController implements NotificationCe
mediumPreset = new Preset(preferences.getString("preset1", "13_13_13_13_1048576_10485760_1048576_524288_1_1_1_0"));
highPreset = new Preset(preferences.getString("preset2", "13_13_13_13_1048576_15728640_3145728_524288_1_1_1_0"));
boolean newConfig;
if (newConfig = preferences.contains("newConfig") || !getUserConfig().isClientActivated()) {
if ((newConfig = preferences.contains("newConfig")) || !getUserConfig().isClientActivated()) {
mobilePreset = new Preset(preferences.getString("mobilePreset", mediumPreset.toString()));
wifiPreset = new Preset(preferences.getString("wifiPreset", highPreset.toString()));
roamingPreset = new Preset(preferences.getString("roamingPreset", lowPreset.toString()));

View file

@ -22,6 +22,7 @@ import java.io.File;
import java.nio.channels.FileChannel;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Scanner;
import java.util.concurrent.CountDownLatch;
import java.util.zip.GZIPInputStream;
@ -114,6 +115,8 @@ public class FileLoadOperation {
private int totalBytesCount;
private int bytesCountPadding;
private int streamStartOffset;
private int streamPriorityStartOffset;
private RequestInfo priorityRequestInfo;
private FileLoadOperationDelegate delegate;
private byte[] key;
private byte[] iv;
@ -386,6 +389,23 @@ public class FileLoadOperation {
break;
}
}
Collections.sort(ranges, (o1, o2) -> {
if (o1.start > o2.start) {
return 1;
} else if (o1.start < o2.start) {
return -1;
}
return 0;
});
for (int a = 0; a < ranges.size() - 1; a++) {
Range r1 = ranges.get(a);
Range r2 = ranges.get(a + 1);
if (r1.end == r2.start) {
r1.end = r2.end;
ranges.remove(a + 1);
a--;
}
}
if (!modified) {
ranges.add(new Range(start, end));
}
@ -533,7 +553,7 @@ public class FileLoadOperation {
}
}
protected void removeStreamListener(final FileStreamLoadOperation operation) {
protected void removeStreamListener(final FileLoadOperationStream operation) {
Utilities.stageQueue.postRunnable(() -> {
if (streamListeners == null) {
return;
@ -557,10 +577,10 @@ public class FileLoadOperation {
}
public boolean start() {
return start(null, 0);
return start(null, 0, false);
}
public boolean start(final FileLoadOperationStream stream, final int streamOffset) {
public boolean start(final FileLoadOperationStream stream, final int streamOffset, final boolean steamPriority) {
if (currentDownloadChunkSize == 0) {
currentDownloadChunkSize = totalBytesCount >= bigFileSizeFrom ? downloadChunkSizeBig : downloadChunkSize;
currentMaxDownloadRequests = totalBytesCount >= bigFileSizeFrom ? maxDownloadRequestsBig : maxDownloadRequests;
@ -573,7 +593,27 @@ public class FileLoadOperation {
if (streamListeners == null) {
streamListeners = new ArrayList<>();
}
streamStartOffset = streamOffset / currentDownloadChunkSize * currentDownloadChunkSize;
if (steamPriority) {
int offset = streamOffset / currentDownloadChunkSize * currentDownloadChunkSize;
if (priorityRequestInfo != null && priorityRequestInfo.offset != offset) {
requestInfos.remove(priorityRequestInfo);
requestedBytesCount -= currentDownloadChunkSize;
removePart(notRequestedBytesRanges, priorityRequestInfo.offset, priorityRequestInfo.offset + currentDownloadChunkSize);
if (priorityRequestInfo.requestToken != 0) {
ConnectionsManager.getInstance(currentAccount).cancelRequest(priorityRequestInfo.requestToken, true);
requestsCount--;
}
if (BuildVars.DEBUG_VERSION) {
FileLog.d("frame get cancel request at offset " + priorityRequestInfo.offset);
}
priorityRequestInfo = null;
}
if (priorityRequestInfo == null) {
streamPriorityStartOffset = offset;
}
} else {
streamStartOffset = streamOffset / currentDownloadChunkSize * currentDownloadChunkSize;
}
streamListeners.add(stream);
if (alreadyStarted) {
if (preloadedBytesRanges != null && getDownloadedLengthFromOffsetInternal(notLoadedBytesRanges, streamStartOffset, 1) == 0) {
@ -1549,12 +1589,13 @@ public class FileLoadOperation {
protected void startDownloadRequest() {
if (paused ||
state != stateDownloading ||
!nextPartWasPreloaded && (requestInfos.size() + delayedRequestInfos.size() >= currentMaxDownloadRequests) ||
isPreloadVideoOperation && (requestedBytesCount > preloadMaxBytes || moovFound != 0 && requestInfos.size() > 0)) {
streamPriorityStartOffset == 0 && (
!nextPartWasPreloaded && (requestInfos.size() + delayedRequestInfos.size() >= currentMaxDownloadRequests) ||
isPreloadVideoOperation && (requestedBytesCount > preloadMaxBytes || moovFound != 0 && requestInfos.size() > 0))) {
return;
}
int count = 1;
if (!nextPartWasPreloaded && (!isPreloadVideoOperation || moovFound != 0) && totalBytesCount > 0) {
if (streamPriorityStartOffset == 0 && !nextPartWasPreloaded && (!isPreloadVideoOperation || moovFound != 0) && totalBytesCount > 0) {
count = Math.max(0, currentMaxDownloadRequests - requestInfos.size());
}
@ -1598,18 +1639,19 @@ public class FileLoadOperation {
preloadNotRequestedBytesCount -= currentDownloadChunkSize;
} else {
if (notRequestedBytesRanges != null) {
int sreamOffset = streamPriorityStartOffset != 0 ? streamPriorityStartOffset : streamStartOffset;
int size = notRequestedBytesRanges.size();
int minStart = Integer.MAX_VALUE;
int minStreamStart = Integer.MAX_VALUE;
for (int b = 0; b < size; b++) {
Range range = notRequestedBytesRanges.get(b);
if (streamStartOffset != 0) {
if (range.start <= streamStartOffset && range.end > streamStartOffset) {
minStreamStart = streamStartOffset;
if (sreamOffset != 0) {
if (range.start <= sreamOffset && range.end > sreamOffset) {
minStreamStart = sreamOffset;
minStart = Integer.MAX_VALUE;
break;
}
if (streamStartOffset < range.start && range.start < minStreamStart) {
if (sreamOffset < range.start && range.start < minStreamStart) {
minStreamStart = range.start;
}
}
@ -1687,11 +1729,24 @@ public class FileLoadOperation {
}
}
}
if (streamPriorityStartOffset != 0) {
if (BuildVars.DEBUG_VERSION) {
FileLog.d("frame get offset = " + streamPriorityStartOffset);
}
streamPriorityStartOffset = 0;
priorityRequestInfo = requestInfo;
}
requestInfo.requestToken = ConnectionsManager.getInstance(currentAccount).sendRequest(request, (response, error) -> {
if (!requestInfos.contains(requestInfo)) {
return;
}
if (requestInfo == priorityRequestInfo) {
if (BuildVars.DEBUG_VERSION) {
FileLog.d("frame get request completed " + priorityRequestInfo.offset);
}
priorityRequestInfo = null;
}
if (error != null) {
if (FileRefController.isFileRefError(error.text)) {
requestReference(requestInfo);

View file

@ -507,7 +507,7 @@ public class FileLoader extends BaseController {
}
}
private FileLoadOperation loadFileInternal(final TLRPC.Document document, final SecureDocument secureDocument, final WebFile webDocument, TLRPC.TL_fileLocationToBeDeprecated location, final ImageLocation imageLocation, Object parentObject, final String locationExt, final int locationSize, final int priority, final FileLoadOperationStream stream, final int streamOffset, final int cacheType) {
private FileLoadOperation loadFileInternal(final TLRPC.Document document, final SecureDocument secureDocument, final WebFile webDocument, TLRPC.TL_fileLocationToBeDeprecated location, final ImageLocation imageLocation, Object parentObject, final String locationExt, final int locationSize, final int priority, final FileLoadOperationStream stream, final int streamOffset, boolean streamPriority, final int cacheType) {
String fileName = null;
if (location != null) {
fileName = getAttachFileName(location, locationExt);
@ -553,15 +553,15 @@ public class FileLoader extends BaseController {
downloadQueue.remove(index);
if (stream != null) {
if (downloadQueue == audioLoadOperationQueue) {
if (operation.start(stream, streamOffset)) {
if (operation.start(stream, streamOffset, streamPriority)) {
currentAudioLoadOperationsCount.put(datacenterId, currentAudioLoadOperationsCount.get(datacenterId) + 1);
}
} else if (downloadQueue == photoLoadOperationQueue) {
if (operation.start(stream, streamOffset)) {
if (operation.start(stream, streamOffset, streamPriority)) {
currentPhotoLoadOperationsCount.put(datacenterId, currentPhotoLoadOperationsCount.get(datacenterId) + 1);
}
} else {
if (operation.start(stream, streamOffset)) {
if (operation.start(stream, streamOffset, streamPriority)) {
currentLoadOperationsCount.put(datacenterId, currentLoadOperationsCount.get(datacenterId) + 1);
}
if (operation.wasStarted() && !activeFileLoadOperation.contains(operation)) {
@ -578,7 +578,7 @@ public class FileLoader extends BaseController {
if (stream != null) {
pauseCurrentFileLoadOperations(operation);
}
operation.start(stream, streamOffset);
operation.start(stream, streamOffset, streamPriority);
if (downloadQueue == loadOperationQueue && !activeFileLoadOperation.contains(operation)) {
activeFileLoadOperation.add(operation);
}
@ -676,7 +676,7 @@ public class FileLoader extends BaseController {
int maxCount = priority > 0 ? 3 : 1;
int count = currentAudioLoadOperationsCount.get(datacenterId);
if (stream != null || count < maxCount) {
if (operation.start(stream, streamOffset)) {
if (operation.start(stream, streamOffset, streamPriority)) {
currentAudioLoadOperationsCount.put(datacenterId, count + 1);
}
} else {
@ -686,7 +686,7 @@ public class FileLoader extends BaseController {
int maxCount = priority > 0 ? 6 : 2;
int count = currentPhotoLoadOperationsCount.get(datacenterId);
if (stream != null || count < maxCount) {
if (operation.start(stream, streamOffset)) {
if (operation.start(stream, streamOffset, streamPriority)) {
currentPhotoLoadOperationsCount.put(datacenterId, count + 1);
}
} else {
@ -696,7 +696,7 @@ public class FileLoader extends BaseController {
int maxCount = priority > 0 ? 4 : 1;
int count = currentLoadOperationsCount.get(datacenterId);
if (stream != null || count < maxCount) {
if (operation.start(stream, streamOffset)) {
if (operation.start(stream, streamOffset, streamPriority)) {
currentLoadOperationsCount.put(datacenterId, count + 1);
activeFileLoadOperation.add(operation);
}
@ -741,14 +741,14 @@ public class FileLoader extends BaseController {
if (cacheType != 10 && !TextUtils.isEmpty(fileName) && !fileName.contains("" + Integer.MIN_VALUE)) {
loadOperationPathsUI.put(fileName, true);
}
fileLoaderQueue.postRunnable(() -> loadFileInternal(document, secureDocument, webDocument, location, imageLocation, parentObject, locationExt, locationSize, priority, null, 0, cacheType));
fileLoaderQueue.postRunnable(() -> loadFileInternal(document, secureDocument, webDocument, location, imageLocation, parentObject, locationExt, locationSize, priority, null, 0, false, cacheType));
}
protected FileLoadOperation loadStreamFile(final FileLoadOperationStream stream, final TLRPC.Document document, final Object parentObject, final int offset) {
protected FileLoadOperation loadStreamFile(final FileLoadOperationStream stream, final TLRPC.Document document, final Object parentObject, final int offset, final boolean priority) {
final CountDownLatch semaphore = new CountDownLatch(1);
final FileLoadOperation[] result = new FileLoadOperation[1];
fileLoaderQueue.postRunnable(() -> {
result[0] = loadFileInternal(document, null, null, null, null, parentObject, null, 0, 1, stream, offset, 0);
result[0] = loadFileInternal(document, null, null, null, null, parentObject, null, 0, 1, stream, offset, priority, 0);
semaphore.countDown();
});
try {
@ -1049,7 +1049,7 @@ public class FileLoader extends BaseController {
public static String fixFileName(String fileName) {
if (fileName != null) {
fileName = fileName.replaceAll("[\u0001-\u001f<>:\"/\\\\|?*\u007f]+", "").trim();
fileName = fileName.replaceAll("[\u0001-\u001f<>\u202E:\"/\\\\|?*\u007f]+", "").trim();
}
return fileName;
}

View file

@ -420,7 +420,7 @@ public class FileRefController extends BaseController {
}
if (done) {
multiMediaCache.remove(multiMedia);
getSendMessagesHelper().performSendMessageRequestMulti(multiMedia, (ArrayList<MessageObject>) objects[1], (ArrayList<String>) objects[2], null, (SendMessagesHelper.DelayedMessage) objects[4]);
AndroidUtilities.runOnUIThread(() -> getSendMessagesHelper().performSendMessageRequestMulti(multiMedia, (ArrayList<MessageObject>) objects[1], (ArrayList<String>) objects[2], null, (SendMessagesHelper.DelayedMessage) objects[4]));
}
} else if (requester.args[0] instanceof TLRPC.TL_messages_sendMedia) {
TLRPC.TL_messages_sendMedia req = (TLRPC.TL_messages_sendMedia) requester.args[0];
@ -431,7 +431,7 @@ public class FileRefController extends BaseController {
TLRPC.TL_inputMediaPhoto mediaPhoto = (TLRPC.TL_inputMediaPhoto) req.media;
mediaPhoto.id.file_reference = file_reference;
}
getSendMessagesHelper().performSendMessageRequest((TLObject) requester.args[0], (MessageObject) requester.args[1], (String) requester.args[2], (SendMessagesHelper.DelayedMessage) requester.args[3], (Boolean) requester.args[4], (SendMessagesHelper.DelayedMessage) requester.args[5], null);
AndroidUtilities.runOnUIThread(() -> getSendMessagesHelper().performSendMessageRequest((TLObject) requester.args[0], (MessageObject) requester.args[1], (String) requester.args[2], (SendMessagesHelper.DelayedMessage) requester.args[3], (Boolean) requester.args[4], (SendMessagesHelper.DelayedMessage) requester.args[5], null));
} else if (requester.args[0] instanceof TLRPC.TL_messages_editMessage) {
TLRPC.TL_messages_editMessage req = (TLRPC.TL_messages_editMessage) requester.args[0];
if (req.media instanceof TLRPC.TL_inputMediaDocument) {
@ -441,7 +441,7 @@ public class FileRefController extends BaseController {
TLRPC.TL_inputMediaPhoto mediaPhoto = (TLRPC.TL_inputMediaPhoto) req.media;
mediaPhoto.id.file_reference = file_reference;
}
getSendMessagesHelper().performSendMessageRequest((TLObject) requester.args[0], (MessageObject) requester.args[1], (String) requester.args[2], (SendMessagesHelper.DelayedMessage) requester.args[3], (Boolean) requester.args[4], (SendMessagesHelper.DelayedMessage) requester.args[5], null);
AndroidUtilities.runOnUIThread(() -> getSendMessagesHelper().performSendMessageRequest((TLObject) requester.args[0], (MessageObject) requester.args[1], (String) requester.args[2], (SendMessagesHelper.DelayedMessage) requester.args[3], (Boolean) requester.args[4], (SendMessagesHelper.DelayedMessage) requester.args[5], null));
} else if (requester.args[0] instanceof TLRPC.TL_messages_saveGif) {
TLRPC.TL_messages_saveGif req = (TLRPC.TL_messages_saveGif) requester.args[0];
req.id.file_reference = file_reference;
@ -489,10 +489,10 @@ public class FileRefController extends BaseController {
Object[] objects = multiMediaCache.get(req);
if (objects != null) {
multiMediaCache.remove(req);
getSendMessagesHelper().performSendMessageRequestMulti(req, (ArrayList<MessageObject>) objects[1], (ArrayList<String>) objects[2], null, (SendMessagesHelper.DelayedMessage) objects[4]);
AndroidUtilities.runOnUIThread(() -> getSendMessagesHelper().performSendMessageRequestMulti(req, (ArrayList<MessageObject>) objects[1], (ArrayList<String>) objects[2], null, (SendMessagesHelper.DelayedMessage) objects[4]));
}
} else if (args[0] instanceof TLRPC.TL_messages_sendMedia || args[0] instanceof TLRPC.TL_messages_editMessage) {
getSendMessagesHelper().performSendMessageRequest((TLObject) args[0], (MessageObject) args[1], (String) args[2], (SendMessagesHelper.DelayedMessage) args[3], (Boolean) args[4], (SendMessagesHelper.DelayedMessage) args[5], null);
AndroidUtilities.runOnUIThread(() -> getSendMessagesHelper().performSendMessageRequest((TLObject) args[0], (MessageObject) args[1], (String) args[2], (SendMessagesHelper.DelayedMessage) args[3], (Boolean) args[4], (SendMessagesHelper.DelayedMessage) args[5], null));
} else if (args[0] instanceof TLRPC.TL_messages_saveGif) {
TLRPC.TL_messages_saveGif req = (TLRPC.TL_messages_saveGif) args[0];
//do nothing

View file

@ -69,7 +69,7 @@ public class FileStreamLoadOperation extends BaseDataSource implements FileLoadO
} else if (document.mime_type.startsWith("audio")) {
document.attributes.add(new TLRPC.TL_documentAttributeAudio());
}
loadOperation = FileLoader.getInstance(currentAccount).loadStreamFile(this, document, parentObject, currentOffset = (int) dataSpec.position);
loadOperation = FileLoader.getInstance(currentAccount).loadStreamFile(this, document, parentObject, currentOffset = (int) dataSpec.position, false);
bytesRemaining = dataSpec.length == C.LENGTH_UNSET ? document.size - dataSpec.position : dataSpec.length;
if (bytesRemaining < 0) {
throw new EOFException();
@ -95,15 +95,17 @@ public class FileStreamLoadOperation extends BaseDataSource implements FileLoadO
if (bytesRemaining < readLength) {
readLength = (int) bytesRemaining;
}
while (availableLength == 0) {
while (availableLength == 0 && opened) {
availableLength = loadOperation.getDownloadedLengthFromOffset(currentOffset, readLength);
if (availableLength == 0) {
FileLog.d("not found bytes " + offset);
FileLoader.getInstance(currentAccount).loadStreamFile(this, document, parentObject, currentOffset);
FileLoader.getInstance(currentAccount).loadStreamFile(this, document, parentObject, currentOffset, false);
countDownLatch = new CountDownLatch(1);
countDownLatch.await();
}
}
if (!opened) {
return 0;
}
file.readFully(buffer, offset, availableLength);
currentOffset += availableLength;
bytesRemaining -= availableLength;
@ -125,9 +127,6 @@ public class FileStreamLoadOperation extends BaseDataSource implements FileLoadO
if (loadOperation != null) {
loadOperation.removeStreamListener(this);
}
if (countDownLatch != null) {
countDownLatch.countDown();
}
if (file != null) {
try {
file.close();
@ -141,6 +140,9 @@ public class FileStreamLoadOperation extends BaseDataSource implements FileLoadO
opened = false;
transferEnded();
}
if (countDownLatch != null) {
countDownLatch.countDown();
}
}
@Override

View file

@ -777,6 +777,8 @@ public class ImageLoader {
int h = Math.min(512, AndroidUtilities.dp(170.6f));
boolean precache = false;
boolean limitFps = false;
int autoRepeat = 1;
int[] colors = null;
if (cacheImage.filter != null) {
String[] args = cacheImage.filter.split("_");
if (args.length >= 2) {
@ -791,8 +793,29 @@ public class ImageLoader {
precache = SharedConfig.getDevicePerfomanceClass() != SharedConfig.PERFORMANCE_CLASS_HIGH;
}
}
if (args.length >= 3) {
if ("nr".equals(args[2])) {
autoRepeat = 2;
} else if ("nrs".equals(args[2])) {
autoRepeat = 3;
}
}
if (args.length >= 5) {
if ("c1".equals(args[4])) {
colors = new int[]{0xf77e41, 0xca907a, 0xffb139, 0xedc5a5, 0xffd140, 0xf7e3c3, 0xffdf79, 0xfbefd6};
} else if ("c2".equals(args[4])) {
colors = new int[]{0xf77e41, 0xaa7c60, 0xffb139, 0xc8a987, 0xffd140, 0xddc89f, 0xffdf79, 0xe6d6b2};
} else if ("c3".equals(args[4])) {
colors = new int[]{0xf77e41, 0x8c6148, 0xffb139, 0xad8562, 0xffd140, 0xc49e76, 0xffdf79, 0xd4b188};
} else if ("c4".equals(args[4])) {
colors = new int[]{0xf77e41, 0x6e3c2c, 0xffb139, 0x925a34, 0xffd140, 0xa16e46, 0xffdf79, 0xac7a52};
} else if ("c5".equals(args[4])) {
colors = new int[]{0xf77e41, 0x291c12, 0xffb139, 0x472a22, 0xffd140, 0x573b30, 0xffdf79, 0x68493c};
}
}
}
RLottieDrawable lottieDrawable = new RLottieDrawable(cacheImage.finalFilePath, w, h, precache, limitFps);
RLottieDrawable lottieDrawable = new RLottieDrawable(cacheImage.finalFilePath, w, h, precache, limitFps, colors);
lottieDrawable.setAutoRepeat(autoRepeat);
onPostExecute(lottieDrawable);
} else if (cacheImage.animatedFile) {
synchronized (sync) {
@ -802,9 +825,9 @@ public class ImageLoader {
}
AnimatedFileDrawable fileDrawable;
if (AUTOPLAY_FILTER.equals(cacheImage.filter) && !(cacheImage.imageLocation.document instanceof TLRPC.TL_documentEncrypted)) {
fileDrawable = new AnimatedFileDrawable(cacheImage.finalFilePath, false, cacheImage.size, cacheImage.imageLocation.document instanceof TLRPC.Document ? cacheImage.imageLocation.document : null, cacheImage.parentObject, cacheImage.currentAccount);
fileDrawable = new AnimatedFileDrawable(cacheImage.finalFilePath, false, cacheImage.size, cacheImage.imageLocation.document instanceof TLRPC.Document ? cacheImage.imageLocation.document : null, cacheImage.parentObject, cacheImage.currentAccount, false);
} else {
fileDrawable = new AnimatedFileDrawable(cacheImage.finalFilePath, "d".equals(cacheImage.filter), 0, null, null, cacheImage.currentAccount);
fileDrawable = new AnimatedFileDrawable(cacheImage.finalFilePath, "d".equals(cacheImage.filter), 0, null, null, cacheImage.currentAccount, false);
}
Thread.interrupted();
onPostExecute(fileDrawable);

View file

@ -31,6 +31,8 @@ public class ImageReceiver implements NotificationCenter.NotificationCenterDeleg
public interface ImageReceiverDelegate {
void didSetImage(ImageReceiver imageReceiver, boolean set, boolean thumb);
default void onAnimationReady(ImageReceiver imageReceiver) {
}
}
public static class BitmapHolder {
@ -152,6 +154,8 @@ public class ImageReceiver implements NotificationCenter.NotificationCenterDeleg
private boolean allowStartAnimation = true;
private boolean useSharedAnimationQueue;
private boolean allowDecodeSingleFrame;
private int autoRepeat = 1;
private boolean animationReadySent;
private boolean crossfadeWithOldImage;
private boolean crossfadingWithThumb;
@ -936,6 +940,12 @@ public class ImageReceiver implements NotificationCenter.NotificationCenterDeleg
if (lottieDrawable != null) {
lottieDrawable.setCurrentParentView(parentView);
}
if ((animation != null || lottieDrawable != null) && !animationNotReady && !animationReadySent) {
animationReadySent = true;
if (delegate != null) {
delegate.onAnimationReady(this);
}
}
int orientation = 0;
BitmapShader shaderToUse = null;
if (!forcePreview && currentMediaDrawable != null && !animationNotReady) {
@ -1399,6 +1409,14 @@ public class ImageReceiver implements NotificationCenter.NotificationCenterDeleg
allowDecodeSingleFrame = value;
}
public void setAutoRepeat(int value) {
autoRepeat = value;
RLottieDrawable drawable = getLottieAnimation();
if (drawable != null) {
drawable.setAutoRepeat(value);
}
}
public void setUseSharedAnimationQueue(boolean value) {
useSharedAnimationQueue = value;
}
@ -1618,6 +1636,7 @@ public class ImageReceiver implements NotificationCenter.NotificationCenterDeleg
fileDrawable.start();
}
fileDrawable.setAllowDecodeSingleFrame(allowDecodeSingleFrame);
animationReadySent = false;
} else if (drawable instanceof RLottieDrawable) {
RLottieDrawable fileDrawable = (RLottieDrawable) drawable;
fileDrawable.addParentView(parentView);
@ -1625,6 +1644,8 @@ public class ImageReceiver implements NotificationCenter.NotificationCenterDeleg
fileDrawable.start();
}
fileDrawable.setAllowDecodeSingleFrame(true);
fileDrawable.setAutoRepeat(autoRepeat);
animationReadySent = false;
}
if (parentView != null) {
if (invalidateAll) {

View file

@ -139,6 +139,7 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener,
public static class AlbumEntry {
public int bucketId;
public boolean videoOnly;
public String bucketName;
public PhotoEntry coverPhoto;
public ArrayList<PhotoEntry> photos = new ArrayList<>();
@ -358,6 +359,8 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener,
public static AlbumEntry allMediaAlbumEntry;
public static AlbumEntry allPhotosAlbumEntry;
public static AlbumEntry allVideosAlbumEntry;
public static ArrayList<AlbumEntry> allMediaAlbums = new ArrayList<>();
public static ArrayList<AlbumEntry> allPhotoAlbums = new ArrayList<>();
private static Runnable broadcastPhotosRunnable;
private boolean isPaused = false;
@ -1763,7 +1766,7 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener,
private void playNextMessageWithoutOrder(boolean byStop) {
ArrayList<MessageObject> currentPlayList = SharedConfig.shuffleMusic ? shuffledPlaylist : playlist;
if (byStop && SharedConfig.repeatMode == 2 && !forceLoopCurrentPlaylist) {
if (byStop && (SharedConfig.repeatMode == 2 || SharedConfig.repeatMode == 1 && currentPlayList.size() == 1) && !forceLoopCurrentPlaylist) {
cleanupPlayer(false, false);
MessageObject messageObject = currentPlayList.get(currentPlaylistNum);
messageObject.audioProgress = 0;
@ -2081,7 +2084,7 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener,
return currentPlaybackSpeed;
}
private void updateVideoState(MessageObject messageObject, int playCount[], boolean destroyAtEnd, boolean playWhenReady, int playbackState) {
private void updateVideoState(MessageObject messageObject, int[] playCount, boolean destroyAtEnd, boolean playWhenReady, int playbackState) {
if (videoPlayer == null) {
return;
}
@ -2495,7 +2498,7 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener,
@Override
public void onStateChanged(boolean playWhenReady, int playbackState) {
if (playbackState == ExoPlayer.STATE_ENDED || (playbackState == ExoPlayer.STATE_IDLE || playbackState == ExoPlayer.STATE_BUFFERING) && playWhenReady && messageObject.audioProgress >= 0.999f) {
if (!playlist.isEmpty() && playlist.size() > 1) {
if (!playlist.isEmpty() && (playlist.size() > 1 || !messageObject.isVoice())) {
playNextMessageWithoutOrder(true);
} else {
cleanupPlayer(true, true, messageObject != null && messageObject.isVoice(), false);
@ -3017,13 +3020,9 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener,
if (!destFile.exists()) {
destFile.createNewFile();
}
FileChannel source = null;
FileChannel destination = null;
boolean result = true;
long lastProgress = System.currentTimeMillis() - 500;
try {
source = new FileInputStream(sourceFile).getChannel();
destination = new FileOutputStream(destFile).getChannel();
try (FileChannel source = new FileInputStream(sourceFile).getChannel(); FileChannel destination = new FileOutputStream(destFile).getChannel()) {
long size = source.size();
for (long a = 0; a < size; a += 4096) {
if (cancelled[0]) {
@ -3047,21 +3046,6 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener,
} catch (Exception e) {
FileLog.e(e);
result = false;
} finally {
try {
if (source != null) {
source.close();
}
} catch (Exception e) {
//
}
try {
if (destination != null) {
destination.close();
}
} catch (Exception e) {
//
}
}
if (cancelled[0]) {
destFile.delete();
@ -3148,18 +3132,12 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener,
public static String getFileName(Uri uri) {
String result = null;
if (uri.getScheme().equals("content")) {
Cursor cursor = null;
try {
cursor = ApplicationLoader.applicationContext.getContentResolver().query(uri, new String[]{OpenableColumns.DISPLAY_NAME}, null, null, null);
try (Cursor cursor = ApplicationLoader.applicationContext.getContentResolver().query(uri, new String[]{OpenableColumns.DISPLAY_NAME}, null, null, null)) {
if (cursor.moveToFirst()) {
result = cursor.getString(cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME));
}
} catch (Exception e) {
FileLog.e(e);
} finally {
if (cursor != null) {
cursor.close();
}
}
}
if (result == null) {
@ -3340,6 +3318,7 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener,
if (allVideosAlbum == null) {
allVideosAlbum = new AlbumEntry(0, LocaleController.getString("AllVideos", R.string.AllVideos), photoEntry);
allVideosAlbum.videoOnly = true;
int index = 0;
if (allMediaAlbum != null) {
index++;
@ -3408,6 +3387,8 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener,
broadcastNewPhotos(guid, mediaAlbumsSorted, photoAlbumsSorted, cameraAlbumIdFinal, allMediaAlbumFinal, allPhotosAlbumFinal, allVideosAlbumFinal, 1000);
return;
}
allMediaAlbums = mediaAlbumsSorted;
allPhotoAlbums = photoAlbumsSorted;
broadcastPhotosRunnable = null;
allPhotosAlbumEntry = allPhotosAlbumFinal;
allMediaAlbumEntry = allMediaAlbumFinal;

View file

@ -120,16 +120,18 @@ public class MediaDataController extends BaseController {
public static final int TYPE_MASK = 1;
public static final int TYPE_FAVE = 2;
public static final int TYPE_FEATURED = 3;
public static final int TYPE_EMOJI = 4;
private ArrayList<TLRPC.TL_messages_stickerSet>[] stickerSets = new ArrayList[]{new ArrayList<>(), new ArrayList<>(), new ArrayList(0), new ArrayList()};
private ArrayList<TLRPC.TL_messages_stickerSet>[] stickerSets = new ArrayList[]{new ArrayList<>(), new ArrayList<>(), new ArrayList(0), new ArrayList(), new ArrayList()};
private LongSparseArray<TLRPC.Document>[] stickersByIds = new LongSparseArray[]{new LongSparseArray<>(), new LongSparseArray<>(), new LongSparseArray(), new LongSparseArray(), new LongSparseArray()};
private LongSparseArray<TLRPC.TL_messages_stickerSet> stickerSetsById = new LongSparseArray<>();
private LongSparseArray<TLRPC.TL_messages_stickerSet> installedStickerSetsById = new LongSparseArray<>();
private LongSparseArray<TLRPC.TL_messages_stickerSet> groupStickerSets = new LongSparseArray<>();
private HashMap<String, TLRPC.TL_messages_stickerSet> stickerSetsByName = new HashMap<>();
private boolean[] loadingStickers = new boolean[4];
private boolean[] stickersLoaded = new boolean[4];
private int[] loadHash = new int[4];
private int[] loadDate = new int[4];
private boolean[] loadingStickers = new boolean[5];
private boolean[] stickersLoaded = new boolean[5];
private int[] loadHash = new int[5];
private int[] loadDate = new int[5];
private int[] archivedStickersCount = new int[2];
@ -235,6 +237,9 @@ public class MediaDataController extends BaseController {
}
public void addRecentSticker(final int type, Object parentObject, TLRPC.Document document, int date, boolean remove) {
if (document == null) {
return;
}
boolean found = false;
for (int a = 0; a < recentStickers[type].size(); a++) {
TLRPC.Document image = recentStickers[type].get(a);
@ -392,26 +397,44 @@ public class MediaDataController extends BaseController {
if (existingSet == null) {
return;
}
LongSparseArray<TLRPC.Document> documents = new LongSparseArray<>();
for (int a = 0, size = set.documents.size(); a < size; a++) {
TLRPC.Document document = set.documents.get(a);
documents.put(document.id, document);
}
boolean changed = false;
for (int a = 0, size = existingSet.documents.size(); a < size; a++) {
TLRPC.Document document = set.documents.get(a);
TLRPC.Document newDocument = documents.get(document.id);
if (newDocument != null) {
existingSet.documents.set(a, newDocument);
changed = true;
if ("AnimatedEmojies".equals(set.set.short_name)) {
changed = true;
existingSet.documents = set.documents;
existingSet.packs = set.packs;
existingSet.set = set.set;
AndroidUtilities.runOnUIThread(() -> {
LongSparseArray<TLRPC.Document> stickersById = getStickerByIds(TYPE_EMOJI);
for (int b = 0; b < set.documents.size(); b++) {
TLRPC.Document document = set.documents.get(b);
stickersById.put(document.id, document);
}
});
} else {
LongSparseArray<TLRPC.Document> documents = new LongSparseArray<>();
for (int a = 0, size = set.documents.size(); a < size; a++) {
TLRPC.Document document = set.documents.get(a);
documents.put(document.id, document);
}
for (int a = 0, size = existingSet.documents.size(); a < size; a++) {
TLRPC.Document document = set.documents.get(a);
TLRPC.Document newDocument = documents.get(document.id);
if (newDocument != null) {
existingSet.documents.set(a, newDocument);
changed = true;
}
}
}
if (changed) {
if (isGroupSet) {
putSetToCache(existingSet);
} else {
final int type = set.set.masks ? TYPE_MASK : TYPE_IMAGE;
int type = set.set.masks ? TYPE_MASK : TYPE_IMAGE;
putStickersToCache(type, stickerSets[type], loadDate[type], loadHash[type]);
if ("AnimatedEmojies".equals(set.set.short_name)) {
type = TYPE_EMOJI;
putStickersToCache(type, stickerSets[type], loadDate[type], loadHash[type]);
}
}
}
}
@ -524,6 +547,22 @@ public class MediaDataController extends BaseController {
return allStickersFeatured;
}
public TLRPC.Document getEmojiAnimatedSticker(CharSequence message) {
String emoji = message.toString().replace("\uFE0F", "");
ArrayList<TLRPC.TL_messages_stickerSet> arrayList = getStickerSets(MediaDataController.TYPE_EMOJI);
for (int a = 0, N = arrayList.size(); a < N; a++) {
TLRPC.TL_messages_stickerSet set = arrayList.get(a);
for (int b = 0, N2 = set.packs.size(); b < N2; b++) {
TLRPC.TL_stickerPack pack = set.packs.get(b);
if (!pack.documents.isEmpty() && TextUtils.equals(pack.emoticon, emoji)) {
LongSparseArray<TLRPC.Document> stickerByIds = getStickerByIds(MediaDataController.TYPE_EMOJI);
return stickerByIds.get(pack.documents.get(0));
}
}
}
return null;
}
public boolean canAddStickerToFavorites() {
return !stickersLoaded[0] || stickerSets[0].size() >= 5 || !recentStickers[TYPE_FAVE].isEmpty();
}
@ -536,6 +575,10 @@ public class MediaDataController extends BaseController {
}
}
public LongSparseArray<TLRPC.Document> getStickerByIds(int type) {
return stickersByIds[type];
}
public ArrayList<TLRPC.StickerSetCovered> getFeaturedStickerSets() {
return featuredStickerSets;
}
@ -1185,7 +1228,7 @@ public class MediaDataController extends BaseController {
if (featuredStickerSets.isEmpty() || !getMessagesController().preloadFeaturedStickers) {
return;
}
} else {
} else if (type != TYPE_EMOJI) {
loadArchivedStickersCount(type, cache);
}
loadingStickers[type] = true;
@ -1228,24 +1271,36 @@ public class MediaDataController extends BaseController {
response.sets.add(featuredStickerSets.get(a).set);
}
processLoadStickersResponse(type, response);
return;
}
TLObject req;
final int hash;
if (type == TYPE_IMAGE) {
req = new TLRPC.TL_messages_getAllStickers();
hash = ((TLRPC.TL_messages_getAllStickers) req).hash = force ? 0 : loadHash[type];
} else if (type == TYPE_EMOJI) {
TLRPC.TL_messages_getStickerSet req = new TLRPC.TL_messages_getStickerSet();
req.stickerset = new TLRPC.TL_inputStickerSetAnimatedEmoji();
getConnectionsManager().sendRequest(req, (response, error) -> {
if (response instanceof TLRPC.TL_messages_stickerSet) {
final ArrayList<TLRPC.TL_messages_stickerSet> newStickerArray = new ArrayList<>();
newStickerArray.add((TLRPC.TL_messages_stickerSet) response);
processLoadedStickers(type, newStickerArray, false, (int) (System.currentTimeMillis() / 1000), calcStickersHash(newStickerArray));
} else {
processLoadedStickers(type, null, false, (int) (System.currentTimeMillis() / 1000), 0);
}
});
} else {
req = new TLRPC.TL_messages_getMaskStickers();
hash = ((TLRPC.TL_messages_getMaskStickers) req).hash = force ? 0 : loadHash[type];
}
getConnectionsManager().sendRequest(req, (response, error) -> AndroidUtilities.runOnUIThread(() -> {
if (response instanceof TLRPC.TL_messages_allStickers) {
processLoadStickersResponse(type, (TLRPC.TL_messages_allStickers) response);
TLObject req;
final int hash;
if (type == TYPE_IMAGE) {
req = new TLRPC.TL_messages_getAllStickers();
hash = ((TLRPC.TL_messages_getAllStickers) req).hash = force ? 0 : loadHash[type];
} else {
processLoadedStickers(type, null, false, (int) (System.currentTimeMillis() / 1000), hash);
req = new TLRPC.TL_messages_getMaskStickers();
hash = ((TLRPC.TL_messages_getMaskStickers) req).hash = force ? 0 : loadHash[type];
}
}));
getConnectionsManager().sendRequest(req, (response, error) -> AndroidUtilities.runOnUIThread(() -> {
if (response instanceof TLRPC.TL_messages_allStickers) {
processLoadStickersResponse(type, (TLRPC.TL_messages_allStickers) response);
} else {
processLoadedStickers(type, null, false, (int) (System.currentTimeMillis() / 1000), hash);
}
}));
}
}
}
@ -1411,12 +1466,14 @@ public class MediaDataController extends BaseController {
for (int a = 0; a < stickerSets[type].size(); a++) {
TLRPC.StickerSet set = stickerSets[type].get(a).set;
stickerSetsById.remove(set.id);
installedStickerSetsById.remove(set.id);
stickerSetsByName.remove(set.short_name);
if (type != TYPE_FEATURED && type != TYPE_EMOJI) {
installedStickerSetsById.remove(set.id);
}
}
for (int a = 0; a < stickerSetsByIdNew.size(); a++) {
stickerSetsById.put(stickerSetsByIdNew.keyAt(a), stickerSetsByIdNew.valueAt(a));
if (type != TYPE_FEATURED) {
if (type != TYPE_FEATURED && type != TYPE_EMOJI) {
installedStickerSetsById.put(stickerSetsByIdNew.keyAt(a), stickerSetsByIdNew.valueAt(a));
}
}
@ -1424,6 +1481,7 @@ public class MediaDataController extends BaseController {
stickerSets[type] = stickerSetsNew;
loadHash[type] = hash;
loadDate[type] = date;
stickersByIds[type] = stickersByIdNew;
if (type == TYPE_IMAGE) {
allStickers = allStickersNew;
stickersByEmoji = stickersByEmojiNew;
@ -3524,7 +3582,6 @@ public class MediaDataController extends BaseController {
public static void addStyleToText(TextStyleSpan span, int start, int end, Spannable editable, boolean allowIntersection) {
try {
allowIntersection = true;
CharacterStyle[] spans = editable.getSpans(start, end, CharacterStyle.class);
if (spans != null && spans.length > 0) {
for (int a = 0; a < spans.length; a++) {

View file

@ -75,6 +75,8 @@ public class MessageObject {
public boolean localChannel;
public boolean localEdit;
public TLRPC.Message messageOwner;
public TLRPC.Document emojiAnimatedSticker;
public String emojiAnimatedStickerColor;
public CharSequence messageText;
public CharSequence linkDescription;
public CharSequence caption;
@ -87,6 +89,7 @@ public class MessageObject {
public String monthKey;
public boolean deleted;
public float audioProgress;
public float forceSeekTo = -1;
public int audioProgressMs;
public float bufferedProgress;
public float gifState;
@ -141,6 +144,7 @@ public class MessageObject {
public static Pattern urlPattern;
public static Pattern instagramUrlPattern;
public static Pattern videoTimeUrlPattern;
public CharSequence vCardData;
@ -745,7 +749,11 @@ public class MessageObject {
}
public MessageObject(int accountNum, TLRPC.Message message, boolean generateLayout) {
this(accountNum, message, null, null, null, null, generateLayout, 0);
this(accountNum, message, null, null, null, null, null, generateLayout, 0);
}
public MessageObject(int accountNum, TLRPC.Message message, MessageObject replyToMessage, boolean generateLayout) {
this(accountNum, message, replyToMessage, null, null, null, null, generateLayout, 0);
}
public MessageObject(int accountNum, TLRPC.Message message, AbstractMap<Integer, TLRPC.User> users, AbstractMap<Integer, TLRPC.Chat> chats, boolean generateLayout) {
@ -753,22 +761,23 @@ public class MessageObject {
}
public MessageObject(int accountNum, TLRPC.Message message, SparseArray<TLRPC.User> users, SparseArray<TLRPC.Chat> chats, boolean generateLayout) {
this(accountNum, message, null, null, users, chats, generateLayout, 0);
this(accountNum, message, null, null, null, users, chats, generateLayout, 0);
}
public MessageObject(int accountNum, TLRPC.Message message, AbstractMap<Integer, TLRPC.User> users, AbstractMap<Integer, TLRPC.Chat> chats, boolean generateLayout, long eid) {
this(accountNum, message, users, chats, null, null, generateLayout, eid);
this(accountNum, message, null, users, chats, null, null, generateLayout, eid);
}
public MessageObject(int accountNum, TLRPC.Message message, AbstractMap<Integer, TLRPC.User> users, AbstractMap<Integer, TLRPC.Chat> chats, SparseArray<TLRPC.User> sUsers, SparseArray<TLRPC.Chat> sChats, boolean generateLayout, long eid) {
public MessageObject(int accountNum, TLRPC.Message message, MessageObject replyToMessage, AbstractMap<Integer, TLRPC.User> users, AbstractMap<Integer, TLRPC.Chat> chats, SparseArray<TLRPC.User> sUsers, SparseArray<TLRPC.Chat> sChats, boolean generateLayout, long eid) {
Theme.createChatResources(null, true);
currentAccount = accountNum;
messageOwner = message;
replyMessageObject = replyToMessage;
eventId = eid;
if (message.replyMessage != null) {
replyMessageObject = new MessageObject(currentAccount, message.replyMessage, users, chats, sUsers, sChats, false, eid);
replyMessageObject = new MessageObject(currentAccount, message.replyMessage, null, users, chats, sUsers, sChats, false, eid);
}
TLRPC.User fromUser = null;
@ -807,7 +816,40 @@ public class MessageObject {
int[] emojiOnly = SharedConfig.allowBigEmoji ? new int[1] : null;
messageText = Emoji.replaceEmoji(messageText, paint.getFontMetricsInt(), AndroidUtilities.dp(20), false, emojiOnly);
checkEmojiOnly(emojiOnly);
generateLayout(fromUser);
emojiAnimatedSticker = null;
if (emojiOnlyCount == 1 && !(message.media instanceof TLRPC.TL_messageMediaWebPage) && message.entities.isEmpty()) {
CharSequence emoji = messageText;
int index;
if ((index = TextUtils.indexOf(emoji, "\uD83C\uDFFB")) >= 0) {
emojiAnimatedStickerColor = "_c1";
emoji = emoji.subSequence(0, index);
} else if ((index = TextUtils.indexOf(emoji, "\uD83C\uDFFC")) >= 0) {
emojiAnimatedStickerColor = "_c2";
emoji = emoji.subSequence(0, index);
} else if ((index = TextUtils.indexOf(emoji, "\uD83C\uDFFD")) >= 0) {
emojiAnimatedStickerColor = "_c3";
emoji = emoji.subSequence(0, index);
} else if ((index = TextUtils.indexOf(emoji, "\uD83C\uDFFE")) >= 0) {
emojiAnimatedStickerColor = "_c4";
emoji = emoji.subSequence(0, index);
} else if ((index = TextUtils.indexOf(emoji, "\uD83C\uDFFF")) >= 0) {
emojiAnimatedStickerColor = "_c5";
emoji = emoji.subSequence(0, index);
} else {
emojiAnimatedStickerColor = "";
}
emojiAnimatedSticker = MediaDataController.getInstance(currentAccount).getEmojiAnimatedSticker(emoji);
}
if (emojiAnimatedSticker == null) {
generateLayout(fromUser);
} else {
type = 1000;
if (isSticker()) {
type = TYPE_STICKER;
} else if (isAnimatedSticker()) {
type = TYPE_ANIMATED_STICKER;
}
}
}
layoutCreated = generateLayout;
generateThumbs(false);
@ -966,6 +1008,15 @@ public class MessageObject {
if (n == null) {
n = new TLRPC.TL_chatAdminRights();
}
if (!TextUtils.equals(event.action.prev_participant.rank, event.action.new_participant.rank)) {
if (TextUtils.isEmpty(event.action.new_participant.rank)) {
rights.append('\n').append('-').append(' ');
rights.append(LocaleController.getString("EventLogPromotedRemovedTitle", R.string.EventLogPromotedRemovedTitle));
} else {
rights.append('\n').append('+').append(' ');
rights.append(LocaleController.formatString("EventLogPromotedTitle", R.string.EventLogPromotedTitle, event.action.new_participant.rank));
}
}
if (o.change_info != n.change_info) {
rights.append('\n').append(n.change_info ? '+' : '-').append(' ');
rights.append(chat.megagroup ? LocaleController.getString("EventLogPromotedChangeGroupInfo", R.string.EventLogPromotedChangeGroupInfo) : LocaleController.getString("EventLogPromotedChangeChannelInfo", R.string.EventLogPromotedChangeChannelInfo));
@ -1418,6 +1469,21 @@ public class MessageObject {
TLRPC.TL_channelLocation channelLocation = (TLRPC.TL_channelLocation) location.new_value;
messageText = replaceWithLink(LocaleController.formatString("EventLogChangedLocation", R.string.EventLogChangedLocation, channelLocation.address), "un1", fromUser);
}
} else if (event.action instanceof TLRPC.TL_channelAdminLogEventActionToggleSlowMode) {
TLRPC.TL_channelAdminLogEventActionToggleSlowMode slowMode = (TLRPC.TL_channelAdminLogEventActionToggleSlowMode) event.action;
if (slowMode.new_value == 0) {
messageText = replaceWithLink(LocaleController.getString("EventLogToggledSlowmodeOff", R.string.EventLogToggledSlowmodeOff), "un1", fromUser);
} else {
String string;
if (slowMode.new_value < 60) {
string = LocaleController.formatPluralString("Seconds", slowMode.new_value);
} else if (slowMode.new_value < 60 * 60) {
string = LocaleController.formatPluralString("Minutes", slowMode.new_value / 60);
} else {
string = LocaleController.formatPluralString("Hours", slowMode.new_value / 60 / 60);
}
messageText = replaceWithLink(LocaleController.formatString("EventLogToggledSlowmodeOn", R.string.EventLogToggledSlowmodeOn, string), "un1", fromUser);
}
} else {
messageText = "unsupported " + event.action;
}
@ -2224,7 +2290,7 @@ public class MessageObject {
} else {
messageText = LocaleController.getString("AttachPhoto", R.string.AttachPhoto);
}
} else if (isVideo() || messageOwner.media instanceof TLRPC.TL_messageMediaDocument && messageOwner.media.document instanceof TLRPC.TL_documentEmpty && messageOwner.media.ttl_seconds != 0) {
} else if (isVideo() || messageOwner.media instanceof TLRPC.TL_messageMediaDocument && getDocument() instanceof TLRPC.TL_documentEmpty && messageOwner.media.ttl_seconds != 0) {
if (messageOwner.media.ttl_seconds != 0 && !(messageOwner instanceof TLRPC.TL_message_secret)) {
messageText = LocaleController.getString("AttachDestructingVideo", R.string.AttachDestructingVideo);
} else {
@ -2262,7 +2328,7 @@ public class MessageObject {
} else if (isGif()) {
messageText = LocaleController.getString("AttachGif", R.string.AttachGif);
} else {
String name = FileLoader.getDocumentFileName(messageOwner.media.document);
String name = FileLoader.getDocumentFileName(getDocument());
if (name != null && name.length() > 0) {
messageText = name;
} else {
@ -2283,12 +2349,18 @@ public class MessageObject {
int oldType = type;
isRoundVideoCached = 0;
if (messageOwner instanceof TLRPC.TL_message || messageOwner instanceof TLRPC.TL_messageForwarded_old2) {
if (isMediaEmpty()) {
if (emojiAnimatedSticker != null) {
if (isSticker()) {
type = TYPE_STICKER;
} else {
type = TYPE_ANIMATED_STICKER;
}
} else if (isMediaEmpty()) {
type = 0;
if (TextUtils.isEmpty(messageText) && eventId == 0) {
messageText = "Empty message";
}
} else if (messageOwner.media.ttl_seconds != 0 && (messageOwner.media.photo instanceof TLRPC.TL_photoEmpty || messageOwner.media.document instanceof TLRPC.TL_documentEmpty)) {
} else if (messageOwner.media.ttl_seconds != 0 && (messageOwner.media.photo instanceof TLRPC.TL_photoEmpty || getDocument() instanceof TLRPC.TL_documentEmpty)) {
contentType = 1;
type = 10;
} else if (messageOwner.media instanceof TLRPC.TL_messageMediaPhoto) {
@ -2310,8 +2382,9 @@ public class MessageObject {
} else if (messageOwner.media instanceof TLRPC.TL_messageMediaUnsupported) {
type = 0;
} else if (messageOwner.media instanceof TLRPC.TL_messageMediaDocument) {
if (messageOwner.media.document != null && messageOwner.media.document.mime_type != null) {
if (isGifDocument(messageOwner.media.document)) {
TLRPC.Document document = getDocument();
if (document != null && document.mime_type != null) {
if (isGifDocument(document)) {
type = 8;
} else if (isSticker()) {
type = TYPE_STICKER;
@ -2394,8 +2467,9 @@ public class MessageObject {
}
public String getMimeType() {
if (messageOwner.media instanceof TLRPC.TL_messageMediaDocument) {
return messageOwner.media.document.mime_type;
TLRPC.Document document = getDocument();
if (document != null) {
return document.mime_type;
} else if (messageOwner.media instanceof TLRPC.TL_messageMediaInvoice) {
TLRPC.WebDocument photo = ((TLRPC.TL_messageMediaInvoice) messageOwner.media).photo;
if (photo != null) {
@ -2404,9 +2478,7 @@ public class MessageObject {
} else if (messageOwner.media instanceof TLRPC.TL_messageMediaPhoto) {
return "image/jpeg";
} else if (messageOwner.media instanceof TLRPC.TL_messageMediaWebPage) {
if (messageOwner.media.webpage.document != null) {
return messageOwner.media.document.mime_type;
} else if (messageOwner.media.webpage.photo != null) {
if (messageOwner.media.webpage.photo != null) {
return "image/jpeg";
}
}
@ -2551,6 +2623,16 @@ public class MessageObject {
}
photoThumbsObject = messageOwner.action.photo;
}
} else if (emojiAnimatedSticker != null) {
if (TextUtils.isEmpty(emojiAnimatedStickerColor) && isDocumentHasThumb(emojiAnimatedSticker)) {
if (!update || photoThumbs == null) {
photoThumbs = new ArrayList<>();
photoThumbs.addAll(emojiAnimatedSticker.thumbs);
} else if (photoThumbs != null && !photoThumbs.isEmpty()) {
updatePhotoSizeLocations(photoThumbs, emojiAnimatedSticker.thumbs);
}
photoThumbsObject = emojiAnimatedSticker;
}
} else if (messageOwner.media != null && !(messageOwner.media instanceof TLRPC.TL_messageMediaEmpty)) {
if (messageOwner.media instanceof TLRPC.TL_messageMediaPhoto) {
TLRPC.Photo photo = messageOwner.media.photo;
@ -2576,7 +2658,7 @@ public class MessageObject {
}
photoThumbsObject = messageOwner.media.photo;
} else if (messageOwner.media instanceof TLRPC.TL_messageMediaDocument) {
TLRPC.Document document = messageOwner.media.document;
TLRPC.Document document = getDocument();
if (isDocumentHasThumb(document)) {
if (!update || photoThumbs == null) {
photoThumbs = new ArrayList<>();
@ -2719,7 +2801,7 @@ public class MessageObject {
ext = fileName.substring(idx + 1);
}
if (ext == null || ext.length() == 0) {
ext = messageOwner.media.document.mime_type;
ext = getDocument().mime_type;
}
if (ext == null) {
ext = "";
@ -2730,7 +2812,7 @@ public class MessageObject {
public String getFileName() {
if (messageOwner.media instanceof TLRPC.TL_messageMediaDocument) {
return FileLoader.getAttachFileName(messageOwner.media.document);
return FileLoader.getAttachFileName(getDocument());
} else if (messageOwner.media instanceof TLRPC.TL_messageMediaPhoto) {
ArrayList<TLRPC.PhotoSize> sizes = messageOwner.media.photo.sizes;
if (sizes.size() > 0) {
@ -2852,7 +2934,7 @@ public class MessageObject {
if (!(linkDescription instanceof Spannable)) {
linkDescription = new SpannableStringBuilder(linkDescription);
}
addUsernamesAndHashtags(isOutOwner(), linkDescription, false, hashtagsType);
addUrlsByPattern(isOutOwner(), linkDescription, false, hashtagsType, 0);
}
}
}
@ -2896,23 +2978,25 @@ public class MessageObject {
FileLog.e(e);
}
}
addUsernamesAndHashtags(isOutOwner(), caption, true, 0);
} else {
try {
Linkify.addLinks((Spannable) caption, Linkify.PHONE_NUMBERS);
} catch (Throwable e) {
FileLog.e(e);
}
addUrlsByPattern(isOutOwner(), caption, true, 0, 0);
}
addEntitiesToText(caption, useManualParse);
if (isVideo()) {
addUrlsByPattern(isOutOwner(), caption, true, 3, getDuration());
}
}
}
private static void addUsernamesAndHashtags(boolean isOut, CharSequence charSequence, boolean botCommands, int hashtagsType) {
private static void addUrlsByPattern(boolean isOut, CharSequence charSequence, boolean botCommands, int patternType, int duration) {
try {
Matcher matcher;
if (hashtagsType == 1) {
if (patternType == 3) {
if (videoTimeUrlPattern == null) {
videoTimeUrlPattern = Pattern.compile("\\b(?:(\\d{1,2}):)?(\\d{1,3}):([0-5][0-9])\\b");
}
matcher = videoTimeUrlPattern.matcher(charSequence);
} else if (patternType == 1) {
if (instagramUrlPattern == null) {
instagramUrlPattern = Pattern.compile("(^|\\s|\\()@[a-zA-Z\\d_.]{1,32}|(^|\\s|\\()#[\\w.]+");
}
@ -2923,47 +3007,73 @@ public class MessageObject {
}
matcher = urlPattern.matcher(charSequence);
}
Spannable spannable = (Spannable) charSequence;
while (matcher.find()) {
int start = matcher.start();
int end = matcher.end();
char ch = charSequence.charAt(start);
if (hashtagsType != 0) {
if (ch != '@' && ch != '#') {
start++;
}
ch = charSequence.charAt(start);
if (ch != '@' && ch != '#') {
URLSpanNoUnderline url = null;
if (patternType == 3) {
URLSpan[] spans = spannable.getSpans(start, end, URLSpan.class);
if (spans != null && spans.length > 0) {
continue;
}
int count = matcher.groupCount();
int s1 = matcher.start(1);
int e1 = matcher.end(1);
int s2 = matcher.start(2);
int e2 = matcher.end(2);
int s3 = matcher.start(3);
int e3 = matcher.end(3);
int minutes = Utilities.parseInt(charSequence.subSequence(s2, e2));
int seconds = Utilities.parseInt(charSequence.subSequence(s3, e3));
int hours = s1 >= 0 && e1 >= 0 ? Utilities.parseInt(charSequence.subSequence(s1, e1)) : -1;
seconds += minutes * 60;
if (hours > 0) {
seconds += hours * 60 * 60;
}
if (seconds > duration) {
continue;
}
url = new URLSpanNoUnderline("video?" + seconds);
} else {
if (ch != '@' && ch != '#' && ch != '/' && ch != '$') {
start++;
}
}
URLSpanNoUnderline url = null;
if (hashtagsType == 1) {
if (ch == '@') {
url = new URLSpanNoUnderline("https://instagram.com/" + charSequence.subSequence(start + 1, end).toString());
} else if (ch == '#') {
url = new URLSpanNoUnderline("https://www.instagram.com/explore/tags/" + charSequence.subSequence(start + 1, end).toString());
}
} else if (hashtagsType == 2) {
if (ch == '@') {
url = new URLSpanNoUnderline("https://twitter.com/" + charSequence.subSequence(start + 1, end).toString());
} else if (ch == '#') {
url = new URLSpanNoUnderline("https://twitter.com/hashtag/" + charSequence.subSequence(start + 1, end).toString());
}
} else {
if (charSequence.charAt(start) == '/') {
if (botCommands) {
url = new URLSpanBotCommand(charSequence.subSequence(start, end).toString(), isOut ? 1 : 0);
char ch = charSequence.charAt(start);
if (patternType != 0) {
if (ch != '@' && ch != '#') {
start++;
}
ch = charSequence.charAt(start);
if (ch != '@' && ch != '#') {
continue;
}
} else {
url = new URLSpanNoUnderline(charSequence.subSequence(start, end).toString());
if (ch != '@' && ch != '#' && ch != '/' && ch != '$') {
start++;
}
}
if (patternType == 1) {
if (ch == '@') {
url = new URLSpanNoUnderline("https://instagram.com/" + charSequence.subSequence(start + 1, end).toString());
} else if (ch == '#') {
url = new URLSpanNoUnderline("https://www.instagram.com/explore/tags/" + charSequence.subSequence(start + 1, end).toString());
}
} else if (patternType == 2) {
if (ch == '@') {
url = new URLSpanNoUnderline("https://twitter.com/" + charSequence.subSequence(start + 1, end).toString());
} else if (ch == '#') {
url = new URLSpanNoUnderline("https://twitter.com/hashtag/" + charSequence.subSequence(start + 1, end).toString());
}
} else {
if (charSequence.charAt(start) == '/') {
if (botCommands) {
url = new URLSpanBotCommand(charSequence.subSequence(start, end).toString(), isOut ? 1 : 0);
}
} else {
url = new URLSpanNoUnderline(charSequence.subSequence(start, end).toString());
}
}
}
if (url != null) {
((Spannable) charSequence).setSpan(url, start, end, 0);
spannable.setSpan(url, start, end, 0);
}
}
} catch (Exception e) {
@ -3051,7 +3161,7 @@ public class MessageObject {
FileLog.e(e);
}
}
addUsernamesAndHashtags(isOut, messageText, botCommands, 0);
addUrlsByPattern(isOut, messageText, botCommands, 0, 0);
}
}
@ -3116,7 +3226,8 @@ public class MessageObject {
entity instanceof TLRPC.TL_messageEntityCode ||
entity instanceof TLRPC.TL_messageEntityPre ||
entity instanceof TLRPC.TL_messageEntityMentionName ||
entity instanceof TLRPC.TL_inputMessageEntityMentionName) {
entity instanceof TLRPC.TL_inputMessageEntityMentionName ||
entity instanceof TLRPC.TL_messageEntityTextUrl) {
if (spans != null && spans.length > 0) {
for (int b = 0; b < spans.length; b++) {
if (spans[b] == null) {
@ -3161,7 +3272,7 @@ public class MessageObject {
newRun.flags = TextStyleSpan.FLAG_STYLE_MENTION;
newRun.urlEntity = entity;
} else {
if (useManualParse) {
if (useManualParse && !(entity instanceof TLRPC.TL_messageEntityTextUrl)) {
continue;
}
if ((entity instanceof TLRPC.TL_messageEntityUrl || entity instanceof TLRPC.TL_messageEntityTextUrl) && Browser.isPassportUrl(entity.url)) {
@ -3313,6 +3424,10 @@ public class MessageObject {
return false;
}
public boolean isYouTubeVideo() {
return messageOwner.media instanceof TLRPC.TL_messageMediaWebPage && messageOwner.media.webpage != null && !TextUtils.isEmpty(messageOwner.media.webpage.embed_url) && "YouTube".equals(messageOwner.media.webpage.site_name);
}
public int getMaxMessageTextWidth() {
int maxWidth = 0;
if (AndroidUtilities.isTablet() && eventId != 0) {
@ -3391,6 +3506,11 @@ public class MessageObject {
}
}
}
if (isYouTubeVideo() || replyMessageObject != null && replyMessageObject.isYouTubeVideo()) {
addUrlsByPattern(isOutOwner(), messageText, false, 3, Integer.MAX_VALUE);
} else if (replyMessageObject != null && replyMessageObject.isVideo()) {
addUrlsByPattern(isOutOwner(), messageText, false, 3, replyMessageObject.getDuration());
}
boolean hasUrls = addEntitiesToText(messageText, useManualParse);
@ -3894,13 +4014,7 @@ public class MessageObject {
}
public String getDocumentName() {
TLRPC.Document document;
if (messageOwner.media instanceof TLRPC.TL_messageMediaDocument) {
return FileLoader.getDocumentFileName(messageOwner.media.document);
} else if (messageOwner.media instanceof TLRPC.TL_messageMediaWebPage) {
return FileLoader.getDocumentFileName(messageOwner.media.webpage.document);
}
return "";
return FileLoader.getDocumentFileName(getDocument());
}
public static boolean isStickerDocument(TLRPC.Document document) {
@ -4010,6 +4124,9 @@ public class MessageObject {
}
public TLRPC.Document getDocument() {
if (emojiAnimatedSticker != null) {
return emojiAnimatedSticker;
}
return getDocument(messageOwner);
}
@ -4108,13 +4225,22 @@ public class MessageObject {
public static TLRPC.InputStickerSet getInputStickerSet(TLRPC.Message message) {
if (message.media != null && message.media.document != null) {
for (TLRPC.DocumentAttribute attribute : message.media.document.attributes) {
if (attribute instanceof TLRPC.TL_documentAttributeSticker) {
if (attribute.stickerset instanceof TLRPC.TL_inputStickerSetEmpty) {
return null;
}
return attribute.stickerset;
return getInputStickerSet(message.media.document);
}
return null;
}
public static TLRPC.InputStickerSet getInputStickerSet(TLRPC.Document document) {
if (document == null) {
return null;
}
for (int a = 0, N = document.attributes.size(); a < N; a++) {
TLRPC.DocumentAttribute attribute = document.attributes.get(a);
if (attribute instanceof TLRPC.TL_documentAttributeSticker) {
if (attribute.stickerset instanceof TLRPC.TL_inputStickerSetEmpty) {
return null;
}
return attribute.stickerset;
}
}
return null;
@ -4137,8 +4263,9 @@ public class MessageObject {
}
public String getStrickerChar() {
if (messageOwner.media != null && messageOwner.media.document != null) {
for (TLRPC.DocumentAttribute attribute : messageOwner.media.document.attributes) {
TLRPC.Document document = getDocument();
if (document != null) {
for (TLRPC.DocumentAttribute attribute : document.attributes) {
if (attribute instanceof TLRPC.TL_documentAttributeSticker) {
return attribute.alt;
}
@ -4180,7 +4307,9 @@ public class MessageObject {
}
int photoHeight = 0;
int photoWidth = 0;
for (TLRPC.DocumentAttribute attribute : messageOwner.media.document.attributes) {
TLRPC.Document document = getDocument();
for (int a = 0, N = document.attributes.size(); a < N; a++) {
TLRPC.DocumentAttribute attribute = document.attributes.get(a);
if (attribute instanceof TLRPC.TL_documentAttributeImageSize) {
photoWidth = attribute.w;
photoHeight = attribute.h;
@ -4242,8 +4371,12 @@ public class MessageObject {
}
public String getStickerEmoji() {
for (int a = 0; a < messageOwner.media.document.attributes.size(); a++) {
TLRPC.DocumentAttribute attribute = messageOwner.media.document.attributes.get(a);
TLRPC.Document document = getDocument();
if (document == null) {
return null;
}
for (int a = 0; a < document.attributes.size(); a++) {
TLRPC.DocumentAttribute attribute = document.attributes.get(a);
if (attribute instanceof TLRPC.TL_documentAttributeSticker) {
return attribute.alt != null && attribute.alt.length() > 0 ? attribute.alt : null;
}
@ -4251,18 +4384,22 @@ public class MessageObject {
return null;
}
public boolean isAnimatedEmoji() {
return emojiAnimatedSticker != null;
}
public boolean isSticker() {
if (type != 1000) {
return type == TYPE_STICKER;
}
return isStickerMessage(messageOwner);
return isStickerDocument(getDocument());
}
public boolean isAnimatedSticker() {
if (type != 1000) {
return type == TYPE_ANIMATED_STICKER;
}
return isAnimatedStickerMessage(messageOwner);
return isAnimatedStickerDocument(getDocument());
}
public boolean isAnyKindOfSticker() {

View file

@ -104,6 +104,8 @@ public class MessagesController extends BaseController implements NotificationCe
public boolean loadingBlockedUsers = false;
public SparseIntArray blockedUsers = new SparseIntArray();
public int totalBlockedCount = -1;
public boolean blockedEndReached;
private SparseArray<ArrayList<Integer>> channelViewsToSend = new SparseArray<>();
private LongSparseArray<SparseArray<MessageObject>> pollsToCheck = new LongSparseArray<>();
@ -133,7 +135,7 @@ public class MessagesController extends BaseController implements NotificationCe
private ArrayList<Integer> loadingFullParticipants = new ArrayList<>();
private ArrayList<Integer> loadedFullParticipants = new ArrayList<>();
private ArrayList<Integer> loadedFullChats = new ArrayList<>();
private SparseArray<ArrayList<Integer>> channelAdmins = new SparseArray<>();
private SparseArray<SparseArray<String>> channelAdmins = new SparseArray<>();
private SparseIntArray loadingChannelAdmins = new SparseIntArray();
private SparseIntArray migratedChats = new SparseIntArray();
@ -205,6 +207,8 @@ public class MessagesController extends BaseController implements NotificationCe
private boolean uploadingWallpaperBlurred;
private boolean uploadingWallpaperMotion;
private boolean loadingAppConfig;
public boolean enableJoined;
public String linkPrefix;
public int maxGroupCount;
@ -233,6 +237,7 @@ public class MessagesController extends BaseController implements NotificationCe
public boolean blockedCountry;
public boolean defaultP2pContacts;
public boolean preloadFeaturedStickers;
public float animatedEmojisZoom;
public String venueSearchBot;
public String gifSearchBot;
public String imageSearchBot;
@ -435,14 +440,46 @@ public class MessagesController extends BaseController implements NotificationCe
gifSearchBot = mainPreferences.getString("gifSearchBot", "gif");
imageSearchBot = mainPreferences.getString("imageSearchBot", "pic");
blockedCountry = mainPreferences.getBoolean("blockedCountry", false);
dcDomainName = mainPreferences.getString("dcDomainName", ConnectionsManager.native_isTestBackend(currentAccount) != 0 ? "tapv2.stel.com" : "apv2.stel.com");
dcDomainName = mainPreferences.getString("dcDomainName2", ConnectionsManager.native_isTestBackend(currentAccount) != 0 ? "tapv3.stel.com" : "apv3.stel.com");
webFileDatacenterId = mainPreferences.getInt("webFileDatacenterId", ConnectionsManager.native_isTestBackend(currentAccount) != 0 ? 2 : 4);
suggestedLangCode = mainPreferences.getString("suggestedLangCode", "en");
animatedEmojisZoom = mainPreferences.getFloat("animatedEmojisZoom", 0.625f);
}
private void loadAppConfig() {
if (loadingAppConfig) {
return;
}
loadingAppConfig = true;
TLRPC.TL_help_getAppConfig req = new TLRPC.TL_help_getAppConfig();
getConnectionsManager().sendRequest(req, (response, error) -> AndroidUtilities.runOnUIThread(() -> {
if (response instanceof TLRPC.TL_jsonObject) {
SharedPreferences.Editor editor = mainPreferences.edit();
boolean changed = false;
TLRPC.TL_jsonObject object = (TLRPC.TL_jsonObject) response;
for (int a = 0, N = object.value.size(); a < N; a++) {
TLRPC.TL_jsonObjectValue value = object.value.get(a);
if ("emojies_animated_zoom".equals(value.key) && value.value instanceof TLRPC.TL_jsonNumber) {
TLRPC.TL_jsonNumber number = (TLRPC.TL_jsonNumber) value.value;
if (animatedEmojisZoom != number.value) {
animatedEmojisZoom = (float) number.value;
editor.putFloat("animatedEmojisZoom", animatedEmojisZoom);
changed = true;
}
}
}
if (changed) {
editor.commit();
}
}
loadingAppConfig = false;
}));
}
public void updateConfig(final TLRPC.TL_config config) {
AndroidUtilities.runOnUIThread(() -> {
getDownloadController().loadAutoDownloadConfig(false);
loadAppConfig();
maxMegagroupCount = config.megagroup_size_max;
maxGroupCount = config.chat_size_max;
maxEditTime = config.edit_time_limit;
@ -563,7 +600,7 @@ public class MessagesController extends BaseController implements NotificationCe
editor.putString("venueSearchBot", venueSearchBot);
editor.putString("gifSearchBot", gifSearchBot);
editor.putString("imageSearchBot", imageSearchBot);
editor.putString("dcDomainName", dcDomainName);
editor.putString("dcDomainName2", dcDomainName);
editor.putInt("webFileDatacenterId", webFileDatacenterId);
editor.putString("suggestedLangCode", suggestedLangCode);
editor.commit();
@ -783,6 +820,16 @@ public class MessagesController extends BaseController implements NotificationCe
if (obj != null) {
dialogMessagesByIds.put(newMsgId, obj);
}
int lowerId = (int) (long) did;
if (lowerId < 0) {
TLRPC.ChatFull chatFull = fullChats.get(-lowerId);
TLRPC.Chat chat = getChat(-lowerId);
if (chat != null && !ChatObject.hasAdminRights(chat) && chatFull != null && chatFull.slowmode_seconds != 0) {
chatFull.slowmode_next_send_date = ConnectionsManager.getInstance(currentAccount).getCurrentTime() + chatFull.slowmode_seconds;
chatFull.flags |= 262144;
getMessagesStorage().updateChatInfo(chatFull, false);
}
}
} else if (id == NotificationCenter.updateMessageMedia) {
TLRPC.Message message = (TLRPC.Message) args[0];
MessageObject existMessageObject = dialogMessagesByIds.get(message.id);
@ -812,7 +859,7 @@ public class MessagesController extends BaseController implements NotificationCe
editor = emojiPreferences.edit();
editor.putLong("lastGifLoadTime", 0).putLong("lastStickersLoadTime", 0).putLong("lastStickersLoadTimeMask", 0).putLong("lastStickersLoadTimeFavs", 0).commit();
editor = mainPreferences.edit();
editor.remove("archivehint").remove("archivehint_l").remove("gifhint").remove("soundHint").remove("dcDomainName").remove("webFileDatacenterId").commit();
editor.remove("archivehint").remove("archivehint_l").remove("gifhint").remove("soundHint").remove("dcDomainName2").remove("webFileDatacenterId").commit();
reloadingWebpages.clear();
reloadingWebpagesPending.clear();
@ -889,6 +936,8 @@ public class MessagesController extends BaseController implements NotificationCe
dialogsEndReached.clear();
serverDialogsEndReached.clear();
loadingAppConfig = false;
checkingTosUpdate = false;
nextTosCheckTime = 0;
nextProxyInfoCheckTime = 0;
@ -900,6 +949,8 @@ public class MessagesController extends BaseController implements NotificationCe
currentDeletingTaskChannelId = 0;
gettingNewDeleteTask = false;
loadingBlockedUsers = false;
totalBlockedCount = -1;
blockedEndReached = false;
firstGettingTask = false;
updatingState = false;
resetingDialogs = false;
@ -1395,53 +1446,69 @@ public class MessagesController extends BaseController implements NotificationCe
});
}
public boolean isChannelAdmin(int chatId, int uid) {
ArrayList<Integer> array = channelAdmins.get(chatId);
return array != null && array.indexOf(uid) >= 0;
public String getAdminRank(int chatId, int uid) {
SparseArray<String> array = channelAdmins.get(chatId);
if (array == null) {
return null;
}
return array.get(uid);
}
public boolean isChannelAdminsLoaded(int chatId) {
return channelAdmins.get(chatId) != null;
}
public void loadChannelAdmins(final int chatId, final boolean cache) {
if (loadingChannelAdmins.indexOfKey(chatId) >= 0) {
int loadTime = loadingChannelAdmins.get(chatId);
if (SystemClock.uptimeMillis() - loadTime < 60) {
return;
}
loadingChannelAdmins.put(chatId, 0);
loadingChannelAdmins.put(chatId, (int) (SystemClock.uptimeMillis() / 1000));
if (cache) {
getMessagesStorage().loadChannelAdmins(chatId);
} else {
TLRPC.TL_channels_getParticipants req = new TLRPC.TL_channels_getParticipants();
ArrayList<Integer> array = channelAdmins.get(chatId);
/*SparseArray<String> array = channelAdmins.get(chatId);
if (array != null) {
long acc = 0;
ArrayList<Integer> values = new ArrayList<>();
for (int a = 0; a < array.size(); a++) {
acc = ((acc * 20261) + 0x80000000L + array.get(a)) % 0x80000000L;
values.add(array.keyAt(a));
}
Collections.sort(values);
long acc = 0;
for (int a = 0; a < values.size(); a++) {
acc = ((acc * 20261) + 0x80000000L + values.get(a)) % 0x80000000L;
}
req.hash = (int) acc;
}
}*/
req.channel = getInputChannel(chatId);
req.limit = 100;
req.filter = new TLRPC.TL_channelParticipantsAdmins();
getConnectionsManager().sendRequest(req, (response, error) -> {
if (response instanceof TLRPC.TL_channels_channelParticipants) {
TLRPC.TL_channels_channelParticipants participants = (TLRPC.TL_channels_channelParticipants) response;
final ArrayList<Integer> array1 = new ArrayList<>(participants.participants.size());
for (int a = 0; a < participants.participants.size(); a++) {
array1.add(participants.participants.get(a).user_id);
}
processLoadedChannelAdmins(array1, chatId, false);
processLoadedAdminsResponse(chatId, (TLRPC.TL_channels_channelParticipants) response);
}
});
}
}
public void processLoadedChannelAdmins(final ArrayList<Integer> array, final int chatId, final boolean cache) {
Collections.sort(array);
public void processLoadedAdminsResponse(int chatId, TLRPC.TL_channels_channelParticipants participants) {
final SparseArray<String> array1 = new SparseArray<>(participants.participants.size());
for (int a = 0; a < participants.participants.size(); a++) {
TLRPC.ChannelParticipant participant = participants.participants.get(a);
array1.put(participant.user_id, participant.rank != null ? participant.rank : "");
}
processLoadedChannelAdmins(array1, chatId, false);
}
public void processLoadedChannelAdmins(final SparseArray<String> array, final int chatId, final boolean cache) {
if (!cache) {
getMessagesStorage().putChannelAdmins(chatId, array);
}
AndroidUtilities.runOnUIThread(() -> {
loadingChannelAdmins.delete(chatId);
channelAdmins.put(chatId, array);
if (cache) {
loadingChannelAdmins.delete(chatId);
loadChannelAdmins(chatId, false);
}
});
@ -1564,17 +1631,11 @@ public class MessagesController extends BaseController implements NotificationCe
int index = blockedUsers.indexOfKey(user.id);
if (userFull.blocked) {
if (index < 0) {
SparseIntArray ids = new SparseIntArray();
ids.put(user.id, 1);
getMessagesStorage().putBlockedUsers(ids, false);
blockedUsers.put(user.id, 1);
getNotificationCenter().postNotificationName(NotificationCenter.blockedUsersDidLoad);
}
} else {
if (index >= 0) {
getMessagesStorage().deleteBlockedUser(user.id);
blockedUsers.removeAt(index);
getNotificationCenter().postNotificationName(NotificationCenter.blockedUsersDidLoad);
}
@ -2053,11 +2114,7 @@ public class MessagesController extends BaseController implements NotificationCe
TLRPC.TL_contacts_block req = new TLRPC.TL_contacts_block();
req.id = getInputUser(user);
getConnectionsManager().sendRequest(req, (response, error) -> {
if (error == null) {
SparseIntArray ids = new SparseIntArray();
ids.put(user.id, 1);
getMessagesStorage().putBlockedUsers(ids, false);
}
});
}
@ -2079,6 +2136,18 @@ public class MessagesController extends BaseController implements NotificationCe
});
}
public void setChannelSlowMode(int chatId, int seconds) {
TLRPC.TL_channels_toggleSlowMode req = new TLRPC.TL_channels_toggleSlowMode();
req.seconds = seconds;
req.channel = getInputChannel(chatId);
getConnectionsManager().sendRequest(req, (response, error) -> {
if (error == null) {
getMessagesController().processUpdates((TLRPC.Updates) response, false);
AndroidUtilities.runOnUIThread(() -> loadFullChat(chatId, 0, true), 1000);
}
});
}
public void setDefaultBannedRole(final int chatId, TLRPC.TL_chatBannedRights rights, final boolean isChannel, final BaseFragment parentFragment) {
if (rights == null) {
return;
@ -2096,7 +2165,7 @@ public class MessagesController extends BaseController implements NotificationCe
});
}
public void setUserAdminRole(final int chatId, TLRPC.User user, TLRPC.TL_chatAdminRights rights, final boolean isChannel, final BaseFragment parentFragment, boolean addingNew) {
public void setUserAdminRole(final int chatId, TLRPC.User user, TLRPC.TL_chatAdminRights rights, String rank, final boolean isChannel, final BaseFragment parentFragment, boolean addingNew) {
if (user == null || rights == null) {
return;
}
@ -2106,6 +2175,7 @@ public class MessagesController extends BaseController implements NotificationCe
req.channel = getInputChannel(chat);
req.user_id = getInputUser(user);
req.admin_rights = rights;
req.rank = rank;
getConnectionsManager().sendRequest(req, (response, error) -> {
if (error == null) {
processUpdates((TLRPC.Updates) response, false);
@ -2143,53 +2213,37 @@ public class MessagesController extends BaseController implements NotificationCe
blockedUsers.delete(user.id);
req.id = getInputUser(user);
getNotificationCenter().postNotificationName(NotificationCenter.blockedUsersDidLoad);
getConnectionsManager().sendRequest(req, (response, error) -> getMessagesStorage().deleteBlockedUser(user.id));
getConnectionsManager().sendRequest(req, (response, error) -> {
});
}
public void getBlockedUsers(boolean cache) {
public void getBlockedUsers(boolean reset) {
if (!getUserConfig().isClientActivated() || loadingBlockedUsers) {
return;
}
loadingBlockedUsers = true;
if (cache) {
getMessagesStorage().getBlockedUsers();
} else {
TLRPC.TL_contacts_getBlocked req = new TLRPC.TL_contacts_getBlocked();
req.offset = 0;
req.limit = 200;
getConnectionsManager().sendRequest(req, (response, error) -> {
SparseIntArray blocked = new SparseIntArray();
ArrayList<TLRPC.User> users = null;
if (error == null) {
final TLRPC.contacts_Blocked res = (TLRPC.contacts_Blocked) response;
for (TLRPC.TL_contactBlocked contactBlocked : res.blocked) {
blocked.put(contactBlocked.user_id, 1);
}
users = res.users;
getMessagesStorage().putUsersAndChats(res.users, null, true, true);
getMessagesStorage().putBlockedUsers(blocked, true);
TLRPC.TL_contacts_getBlocked req = new TLRPC.TL_contacts_getBlocked();
req.offset = reset ? 0 : blockedUsers.size();
req.limit = reset ? 20 : 100;
getConnectionsManager().sendRequest(req, (response, error) -> AndroidUtilities.runOnUIThread(() -> {
if (response != null) {
TLRPC.contacts_Blocked res = (TLRPC.contacts_Blocked) response;
putUsers(res.users, false);
getMessagesStorage().putUsersAndChats(res.users, null, true, true);
if (reset) {
blockedUsers.clear();
}
processLoadedBlockedUsers(blocked, users, false);
});
}
}
public void processLoadedBlockedUsers(final SparseIntArray ids, final ArrayList<TLRPC.User> users, final boolean cache) {
AndroidUtilities.runOnUIThread(() -> {
if (users != null) {
putUsers(users, cache);
totalBlockedCount = Math.max(res.count, res.blocked.size());
blockedEndReached = res.blocked.size() < req.limit;
for (int a = 0, N = res.blocked.size(); a < N; a++) {
TLRPC.TL_contactBlocked blocked = res.blocked.get(a);
blockedUsers.put(blocked.user_id, 1);
}
loadingBlockedUsers = false;
getNotificationCenter().postNotificationName(NotificationCenter.blockedUsersDidLoad);
}
loadingBlockedUsers = false;
if (ids.size() == 0 && cache && !getUserConfig().blockedUsersLoaded) {
getBlockedUsers(false);
return;
} else if (!cache) {
getUserConfig().blockedUsersLoaded = true;
getUserConfig().saveConfig(false);
}
blockedUsers = ids;
getNotificationCenter().postNotificationName(NotificationCenter.blockedUsersDidLoad);
});
}));
}
public void deleteUserPhoto(TLRPC.InputPhoto photo) {
@ -2380,7 +2434,7 @@ public class MessagesController extends BaseController implements NotificationCe
toSend.add(mid);
}
}
getMessagesStorage().markMessagesAsDeleted(messages, true, channelId);
getMessagesStorage().markMessagesAsDeleted(messages, true, channelId, forAll);
getMessagesStorage().updateDialogsWithDeletedMessages(messages, null, true, channelId);
getNotificationCenter().postNotificationName(NotificationCenter.messagesDeleted, messages, channelId);
}
@ -2819,23 +2873,22 @@ public class MessagesController extends BaseController implements NotificationCe
}));
}
public void loadChatInfo(final int chat_id, CountDownLatch countDownLatch, boolean force) {
getMessagesStorage().loadChatInfo(chat_id, countDownLatch, force, false);
}
public void processChatInfo(int chat_id, final TLRPC.ChatFull info, final ArrayList<TLRPC.User> usersArr, final boolean fromCache, boolean force, final boolean byChannelUsers, final MessageObject pinnedMessageObject) {
if (fromCache && chat_id > 0 && !byChannelUsers) {
loadFullChat(chat_id, 0, force);
}
if (info != null) {
AndroidUtilities.runOnUIThread(() -> {
AndroidUtilities.runOnUIThread(() -> {
if (fromCache && chat_id > 0 && !byChannelUsers) {
loadFullChat(chat_id, 0, force);
}
if (info != null) {
if (fullChats.get(chat_id) == null) {
fullChats.put(chat_id, info);
}
putUsers(usersArr, fromCache);
if (info.stickerset != null) {
getMediaDataController().getGroupStickerSetById(info.stickerset);
}
getNotificationCenter().postNotificationName(NotificationCenter.chatInfoDidLoad, info, 0, byChannelUsers, pinnedMessageObject);
});
}
}
});
}
public void loadUserInfo(TLRPC.User user, boolean force, int classGuid) {
@ -2843,15 +2896,22 @@ public class MessagesController extends BaseController implements NotificationCe
}
public void processUserInfo(TLRPC.User user, final TLRPC.UserFull info, final boolean fromCache, boolean force, final MessageObject pinnedMessageObject, int classGuid) {
if (fromCache) {
loadFullUser(user, classGuid, force);
}
if (info != null) {
if (fullUsers.get(user.id) == null) {
fullUsers.put(user.id, info);
AndroidUtilities.runOnUIThread(() -> {
if (fromCache) {
loadFullUser(user, classGuid, force);
}
AndroidUtilities.runOnUIThread(() -> getNotificationCenter().postNotificationName(NotificationCenter.userInfoDidLoad, user.id, info, pinnedMessageObject));
}
if (info != null) {
if (fullUsers.get(user.id) == null) {
fullUsers.put(user.id, info);
if (info.blocked) {
blockedUsers.put(user.id, 1);
} else {
blockedUsers.delete(user.id);
}
}
getNotificationCenter().postNotificationName(NotificationCenter.userInfoDidLoad, user.id, info, pinnedMessageObject);
}
});
}
public void updateTimerProc() {
@ -3196,6 +3256,9 @@ public class MessagesController extends BaseController implements NotificationCe
nextProxyInfoCheckTime = res.expires;
if (!noDialog) {
AndroidUtilities.runOnUIThread(() -> {
if (proxyDialog != null && did != proxyDialog.id) {
removeProxyDialog();
}
proxyDialog = dialogs_dict.get(did);
if (proxyDialog != null) {
@ -3341,22 +3404,7 @@ public class MessagesController extends BaseController implements NotificationCe
getGlobalMainSettings().edit().putLong("proxy_dialog", proxyDialogId).remove("proxyDialogAddress").commit();
checkingProxyInfoRequestId = 0;
checkingProxyInfo = false;
AndroidUtilities.runOnUIThread(() -> {
if (proxyDialog != null) {
int lowerId = (int) proxyDialog.id;
if (lowerId < 0) {
TLRPC.Chat chat = getChat(-lowerId);
if (ChatObject.isNotInChat(chat) || chat.restricted) {
removeDialog(proxyDialog);
}
} else {
removeDialog(proxyDialog);
}
proxyDialog = null;
sortDialogs(null);
getNotificationCenter().postNotificationName(NotificationCenter.dialogsNeedReload);
}
});
AndroidUtilities.runOnUIThread(this::removeProxyDialog);
}
});
} else {
@ -3374,25 +3422,28 @@ public class MessagesController extends BaseController implements NotificationCe
checkingProxyInfoRequestId = 0;
}
}
AndroidUtilities.runOnUIThread(() -> {
if (proxyDialog != null) {
int lowerId = (int) proxyDialog.id;
if (lowerId < 0) {
TLRPC.Chat chat = getChat(-lowerId);
if (ChatObject.isNotInChat(chat) || chat.restricted) {
removeDialog(proxyDialog);
}
} else {
removeDialog(proxyDialog);
}
proxyDialog = null;
sortDialogs(null);
getNotificationCenter().postNotificationName(NotificationCenter.dialogsNeedReload);
}
});
AndroidUtilities.runOnUIThread(this::removeProxyDialog);
}
}
private void removeProxyDialog() {
if (proxyDialog == null) {
return;
}
int lowerId = (int) proxyDialog.id;
if (lowerId < 0) {
TLRPC.Chat chat = getChat(-lowerId);
if (ChatObject.isNotInChat(chat) || chat.restricted) {
removeDialog(proxyDialog);
}
} else {
removeDialog(proxyDialog);
}
proxyDialog = null;
sortDialogs(null);
getNotificationCenter().postNotificationName(NotificationCenter.dialogsNeedReload);
}
public boolean isProxyDialog(long did, boolean checkLeft) {
return proxyDialog != null && proxyDialog.id == did && (!checkLeft || isLeftProxyChannel);
}
@ -6192,7 +6243,7 @@ public class MessagesController extends BaseController implements NotificationCe
return 0;
}
public void convertToMegaGroup(final Context context, int chat_id, MessagesStorage.IntCallback convertRunnable) {
public void convertToMegaGroup(final Context context, int chat_id, BaseFragment fragment, MessagesStorage.IntCallback convertRunnable) {
TLRPC.TL_messages_migrateChat req = new TLRPC.TL_messages_migrateChat();
req.chat_id = chat_id;
final AlertDialog progressDialog = new AlertDialog(context, 3);
@ -6228,11 +6279,7 @@ public class MessagesController extends BaseController implements NotificationCe
} catch (Exception e) {
FileLog.e(e);
}
AlertDialog.Builder builder = new AlertDialog.Builder(context);
builder.setTitle(LocaleController.getString("AppName", R.string.AppName));
builder.setMessage(LocaleController.getString("ErrorOccurred", R.string.ErrorOccurred));
builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), null);
builder.show().setCanceledOnTouchOutside(true);
AlertsCreator.processError(currentAccount, error, fragment, req, false);
}
});
}
@ -7993,7 +8040,7 @@ public class MessagesController extends BaseController implements NotificationCe
}
});
getMessagesStorage().deletePushMessages(dialogId, ids);
ArrayList<Long> dialogIds = getMessagesStorage().markMessagesAsDeleted(ids, false, channelId);
ArrayList<Long> dialogIds = getMessagesStorage().markMessagesAsDeleted(ids, false, channelId, true);
getMessagesStorage().updateDialogsWithDeletedMessages(ids, dialogIds, false, channelId);
});
}
@ -9172,13 +9219,6 @@ public class MessagesController extends BaseController implements NotificationCe
getSecretChatHelper().processUpdateEncryption((TLRPC.TL_updateEncryption) baseUpdate, usersDict);
} else if (baseUpdate instanceof TLRPC.TL_updateUserBlocked) {
final TLRPC.TL_updateUserBlocked finalUpdate = (TLRPC.TL_updateUserBlocked) baseUpdate;
if (finalUpdate.blocked) {
SparseIntArray ids = new SparseIntArray();
ids.put(finalUpdate.user_id, 1);
getMessagesStorage().putBlockedUsers(ids, false);
} else {
getMessagesStorage().deleteBlockedUser(finalUpdate.user_id);
}
getMessagesStorage().getStorageQueue().postRunnable(() -> AndroidUtilities.runOnUIThread(() -> {
if (finalUpdate.blocked) {
if (blockedUsers.indexOfKey(finalUpdate.user_id) < 0) {
@ -10286,7 +10326,7 @@ public class MessagesController extends BaseController implements NotificationCe
final int key = deletedMessages.keyAt(a);
final ArrayList<Integer> arrayList = deletedMessages.valueAt(a);
getMessagesStorage().getStorageQueue().postRunnable(() -> {
ArrayList<Long> dialogIds = getMessagesStorage().markMessagesAsDeleted(arrayList, false, key);
ArrayList<Long> dialogIds = getMessagesStorage().markMessagesAsDeleted(arrayList, false, key, true);
getMessagesStorage().updateDialogsWithDeletedMessages(arrayList, dialogIds, false, key);
});
}
@ -10296,7 +10336,7 @@ public class MessagesController extends BaseController implements NotificationCe
final int key = clearHistoryMessages.keyAt(a);
final int id = clearHistoryMessages.valueAt(a);
getMessagesStorage().getStorageQueue().postRunnable(() -> {
ArrayList<Long> dialogIds = getMessagesStorage().markMessagesAsDeleted(key, id, false);
ArrayList<Long> dialogIds = getMessagesStorage().markMessagesAsDeleted(key, id, false, true);
getMessagesStorage().updateDialogsWithDeletedMessages(new ArrayList<>(), dialogIds, false, key);
});
}
@ -10392,7 +10432,7 @@ public class MessagesController extends BaseController implements NotificationCe
if (message.isOut() && !message.isSending() && !message.isForwarded()) {
if (message.isNewGif()) {
getMediaDataController().addRecentGif(message.messageOwner.media.document, message.messageOwner.date);
} else if (message.isSticker() || message.isAnimatedSticker()) {
} else if (!message.isAnimatedEmoji() && (message.isSticker() || message.isAnimatedSticker())) {
getMediaDataController().addRecentSticker(MediaDataController.TYPE_IMAGE, message, message.messageOwner.media.document, message.messageOwner.date, false);
}
}

View file

@ -67,7 +67,7 @@ public class MessagesStorage extends BaseController {
private CountDownLatch openSync = new CountDownLatch(1);
private static volatile MessagesStorage[] Instance = new MessagesStorage[UserConfig.MAX_ACCOUNT_COUNT];
private final static int LAST_DB_VERSION = 60;
private final static int LAST_DB_VERSION = 62;
public static MessagesStorage getInstance(int num) {
MessagesStorage localInstance = Instance[num];
@ -224,7 +224,7 @@ public class MessagesStorage extends BaseController {
database.executeFast("CREATE INDEX IF NOT EXISTS uid_date_mid_idx_messages ON messages(uid, date, mid);").stepThis().dispose();
database.executeFast("CREATE INDEX IF NOT EXISTS mid_out_idx_messages ON messages(mid, out);").stepThis().dispose();
database.executeFast("CREATE INDEX IF NOT EXISTS task_idx_messages ON messages(uid, out, read_state, ttl, date, send_state);").stepThis().dispose();
database.executeFast("CREATE INDEX IF NOT EXISTS send_state_idx_messages ON messages(mid, send_state, date) WHERE mid < 0 AND send_state = 1;").stepThis().dispose();
database.executeFast("CREATE INDEX IF NOT EXISTS send_state_idx_messages2 ON messages(mid, send_state, date);").stepThis().dispose();
database.executeFast("CREATE INDEX IF NOT EXISTS uid_mention_idx_messages ON messages(uid, mention, read_state);").stepThis().dispose();
database.executeFast("CREATE TABLE download_queue(uid INTEGER, type INTEGER, date INTEGER, data BLOB, parent TEXT, PRIMARY KEY (uid, type));").stepThis().dispose();
@ -280,10 +280,9 @@ public class MessagesStorage extends BaseController {
database.executeFast("CREATE TABLE chats(uid INTEGER PRIMARY KEY, name TEXT, data BLOB)").stepThis().dispose();
database.executeFast("CREATE TABLE enc_chats(uid INTEGER PRIMARY KEY, user INTEGER, name TEXT, data BLOB, g BLOB, authkey BLOB, ttl INTEGER, layer INTEGER, seq_in INTEGER, seq_out INTEGER, use_count INTEGER, exchange_id INTEGER, key_date INTEGER, fprint INTEGER, fauthkey BLOB, khash BLOB, in_seq_no INTEGER, admin_id INTEGER, mtproto_seq INTEGER)").stepThis().dispose();
database.executeFast("CREATE TABLE channel_users_v2(did INTEGER, uid INTEGER, date INTEGER, data BLOB, PRIMARY KEY(did, uid))").stepThis().dispose();
database.executeFast("CREATE TABLE channel_admins(did INTEGER, uid INTEGER, PRIMARY KEY(did, uid))").stepThis().dispose();
database.executeFast("CREATE TABLE channel_admins_v2(did INTEGER, uid INTEGER, rank TEXT, PRIMARY KEY(did, uid))").stepThis().dispose();
database.executeFast("CREATE TABLE contacts(uid INTEGER PRIMARY KEY, mutual INTEGER)").stepThis().dispose();
database.executeFast("CREATE TABLE user_photos(uid INTEGER, id INTEGER, data BLOB, PRIMARY KEY (uid, id))").stepThis().dispose();
database.executeFast("CREATE TABLE blocked_users(uid INTEGER PRIMARY KEY)").stepThis().dispose();
database.executeFast("CREATE TABLE dialog_settings(did INTEGER PRIMARY KEY, flags INTEGER);").stepThis().dispose();
database.executeFast("CREATE TABLE web_recent_v3(id TEXT, type INTEGER, image_url TEXT, thumb_url TEXT, local_url TEXT, width INTEGER, height INTEGER, size INTEGER, date INTEGER, document BLOB, PRIMARY KEY (id, type));").stepThis().dispose();
database.executeFast("CREATE TABLE stickers_v2(id INTEGER PRIMARY KEY, data BLOB, date INTEGER, hash TEXT);").stepThis().dispose();
@ -407,15 +406,11 @@ public class MessagesStorage extends BaseController {
database.executeFast("CREATE TABLE IF NOT EXISTS sent_files_v2(uid TEXT, type INTEGER, data BLOB, PRIMARY KEY (uid, type))").stepThis().dispose();
database.executeFast("CREATE TABLE IF NOT EXISTS blocked_users(uid INTEGER PRIMARY KEY)").stepThis().dispose();
database.executeFast("CREATE TABLE IF NOT EXISTS download_queue(uid INTEGER, type INTEGER, date INTEGER, data BLOB, PRIMARY KEY (uid, type));").stepThis().dispose();
database.executeFast("CREATE INDEX IF NOT EXISTS type_date_idx_download_queue ON download_queue(type, date);").stepThis().dispose();
database.executeFast("CREATE TABLE IF NOT EXISTS dialog_settings(did INTEGER PRIMARY KEY, flags INTEGER);").stepThis().dispose();
database.executeFast("CREATE INDEX IF NOT EXISTS send_state_idx_messages ON messages(mid, send_state, date) WHERE mid < 0 AND send_state = 1;").stepThis().dispose();
database.executeFast("CREATE INDEX IF NOT EXISTS unread_count_idx_dialogs ON dialogs(unread_count);").stepThis().dispose();
database.executeFast("UPDATE messages SET send_state = 2 WHERE mid < 0 AND send_state = 1").stepThis().dispose();
@ -690,7 +685,6 @@ public class MessagesStorage extends BaseController {
version = 43;
}
if (version == 43) {
database.executeFast("CREATE TABLE IF NOT EXISTS channel_admins(did INTEGER, uid INTEGER, PRIMARY KEY(did, uid))").stepThis().dispose();
database.executeFast("PRAGMA user_version = 44").stepThis().dispose();
version = 44;
}
@ -785,6 +779,19 @@ public class MessagesStorage extends BaseController {
version = 60;
}
if (version == 60) {
database.executeFast("DROP TABLE IF EXISTS channel_admins;").stepThis().dispose();
database.executeFast("DROP TABLE IF EXISTS blocked_users;").stepThis().dispose();
database.executeFast("CREATE TABLE IF NOT EXISTS channel_admins_v2(did INTEGER, uid INTEGER, rank TEXT, PRIMARY KEY(did, uid))").stepThis().dispose();
database.executeFast("PRAGMA user_version = 61").stepThis().dispose();
version = 61;
}
if (version == 61) {
database.executeFast("DROP INDEX IF EXISTS send_state_idx_messages;").stepThis().dispose();
database.executeFast("CREATE INDEX IF NOT EXISTS send_state_idx_messages2 ON messages(mid, send_state, date);").stepThis().dispose();
database.executeFast("PRAGMA user_version = 62").stepThis().dispose();
version = 62;
}
if (version == 62) {
}
} catch (Exception e) {
@ -1487,16 +1494,16 @@ public class MessagesStorage extends BaseController {
getChatsInternal(TextUtils.join(",", chatsToLoad), chats);
for (int a = 0; a < chats.size(); a++) {
TLRPC.Chat chat = chats.get(a);
if (chat != null && (chat.left || chat.migrated_to != null)) {
if (chat != null && (ChatObject.isNotInChat(chat) || chat.migrated_to != null)) {
long did = -chat.id;
database.executeFast("UPDATE dialogs SET unread_count = 0 WHERE did = " + did).stepThis().dispose();
database.executeFast(String.format(Locale.US, "UPDATE messages SET read_state = 3 WHERE uid = %d AND mid > 0 AND read_state IN(0,2) AND out = 0", did)).stepThis().dispose();
chats.remove(a);
a--;
pushDialogs.remove((long) -chat.id);
pushDialogs.remove(did);
for (int b = 0; b < messages.size(); b++) {
TLRPC.Message message = messages.get(b);
if (message.dialog_id == -chat.id) {
if (message.dialog_id == did) {
messages.remove(b);
b--;
}
@ -1715,68 +1722,6 @@ public class MessagesStorage extends BaseController {
});
}
public void getBlockedUsers() {
storageQueue.postRunnable(() -> {
try {
SparseIntArray ids = new SparseIntArray();
ArrayList<TLRPC.User> users = new ArrayList<>();
SQLiteCursor cursor = database.queryFinalized("SELECT * FROM blocked_users WHERE 1");
StringBuilder usersToLoad = new StringBuilder();
while (cursor.next()) {
int user_id = cursor.intValue(0);
ids.put(user_id, 1);
if (usersToLoad.length() != 0) {
usersToLoad.append(",");
}
usersToLoad.append(user_id);
}
cursor.dispose();
if (usersToLoad.length() != 0) {
getUsersInternal(usersToLoad.toString(), users);
}
getMessagesController().processLoadedBlockedUsers(ids, users, true);
} catch (Exception e) {
FileLog.e(e);
}
});
}
public void deleteBlockedUser(final int id) {
storageQueue.postRunnable(() -> {
try {
database.executeFast("DELETE FROM blocked_users WHERE uid = " + id).stepThis().dispose();
} catch (Exception e) {
FileLog.e(e);
}
});
}
public void putBlockedUsers(final SparseIntArray ids, final boolean replace) {
if (ids == null || ids.size() == 0) {
return;
}
storageQueue.postRunnable(() -> {
try {
if (replace) {
database.executeFast("DELETE FROM blocked_users WHERE 1").stepThis().dispose();
}
database.beginTransaction();
SQLitePreparedStatement state = database.executeFast("REPLACE INTO blocked_users VALUES(?)");
for (int a = 0, size = ids.size(); a < size; a++) {
state.requery();
state.bindInteger(1, ids.keyAt(a));
state.step();
}
state.dispose();
database.commitTransaction();
} catch (Exception e) {
FileLog.e(e);
}
});
}
public void deleteUserChannelHistory(final int channelId, final int uid) {
storageQueue.postRunnable(() -> {
try {
@ -1793,27 +1738,7 @@ public class MessagesStorage extends BaseController {
data.reuse();
if (message != null && message.from_id == uid && message.id != 1) {
mids.add(message.id);
if (message.media instanceof TLRPC.TL_messageMediaPhoto) {
for (int a = 0, N = message.media.photo.sizes.size(); a < N; a++) {
TLRPC.PhotoSize photoSize = message.media.photo.sizes.get(a);
File file = FileLoader.getPathToAttach(photoSize);
if (file != null && file.toString().length() > 0) {
filesToDelete.add(file);
}
}
} else if (message.media instanceof TLRPC.TL_messageMediaDocument) {
File file = FileLoader.getPathToAttach(message.media.document);
if (file != null && file.toString().length() > 0) {
filesToDelete.add(file);
}
for (int a = 0, N = message.media.document.thumbs.size(); a < N; a++) {
TLRPC.PhotoSize photoSize = message.media.document.thumbs.get(a);
file = FileLoader.getPathToAttach(photoSize);
if (file != null && file.toString().length() > 0) {
filesToDelete.add(file);
}
}
}
addFilesToDelete(message, filesToDelete, false);
}
}
}
@ -1822,7 +1747,7 @@ public class MessagesStorage extends BaseController {
}
cursor.dispose();
AndroidUtilities.runOnUIThread(() -> getMessagesController().markChannelDialogMessageAsDeleted(mids, channelId));
markMessagesAsDeletedInternal(mids, channelId);
markMessagesAsDeletedInternal(mids, channelId, false);
updateDialogsWithDeletedMessagesInternal(mids, null, channelId);
getFileLoader().deleteFiles(filesToDelete, 0);
if (!mids.isEmpty()) {
@ -1834,6 +1759,36 @@ public class MessagesStorage extends BaseController {
});
}
private boolean addFilesToDelete(TLRPC.Message message, ArrayList<File> filesToDelete, boolean forceCache) {
if (message == null) {
return false;
}
if (message.media instanceof TLRPC.TL_messageMediaPhoto && message.media.photo != null) {
for (int a = 0, N = message.media.photo.sizes.size(); a < N; a++) {
TLRPC.PhotoSize photoSize = message.media.photo.sizes.get(a);
File file = FileLoader.getPathToAttach(photoSize);
if (file != null && file.toString().length() > 0) {
filesToDelete.add(file);
}
}
return true;
} else if (message.media instanceof TLRPC.TL_messageMediaDocument && message.media.document != null) {
File file = FileLoader.getPathToAttach(message.media.document, forceCache);
if (file != null && file.toString().length() > 0) {
filesToDelete.add(file);
}
for (int a = 0, N = message.media.document.thumbs.size(); a < N; a++) {
TLRPC.PhotoSize photoSize = message.media.document.thumbs.get(a);
file = FileLoader.getPathToAttach(photoSize);
if (file != null && file.toString().length() > 0) {
filesToDelete.add(file);
}
}
return true;
}
return false;
}
public void deleteDialog(final long did, final int messagesOnly) {
storageQueue.postRunnable(() -> {
try {
@ -1858,29 +1813,7 @@ public class MessagesStorage extends BaseController {
TLRPC.Message message = TLRPC.Message.TLdeserialize(data, data.readInt32(false), false);
message.readAttachPath(data, getUserConfig().clientUserId);
data.reuse();
if (message != null && message.media != null) {
if (message.media instanceof TLRPC.TL_messageMediaPhoto) {
for (int a = 0, N = message.media.photo.sizes.size(); a < N; a++) {
TLRPC.PhotoSize photoSize = message.media.photo.sizes.get(a);
File file = FileLoader.getPathToAttach(photoSize);
if (file != null && file.toString().length() > 0) {
filesToDelete.add(file);
}
}
} else if (message.media instanceof TLRPC.TL_messageMediaDocument) {
File file = FileLoader.getPathToAttach(message.media.document);
if (file != null && file.toString().length() > 0) {
filesToDelete.add(file);
}
for (int a = 0, N = message.media.document.thumbs.size(); a < N; a++) {
TLRPC.PhotoSize photoSize = message.media.document.thumbs.get(a);
file = FileLoader.getPathToAttach(photoSize);
if (file != null && file.toString().length() > 0) {
filesToDelete.add(file);
}
}
}
}
addFilesToDelete(message, filesToDelete, false);
}
}
} catch (Exception e) {
@ -2219,29 +2152,7 @@ public class MessagesStorage extends BaseController {
message.readAttachPath(data, getUserConfig().clientUserId);
data.reuse();
if (message.media != null) {
if (message.media.document != null) {
File file = FileLoader.getPathToAttach(message.media.document, true);
if (file != null && file.toString().length() > 0) {
filesToDelete.add(file);
}
for (int a = 0, N = message.media.document.thumbs.size(); a < N; a++) {
TLRPC.PhotoSize photoSize = message.media.document.thumbs.get(a);
file = FileLoader.getPathToAttach(photoSize);
if (file != null && file.toString().length() > 0) {
filesToDelete.add(file);
}
}
message.media.document = new TLRPC.TL_documentEmpty();
} else if (message.media.photo != null) {
for (int a = 0, N = message.media.photo.sizes.size(); a < N; a++) {
TLRPC.PhotoSize photoSize = message.media.photo.sizes.get(a);
File file = FileLoader.getPathToAttach(photoSize);
if (file != null && file.toString().length() > 0) {
filesToDelete.add(file);
}
}
message.media.photo = new TLRPC.TL_photoEmpty();
} else {
if (!addFilesToDelete(message, filesToDelete, true)) {
continue;
}
message.media.flags = message.media.flags &~ 1;
@ -2747,10 +2658,10 @@ public class MessagesStorage extends BaseController {
public void loadChannelAdmins(final int chatId) {
storageQueue.postRunnable(() -> {
try {
SQLiteCursor cursor = database.queryFinalized("SELECT uid FROM channel_admins WHERE did = " + chatId);
ArrayList<Integer> ids = new ArrayList<>();
SQLiteCursor cursor = database.queryFinalized("SELECT uid, rank FROM channel_admins_v2 WHERE did = " + chatId);
SparseArray<String> ids = new SparseArray<>();
while (cursor.next()) {
ids.add(cursor.intValue(0));
ids.put(cursor.intValue(0), cursor.stringValue(1));
}
cursor.dispose();
getMessagesController().processLoadedChannelAdmins(ids, chatId, true);
@ -2760,17 +2671,18 @@ public class MessagesStorage extends BaseController {
});
}
public void putChannelAdmins(final int chatId, final ArrayList<Integer> ids) {
public void putChannelAdmins(final int chatId, final SparseArray<String> ids) {
storageQueue.postRunnable(() -> {
try {
database.executeFast("DELETE FROM channel_admins WHERE did = " + chatId).stepThis().dispose();
database.executeFast("DELETE FROM channel_admins_v2 WHERE did = " + chatId).stepThis().dispose();
database.beginTransaction();
SQLitePreparedStatement state = database.executeFast("REPLACE INTO channel_admins VALUES(?, ?)");
SQLitePreparedStatement state = database.executeFast("REPLACE INTO channel_admins_v2 VALUES(?, ?, ?)");
int date = (int) (System.currentTimeMillis() / 1000);
for (int a = 0; a < ids.size(); a++) {
state.requery();
state.bindInteger(1, chatId);
state.bindInteger(2, ids.get(a));
state.bindInteger(2, ids.keyAt(a));
state.bindString(3, ids.valueAt(a));
state.step();
}
state.dispose();
@ -3192,7 +3104,8 @@ public class MessagesStorage extends BaseController {
return result[0];
}
public void loadChatInfo(final int chat_id, final CountDownLatch countDownLatch, final boolean force, final boolean byChannelUsers) {
public TLRPC.ChatFull loadChatInfo(final int chat_id, final CountDownLatch countDownLatch, final boolean force, final boolean byChannelUsers) {
TLRPC.ChatFull[] result = new TLRPC.ChatFull[1];
storageQueue.postRunnable(() -> {
MessageObject pinnedMessageObject = null;
TLRPC.ChatFull info = null;
@ -3269,21 +3182,27 @@ public class MessagesStorage extends BaseController {
getUsersInternal(usersToLoad.toString(), loadedUsers);
}
}
if (countDownLatch != null) {
countDownLatch.countDown();
}
if (info != null && info.pinned_msg_id != 0) {
pinnedMessageObject = getMediaDataController().loadPinnedMessage(-chat_id, info instanceof TLRPC.TL_channelFull ? chat_id : 0, info.pinned_msg_id, false);
}
} catch (Exception e) {
FileLog.e(e);
} finally {
result[0] = info;
getMessagesController().processChatInfo(chat_id, info, loadedUsers, true, force, byChannelUsers, pinnedMessageObject);
if (countDownLatch != null) {
countDownLatch.countDown();
}
}
});
if (countDownLatch != null) {
try {
countDownLatch.await();
} catch (Throwable ignore) {
}
}
return result[0];
}
public void processPendingRead(final long dialog_id, final long maxPositiveId, final long maxNegativeId, final boolean isChannel) {
@ -3683,6 +3602,7 @@ public class MessagesStorage extends BaseController {
ArrayList<Integer> chatsToLoad = new ArrayList<>();
ArrayList<Integer> broadcastIds = new ArrayList<>();
ArrayList<Integer> encryptedChatIds = new ArrayList<>();
SQLiteCursor cursor = database.queryFinalized("SELECT m.read_state, m.data, m.send_state, m.mid, m.date, r.random_id, m.uid, s.seq_in, s.seq_out, m.ttl FROM messages as m LEFT JOIN randoms as r ON r.mid = m.mid LEFT JOIN messages_seq as s ON m.mid = s.mid WHERE (m.mid < 0 AND m.send_state = 1) OR (m.mid > 0 AND m.send_state = 3) ORDER BY m.mid DESC LIMIT " + count);
while (cursor.next()) {
NativeByteBuffer data = cursor.byteBufferValue(1);
@ -6291,7 +6211,7 @@ public class MessagesStorage extends BaseController {
if (!mids.isEmpty()) {
AndroidUtilities.runOnUIThread(() -> getNotificationCenter().postNotificationName(NotificationCenter.messagesDeleted, mids, 0));
updateDialogsWithReadMessagesInternal(mids, null, null, null);
markMessagesAsDeletedInternal(mids, 0);
markMessagesAsDeletedInternal(mids, 0, true);
updateDialogsWithDeletedMessagesInternal(mids, null, 0);
}
} catch (Exception e) {
@ -6308,7 +6228,7 @@ public class MessagesStorage extends BaseController {
}
}
private ArrayList<Long> markMessagesAsDeletedInternal(final ArrayList<Integer> messages, int channelId) {
private ArrayList<Long> markMessagesAsDeletedInternal(final ArrayList<Integer> messages, int channelId, boolean deleteFiles) {
try {
String ids;
final ArrayList<Integer> temp = new ArrayList<>(messages);
@ -6354,7 +6274,7 @@ public class MessagesStorage extends BaseController {
unread_count[0]++;
}
}
if ((int) did != 0) {
if ((int) did != 0 && !deleteFiles) {
continue;
}
NativeByteBuffer data = cursor.byteBufferValue(1);
@ -6362,29 +6282,7 @@ public class MessagesStorage extends BaseController {
TLRPC.Message message = TLRPC.Message.TLdeserialize(data, data.readInt32(false), false);
message.readAttachPath(data, getUserConfig().clientUserId);
data.reuse();
if (message != null) {
if (message.media instanceof TLRPC.TL_messageMediaPhoto) {
for (int a = 0, N = message.media.photo.sizes.size(); a < N; a++) {
TLRPC.PhotoSize photoSize = message.media.photo.sizes.get(a);
File file = FileLoader.getPathToAttach(photoSize);
if (file != null && file.toString().length() > 0) {
filesToDelete.add(file);
}
}
} else if (message.media instanceof TLRPC.TL_messageMediaDocument) {
File file = FileLoader.getPathToAttach(message.media.document);
if (file != null && file.toString().length() > 0) {
filesToDelete.add(file);
}
for (int a = 0, N = message.media.document.thumbs.size(); a < N; a++) {
TLRPC.PhotoSize photoSize = message.media.document.thumbs.get(a);
file = FileLoader.getPathToAttach(photoSize);
if (file != null && file.toString().length() > 0) {
filesToDelete.add(file);
}
}
}
}
addFilesToDelete(message, filesToDelete, false);
}
}
} catch (Exception e) {
@ -6650,19 +6548,19 @@ public class MessagesStorage extends BaseController {
}
}
public ArrayList<Long> markMessagesAsDeleted(final ArrayList<Integer> messages, boolean useQueue, final int channelId) {
public ArrayList<Long> markMessagesAsDeleted(final ArrayList<Integer> messages, boolean useQueue, final int channelId, boolean deleteFiles) {
if (messages.isEmpty()) {
return null;
}
if (useQueue) {
storageQueue.postRunnable(() -> markMessagesAsDeletedInternal(messages, channelId));
storageQueue.postRunnable(() -> markMessagesAsDeletedInternal(messages, channelId, deleteFiles));
} else {
return markMessagesAsDeletedInternal(messages, channelId);
return markMessagesAsDeletedInternal(messages, channelId, deleteFiles);
}
return null;
}
private ArrayList<Long> markMessagesAsDeletedInternal(final int channelId, final int mid) {
private ArrayList<Long> markMessagesAsDeletedInternal(final int channelId, final int mid, boolean deleteFiles) {
try {
String ids;
ArrayList<Long> dialogsIds = new ArrayList<>();
@ -6695,7 +6593,7 @@ public class MessagesStorage extends BaseController {
unread_count[0]++;
}
}
if ((int) did != 0) {
if ((int) did != 0 && !deleteFiles) {
continue;
}
NativeByteBuffer data = cursor.byteBufferValue(1);
@ -6703,29 +6601,7 @@ public class MessagesStorage extends BaseController {
TLRPC.Message message = TLRPC.Message.TLdeserialize(data, data.readInt32(false), false);
message.readAttachPath(data, getUserConfig().clientUserId);
data.reuse();
if (message != null) {
if (message.media instanceof TLRPC.TL_messageMediaPhoto) {
for (int a = 0, N = message.media.photo.sizes.size(); a < N; a++) {
TLRPC.PhotoSize photoSize = message.media.photo.sizes.get(a);
File file = FileLoader.getPathToAttach(photoSize);
if (file != null && file.toString().length() > 0) {
filesToDelete.add(file);
}
}
} else if (message.media instanceof TLRPC.TL_messageMediaDocument) {
File file = FileLoader.getPathToAttach(message.media.document);
if (file != null && file.toString().length() > 0) {
filesToDelete.add(file);
}
for (int a = 0, N = message.media.document.thumbs.size(); a < N; a++) {
TLRPC.PhotoSize photoSize = message.media.document.thumbs.get(a);
file = FileLoader.getPathToAttach(photoSize);
if (file != null && file.toString().length() > 0) {
filesToDelete.add(file);
}
}
}
}
addFilesToDelete(message, filesToDelete, false);
}
}
} catch (Exception e) {
@ -6768,11 +6644,11 @@ public class MessagesStorage extends BaseController {
return null;
}
public ArrayList<Long> markMessagesAsDeleted(final int channelId, final int mid, boolean useQueue) {
public ArrayList<Long> markMessagesAsDeleted(final int channelId, final int mid, boolean useQueue, boolean deleteFiles) {
if (useQueue) {
storageQueue.postRunnable(() -> markMessagesAsDeletedInternal(channelId, mid));
storageQueue.postRunnable(() -> markMessagesAsDeletedInternal(channelId, mid, deleteFiles));
} else {
return markMessagesAsDeletedInternal(channelId, mid);
return markMessagesAsDeletedInternal(channelId, mid, deleteFiles);
}
return null;
}
@ -7129,6 +7005,7 @@ public class MessagesStorage extends BaseController {
int minChannelMessageId = Integer.MAX_VALUE;
int maxChannelMessageId = 0;
int channelId = 0;
ArrayList<File> filesToDelete = new ArrayList<>();
for (int a = 0; a < count; a++) {
TLRPC.Message message = messages.messages.get(a);
@ -7154,6 +7031,15 @@ public class MessagesStorage extends BaseController {
message.attachPath = oldMessage.attachPath;
message.ttl = cursor.intValue(2);
}
boolean sameMedia = false;
if (oldMessage.media instanceof TLRPC.TL_messageMediaPhoto && message.media instanceof TLRPC.TL_messageMediaPhoto && oldMessage.media.photo != null && message.media.photo != null) {
sameMedia = oldMessage.media.photo.id == message.media.photo.id;
} else if (oldMessage.media instanceof TLRPC.TL_messageMediaDocument && message.media instanceof TLRPC.TL_messageMediaDocument && oldMessage.media.document != null && message.media.document != null) {
sameMedia = oldMessage.media.document.id == message.media.document.id;
}
if (!sameMedia) {
addFilesToDelete(oldMessage, filesToDelete, false);
}
}
boolean oldMention = cursor.intValue(3) != 0;
int readState = cursor.intValue(4);
@ -7294,6 +7180,7 @@ public class MessagesStorage extends BaseController {
if (botKeyboard != null) {
getMediaDataController().putBotKeyboard(dialog_id, botKeyboard);
}
getFileLoader().deleteFiles(filesToDelete, 0);
putUsersInternal(messages.users);
putChatsInternal(messages.chats);

View file

@ -93,6 +93,7 @@ public class NotificationCenter {
public static final int newPeopleNearbyAvailable = totalEvents++;
public static final int stopAllHeavyOperations = totalEvents++;
public static final int startAllHeavyOperations = totalEvents++;
public static final int sendingMessagesChanged = totalEvents++;
public static final int httpFileDidLoad = totalEvents++;
public static final int httpFileDidFailedLoad = totalEvents++;

View file

@ -16,121 +16,130 @@ import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
public class NotificationImageProvider extends ContentProvider implements NotificationCenter.NotificationCenterDelegate{
public class NotificationImageProvider extends ContentProvider implements NotificationCenter.NotificationCenterDelegate {
public static final String AUTHORITY=BuildConfig.APPLICATION_ID+".notification_image_provider";
public static final String AUTHORITY = BuildConfig.APPLICATION_ID + ".notification_image_provider";
private static final UriMatcher matcher=new UriMatcher(UriMatcher.NO_MATCH);
static{
private static final UriMatcher matcher = new UriMatcher(UriMatcher.NO_MATCH);
static {
matcher.addURI(AUTHORITY, "msg_media_raw/#/*", 1); // content://org.telegram..../msg_media_raw/account/filename.ext
}
private HashSet<String> waitingForFiles=new HashSet<>();
private final Object sync=new Object();
private HashMap<String, Long> fileStartTimes=new HashMap<>();
private HashSet<String> waitingForFiles = new HashSet<>();
private final Object sync = new Object();
private HashMap<String, Long> fileStartTimes = new HashMap<>();
@Override
public boolean onCreate(){
for(int i=0;i<UserConfig.getActivatedAccountsCount();i++){
public boolean onCreate() {
for (int i = 0; i < UserConfig.getActivatedAccountsCount(); i++) {
NotificationCenter.getInstance(i).addObserver(this, NotificationCenter.fileDidLoad);
}
return true;
}
@Override
public void shutdown(){
for(int i=0;i<UserConfig.getActivatedAccountsCount();i++){
public void shutdown() {
for (int i = 0; i < UserConfig.getActivatedAccountsCount(); i++) {
NotificationCenter.getInstance(i).removeObserver(this, NotificationCenter.fileDidLoad);
}
}
@Nullable
@Override
public Cursor query(@NonNull Uri uri, @Nullable String[] projection, @Nullable String selection, @Nullable String[] selectionArgs, @Nullable String sortOrder){
public Cursor query(@NonNull Uri uri, @Nullable String[] projection, @Nullable String selection, @Nullable String[] selectionArgs, @Nullable String sortOrder) {
return null;
}
@Nullable
@Override
public String getType(@NonNull Uri uri){
public String getType(@NonNull Uri uri) {
return null;
}
@Nullable
@Override
public Uri insert(@NonNull Uri uri, @Nullable ContentValues values){
public Uri insert(@NonNull Uri uri, @Nullable ContentValues values) {
return null;
}
@Override
public int delete(@NonNull Uri uri, @Nullable String selection, @Nullable String[] selectionArgs){
public int delete(@NonNull Uri uri, @Nullable String selection, @Nullable String[] selectionArgs) {
return 0;
}
@Override
public int update(@NonNull Uri uri, @Nullable ContentValues values, @Nullable String selection, @Nullable String[] selectionArgs){
public int update(@NonNull Uri uri, @Nullable ContentValues values, @Nullable String selection, @Nullable String[] selectionArgs) {
return 0;
}
@Nullable
@Override
public String[] getStreamTypes(@NonNull Uri uri, @NonNull String mimeTypeFilter){
if(mimeTypeFilter.startsWith("*/") || mimeTypeFilter.startsWith("image/"))
public String[] getStreamTypes(@NonNull Uri uri, @NonNull String mimeTypeFilter) {
if (mimeTypeFilter.startsWith("*/") || mimeTypeFilter.startsWith("image/")) {
return new String[]{"image/jpeg", "image/png", "image/webp"};
}
return null;
}
@Nullable
@Override
public ParcelFileDescriptor openFile(@NonNull Uri uri, @NonNull String mode) throws FileNotFoundException{
if(!"r".equals(mode))
public ParcelFileDescriptor openFile(@NonNull Uri uri, @NonNull String mode) throws FileNotFoundException {
if (!"r".equals(mode)) {
throw new SecurityException("Can only open files for read");
switch(matcher.match(uri)){
case 1:
{
List<String> path=uri.getPathSegments();
int account=Integer.parseInt(path.get(1));
String name=path.get(2);
String finalPath=uri.getQueryParameter("final_path");
String fallbackPath=uri.getQueryParameter("fallback");
File finalFile=new File(finalPath);
if(finalFile.exists()){
FileLog.d(finalFile+" already exists");
return ParcelFileDescriptor.open(finalFile, ParcelFileDescriptor.MODE_READ_ONLY);
}else{
Long _startTime=fileStartTimes.get(name);
long startTime=_startTime!=null ? _startTime : System.currentTimeMillis();
if(_startTime==null)
fileStartTimes.put(name, startTime);
while(!finalFile.exists()){
if(System.currentTimeMillis()-startTime>=3000){
if(BuildVars.LOGS_ENABLED)
FileLog.w("Waiting for "+name+" to download timed out");
if(TextUtils.isEmpty(fallbackPath))
throw new FileNotFoundException("Download timed out");
return ParcelFileDescriptor.open(new File(fallbackPath), ParcelFileDescriptor.MODE_READ_ONLY);
}
if (matcher.match(uri) == 1) {
List<String> path = uri.getPathSegments();
int account = Integer.parseInt(path.get(1));
String name = path.get(2);
String finalPath = uri.getQueryParameter("final_path");
String fallbackPath = uri.getQueryParameter("fallback");
File finalFile = new File(finalPath);
if (AndroidUtilities.isInternalUri(Uri.fromFile(finalFile))) {
throw new SecurityException("trying to read internal file");
}
if (finalFile.exists()) {
return ParcelFileDescriptor.open(finalFile, ParcelFileDescriptor.MODE_READ_ONLY);
} else {
Long _startTime = fileStartTimes.get(name);
long startTime = _startTime != null ? _startTime : System.currentTimeMillis();
if (_startTime == null) {
fileStartTimes.put(name, startTime);
}
while (!finalFile.exists()) {
if (System.currentTimeMillis() - startTime >= 3000) {
if (BuildVars.LOGS_ENABLED) {
FileLog.w("Waiting for " + name + " to download timed out");
}
synchronized(sync){
waitingForFiles.add(name);
try{
sync.wait(1000);
}catch(InterruptedException ignore){
}
if (TextUtils.isEmpty(fallbackPath)) {
throw new FileNotFoundException("Download timed out");
}
File file = new File(fallbackPath);
if (AndroidUtilities.isInternalUri(Uri.fromFile(file))) {
throw new SecurityException("trying to read internal file");
}
return ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_ONLY);
}
synchronized (sync) {
waitingForFiles.add(name);
try {
sync.wait(1000);
} catch (InterruptedException ignore) {
}
}
return ParcelFileDescriptor.open(finalFile, ParcelFileDescriptor.MODE_READ_ONLY);
}
return ParcelFileDescriptor.open(finalFile, ParcelFileDescriptor.MODE_READ_ONLY);
}
}
throw new FileNotFoundException("Invalid URI");
}
@Override
public void didReceivedNotification(int id, int account, Object... args){
if(id==NotificationCenter.fileDidLoad){
synchronized(sync){
String name=(String)args[0];
if(waitingForFiles.remove(name)){
public void didReceivedNotification(int id, int account, Object... args) {
if (id == NotificationCenter.fileDidLoad) {
synchronized (sync) {
String name = (String) args[0];
if (waitingForFiles.remove(name)) {
fileStartTimes.remove(name);
sync.notifyAll();
}

View file

@ -1045,6 +1045,9 @@ public class SecretChatHelper extends BaseController {
newMessage.media.ttl_seconds = newMessage.ttl;
newMessage.media.flags |= 4;
}
if (newMessage.message != null) {
newMessage.message = newMessage.message.replace('\u202E', ' ');
}
return newMessage;
} else if (object instanceof TLRPC.TL_decryptedMessageService) {
final TLRPC.TL_decryptedMessageService serviceMessage = (TLRPC.TL_decryptedMessageService) object;

View file

@ -31,6 +31,7 @@ import android.text.TextUtils;
import android.util.Base64;
import android.util.LongSparseArray;
import android.util.SparseArray;
import android.util.SparseIntArray;
import android.webkit.MimeTypeMap;
import android.widget.Toast;
@ -68,6 +69,10 @@ public class SendMessagesHelper extends BaseController implements NotificationCe
private HashMap<String, ArrayList<DelayedMessage>> delayedMessages = new HashMap<>();
private SparseArray<MessageObject> unsentMessages = new SparseArray<>();
private SparseArray<TLRPC.Message> sendingMessages = new SparseArray<>();
private SparseArray<TLRPC.Message> editingMessages = new SparseArray<>();
private SparseArray<TLRPC.Message> uploadMessages = new SparseArray<>();
private LongSparseArray<Integer> sendingMessagesIdDialogs = new LongSparseArray<>();
private LongSparseArray<Integer> uploadingMessagesIdDialogs = new LongSparseArray<>();
private HashMap<String, MessageObject> waitingForLocation = new HashMap<>();
private HashMap<String, Boolean> waitingForCallback = new HashMap<>();
private HashMap<String, byte[]> waitingForVote = new HashMap<>();
@ -361,6 +366,7 @@ public class SendMessagesHelper extends BaseController implements NotificationCe
obj.messageOwner.send_state = MessageObject.MESSAGE_SEND_STATE_SEND_ERROR;
getNotificationCenter().postNotificationName(NotificationCenter.messageSendError, obj.getId());
processSentMessage(obj.getId());
removeFromUploadingMessages(obj.getId());
}
delayedMessages.remove( "group_" + groupId);
} else {
@ -368,6 +374,7 @@ public class SendMessagesHelper extends BaseController implements NotificationCe
obj.messageOwner.send_state = MessageObject.MESSAGE_SEND_STATE_SEND_ERROR;
getNotificationCenter().postNotificationName(NotificationCenter.messageSendError, obj.getId());
processSentMessage(obj.getId());
removeFromUploadingMessages(obj.getId());
}
sendDelayedRequests();
}
@ -407,6 +414,10 @@ public class SendMessagesHelper extends BaseController implements NotificationCe
delayedMessages.clear();
unsentMessages.clear();
sendingMessages.clear();
editingMessages.clear();
sendingMessagesIdDialogs.clear();
uploadMessages.clear();
uploadingMessagesIdDialogs.clear();
waitingForLocation.clear();
waitingForCallback.clear();
waitingForVote.clear();
@ -807,6 +818,7 @@ public class SendMessagesHelper extends BaseController implements NotificationCe
public void cancelSendingMessage(ArrayList<MessageObject> objects) {
ArrayList<String> keysToRemove = new ArrayList<>();
ArrayList<DelayedMessage> checkReadyToSendGroups = new ArrayList<>();
ArrayList<Integer> messageIds = new ArrayList<>();
boolean enc = false;
int channelId = 0;
@ -830,6 +842,7 @@ public class SendMessagesHelper extends BaseController implements NotificationCe
messageObject = message.messageObjects.get(b);
if (messageObject.getId() == object.getId()) {
index = b;
removeFromUploadingMessages(object.getId());
break;
}
}
@ -862,13 +875,15 @@ public class SendMessagesHelper extends BaseController implements NotificationCe
TLRPC.TL_messages_messages messagesRes = new TLRPC.TL_messages_messages();
messagesRes.messages.add(prevMessage.messageOwner);
getMessagesStorage().putMessages(messagesRes, message.peer, -2, 0, false);
}
sendReadyToSendGroup(message, false, true);
if (!checkReadyToSendGroups.contains(message)) {
checkReadyToSendGroups.add(message);
}
}
}
break;
} else if (message.obj.getId() == object.getId()) {
removeFromUploadingMessages(object.getId());
messages.remove(a);
message.sendDelayedRequests();
MediaController.getInstance().cancelVideoConvert(message.obj);
@ -893,6 +908,9 @@ public class SendMessagesHelper extends BaseController implements NotificationCe
stopVideoService(key);
delayedMessages.remove(key);
}
for (int a = 0, N = checkReadyToSendGroups.size(); a < N; a++) {
sendReadyToSendGroup(checkReadyToSendGroups.get(a), false, true);
}
if (objects.size() == 1 && objects.get(0).isEditing() && objects.get(0).previousMedia != null) {
revertEditingMessageObject(objects.get(0));
} else {
@ -1381,9 +1399,7 @@ public class SendMessagesHelper extends BaseController implements NotificationCe
final TLRPC.TL_messages_forwardMessages req = new TLRPC.TL_messages_forwardMessages();
req.to_peer = inputPeer;
req.grouped = lastGroupedId != 0;
if (req.to_peer instanceof TLRPC.TL_inputPeerChannel) {
req.silent = MessagesController.getNotificationsSettings(currentAccount).getBoolean("silent_" + peer, false);
}
req.silent = MessagesController.getNotificationsSettings(currentAccount).getBoolean("silent_" + peer, false);
if (msgObj.messageOwner.to_id instanceof TLRPC.TL_peerChannel) {
TLRPC.Chat channel = getMessagesController().getChat(msgObj.messageOwner.to_id.channel_id);
req.from_peer = new TLRPC.TL_inputPeerChannel();
@ -2149,7 +2165,11 @@ public class SendMessagesHelper extends BaseController implements NotificationCe
TLRPC.TL_messages_sendMedia request = new TLRPC.TL_messages_sendMedia();
request.peer = peer;
if (request.peer instanceof TLRPC.TL_inputPeerChannel) {
request.silent = MessagesController.getNotificationsSettings(currentAccount).getBoolean("silent_" + peer.channel_id, false);
request.silent = MessagesController.getNotificationsSettings(currentAccount).getBoolean("silent_" + -peer.channel_id, false);
} else if (request.peer instanceof TLRPC.TL_inputPeerChat) {
request.silent = MessagesController.getNotificationsSettings(currentAccount).getBoolean("silent_" + -peer.chat_id, false);
} else {
request.silent = MessagesController.getNotificationsSettings(currentAccount).getBoolean("silent_" + peer.user_id, false);
}
request.random_id = random_id != 0 ? random_id : getNextRandomId();
request.message = "";
@ -2260,7 +2280,7 @@ public class SendMessagesHelper extends BaseController implements NotificationCe
if (retryMessageObject.isForwarded()) {
type = 4;
} else {
if (retryMessageObject.type == 0) {
if (retryMessageObject.type == 0 || retryMessageObject.isAnimatedEmoji()) {
if (retryMessageObject.messageOwner.media instanceof TLRPC.TL_messageMediaGame) {
//game = retryMessageObject.messageOwner.media.game;
} else {
@ -2284,7 +2304,7 @@ public class SendMessagesHelper extends BaseController implements NotificationCe
user.restriction_reason = newMsg.media.vcard;
user.id = newMsg.media.user_id;
type = 6;
} else if (retryMessageObject.type == 8 || retryMessageObject.type == 9 || retryMessageObject.type == 13 || retryMessageObject.type == 14) {
} else if (retryMessageObject.type == 8 || retryMessageObject.type == 9 || retryMessageObject.type == MessageObject.TYPE_STICKER || retryMessageObject.type == 14 || retryMessageObject.type == MessageObject.TYPE_ANIMATED_STICKER) {
document = (TLRPC.TL_document) newMsg.media.document;
type = 7;
} else if (retryMessageObject.type == 2) {
@ -2624,8 +2644,7 @@ public class SendMessagesHelper extends BaseController implements NotificationCe
}
newMsg.send_state = MessageObject.MESSAGE_SEND_STATE_SENDING;
newMsgObj = new MessageObject(currentAccount, newMsg, true);
newMsgObj.replyMessageObject = reply_to_msg;
newMsgObj = new MessageObject(currentAccount, newMsg, reply_to_msg, true);
if (!newMsgObj.isForwarded() && (newMsgObj.type == 3 || videoEditedInfo != null || newMsgObj.type == 2) && !TextUtils.isEmpty(newMsg.attachPath)) {
newMsgObj.attachPathExists = true;
}
@ -2698,9 +2717,7 @@ public class SendMessagesHelper extends BaseController implements NotificationCe
TLRPC.TL_messages_sendMessage reqSend = new TLRPC.TL_messages_sendMessage();
reqSend.message = message;
reqSend.clear_draft = retryMessageObject == null;
if (newMsg.to_id instanceof TLRPC.TL_peerChannel) {
reqSend.silent = MessagesController.getNotificationsSettings(currentAccount).getBoolean("silent_" + peer, false);
}
reqSend.silent = MessagesController.getNotificationsSettings(currentAccount).getBoolean("silent_" + peer, false);
reqSend.peer = sendToPeer;
reqSend.random_id = newMsg.random_id;
if (newMsg.reply_to_msg_id != 0) {
@ -2989,9 +3006,7 @@ public class SendMessagesHelper extends BaseController implements NotificationCe
} else {
request = new TLRPC.TL_messages_sendMultiMedia();
request.peer = sendToPeer;
if (newMsg.to_id instanceof TLRPC.TL_peerChannel) {
request.silent = MessagesController.getNotificationsSettings(currentAccount).getBoolean("silent_" + peer, false);
}
request.silent = MessagesController.getNotificationsSettings(currentAccount).getBoolean("silent_" + peer, false);
if (newMsg.reply_to_msg_id != 0) {
request.flags |= 1;
request.reply_to_msg_id = newMsg.reply_to_msg_id;
@ -3019,9 +3034,7 @@ public class SendMessagesHelper extends BaseController implements NotificationCe
} else {
TLRPC.TL_messages_sendMedia request = new TLRPC.TL_messages_sendMedia();
request.peer = sendToPeer;
if (newMsg.to_id instanceof TLRPC.TL_peerChannel) {
request.silent = MessagesController.getNotificationsSettings(currentAccount).getBoolean("silent_" + peer, false);
}
request.silent = MessagesController.getNotificationsSettings(currentAccount).getBoolean("silent_" + peer, false);
if (newMsg.reply_to_msg_id != 0) {
request.flags |= 1;
request.reply_to_msg_id = newMsg.reply_to_msg_id;
@ -3353,9 +3366,7 @@ public class SendMessagesHelper extends BaseController implements NotificationCe
} else {
reqSend.from_peer = new TLRPC.TL_inputPeerEmpty();
}
if (retryMessageObject.messageOwner.to_id instanceof TLRPC.TL_peerChannel) {
reqSend.silent = MessagesController.getNotificationsSettings(currentAccount).getBoolean("silent_" + peer, false);
}
reqSend.silent = MessagesController.getNotificationsSettings(currentAccount).getBoolean("silent_" + peer, false);
reqSend.random_id.add(newMsg.random_id);
if (retryMessageObject.getId() >= 0) {
reqSend.id.add(retryMessageObject.getId());
@ -3376,9 +3387,7 @@ public class SendMessagesHelper extends BaseController implements NotificationCe
reqSend.flags |= 1;
reqSend.reply_to_msg_id = newMsg.reply_to_msg_id;
}
if (newMsg.to_id instanceof TLRPC.TL_peerChannel) {
reqSend.silent = MessagesController.getNotificationsSettings(currentAccount).getBoolean("silent_" + peer, false);
}
reqSend.silent = MessagesController.getNotificationsSettings(currentAccount).getBoolean("silent_" + peer, false);
reqSend.query_id = Utilities.parseLong(params.get("query_id"));
reqSend.id = params.get("id");
if (retryMessageObject == null) {
@ -3440,6 +3449,7 @@ public class SendMessagesHelper extends BaseController implements NotificationCe
String location = FileLoader.getPathToAttach(message.photoSize).toString();
putToDelayedMessages(location, message);
getFileLoader().uploadFile(location, false, true, ConnectionsManager.FileTypePhoto);
putToUploadingMessages(message.obj);
} else {
String location = FileLoader.getPathToAttach(message.photoSize).toString();
if (message.sendEncryptedRequest != null && message.photoSize.location.dc_id != 0) {
@ -3456,6 +3466,7 @@ public class SendMessagesHelper extends BaseController implements NotificationCe
}
putToDelayedMessages(location, message);
getFileLoader().uploadFile(location, true, true, ConnectionsManager.FileTypePhoto);
putToUploadingMessages(message.obj);
}
}
} else if (message.type == 1) {
@ -3467,6 +3478,7 @@ public class SendMessagesHelper extends BaseController implements NotificationCe
}
putToDelayedMessages(location, message);
MediaController.getInstance().scheduleVideoConvert(message.obj);
putToUploadingMessages(message.obj);
} else {
if (message.videoEditedInfo != null) {
if (message.videoEditedInfo.file != null) {
@ -3511,10 +3523,12 @@ public class SendMessagesHelper extends BaseController implements NotificationCe
} else {
getFileLoader().uploadFile(location, false, false, ConnectionsManager.FileTypeVideo);
}
putToUploadingMessages(message.obj);
} else {
String location = FileLoader.getDirectory(FileLoader.MEDIA_DIR_CACHE) + "/" + message.photoSize.location.volume_id + "_" + message.photoSize.location.local_id + ".jpg";
putToDelayedMessages(location, message);
getFileLoader().uploadFile(location, false, true, ConnectionsManager.FileTypePhoto);
putToUploadingMessages(message.obj);
}
} else {
String location = message.obj.messageOwner.attachPath;
@ -3536,6 +3550,7 @@ public class SendMessagesHelper extends BaseController implements NotificationCe
} else {
getFileLoader().uploadFile(location, true, false, ConnectionsManager.FileTypeVideo);
}
putToUploadingMessages(message.obj);
}
}
} else if (message.type == 2) {
@ -3556,10 +3571,12 @@ public class SendMessagesHelper extends BaseController implements NotificationCe
String location = message.obj.messageOwner.attachPath;
putToDelayedMessages(location, message);
getFileLoader().uploadFile(location, message.sendRequest == null, false, ConnectionsManager.FileTypeFile);
putToUploadingMessages(message.obj);
} else if (media.thumb == null && message.photoSize != null) {
String location = FileLoader.getDirectory(FileLoader.MEDIA_DIR_CACHE) + "/" + message.photoSize.location.volume_id + "_" + message.photoSize.location.local_id + ".jpg";
putToDelayedMessages(location, message);
getFileLoader().uploadFile(location, false, true, ConnectionsManager.FileTypePhoto);
putToUploadingMessages(message.obj);
}
} else {
String location = message.obj.messageOwner.attachPath;
@ -3574,12 +3591,14 @@ public class SendMessagesHelper extends BaseController implements NotificationCe
}
putToDelayedMessages(location, message);
getFileLoader().uploadFile(location, true, false, ConnectionsManager.FileTypeFile);
putToUploadingMessages(message.obj);
}
}
} else if (message.type == 3) {
String location = message.obj.messageOwner.attachPath;
putToDelayedMessages(location, message);
getFileLoader().uploadFile(location, message.sendRequest == null, true, ConnectionsManager.FileTypeAudio);
putToUploadingMessages(message.obj);
} else if (message.type == 4) {
boolean add = index < 0;
if (message.performMediaUpload) {
@ -3601,6 +3620,8 @@ public class SendMessagesHelper extends BaseController implements NotificationCe
message.extraHashMap.put(location + "_t", message.photoSize);
}
MediaController.getInstance().scheduleVideoConvert(messageObject);
message.obj = messageObject;
putToUploadingMessages(messageObject);
} else {
TLRPC.Document document = messageObject.getDocument();
String documentLocation = messageObject.messageOwner.attachPath;
@ -3623,6 +3644,7 @@ public class SendMessagesHelper extends BaseController implements NotificationCe
} else {
getFileLoader().uploadFile(documentLocation, false, false, ConnectionsManager.FileTypeVideo);
}
putToUploadingMessages(messageObject);
} else {
String location = FileLoader.getDirectory(FileLoader.MEDIA_DIR_CACHE) + "/" + message.photoSize.location.volume_id + "_" + message.photoSize.location.local_id + ".jpg";
putToDelayedMessages(location, message);
@ -3630,6 +3652,7 @@ public class SendMessagesHelper extends BaseController implements NotificationCe
message.extraHashMap.put(messageObject, location);
message.extraHashMap.put(location, media);
getFileLoader().uploadFile(location, false, true, ConnectionsManager.FileTypePhoto);
putToUploadingMessages(messageObject);
}
} else {
TLRPC.TL_messages_sendEncryptedMultiMedia request = (TLRPC.TL_messages_sendEncryptedMultiMedia) message.sendEncryptedRequest;
@ -3645,6 +3668,7 @@ public class SendMessagesHelper extends BaseController implements NotificationCe
} else {
getFileLoader().uploadFile(documentLocation, true, false, ConnectionsManager.FileTypeVideo);
}
putToUploadingMessages(messageObject);
}
}
message.videoEditedInfo = null;
@ -3670,12 +3694,13 @@ public class SendMessagesHelper extends BaseController implements NotificationCe
message.extraHashMap.put(location, inputMedia);
message.extraHashMap.put(messageObject, location);
getFileLoader().uploadFile(location, message.sendEncryptedRequest != null, true, ConnectionsManager.FileTypePhoto);
putToUploadingMessages(messageObject);
message.photoSize = null;
}
}
message.performMediaUpload = false;
} else if (!message.messageObjects.isEmpty()) {
putToSendingMessages(message.messageObjects.get(message.messageObjects.size() - 1).messageOwner);
putToSendingMessages(message.messageObjects.get(message.messageObjects.size() - 1).messageOwner, message.finalGroupMessage != 0);
}
sendReadyToSendGroup(message, add, true);
}
@ -3805,19 +3830,121 @@ public class SendMessagesHelper extends BaseController implements NotificationCe
}
protected void putToSendingMessages(TLRPC.Message message) {
sendingMessages.put(message.id, message);
if (Thread.currentThread() != ApplicationLoader.applicationHandler.getLooper().getThread()) {
AndroidUtilities.runOnUIThread(() -> putToSendingMessages(message, true));
} else {
putToSendingMessages(message, true);
}
}
protected void putToSendingMessages(TLRPC.Message message, boolean notify) {
if (message == null) {
return;
}
if (message.id > 0) {
editingMessages.put(message.id, message);
} else {
boolean contains = sendingMessages.indexOfKey(message.id) >= 0;
removeFromUploadingMessages(message.id);
sendingMessages.put(message.id, message);
if (!contains) {
long did = MessageObject.getDialogId(message);
sendingMessagesIdDialogs.put(did, sendingMessagesIdDialogs.get(did, 0) + 1);
if (notify) {
getNotificationCenter().postNotificationName(NotificationCenter.sendingMessagesChanged);
}
}
}
}
protected TLRPC.Message removeFromSendingMessages(int mid) {
TLRPC.Message message = sendingMessages.get(mid);
if (message != null) {
sendingMessages.remove(mid);
TLRPC.Message message;
if (mid > 0) {
message = editingMessages.get(mid);
if (message != null) {
editingMessages.remove(mid);
}
} else {
message = sendingMessages.get(mid);
if (message != null) {
sendingMessages.remove(mid);
long did = MessageObject.getDialogId(message);
Integer currentCount = sendingMessagesIdDialogs.get(did);
if (currentCount != null) {
int count = currentCount - 1;
if (count <= 0) {
sendingMessagesIdDialogs.remove(did);
} else {
sendingMessagesIdDialogs.put(did, count);
}
getNotificationCenter().postNotificationName(NotificationCenter.sendingMessagesChanged);
}
}
}
return message;
}
public int getSendingMessageId(long did) {
for (int a = 0; a < sendingMessages.size(); a++) {
TLRPC.Message message = sendingMessages.valueAt(a);
if (message.dialog_id == did) {
return message.id;
}
}
for (int a = 0; a < uploadMessages.size(); a++) {
TLRPC.Message message = uploadMessages.valueAt(a);
if (message.dialog_id == did) {
return message.id;
}
}
return 0;
}
protected void putToUploadingMessages(MessageObject obj) {
if (obj == null || obj.getId() > 0) {
return;
}
TLRPC.Message message = obj.messageOwner;
boolean contains = uploadMessages.indexOfKey(message.id) >= 0;
uploadMessages.put(message.id, message);
if (!contains) {
long did = MessageObject.getDialogId(message);
uploadingMessagesIdDialogs.put(did, uploadingMessagesIdDialogs.get(did, 0) + 1);
getNotificationCenter().postNotificationName(NotificationCenter.sendingMessagesChanged);
}
}
protected void removeFromUploadingMessages(int mid) {
if (mid > 0) {
return;
}
TLRPC.Message message = uploadMessages.get(mid);
if (message != null) {
uploadMessages.remove(mid);
long did = MessageObject.getDialogId(message);
Integer currentCount = uploadingMessagesIdDialogs.get(did);
if (currentCount != null) {
int count = currentCount - 1;
if (count <= 0) {
uploadingMessagesIdDialogs.remove(did);
} else {
uploadingMessagesIdDialogs.put(did, count);
}
getNotificationCenter().postNotificationName(NotificationCenter.sendingMessagesChanged);
}
}
}
public boolean isSendingMessage(int mid) {
return sendingMessages.indexOfKey(mid) >= 0;
return sendingMessages.indexOfKey(mid) >= 0 || editingMessages.indexOfKey(mid) >= 0;
}
public boolean isSendingMessageIdDialog(long did) {
return sendingMessagesIdDialogs.get(did, 0) > 0;
}
public boolean isUploadingMessageIdDialog(long did) {
return uploadingMessagesIdDialogs.get(did, 0) > 0;
}
protected void performSendMessageRequestMulti(final TLRPC.TL_messages_sendMultiMedia req, final ArrayList<MessageObject> msgObjs, final ArrayList<String> originalPaths, final ArrayList<Object> parentObjects, DelayedMessage delayedMessage) {

View file

@ -17,6 +17,7 @@ import android.os.Environment;
import android.os.SystemClock;
import android.text.TextUtils;
import android.util.Base64;
import android.util.SparseArray;
import org.json.JSONObject;
import org.telegram.tgnet.ConnectionsManager;
@ -53,6 +54,9 @@ public class SharedConfig {
public static boolean useFingerprint = true;
public static String lastUpdateVersion;
public static int suggestStickers;
public static boolean loopStickers;
public static int keepMedia = 2;
public static int lastKeepMediaCheckTime;
private static int lastLocalId = -210000;
private static String passportConfigJson = "";
@ -72,7 +76,6 @@ public class SharedConfig {
public static boolean directShare = true;
public static boolean inappCamera = true;
public static boolean roundCamera16to9 = true;
public static boolean groupPhotosEnabled = true;
public static boolean noSoundHintShowed = false;
public static boolean streamMedia = true;
public static boolean streamAllVideo = false;
@ -231,7 +234,6 @@ public class SharedConfig {
inappCamera = preferences.getBoolean("inappCamera", true);
hasCameraCache = preferences.contains("cameraCache");
roundCamera16to9 = true;//preferences.getBoolean("roundCamera16to9", false);
groupPhotosEnabled = preferences.getBoolean("groupPhotosEnabled", true);
repeatMode = preferences.getInt("repeatMode", 0);
fontSize = preferences.getInt("fons_size", AndroidUtilities.isTablet() ? 18 : 16);
allowBigEmoji = preferences.getBoolean("allowBigEmoji", true);
@ -248,6 +250,9 @@ public class SharedConfig {
archiveHidden = preferences.getBoolean("archiveHidden", false);
distanceSystemType = preferences.getInt("distanceSystemType", 0);
devicePerformanceClass = preferences.getInt("devicePerformanceClass", -1);
loopStickers = preferences.getBoolean("loopStickers", true);
keepMedia = preferences.getInt("keep_media", 2);
lastKeepMediaCheckTime = preferences.getInt("lastKeepMediaCheckTime", 0);
preferences = ApplicationLoader.applicationContext.getSharedPreferences("Notifications", Activity.MODE_PRIVATE);
showNotificationsForAllAccounts = preferences.getBoolean("AllAccounts", true);
@ -374,6 +379,64 @@ public class SharedConfig {
editor.commit();
}
public static void setKeepMedia(int value) {
keepMedia = value;
SharedPreferences preferences = MessagesController.getGlobalMainSettings();
SharedPreferences.Editor editor = preferences.edit();
editor.putInt("keep_media", keepMedia);
editor.commit();
}
public static void checkKeepMedia() {
int time = (int) (System.currentTimeMillis() / 1000);
if (keepMedia == 2 || Math.abs(time - lastKeepMediaCheckTime) < 24 * 60 * 60) {
return;
}
lastKeepMediaCheckTime = time;
Utilities.globalQueue.postRunnable(() -> {
int days;
if (keepMedia == 0) {
days = 7;
} else if (keepMedia == 1) {
days = 30;
} else {
days = 3;
}
long currentTime = time - 60 * 60 * 24 * days;
final SparseArray<File> paths = ImageLoader.getInstance().createMediaPaths();
for (int a = 0; a < paths.size(); a++) {
if (paths.keyAt(a) == FileLoader.MEDIA_DIR_CACHE) {
continue;
}
try {
Utilities.clearDir(paths.valueAt(a).getAbsolutePath(), 0, currentTime);
} catch (Throwable e) {
FileLog.e(e);
}
}
SharedPreferences preferences = MessagesController.getGlobalMainSettings();
SharedPreferences.Editor editor = preferences.edit();
editor.putInt("lastKeepMediaCheckTime", lastKeepMediaCheckTime);
editor.commit();
});
}
public static void toggleLoopStickers() {
loopStickers = !loopStickers;
SharedPreferences preferences = MessagesController.getGlobalMainSettings();
SharedPreferences.Editor editor = preferences.edit();
editor.putBoolean("loopStickers", loopStickers);
editor.commit();
}
public static void toggleBigEmoji() {
allowBigEmoji = !allowBigEmoji;
SharedPreferences preferences = MessagesController.getGlobalMainSettings();
SharedPreferences.Editor editor = preferences.edit();
editor.putBoolean("allowBigEmoji", allowBigEmoji);
editor.commit();
}
public static void toggleShuffleMusic(int type) {
if (type == 2) {
shuffleMusic = !shuffleMusic;
@ -545,14 +608,6 @@ public class SharedConfig {
editor.commit();
}
public static void toggleGroupPhotosEnabled() {
groupPhotosEnabled = !groupPhotosEnabled;
SharedPreferences preferences = MessagesController.getGlobalMainSettings();
SharedPreferences.Editor editor = preferences.edit();
editor.putBoolean("groupPhotosEnabled", groupPhotosEnabled);
editor.commit();
}
public static void setDistanceSystemType(int type) {
distanceSystemType = type;
SharedPreferences preferences = MessagesController.getGlobalMainSettings();

View file

@ -1,78 +0,0 @@
/*
* This is the source code of Telegram for Android v. 5.x.x.
* It is licensed under GNU GPL v. 2 or later.
* You should have received a copy of the license in this archive (see LICENSE).
*
* Copyright Nikolai Kudashov, 2013-2018.
*/
package org.telegram.messenger;
import android.annotation.TargetApi;
import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.provider.Telephony;
import android.telephony.SmsMessage;
import android.text.TextUtils;
import com.google.android.gms.auth.api.phone.SmsRetriever;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@TargetApi(26)
public class SmsReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
if (intent == null) {
return;
}
try {
String message = "";
SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("mainconfig", Activity.MODE_PRIVATE);
String hash = preferences.getString("sms_hash", null);
if (SmsRetriever.SMS_RETRIEVED_ACTION.equals(intent.getAction())) {
if (!AndroidUtilities.isWaitingForSms()) {
return;
}
Bundle bundle = intent.getExtras();
message = (String) bundle.get(SmsRetriever.EXTRA_SMS_MESSAGE);
} else {
if (TextUtils.isEmpty(hash)) {
return;
}
SmsMessage[] msgs = Telephony.Sms.Intents.getMessagesFromIntent(intent);
if (msgs == null || msgs.length <= 0) {
return;
}
for (int i = 0; i < msgs.length; i++) {
message += msgs[i].getMessageBody();
}
if (!message.contains(hash)) {
return;
}
}
if (TextUtils.isEmpty(message)) {
return;
}
Pattern pattern = Pattern.compile("[0-9\\-]+");
final Matcher matcher = pattern.matcher(message);
if (matcher.find()) {
String code = matcher.group(0).replace("-", "");
if (code.length() >= 3) {
if (preferences != null && hash != null) {
preferences.edit().putString("sms_hash_code", hash + "|" + code).commit();
}
AndroidUtilities.runOnUIThread(() -> NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.didReceiveSmsCode, code));
}
}
} catch (Throwable e) {
FileLog.e(e);
}
}
}

View file

@ -32,7 +32,6 @@ public class UserConfig extends BaseController {
public int lastBroadcastId = -1;
public int contactsSavedCount;
public int clientUserId;
public boolean blockedUsersLoaded;
public int lastContactsSyncTime;
public int lastHintsSyncTime;
public boolean draftsLoaded;
@ -118,7 +117,6 @@ public class UserConfig extends BaseController {
editor.putInt("lastSendMessageId", lastSendMessageId);
editor.putInt("contactsSavedCount", contactsSavedCount);
editor.putInt("lastBroadcastId", lastBroadcastId);
editor.putBoolean("blockedUsersLoaded", blockedUsersLoaded);
editor.putInt("lastContactsSyncTime", lastContactsSyncTime);
editor.putInt("lastHintsSyncTime", lastHintsSyncTime);
editor.putBoolean("draftsLoaded", draftsLoaded);
@ -255,7 +253,6 @@ public class UserConfig extends BaseController {
lastSendMessageId = preferences.getInt("lastSendMessageId", -210000);
contactsSavedCount = preferences.getInt("contactsSavedCount", 0);
lastBroadcastId = preferences.getInt("lastBroadcastId", -1);
blockedUsersLoaded = preferences.getBoolean("blockedUsersLoaded", false);
lastContactsSyncTime = preferences.getInt("lastContactsSyncTime", (int) (System.currentTimeMillis() / 1000) - 23 * 60 * 60);
lastHintsSyncTime = preferences.getInt("lastHintsSyncTime", (int) (System.currentTimeMillis() / 1000) - 25 * 60 * 60);
draftsLoaded = preferences.getBoolean("draftsLoaded", false);
@ -399,7 +396,6 @@ public class UserConfig extends BaseController {
contactsSavedCount = 0;
lastSendMessageId = -210000;
lastBroadcastId = -1;
blockedUsersLoaded = false;
notificationsSettingsLoaded = false;
notificationsSignUpSettingsLoaded = false;
migrateOffsetId = -1;

View file

@ -91,11 +91,11 @@ public class Utilities {
aesCbcEncryptionByteArray(buffer, key, iv.clone(), offset, length, n, encrypt);
}
public static Integer parseInt(String value) {
public static Integer parseInt(CharSequence value) {
if (value == null) {
return 0;
}
Integer val = 0;
int val = 0;
try {
Matcher matcher = pattern.matcher(value);
if (matcher.find()) {
@ -112,7 +112,7 @@ public class Utilities {
if (value == null) {
return 0L;
}
Long val = 0L;
long val = 0L;
try {
Matcher matcher = pattern.matcher(value);
if (matcher.find()) {

View file

@ -15,6 +15,8 @@ import java.util.Locale;
public class VideoEditedInfo {
public long startTime;
public long endTime;
public float start;
public float end;
public int rotationValue;
public int originalWidth;
public int originalHeight;

View file

@ -41,7 +41,6 @@ import org.telegram.messenger.support.customtabsclient.shared.ServiceConnectionC
import org.telegram.tgnet.ConnectionsManager;
import org.telegram.tgnet.TLRPC;
import org.telegram.ui.ActionBar.AlertDialog;
import org.telegram.ui.ActionBar.Theme;
import org.telegram.ui.LaunchActivity;
import java.lang.ref.WeakReference;
@ -287,7 +286,7 @@ public class Browser {
CustomTabsIntent.Builder builder = new CustomTabsIntent.Builder(getSession());
builder.addMenuItem(LocaleController.getString("CopyLink", R.string.CopyLink), copy);
builder.setToolbarColor(Theme.getColor(Theme.key_actionBarDefault));
builder.setToolbarColor(0xffffffff);
builder.setShowTitle(true);
builder.setActionButton(BitmapFactory.decodeResource(context.getResources(), R.drawable.abc_ic_menu_share_mtrl_alpha), LocaleController.getString("ShareFile", R.string.ShareFile), PendingIntent.getBroadcast(ApplicationLoader.applicationContext, 0, share, 0), false);
CustomTabsIntent intent = builder.build();

View file

@ -242,6 +242,10 @@ public class CameraController implements MediaRecorder.OnInfoListener {
return cameraInitied && cameraInfos != null && !cameraInfos.isEmpty();
}
public void runOnThreadPool(Runnable runnable) {
threadPool.execute(runnable);
}
public void close(final CameraSession session, final CountDownLatch countDownLatch, final Runnable beforeDestroyRunnable) {
session.destroy();
threadPool.execute(() -> {

View file

@ -38,23 +38,22 @@ public class CameraSession {
private final Size previewSize;
private final int pictureFormat;
private boolean initied;
private int maxZoom;
private boolean meteringAreaSupported;
private int currentOrientation;
private int diffOrientation;
private int jpegOrientation;
private boolean sameTakePictureOrientation;
private boolean flipFront = true;
private float currentZoom;
public static final int ORIENTATION_HYSTERESIS = 5;
private Camera.AutoFocusCallback autoFocusCallback = new Camera.AutoFocusCallback() {
@Override
public void onAutoFocus(boolean success, Camera camera) {
if (success) {
private Camera.AutoFocusCallback autoFocusCallback = (success, camera) -> {
if (success) {
} else {
} else {
}
}
};
@ -335,6 +334,10 @@ public class CameraSession {
params.setPreviewSize(previewSize.getWidth(), previewSize.getHeight());
params.setPictureSize(pictureSize.getWidth(), pictureSize.getHeight());
params.setPictureFormat(pictureFormat);
params.setJpegQuality(100);
params.setJpegThumbnailQuality(100);
maxZoom = params.getMaxZoom();
params.setZoom((int) (currentZoom * maxZoom));
String desiredMode = Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE;
if (params.getSupportedFocusModes().contains(desiredMode)) {
@ -380,7 +383,6 @@ public class CameraSession {
try {
Camera camera = cameraInfo.camera;
if (camera != null) {
camera.cancelAutoFocus();
Camera.Parameters parameters = null;
try {
@ -414,6 +416,15 @@ public class CameraSession {
}
}
protected int getMaxZoom() {
return maxZoom;
}
protected void setZoom(float value) {
currentZoom = value;
configurePhotoCamera();
}
protected void configureRecorder(int quality, MediaRecorder recorder) {
Camera.CameraInfo info = new Camera.CameraInfo();
Camera.getCameraInfo(cameraInfo.cameraId, info);
@ -509,9 +520,10 @@ public class CameraSession {
cameraInfo.camera.setPreviewCallback(callback);
}
public void setOneShotPreviewCallback(Camera.PreviewCallback callback){
if(cameraInfo!=null && cameraInfo.camera!=null)
cameraInfo.camera.setOneShotPreviewCallback(callback);
public void setOneShotPreviewCallback(Camera.PreviewCallback callback) {
if (cameraInfo != null && cameraInfo.camera != null) {
cameraInfo.camera.setOneShotPreviewCallback(callback);
}
}
public void destroy() {

View file

@ -40,7 +40,7 @@ public class CameraView extends FrameLayout implements TextureView.SurfaceTextur
private boolean initied;
private CameraViewDelegate delegate;
private int clipTop;
private int clipLeft;
private int clipBottom;
private boolean isFrontface;
private Matrix txform = new Matrix();
private Matrix matrix = new Matrix();
@ -90,6 +90,10 @@ public class CameraView extends FrameLayout implements TextureView.SurfaceTextur
return isFrontface;
}
public TextureView getTextureView() {
return textureView;
}
public boolean hasFrontFaceCamera() {
ArrayList<CameraInfo> cameraInfos = CameraController.getInstance().getCameras();
for (int a = 0; a < cameraInfos.size(); a++) {
@ -168,20 +172,14 @@ public class CameraView extends FrameLayout implements TextureView.SurfaceTextur
if (previewSize != null && surfaceTexture != null) {
surfaceTexture.setDefaultBufferSize(previewSize.getWidth(), previewSize.getHeight());
cameraSession = new CameraSession(info, previewSize, pictureSize, ImageFormat.JPEG);
CameraController.getInstance().open(cameraSession, surfaceTexture, new Runnable() {
@Override
public void run() {
if (cameraSession != null) {
cameraSession.setInitied();
}
checkPreviewMatrix();
CameraController.getInstance().open(cameraSession, surfaceTexture, () -> {
if (cameraSession != null) {
cameraSession.setInitied();
}
}, new Runnable() {
@Override
public void run() {
if (delegate != null) {
delegate.onCameraCreated(cameraSession.cameraInfo.camera);
}
checkPreviewMatrix();
}, () -> {
if (delegate != null) {
delegate.onCameraCreated(cameraSession.cameraInfo.camera);
}
});
}
@ -223,8 +221,8 @@ public class CameraView extends FrameLayout implements TextureView.SurfaceTextur
clipTop = value;
}
public void setClipLeft(int value) {
clipLeft = value;
public void setClipBottom(int value) {
clipBottom = value;
}
private void checkPreviewMatrix() {
@ -244,9 +242,9 @@ public class CameraView extends FrameLayout implements TextureView.SurfaceTextur
float scale;
if (rotation == Surface.ROTATION_0 || rotation == Surface.ROTATION_180) {
scale = Math.max((float) (viewHeight + clipTop) / previewWidth, (float) (viewWidth + clipLeft) / previewHeight);
scale = Math.max((float) (viewHeight + clipTop + clipBottom) / previewWidth, (float) (viewWidth) / previewHeight);
} else {
scale = Math.max((float) (viewHeight + clipTop) / previewHeight, (float) (viewWidth + clipLeft) / previewWidth);
scale = Math.max((float) (viewHeight + clipTop + clipBottom) / previewHeight, (float) (viewWidth) / previewWidth);
}
float previewWidthScaled = previewWidth * scale;
@ -268,8 +266,10 @@ public class CameraView extends FrameLayout implements TextureView.SurfaceTextur
if (mirror) {
txform.postScale(-1, 1, viewCenterX, viewCenterY);
}
if (clipTop != 0 || clipLeft != 0) {
txform.postTranslate(-clipLeft / 2, -clipTop / 2);
if (clipTop != 0) {
txform.postTranslate(0, -clipTop / 2);
} else if (clipBottom != 0) {
txform.postTranslate(0, clipBottom / 2);
}
textureView.setTransform(txform);
@ -320,6 +320,12 @@ public class CameraView extends FrameLayout implements TextureView.SurfaceTextur
invalidate();
}
public void setZoom(float value) {
if (cameraSession != null) {
cameraSession.setZoom(value);
}
}
public void setDelegate(CameraViewDelegate cameraViewDelegate) {
delegate = cameraViewDelegate;
}
@ -339,6 +345,10 @@ public class CameraView extends FrameLayout implements TextureView.SurfaceTextur
}
}
public Matrix getMatrix() {
return txform;
}
@Override
protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
boolean result = super.drawChild(canvas, child, drawingTime);

View file

@ -34,6 +34,8 @@ import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
import android.util.Log;
import org.telegram.messenger.FileLog;
import java.util.ArrayList;
import java.util.HashMap;
@ -162,8 +164,13 @@ public abstract class JobIntentService extends Service {
mServiceProcessing = true;
// Keep the device awake, but only for at most 10 minutes at a time
// (Similar to JobScheduler.)
mRunWakeLock.acquire(2 * 60 * 1000L);
mLaunchWakeLock.release();
try {
mRunWakeLock.acquire(2 * 60 * 1000L);
mLaunchWakeLock.release();
} catch (Throwable e) {
FileLog.e(e);
mServiceProcessing = false;
}
}
}
}
@ -344,7 +351,11 @@ public abstract class JobIntentService extends Service {
if (DEBUG) Log.d(TAG, "Processing next work: " + work);
onHandleWork(work.getIntent());
if (DEBUG) Log.d(TAG, "Completing work: " + work);
work.complete();
try {
work.complete();
} catch (Throwable ignore) {
}
}
if (DEBUG) Log.d(TAG, "Done processing work!");

View file

@ -502,14 +502,7 @@ public class ConnectionsManager extends BaseController {
return;
}
lastDnsRequestTime = System.currentTimeMillis();
if (second == 2) {
if (BuildVars.LOGS_ENABLED) {
FileLog.d("start azure dns task");
}
AzureLoadTask task = new AzureLoadTask(currentAccount);
task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, null, null, null);
currentTask = task;
} else if (second == 1) {
if (second == 1) {
if (BuildVars.LOGS_ENABLED) {
FileLog.d("start dns txt task");
}
@ -631,7 +624,7 @@ public class ConnectionsManager extends BaseController {
public static native void native_seSystemLangCode(int currentAccount, String langCode);
public static native void native_setJava(boolean useJavaByteBuffers);
public static native void native_setPushConnectionEnabled(int currentAccount, boolean value);
public static native void native_applyDnsConfig(int currentAccount, long address, String phone);
public static native void native_applyDnsConfig(int currentAccount, long address, String phone, int date);
public static native long native_checkProxy(int currentAccount, String address, int port, String username, String password, String secret, RequestTimeDelegate requestTimeDelegate);
public static native void native_onHostNameResolved(String host, long address, String ip);
@ -832,6 +825,7 @@ 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();
@ -851,7 +845,7 @@ public class ConnectionsManager extends BaseController {
} else {
googleDomain = "google.com";
}
String domain = native_isTestBackend(currentAccount) != 0 ? "tapv2.stel.com" : AccountInstance.getInstance(currentAccount).getMessagesController().dcDomainName;
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";
@ -867,6 +861,7 @@ public class ConnectionsManager extends BaseController {
httpConnection.setReadTimeout(5000);
httpConnection.connect();
httpConnectionStream = httpConnection.getInputStream();
responseDate = (int) (httpConnection.getDate() / 1000);
outbuf = new ByteArrayOutputStream();
@ -941,17 +936,13 @@ public class ConnectionsManager extends BaseController {
protected void onPostExecute(final NativeByteBuffer result) {
Utilities.stageQueue.postRunnable(() -> {
if (result != null) {
currentTask = null;
native_applyDnsConfig(currentAccount, result.address, AccountInstance.getInstance(currentAccount).getUserConfig().getClientPhone());
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 azure task");
}
AzureLoadTask task = new AzureLoadTask(currentAccount);
task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, null, null, null);
currentTask = task;
}
currentTask = null;
});
}
}
@ -974,7 +965,7 @@ public class ConnectionsManager extends BaseController {
firebaseRemoteConfig = FirebaseRemoteConfig.getInstance();
FirebaseRemoteConfigSettings configSettings = new FirebaseRemoteConfigSettings.Builder().setDeveloperModeEnabled(BuildConfig.DEBUG).build();
firebaseRemoteConfig.setConfigSettings(configSettings);
String currentValue = firebaseRemoteConfig.getString("ipconfigv2");
String currentValue = firebaseRemoteConfig.getString("ipconfigv3");
if (BuildVars.LOGS_ENABLED) {
FileLog.d("current firebase value = " + currentValue);
}
@ -993,7 +984,8 @@ public class ConnectionsManager extends BaseController {
try {
NativeByteBuffer buffer = new NativeByteBuffer(bytes.length);
buffer.writeBytes(bytes);
native_applyDnsConfig(currentAccount, buffer.address, AccountInstance.getInstance(currentAccount).getUserConfig().getClientPhone());
int date = (int) (firebaseRemoteConfig.getInfo().getFetchTimeMillis() / 1000);
native_applyDnsConfig(currentAccount, buffer.address, AccountInstance.getInstance(currentAccount).getUserConfig().getClientPhone(), date);
} catch (Exception e) {
FileLog.e(e);
}
@ -1028,87 +1020,4 @@ public class ConnectionsManager extends BaseController {
}
}
private static class AzureLoadTask extends AsyncTask<Void, Void, NativeByteBuffer> {
private int currentAccount;
public AzureLoadTask(int instance) {
super();
currentAccount = instance;
}
protected NativeByteBuffer doInBackground(Void... voids) {
ByteArrayOutputStream outbuf = null;
InputStream httpConnectionStream = null;
try {
URL downloadUrl;
if (native_isTestBackend(currentAccount) != 0) {
downloadUrl = new URL("https://software-download.microsoft.com/testv2/config.txt");
} else {
downloadUrl = new URL("https://software-download.microsoft.com/prodv2/config.txt");
}
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", "tcdnb.azureedge.net");
httpConnection.setConnectTimeout(5000);
httpConnection.setReadTimeout(5000);
httpConnection.connect();
httpConnectionStream = httpConnection.getInputStream();
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;
}
}
byte[] bytes = Base64.decode(outbuf.toByteArray(), Base64.DEFAULT);
NativeByteBuffer buffer = new NativeByteBuffer(bytes.length);
buffer.writeBytes(bytes);
return buffer;
} catch (Throwable e) {
FileLog.e(e);
} finally {
try {
if (httpConnectionStream != null) {
httpConnectionStream.close();
}
} catch (Throwable e) {
FileLog.e(e);
}
try {
if (outbuf != null) {
outbuf.close();
}
} catch (Exception ignore) {
}
}
return null;
}
@Override
protected void onPostExecute(final NativeByteBuffer result) {
Utilities.stageQueue.postRunnable(() -> {
if (result != null) {
native_applyDnsConfig(currentAccount, result.address, AccountInstance.getInstance(currentAccount).getUserConfig().getClientPhone());
} else {
if (BuildVars.LOGS_ENABLED) {
FileLog.d("failed to get azure result");
}
}
currentTask = null;
});
}
}
}

File diff suppressed because it is too large Load diff

View file

@ -652,6 +652,10 @@ public class ActionBar extends FrameLayout {
menu.setSearchFieldText(text);
}
public void onSearchPressed() {
menu.onSearchPressed();
}
@Override
public void setEnabled(boolean enabled) {
super.setEnabled(enabled);

View file

@ -1112,7 +1112,7 @@ public class ActionBarLayout extends FrameLayout {
}
previousFragment.onTransitionAnimationStart(true, true);
currentFragment.onTransitionAnimationStart(false, false);
currentFragment.onTransitionAnimationStart(false, true);
previousFragment.onResume();
if (themeAnimatorSet != null) {
presentingFragmentDescriptions = previousFragment.getThemeDescriptions();
@ -1140,7 +1140,7 @@ public class ActionBarLayout extends FrameLayout {
containerViewBack.setTranslationX(0);
}
closeLastFragmentInternalRemoveOld(currentFragment);
currentFragment.onTransitionAnimationEnd(false, false);
currentFragment.onTransitionAnimationEnd(false, true);
previousFragmentFinal.onTransitionAnimationEnd(true, true);
previousFragmentFinal.onBecomeFullyVisible();
};
@ -1168,7 +1168,7 @@ public class ActionBarLayout extends FrameLayout {
currentAnimation = animation;
}
} else {
currentFragment.onTransitionAnimationEnd(false, false);
currentFragment.onTransitionAnimationEnd(false, true);
previousFragment.onTransitionAnimationEnd(true, true);
previousFragment.onBecomeFullyVisible();
}

View file

@ -219,6 +219,20 @@ public class ActionBarMenu extends LinearLayout {
}
}
public void onSearchPressed() {
int count = getChildCount();
for (int a = 0; a < count; a++) {
View view = getChildAt(a);
if (view instanceof ActionBarMenuItem) {
ActionBarMenuItem item = (ActionBarMenuItem) view;
if (item.isSearchField()) {
item.onSearchPressed();
break;
}
}
}
}
public void openSearchField(boolean toggle, String text, boolean animated) {
int count = getChildCount();
for (int a = 0; a < count; a++) {

View file

@ -99,7 +99,8 @@ public class ActionBarMenuItem extends FrameLayout {
private boolean animationEnabled = true;
private boolean ignoreOnTextChange;
private CloseProgressDrawable2 progressDrawable;
private int additionalOffset;
private int additionalYOffset;
private int additionalXOffset;
private boolean longClickEnabled = true;
private boolean animateClear = true;
@ -261,6 +262,13 @@ public class ActionBarMenuItem extends FrameLayout {
});
}
public void removeAllSubItems() {
if (popupLayout == null) {
return;
}
popupLayout.removeInnerViews();
}
public void addSubItem(View view, int width, int height) {
createPopupLayout();
popupLayout.addView(view, new LinearLayout.LayoutParams(width, height));
@ -301,6 +309,8 @@ public class ActionBarMenuItem extends FrameLayout {
textView.setPadding(AndroidUtilities.dp(16), 0, AndroidUtilities.dp(16), 0);
textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16);
textView.setMinWidth(AndroidUtilities.dp(196));
textView.setSingleLine(true);
textView.setEllipsize(TextUtils.TruncateAt.END);
textView.setTag(id);
textView.setText(text);
popupLayout.addView(textView);
@ -534,6 +544,12 @@ public class ActionBarMenuItem extends FrameLayout {
}
}
public void onSearchPressed() {
if (listener != null) {
listener.onSearchPressed(searchField);
}
}
public EditTextBoldCursor getSearchField() {
return searchField;
}
@ -827,8 +843,12 @@ public class ActionBarMenuItem extends FrameLayout {
}
}
public void setAdditionalOffset(int value) {
additionalOffset = value;
public void setAdditionalYOffset(int value) {
additionalYOffset = value;
}
public void setAdditionalXOffset(int value) {
additionalXOffset = value;
}
private void updateOrShowPopup(boolean show, boolean update) {
@ -838,7 +858,7 @@ public class ActionBarMenuItem extends FrameLayout {
offsetY = -parentMenu.parentActionBar.getMeasuredHeight() + parentMenu.getTop() + parentMenu.getPaddingTop();
} else {
float scaleY = getScaleY();
offsetY = -(int) (getMeasuredHeight() * scaleY - (subMenuOpenSide != 2 ? getTranslationY() : 0) / scaleY) + additionalOffset;
offsetY = -(int) (getMeasuredHeight() * scaleY - (subMenuOpenSide != 2 ? getTranslationY() : 0) / scaleY) + additionalYOffset;
}
offsetY += yOffset;
@ -868,25 +888,25 @@ public class ActionBarMenuItem extends FrameLayout {
if (getParent() != null) {
View parent = (View) getParent();
if (show) {
popupWindow.showAsDropDown(parent, getLeft() + getMeasuredWidth() - popupLayout.getMeasuredWidth(), offsetY);
popupWindow.showAsDropDown(parent, getLeft() + getMeasuredWidth() - popupLayout.getMeasuredWidth() + additionalXOffset, offsetY);
}
if (update) {
popupWindow.update(parent, getLeft() + getMeasuredWidth() - popupLayout.getMeasuredWidth(), offsetY, -1, -1);
popupWindow.update(parent, getLeft() + getMeasuredWidth() - popupLayout.getMeasuredWidth() + additionalXOffset, offsetY, -1, -1);
}
}
} else if (subMenuOpenSide == 1) {
if (show) {
popupWindow.showAsDropDown(this, -AndroidUtilities.dp(8), offsetY);
popupWindow.showAsDropDown(this, -AndroidUtilities.dp(8) + additionalXOffset, offsetY);
}
if (update) {
popupWindow.update(this, -AndroidUtilities.dp(8), offsetY, -1, -1);
popupWindow.update(this, -AndroidUtilities.dp(8) + additionalXOffset, offsetY, -1, -1);
}
} else {
if (show) {
popupWindow.showAsDropDown(this, getMeasuredWidth() - popupLayout.getMeasuredWidth(), offsetY);
popupWindow.showAsDropDown(this, getMeasuredWidth() - popupLayout.getMeasuredWidth() + additionalXOffset, offsetY);
}
if (update) {
popupWindow.update(this, getMeasuredWidth() - popupLayout.getMeasuredWidth(), offsetY, -1, -1);
popupWindow.update(this, getMeasuredWidth() - popupLayout.getMeasuredWidth() + additionalXOffset, offsetY, -1, -1);
}
}
}

View file

@ -6,11 +6,10 @@
* Copyright Nikolai Kudashov, 2013-2018.
*/
//Thanks to https://github.com/JakeWharton/ActionBarSherlock/
package org.telegram.ui.ActionBar;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.content.Context;
@ -24,6 +23,7 @@ import android.view.KeyEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.view.WindowManager;
import android.view.animation.DecelerateInterpolator;
import android.widget.FrameLayout;
import android.widget.LinearLayout;
@ -37,6 +37,7 @@ import org.telegram.ui.Components.LayoutHelper;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
public class ActionBarPopupWindow extends PopupWindow {
@ -79,6 +80,7 @@ public class ActionBarPopupWindow extends PopupWindow {
private int lastStartedChild = 0;
private boolean showedFromBotton;
private boolean animationEnabled = allowAnimation;
private ArrayList<AnimatorSet> itemAnimators;
private HashMap<View, Integer> positions = new HashMap<>();
private ScrollView scrollView;
@ -141,11 +143,6 @@ public class ActionBarPopupWindow extends PopupWindow {
public void setBackScaleY(float value) {
backScaleY = value;
if (animationEnabled) {
int count = getItemsCount();
int visibleCount = 0;
for (int a = 0; a < count; a++) {
visibleCount += getItemAt(a).getVisibility() == VISIBLE ? 1 : 0;
}
int height = getMeasuredHeight() - AndroidUtilities.dp(16);
if (showedFromBotton) {
for (int a = lastStartedChild; a >= 0; a--) {
@ -161,6 +158,7 @@ public class ActionBarPopupWindow extends PopupWindow {
startChildAnimation(child);
}
} else {
int count = getItemsCount();
for (int a = lastStartedChild; a < count; a++) {
View child = getItemAt(a);
if (child.getVisibility() != VISIBLE) {
@ -186,11 +184,21 @@ public class ActionBarPopupWindow extends PopupWindow {
if (animationEnabled) {
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.playTogether(
ObjectAnimator.ofFloat(child, "alpha", 0.0f, 1.0f),
ObjectAnimator.ofFloat(child, "translationY", AndroidUtilities.dp(showedFromBotton ? 6 : -6), 0));
ObjectAnimator.ofFloat(child, View.ALPHA, 0.0f, 1.0f),
ObjectAnimator.ofFloat(child, View.TRANSLATION_Y, AndroidUtilities.dp(showedFromBotton ? 6 : -6), 0));
animatorSet.setDuration(180);
animatorSet.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
itemAnimators.remove(animatorSet);
}
});
animatorSet.setInterpolator(decelerateInterpolator);
animatorSet.start();
if (itemAnimators == null) {
itemAnimators = new ArrayList<>();
}
itemAnimators.add(animatorSet);
}
}
@ -237,6 +245,10 @@ public class ActionBarPopupWindow extends PopupWindow {
}
}
public Drawable getBackgroundDrawable() {
return backgroundDrawable;
}
public int getItemsCount() {
return linearLayout.getChildCount();
}
@ -337,6 +349,16 @@ public class ActionBarPopupWindow extends PopupWindow {
}
}
public void dimBehind() {
View container = getContentView().getRootView();
Context context = getContentView().getContext();
WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
WindowManager.LayoutParams p = (WindowManager.LayoutParams) container.getLayoutParams();
p.flags |= WindowManager.LayoutParams.FLAG_DIM_BEHIND;
p.dimAmount = 0.2f;
wm.updateViewLayout(container, p);
}
@Override
public void showAsDropDown(View anchor, int xoff, int yoff) {
try {
@ -362,11 +384,11 @@ public class ActionBarPopupWindow extends PopupWindow {
int visibleCount = 0;
for (int a = 0; a < count; a++) {
View child = content.getItemAt(a);
child.setAlpha(0.0f);
if (child.getVisibility() != View.VISIBLE) {
continue;
}
content.positions.put(child, visibleCount);
child.setAlpha(0.0f);
visibleCount++;
}
if (content.showedFromBotton) {
@ -388,6 +410,12 @@ public class ActionBarPopupWindow extends PopupWindow {
@Override
public void onAnimationEnd(Animator animation) {
windowAnimatorSet = null;
ActionBarPopupWindowLayout content = (ActionBarPopupWindowLayout) getContentView();
int count = content.getItemsCount();
for (int a = 0; a < count; a++) {
View child = content.getItemAt(a);
child.setAlpha(1.0f);
}
}
@Override
@ -434,10 +462,16 @@ public class ActionBarPopupWindow extends PopupWindow {
windowAnimatorSet.cancel();
}
ActionBarPopupWindowLayout content = (ActionBarPopupWindowLayout) getContentView();
if (content.itemAnimators != null && content.itemAnimators.isEmpty()) {
for (int a = 0, N = content.itemAnimators.size(); a < N; a++) {
content.itemAnimators.get(a).cancel();
}
content.itemAnimators.clear();
}
windowAnimatorSet = new AnimatorSet();
windowAnimatorSet.playTogether(
ObjectAnimator.ofFloat(content, "translationY", AndroidUtilities.dp(content.showedFromBotton ? 5 : -5)),
ObjectAnimator.ofFloat(content, "alpha", 0.0f));
ObjectAnimator.ofFloat(content, View.TRANSLATION_Y, AndroidUtilities.dp(content.showedFromBotton ? 5 : -5)),
ObjectAnimator.ofFloat(content, View.ALPHA, 0.0f));
windowAnimatorSet.setDuration(dismissAnimationDuration);
windowAnimatorSet.addListener(new Animator.AnimatorListener() {
@Override
@ -451,8 +485,8 @@ public class ActionBarPopupWindow extends PopupWindow {
setFocusable(false);
try {
ActionBarPopupWindow.super.dismiss();
} catch (Exception e) {
//don't promt
} catch (Exception ignore) {
}
unregisterListener();
}
@ -471,8 +505,8 @@ public class ActionBarPopupWindow extends PopupWindow {
} else {
try {
super.dismiss();
} catch (Exception e) {
//don't promt
} catch (Exception ignore) {
}
unregisterListener();
}

View file

@ -37,6 +37,7 @@ import android.view.ViewGroup;
import android.view.Window;
import android.view.WindowInsets;
import android.view.WindowManager;
import android.view.animation.Interpolator;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.TextView;
@ -47,6 +48,7 @@ import org.telegram.messenger.FileLog;
import org.telegram.messenger.NotificationCenter;
import org.telegram.messenger.R;
import org.telegram.messenger.UserConfig;
import org.telegram.ui.Components.AnimationProperties;
import org.telegram.ui.Components.CubicBezierInterpolator;
import org.telegram.ui.Components.LayoutHelper;
@ -84,6 +86,7 @@ public class BottomSheet extends Dialog {
private int touchSlop;
private boolean useFastDismiss;
protected Interpolator openInterpolator = CubicBezierInterpolator.EASE_OUT_QUINT;
private TextView titleView;
@ -93,7 +96,7 @@ public class BottomSheet extends Dialog {
private boolean allowNestedScroll = true;
private Drawable shadowDrawable;
protected Drawable shadowDrawable;
protected int backgroundPaddingTop;
protected int backgroundPaddingLeft;
@ -107,6 +110,7 @@ public class BottomSheet extends Dialog {
private BottomSheetDelegateInterface delegate;
protected AnimatorSet currentSheetAnimation;
protected int currentSheetAnimationType;
protected View nestedScrollChild;
@ -681,6 +685,27 @@ public class BottomSheet extends Dialog {
window.setAttributes(params);
}
public boolean isFocusable() {
return focusable;
}
public void setFocusable(boolean value) {
if (focusable == value) {
return;
}
focusable = value;
Window window = getWindow();
WindowManager.LayoutParams params = window.getAttributes();
if (focusable) {
params.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
params.flags &=~ WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
} else {
params.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING;
params.flags |= WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
}
window.setAttributes(params);
}
public void setShowWithoutAnimation(boolean value) {
showWithoutAnimation = value;
}
@ -778,6 +803,7 @@ public class BottomSheet extends Dialog {
if (currentSheetAnimation != null) {
currentSheetAnimation.cancel();
currentSheetAnimation = null;
currentSheetAnimationType = 0;
}
}
@ -792,18 +818,20 @@ public class BottomSheet extends Dialog {
container.setLayerType(View.LAYER_TYPE_HARDWARE, null);
}
containerView.setTranslationY(containerView.getMeasuredHeight());
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.playTogether(
ObjectAnimator.ofFloat(containerView, "translationY", 0),
ObjectAnimator.ofInt(backDrawable, "alpha", dimBehind ? 51 : 0));
animatorSet.setDuration(400);
animatorSet.setStartDelay(20);
animatorSet.setInterpolator(CubicBezierInterpolator.EASE_OUT_QUINT);
animatorSet.addListener(new AnimatorListenerAdapter() {
currentSheetAnimationType = 1;
currentSheetAnimation = new AnimatorSet();
currentSheetAnimation.playTogether(
ObjectAnimator.ofFloat(containerView, View.TRANSLATION_Y, 0),
ObjectAnimator.ofInt(backDrawable, AnimationProperties.COLOR_DRAWABLE_ALPHA, dimBehind ? 51 : 0));
currentSheetAnimation.setDuration(400);
currentSheetAnimation.setStartDelay(20);
currentSheetAnimation.setInterpolator(openInterpolator);
currentSheetAnimation.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
if (currentSheetAnimation != null && currentSheetAnimation.equals(animation)) {
currentSheetAnimation = null;
currentSheetAnimationType = 0;
if (delegate != null) {
delegate.onOpenAnimationEnd();
}
@ -824,12 +852,12 @@ public class BottomSheet extends Dialog {
public void onAnimationCancel(Animator animation) {
if (currentSheetAnimation != null && currentSheetAnimation.equals(animation)) {
currentSheetAnimation = null;
currentSheetAnimationType = 0;
}
}
});
NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.stopAllHeavyOperations, 512);
animatorSet.start();
currentSheetAnimation = animatorSet;
currentSheetAnimation.start();
}
}
@ -893,18 +921,20 @@ public class BottomSheet extends Dialog {
}
dismissed = true;
cancelSheetAnimation();
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.playTogether(
currentSheetAnimationType = 2;
currentSheetAnimation = new AnimatorSet();
currentSheetAnimation.playTogether(
ObjectAnimator.ofFloat(containerView, "translationY", containerView.getMeasuredHeight() + AndroidUtilities.dp(10)),
ObjectAnimator.ofInt(backDrawable, "alpha", 0)
);
animatorSet.setDuration(180);
animatorSet.setInterpolator(CubicBezierInterpolator.EASE_OUT);
animatorSet.addListener(new AnimatorListenerAdapter() {
currentSheetAnimation.setDuration(180);
currentSheetAnimation.setInterpolator(CubicBezierInterpolator.EASE_OUT);
currentSheetAnimation.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
if (currentSheetAnimation != null && currentSheetAnimation.equals(animation)) {
currentSheetAnimation = null;
currentSheetAnimationType = 0;
if (onClickListener != null) {
onClickListener.onClick(BottomSheet.this, item);
}
@ -923,12 +953,12 @@ public class BottomSheet extends Dialog {
public void onAnimationCancel(Animator animation) {
if (currentSheetAnimation != null && currentSheetAnimation.equals(animation)) {
currentSheetAnimation = null;
currentSheetAnimationType = 0;
}
}
});
NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.stopAllHeavyOperations, 512);
animatorSet.start();
currentSheetAnimation = animatorSet;
currentSheetAnimation.start();
}
@Override
@ -942,24 +972,26 @@ public class BottomSheet extends Dialog {
dismissed = true;
cancelSheetAnimation();
if (!allowCustomAnimation || !onCustomCloseAnimation()) {
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.playTogether(
currentSheetAnimationType = 2;
currentSheetAnimation = new AnimatorSet();
currentSheetAnimation.playTogether(
ObjectAnimator.ofFloat(containerView, "translationY", containerView.getMeasuredHeight() + AndroidUtilities.dp(10)),
ObjectAnimator.ofInt(backDrawable, "alpha", 0)
);
if (useFastDismiss) {
int height = containerView.getMeasuredHeight();
animatorSet.setDuration(Math.max(60, (int) (180 * (height - containerView.getTranslationY()) / (float) height)));
currentSheetAnimation.setDuration(Math.max(60, (int) (180 * (height - containerView.getTranslationY()) / (float) height)));
useFastDismiss = false;
} else {
animatorSet.setDuration(180);
currentSheetAnimation.setDuration(180);
}
animatorSet.setInterpolator(CubicBezierInterpolator.EASE_OUT);
animatorSet.addListener(new AnimatorListenerAdapter() {
currentSheetAnimation.setInterpolator(CubicBezierInterpolator.EASE_OUT);
currentSheetAnimation.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
if (currentSheetAnimation != null && currentSheetAnimation.equals(animation)) {
currentSheetAnimation = null;
currentSheetAnimationType = 0;
AndroidUtilities.runOnUIThread(() -> {
try {
dismissInternal();
@ -975,12 +1007,12 @@ public class BottomSheet extends Dialog {
public void onAnimationCancel(Animator animation) {
if (currentSheetAnimation != null && currentSheetAnimation.equals(animation)) {
currentSheetAnimation = null;
currentSheetAnimationType = 0;
}
}
});
NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.stopAllHeavyOperations, 512);
animatorSet.start();
currentSheetAnimation = animatorSet;
currentSheetAnimation.start();
}
}

View file

@ -136,12 +136,6 @@ public class SimpleTextView extends View implements Drawable.Callback {
textWidth = (int) Math.ceil(layout.getLineWidth(0));
textHeight = layout.getLineBottom(0);
if ((gravity & Gravity.VERTICAL_GRAVITY_MASK) == Gravity.CENTER_VERTICAL) {
offsetY = (getMeasuredHeight() - textHeight) / 2;
} else {
offsetY = 0;
}
if ((gravity & Gravity.HORIZONTAL_GRAVITY_MASK) == Gravity.LEFT) {
offsetX = -(int) layout.getLineLeft(0);
} else if (layout.getLineLeft(0) == 0) {
@ -207,6 +201,12 @@ public class SimpleTextView extends View implements Drawable.Callback {
finalHeight = textHeight;
}
setMeasuredDimension(width, finalHeight);
if ((gravity & Gravity.VERTICAL_GRAVITY_MASK) == Gravity.CENTER_VERTICAL) {
offsetY = (getMeasuredHeight() - textHeight) / 2;
} else {
offsetY = 0;
}
}
@Override
@ -306,7 +306,13 @@ public class SimpleTextView extends View implements Drawable.Callback {
private boolean recreateLayoutMaybe() {
if (wasLayout && getMeasuredHeight() != 0) {
return createLayout(getMeasuredWidth());
boolean result = createLayout(getMeasuredWidth() - getPaddingLeft() - getPaddingRight());
if ((gravity & Gravity.VERTICAL_GRAVITY_MASK) == Gravity.CENTER_VERTICAL) {
offsetY = (getMeasuredHeight() - textHeight) / 2;
} else {
offsetY = 0;
}
return result;
} else {
requestLayout();
}

View file

@ -20,7 +20,6 @@ import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.ColorFilter;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PixelFormat;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffColorFilter;
@ -207,91 +206,6 @@ public class Theme {
public static double autoNightLocationLatitude = 10000;
public static double autoNightLocationLongitude = 10000;
private static class AttachCameraDrawable extends Drawable {
private Path segment;
private Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
public AttachCameraDrawable() {
int size = AndroidUtilities.dp(54);
RectF rect = new RectF(0, 0, size, size);
segment = new Path();
segment.moveTo(AndroidUtilities.dp(23), AndroidUtilities.dp(20));
segment.lineTo(AndroidUtilities.dp(23), 0);
segment.arcTo(rect, -98, 50, false);
segment.close();
}
@Override
public void draw(Canvas canvas) {
canvas.save();
int cx = AndroidUtilities.dp(27);
canvas.rotate(-90, cx, cx);
for (int a = 0; a < 6; a++) {
switch (a) {
case 0:
paint.setColor(getColor(key_chat_attachCameraIcon1));
break;
case 1:
paint.setColor(getColor(key_chat_attachCameraIcon2));
break;
case 2:
paint.setColor(getColor(key_chat_attachCameraIcon3));
break;
case 3:
paint.setColor(getColor(key_chat_attachCameraIcon4));
break;
case 4:
paint.setColor(getColor(key_chat_attachCameraIcon5));
break;
case 5:
paint.setColor(getColor(key_chat_attachCameraIcon6));
break;
}
canvas.rotate(60, cx, cx);
canvas.drawPath(segment, paint);
}
canvas.restore();
}
@Override
public void setAlpha(int alpha) {
}
@Override
public void setColorFilter(ColorFilter colorFilter) {
invalidateSelf();
}
@Override
public int getOpacity() {
return PixelFormat.TRANSPARENT;
}
@Override
public int getIntrinsicWidth() {
return AndroidUtilities.dp(54);
}
@Override
public int getIntrinsicHeight() {
return AndroidUtilities.dp(54);
}
@Override
public int getMinimumWidth() {
return AndroidUtilities.dp(54);
}
@Override
public int getMinimumHeight() {
return AndroidUtilities.dp(54);
}
}
private static Paint maskPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
public static ArrayList<ThemeInfo> themes;
@ -505,7 +419,8 @@ public class Theme {
public static Drawable chat_msgCallDownGreenDrawable;
public static Drawable chat_msgAvatarLiveLocationDrawable;
public static Drawable[] chat_attachButtonDrawables = new Drawable[10];
public static Drawable chat_attachEmptyDrawable;
public static Drawable[] chat_attachButtonDrawables = new Drawable[6];
public static Drawable[] chat_locationDrawable = new Drawable[2];
public static Drawable[] chat_contactDrawable = new Drawable[2];
public static Drawable[] chat_cornerOuter = new Drawable[4];
@ -772,41 +687,29 @@ public class Theme {
public static final String key_chats_actionUnreadBackground = "chats_actionUnreadBackground";
public static final String key_chats_actionUnreadPressedBackground = "chats_actionUnreadPressedBackground";
public static final String key_chat_attachCameraIcon1 = "chat_attachCameraIcon1";
public static final String key_chat_attachCameraIcon2 = "chat_attachCameraIcon2";
public static final String key_chat_attachCameraIcon3 = "chat_attachCameraIcon3";
public static final String key_chat_attachCameraIcon4 = "chat_attachCameraIcon4";
public static final String key_chat_attachCameraIcon5 = "chat_attachCameraIcon5";
public static final String key_chat_attachCameraIcon6 = "chat_attachCameraIcon6";
public static final String key_chat_attachMediaBanBackground = "chat_attachMediaBanBackground";
public static final String key_chat_attachMediaBanText = "chat_attachMediaBanText";
public static final String key_chat_attachCheckBoxCheck = "chat_attachCheckBoxCheck";
public static final String key_chat_attachCheckBoxBackground = "chat_attachCheckBoxBackground";
public static final String key_chat_attachPhotoBackground = "chat_attachPhotoBackground";
public static final String key_chat_attachActiveTab = "chat_attachActiveTab";
public static final String key_chat_attachUnactiveTab = "chat_attachUnactiveTab";
public static final String key_chat_attachPermissionImage = "chat_attachPermissionImage";
public static final String key_chat_attachPermissionMark = "chat_attachPermissionMark";
public static final String key_chat_attachPermissionText = "chat_attachPermissionText";
public static final String key_chat_attachEmptyImage = "chat_attachEmptyImage";
public static final String key_chat_attachGalleryBackground = "chat_attachGalleryBackground";
//public static final String key_chat_attachGalleryBackgroundPressed = "chat_attachGalleryBackgroundPressed";
public static final String key_chat_attachGalleryIcon = "chat_attachGalleryIcon";
public static final String key_chat_attachVideoBackground = "chat_attachVideoBackground";
//public static final String key_chat_attachVideoBackgroundPressed = "chat_attachVideoBackgroundPressed";
public static final String key_chat_attachVideoIcon = "chat_attachVideoIcon";
public static final String key_chat_attachAudioBackground = "chat_attachAudioBackground";
//public static final String key_chat_attachAudioBackgroundPressed = "chat_attachAudioBackgroundPressed";
public static final String key_chat_attachAudioIcon = "chat_attachAudioIcon";
public static final String key_chat_attachFileBackground = "chat_attachFileBackground";
//public static final String key_chat_attachFileBackgroundPressed = "chat_attachFileBackgroundPressed";
public static final String key_chat_attachFileIcon = "chat_attachFileIcon";
public static final String key_chat_attachContactBackground = "chat_attachContactBackground";
//public static final String key_chat_attachContactBackgroundPressed = "chat_attachContactBackgroundPressed";
public static final String key_chat_attachContactIcon = "chat_attachContactIcon";
public static final String key_chat_attachLocationBackground = "chat_attachLocationBackground";
//public static final String key_chat_attachLocationBackgroundPressed = "chat_attachLocationBackgroundPressed";
public static final String key_chat_attachLocationIcon = "chat_attachLocationIcon";
public static final String key_chat_attachHideBackground = "chat_attachHideBackground";
//public static final String key_chat_attachHideBackgroundPressed = "chat_attachHideBackgroundPressed";
public static final String key_chat_attachHideIcon = "chat_attachHideIcon";
public static final String key_chat_attachSendBackground = "chat_attachSendBackground";
//public static final String key_chat_attachSendBackgroundPressed = "chat_attachSendBackgroundPressed";
public static final String key_chat_attachSendIcon = "chat_attachSendIcon";
public static final String key_chat_attachPollBackground = "chat_attachPollBackground";
//public static final String key_chat_attachPollBackgroundPressed = "chat_attachPollBackgroundPressed";
public static final String key_chat_attachPollIcon = "chat_attachPollIcon";
public static final String key_chat_status = "chat_status";
@ -964,6 +867,7 @@ public class Theme {
public static final String key_chat_messagePanelHint = "chat_messagePanelHint";
public static final String key_chat_messagePanelIcons = "chat_messagePanelIcons";
public static final String key_chat_messagePanelSend = "chat_messagePanelSend";
public static final String key_chat_messagePanelSendPressed = "chat_messagePanelPressedSend";
public static final String key_chat_messagePanelVoiceLock = "key_chat_messagePanelVoiceLock";
public static final String key_chat_messagePanelVoiceLockBackground = "key_chat_messagePanelVoiceLockBackground";
public static final String key_chat_messagePanelVoiceLockShadow = "key_chat_messagePanelVoiceLockShadow";
@ -1405,40 +1309,29 @@ public class Theme {
defaultColors.put(key_chats_actionUnreadPressedBackground, 0xfff2f2f2);
defaultColors.put(key_chats_menuTopBackgroundCats, 0xff598fba);
defaultColors.put(key_chat_attachCameraIcon1, 0xffff7d30);
defaultColors.put(key_chat_attachCameraIcon2, 0xffeb5850);
defaultColors.put(key_chat_attachCameraIcon3, 0xff43a9f2);
defaultColors.put(key_chat_attachCameraIcon4, 0xffb455e0);
defaultColors.put(key_chat_attachCameraIcon5, 0xff61d061);
defaultColors.put(key_chat_attachCameraIcon6, 0xfffec125);
defaultColors.put(key_chat_attachMediaBanBackground, 0xff464646);
defaultColors.put(key_chat_attachMediaBanText, 0xffffffff);
defaultColors.put(key_chat_attachCheckBoxCheck, 0xffffffff);
defaultColors.put(key_chat_attachCheckBoxBackground, 0xff39b2f7);
defaultColors.put(key_chat_attachPhotoBackground, 0x08000000);
defaultColors.put(key_chat_attachActiveTab, 0xff33a7f5);
defaultColors.put(key_chat_attachUnactiveTab, 0xff92999e);
defaultColors.put(key_chat_attachPermissionImage, 0xff333333);
defaultColors.put(key_chat_attachPermissionMark, 0xffe25050);
defaultColors.put(key_chat_attachPermissionText, 0xff6f777a);
defaultColors.put(key_chat_attachEmptyImage, 0xffcccccc);
defaultColors.put(key_chat_attachGalleryBackground, 0xffa47ad9);
//defaultColors.put(key_chat_attachGalleryBackgroundPressed, 0xffa47ad9);
defaultColors.put(key_chat_attachGalleryBackground, 0xff459df5);
defaultColors.put(key_chat_attachGalleryIcon, 0xffffffff);
defaultColors.put(key_chat_attachVideoBackground, 0xffe37179);
//defaultColors.put(key_chat_attachVideoBackgroundPressed, 0xffe37179);
defaultColors.put(key_chat_attachVideoIcon, 0xffffffff);
defaultColors.put(key_chat_attachAudioBackground, 0xfff68751);
//defaultColors.put(key_chat_attachAudioBackgroundPressed, 0xfff68751);
defaultColors.put(key_chat_attachAudioBackground, 0xffeb6060);
defaultColors.put(key_chat_attachAudioIcon, 0xffffffff);
defaultColors.put(key_chat_attachFileBackground, 0xff34a0f4);
//defaultColors.put(key_chat_attachFileBackgroundPressed, 0xff34a0f4);
defaultColors.put(key_chat_attachFileBackground, 0xff34b9f1);
defaultColors.put(key_chat_attachFileIcon, 0xffffffff);
defaultColors.put(key_chat_attachContactBackground, 0xff3ebffa);
//defaultColors.put(key_chat_attachContactBackgroundPressed, 0xff3ebffa);
defaultColors.put(key_chat_attachContactBackground, 0xfff2c04b);
defaultColors.put(key_chat_attachContactIcon, 0xffffffff);
defaultColors.put(key_chat_attachLocationBackground, 0xff3fc87a);
//defaultColors.put(key_chat_attachLocationBackgroundPressed, 0xff3fc87a);
defaultColors.put(key_chat_attachLocationBackground, 0xff36c766);
defaultColors.put(key_chat_attachLocationIcon, 0xffffffff);
defaultColors.put(key_chat_attachHideBackground, 0xffaeaab8);
//defaultColors.put(key_chat_attachHideBackgroundPressed, 0xffaeaab8);
defaultColors.put(key_chat_attachHideIcon, 0xffffffff);
defaultColors.put(key_chat_attachSendBackground, 0xff3ebffa);
//defaultColors.put(key_chat_attachSendBackgroundPressed, 0xff3ebffa);
defaultColors.put(key_chat_attachPollBackground, 0xfff5c34d);
//defaultColors.put(key_chat_attachPollBackgroundPressed, 0xfff68751);
defaultColors.put(key_chat_attachPollBackground, 0xfff2c04b);
defaultColors.put(key_chat_attachPollIcon, 0xffffffff);
@ -1446,7 +1339,6 @@ public class Theme {
defaultColors.put(key_chat_inGreenCall, 0xff00c853);
defaultColors.put(key_chat_inRedCall, 0xffff4848);
defaultColors.put(key_chat_outGreenCall, 0xff00c853);
defaultColors.put(key_chat_attachSendIcon, 0xffffffff);
defaultColors.put(key_chat_shareBackground, 0x66728fa6);
defaultColors.put(key_chat_shareBackgroundSelected, 0x99728fa6);
defaultColors.put(key_chat_lockIcon, 0xffffffff);
@ -1652,6 +1544,7 @@ public class Theme {
defaultColors.put(key_chat_recordedVoiceProgressInner, 0xffffffff);
defaultColors.put(key_chat_recordVoiceCancel, 0xff999999);
defaultColors.put(key_chat_messagePanelSend, 0xff62b0eb);
defaultColors.put(key_chat_messagePanelSendPressed, 0xffffffff);
defaultColors.put(key_chat_messagePanelVoiceLock, 0xffa4a4a4);
defaultColors.put(key_chat_messagePanelVoiceLockBackground, 0xffffffff);
defaultColors.put(key_chat_messagePanelVoiceLockShadow, 0xff000000);
@ -1893,6 +1786,13 @@ public class Theme {
fallbackKeys.put(key_actionBarTabSelector, key_actionBarDefaultSelector);
fallbackKeys.put(key_profile_status, key_avatar_subtitleInProfileBlue);
fallbackKeys.put(key_chats_menuTopBackgroundCats, key_avatar_backgroundActionBarBlue);
fallbackKeys.put(key_chat_messagePanelSendPressed, key_chat_messagePanelVoicePressed);
//fallbackKeys.put(key_chat_attachActiveTab, 0xff33a7f5); //TODO fallback
//fallbackKeys.put(key_chat_attachUnactiveTab, 0xff92999e); //TODO fallback
fallbackKeys.put(key_chat_attachPermissionImage, key_dialogTextBlack);
fallbackKeys.put(key_chat_attachPermissionMark, key_chat_sentError);
fallbackKeys.put(key_chat_attachPermissionText, key_dialogTextBlack);
fallbackKeys.put(key_chat_attachEmptyImage, key_emptyListPlaceholder);
themes = new ArrayList<>();
otherThemes = new ArrayList<>();
@ -2407,30 +2307,45 @@ public class Theme {
}
public static Drawable createSelectorDrawable(int color) {
return createSelectorDrawable(color, 1);
return createSelectorDrawable(color, 1, -1);
}
public static Drawable createSelectorDrawable(int color, int maskType) {
return createSelectorDrawable(color, maskType, -1);
}
public static Drawable createSelectorDrawable(int color, int maskType, int radius) {
Drawable drawable;
if (Build.VERSION.SDK_INT >= 21) {
Drawable maskDrawable = null;
if ((maskType == 1 || maskType == 5) && Build.VERSION.SDK_INT >= 23) {
maskDrawable = null;
} else if (maskType == 1 || maskType == 3 || maskType == 4 || maskType == 5) {
} else if (maskType == 1 || maskType == 3 || maskType == 4 || maskType == 5 || maskType == 6 || maskType == 7) {
maskPaint.setColor(0xffffffff);
maskDrawable = new Drawable() {
RectF rect;
@Override
public void draw(Canvas canvas) {
android.graphics.Rect bounds = getBounds();
int rad;
if (maskType == 1) {
rad = AndroidUtilities.dp(20);
} else if (maskType == 3) {
rad = (Math.max(bounds.width(), bounds.height()) / 2);
if (maskType == 7) {
if (rect == null) {
rect = new RectF();
}
rect.set(bounds);
canvas.drawRoundRect(rect, AndroidUtilities.dp(6), AndroidUtilities.dp(6), maskPaint);
} else {
rad = (int) Math.ceil(Math.sqrt((bounds.left - bounds.centerX()) * (bounds.left - bounds.centerX()) + (bounds.top - bounds.centerY()) * (bounds.top - bounds.centerY())));
int rad;
if (maskType == 1 || maskType == 6) {
rad = AndroidUtilities.dp(20);
} else if (maskType == 3) {
rad = (Math.max(bounds.width(), bounds.height()) / 2);
} else {
rad = (int) Math.ceil(Math.sqrt((bounds.left - bounds.centerX()) * (bounds.left - bounds.centerX()) + (bounds.top - bounds.centerY()) * (bounds.top - bounds.centerY())));
}
canvas.drawCircle(bounds.centerX(), bounds.centerY(), rad, maskPaint);
}
canvas.drawCircle(bounds.centerX(), bounds.centerY(), rad, maskPaint);
}
@Override
@ -2458,7 +2373,7 @@ public class Theme {
RippleDrawable rippleDrawable = new RippleDrawable(colorStateList, null, maskDrawable);
if (Build.VERSION.SDK_INT >= 23) {
if (maskType == 1) {
rippleDrawable.setRadius(AndroidUtilities.dp(20));
rippleDrawable.setRadius(radius <= 0 ? AndroidUtilities.dp(20) : radius);
} else if (maskType == 5) {
rippleDrawable.setRadius(RippleDrawable.RADIUS_AUTO);
}
@ -3352,16 +3267,13 @@ public class Theme {
chat_contextResult_shadowUnderSwitchDrawable = resources.getDrawable(R.drawable.header_shadow).mutate();
chat_attachButtonDrawables[0] = new AttachCameraDrawable();
chat_attachButtonDrawables[1] = createCircleDrawableWithIcon(AndroidUtilities.dp(54), R.drawable.attach_gallery);
chat_attachButtonDrawables[2] = createCircleDrawableWithIcon(AndroidUtilities.dp(54), R.drawable.attach_video);
chat_attachButtonDrawables[3] = createCircleDrawableWithIcon(AndroidUtilities.dp(54), R.drawable.attach_audio);
chat_attachButtonDrawables[4] = createCircleDrawableWithIcon(AndroidUtilities.dp(54), R.drawable.attach_file);
chat_attachButtonDrawables[5] = createCircleDrawableWithIcon(AndroidUtilities.dp(54), R.drawable.attach_contact);
chat_attachButtonDrawables[6] = createCircleDrawableWithIcon(AndroidUtilities.dp(54), R.drawable.attach_location);
chat_attachButtonDrawables[7] = createCircleDrawableWithIcon(AndroidUtilities.dp(54), R.drawable.attach_close);
chat_attachButtonDrawables[8] = createCircleDrawableWithIcon(AndroidUtilities.dp(54), R.drawable.attach_send);
chat_attachButtonDrawables[9] = createCircleDrawableWithIcon(AndroidUtilities.dp(54), R.drawable.attach_polls);
chat_attachButtonDrawables[0] = createCircleDrawableWithIcon(AndroidUtilities.dp(50), R.drawable.attach_gallery);
chat_attachButtonDrawables[1] = createCircleDrawableWithIcon(AndroidUtilities.dp(50), R.drawable.attach_audio);
chat_attachButtonDrawables[2] = createCircleDrawableWithIcon(AndroidUtilities.dp(50), R.drawable.attach_file);
chat_attachButtonDrawables[3] = createCircleDrawableWithIcon(AndroidUtilities.dp(50), R.drawable.attach_contact);
chat_attachButtonDrawables[4] = createCircleDrawableWithIcon(AndroidUtilities.dp(50), R.drawable.attach_location);
chat_attachButtonDrawables[5] = createCircleDrawableWithIcon(AndroidUtilities.dp(50), R.drawable.attach_polls);
chat_attachEmptyDrawable = resources.getDrawable(R.drawable.nophotos3);
chat_cornerOuter[0] = resources.getDrawable(R.drawable.corner_out_tl);
chat_cornerOuter[1] = resources.getDrawable(R.drawable.corner_out_tr);
@ -3667,43 +3579,20 @@ public class Theme {
setDrawableColorByKey(chat_composeShadowDrawable, key_chat_messagePanelShadow);
/*for (int a = 1; a < 3; a++) {
setCombinedDrawableColor(chat_attachButtonDrawables[9 * a + 1], getColor(a == 1 ? key_chat_attachGalleryBackground : key_chat_attachGalleryBackgroundPressed), false);
setCombinedDrawableColor(chat_attachButtonDrawables[9 * a + 1], getColor(key_chat_attachGalleryIcon), true);
setCombinedDrawableColor(chat_attachButtonDrawables[9 * a + 2], getColor(a == 1 ? key_chat_attachVideoBackground : key_chat_attachVideoBackgroundPressed), false);
setCombinedDrawableColor(chat_attachButtonDrawables[9 * a + 2], getColor(key_chat_attachVideoIcon), true);
setCombinedDrawableColor(chat_attachButtonDrawables[9 * a + 3], getColor(a == 1 ? key_chat_attachAudioBackground : key_chat_attachAudioBackgroundPressed), false);
setCombinedDrawableColor(chat_attachButtonDrawables[9 * a + 3], getColor(key_chat_attachAudioIcon), true);
setCombinedDrawableColor(chat_attachButtonDrawables[9 * a + 4], getColor(a == 1 ? key_chat_attachFileBackground : key_chat_attachFileBackgroundPressed), false);
setCombinedDrawableColor(chat_attachButtonDrawables[9 * a + 4], getColor(key_chat_attachFileIcon), true);
setCombinedDrawableColor(chat_attachButtonDrawables[9 * a + 5], getColor(a == 1 ? key_chat_attachContactBackground : key_chat_attachContactBackgroundPressed), false);
setCombinedDrawableColor(chat_attachButtonDrawables[9 * a + 5], getColor(key_chat_attachContactIcon), true);
setCombinedDrawableColor(chat_attachButtonDrawables[9 * a + 6], getColor(a == 1 ? key_chat_attachLocationBackground : key_chat_attachLocationBackgroundPressed), false);
setCombinedDrawableColor(chat_attachButtonDrawables[9 * a + 6], getColor(key_chat_attachLocationIcon), true);
setCombinedDrawableColor(chat_attachButtonDrawables[9 * a + 7], getColor(a == 1 ? key_chat_attachHideBackground : key_chat_attachHideBackgroundPressed), false);
setCombinedDrawableColor(chat_attachButtonDrawables[9 * a + 7], getColor(key_chat_attachHideIcon), true);
setCombinedDrawableColor(chat_attachButtonDrawables[9 * a + 8], getColor(a == 1 ? key_chat_attachSendBackground : key_chat_attachSendBackgroundPressed), false);
setCombinedDrawableColor(chat_attachButtonDrawables[9 * a + 8], getColor(key_chat_attachSendIcon), true);
}*/
setCombinedDrawableColor(chat_attachButtonDrawables[0], getColor(key_chat_attachGalleryBackground), false);
setCombinedDrawableColor(chat_attachButtonDrawables[0], getColor(key_chat_attachGalleryIcon), true);
setCombinedDrawableColor(chat_attachButtonDrawables[1], getColor(key_chat_attachAudioBackground), false);
setCombinedDrawableColor(chat_attachButtonDrawables[1], getColor(key_chat_attachAudioIcon), true);
setCombinedDrawableColor(chat_attachButtonDrawables[2], getColor(key_chat_attachFileBackground), false);
setCombinedDrawableColor(chat_attachButtonDrawables[2], getColor(key_chat_attachFileIcon), true);
setCombinedDrawableColor(chat_attachButtonDrawables[3], getColor(key_chat_attachContactBackground), false);
setCombinedDrawableColor(chat_attachButtonDrawables[3], getColor(key_chat_attachContactIcon), true);
setCombinedDrawableColor(chat_attachButtonDrawables[4], getColor(key_chat_attachLocationBackground), false);
setCombinedDrawableColor(chat_attachButtonDrawables[4], getColor(key_chat_attachLocationIcon), true);
setCombinedDrawableColor(chat_attachButtonDrawables[5], getColor(key_chat_attachPollBackground), false);
setCombinedDrawableColor(chat_attachButtonDrawables[5], getColor(key_chat_attachPollIcon), true);
setCombinedDrawableColor(chat_attachButtonDrawables[1], getColor(key_chat_attachGalleryBackground), false);
setCombinedDrawableColor(chat_attachButtonDrawables[1], getColor(key_chat_attachGalleryIcon), true);
setCombinedDrawableColor(chat_attachButtonDrawables[2], getColor(key_chat_attachVideoBackground), false);
setCombinedDrawableColor(chat_attachButtonDrawables[2], getColor(key_chat_attachVideoIcon), true);
setCombinedDrawableColor(chat_attachButtonDrawables[3], getColor(key_chat_attachAudioBackground), false);
setCombinedDrawableColor(chat_attachButtonDrawables[3], getColor(key_chat_attachAudioIcon), true);
setCombinedDrawableColor(chat_attachButtonDrawables[4], getColor(key_chat_attachFileBackground), false);
setCombinedDrawableColor(chat_attachButtonDrawables[4], getColor(key_chat_attachFileIcon), true);
setCombinedDrawableColor(chat_attachButtonDrawables[5], getColor(key_chat_attachContactBackground), false);
setCombinedDrawableColor(chat_attachButtonDrawables[5], getColor(key_chat_attachContactIcon), true);
setCombinedDrawableColor(chat_attachButtonDrawables[6], getColor(key_chat_attachLocationBackground), false);
setCombinedDrawableColor(chat_attachButtonDrawables[6], getColor(key_chat_attachLocationIcon), true);
setCombinedDrawableColor(chat_attachButtonDrawables[7], getColor(key_chat_attachHideBackground), false);
setCombinedDrawableColor(chat_attachButtonDrawables[7], getColor(key_chat_attachHideIcon), true);
setCombinedDrawableColor(chat_attachButtonDrawables[8], getColor(key_chat_attachSendBackground), false);
setCombinedDrawableColor(chat_attachButtonDrawables[8], getColor(key_chat_attachSendIcon), true);
setCombinedDrawableColor(chat_attachButtonDrawables[9], getColor(key_chat_attachPollBackground), false);
setCombinedDrawableColor(chat_attachButtonDrawables[9], getColor(key_chat_attachPollIcon), true);
setDrawableColor(chat_attachEmptyDrawable, getColor(key_chat_attachEmptyImage));
applyChatServiceMessageColor();
}

View file

@ -8,6 +8,7 @@
package org.telegram.ui.ActionBar;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffColorFilter;
@ -96,6 +97,7 @@ public class ThemeDescription {
public static int FLAG_AB_SUBMENUBACKGROUND = 0x80000000;
private View viewToInvalidate;
private int alphaOverride = -1;
private Paint[] paintToUpdate;
private Drawable[] drawablesToUpdate;
private Class[] listClasses;
@ -157,6 +159,10 @@ public class ThemeDescription {
}
public ThemeDescription(View view, int flags, Class[] classes, String[] classesFields, Paint[] paint, Drawable[] drawables, ThemeDescriptionDelegate themeDescriptionDelegate, String key) {
this(view, flags, classes, classesFields, paint, drawables, -1, themeDescriptionDelegate, key);
}
public ThemeDescription(View view, int flags, Class[] classes, String[] classesFields, Paint[] paint, Drawable[] drawables, int alpha, ThemeDescriptionDelegate themeDescriptionDelegate, String key) {
currentKey = key;
paintToUpdate = paint;
drawablesToUpdate = drawables;
@ -164,6 +170,7 @@ public class ThemeDescription {
changeFlags = flags;
listClasses = classes;
listClassesFieldName = classesFields;
alphaOverride = alpha;
delegate = themeDescriptionDelegate;
cachedFields = new HashMap<>();
notFoundCachedFields = new HashMap<>();
@ -211,6 +218,10 @@ public class ThemeDescription {
if (save) {
Theme.setColor(currentKey, color, useDefault);
}
currentColor = color;
if (alphaOverride > 0) {
color = Color.argb(alphaOverride, Color.red(color), Color.green(color), Color.blue(color));
}
if (paintToUpdate != null) {
for (int a = 0; a < paintToUpdate.length; a++) {
if ((changeFlags & FLAG_LINKCOLOR) != 0 && paintToUpdate[a] instanceof TextPaint) {
@ -465,7 +476,6 @@ public class ThemeDescription {
}
processViewColor(viewToInvalidate, color);
}
currentColor = color;
if (delegate != null) {
delegate.didSetColor();
}

View file

@ -236,6 +236,16 @@ public class StickersAdapter extends RecyclerListView.SelectionAdapter implement
lastSticker = emoji.toString();
stickersToLoad.clear();
boolean isValidEmoji = searchEmoji && (Emoji.isValidEmoji(originalEmoji) || Emoji.isValidEmoji(lastSticker));
if (isValidEmoji) {
TLRPC.Document animatedSticker = MediaDataController.getInstance(currentAccount).getEmojiAnimatedSticker(emoji);
if (animatedSticker != null) {
ArrayList<TLRPC.TL_messages_stickerSet> sets = MediaDataController.getInstance(currentAccount).getStickerSets(MediaDataController.TYPE_EMOJI);
File f = FileLoader.getPathToAttach(animatedSticker, true);
if (!f.exists()) {
FileLoader.getInstance(currentAccount).loadFile(ImageLocation.getForDocument(animatedSticker), sets.get(0), null, 1, 1);
}
}
}
if (emojiOnly || SharedConfig.suggestStickers == 2 || !isValidEmoji) {
if (visible && (keywordResults == null || keywordResults.isEmpty())) {
visible = false;

View file

@ -40,6 +40,7 @@ import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import androidx.annotation.Keep;
import androidx.annotation.NonNull;
import androidx.core.content.FileProvider;
import androidx.recyclerview.widget.DefaultItemAnimator;
import androidx.recyclerview.widget.GridLayoutManager;
@ -49,12 +50,14 @@ import androidx.recyclerview.widget.RecyclerView;
import androidx.viewpager.widget.PagerAdapter;
import androidx.viewpager.widget.ViewPager;
import android.text.Layout;
import android.text.Selection;
import android.text.Spannable;
import android.text.SpannableStringBuilder;
import android.text.Spanned;
import android.text.StaticLayout;
import android.text.TextPaint;
import android.text.TextUtils;
import android.text.method.LinkMovementMethod;
import android.text.style.MetricAffectingSpan;
import android.text.style.URLSpan;
import android.util.LongSparseArray;
@ -156,6 +159,7 @@ import org.telegram.ui.Components.TextPaintSpan;
import org.telegram.ui.Components.TextPaintUrlSpan;
import org.telegram.ui.Components.TextPaintWebpageUrlSpan;
import org.telegram.ui.Components.TypefaceSpan;
import org.telegram.ui.Components.URLSpanNoUnderline;
import org.telegram.ui.Components.VideoPlayer;
import org.telegram.ui.Components.WebPlayerView;
@ -3707,7 +3711,7 @@ public class ArticleViewer implements NotificationCenter.NotificationCenterDeleg
captionTextViewNext = new TextView(activity);
captionTextViewNext.setMaxLines(10);
captionTextViewNext.setBackgroundColor(0x7f000000);
captionTextViewNext.setMovementMethod(new PhotoViewer.LinkMovementMethodMy());
captionTextViewNext.setMovementMethod(new LinkMovementMethodMy());
captionTextViewNext.setPadding(AndroidUtilities.dp(20), AndroidUtilities.dp(8), AndroidUtilities.dp(20), AndroidUtilities.dp(8));
captionTextViewNext.setLinkTextColor(0xffffffff);
captionTextViewNext.setTextColor(0xffffffff);
@ -3720,7 +3724,7 @@ public class ArticleViewer implements NotificationCenter.NotificationCenterDeleg
captionTextView = new TextView(activity);
captionTextView.setMaxLines(10);
captionTextView.setBackgroundColor(0x7f000000);
captionTextView.setMovementMethod(new PhotoViewer.LinkMovementMethodMy());
captionTextView.setMovementMethod(new LinkMovementMethodMy());
captionTextView.setPadding(AndroidUtilities.dp(20), AndroidUtilities.dp(8), AndroidUtilities.dp(20), AndroidUtilities.dp(8));
captionTextView.setLinkTextColor(0xffffffff);
captionTextView.setTextColor(0xffffffff);
@ -10409,6 +10413,22 @@ public class ArticleViewer implements NotificationCenter.NotificationCenterDeleg
//------------ photo viewer
private class LinkMovementMethodMy extends LinkMovementMethod {
@Override
public boolean onTouchEvent(@NonNull TextView widget, @NonNull Spannable buffer, @NonNull MotionEvent event) {
try {
boolean result = super.onTouchEvent(widget, buffer, event);
if (event.getAction() == MotionEvent.ACTION_UP || event.getAction() == MotionEvent.ACTION_CANCEL) {
Selection.removeSelection(buffer);
}
return result;
} catch (Exception e) {
FileLog.e(e);
}
return false;
}
}
private int[] coords = new int[2];
private boolean isPhotoVisible;

View file

@ -8,10 +8,7 @@
package org.telegram.ui;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.view.View;
import android.view.ViewGroup;
@ -22,8 +19,6 @@ import org.telegram.SQLite.SQLiteCursor;
import org.telegram.SQLite.SQLiteDatabase;
import org.telegram.SQLite.SQLitePreparedStatement;
import org.telegram.messenger.AndroidUtilities;
import org.telegram.messenger.ApplicationLoader;
import org.telegram.messenger.ClearCacheService;
import org.telegram.messenger.MediaDataController;
import org.telegram.messenger.FileLoader;
import org.telegram.messenger.FileLog;
@ -32,6 +27,7 @@ import org.telegram.messenger.LocaleController;
import org.telegram.messenger.MessagesController;
import org.telegram.messenger.MessagesStorage;
import org.telegram.messenger.R;
import org.telegram.messenger.SharedConfig;
import org.telegram.messenger.UserConfig;
import org.telegram.messenger.Utilities;
import org.telegram.tgnet.NativeByteBuffer;
@ -252,26 +248,19 @@ public class CacheControlActivity extends BaseFragment {
if (position == keepMediaRow) {
BottomSheet.Builder builder = new BottomSheet.Builder(getParentActivity());
builder.setItems(new CharSequence[]{LocaleController.formatPluralString("Days", 3), LocaleController.formatPluralString("Weeks", 1), LocaleController.formatPluralString("Months", 1), LocaleController.getString("KeepMediaForever", R.string.KeepMediaForever)}, (dialog, which) -> {
SharedPreferences.Editor editor = MessagesController.getGlobalMainSettings().edit();
if (which == 0) {
editor.putInt("keep_media", 3);
SharedConfig.setKeepMedia(3);
} else if (which == 1) {
editor.putInt("keep_media", 0);
SharedConfig.setKeepMedia(0);
} else if (which == 2) {
editor.putInt("keep_media", 1);
SharedConfig.setKeepMedia(1);
} else if (which == 3) {
editor.putInt("keep_media", 2);
SharedConfig.setKeepMedia(2);
}
editor.commit();
if (listAdapter != null) {
listAdapter.notifyDataSetChanged();
}
PendingIntent pintent = PendingIntent.getService(ApplicationLoader.applicationContext, 1, new Intent(ApplicationLoader.applicationContext, ClearCacheService.class), 0);
AlarmManager alarmManager = (AlarmManager) ApplicationLoader.applicationContext.getSystemService(Context.ALARM_SERVICE);
alarmManager.cancel(pintent);
if (which != 3) {
alarmManager.setInexactRepeating(AlarmManager.RTC_WAKEUP, 0, AlarmManager.INTERVAL_DAY, pintent);
}
SharedConfig.checkKeepMedia();
});
showDialog(builder.create());
} else if (position == databaseRow) {
@ -280,6 +269,9 @@ public class CacheControlActivity extends BaseFragment {
builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null);
builder.setMessage(LocaleController.getString("LocalDatabaseClear", R.string.LocalDatabaseClear));
builder.setPositiveButton(LocaleController.getString("CacheClear", R.string.CacheClear), (dialogInterface, i) -> {
if (getParentActivity() == null) {
return;
}
final AlertDialog progressDialog = new AlertDialog(getParentActivity(), 3);
progressDialog.setCanCacnel(false);
progressDialog.show();
@ -507,7 +499,7 @@ public class CacheControlActivity extends BaseFragment {
}
} else if (position == keepMediaRow) {
SharedPreferences preferences = MessagesController.getGlobalMainSettings();
int keepMedia = preferences.getInt("keep_media", 2);
int keepMedia = SharedConfig.keepMedia;
String value;
if (keepMedia == 0) {
value = LocaleController.formatPluralString("Weeks", 1);

View file

@ -13,12 +13,9 @@ import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.Dialog;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.PackageInfo;
import android.graphics.Canvas;
import android.graphics.Paint;
@ -29,7 +26,6 @@ import android.graphics.drawable.Drawable;
import android.os.Build;
import android.os.Bundle;
import android.telephony.PhoneNumberUtils;
import android.telephony.SmsManager;
import android.telephony.TelephonyManager;
import android.text.Editable;
import android.text.InputType;
@ -50,12 +46,10 @@ import android.widget.TextView;
import org.telegram.PhoneFormat.PhoneFormat;
import org.telegram.messenger.AndroidUtilities;
import org.telegram.messenger.ApplicationLoader;
import org.telegram.messenger.BuildVars;
import org.telegram.messenger.FileLog;
import org.telegram.messenger.LocaleController;
import org.telegram.messenger.NotificationCenter;
import org.telegram.messenger.R;
import org.telegram.messenger.SmsReceiver;
import org.telegram.tgnet.ConnectionsManager;
import org.telegram.tgnet.TLRPC;
import org.telegram.ui.ActionBar.ActionBar;
@ -388,24 +382,7 @@ public class CancelAccountDeletionActivity extends BaseFragment {
req.hash = hash;
req.settings = new TLRPC.TL_codeSettings();
req.settings.allow_flashcall = false;//simcardAvailable && allowCall;
if (Build.VERSION.SDK_INT >= 26) {
try {
req.settings.app_hash = SmsManager.getDefault().createAppSpecificSmsToken(PendingIntent.getBroadcast(ApplicationLoader.applicationContext, 0, new Intent(ApplicationLoader.applicationContext, SmsReceiver.class), PendingIntent.FLAG_UPDATE_CURRENT));
} catch (Throwable e) {
FileLog.e(e);
}
} else {
req.settings.app_hash = BuildVars.SMS_HASH;
req.settings.app_hash_persistent = true;
}
SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("mainconfig", Activity.MODE_PRIVATE);
if (!TextUtils.isEmpty(req.settings.app_hash)) {
req.settings.flags |= 8;
preferences.edit().putString("sms_hash", req.settings.app_hash).commit();
} else {
preferences.edit().remove("sms_hash").commit();
}
req.settings.allow_app_hash = ApplicationLoader.hasPlayServices;
if (req.settings.allow_flashcall) {
try {
@SuppressLint("HardwareIds") String number = tm.getLine1Number();

View file

@ -23,7 +23,7 @@ import org.telegram.messenger.FileLoader;
import org.telegram.messenger.ImageLocation;
import org.telegram.messenger.LocaleController;
import org.telegram.messenger.MessageObject;
import org.telegram.messenger.SharedConfig;
import org.telegram.tgnet.TLObject;
import org.telegram.tgnet.TLRPC;
import org.telegram.ui.ActionBar.Theme;
import org.telegram.ui.Components.BackupImageView;
@ -100,20 +100,38 @@ public class ArchivedStickerSetCell extends FrameLayout {
textView.setText(stickersSet.set.title);
valueTextView.setText(LocaleController.formatPluralString("Stickers", set.set.count));
TLRPC.PhotoSize thumb = set.cover != null ? FileLoader.getClosestPhotoSizeWithSize(set.cover.thumbs, 90) : null;
if (thumb != null && thumb.location != null) {
if (MessageObject.canAutoplayAnimatedSticker(set.cover)) {
imageView.setImage(ImageLocation.getForDocument(set.cover), "80_80", ImageLocation.getForDocument(thumb, set.cover), null, 0, set);
} else {
imageView.setImage(ImageLocation.getForDocument(thumb, set.cover), null, "webp", null, set);
}
TLRPC.Document sticker;
if (set.cover != null) {
sticker = set.cover;
} else if (!set.covers.isEmpty()) {
TLRPC.Document document = set.covers.get(0);
thumb = FileLoader.getClosestPhotoSizeWithSize(document.thumbs, 90);
if (MessageObject.canAutoplayAnimatedSticker(document)) {
imageView.setImage(ImageLocation.getForDocument(document), "80_80", ImageLocation.getForDocument(thumb, document), null, 0, set);
sticker = set.covers.get(0);
} else {
sticker = null;
}
if (sticker != null) {
TLObject object;
if (set.set.thumb instanceof TLRPC.TL_photoSize) {
object = set.set.thumb;
} else {
imageView.setImage(ImageLocation.getForDocument(thumb, document), null, "webp", null, set);
object = sticker;
}
ImageLocation imageLocation;
if (object instanceof TLRPC.Document) {
TLRPC.PhotoSize thumb = FileLoader.getClosestPhotoSizeWithSize(sticker.thumbs, 90);
imageLocation = ImageLocation.getForDocument(thumb, sticker);
} else {
TLRPC.PhotoSize thumb = (TLRPC.PhotoSize) object;
imageLocation = ImageLocation.getForSticker(thumb, sticker);
}
if (object instanceof TLRPC.Document && MessageObject.isAnimatedStickerDocument(sticker)) {
imageView.setImage(ImageLocation.getForDocument(sticker), "50_50", imageLocation, null, 0, set);
} else if (imageLocation != null && imageLocation.lottieAnimation) {
imageView.setImage(imageLocation, "50_50", "tgs", null, set);
} else {
imageView.setImage(imageLocation, "50_50", "webp", null, set);
}
} else {
imageView.setImage(null, null, "webp", null, set);

View file

@ -133,7 +133,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate
default void didPressReplyMessage(ChatMessageCell cell, int id) {
}
default void didPressUrl(MessageObject messageObject, CharacterStyle url, boolean longPress) {
default void didPressUrl(ChatMessageCell cell, CharacterStyle url, boolean longPress) {
}
default void needOpenWebView(String url, String title, String description, String originalUrl, int w, int h) {
@ -157,8 +157,8 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate
default void didPressInstantButton(ChatMessageCell cell, int type) {
}
default boolean isChatAdminCell(int uid) {
return false;
default String getAdminRank(int uid) {
return null;
}
default boolean needPlayMessage(MessageObject messageObject) {
@ -174,6 +174,13 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate
default void didStartVideoStream(MessageObject message) {
}
default boolean shouldRepeatSticker(MessageObject message) {
return true;
}
default void setShouldNotRepeatSticker(MessageObject message) {
}
}
private final static int DOCUMENT_ATTACH_TYPE_NONE = 0;
@ -751,7 +758,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate
return true;
} else {
if (link[0] == pressedLink) {
delegate.didPressUrl(currentMessageObject, pressedLink, false);
delegate.didPressUrl(this, pressedLink, false);
resetPressedLink(1);
return true;
}
@ -817,7 +824,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate
FileLog.e(e);
}
} else if (pressedLinkType == 3) {
delegate.didPressUrl(currentMessageObject, pressedLink, false);
delegate.didPressUrl(this, pressedLink, false);
resetPressedLink(3);
return true;
}
@ -1256,7 +1263,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate
imagePressed = true;
result = true;
}
} else if (!currentMessageObject.isAnyKindOfSticker() || currentMessageObject.getInputStickerSet() != null) {
} else if (!currentMessageObject.isAnyKindOfSticker() || currentMessageObject.getInputStickerSet() != null || currentMessageObject.isAnimatedEmoji()) {
if (x >= photoImage.getImageX() && x <= photoImage.getImageX() + photoImage.getImageWidth() && y >= photoImage.getImageY() && y <= photoImage.getImageY() + photoImage.getImageHeight()) {
imagePressed = true;
result = true;
@ -1652,7 +1659,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate
}
if (documentAttachType == DOCUMENT_ATTACH_TYPE_VIDEO) {
if (PhotoViewer.isPlayingMessage(currentMessageObject) || MediaController.getInstance().isGoingToShowMessageObject(currentMessageObject)) {
if (infoLayout != null && (PhotoViewer.isPlayingMessage(currentMessageObject) || MediaController.getInstance().isGoingToShowMessageObject(currentMessageObject))) {
return;
}
int duration = 0;
@ -2973,6 +2980,13 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate
photoImage.setImage(null, null, ImageLocation.getForDocument(currentPhotoObject, document), "b1", 0, "jpg", messageObject, 1);
}
} else if (documentAttachType == DOCUMENT_ATTACH_TYPE_STICKER) {
boolean isWebpSticker = messageObject.isSticker();
if (SharedConfig.loopStickers || isWebpSticker) {
photoImage.setAutoRepeat(1);
} else {
currentPhotoFilter = String.format(Locale.US, "%d_%d_nr_%s", width, height, messageObject.toString());
photoImage.setAutoRepeat(delegate.shouldRepeatSticker(messageObject) ? 2 : 3);
}
photoImage.setImage(ImageLocation.getForDocument(documentAttach), currentPhotoFilter, ImageLocation.getForDocument(currentPhotoObject, documentAttach), "b1", documentAttach.size, "webp", messageObject, 1);
} else if (documentAttachType == DOCUMENT_ATTACH_TYPE_VIDEO) {
photoImage.setNeedsQualityThumb(true);
@ -3618,14 +3632,15 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate
} else if (messageObject.isAnyKindOfSticker()) { //sticker
drawBackground = false;
boolean isWebpSticker = messageObject.type == MessageObject.TYPE_STICKER;
for (int a = 0; a < messageObject.messageOwner.media.document.attributes.size(); a++) {
TLRPC.DocumentAttribute attribute = messageObject.messageOwner.media.document.attributes.get(a);
for (int a = 0; a < messageObject.getDocument().attributes.size(); a++) {
TLRPC.DocumentAttribute attribute = messageObject.getDocument().attributes.get(a);
if (attribute instanceof TLRPC.TL_documentAttributeImageSize) {
photoWidth = attribute.w;
photoHeight = attribute.h;
break;
}
}
if (photoWidth == 0 && photoHeight == 0 && messageObject.isAnimatedSticker()) {
if (messageObject.isAnimatedSticker() && photoWidth == 0 && photoHeight == 0) {
photoWidth = photoHeight = 512;
}
float maxHeight;
@ -3635,15 +3650,34 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate
} else {
maxHeight = maxWidth = Math.min(AndroidUtilities.displaySize.x, AndroidUtilities.displaySize.y) * 0.5f;
}
if (photoWidth == 0) {
photoHeight = (int) maxHeight;
photoWidth = photoHeight + AndroidUtilities.dp(100);
String filter;
if (messageObject.isAnimatedEmoji()) {
float zoom = MessagesController.getInstance(currentAccount).animatedEmojisZoom;
photoWidth = (int) ((photoWidth / 512.0f) * maxWidth * zoom);
photoHeight = (int) ((photoHeight / 512.0f) * maxHeight * zoom);
} else {
if (photoWidth == 0) {
photoHeight = (int) maxHeight;
photoWidth = photoHeight + AndroidUtilities.dp(100);
}
photoHeight *= maxWidth / photoWidth;
photoWidth = (int) maxWidth;
if (photoHeight > maxHeight) {
photoWidth *= maxHeight / photoHeight;
photoHeight = (int) maxHeight;
}
}
photoHeight *= maxWidth / photoWidth;
photoWidth = (int) maxWidth;
if (photoHeight > maxHeight) {
photoWidth *= maxHeight / photoHeight;
photoHeight = (int) maxHeight;
Object parentObject = messageObject;
if (messageObject.isAnimatedEmoji()) {
filter = String.format(Locale.US, "%d_%d_nr_%s" + messageObject.emojiAnimatedStickerColor, photoWidth, photoHeight, messageObject.toString());
photoImage.setAutoRepeat(delegate.shouldRepeatSticker(messageObject) ? 2 : 3);
parentObject = MessageObject.getInputStickerSet(messageObject.emojiAnimatedSticker);
} else if (SharedConfig.loopStickers || isWebpSticker) {
filter = String.format(Locale.US, "%d_%d", photoWidth, photoHeight);
photoImage.setAutoRepeat(1);
} else {
filter = String.format(Locale.US, "%d_%d_nr_%s", photoWidth, photoHeight, messageObject.toString());
photoImage.setAutoRepeat(delegate.shouldRepeatSticker(messageObject) ? 2 : 3);
}
documentAttachType = DOCUMENT_ATTACH_TYPE_STICKER;
availableTimeWidth = photoWidth - AndroidUtilities.dp(14);
@ -3652,13 +3686,13 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate
currentPhotoObjectThumb = FileLoader.getClosestPhotoSizeWithSize(messageObject.photoThumbs, 40);
photoParentObject = messageObject.photoThumbsObject;
if (messageObject.attachPathExists) {
photoImage.setImage(ImageLocation.getForPath(messageObject.messageOwner.attachPath), String.format(Locale.US, "%d_%d", photoWidth, photoHeight),
photoImage.setImage(ImageLocation.getForPath(messageObject.messageOwner.attachPath), filter,
ImageLocation.getForObject(currentPhotoObjectThumb, photoParentObject), "b1",
messageObject.messageOwner.media.document.size, isWebpSticker ? "webp" : null, messageObject, 1);
} else if (messageObject.messageOwner.media.document.id != 0) {
photoImage.setImage(ImageLocation.getForDocument(messageObject.messageOwner.media.document), String.format(Locale.US, "%d_%d", photoWidth, photoHeight),
messageObject.getDocument().size, isWebpSticker ? "webp" : null, parentObject, 1);
} else if (messageObject.getDocument().id != 0) {
photoImage.setImage(ImageLocation.getForDocument(messageObject.getDocument()), filter,
ImageLocation.getForObject(currentPhotoObjectThumb, photoParentObject), "b1",
messageObject.messageOwner.media.document.size, isWebpSticker ? "webp" : null, messageObject, 1);
messageObject.getDocument().size, isWebpSticker ? "webp" : null, parentObject, 1);
}
} else {
currentPhotoObject = FileLoader.getClosestPhotoSizeWithSize(messageObject.photoThumbs, AndroidUtilities.getPhotoSize());
@ -3780,8 +3814,8 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate
}
if ((w == 0 || h == 0) && messageObject.type == 8) {
for (int a = 0; a < messageObject.messageOwner.media.document.attributes.size(); a++) {
TLRPC.DocumentAttribute attribute = messageObject.messageOwner.media.document.attributes.get(a);
for (int a = 0; a < messageObject.getDocument().attributes.size(); a++) {
TLRPC.DocumentAttribute attribute = messageObject.getDocument().attributes.get(a);
if (attribute instanceof TLRPC.TL_documentAttributeImageSize || attribute instanceof TLRPC.TL_documentAttributeVideo) {
float scale = (float) attribute.w / (float) photoWidth;
w = (int) (attribute.w / scale);
@ -4068,8 +4102,8 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate
if (autoPlayingMedia) {
photoImage.setAllowStartAnimation(true);
photoImage.startAnimation();
TLRPC.Document document = messageObject.messageOwner.media.document;
photoImage.setImage(ImageLocation.getForDocument(document), ImageLoader.AUTOPLAY_FILTER, ImageLocation.getForObject(currentPhotoObject, photoParentObject), currentPhotoFilter, ImageLocation.getForDocument(currentPhotoObjectThumb, document), currentPhotoFilterThumb, null, messageObject.messageOwner.media.document.size, null, messageObject, 0);
TLRPC.Document document = messageObject.getDocument();
photoImage.setImage(ImageLocation.getForDocument(document), ImageLoader.AUTOPLAY_FILTER, ImageLocation.getForObject(currentPhotoObject, photoParentObject), currentPhotoFilter, ImageLocation.getForDocument(currentPhotoObjectThumb, document), currentPhotoFilterThumb, null, messageObject.getDocument().size, null, messageObject, 0);
} else if (messageObject.type == 1) {
if (messageObject.useCustomPhoto) {
photoImage.setImageBitmap(getResources().getDrawable(R.drawable.theme_preview_image));
@ -4097,7 +4131,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate
}
}
} else if (messageObject.type == 8 || messageObject.type == MessageObject.TYPE_ROUND_VIDEO) {
String fileName = FileLoader.getAttachFileName(messageObject.messageOwner.media.document);
String fileName = FileLoader.getAttachFileName(messageObject.getDocument());
int localFile = 0;
if (messageObject.attachPathExists) {
DownloadController.getInstance(currentAccount).removeLoadingFileObserver(this);
@ -4106,17 +4140,17 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate
localFile = 2;
}
boolean autoDownload = false;
if (MessageObject.isGifDocument(messageObject.messageOwner.media.document) || messageObject.type == MessageObject.TYPE_ROUND_VIDEO) {
if (MessageObject.isGifDocument(messageObject.getDocument()) || messageObject.type == MessageObject.TYPE_ROUND_VIDEO) {
autoDownload = DownloadController.getInstance(currentAccount).canDownloadMedia(currentMessageObject);
}
if (!messageObject.isSending() && !messageObject.isEditing() && (localFile != 0 || FileLoader.getInstance(currentAccount).isLoadingFile(fileName) || autoDownload)) {
if (localFile != 1 && !messageObject.needDrawBluredPreview() && (localFile != 0 || messageObject.canStreamVideo() && autoDownload)) {
autoPlayingMedia = true;
photoImage.setImage(ImageLocation.getForDocument(messageObject.messageOwner.media.document), ImageLoader.AUTOPLAY_FILTER, ImageLocation.getForObject(currentPhotoObject, photoParentObject), currentPhotoFilter, ImageLocation.getForObject(currentPhotoObjectThumb, photoParentObject), currentPhotoFilterThumb, null, messageObject.messageOwner.media.document.size, null, messageObject, 0);
photoImage.setImage(ImageLocation.getForDocument(messageObject.getDocument()), ImageLoader.AUTOPLAY_FILTER, ImageLocation.getForObject(currentPhotoObject, photoParentObject), currentPhotoFilter, ImageLocation.getForObject(currentPhotoObjectThumb, photoParentObject), currentPhotoFilterThumb, null, messageObject.getDocument().size, null, messageObject, 0);
} else if (localFile == 1) {
photoImage.setImage(ImageLocation.getForPath(messageObject.isSendError() ? null : messageObject.messageOwner.attachPath), null, ImageLocation.getForObject(currentPhotoObjectThumb, photoParentObject), currentPhotoFilterThumb, 0, null, messageObject, 0);
} else {
photoImage.setImage(ImageLocation.getForDocument(messageObject.messageOwner.media.document), null, ImageLocation.getForObject(currentPhotoObject, photoParentObject), currentPhotoFilter, ImageLocation.getForObject(currentPhotoObjectThumb, photoParentObject), currentPhotoFilterThumb, null, messageObject.messageOwner.media.document.size, null, messageObject, 0);
photoImage.setImage(ImageLocation.getForDocument(messageObject.getDocument()), null, ImageLocation.getForObject(currentPhotoObject, photoParentObject), currentPhotoFilter, ImageLocation.getForObject(currentPhotoObjectThumb, photoParentObject), currentPhotoFilterThumb, null, messageObject.getDocument().size, null, messageObject, 0);
}
} else {
photoImage.setImage(ImageLocation.getForObject(currentPhotoObject, photoParentObject), currentPhotoFilter, ImageLocation.getForObject(currentPhotoObjectThumb, photoParentObject), currentPhotoFilterThumb, 0, null, messageObject, 0);
@ -4423,16 +4457,16 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate
@Override
protected void onLongPress() {
if (pressedLink instanceof URLSpanMono) {
delegate.didPressUrl(currentMessageObject, pressedLink, true);
delegate.didPressUrl(this, pressedLink, true);
return;
} else if (pressedLink instanceof URLSpanNoUnderline) {
URLSpanNoUnderline url = (URLSpanNoUnderline) pressedLink;
if (url.getURL().startsWith("/")) {
delegate.didPressUrl(currentMessageObject, pressedLink, true);
delegate.didPressUrl(this, pressedLink, true);
return;
}
} else if (pressedLink instanceof URLSpan) {
delegate.didPressUrl(currentMessageObject, pressedLink, true);
delegate.didPressUrl(this, pressedLink, true);
return;
}
resetPressedLink(-1);
@ -4591,7 +4625,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate
if (messageObject.type == 0) {
documentAttach = messageObject.messageOwner.media.webpage.document;
} else {
documentAttach = messageObject.messageOwner.media.document;
documentAttach = messageObject.getDocument();
}
if (documentAttach == null) {
return 0;
@ -4701,7 +4735,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate
if (infoWidth < 0) {
infoWidth = AndroidUtilities.dp(10);
}
infoLayout = new StaticLayout(str2, Theme.chat_infoPaint, infoWidth, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false);
infoLayout = new StaticLayout(str2, Theme.chat_infoPaint, infoWidth + AndroidUtilities.dp(6), Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false);
} catch (Exception e) {
FileLog.e(e);
}
@ -5510,7 +5544,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate
imageDrawn = photoImage.draw(canvas);
}
}
if (documentAttachType == DOCUMENT_ATTACH_TYPE_VIDEO) {
if (documentAttachType == DOCUMENT_ATTACH_TYPE_VIDEO || documentAttachType == DOCUMENT_ATTACH_TYPE_GIF) {
videoButtonX = photoImage.getImageX() + AndroidUtilities.dp(8);
videoButtonY = photoImage.getImageY() + AndroidUtilities.dp(8);
videoRadialProgress.setProgressRect(videoButtonX, videoButtonY, videoButtonX + AndroidUtilities.dp(24), videoButtonY + AndroidUtilities.dp(24));
@ -6007,7 +6041,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate
int x = button.x + button.width - AndroidUtilities.dp(9 + 3) + addX;
rect.set(x, y + AndroidUtilities.dp(4), x + AndroidUtilities.dp(8), y + AndroidUtilities.dp(8 + 4));
canvas.drawArc(rect, button.angle, 220, false, Theme.chat_botProgressPaint);
invalidate((int) rect.left - AndroidUtilities.dp(2), (int) rect.top - AndroidUtilities.dp(2), (int) rect.right + AndroidUtilities.dp(2), (int) rect.bottom + AndroidUtilities.dp(2));
invalidate();
long newTime = System.currentTimeMillis();
if (Math.abs(button.lastUpdateTime - System.currentTimeMillis()) < 1000) {
long delta = (newTime - button.lastUpdateTime);
@ -6556,7 +6590,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate
photoImage.setImage(ImageLocation.getForDocument(document), null, ImageLocation.getForObject(thumb, document), thumbFilter, document.size, null, currentMessageObject, 0);
}
} else if (currentMessageObject.type == 9) {
FileLoader.getInstance(currentAccount).loadFile(documentAttach, currentMessageObject, 0, 0);
FileLoader.getInstance(currentAccount).loadFile(documentAttach, currentMessageObject, 1, 0);
} else if (documentAttachType == DOCUMENT_ATTACH_TYPE_VIDEO) {
FileLoader.getInstance(currentAccount).loadFile(documentAttach, currentMessageObject, 1, currentMessageObject.shouldEncryptPhotoOrVideo() ? 2 : 0);
} else if (currentMessageObject.type == 0 && documentAttachType != DOCUMENT_ATTACH_TYPE_NONE) {
@ -6603,7 +6637,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate
ImageLoader.getInstance().cancelForceLoadingForImageReceiver(photoImage);
photoImage.cancelLoadImage();
} else if (currentMessageObject.type == 9) {
FileLoader.getInstance(currentAccount).cancelLoadFile(currentMessageObject.messageOwner.media.document);
FileLoader.getInstance(currentAccount).cancelLoadFile(currentMessageObject.getDocument());
}
buttonState = 0;
if (video) {
@ -6733,6 +6767,13 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate
}
}
@Override
public void onAnimationReady(ImageReceiver imageReceiver) {
if (currentMessageObject != null && imageReceiver == photoImage && currentMessageObject.isAnimatedSticker()) {
delegate.setShouldNotRepeatSticker(currentMessageObject);
}
}
@Override
public void onProgressDownload(String fileName, float progress) {
if (drawVideoImageButton) {
@ -7004,12 +7045,16 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate
}
int adminWidth;
String adminString;
String adminLabel;
if (isMegagroup && currentChat != null && currentMessageObject.isForwardedChannelPost()) {
adminString = LocaleController.getString("DiscussChannel", R.string.DiscussChannel);
adminWidth = (int) Math.ceil(Theme.chat_adminPaint.measureText(adminString));
nameWidth -= adminWidth;
} else if (currentUser != null && !currentMessageObject.isOutOwner() && !currentMessageObject.isAnyKindOfSticker() && currentMessageObject.type != 5 && delegate.isChatAdminCell(currentUser.id)) {
adminString = LocaleController.getString("ChatAdmin", R.string.ChatAdmin);
} else if (currentUser != null && !currentMessageObject.isOutOwner() && !currentMessageObject.isAnyKindOfSticker() && currentMessageObject.type != 5 && (adminLabel = delegate.getAdminRank(currentUser.id)) != null) {
if (adminLabel.length() == 0) {
adminLabel = LocaleController.getString("ChatAdmin", R.string.ChatAdmin);
}
adminString = adminLabel;
adminWidth = (int) Math.ceil(Theme.chat_adminPaint.measureText(adminString));
nameWidth -= adminWidth;
} else {
@ -7838,13 +7883,13 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate
public void setCheckBoxVisible(boolean visible, boolean animated) {
if (visible && checkBox == null) {
checkBox = new CheckBoxBase(this);
checkBox = new CheckBoxBase(this, 21);
if (attachedToWindow) {
checkBox.onAttachedToWindow();
}
}
if (visible && photoCheckBox == null && currentMessagesGroup != null && currentMessagesGroup.messages.size() > 1) {
photoCheckBox = new CheckBoxBase(this);
photoCheckBox = new CheckBoxBase(this, 21);
photoCheckBox.setUseDefaultCheck(true);
if (attachedToWindow) {
photoCheckBox.onAttachedToWindow();
@ -9002,7 +9047,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate
if (virtualViewId >= LINK_IDS_START) {
ClickableSpan link = getLinkById(virtualViewId);
if (link != null) {
delegate.didPressUrl(currentMessageObject, link, false);
delegate.didPressUrl(ChatMessageCell.this, link, false);
sendAccessibilityEventForVirtualView(virtualViewId, AccessibilityEvent.TYPE_VIEW_CLICKED);
}
} else if (virtualViewId >= BOT_BUTTONS_START) {
@ -9041,7 +9086,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate
} else if (action == AccessibilityNodeInfo.ACTION_LONG_CLICK) {
ClickableSpan link = getLinkById(virtualViewId);
if (link != null) {
delegate.didPressUrl(currentMessageObject, link, true);
delegate.didPressUrl(ChatMessageCell.this, link, true);
sendAccessibilityEventForVirtualView(virtualViewId, AccessibilityEvent.TYPE_VIEW_LONG_CLICKED);
}
}

View file

@ -637,6 +637,11 @@ public class ContextLinkCell extends View implements DownloadController.FileDown
}
if (!mediaWebpage) {
if (drawLinkImageView && !PhotoViewer.isShowingImage(inlineResult)) {
letterDrawable.setAlpha((int) (255 * (1.0f - linkImageView.getCurrentAlpha())));
} else {
letterDrawable.setAlpha(255);
}
if (documentAttachType == DOCUMENT_ATTACH_TYPE_AUDIO || documentAttachType == DOCUMENT_ATTACH_TYPE_MUSIC) {
radialProgress.setProgressColor(Theme.getColor(buttonPressed ? Theme.key_chat_inAudioSelectedProgress : Theme.key_chat_inAudioProgress));
radialProgress.draw(canvas);

View file

@ -216,9 +216,8 @@ public class DialogCell extends BaseCell {
useForceThreeLines = forceThreeLines;
if (needCheck) {
checkBox = new CheckBox2(context);
checkBox = new CheckBox2(context, 21);
checkBox.setColor(null, Theme.key_windowBackgroundWhite, Theme.key_checkboxCheck);
checkBox.setSize(21);
checkBox.setDrawUnchecked(false);
checkBox.setDrawBackgroundAsArc(3);
addView(checkBox);

View file

@ -37,6 +37,7 @@ import org.telegram.messenger.LocaleController;
import org.telegram.messenger.MessageObject;
import org.telegram.messenger.R;
import org.telegram.messenger.UserConfig;
import org.telegram.tgnet.TLObject;
import org.telegram.tgnet.TLRPC;
import org.telegram.ui.ActionBar.Theme;
import org.telegram.ui.Components.BackupImageView;
@ -228,21 +229,38 @@ public class FeaturedStickerSetCell extends FrameLayout {
}
valueTextView.setText(LocaleController.formatPluralString("Stickers", set.set.count));
TLRPC.PhotoSize thumb = set.cover != null ? FileLoader.getClosestPhotoSizeWithSize(set.cover.thumbs, 90) : null;
if (thumb != null && thumb.location != null) {
if (MessageObject.canAutoplayAnimatedSticker(set.cover)) {
imageView.setImage(ImageLocation.getForDocument(set.cover), "80_80", ImageLocation.getForDocument(thumb, set.cover), null, 0, set);
} else {
imageView.setImage(ImageLocation.getForDocument(thumb, set.cover), null, "webp", null, set);
}
TLRPC.Document sticker;
if (set.cover != null) {
sticker = set.cover;
} else if (!set.covers.isEmpty()) {
TLRPC.Document document = set.covers.get(0);
thumb = FileLoader.getClosestPhotoSizeWithSize(document.thumbs, 90);
if (MessageObject.canAutoplayAnimatedSticker(document)) {
imageView.setImage(ImageLocation.getForDocument(document), "80_80", ImageLocation.getForDocument(thumb, document), null, 0, set);
sticker = set.covers.get(0);
} else {
sticker = null;
}
if (sticker != null) {
TLObject object;
if (set.set.thumb instanceof TLRPC.TL_photoSize) {
object = set.set.thumb;
} else {
imageView.setImage(ImageLocation.getForDocument(thumb, document), null, "webp", null, set);
object = sticker;
}
ImageLocation imageLocation;
if (object instanceof TLRPC.Document) {
TLRPC.PhotoSize thumb = FileLoader.getClosestPhotoSizeWithSize(sticker.thumbs, 90);
imageLocation = ImageLocation.getForDocument(thumb, sticker);
} else {
TLRPC.PhotoSize thumb = (TLRPC.PhotoSize) object;
imageLocation = ImageLocation.getForSticker(thumb, sticker);
}
if (object instanceof TLRPC.Document && MessageObject.isAnimatedStickerDocument(sticker)) {
imageView.setImage(ImageLocation.getForDocument(sticker), "50_50", imageLocation, null, 0, set);
} else if (imageLocation != null && imageLocation.lottieAnimation) {
imageView.setImage(imageLocation, "50_50", "tgs", null, set);
} else {
imageView.setImage(imageLocation, "50_50", "webp", null, set);
}
} else {
imageView.setImage(null, null, "webp", null, set);

View file

@ -68,9 +68,8 @@ public class GroupCreateUserCell extends FrameLayout {
addView(statusTextView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 20, (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.TOP, (LocaleController.isRTL ? 28 : 72) + padding, 32, (LocaleController.isRTL ? 72 : 28) + padding, 0));
if (needCheck) {
checkBox = new CheckBox2(context);
checkBox = new CheckBox2(context, 21);
checkBox.setColor(null, Theme.key_windowBackgroundWhite, Theme.key_checkboxCheck);
checkBox.setSize(21);
checkBox.setDrawUnchecked(false);
checkBox.setDrawBackgroundAsArc(3);
addView(checkBox, LayoutHelper.createFrame(24, 24, (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.TOP, LocaleController.isRTL ? 0 : 40, 33, LocaleController.isRTL ? 39 : 0, 0));

View file

@ -53,9 +53,8 @@ public class InviteUserCell extends FrameLayout {
addView(statusTextView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 20, (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.TOP, LocaleController.isRTL ? 28 : 72, 39, LocaleController.isRTL ? 72 : 28, 0));
if (needCheck) {
checkBox = new CheckBox2(context);
checkBox = new CheckBox2(context, 21);
checkBox.setColor(null, Theme.key_windowBackgroundWhite, Theme.key_checkboxCheck);
checkBox.setSize(21);
checkBox.setDrawUnchecked(false);
checkBox.setDrawBackgroundAsArc(3);
addView(checkBox, LayoutHelper.createFrame(24, 24, (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.TOP, LocaleController.isRTL ? 0 : 40, 40, LocaleController.isRTL ? 39 : 0, 0));

View file

@ -10,35 +10,59 @@ package org.telegram.ui.Cells;
import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffColorFilter;
import android.view.View;
import android.widget.FrameLayout;
import android.widget.ImageView;
import org.telegram.messenger.AndroidUtilities;
import org.telegram.messenger.ApplicationLoader;
import org.telegram.messenger.R;
import org.telegram.ui.ActionBar.Theme;
import org.telegram.ui.Components.LayoutHelper;
import java.io.File;
@SuppressLint("NewApi")
public class PhotoAttachCameraCell extends FrameLayout {
private ImageView imageView;
private ImageView backgroundView;
private int itemSize;
public PhotoAttachCameraCell(Context context) {
super(context);
backgroundView = new ImageView(context);
backgroundView.setScaleType(ImageView.ScaleType.CENTER_CROP);
//backgroundView.setAdjustViewBounds(false);
addView(backgroundView, LayoutHelper.createFrame(80, 80));
imageView = new ImageView(context);
imageView.setScaleType(ImageView.ScaleType.CENTER);
imageView.setImageResource(R.drawable.instant_camera);
imageView.setBackgroundColor(0xff000000);
addView(imageView, LayoutHelper.createFrame(80, 80));
setFocusable(true);
itemSize = AndroidUtilities.dp(0);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(86), MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(80), MeasureSpec.EXACTLY));
super.onMeasure(MeasureSpec.makeMeasureSpec(itemSize + AndroidUtilities.dp(5), MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(itemSize + AndroidUtilities.dp(5), MeasureSpec.EXACTLY));
}
public void setItemSize(int size) {
itemSize = size;
LayoutParams layoutParams = (LayoutParams) imageView.getLayoutParams();
layoutParams.width = layoutParams.height = itemSize;
layoutParams = (LayoutParams) backgroundView.getLayoutParams();
layoutParams.width = layoutParams.height = itemSize;
}
public ImageView getImageView() {
@ -50,4 +74,19 @@ public class PhotoAttachCameraCell extends FrameLayout {
super.onAttachedToWindow();
imageView.setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_dialogCameraIcon), PorterDuff.Mode.MULTIPLY));
}
public void updateBitmap() {
Bitmap bitmap = null;
try {
File file = new File(ApplicationLoader.getFilesDirFixed(), "cthumb.jpg");
bitmap = BitmapFactory.decodeFile(file.getAbsolutePath());
} catch (Throwable ignore) {
}
if (bitmap != null) {
backgroundView.setImageBitmap(bitmap);
} else {
backgroundView.setImageResource(R.drawable.icplaceholder);
}
}
}

View file

@ -0,0 +1,81 @@
/*
* This is the source code of Telegram for Android v. 5.x.x.
* It is licensed under GNU GPL v. 2 or later.
* You should have received a copy of the license in this archive (see LICENSE).
*
* Copyright Nikolai Kudashov, 2013-2018.
*/
package org.telegram.ui.Cells;
import android.content.Context;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffColorFilter;
import android.util.TypedValue;
import android.view.Gravity;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.TextView;
import org.telegram.messenger.AndroidUtilities;
import org.telegram.messenger.LocaleController;
import org.telegram.messenger.R;
import org.telegram.ui.ActionBar.Theme;
import org.telegram.ui.Components.LayoutHelper;
public class PhotoAttachPermissionCell extends FrameLayout {
private ImageView imageView;
private ImageView imageView2;
private TextView textView;
private int itemSize;
public PhotoAttachPermissionCell(Context context) {
super(context);
imageView = new ImageView(context);
imageView.setScaleType(ImageView.ScaleType.CENTER);
imageView.setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_chat_attachPermissionImage), PorterDuff.Mode.MULTIPLY));
addView(imageView, LayoutHelper.createFrame(44, 44, Gravity.CENTER, 5, 0, 0, 27));
imageView2 = new ImageView(context);
imageView2.setScaleType(ImageView.ScaleType.CENTER);
imageView2.setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_chat_attachPermissionMark), PorterDuff.Mode.MULTIPLY));
addView(imageView2, LayoutHelper.createFrame(44, 44, Gravity.CENTER, 5, 0, 0, 27));
textView = new TextView(context);
textView.setTextColor(Theme.getColor(Theme.key_chat_attachPermissionText));
textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 12);
textView.setGravity(Gravity.CENTER);
addView(textView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER, 5, 13, 5, 0));
itemSize = AndroidUtilities.dp(80);
}
public void setItemSize(int size) {
itemSize = size;
}
public void setType(int type) {
if (type == 0) {
imageView.setImageResource(R.drawable.permissions_camera1);
imageView2.setImageResource(R.drawable.permissions_camera2);
textView.setText(LocaleController.getString("CameraPermissionText", R.string.CameraPermissionText));
imageView.setLayoutParams(LayoutHelper.createFrame(44, 44, Gravity.CENTER, 5, 0, 0, 27));
imageView2.setLayoutParams(LayoutHelper.createFrame(44, 44, Gravity.CENTER, 5, 0, 0, 27));
} else {
imageView.setImageResource(R.drawable.permissions_gallery1);
imageView2.setImageResource(R.drawable.permissions_gallery2);
textView.setText(LocaleController.getString("GalleryPermissionText", R.string.GalleryPermissionText));
imageView.setLayoutParams(LayoutHelper.createFrame(44, 44, Gravity.CENTER, 0, 0, 2, 27));
imageView2.setLayoutParams(LayoutHelper.createFrame(44, 44, Gravity.CENTER, 0, 0, 2, 27));
}
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(MeasureSpec.makeMeasureSpec(itemSize, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(itemSize + AndroidUtilities.dp(5), MeasureSpec.EXACTLY));
}
}

View file

@ -13,7 +13,10 @@ import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.RectF;
import android.os.Build;
import android.os.Bundle;
import android.os.SystemClock;
@ -33,16 +36,18 @@ import org.telegram.messenger.AndroidUtilities;
import org.telegram.messenger.LocaleController;
import org.telegram.messenger.MediaController;
import org.telegram.messenger.R;
import org.telegram.ui.ActionBar.Theme;
import org.telegram.ui.Components.BackupImageView;
import org.telegram.ui.Components.CheckBox;
import org.telegram.ui.Components.CheckBox2;
import org.telegram.ui.Components.LayoutHelper;
import org.telegram.ui.PhotoViewer;
public class PhotoAttachPhotoCell extends FrameLayout {
private BackupImageView imageView;
private FrameLayout container;
private FrameLayout checkFrame;
private CheckBox checkBox;
private CheckBox2 checkBox;
private TextView videoTextView;
private FrameLayout videoInfoContainer;
private AnimatorSet animatorSet;
@ -50,8 +55,13 @@ public class PhotoAttachPhotoCell extends FrameLayout {
private boolean pressed;
private static Rect rect = new Rect();
private PhotoAttachPhotoCellDelegate delegate;
private boolean isVertical;
private boolean itemSizeChanged;
private boolean needCheckShow;
private int itemSize;
private boolean isVertical;
private Paint backgroundPaint = new Paint();
private AnimatorSet animator;
public interface PhotoAttachPhotoCellDelegate {
void onCheckClick(PhotoAttachPhotoCell v);
@ -62,46 +72,85 @@ public class PhotoAttachPhotoCell extends FrameLayout {
public PhotoAttachPhotoCell(Context context) {
super(context);
imageView = new BackupImageView(context);
addView(imageView, LayoutHelper.createFrame(80, 80));
checkFrame = new FrameLayout(context);
addView(checkFrame, LayoutHelper.createFrame(42, 42, Gravity.LEFT | Gravity.TOP, 38, 0, 0, 0));
setWillNotDraw(false);
videoInfoContainer = new FrameLayout(context);
videoInfoContainer.setBackgroundResource(R.drawable.phototime);
videoInfoContainer.setPadding(AndroidUtilities.dp(3), 0, AndroidUtilities.dp(3), 0);
addView(videoInfoContainer, LayoutHelper.createFrame(80, 16, Gravity.BOTTOM | Gravity.LEFT));
container = new FrameLayout(context);
addView(container, LayoutHelper.createFrame(80, 80));
imageView = new BackupImageView(context);
container.addView(imageView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT));
videoInfoContainer = new FrameLayout(context) {
private RectF rect = new RectF();
@Override
protected void onDraw(Canvas canvas) {
rect.set(0, 0, getMeasuredWidth(), getMeasuredHeight());
canvas.drawRoundRect(rect, AndroidUtilities.dp(4), AndroidUtilities.dp(4), Theme.chat_timeBackgroundPaint);
}
};
videoInfoContainer.setWillNotDraw(false);
videoInfoContainer.setPadding(AndroidUtilities.dp(5), 0, AndroidUtilities.dp(5), 0);
container.addView(videoInfoContainer, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, 17, Gravity.BOTTOM | Gravity.LEFT, 4, 0, 0, 4));
ImageView imageView1 = new ImageView(context);
imageView1.setImageResource(R.drawable.ic_video);
imageView1.setImageResource(R.drawable.play_mini_video);
videoInfoContainer.addView(imageView1, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.LEFT | Gravity.CENTER_VERTICAL));
videoTextView = new TextView(context);
videoTextView.setTextColor(0xffffffff);
videoTextView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf"));
videoTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 12);
videoTextView.setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_NO);
videoInfoContainer.addView(videoTextView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.LEFT | Gravity.CENTER_VERTICAL, 18, -0.7f, 0, 0));
videoInfoContainer.addView(videoTextView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.LEFT | Gravity.CENTER_VERTICAL, 13, -0.7f, 0, 0));
checkBox = new CheckBox(context, R.drawable.checkbig);
checkBox.setSize(30);
checkBox.setCheckOffset(AndroidUtilities.dp(1));
checkBox.setDrawBackground(true);
checkBox.setColor(0xff3ccaef, 0xffffffff);
addView(checkBox, LayoutHelper.createFrame(30, 30, Gravity.LEFT | Gravity.TOP, 46, 4, 0, 0));
checkBox = new CheckBox2(context, 24);
checkBox.setDrawBackgroundAsArc(7);
checkBox.setColor(Theme.key_chat_attachCheckBoxBackground, Theme.key_chat_attachPhotoBackground, Theme.key_chat_attachCheckBoxCheck);
addView(checkBox, LayoutHelper.createFrame(26, 26, Gravity.LEFT | Gravity.TOP, 52, 4, 0, 0));
checkBox.setVisibility(VISIBLE);
setFocusable(true);
checkFrame = new FrameLayout(context);
addView(checkFrame, LayoutHelper.createFrame(42, 42, Gravity.LEFT | Gravity.TOP, 38, 0, 0, 0));
itemSize = AndroidUtilities.dp(80);
}
public void setIsVertical(boolean value) {
isVertical = value;
}
public void setItemSize(int size) {
itemSize = size;
LayoutParams layoutParams = (LayoutParams) container.getLayoutParams();
layoutParams.width = layoutParams.height = itemSize;
layoutParams = (LayoutParams) checkFrame.getLayoutParams();
layoutParams.gravity = Gravity.RIGHT | Gravity.TOP;
layoutParams.leftMargin = 0;
layoutParams = (LayoutParams) checkBox.getLayoutParams();
layoutParams.gravity = Gravity.RIGHT | Gravity.TOP;
layoutParams.leftMargin = 0;
layoutParams.rightMargin = layoutParams.topMargin = AndroidUtilities.dp(5);
checkBox.setDrawBackgroundAsArc(6);
itemSizeChanged = true;
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
if (isVertical) {
super.onMeasure(MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(80), MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(80 + (isLast ? 0 : 6)), MeasureSpec.EXACTLY));
if (itemSizeChanged) {
super.onMeasure(MeasureSpec.makeMeasureSpec(itemSize, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(itemSize + AndroidUtilities.dp(5), MeasureSpec.EXACTLY));
} else {
super.onMeasure(MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(80 + (isLast ? 0 : 6)), MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(80), MeasureSpec.EXACTLY));
if (isVertical) {
super.onMeasure(MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(80), MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(80 + (isLast ? 0 : 6)), MeasureSpec.EXACTLY));
} else {
super.onMeasure(MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(80 + (isLast ? 0 : 6)), MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(80), MeasureSpec.EXACTLY));
}
}
}
@ -113,7 +162,11 @@ public class PhotoAttachPhotoCell extends FrameLayout {
return imageView;
}
public CheckBox getCheckBox() {
public float getScale() {
return container.getScaleX();
}
public CheckBox2 getCheckBox() {
return checkBox;
}
@ -139,16 +192,16 @@ public class PhotoAttachPhotoCell extends FrameLayout {
videoInfoContainer.setVisibility(INVISIBLE);
}
if (photoEntry.thumbPath != null) {
imageView.setImage(photoEntry.thumbPath, null, getResources().getDrawable(R.drawable.nophotos));
imageView.setImage(photoEntry.thumbPath, null, Theme.chat_attachEmptyDrawable);
} else if (photoEntry.path != null) {
if (photoEntry.isVideo) {
imageView.setImage("vthumb://" + photoEntry.imageId + ":" + photoEntry.path, null, getResources().getDrawable(R.drawable.nophotos));
imageView.setImage("vthumb://" + photoEntry.imageId + ":" + photoEntry.path, null, Theme.chat_attachEmptyDrawable);
} else {
imageView.setOrientation(photoEntry.orientation, true);
imageView.setImage("thumb://" + photoEntry.imageId + ":" + photoEntry.path, null, getResources().getDrawable(R.drawable.nophotos));
imageView.setImage("thumb://" + photoEntry.imageId + ":" + photoEntry.path, null, Theme.chat_attachEmptyDrawable);
}
} else {
imageView.setImageResource(R.drawable.nophotos);
imageView.setImageDrawable(Theme.chat_attachEmptyDrawable);
}
boolean showing = needCheckShow && PhotoViewer.isShowingImage(photoEntry.path);
imageView.getImageReceiver().setVisible(!showing, true);
@ -157,8 +210,43 @@ public class PhotoAttachPhotoCell extends FrameLayout {
requestLayout();
}
public void setChecked(int num, boolean value, boolean animated) {
checkBox.setChecked(num, value, animated);
public void setChecked(int num, boolean checked, boolean animated) {
checkBox.setChecked(num, checked, animated);
if (itemSizeChanged) {
if (animator != null) {
animator.cancel();
animator = null;
}
if (animated) {
animator = new AnimatorSet();
animator.playTogether(
ObjectAnimator.ofFloat(container, View.SCALE_X, checked ? 0.787f : 1.0f),
ObjectAnimator.ofFloat(container, View.SCALE_Y, checked ? 0.787f : 1.0f));
animator.setDuration(200);
animator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
if (animator != null && animator.equals(animation)) {
animator = null;
if (!checked) {
setBackgroundColor(0);
}
}
}
@Override
public void onAnimationCancel(Animator animation) {
if (animator != null && animator.equals(animation)) {
animator = null;
}
}
});
animator.start();
} else {
container.setScaleX(checked ? 0.787f : 1.0f);
container.setScaleY(checked ? 0.787f : 1.0f);
}
}
}
public void setNum(int num) {
@ -193,8 +281,8 @@ public class PhotoAttachPhotoCell extends FrameLayout {
animatorSet.setInterpolator(new DecelerateInterpolator());
animatorSet.setDuration(180);
animatorSet.playTogether(
ObjectAnimator.ofFloat(videoInfoContainer, "alpha", show ? 1.0f : 0.0f),
ObjectAnimator.ofFloat(checkBox, "alpha", show ? 1.0f : 0.0f));
ObjectAnimator.ofFloat(videoInfoContainer, View.ALPHA, show ? 1.0f : 0.0f),
ObjectAnimator.ofFloat(checkBox, View.ALPHA, show ? 1.0f : 0.0f));
animatorSet.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
@ -206,6 +294,18 @@ public class PhotoAttachPhotoCell extends FrameLayout {
animatorSet.start();
}
@Override
public void clearAnimation() {
super.clearAnimation();
if (animator != null) {
animator.cancel();
animator = null;
container.setScaleX(checkBox.isChecked() ? 0.787f : 1.0f);
container.setScaleY(checkBox.isChecked() ? 0.787f : 1.0f);
}
}
@Override
public boolean onTouchEvent(MotionEvent event) {
boolean result = false;
@ -242,6 +342,14 @@ public class PhotoAttachPhotoCell extends FrameLayout {
return result;
}
@Override
protected void onDraw(Canvas canvas) {
if (checkBox.isChecked() || container.getScaleX() != 1.0f || !imageView.getImageReceiver().hasNotThumb() || imageView.getImageReceiver().getCurrentAlpha() != 1.0f || PhotoViewer.isShowingImage(photoEntry.path)) {
backgroundPaint.setColor(Theme.getColor(Theme.key_chat_attachPhotoBackground));
canvas.drawRect(0, 0, imageView.getMeasuredWidth(), imageView.getMeasuredHeight(), backgroundPaint);
}
}
@Override
public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
super.onInitializeAccessibilityNodeInfo(info);
@ -251,8 +359,9 @@ public class PhotoAttachPhotoCell extends FrameLayout {
} else {
info.setText(LocaleController.getString("AttachPhoto", R.string.AttachPhoto));
}
if (checkBox.isChecked())
if (checkBox.isChecked()) {
info.setSelected(true);
}
if (Build.VERSION.SDK_INT >= 21) {
info.addAction(new AccessibilityNodeInfo.AccessibilityAction(R.id.acc_action_open_photo, LocaleController.getString("Open", R.string.Open)));
}
@ -261,7 +370,7 @@ public class PhotoAttachPhotoCell extends FrameLayout {
@Override
public boolean performAccessibilityAction(int action, Bundle arguments) {
if (action == R.id.acc_action_open_photo) {
View parent = (View)getParent();
View parent = (View) getParent();
parent.dispatchTouchEvent(MotionEvent.obtain(SystemClock.uptimeMillis(), SystemClock.uptimeMillis(), MotionEvent.ACTION_DOWN, getLeft(), getTop() + getHeight() - 1, 0));
parent.dispatchTouchEvent(MotionEvent.obtain(SystemClock.uptimeMillis(), SystemClock.uptimeMillis(), MotionEvent.ACTION_UP, getLeft(), getTop() + getHeight() - 1, 0));
}

View file

@ -9,6 +9,8 @@
package org.telegram.ui.Cells;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.os.Build;
import android.text.TextUtils;
import android.util.TypedValue;
@ -21,7 +23,6 @@ import android.widget.TextView;
import org.telegram.messenger.AndroidUtilities;
import org.telegram.messenger.MediaController;
import org.telegram.messenger.R;
import org.telegram.ui.ActionBar.Theme;
import org.telegram.ui.Components.BackupImageView;
import org.telegram.ui.Components.LayoutHelper;
@ -36,6 +37,7 @@ public class PhotoPickerAlbumsCell extends FrameLayout {
private MediaController.AlbumEntry[] albumEntries;
private int albumsCount;
private PhotoPickerAlbumsCellDelegate delegate;
private Paint backgroundPaint = new Paint();
private class AlbumView extends FrameLayout {
@ -85,6 +87,14 @@ public class PhotoPickerAlbumsCell extends FrameLayout {
}
return super.onTouchEvent(event);
}
@Override
protected void onDraw(Canvas canvas) {
if (!imageView.getImageReceiver().hasNotThumb() || imageView.getImageReceiver().getCurrentAlpha() != 1.0f) {
backgroundPaint.setColor(Theme.getColor(Theme.key_chat_attachPhotoBackground));
canvas.drawRect(0, 0, imageView.getMeasuredWidth(), imageView.getMeasuredHeight(), backgroundPaint);
}
}
}
public PhotoPickerAlbumsCell(Context context) {
@ -96,12 +106,9 @@ public class PhotoPickerAlbumsCell extends FrameLayout {
addView(albumViews[a]);
albumViews[a].setVisibility(INVISIBLE);
albumViews[a].setTag(a);
albumViews[a].setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
if (delegate != null) {
delegate.didSelectAlbum(albumEntries[(Integer) v.getTag()]);
}
albumViews[a].setOnClickListener(v -> {
if (delegate != null) {
delegate.didSelectAlbum(albumEntries[(Integer) v.getTag()]);
}
});
}
@ -127,12 +134,12 @@ public class PhotoPickerAlbumsCell extends FrameLayout {
if (albumEntry.coverPhoto != null && albumEntry.coverPhoto.path != null) {
albumView.imageView.setOrientation(albumEntry.coverPhoto.orientation, true);
if (albumEntry.coverPhoto.isVideo) {
albumView.imageView.setImage("vthumb://" + albumEntry.coverPhoto.imageId + ":" + albumEntry.coverPhoto.path, null, getContext().getResources().getDrawable(R.drawable.nophotos));
albumView.imageView.setImage("vthumb://" + albumEntry.coverPhoto.imageId + ":" + albumEntry.coverPhoto.path, null, Theme.chat_attachEmptyDrawable);
} else {
albumView.imageView.setImage("thumb://" + albumEntry.coverPhoto.imageId + ":" + albumEntry.coverPhoto.path, null, getContext().getResources().getDrawable(R.drawable.nophotos));
albumView.imageView.setImage("thumb://" + albumEntry.coverPhoto.imageId + ":" + albumEntry.coverPhoto.path, null, Theme.chat_attachEmptyDrawable);
}
} else {
albumView.imageView.setImageResource(R.drawable.nophotos);
albumView.imageView.setImageDrawable(Theme.chat_attachEmptyDrawable);
}
albumView.nameTextView.setText(albumEntry.bucketName);
albumView.countTextView.setText(String.format("%d", albumEntry.photos.size()));

View file

@ -13,9 +13,12 @@ import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.drawable.Drawable;
import android.util.TypedValue;
import android.view.Gravity;
import android.view.View;
import android.view.animation.DecelerateInterpolator;
import android.widget.FrameLayout;
import android.widget.ImageView;
@ -24,17 +27,20 @@ import android.widget.TextView;
import org.telegram.messenger.AndroidUtilities;
import org.telegram.messenger.FileLoader;
import org.telegram.messenger.ImageLocation;
import org.telegram.messenger.LocaleController;
import org.telegram.messenger.MediaController;
import org.telegram.messenger.MessageObject;
import org.telegram.messenger.R;
import org.telegram.tgnet.TLRPC;
import org.telegram.ui.ActionBar.Theme;
import org.telegram.ui.Components.BackupImageView;
import org.telegram.ui.Components.CheckBox;
import org.telegram.ui.Components.LayoutHelper;
import org.telegram.ui.PhotoViewer;
public class PhotoPickerPhotoCell extends FrameLayout {
public BackupImageView photoImage;
public BackupImageView imageView;
public FrameLayout checkFrame;
public CheckBox checkBox;
public TextView videoTextView;
@ -43,14 +49,17 @@ public class PhotoPickerPhotoCell extends FrameLayout {
private AnimatorSet animatorSet;
public int itemWidth;
private boolean zoomOnSelect;
private Paint backgroundPaint = new Paint();
private MediaController.PhotoEntry photoEntry;
public PhotoPickerPhotoCell(Context context, boolean zoom) {
super(context);
setWillNotDraw(false);
zoomOnSelect = zoom;
photoImage = new BackupImageView(context);
addView(photoImage, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT));
imageView = new BackupImageView(context);
addView(imageView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT));
checkFrame = new FrameLayout(context);
addView(checkFrame, LayoutHelper.createFrame(42, 42, Gravity.RIGHT | Gravity.TOP));
@ -111,21 +120,45 @@ public class PhotoPickerPhotoCell extends FrameLayout {
checkBox.setNum(num);
}
public void setImage(MediaController.PhotoEntry entry) {
Drawable thumb = zoomOnSelect ? Theme.chat_attachEmptyDrawable : getResources().getDrawable(R.drawable.nophotos);
photoEntry = entry;
if (photoEntry.thumbPath != null) {
imageView.setImage(photoEntry.thumbPath, null, thumb);
} else if (photoEntry.path != null) {
imageView.setOrientation(photoEntry.orientation, true);
if (photoEntry.isVideo) {
videoInfoContainer.setVisibility(View.VISIBLE);
int minutes = photoEntry.duration / 60;
int seconds = photoEntry.duration - minutes * 60;
videoTextView.setText(String.format("%d:%02d", minutes, seconds));
setContentDescription(LocaleController.getString("AttachVideo", R.string.AttachVideo) + ", " + LocaleController.formatCallDuration(photoEntry.duration));
imageView.setImage("vthumb://" + photoEntry.imageId + ":" + photoEntry.path, null, thumb);
} else {
videoInfoContainer.setVisibility(View.INVISIBLE);
setContentDescription(LocaleController.getString("AttachPhoto", R.string.AttachPhoto));
imageView.setImage("thumb://" + photoEntry.imageId + ":" + photoEntry.path, null, thumb);
}
} else {
imageView.setImageDrawable(thumb);
}
}
public void setImage(MediaController.SearchImage searchImage) {
Drawable thumb = getResources().getDrawable(R.drawable.nophotos);
Drawable thumb = zoomOnSelect ? Theme.chat_attachEmptyDrawable : getResources().getDrawable(R.drawable.nophotos);
if (searchImage.thumbPhotoSize != null) {
photoImage.setImage(ImageLocation.getForPhoto(searchImage.thumbPhotoSize, searchImage.photo), null, thumb, searchImage);
imageView.setImage(ImageLocation.getForPhoto(searchImage.thumbPhotoSize, searchImage.photo), null, thumb, searchImage);
} else if (searchImage.photoSize != null) {
photoImage.setImage(ImageLocation.getForPhoto(searchImage.photoSize, searchImage.photo), "80_80", thumb, searchImage);
imageView.setImage(ImageLocation.getForPhoto(searchImage.photoSize, searchImage.photo), "80_80", thumb, searchImage);
} else if (searchImage.thumbPath != null) {
photoImage.setImage(searchImage.thumbPath, null, thumb);
imageView.setImage(searchImage.thumbPath, null, thumb);
} else if (searchImage.thumbUrl != null && searchImage.thumbUrl.length() > 0) {
photoImage.setImage(searchImage.thumbUrl, null, thumb);
imageView.setImage(searchImage.thumbUrl, null, thumb);
} else if (MessageObject.isDocumentHasThumb(searchImage.document)) {
TLRPC.PhotoSize photoSize = FileLoader.getClosestPhotoSizeWithSize(searchImage.document.thumbs, 320);
photoImage.setImage(ImageLocation.getForDocument(photoSize, searchImage.document), null, thumb, searchImage);
imageView.setImage(ImageLocation.getForDocument(photoSize, searchImage.document), null, thumb, searchImage);
} else {
photoImage.setImageDrawable(thumb);
imageView.setImageDrawable(thumb);
}
}
@ -137,12 +170,9 @@ public class PhotoPickerPhotoCell extends FrameLayout {
}
if (zoomOnSelect) {
if (animated) {
if (checked) {
setBackgroundColor(0xff0a0a0a);
}
animator = new AnimatorSet();
animator.playTogether(ObjectAnimator.ofFloat(photoImage, "scaleX", checked ? 0.85f : 1.0f),
ObjectAnimator.ofFloat(photoImage, "scaleY", checked ? 0.85f : 1.0f));
animator.playTogether(ObjectAnimator.ofFloat(imageView, View.SCALE_X, checked ? 0.85f : 1.0f),
ObjectAnimator.ofFloat(imageView, View.SCALE_Y, checked ? 0.85f : 1.0f));
animator.setDuration(200);
animator.addListener(new AnimatorListenerAdapter() {
@Override
@ -164,10 +194,20 @@ public class PhotoPickerPhotoCell extends FrameLayout {
});
animator.start();
} else {
setBackgroundColor(checked ? 0xff0A0A0A : 0);
photoImage.setScaleX(checked ? 0.85f : 1.0f);
photoImage.setScaleY(checked ? 0.85f : 1.0f);
imageView.setScaleX(checked ? 0.85f : 1.0f);
imageView.setScaleY(checked ? 0.85f : 1.0f);
}
}
}
@Override
protected void onDraw(Canvas canvas) {
if (!zoomOnSelect) {
return;
}
if (checkBox.isChecked() || imageView.getScaleX() != 1.0f || !imageView.getImageReceiver().hasNotThumb() || imageView.getImageReceiver().getCurrentAlpha() != 1.0f || photoEntry != null && PhotoViewer.isShowingImage(photoEntry.path)) {
backgroundPaint.setColor(Theme.getColor(Theme.key_chat_attachPhotoBackground));
canvas.drawRect(0, 0, imageView.getMeasuredWidth(), imageView.getMeasuredHeight(), backgroundPaint);
}
}
}

View file

@ -1,151 +0,0 @@
/*
* This is the source code of Telegram for Android v. 2.0.x.
* It is licensed under GNU GPL v. 2 or later.
* You should have received a copy of the license in this archive (see LICENSE).
*
* Copyright Nikolai Kudashov, 2013-2018.
*/
package org.telegram.ui.Cells;
import android.content.Context;
import android.os.Build;
import android.text.TextUtils;
import android.util.TypedValue;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import org.telegram.messenger.AndroidUtilities;
import org.telegram.messenger.LocaleController;
import org.telegram.messenger.R;
import org.telegram.ui.ActionBar.Theme;
import org.telegram.ui.Components.LayoutHelper;
public class PhotoPickerSearchCell extends LinearLayout {
public interface PhotoPickerSearchCellDelegate {
void didPressedSearchButton(int index);
}
private class SearchButton extends FrameLayout {
private TextView textView1;
private TextView textView2;
private ImageView imageView;
private View selector;
public SearchButton(Context context) {
super(context);
setBackgroundColor(0xff1a1a1a);
selector = new View(context);
selector.setBackgroundDrawable(Theme.getSelectorDrawable(false));
addView(selector, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT));
imageView = new ImageView(context);
imageView.setScaleType(ImageView.ScaleType.CENTER);
addView(imageView, LayoutHelper.createFrame(48, 48, Gravity.LEFT | Gravity.TOP));
textView1 = new TextView(context);
textView1.setGravity(Gravity.CENTER_VERTICAL);
textView1.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14);
textView1.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf"));
textView1.setTextColor(0xffffffff);
textView1.setSingleLine(true);
textView1.setEllipsize(TextUtils.TruncateAt.END);
addView(textView1, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.TOP | Gravity.LEFT, 51, 8, 4, 0));
textView2 = new TextView(context);
textView2.setGravity(Gravity.CENTER_VERTICAL);
textView2.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 10);
textView2.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf"));
textView2.setTextColor(0xff666666);
textView2.setSingleLine(true);
textView2.setEllipsize(TextUtils.TruncateAt.END);
addView(textView2, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.TOP | Gravity.LEFT, 51, 26, 4, 0));
}
@Override
public boolean onTouchEvent(MotionEvent event) {
if (Build.VERSION.SDK_INT >= 21) {
selector.drawableHotspotChanged(event.getX(), event.getY());
}
return super.onTouchEvent(event);
}
}
private PhotoPickerSearchCellDelegate delegate;
public PhotoPickerSearchCell(Context context, boolean allowGifs) {
super(context);
setOrientation(HORIZONTAL);
SearchButton searchButton = new SearchButton(context);
searchButton.textView1.setText(LocaleController.getString("SearchImages", R.string.SearchImages));
searchButton.textView2.setText(LocaleController.getString("SearchImagesInfo", R.string.SearchImagesInfo));
searchButton.imageView.setImageResource(R.drawable.search_web);
addView(searchButton);
LayoutParams layoutParams = (LayoutParams) searchButton.getLayoutParams();
layoutParams.weight = 0.5f;
layoutParams.topMargin = AndroidUtilities.dp(4);
layoutParams.height = AndroidUtilities.dp(48);
layoutParams.width = 0;
searchButton.setLayoutParams(layoutParams);
searchButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
if (delegate != null) {
delegate.didPressedSearchButton(0);
}
}
});
FrameLayout frameLayout = new FrameLayout(context);
frameLayout.setBackgroundColor(0);
addView(frameLayout);
layoutParams = (LayoutParams) frameLayout.getLayoutParams();
layoutParams.topMargin = AndroidUtilities.dp(4);
layoutParams.height = AndroidUtilities.dp(48);
layoutParams.width = AndroidUtilities.dp(4);
frameLayout.setLayoutParams(layoutParams);
searchButton = new SearchButton(context);
searchButton.textView1.setText(LocaleController.getString("SearchGifs", R.string.SearchGifs));
searchButton.textView2.setText("GIPHY");
searchButton.imageView.setImageResource(R.drawable.search_gif);
addView(searchButton);
layoutParams = (LayoutParams) searchButton.getLayoutParams();
layoutParams.weight = 0.5f;
layoutParams.topMargin = AndroidUtilities.dp(4);
layoutParams.height = AndroidUtilities.dp(48);
layoutParams.width = 0;
searchButton.setLayoutParams(layoutParams);
if (allowGifs) {
searchButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
if (delegate != null) {
delegate.didPressedSearchButton(1);
}
}
});
} else {
searchButton.setAlpha(0.5f);
}
}
public void setDelegate(PhotoPickerSearchCellDelegate delegate) {
this.delegate = delegate;
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(52), MeasureSpec.EXACTLY));
}
}

View file

@ -13,6 +13,7 @@ import android.content.Context;
import android.graphics.Canvas;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffColorFilter;
import android.text.TextUtils;
import android.text.TextWatcher;
import android.util.TypedValue;
import android.view.Gravity;
@ -143,6 +144,9 @@ public class PollEditTextCell extends FrameLayout {
deleteImageView.setTag(null);
}
textView.setText(text);
if (!TextUtils.isEmpty(text)) {
textView.setSelection(text.length());
}
textView.setHint(hint);
needDivider = divider;
setWillNotDraw(!divider);

View file

@ -65,8 +65,7 @@ public class ShareDialogCell extends FrameLayout {
nameTextView.setEllipsize(TextUtils.TruncateAt.END);
addView(nameTextView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.LEFT | Gravity.TOP, 6, 66, 6, 0));
checkBox = new CheckBox2(context);
checkBox.setSize(21);
checkBox = new CheckBox2(context, 21);
checkBox.setColor(Theme.key_dialogRoundCheckBox, Theme.key_dialogBackground, Theme.key_dialogRoundCheckBoxCheck);
checkBox.setDrawUnchecked(false);
checkBox.setDrawBackgroundAsArc(4);

View file

@ -66,10 +66,9 @@ public class SharedAudioCell extends FrameLayout implements DownloadController.F
TAG = DownloadController.getInstance(currentAccount).generateObserverTag();
setWillNotDraw(false);
checkBox = new CheckBox2(context);
checkBox = new CheckBox2(context, 21);
checkBox.setVisibility(INVISIBLE);
checkBox.setColor(null, Theme.key_windowBackgroundWhite, Theme.key_checkboxCheck);
checkBox.setSize(21);
checkBox.setDrawUnchecked(false);
checkBox.setDrawBackgroundAsArc(3);
addView(checkBox, LayoutHelper.createFrame(24, 24, (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.TOP, LocaleController.isRTL ? 0 : 38, 32, LocaleController.isRTL ? 39 : 0, 0));

View file

@ -124,10 +124,9 @@ public class SharedDocumentCell extends FrameLayout implements DownloadControlle
progressView.setProgressColor(Theme.getColor(Theme.key_sharedMedia_startStopLoadIcon));
addView(progressView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 2, (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.TOP, LocaleController.isRTL ? 0 : 72, 54, LocaleController.isRTL ? 72 : 0, 0));
checkBox = new CheckBox2(context);
checkBox = new CheckBox2(context, 21);
checkBox.setVisibility(INVISIBLE);
checkBox.setColor(null, Theme.key_windowBackgroundWhite, Theme.key_checkboxCheck);
checkBox.setSize(21);
checkBox.setDrawUnchecked(false);
checkBox.setDrawBackgroundAsArc(2);
addView(checkBox, LayoutHelper.createFrame(24, 24, (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.TOP, LocaleController.isRTL ? 0 : 33, 28, LocaleController.isRTL ? 33 : 0, 0));

View file

@ -157,10 +157,9 @@ public class SharedLinkCell extends FrameLayout {
linkImageView.setRoundRadius(AndroidUtilities.dp(4));
letterDrawable = new LetterDrawable();
checkBox = new CheckBox2(context);
checkBox = new CheckBox2(context, 21);
checkBox.setVisibility(INVISIBLE);
checkBox.setColor(null, Theme.key_windowBackgroundWhite, Theme.key_checkboxCheck);
checkBox.setSize(21);
checkBox.setDrawUnchecked(false);
checkBox.setDrawBackgroundAsArc(2);
addView(checkBox, LayoutHelper.createFrame(24, 24, (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.TOP, LocaleController.isRTL ? 0 : 44, 44, LocaleController.isRTL ? 44 : 0, 0));

View file

@ -115,10 +115,9 @@ public class SharedPhotoVideoCell extends FrameLayout {
selector.setBackgroundDrawable(Theme.getSelectorDrawable(false));
addView(selector, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT));
checkBox = new CheckBox2(context);
checkBox = new CheckBox2(context, 21);
checkBox.setVisibility(INVISIBLE);
checkBox.setColor(null, Theme.key_sharedMedia_photoPlaceholder, Theme.key_checkboxCheck);
checkBox.setSize(21);
checkBox.setDrawUnchecked(false);
checkBox.setDrawBackgroundAsArc(1);
addView(checkBox, LayoutHelper.createFrame(24, 24, Gravity.RIGHT | Gravity.TOP, 0, 1, 1, 0));
@ -144,8 +143,8 @@ public class SharedPhotoVideoCell extends FrameLayout {
if (animated) {
animator = new AnimatorSet();
animator.playTogether(
ObjectAnimator.ofFloat(container, "scaleX", checked ? 0.81f : 1.0f),
ObjectAnimator.ofFloat(container, "scaleY", checked ? 0.81f : 1.0f));
ObjectAnimator.ofFloat(container, View.SCALE_X, checked ? 0.81f : 1.0f),
ObjectAnimator.ofFloat(container, View.SCALE_Y, checked ? 0.81f : 1.0f));
animator.setDuration(200);
animator.addListener(new AnimatorListenerAdapter() {
@Override

View file

@ -28,6 +28,7 @@ import org.telegram.messenger.ImageLocation;
import org.telegram.messenger.LocaleController;
import org.telegram.messenger.MessageObject;
import org.telegram.messenger.R;
import org.telegram.tgnet.TLObject;
import org.telegram.tgnet.TLRPC;
import org.telegram.ui.ActionBar.Theme;
import org.telegram.ui.Components.BackupImageView;
@ -53,12 +54,13 @@ public class StickerSetCell extends FrameLayout {
textView = new TextView(context);
textView.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlackText));
textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16);
textView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf"));
textView.setLines(1);
textView.setMaxLines(1);
textView.setSingleLine(true);
textView.setEllipsize(TextUtils.TruncateAt.END);
textView.setGravity(LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT);
addView(textView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT, LocaleController.isRTL ? 40 : 71, 10, LocaleController.isRTL ? 71 : 40, 0));
addView(textView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT, LocaleController.isRTL ? 40 : 71, 9, LocaleController.isRTL ? 71 : 40, 0));
valueTextView = new TextView(context);
valueTextView.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteGrayText2));
@ -67,18 +69,18 @@ public class StickerSetCell extends FrameLayout {
valueTextView.setMaxLines(1);
valueTextView.setSingleLine(true);
valueTextView.setGravity(LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT);
addView(valueTextView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT, LocaleController.isRTL ? 40 : 71, 35, LocaleController.isRTL ? 71 : 40, 0));
addView(valueTextView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT, LocaleController.isRTL ? 40 : 71, 32, LocaleController.isRTL ? 71 : 40, 0));
imageView = new BackupImageView(context);
imageView.setAspectFit(true);
imageView.setLayerNum(1);
addView(imageView, LayoutHelper.createFrame(48, 48, (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.TOP, LocaleController.isRTL ? 0 : 12, 8, LocaleController.isRTL ? 12 : 0, 0));
addView(imageView, LayoutHelper.createFrame(40, 40, (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.TOP, LocaleController.isRTL ? 0 : 13, 9, LocaleController.isRTL ? 13 : 0, 0));
if (option == 2) {
progressView = new RadialProgressView(getContext());
progressView.setProgressColor(Theme.getColor(Theme.key_dialogProgressCircle));
progressView.setSize(AndroidUtilities.dp(30));
addView(progressView, LayoutHelper.createFrame(48, 48, (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.TOP, LocaleController.isRTL ? 0 : 12, 8, LocaleController.isRTL ? 12 : 0, 0));
addView(progressView, LayoutHelper.createFrame(48, 48, (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.TOP, LocaleController.isRTL ? 0 : 12, 5, LocaleController.isRTL ? 12 : 0, 0));
} else if (option != 0) {
optionsButton = new ImageView(context);
optionsButton.setFocusable(false);
@ -87,18 +89,18 @@ public class StickerSetCell extends FrameLayout {
if (option == 1) {
optionsButton.setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_stickers_menu), PorterDuff.Mode.MULTIPLY));
optionsButton.setImageResource(R.drawable.msg_actions);
addView(optionsButton, LayoutHelper.createFrame(40, 40, (LocaleController.isRTL ? Gravity.LEFT : Gravity.RIGHT) | Gravity.TOP));
addView(optionsButton, LayoutHelper.createFrame(40, 40, (LocaleController.isRTL ? Gravity.LEFT : Gravity.RIGHT) | Gravity.CENTER_VERTICAL));
} else if (option == 3) {
optionsButton.setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_featuredStickers_addedIcon), PorterDuff.Mode.MULTIPLY));
optionsButton.setImageResource(R.drawable.sticker_added);
addView(optionsButton, LayoutHelper.createFrame(40, 40, (LocaleController.isRTL ? Gravity.LEFT : Gravity.RIGHT) | Gravity.TOP, (LocaleController.isRTL ? 10 : 0), 12, (LocaleController.isRTL ? 0 : 10), 0));
addView(optionsButton, LayoutHelper.createFrame(40, 40, (LocaleController.isRTL ? Gravity.LEFT : Gravity.RIGHT) | Gravity.TOP, (LocaleController.isRTL ? 10 : 0), 9, (LocaleController.isRTL ? 0 : 10), 0));
}
}
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(64) + (needDivider ? 1 : 0), MeasureSpec.EXACTLY));
super.onMeasure(MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(58) + (needDivider ? 1 : 0), MeasureSpec.EXACTLY));
}
public void setText(String title, String subtitle, int icon, boolean divider) {
@ -145,15 +147,34 @@ public class StickerSetCell extends FrameLayout {
valueTextView.setAlpha(1.0f);
imageView.setAlpha(1.0f);
}
ArrayList<TLRPC.Document> documents = set.documents;
if (documents != null && !documents.isEmpty()) {
valueTextView.setText(LocaleController.formatPluralString("Stickers", documents.size()));
TLRPC.Document document = documents.get(0);
TLRPC.PhotoSize thumb = FileLoader.getClosestPhotoSizeWithSize(document.thumbs, 90);
if (MessageObject.canAutoplayAnimatedSticker(document)) {
imageView.setImage(ImageLocation.getForDocument(document), "80_80", ImageLocation.getForDocument(thumb, document), null, 0, set);
TLRPC.Document sticker = documents.get(0);
TLObject object;
if (set.set.thumb instanceof TLRPC.TL_photoSize) {
object = set.set.thumb;
} else {
imageView.setImage(ImageLocation.getForDocument(thumb, document), null, "webp", null, set);
object = sticker;
}
ImageLocation imageLocation;
if (object instanceof TLRPC.Document) {
TLRPC.PhotoSize thumb = FileLoader.getClosestPhotoSizeWithSize(sticker.thumbs, 90);
imageLocation = ImageLocation.getForDocument(thumb, sticker);
} else {
TLRPC.PhotoSize thumb = (TLRPC.PhotoSize) object;
imageLocation = ImageLocation.getForSticker(thumb, sticker);
}
if (object instanceof TLRPC.Document && MessageObject.isAnimatedStickerDocument(sticker)) {
imageView.setImage(ImageLocation.getForDocument(sticker), "50_50", imageLocation, null, 0, set);
} else if (imageLocation != null && imageLocation.lottieAnimation) {
imageView.setImage(imageLocation, "50_50", "tgs", null, set);
} else {
imageView.setImage(imageLocation, "50_50", "webp", null, set);
}
} else {
valueTextView.setText(LocaleController.formatPluralString("Stickers", 0));

View file

@ -168,17 +168,13 @@ public class UserCell extends FrameLayout {
addButton.setVisibility(value ? VISIBLE : GONE);
}
public void setIsAdmin(int value) {
public void setAdminRole(String role) {
if (adminTextView == null) {
return;
}
adminTextView.setVisibility(value != 0 ? VISIBLE : GONE);
if (value == 1) {
adminTextView.setText(LocaleController.getString("ChannelCreator", R.string.ChannelCreator));
} else if (value == 2) {
adminTextView.setText(LocaleController.getString("ChannelAdmin", R.string.ChannelAdmin));
}
if (value != 0) {
adminTextView.setVisibility(role != null ? VISIBLE : GONE);
adminTextView.setText(role);
if (role != null) {
CharSequence text = adminTextView.getText();
int size = (int) Math.ceil(adminTextView.getPaint().measureText(text, 0, text.length()));
nameTextView.setPadding(LocaleController.isRTL ? size + AndroidUtilities.dp(6) : 0, 0, !LocaleController.isRTL ? size + AndroidUtilities.dp(6) : 0, 0);
@ -447,6 +443,8 @@ public class UserCell extends FrameLayout {
avatarImageView.setImage(ImageLocation.getForUser(currentUser, false), "50_50", avatarDrawable, currentUser);
} else if (currentChat != null) {
avatarImageView.setImage(ImageLocation.getForChat(currentChat, false), "50_50", avatarDrawable, currentChat);
} else {
avatarImageView.setImageDrawable(avatarDrawable);
}
}

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