diff --git a/TMessagesProj/build.gradle b/TMessagesProj/build.gradle index b91cd10ec..63db5816b 100644 --- a/TMessagesProj/build.gradle +++ b/TMessagesProj/build.gradle @@ -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'] diff --git a/TMessagesProj/config/debug/AndroidManifest_SDK23.xml b/TMessagesProj/config/debug/AndroidManifest_SDK23.xml index d6c6fee36..b769db024 100644 --- a/TMessagesProj/config/debug/AndroidManifest_SDK23.xml +++ b/TMessagesProj/config/debug/AndroidManifest_SDK23.xml @@ -16,6 +16,7 @@ + diff --git a/TMessagesProj/config/release/AndroidManifest_SDK23.xml b/TMessagesProj/config/release/AndroidManifest_SDK23.xml index 6c16007f0..0d58e3d78 100644 --- a/TMessagesProj/config/release/AndroidManifest_SDK23.xml +++ b/TMessagesProj/config/release/AndroidManifest_SDK23.xml @@ -16,6 +16,7 @@ + diff --git a/TMessagesProj/jni/Android.mk b/TMessagesProj/jni/Android.mk index 441ef1287..d01178934 100755 --- a/TMessagesProj/jni/Android.mk +++ b/TMessagesProj/jni/Android.mk @@ -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 diff --git a/TMessagesProj/jni/TgNetWrapper.cpp b/TMessagesProj/jni/TgNetWrapper.cpp index 97aba7855..6e37cfa5c 100644 --- a/TMessagesProj/jni/TgNetWrapper.cpp +++ b/TMessagesProj/jni/TgNetWrapper.cpp @@ -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} }; diff --git a/TMessagesProj/jni/gifvideo.cpp b/TMessagesProj/jni/gifvideo.cpp index 376bdec09..863eef2a2 100644 --- a/TMessagesProj/jni/gifvideo.cpp +++ b/TMessagesProj/jni/gifvideo.cpp @@ -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)); diff --git a/TMessagesProj/jni/lottie.cpp b/TMessagesProj/jni/lottie.cpp index 08e97fa90..a0f70c86c 100644 --- a/TMessagesProj/jni/lottie.cpp +++ b/TMessagesProj/jni/lottie.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #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 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); } diff --git a/TMessagesProj/jni/rlottie/inc/rlottie.h b/TMessagesProj/jni/rlottie/inc/rlottie.h index adfa05d39..8a42bef0b 100755 --- a/TMessagesProj/jni/rlottie/inc/rlottie.h +++ b/TMessagesProj/jni/rlottie/inc/rlottie.h @@ -22,6 +22,7 @@ #include #include #include +#include #ifdef _WIN32 #ifdef LOT_BUILD @@ -257,7 +258,7 @@ public: * @internal */ static std::unique_ptr - loadFromFile(const std::string &path); + loadFromFile(const std::string &path, std::map &colorReplacement); /** * @brief Constructs an animation object from JSON string data. diff --git a/TMessagesProj/jni/rlottie/src/lottie/lottieanimation.cpp b/TMessagesProj/jni/rlottie/src/lottie/lottieanimation.cpp index f18ca4330..8f05dedef 100755 --- a/TMessagesProj/jni/rlottie/src/lottie/lottieanimation.cpp +++ b/TMessagesProj/jni/rlottie/src/lottie/lottieanimation.cpp @@ -136,7 +136,7 @@ std::unique_ptr Animation::loadFromData( return nullptr; } -std::unique_ptr Animation::loadFromFile(const std::string &path) +std::unique_ptr Animation::loadFromFile(const std::string &path, std::map &colorReplacement) { if (path.empty()) { vWarning << "File path is empty"; @@ -144,7 +144,7 @@ std::unique_ptr Animation::loadFromFile(const std::string &path) } LottieLoader loader; - if (loader.load(path)) { + if (loader.load(path, colorReplacement)) { auto animation = std::unique_ptr(new Animation); animation->d->init(loader.model()); return animation; diff --git a/TMessagesProj/jni/rlottie/src/lottie/lottieloader.cpp b/TMessagesProj/jni/rlottie/src/lottie/lottieloader.cpp index 50178bda5..dfd2cb0f4 100755 --- a/TMessagesProj/jni/rlottie/src/lottie/lottieloader.cpp +++ b/TMessagesProj/jni/rlottie/src/lottie/lottieloader.cpp @@ -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 &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(buf.str().data()), dirname(path).c_str()); + LottieParser parser(const_cast(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(jsonData.c_str()), - resourcePath.c_str()); + std::map colors; + LottieParser parser(const_cast(jsonData.c_str()), resourcePath.c_str(), colors); mModel = parser.model(); LottieFileCache::instance().add(key, mModel); diff --git a/TMessagesProj/jni/rlottie/src/lottie/lottieloader.h b/TMessagesProj/jni/rlottie/src/lottie/lottieloader.h index d7228bbce..49fba9c59 100755 --- a/TMessagesProj/jni/rlottie/src/lottie/lottieloader.h +++ b/TMessagesProj/jni/rlottie/src/lottie/lottieloader.h @@ -19,14 +19,15 @@ #ifndef LOTTIELOADER_H #define LOTTIELOADER_H -#include -#include +#include +#include +#include class LOTModel; class LottieLoader { public: - bool load(const std::string &filePath); + bool load(const std::string &filePath, std::map &colorReplacement); bool loadFromData(std::string &&jsonData, const std::string &key, const std::string &resourcePath); std::shared_ptr model(); private: diff --git a/TMessagesProj/jni/rlottie/src/lottie/lottiemodel.cpp b/TMessagesProj/jni/rlottie/src/lottie/lottiemodel.cpp index e51941cad..21c6906ec 100755 --- a/TMessagesProj/jni/rlottie/src/lottie/lottiemodel.cpp +++ b/TMessagesProj/jni/rlottie/src/lottie/lottiemodel.cpp @@ -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 diff --git a/TMessagesProj/jni/rlottie/src/lottie/lottieparser.cpp b/TMessagesProj/jni/rlottie/src/lottie/lottieparser.cpp index ad4d53fcc..564030934 100755 --- a/TMessagesProj/jni/rlottie/src/lottie/lottieparser.cpp +++ b/TMessagesProj/jni/rlottie/src/lottie/lottieparser.cpp @@ -55,6 +55,7 @@ #include #include +#include #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 &colorReplacement) + : LookaheadParserHandler(str), mDirPath(dir_path), colorMap(colorReplacement) { } @@ -286,6 +287,8 @@ protected: std::vector> mLayersToUpdate; std::string mDirPath; std::vector mLayerInfoList; + std::map 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::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 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 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::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 &colorReplacement) + : d(new LottieParserImpl(str, dir_path, colorReplacement)) { d->parseComposition(); if (d->hasParsingError()) { diff --git a/TMessagesProj/jni/rlottie/src/lottie/lottieparser.h b/TMessagesProj/jni/rlottie/src/lottie/lottieparser.h index 1c2bf9676..104a0c22e 100755 --- a/TMessagesProj/jni/rlottie/src/lottie/lottieparser.h +++ b/TMessagesProj/jni/rlottie/src/lottie/lottieparser.h @@ -20,12 +20,13 @@ #define LOTTIEPARSER_H #include "lottiemodel.h" +#include class LottieParserImpl; class LottieParser { public: ~LottieParser(); - LottieParser(char* str, const char *dir_path); + LottieParser(char* str, const char *dir_path, std::map &colorReplacement); std::shared_ptr model(); bool hasParsingError(); private: diff --git a/TMessagesProj/jni/rlottie/src/vector/vdasher.cpp b/TMessagesProj/jni/rlottie/src/vector/vdasher.cpp index a6ca9abce..6134fa053 100755 --- a/TMessagesProj/jni/rlottie/src/vector/vdasher.cpp +++ b/TMessagesProj/jni/rlottie/src/vector/vdasher.cpp @@ -209,6 +209,9 @@ VPath VDasher::dashed(const VPath &path) } } } + if (mResult.points().size() > SHRT_MAX) { + mResult.reset(); + } return std::move(mResult); } diff --git a/TMessagesProj/jni/rlottie/src/vector/vraster.cpp b/TMessagesProj/jni/rlottie/src/vector/vraster.cpp index 2c9989d07..3e7877966 100755 --- a/TMessagesProj/jni/rlottie/src/vector/vraster.cpp +++ b/TMessagesProj/jni/rlottie/src/vector/vraster.cpp @@ -19,6 +19,7 @@ #include "vraster.h" #include #include +#include #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 &elements = path.elements(); const std::vector & points = path.points(); + if (points.size() > SHRT_MAX) { + return; + } grow(points.size(), path.segments()); diff --git a/TMessagesProj/jni/tgnet/ApiScheme.cpp b/TMessagesProj/jni/tgnet/ApiScheme.cpp index 3269c64f7..a20409a14 100644 --- a/TMessagesProj/jni/tgnet/ApiScheme.cpp +++ b/TMessagesProj/jni/tgnet/ApiScheme.cpp @@ -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::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::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::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::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::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(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::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::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) { diff --git a/TMessagesProj/jni/tgnet/ApiScheme.h b/TMessagesProj/jni/tgnet/ApiScheme.h index 610f8647d..760729edd 100644 --- a/TMessagesProj/jni/tgnet/ApiScheme.h +++ b/TMessagesProj/jni/tgnet/ApiScheme.h @@ -315,8 +315,355 @@ 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 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 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 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 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 id; + std::string text; + std::vector> 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 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; - 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 { diff --git a/TMessagesProj/jni/tgnet/Connection.cpp b/TMessagesProj/jni/tgnet/Connection.cpp index c11b9ff27..457114f5b 100644 --- a/TMessagesProj/jni/tgnet/Connection.cpp +++ b/TMessagesProj/jni/tgnet/Connection.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #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); diff --git a/TMessagesProj/jni/tgnet/Connection.h b/TMessagesProj/jni/tgnet/Connection.h index dd984f2c1..c79af5c48 100644 --- a/TMessagesProj/jni/tgnet/Connection.h +++ b/TMessagesProj/jni/tgnet/Connection.h @@ -64,7 +64,8 @@ private: enum ProtocolType { ProtocolTypeEF, ProtocolTypeEE, - ProtocolTypeDD + ProtocolTypeDD, + ProtocolTypeTLS }; inline void encryptKeyWithSecret(uint8_t *array, uint8_t secretType); diff --git a/TMessagesProj/jni/tgnet/ConnectionSocket.cpp b/TMessagesProj/jni/tgnet/ConnectionSocket.cpp index 8929d21a0..bb9ccf4de 100644 --- a/TMessagesProj/jni/tgnet/ConnectionSocket.cpp +++ b/TMessagesProj/jni/tgnet/ConnectionSocket.cpp @@ -8,12 +8,15 @@ #include #include -#include +#include #include #include #include #include #include +#include +#include +#include #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((size >> 8) & 0xff); + data[length + 1] = static_cast(size & 0xff); + return length + size + 2; + } + + void setDomain(std::string value) { + domain = std::move(value); + } + +private: + std::vector ops; + uint8_t grease[MAX_GREASE]; + std::vector 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((size >> 8) & 0xff); + data[begin_offset + 1] = static_cast(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((remaining >> 8) & 0xff); + tempBuffer->bytes[headersSize + 1] = static_cast(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(); } diff --git a/TMessagesProj/jni/tgnet/ConnectionSocket.h b/TMessagesProj/jni/tgnet/ConnectionSocket.h index f53b14d29..a9c816ab1 100644 --- a/TMessagesProj/jni/tgnet/ConnectionSocket.h +++ b/TMessagesProj/jni/tgnet/ConnectionSocket.h @@ -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; diff --git a/TMessagesProj/jni/tgnet/ConnectionsManager.cpp b/TMessagesProj/jni/tgnet/ConnectionsManager.cpp index 14a4e24d3..999f2c275 100644 --- a/TMessagesProj/jni/tgnet/ConnectionsManager.cpp +++ b/TMessagesProj/jni/tgnet/ConnectionsManager.cpp @@ -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(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::vectorgetDatacenterId()) != 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::iterator iter = std::find(requestingSaltsForDc.begin(), requestingSaltsForDc.end(), datacenter->getDatacenterId()); + sendRequest(request, [&, datacenter, id](TLObject *response, TL_error *error, int32_t networkType) { + std::vector::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 ConnectionsManager::wrapInLayer(TLObject *object, Data return std::unique_ptr(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(64)); + for (unsigned char i = 0; i < 64; i++) { + url_char_to_value[static_cast(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(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(static_cast(c >> 16)); + if (left == 2) { + if ((c & ((1 << 16) - 1)) != 0) { + return ""; + } + } else { + output += static_cast(static_cast(c >> 8)); + if (left == 3) { + if ((c & ((1 << 8) - 1)) != 0) { + return ""; + } + } else { + output += static_cast(static_cast(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>::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::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; diff --git a/TMessagesProj/jni/tgnet/ConnectionsManager.h b/TMessagesProj/jni/tgnet/ConnectionsManager.h index 14bf61829..cc0e88cc7 100644 --- a/TMessagesProj/jni/tgnet/ConnectionsManager.h +++ b/TMessagesProj/jni/tgnet/ConnectionsManager.h @@ -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> &messages, Connection *connection, bool reportAck); void sendMessagesToConnectionWithConfirmation(std::vector> &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; diff --git a/TMessagesProj/jni/tgnet/Datacenter.cpp b/TMessagesProj/jni/tgnet/Datacenter.cpp index b2cb31388..e6b7c2d1f 100644 --- a/TMessagesProj/jni/tgnet/Datacenter.cpp +++ b/TMessagesProj/jni/tgnet/Datacenter.cpp @@ -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)); } diff --git a/TMessagesProj/jni/tgnet/Datacenter.h b/TMessagesProj/jni/tgnet/Datacenter.h index 403552a93..4dabc2fa1 100644 --- a/TMessagesProj/jni/tgnet/Datacenter.h +++ b/TMessagesProj/jni/tgnet/Datacenter.h @@ -122,7 +122,7 @@ private: std::vector> handshakes; - const uint32_t configVersion = 10; + const uint32_t configVersion = 11; const uint32_t paramsConfigVersion = 1; Connection *createProxyConnection(uint8_t num); diff --git a/TMessagesProj/jni/tgnet/Defines.h b/TMessagesProj/jni/tgnet/Defines.h index 24f2348ef..1786f19f8 100644 --- a/TMessagesProj/jni/tgnet/Defines.h +++ b/TMessagesProj/jni/tgnet/Defines.h @@ -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 diff --git a/TMessagesProj/jni/tgnet/MTProtoScheme.cpp b/TMessagesProj/jni/tgnet/MTProtoScheme.cpp index eb270c3ac..4eaf77f62 100644 --- a/TMessagesProj/jni/tgnet/MTProtoScheme.cpp +++ b/TMessagesProj/jni/tgnet/MTProtoScheme.cpp @@ -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; diff --git a/TMessagesProj/jni/tgnet/MTProtoScheme.h b/TMessagesProj/jni/tgnet/MTProtoScheme.h index 0b008349d..3c683fad4 100644 --- a/TMessagesProj/jni/tgnet/MTProtoScheme.h +++ b/TMessagesProj/jni/tgnet/MTProtoScheme.h @@ -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); }; diff --git a/TMessagesProj/src/main/AndroidManifest.xml b/TMessagesProj/src/main/AndroidManifest.xml index f36e36692..9c13dfb84 100644 --- a/TMessagesProj/src/main/AndroidManifest.xml +++ b/TMessagesProj/src/main/AndroidManifest.xml @@ -229,14 +229,6 @@ - - - - - - @@ -276,7 +268,6 @@ - diff --git a/TMessagesProj/src/main/assets/dark.attheme b/TMessagesProj/src/main/assets/dark.attheme index 1806baa21..423e376cc 100644 --- a/TMessagesProj/src/main/assets/dark.attheme +++ b/TMessagesProj/src/main/assets/dark.attheme @@ -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 diff --git a/TMessagesProj/src/main/assets/darkblue.attheme b/TMessagesProj/src/main/assets/darkblue.attheme index 50397595b..2b312e79a 100644 --- a/TMessagesProj/src/main/assets/darkblue.attheme +++ b/TMessagesProj/src/main/assets/darkblue.attheme @@ -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 diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/AndroidUtilities.java b/TMessagesProj/src/main/java/org/telegram/messenger/AndroidUtilities.java index 2df7d2f9f..efc566c07 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/AndroidUtilities.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/AndroidUtilities.java @@ -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) { diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/AnimatedFileDrawableStream.java b/TMessagesProj/src/main/java/org/telegram/messenger/AnimatedFileDrawableStream.java index 1274f11f3..c9e9b9288 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/AnimatedFileDrawableStream.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/AnimatedFileDrawableStream.java @@ -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; } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/ApplicationLoader.java b/TMessagesProj/src/main/java/org/telegram/messenger/ApplicationLoader.java index b1cd2b554..79ab62ac1 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/ApplicationLoader.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/ApplicationLoader.java @@ -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) { diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/BringAppForegroundService.java b/TMessagesProj/src/main/java/org/telegram/messenger/BringAppForegroundService.java index 18208dd3c..aebafc198 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/BringAppForegroundService.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/BringAppForegroundService.java @@ -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); } } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/BuildVars.java b/TMessagesProj/src/main/java/org/telegram/messenger/BuildVars.java index f0714294b..96aad0dce 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/BuildVars.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/BuildVars.java @@ -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"; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/ClearCacheService.java b/TMessagesProj/src/main/java/org/telegram/messenger/ClearCacheService.java deleted file mode 100644 index c81098c05..000000000 --- a/TMessagesProj/src/main/java/org/telegram/messenger/ClearCacheService.java +++ /dev/null @@ -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 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); - } - } - }); - } -} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/DownloadController.java b/TMessagesProj/src/main/java/org/telegram/messenger/DownloadController.java index d6d415f9a..f808575ea 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/DownloadController.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/DownloadController.java @@ -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())); diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/FileLoadOperation.java b/TMessagesProj/src/main/java/org/telegram/messenger/FileLoadOperation.java index 00f02af1c..17c978f03 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/FileLoadOperation.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/FileLoadOperation.java @@ -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); diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/FileLoader.java b/TMessagesProj/src/main/java/org/telegram/messenger/FileLoader.java index 8a8c16bba..11211c44b 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/FileLoader.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/FileLoader.java @@ -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; } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/FileRefController.java b/TMessagesProj/src/main/java/org/telegram/messenger/FileRefController.java index 50451fa6e..1d45994c4 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/FileRefController.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/FileRefController.java @@ -420,7 +420,7 @@ public class FileRefController extends BaseController { } if (done) { multiMediaCache.remove(multiMedia); - getSendMessagesHelper().performSendMessageRequestMulti(multiMedia, (ArrayList) objects[1], (ArrayList) objects[2], null, (SendMessagesHelper.DelayedMessage) objects[4]); + AndroidUtilities.runOnUIThread(() -> getSendMessagesHelper().performSendMessageRequestMulti(multiMedia, (ArrayList) objects[1], (ArrayList) 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) objects[1], (ArrayList) objects[2], null, (SendMessagesHelper.DelayedMessage) objects[4]); + AndroidUtilities.runOnUIThread(() -> getSendMessagesHelper().performSendMessageRequestMulti(req, (ArrayList) objects[1], (ArrayList) 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 diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/FileStreamLoadOperation.java b/TMessagesProj/src/main/java/org/telegram/messenger/FileStreamLoadOperation.java index 457a9b5d8..2a3413787 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/FileStreamLoadOperation.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/FileStreamLoadOperation.java @@ -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 diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/ImageLoader.java b/TMessagesProj/src/main/java/org/telegram/messenger/ImageLoader.java index 8b31a4634..4d658451b 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/ImageLoader.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/ImageLoader.java @@ -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); diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/ImageReceiver.java b/TMessagesProj/src/main/java/org/telegram/messenger/ImageReceiver.java index 9ab6f5c27..aff682500 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/ImageReceiver.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/ImageReceiver.java @@ -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) { diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/MediaController.java b/TMessagesProj/src/main/java/org/telegram/messenger/MediaController.java index 58b81bf9f..6f95ff7b9 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/MediaController.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/MediaController.java @@ -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 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 allMediaAlbums = new ArrayList<>(); + public static ArrayList 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 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; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/MediaDataController.java b/TMessagesProj/src/main/java/org/telegram/messenger/MediaDataController.java index 89c4d4c09..519b94992 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/MediaDataController.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/MediaDataController.java @@ -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[] stickerSets = new ArrayList[]{new ArrayList<>(), new ArrayList<>(), new ArrayList(0), new ArrayList()}; + private ArrayList[] stickerSets = new ArrayList[]{new ArrayList<>(), new ArrayList<>(), new ArrayList(0), new ArrayList(), new ArrayList()}; + private LongSparseArray[] stickersByIds = new LongSparseArray[]{new LongSparseArray<>(), new LongSparseArray<>(), new LongSparseArray(), new LongSparseArray(), new LongSparseArray()}; private LongSparseArray stickerSetsById = new LongSparseArray<>(); private LongSparseArray installedStickerSetsById = new LongSparseArray<>(); private LongSparseArray groupStickerSets = new LongSparseArray<>(); private HashMap 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 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 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 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 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 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 getStickerByIds(int type) { + return stickersByIds[type]; + } + public ArrayList 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 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++) { diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/MessageObject.java b/TMessagesProj/src/main/java/org/telegram/messenger/MessageObject.java index 3766942c2..94ca61872 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/MessageObject.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/MessageObject.java @@ -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 users, AbstractMap chats, boolean generateLayout) { @@ -753,22 +761,23 @@ public class MessageObject { } public MessageObject(int accountNum, TLRPC.Message message, SparseArray users, SparseArray 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 users, AbstractMap 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 users, AbstractMap chats, SparseArray sUsers, SparseArray sChats, boolean generateLayout, long eid) { + public MessageObject(int accountNum, TLRPC.Message message, MessageObject replyToMessage, AbstractMap users, AbstractMap chats, SparseArray sUsers, SparseArray 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 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() { diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/MessagesController.java b/TMessagesProj/src/main/java/org/telegram/messenger/MessagesController.java index e8965a9d6..73e824d45 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/MessagesController.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/MessagesController.java @@ -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> channelViewsToSend = new SparseArray<>(); private LongSparseArray> pollsToCheck = new LongSparseArray<>(); @@ -133,7 +135,7 @@ public class MessagesController extends BaseController implements NotificationCe private ArrayList loadingFullParticipants = new ArrayList<>(); private ArrayList loadedFullParticipants = new ArrayList<>(); private ArrayList loadedFullChats = new ArrayList<>(); - private SparseArray> channelAdmins = new SparseArray<>(); + private SparseArray> 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 array = channelAdmins.get(chatId); - return array != null && array.indexOf(uid) >= 0; + public String getAdminRank(int chatId, int uid) { + SparseArray 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 array = channelAdmins.get(chatId); + /*SparseArray array = channelAdmins.get(chatId); if (array != null) { - long acc = 0; + ArrayList 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 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 array, final int chatId, final boolean cache) { - Collections.sort(array); + public void processLoadedAdminsResponse(int chatId, TLRPC.TL_channels_channelParticipants participants) { + final SparseArray 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 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 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 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 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 dialogIds = getMessagesStorage().markMessagesAsDeleted(ids, false, channelId); + ArrayList 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 arrayList = deletedMessages.valueAt(a); getMessagesStorage().getStorageQueue().postRunnable(() -> { - ArrayList dialogIds = getMessagesStorage().markMessagesAsDeleted(arrayList, false, key); + ArrayList 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 dialogIds = getMessagesStorage().markMessagesAsDeleted(key, id, false); + ArrayList 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); } } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/MessagesStorage.java b/TMessagesProj/src/main/java/org/telegram/messenger/MessagesStorage.java index b47d06350..5fb23dc4e 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/MessagesStorage.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/MessagesStorage.java @@ -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 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 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 ids = new ArrayList<>(); + SQLiteCursor cursor = database.queryFinalized("SELECT uid, rank FROM channel_admins_v2 WHERE did = " + chatId); + SparseArray 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 ids) { + public void putChannelAdmins(final int chatId, final SparseArray 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 chatsToLoad = new ArrayList<>(); ArrayList broadcastIds = new ArrayList<>(); ArrayList 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 markMessagesAsDeletedInternal(final ArrayList messages, int channelId) { + private ArrayList markMessagesAsDeletedInternal(final ArrayList messages, int channelId, boolean deleteFiles) { try { String ids; final ArrayList 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 markMessagesAsDeleted(final ArrayList messages, boolean useQueue, final int channelId) { + public ArrayList markMessagesAsDeleted(final ArrayList 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 markMessagesAsDeletedInternal(final int channelId, final int mid) { + private ArrayList markMessagesAsDeletedInternal(final int channelId, final int mid, boolean deleteFiles) { try { String ids; ArrayList 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 markMessagesAsDeleted(final int channelId, final int mid, boolean useQueue) { + public ArrayList 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 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); diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/NotificationCenter.java b/TMessagesProj/src/main/java/org/telegram/messenger/NotificationCenter.java index 32c7d3f78..6069d75df 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/NotificationCenter.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/NotificationCenter.java @@ -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++; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/NotificationImageProvider.java b/TMessagesProj/src/main/java/org/telegram/messenger/NotificationImageProvider.java index 950e93895..477a5c2b6 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/NotificationImageProvider.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/NotificationImageProvider.java @@ -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 waitingForFiles=new HashSet<>(); - private final Object sync=new Object(); - private HashMap fileStartTimes=new HashMap<>(); + private HashSet waitingForFiles = new HashSet<>(); + private final Object sync = new Object(); + private HashMap fileStartTimes = new HashMap<>(); @Override - public boolean onCreate(){ - for(int i=0;i 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 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(); } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/SecretChatHelper.java b/TMessagesProj/src/main/java/org/telegram/messenger/SecretChatHelper.java index 43cd0216a..f3424d3ba 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/SecretChatHelper.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/SecretChatHelper.java @@ -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; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/SendMessagesHelper.java b/TMessagesProj/src/main/java/org/telegram/messenger/SendMessagesHelper.java index 9319616ab..eba81ed71 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/SendMessagesHelper.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/SendMessagesHelper.java @@ -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> delayedMessages = new HashMap<>(); private SparseArray unsentMessages = new SparseArray<>(); private SparseArray sendingMessages = new SparseArray<>(); + private SparseArray editingMessages = new SparseArray<>(); + private SparseArray uploadMessages = new SparseArray<>(); + private LongSparseArray sendingMessagesIdDialogs = new LongSparseArray<>(); + private LongSparseArray uploadingMessagesIdDialogs = new LongSparseArray<>(); private HashMap waitingForLocation = new HashMap<>(); private HashMap waitingForCallback = new HashMap<>(); private HashMap 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 objects) { ArrayList keysToRemove = new ArrayList<>(); + ArrayList checkReadyToSendGroups = new ArrayList<>(); ArrayList 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 msgObjs, final ArrayList originalPaths, final ArrayList parentObjects, DelayedMessage delayedMessage) { diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/SharedConfig.java b/TMessagesProj/src/main/java/org/telegram/messenger/SharedConfig.java index 261afc784..19badf614 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/SharedConfig.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/SharedConfig.java @@ -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 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(); diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/SmsReceiver.java b/TMessagesProj/src/main/java/org/telegram/messenger/SmsReceiver.java deleted file mode 100644 index f74a3e244..000000000 --- a/TMessagesProj/src/main/java/org/telegram/messenger/SmsReceiver.java +++ /dev/null @@ -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); - } - } -} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/UserConfig.java b/TMessagesProj/src/main/java/org/telegram/messenger/UserConfig.java index 14bf2a9ad..c6495d845 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/UserConfig.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/UserConfig.java @@ -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; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/Utilities.java b/TMessagesProj/src/main/java/org/telegram/messenger/Utilities.java index 344cde814..6da013ac4 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/Utilities.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/Utilities.java @@ -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()) { diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/VideoEditedInfo.java b/TMessagesProj/src/main/java/org/telegram/messenger/VideoEditedInfo.java index ccc9c2125..7e35486ac 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/VideoEditedInfo.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/VideoEditedInfo.java @@ -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; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/browser/Browser.java b/TMessagesProj/src/main/java/org/telegram/messenger/browser/Browser.java index e8acfe444..920ca0457 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/browser/Browser.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/browser/Browser.java @@ -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(); diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/camera/CameraController.java b/TMessagesProj/src/main/java/org/telegram/messenger/camera/CameraController.java index f48a31de8..aa06e7e9f 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/camera/CameraController.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/camera/CameraController.java @@ -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(() -> { diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/camera/CameraSession.java b/TMessagesProj/src/main/java/org/telegram/messenger/camera/CameraSession.java index a2d722daf..6f3df845c 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/camera/CameraSession.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/camera/CameraSession.java @@ -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() { diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/camera/CameraView.java b/TMessagesProj/src/main/java/org/telegram/messenger/camera/CameraView.java index bd3dd3816..8ea9e4233 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/camera/CameraView.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/camera/CameraView.java @@ -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 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); diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/support/JobIntentService.java b/TMessagesProj/src/main/java/org/telegram/messenger/support/JobIntentService.java index e25d61c75..bb78560a9 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/support/JobIntentService.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/support/JobIntentService.java @@ -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!"); diff --git a/TMessagesProj/src/main/java/org/telegram/tgnet/ConnectionsManager.java b/TMessagesProj/src/main/java/org/telegram/tgnet/ConnectionsManager.java index 7a049d112..093f43c36 100644 --- a/TMessagesProj/src/main/java/org/telegram/tgnet/ConnectionsManager.java +++ b/TMessagesProj/src/main/java/org/telegram/tgnet/ConnectionsManager.java @@ -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 { 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 { - - 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; - }); - } - } } diff --git a/TMessagesProj/src/main/java/org/telegram/tgnet/TLRPC.java b/TMessagesProj/src/main/java/org/telegram/tgnet/TLRPC.java index 8eeb45c51..e57096748 100644 --- a/TMessagesProj/src/main/java/org/telegram/tgnet/TLRPC.java +++ b/TMessagesProj/src/main/java/org/telegram/tgnet/TLRPC.java @@ -61,7 +61,7 @@ public class TLRPC { public static final int MESSAGE_FLAG_EDITED = 0x00008000; public static final int MESSAGE_FLAG_MEGAGROUP = 0x80000000; - public static final int LAYER = 103; + public static final int LAYER = 104; public static class TL_chatBannedRights extends TLObject { public static int constructor = 0x9f120418; @@ -675,34 +675,6 @@ public class TLRPC { } } - public static class TL_auth_checkedPhone extends TLObject { - public static int constructor = 0x811ea28e; - - public boolean phone_registered; - - public static TL_auth_checkedPhone TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { - if (TL_auth_checkedPhone.constructor != constructor) { - if (exception) { - throw new RuntimeException(String.format("can't parse magic %x in TL_auth_checkedPhone", constructor)); - } else { - return null; - } - } - TL_auth_checkedPhone result = new TL_auth_checkedPhone(); - result.readParams(stream, exception); - return result; - } - - public void readParams(AbstractSerializedData stream, boolean exception) { - phone_registered = stream.readBool(exception); - } - - public void serializeToStream(AbstractSerializedData stream) { - stream.writeInt32(constructor); - stream.writeBool(phone_registered); - } - } - public static abstract class UrlAuthResult extends TLObject { public static UrlAuthResult TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { @@ -1863,43 +1835,74 @@ public class TLRPC { } } - public static class TL_auth_authorization extends TLObject { - public static int constructor = 0xcd050916; + public static abstract class auth_Authorization extends TLObject { - public int flags; - public int tmp_sessions; - public User user; + public static auth_Authorization TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + auth_Authorization result = null; + switch (constructor) { + case 0x44747e9a: + result = new TL_auth_authorizationSignUpRequired(); + break; + case 0xcd050916: + result = new TL_auth_authorization(); + break; + } + if (result == null && exception) { + throw new RuntimeException(String.format("can't parse magic %x in auth_Authorization", constructor)); + } + if (result != null) { + result.readParams(stream, exception); + } + return result; + } + } - public static TL_auth_authorization TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { - if (TL_auth_authorization.constructor != constructor) { - if (exception) { - throw new RuntimeException(String.format("can't parse magic %x in TL_auth_authorization", constructor)); - } else { - return null; - } - } - TL_auth_authorization result = new TL_auth_authorization(); - result.readParams(stream, exception); - return result; - } + public static class TL_auth_authorizationSignUpRequired extends auth_Authorization { + public static int constructor = 0x44747e9a; - public void readParams(AbstractSerializedData stream, boolean exception) { - flags = stream.readInt32(exception); - if ((flags & 1) != 0) { - tmp_sessions = stream.readInt32(exception); - } - user = User.TLdeserialize(stream, stream.readInt32(exception), exception); - } + public int flags; + public TL_help_termsOfService terms_of_service; - public void serializeToStream(AbstractSerializedData stream) { - stream.writeInt32(constructor); - stream.writeInt32(flags); - if ((flags & 1) != 0) { - stream.writeInt32(tmp_sessions); - } - user.serializeToStream(stream); - } - } + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + if ((flags & 1) != 0) { + terms_of_service = TL_help_termsOfService.TLdeserialize(stream, stream.readInt32(exception), exception); + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(flags); + if ((flags & 1) != 0) { + terms_of_service.serializeToStream(stream); + } + } + } + + public static class TL_auth_authorization extends auth_Authorization { + public static int constructor = 0xcd050916; + + public int flags; + public int tmp_sessions; + public User user; + + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + if ((flags & 1) != 0) { + tmp_sessions = stream.readInt32(exception); + } + user = User.TLdeserialize(stream, stream.readInt32(exception), exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(flags); + if ((flags & 1) != 0) { + stream.writeInt32(tmp_sessions); + } + user.serializeToStream(stream); + } + } public static class TL_pollAnswer extends TLObject { public static int constructor = 0x6ca9c2e9; @@ -4043,7 +4046,7 @@ public class TLRPC { public static int constructor = 0x1da7158f; public int flags; - public boolean popup; + public boolean can_not_skip; public int id; public String version; public String text; @@ -4053,7 +4056,7 @@ public class TLRPC { public void readParams(AbstractSerializedData stream, boolean exception) { flags = stream.readInt32(exception); - popup = (flags & 1) != 0; + can_not_skip = (flags & 1) != 0; id = stream.readInt32(exception); version = stream.readString(exception); text = stream.readString(exception); @@ -4082,7 +4085,7 @@ public class TLRPC { public void serializeToStream(AbstractSerializedData stream) { stream.writeInt32(constructor); - flags = popup ? (flags | 1) : (flags &~ 1); + flags = can_not_skip ? (flags | 1) : (flags &~ 1); stream.writeInt32(flags); stream.writeInt32(id); stream.writeString(version); @@ -4879,57 +4882,57 @@ public class TLRPC { } } - public static abstract class payments_PaymentResult extends TLObject { - public Updates updates; - public String url; + public static abstract class payments_PaymentResult extends TLObject { - public static payments_PaymentResult TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { - payments_PaymentResult result = null; - switch (constructor) { - case 0x4e5f810d: - result = new TL_payments_paymentResult(); - break; - case 0x6b56b921: - result = new TL_payments_paymentVerficationNeeded(); - break; - } - if (result == null && exception) { - throw new RuntimeException(String.format("can't parse magic %x in payments_PaymentResult", constructor)); - } - if (result != null) { - result.readParams(stream, exception); - } - return result; - } - } + public static payments_PaymentResult TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + payments_PaymentResult result = null; + switch (constructor) { + case 0xd8411139: + result = new TL_payments_paymentVerificationNeeded(); + break; + case 0x4e5f810d: + result = new TL_payments_paymentResult(); + break; + } + if (result == null && exception) { + throw new RuntimeException(String.format("can't parse magic %x in payments_PaymentResult", constructor)); + } + if (result != null) { + result.readParams(stream, exception); + } + return result; + } + } - public static class TL_payments_paymentResult extends payments_PaymentResult { - public static int constructor = 0x4e5f810d; + public static class TL_payments_paymentVerificationNeeded extends payments_PaymentResult { + public static int constructor = 0xd8411139; + public String url; - public void readParams(AbstractSerializedData stream, boolean exception) { - updates = Updates.TLdeserialize(stream, stream.readInt32(exception), exception); - } + public void readParams(AbstractSerializedData stream, boolean exception) { + url = stream.readString(exception); + } - public void serializeToStream(AbstractSerializedData stream) { - stream.writeInt32(constructor); - updates.serializeToStream(stream); - } - } + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeString(url); + } + } - public static class TL_payments_paymentVerficationNeeded extends payments_PaymentResult { - public static int constructor = 0x6b56b921; + public static class TL_payments_paymentResult extends payments_PaymentResult { + public static int constructor = 0x4e5f810d; + public Updates updates; - public void readParams(AbstractSerializedData stream, boolean exception) { - url = stream.readString(exception); - } + public void readParams(AbstractSerializedData stream, boolean exception) { + updates = Updates.TLdeserialize(stream, stream.readInt32(exception), exception); + } - public void serializeToStream(AbstractSerializedData stream) { - stream.writeInt32(constructor); - stream.writeString(url); - } - } + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + updates.serializeToStream(stream); + } + } public static class TL_channels_adminLogResults extends TLObject { public static int constructor = 0xed8af74d; @@ -5924,63 +5927,53 @@ public class TLRPC { } } - public static class TL_auth_sentCode extends TLObject { - public static int constructor = 0x38faab5f; + public static class TL_auth_sentCode extends TLObject { + public static int constructor = 0x5e002502; - public int flags; - public boolean phone_registered; - public auth_SentCodeType type; - public String phone_code_hash; - public auth_CodeType next_type; - public int timeout; - public TL_help_termsOfService terms_of_service; + public int flags; + public auth_SentCodeType type; + public String phone_code_hash; + public auth_CodeType next_type; + public int timeout; - public static TL_auth_sentCode TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { - if (TL_auth_sentCode.constructor != constructor) { - if (exception) { - throw new RuntimeException(String.format("can't parse magic %x in TL_auth_sentCode", constructor)); - } else { - return null; - } - } - TL_auth_sentCode result = new TL_auth_sentCode(); - result.readParams(stream, exception); - return result; - } + public static TL_auth_sentCode TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + if (TL_auth_sentCode.constructor != constructor) { + if (exception) { + throw new RuntimeException(String.format("can't parse magic %x in TL_auth_sentCode", constructor)); + } else { + return null; + } + } + TL_auth_sentCode result = new TL_auth_sentCode(); + result.readParams(stream, exception); + return result; + } - public void readParams(AbstractSerializedData stream, boolean exception) { - flags = stream.readInt32(exception); - phone_registered = (flags & 1) != 0; - type = auth_SentCodeType.TLdeserialize(stream, stream.readInt32(exception), exception); - phone_code_hash = stream.readString(exception); - if ((flags & 2) != 0) { - next_type = auth_CodeType.TLdeserialize(stream, stream.readInt32(exception), exception); - } - if ((flags & 4) != 0) { - timeout = stream.readInt32(exception); - } - if ((flags & 8) != 0) { - terms_of_service = TL_help_termsOfService.TLdeserialize(stream, stream.readInt32(exception), exception); - } - } + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + type = auth_SentCodeType.TLdeserialize(stream, stream.readInt32(exception), exception); + phone_code_hash = stream.readString(exception); + if ((flags & 2) != 0) { + next_type = auth_CodeType.TLdeserialize(stream, stream.readInt32(exception), exception); + } + if ((flags & 4) != 0) { + timeout = stream.readInt32(exception); + } + } - public void serializeToStream(AbstractSerializedData stream) { - stream.writeInt32(constructor); - flags = phone_registered ? (flags | 1) : (flags &~ 1); - stream.writeInt32(flags); - type.serializeToStream(stream); - stream.writeString(phone_code_hash); - if ((flags & 2) != 0) { - next_type.serializeToStream(stream); - } - if ((flags & 4) != 0) { - stream.writeInt32(timeout); - } - if ((flags & 8) != 0) { - terms_of_service.serializeToStream(stream); - } - } - } + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(flags); + type.serializeToStream(stream); + stream.writeString(phone_code_hash); + if ((flags & 2) != 0) { + next_type.serializeToStream(stream); + } + if ((flags & 4) != 0) { + stream.writeInt32(timeout); + } + } + } public static abstract class BotInlineResult extends TLObject { @@ -7781,6 +7774,8 @@ public class TLRPC { public int call_msg_id; public int linked_chat_id; public ChannelLocation location; + public int slowmode_seconds; + public int slowmode_next_send_date; public int pts; public static ChatFull TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { @@ -7795,9 +7790,12 @@ public class TLRPC { case 0x2e02a614: result = new TL_chatFull_layer87(); break; - case 0x10916653: + case 0x2d895c74: result = new TL_channelFull(); break; + case 0x10916653: + result = new TL_channelFull_layer103(); + break; case 0x9882e516: result = new TL_channelFull_layer101(); break; @@ -7846,6 +7844,161 @@ public class TLRPC { } public static class TL_channelFull extends ChatFull { + public static int constructor = 0x2d895c74; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + can_view_participants = (flags & 8) != 0; + can_set_username = (flags & 64) != 0; + can_set_stickers = (flags & 128) != 0; + hidden_prehistory = (flags & 1024) != 0; + can_view_stats = (flags & 4096) != 0; + can_set_location = (flags & 65536) != 0; + id = stream.readInt32(exception); + about = stream.readString(exception); + if ((flags & 1) != 0) { + participants_count = stream.readInt32(exception); + } + if ((flags & 2) != 0) { + admins_count = stream.readInt32(exception); + } + if ((flags & 4) != 0) { + kicked_count = stream.readInt32(exception); + } + if ((flags & 4) != 0) { + banned_count = stream.readInt32(exception); + } + if ((flags & 8192) != 0) { + online_count = stream.readInt32(exception); + } + read_inbox_max_id = stream.readInt32(exception); + read_outbox_max_id = stream.readInt32(exception); + unread_count = stream.readInt32(exception); + chat_photo = Photo.TLdeserialize(stream, stream.readInt32(exception), exception); + notify_settings = PeerNotifySettings.TLdeserialize(stream, stream.readInt32(exception), exception); + exported_invite = ExportedChatInvite.TLdeserialize(stream, stream.readInt32(exception), exception); + int magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + int count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + BotInfo object = BotInfo.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + bot_info.add(object); + } + if ((flags & 16) != 0) { + migrated_from_chat_id = stream.readInt32(exception); + } + if ((flags & 16) != 0) { + migrated_from_max_id = stream.readInt32(exception); + } + if ((flags & 32) != 0) { + pinned_msg_id = stream.readInt32(exception); + } + if ((flags & 256) != 0) { + stickerset = StickerSet.TLdeserialize(stream, stream.readInt32(exception), exception); + } + if ((flags & 512) != 0) { + available_min_id = stream.readInt32(exception); + } + if ((flags & 2048) != 0) { + folder_id = stream.readInt32(exception); + } + if ((flags & 16384) != 0) { + linked_chat_id = stream.readInt32(exception); + } + if ((flags & 32768) != 0) { + location = ChannelLocation.TLdeserialize(stream, stream.readInt32(exception), exception); + } + if ((flags & 131072) != 0) { + slowmode_seconds = stream.readInt32(exception); + } + if ((flags & 262144) != 0) { + slowmode_next_send_date = stream.readInt32(exception); + } + pts = stream.readInt32(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + flags = can_view_participants ? (flags | 8) : (flags &~ 8); + flags = can_set_username ? (flags | 64) : (flags &~ 64); + flags = can_set_stickers ? (flags | 128) : (flags &~ 128); + flags = hidden_prehistory ? (flags | 1024) : (flags &~ 1024); + flags = can_view_stats ? (flags | 4096) : (flags &~ 4096); + flags = can_set_location ? (flags | 65536) : (flags &~ 65536); + stream.writeInt32(flags); + stream.writeInt32(id); + stream.writeString(about); + if ((flags & 1) != 0) { + stream.writeInt32(participants_count); + } + if ((flags & 2) != 0) { + stream.writeInt32(admins_count); + } + if ((flags & 4) != 0) { + stream.writeInt32(kicked_count); + } + if ((flags & 4) != 0) { + stream.writeInt32(banned_count); + } + if ((flags & 8192) != 0) { + stream.writeInt32(online_count); + } + stream.writeInt32(read_inbox_max_id); + stream.writeInt32(read_outbox_max_id); + stream.writeInt32(unread_count); + chat_photo.serializeToStream(stream); + notify_settings.serializeToStream(stream); + exported_invite.serializeToStream(stream); + stream.writeInt32(0x1cb5c415); + int count = bot_info.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + bot_info.get(a).serializeToStream(stream); + } + if ((flags & 16) != 0) { + stream.writeInt32(migrated_from_chat_id); + } + if ((flags & 16) != 0) { + stream.writeInt32(migrated_from_max_id); + } + if ((flags & 32) != 0) { + stream.writeInt32(pinned_msg_id); + } + if ((flags & 256) != 0) { + stickerset.serializeToStream(stream); + } + if ((flags & 512) != 0) { + stream.writeInt32(available_min_id); + } + if ((flags & 2048) != 0) { + stream.writeInt32(folder_id); + } + if ((flags & 16384) != 0) { + stream.writeInt32(linked_chat_id); + } + if ((flags & 32768) != 0) { + location.serializeToStream(stream); + } + if ((flags & 131072) != 0) { + stream.writeInt32(slowmode_seconds); + } + if ((flags & 262144) != 0) { + stream.writeInt32(slowmode_next_send_date); + } + stream.writeInt32(pts); + } + } + + public static class TL_channelFull_layer103 extends TL_channelFull { public static int constructor = 0x10916653; @@ -9413,13 +9566,12 @@ public class TLRPC { } public static class TL_codeSettings extends TLObject { - public static int constructor = 0x302f59f3; + public static int constructor = 0xdebebe83; public int flags; public boolean allow_flashcall; public boolean current_number; - public boolean app_hash_persistent; - public String app_hash; + public boolean allow_app_hash; public static TL_codeSettings TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { if (TL_codeSettings.constructor != constructor) { @@ -9438,21 +9590,15 @@ public class TLRPC { flags = stream.readInt32(exception); allow_flashcall = (flags & 1) != 0; current_number = (flags & 2) != 0; - app_hash_persistent = (flags & 4) != 0; - if ((flags & 8) != 0) { - app_hash = stream.readString(exception); - } + allow_app_hash = (flags & 16) != 0; } public void serializeToStream(AbstractSerializedData stream) { stream.writeInt32(constructor); flags = allow_flashcall ? (flags | 1) : (flags &~ 1); flags = current_number ? (flags | 2) : (flags &~ 2); - flags = app_hash_persistent ? (flags | 4) : (flags &~ 4); + flags = allow_app_hash ? (flags | 16) : (flags &~ 16); stream.writeInt32(flags); - if ((flags & 8) != 0) { - stream.writeString(app_hash); - } } } @@ -17883,72 +18029,85 @@ public class TLRPC { } } - public static abstract class InputStickerSet extends TLObject { - public long id; - public long access_hash; - public String short_name; + public static abstract class InputStickerSet extends TLObject { - public static InputStickerSet TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { - InputStickerSet result = null; - switch (constructor) { - case 0xffb62b95: - result = new TL_inputStickerSetEmpty(); - break; - case 0x9de7a269: - result = new TL_inputStickerSetID(); - break; - case 0x861cc8a0: - result = new TL_inputStickerSetShortName(); - break; - } - if (result == null && exception) { - throw new RuntimeException(String.format("can't parse magic %x in InputStickerSet", constructor)); - } - if (result != null) { - result.readParams(stream, exception); - } - return result; - } - } + public long id; + public long access_hash; + public String short_name; - public static class TL_inputStickerSetEmpty extends InputStickerSet { - public static int constructor = 0xffb62b95; + public static InputStickerSet TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + InputStickerSet result = null; + switch (constructor) { + case 0xffb62b95: + result = new TL_inputStickerSetEmpty(); + break; + case 0x9de7a269: + result = new TL_inputStickerSetID(); + break; + case 0x861cc8a0: + result = new TL_inputStickerSetShortName(); + break; + case 0x28703c8: + result = new TL_inputStickerSetAnimatedEmoji(); + break; + } + if (result == null && exception) { + throw new RuntimeException(String.format("can't parse magic %x in InputStickerSet", constructor)); + } + if (result != null) { + result.readParams(stream, exception); + } + return result; + } + } + + public static class TL_inputStickerSetEmpty extends InputStickerSet { + public static int constructor = 0xffb62b95; - public void serializeToStream(AbstractSerializedData stream) { - stream.writeInt32(constructor); - } - } + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } - public static class TL_inputStickerSetID extends InputStickerSet { - public static int constructor = 0x9de7a269; + public static class TL_inputStickerSetID extends InputStickerSet { + public static int constructor = 0x9de7a269; - public void readParams(AbstractSerializedData stream, boolean exception) { - id = stream.readInt64(exception); - access_hash = stream.readInt64(exception); - } + public void readParams(AbstractSerializedData stream, boolean exception) { + id = stream.readInt64(exception); + access_hash = stream.readInt64(exception); + } - public void serializeToStream(AbstractSerializedData stream) { - stream.writeInt32(constructor); - stream.writeInt64(id); - stream.writeInt64(access_hash); - } - } + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt64(id); + stream.writeInt64(access_hash); + } + } - public static class TL_inputStickerSetShortName extends InputStickerSet { - public static int constructor = 0x861cc8a0; + public static class TL_inputStickerSetShortName extends InputStickerSet { + public static int constructor = 0x861cc8a0; - public void readParams(AbstractSerializedData stream, boolean exception) { - short_name = stream.readString(exception); - } + public void readParams(AbstractSerializedData stream, boolean exception) { + short_name = stream.readString(exception); + } - public void serializeToStream(AbstractSerializedData stream) { - stream.writeInt32(constructor); - stream.writeString(short_name); - } - } + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeString(short_name); + } + } + + public static class TL_inputStickerSetAnimatedEmoji extends InputStickerSet { + public static int constructor = 0x28703c8; + + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } public static class TL_channelAdminLogEventsFilter extends TLObject { public static int constructor = 0xea107ae4; @@ -23790,6 +23949,7 @@ public class TLRPC { public TL_channelAdminRights_layer92 admin_rights_layer92; public TL_chatAdminRights admin_rights; public TL_chatBannedRights banned_rights; + public String rank; public static ChannelParticipant TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { ChannelParticipant result = null; @@ -23801,7 +23961,7 @@ public class TLRPC { result = new TL_channelParticipantBanned_layer92(); break; case 0xe3e2e1f9: - result = new TL_channelParticipantCreator(); + result = new TL_channelParticipantCreator_layer103(); break; case 0x15ebac1d: result = new TL_channelParticipant(); @@ -23812,6 +23972,12 @@ public class TLRPC { case 0xa3289a6d: result = new TL_channelParticipantSelf(); break; + case 0xccbebbaf: + result = new TL_channelParticipantAdmin(); + break; + case 0x808d15a4: + result = new TL_channelParticipantCreator(); + break; case 0x91057fef: result = new TL_channelParticipantModerator_layer67(); break; @@ -23822,7 +23988,7 @@ public class TLRPC { result = new TL_channelParticipantAdmin_layer92(); break; case 0x5daa6e23: - result = new TL_channelParticipantAdmin(); + result = new TL_channelParticipantAdmin_layer103(); break; } if (result == null && exception) { @@ -23859,7 +24025,7 @@ public class TLRPC { } } - public static class TL_channelParticipantCreator extends ChannelParticipant { + public static class TL_channelParticipantCreator_layer103 extends TL_channelParticipantCreator { public static int constructor = 0xe3e2e1f9; @@ -23925,6 +24091,66 @@ public class TLRPC { } } + public static class TL_channelParticipantAdmin extends ChannelParticipant { + public static int constructor = 0xccbebbaf; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + can_edit = (flags & 1) != 0; + self = (flags & 2) != 0; + user_id = stream.readInt32(exception); + if ((flags & 2) != 0) { + inviter_id = stream.readInt32(exception); + } + promoted_by = stream.readInt32(exception); + date = stream.readInt32(exception); + admin_rights = TL_chatAdminRights.TLdeserialize(stream, stream.readInt32(exception), exception); + if ((flags & 4) != 0) { + rank = stream.readString(exception); + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + flags = can_edit ? (flags | 1) : (flags &~ 1); + flags = self ? (flags | 2) : (flags &~ 2); + stream.writeInt32(flags); + stream.writeInt32(user_id); + if ((flags & 2) != 0) { + stream.writeInt32(inviter_id); + } + stream.writeInt32(promoted_by); + stream.writeInt32(date); + admin_rights.serializeToStream(stream); + if ((flags & 4) != 0) { + stream.writeString(rank); + } + } + } + + public static class TL_channelParticipantCreator extends ChannelParticipant { + public static int constructor = 0x808d15a4; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + user_id = stream.readInt32(exception); + if ((flags & 1) != 0) { + rank = stream.readString(exception); + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(flags); + stream.writeInt32(user_id); + if ((flags & 1) != 0) { + stream.writeString(rank); + } + } + } + public static class TL_channelParticipantModerator_layer67 extends TL_channelParticipantAdmin { public static int constructor = 0x91057fef; @@ -23988,7 +24214,7 @@ public class TLRPC { } } - public static class TL_channelParticipantAdmin extends ChannelParticipant { + public static class TL_channelParticipantAdmin_layer103 extends TL_channelParticipantAdmin { public static int constructor = 0x5daa6e23; @@ -25437,6 +25663,9 @@ public class TLRPC { break; case 0x8f079643: result = new TL_channelAdminLogEventActionStopPoll(); + break; + case 0x53909779: + result = new TL_channelAdminLogEventActionToggleSlowMode(); break; case 0x42e047bb: result = new TL_channelAdminLogEventActionDeleteMessage(); @@ -25679,6 +25908,24 @@ public class TLRPC { } } + public static class TL_channelAdminLogEventActionToggleSlowMode extends ChannelAdminLogEventAction { + public static int constructor = 0x53909779; + + public int prev_value; + public int new_value; + + public void readParams(AbstractSerializedData stream, boolean exception) { + prev_value = stream.readInt32(exception); + new_value = stream.readInt32(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(prev_value); + stream.writeInt32(new_value); + } + } + public static class TL_channelAdminLogEventActionDeleteMessage extends ChannelAdminLogEventAction { public static int constructor = 0x42e047bb; @@ -26023,6 +26270,7 @@ public class TLRPC { public boolean deactivated; public boolean left; public boolean has_geo; + public boolean slowmode_enabled; public ChatPhoto photo; public int participants_count; public int version; @@ -26545,6 +26793,7 @@ public class TLRPC { scam = (flags & 524288) != 0; has_link = (flags & 1048576) != 0; has_geo = (flags & 2097152) != 0; + slowmode_enabled = (flags & 4194304) != 0; id = stream.readInt32(exception); if ((flags & 8192) != 0) { access_hash = stream.readInt64(exception); @@ -26586,6 +26835,7 @@ public class TLRPC { flags = scam ? (flags | 524288) : (flags &~ 524288); flags = has_link ? (flags | 1048576) : (flags &~ 1048576); flags = has_geo ? (flags | 2097152) : (flags &~ 2097152); + flags = slowmode_enabled ? (flags | 4194304) : (flags &~ 4194304); stream.writeInt32(flags); stream.writeInt32(id); if ((flags & 8192) != 0) { @@ -30865,21 +31115,6 @@ public class TLRPC { } } - public static class TL_auth_checkPhone extends TLObject { - public static int constructor = 0x6fe51dfb; - - public String phone_number; - - public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { - return TL_auth_checkedPhone.TLdeserialize(stream, constructor, exception); - } - - public void serializeToStream(AbstractSerializedData stream) { - stream.writeInt32(constructor); - stream.writeString(phone_number); - } - } - public static class TL_auth_sendCode extends TLObject { public static int constructor = 0xa677244f; @@ -30901,28 +31136,26 @@ public class TLRPC { } } - public static class TL_auth_signUp extends TLObject { - public static int constructor = 0x1b067634; + public static class TL_auth_signUp extends TLObject { + public static int constructor = 0x80eee427; - public String phone_number; - public String phone_code_hash; - public String phone_code; - public String first_name; - public String last_name; + public String phone_number; + public String phone_code_hash; + public String first_name; + public String last_name; - public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { - return TL_auth_authorization.TLdeserialize(stream, constructor, exception); - } + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return auth_Authorization.TLdeserialize(stream, constructor, exception); + } public void serializeToStream(AbstractSerializedData stream) { - stream.writeInt32(constructor); - stream.writeString(phone_number); - stream.writeString(phone_code_hash); - stream.writeString(phone_code); - stream.writeString(first_name); - stream.writeString(last_name); - } - } + stream.writeInt32(constructor); + stream.writeString(phone_number); + stream.writeString(phone_code_hash); + stream.writeString(first_name); + stream.writeString(last_name); + } + } public static class TL_auth_signIn extends TLObject { public static int constructor = 0xbcd51581; @@ -30932,7 +31165,7 @@ public class TLRPC { public String phone_code; public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { - return TL_auth_authorization.TLdeserialize(stream, constructor, exception); + return auth_Authorization.TLdeserialize(stream, constructor, exception); } public void serializeToStream(AbstractSerializedData stream) { @@ -30991,7 +31224,7 @@ public class TLRPC { public byte[] bytes; public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { - return TL_auth_authorization.TLdeserialize(stream, constructor, exception); + return auth_Authorization.TLdeserialize(stream, constructor, exception); } public void serializeToStream(AbstractSerializedData stream) { @@ -32413,24 +32646,28 @@ public class TLRPC { } } - public static class TL_upload_getFile extends TLObject { - public static int constructor = 0xe3a6cfb5; + public static class TL_upload_getFile extends TLObject { + public static int constructor = 0xb15a9afc; - public InputFileLocation location; - public int offset; - public int limit; + public int flags; + public boolean precise; + public InputFileLocation location; + public int offset; + public int limit; - public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { - return TL_upload_file.TLdeserialize(stream, constructor, exception); + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return upload_File.TLdeserialize(stream, constructor, exception); } public void serializeToStream(AbstractSerializedData stream) { - stream.writeInt32(constructor); - location.serializeToStream(stream); - stream.writeInt32(offset); - stream.writeInt32(limit); + stream.writeInt32(constructor); + flags = precise ? (flags | 1) : (flags &~ 1); + stream.writeInt32(flags); + location.serializeToStream(stream); + stream.writeInt32(offset); + stream.writeInt32(limit); } - } + } public static class TL_help_getConfig extends TLObject { public static int constructor = 0xc4f9186b; @@ -33631,7 +33868,7 @@ public class TLRPC { public InputCheckPasswordSRP password; public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { - return TL_auth_authorization.TLdeserialize(stream, constructor, exception); + return auth_Authorization.TLdeserialize(stream, constructor, exception); } public void serializeToStream(AbstractSerializedData stream) { @@ -33659,7 +33896,7 @@ public class TLRPC { public String code; public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { - return TL_auth_authorization.TLdeserialize(stream, constructor, exception); + return auth_Authorization.TLdeserialize(stream, constructor, exception); } public void serializeToStream(AbstractSerializedData stream) { @@ -35395,11 +35632,12 @@ public class TLRPC { } public static class TL_channels_editAdmin extends TLObject { - public static int constructor = 0x70f893ba; + public static int constructor = 0xd33c8902; public InputChannel channel; public InputUser user_id; public TL_chatAdminRights admin_rights; + public String rank; public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { return Updates.TLdeserialize(stream, constructor, exception); @@ -35410,6 +35648,7 @@ public class TLRPC { channel.serializeToStream(stream); user_id.serializeToStream(stream); admin_rights.serializeToStream(stream); + stream.writeString(rank); } } @@ -35737,6 +35976,23 @@ public class TLRPC { } } + public static class TL_channels_toggleSlowMode extends TLObject { + public static int constructor = 0xedd49ef0; + + public InputChannel channel; + public int seconds; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return Updates.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + channel.serializeToStream(stream); + stream.writeInt32(seconds); + } + } + public static class TL_phone_getCallConfig extends TLObject { public static int constructor = 0x55451fa9; @@ -37107,24 +37363,28 @@ public class TLRPC { } if (stream.remaining() > 0) { attachPath = stream.readString(false); - if ((id < 0 || send_state == 3 || legacy) && attachPath.startsWith("||")) { - String args[] = attachPath.split("\\|\\|"); - if (args.length > 0) { - if (params == null) { - params = new HashMap<>(); - } - for (int a = 1; a < args.length - 1; a++) { - String args2[] = args[a].split("\\|=\\|"); - if (args2.length == 2) { - params.put(args2[0], args2[1]); - } - } - attachPath = args[args.length - 1].trim(); - if (legacy) { - layer = Utilities.parseInt(params.get("legacy_layer")); + if (attachPath != null) { + if ((id < 0 || send_state == 3 || legacy) && attachPath.startsWith("||")) { + String args[] = attachPath.split("\\|\\|"); + if (args.length > 0) { + if (params == null) { + params = new HashMap<>(); + } + for (int a = 1; a < args.length - 1; a++) { + String args2[] = args[a].split("\\|=\\|"); + if (args2.length == 2) { + params.put(args2[0], args2[1]); + } + } + attachPath = args[args.length - 1].trim(); + if (legacy) { + layer = Utilities.parseInt(params.get("legacy_layer")); + } } - } - } + } else { + attachPath = attachPath.trim(); + } + } } } if ((flags & MESSAGE_FLAG_FWD) != 0 && id < 0) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBar.java b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBar.java index ac2fcd69c..b61aa5df0 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBar.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBar.java @@ -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); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBarLayout.java b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBarLayout.java index 88bdef226..efbdcfe16 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBarLayout.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBarLayout.java @@ -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(); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBarMenu.java b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBarMenu.java index 249d80d97..d16fc10c5 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBarMenu.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBarMenu.java @@ -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++) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBarMenuItem.java b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBarMenuItem.java index a26df9a13..2436eb7bb 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBarMenuItem.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBarMenuItem.java @@ -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); } } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBarPopupWindow.java b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBarPopupWindow.java index 77f7c0ad7..7020e7101 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBarPopupWindow.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBarPopupWindow.java @@ -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 itemAnimators; private HashMap 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(); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/BottomSheet.java b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/BottomSheet.java index 27851da48..afbb8b5bb 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/BottomSheet.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/BottomSheet.java @@ -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(); } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/SimpleTextView.java b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/SimpleTextView.java index b97f37ca6..dc033081d 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/SimpleTextView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/SimpleTextView.java @@ -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(); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/Theme.java b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/Theme.java index 5ab242c2a..99387aaf2 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/Theme.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/Theme.java @@ -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 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(); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ThemeDescription.java b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ThemeDescription.java index c63b03eda..a7fab2401 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ThemeDescription.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ThemeDescription.java @@ -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(); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Adapters/StickersAdapter.java b/TMessagesProj/src/main/java/org/telegram/ui/Adapters/StickersAdapter.java index 0674cc995..81719ca8f 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Adapters/StickersAdapter.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Adapters/StickersAdapter.java @@ -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 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; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ArticleViewer.java b/TMessagesProj/src/main/java/org/telegram/ui/ArticleViewer.java index 5e9f50e41..351ea0e2a 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ArticleViewer.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ArticleViewer.java @@ -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; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/CacheControlActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/CacheControlActivity.java index c730dced3..167eb6f6d 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/CacheControlActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/CacheControlActivity.java @@ -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); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/CancelAccountDeletionActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/CancelAccountDeletionActivity.java index 03b6ac14e..5e4ff585c 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/CancelAccountDeletionActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/CancelAccountDeletionActivity.java @@ -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(); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ArchivedStickerSetCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ArchivedStickerSetCell.java index 60ecaad94..675938a5e 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ArchivedStickerSetCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ArchivedStickerSetCell.java @@ -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); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatMessageCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatMessageCell.java index 02133f1f1..c6851e361 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatMessageCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatMessageCell.java @@ -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); } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ContextLinkCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ContextLinkCell.java index 65edf0ba6..24eb5ec8b 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ContextLinkCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ContextLinkCell.java @@ -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); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/DialogCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/DialogCell.java index 820266177..4831f7c24 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/DialogCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/DialogCell.java @@ -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); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/FeaturedStickerSetCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/FeaturedStickerSetCell.java index 9761a50fc..759be724e 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/FeaturedStickerSetCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/FeaturedStickerSetCell.java @@ -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); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/GroupCreateUserCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/GroupCreateUserCell.java index e7b7c0e19..a9ea63f79 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/GroupCreateUserCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/GroupCreateUserCell.java @@ -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)); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/InviteUserCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/InviteUserCell.java index 8552e6e3a..8905fcbf6 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/InviteUserCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/InviteUserCell.java @@ -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)); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/PhotoAttachCameraCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/PhotoAttachCameraCell.java index 376637e5f..0dde050cf 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/PhotoAttachCameraCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/PhotoAttachCameraCell.java @@ -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); + } + } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/PhotoAttachPermissionCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/PhotoAttachPermissionCell.java new file mode 100644 index 000000000..3940e4025 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/PhotoAttachPermissionCell.java @@ -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)); + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/PhotoAttachPhotoCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/PhotoAttachPhotoCell.java index 646e7a30a..af7a7f156 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/PhotoAttachPhotoCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/PhotoAttachPhotoCell.java @@ -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)); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/PhotoPickerAlbumsCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/PhotoPickerAlbumsCell.java index 112069daf..bcc303967 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/PhotoPickerAlbumsCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/PhotoPickerAlbumsCell.java @@ -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())); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/PhotoPickerPhotoCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/PhotoPickerPhotoCell.java index 323beb45a..1a290353f 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/PhotoPickerPhotoCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/PhotoPickerPhotoCell.java @@ -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); + } + } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/PhotoPickerSearchCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/PhotoPickerSearchCell.java deleted file mode 100644 index 20e0d911b..000000000 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/PhotoPickerSearchCell.java +++ /dev/null @@ -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)); - } -} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/PollEditTextCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/PollEditTextCell.java index c82ce581d..716bd4647 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/PollEditTextCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/PollEditTextCell.java @@ -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); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ShareDialogCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ShareDialogCell.java index 59de24883..0186cfb7a 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ShareDialogCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ShareDialogCell.java @@ -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); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/SharedAudioCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/SharedAudioCell.java index c066b4300..d78dcc8ef 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/SharedAudioCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/SharedAudioCell.java @@ -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)); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/SharedDocumentCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/SharedDocumentCell.java index 939fb32be..0dab17742 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/SharedDocumentCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/SharedDocumentCell.java @@ -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)); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/SharedLinkCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/SharedLinkCell.java index db9a8f549..a7203281e 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/SharedLinkCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/SharedLinkCell.java @@ -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)); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/SharedPhotoVideoCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/SharedPhotoVideoCell.java index d38853d95..b6869eaad 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/SharedPhotoVideoCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/SharedPhotoVideoCell.java @@ -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 diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/StickerSetCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/StickerSetCell.java index b7d389e70..e6f3eb362 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/StickerSetCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/StickerSetCell.java @@ -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 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)); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/UserCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/UserCell.java index 7443ab592..018cedf75 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/UserCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/UserCell.java @@ -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); } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/UserCell2.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/UserCell2.java index e6a1a6ef6..0f5c76739 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/UserCell2.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/UserCell2.java @@ -283,6 +283,8 @@ public class UserCell2 extends FrameLayout { } } avatarImageView.setImage(ImageLocation.getForChat(currentChat, false), "50_50", avatarDrawable, currentObject); + } else { + avatarImageView.setImageDrawable(avatarDrawable); } if (imageView.getVisibility() == VISIBLE && currentDrawable == 0 || imageView.getVisibility() == GONE && currentDrawable != 0) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ChangePhoneActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ChangePhoneActivity.java index 6a5546750..cb414b8ba 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ChangePhoneActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ChangePhoneActivity.java @@ -14,9 +14,7 @@ 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; @@ -31,7 +29,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.InputFilter; @@ -53,7 +50,6 @@ import android.widget.TextView; import org.telegram.PhoneFormat.PhoneFormat; import org.telegram.messenger.AndroidUtilities; -import org.telegram.messenger.BuildVars; import org.telegram.messenger.LocaleController; import org.telegram.messenger.MessagesController; import org.telegram.messenger.MessagesStorage; @@ -61,7 +57,6 @@ import org.telegram.messenger.NotificationCenter; import org.telegram.messenger.ApplicationLoader; import org.telegram.messenger.FileLog; import org.telegram.messenger.R; -import org.telegram.messenger.SmsReceiver; import org.telegram.tgnet.ConnectionsManager; import org.telegram.tgnet.TLRPC; import org.telegram.messenger.UserConfig; @@ -218,7 +213,7 @@ public class ChangePhoneActivity extends BaseFragment { @Override protected void onDialogDismiss(Dialog dialog) { if (Build.VERSION.SDK_INT >= 23 && dialog == permissionsDialog && !permissionsItems.isEmpty()) { - getParentActivity().requestPermissions(permissionsItems.toArray(new String[permissionsItems.size()]), 6); + getParentActivity().requestPermissions(permissionsItems.toArray(new String[0]), 6); } } @@ -452,14 +447,14 @@ public class ChangePhoneActivity extends BaseFragment { country = codesMap.get(sub); if (country != null) { ok = true; - textToSet = text.substring(a, text.length()) + phoneField.getText().toString(); + textToSet = text.substring(a) + phoneField.getText().toString(); codeField.setText(text = sub); break; } } if (!ok) { ignoreOnTextChange = true; - textToSet = text.substring(1, text.length()) + phoneField.getText().toString(); + textToSet = text.substring(1) + phoneField.getText().toString(); codeField.setText(text = text.substring(0, 1)); } } @@ -552,7 +547,7 @@ public class ChangePhoneActivity extends BaseFragment { String phoneChars = "0123456789"; String str = phoneField.getText().toString(); if (characterAction == 3) { - str = str.substring(0, actionPosition) + str.substring(actionPosition + 1, str.length()); + str = str.substring(0, actionPosition) + str.substring(actionPosition + 1); start--; } StringBuilder builder = new StringBuilder(str.length()); @@ -735,7 +730,7 @@ public class ChangePhoneActivity extends BaseFragment { builder.setMessage(LocaleController.getString("AllowReadCall", R.string.AllowReadCall)); permissionsDialog = showDialog(builder.create()); } else { - getParentActivity().requestPermissions(permissionsItems.toArray(new String[permissionsItems.size()]), 6); + getParentActivity().requestPermissions(permissionsItems.toArray(new String[0]), 6); } return; } @@ -755,23 +750,7 @@ public class ChangePhoneActivity extends BaseFragment { req.phone_number = phone; req.settings = new TLRPC.TL_codeSettings(); req.settings.allow_flashcall = 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(); @@ -1658,6 +1637,6 @@ public class ChangePhoneActivity extends BaseFragment { arrayList.add(new ThemeDescription(smsView4.blackImageView, ThemeDescription.FLAG_IMAGECOLOR, null, null, null, null, Theme.key_windowBackgroundWhiteBlackText)); arrayList.add(new ThemeDescription(smsView4.blueImageView, ThemeDescription.FLAG_IMAGECOLOR, null, null, null, null, Theme.key_chats_actionBackground)); - return arrayList.toArray(new ThemeDescription[arrayList.size()]); + return arrayList.toArray(new ThemeDescription[0]); } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ChannelAdminLogActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ChannelAdminLogActivity.java index 3a66c4f84..9f32de5cb 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ChannelAdminLogActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ChannelAdminLogActivity.java @@ -2004,10 +2004,11 @@ public class ChannelAdminLogActivity extends BaseFragment implements Notificatio } @Override - public void didPressUrl(MessageObject messageObject, final CharacterStyle url, boolean longPress) { + public void didPressUrl(ChatMessageCell cell, final CharacterStyle url, boolean longPress) { if (url == null) { return; } + MessageObject messageObject = cell.getMessageObject(); if (url instanceof URLSpanMono) { ((URLSpanMono) url).copyToClipboard(); Toast.makeText(getParentActivity(), LocaleController.getString("TextCopied", R.string.TextCopied), Toast.LENGTH_SHORT).show(); @@ -2176,11 +2177,6 @@ public class ChannelAdminLogActivity extends BaseFragment implements Notificatio } } } - - @Override - public boolean isChatAdminCell(int uid) { - return false; - } }); chatMessageCell.setAllowAssistant(true); } else if (viewType == 1) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ChatActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ChatActivity.java index 6cc519578..96bd6da27 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ChatActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ChatActivity.java @@ -167,6 +167,7 @@ import org.telegram.ui.Components.LayoutHelper; import org.telegram.ui.Components.HintView; import org.telegram.ui.Components.NumberTextView; import org.telegram.ui.Components.PipRoundVideoView; +import org.telegram.ui.Components.RLottieDrawable; import org.telegram.ui.Components.RadialProgressView; import org.telegram.ui.Components.RecyclerListView; import org.telegram.ui.Components.ShareAlert; @@ -205,6 +206,8 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not private ArrayList chatMessageCellsCache = new ArrayList<>(); + private HashMap alredyPlayedStickers = new HashMap<>(); + private Dialog closeChatDialog; private FrameLayout progressView; private View progressView2; @@ -272,6 +275,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not private TextView emptyView; private TextView gifHintTextView; private TextView mediaBanTooltip; + private HintView slowModeHint; private TextView voiceHintTextView; private HintView noSoundHintView; private HintView forwardHintView; @@ -309,6 +313,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not private boolean searchingForUser; private TLRPC.User searchingUserMessages; private UndoView undoView; + private boolean openKeyboardOnAttachMenuClose; private ArrayList animatingMessageObjects = new ArrayList<>(); private MessageObject needAnimateToMessage; @@ -399,6 +404,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not private boolean hasUnfavedSelected; private int cantDeleteMessagesCount; private int cantForwardMessagesCount; + private int canForwardMessagesCount; private int canEditMessagesCount; private ArrayList waitingForLoad = new ArrayList<>(); @@ -428,6 +434,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not private boolean showScrollToMessageError; private int startLoadFromMessageId; + private int startLoadFromMessageIdSaved; private int startLoadFromMessageOffset = Integer.MAX_VALUE; private boolean needSelectFromMessageId; private int returnToMessageId; @@ -933,6 +940,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } if (startLoadFromMessageId != 0) { + startLoadFromMessageIdSaved = startLoadFromMessageId; waitingForLoad.add(lastLoadIndex); if (migrated_to != 0) { mergeDialogId = migrated_to; @@ -946,18 +954,17 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } if (currentChat != null) { - CountDownLatch countDownLatch = null; - if (isBroadcast) { - countDownLatch = new CountDownLatch(1); - } - getMessagesController().loadChatInfo(currentChat.id, countDownLatch, true); chatInfo = getMessagesController().getChatFull(currentChat.id); - if (isBroadcast && countDownLatch != null) { - try { - countDownLatch.await(); - } catch (Exception e) { - FileLog.e(e); - } + if (currentChat.megagroup && !getMessagesController().isChannelAdminsLoaded(currentChat.id)) { + getMessagesController().loadChannelAdmins(currentChat.id, true); + } + TLRPC.ChatFull info = getMessagesStorage().loadChatInfo(currentChat.id, isBroadcast ? new CountDownLatch(1) : null, true, false); + if (chatInfo == null) { + chatInfo = info; + } + if (chatInfo != null && ChatObject.isChannel(currentChat) && chatInfo.migrated_from_chat_id != 0) { + mergeDialogId = -chatInfo.migrated_from_chat_id; + maxMessageId[1] = chatInfo.migrated_from_max_id; } } else if (currentUser != null) { getMessagesController().loadUserInfo(currentUser, true, classGuid); @@ -1103,6 +1110,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not cantDeleteMessagesCount = 0; canEditMessagesCount = 0; cantForwardMessagesCount = 0; + canForwardMessagesCount = 0; videoPlayerContainer = null; hasOwnBackground = true; @@ -1500,7 +1508,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not stringBuilder = new SpannableStringBuilder(LocaleController.getString("Mono", R.string.Mono)); stringBuilder.setSpan(new TypefaceSpan(Typeface.MONOSPACE), 0, stringBuilder.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); editTextItem.addSubItem(text_mono, stringBuilder); - if (currentEncryptedChat != null && AndroidUtilities.getPeerLayerVersion(currentEncryptedChat.layer) >= 101) { + if (currentEncryptedChat == null || currentEncryptedChat != null && AndroidUtilities.getPeerLayerVersion(currentEncryptedChat.layer) >= 101) { stringBuilder = new SpannableStringBuilder(LocaleController.getString("Strike", R.string.Strike)); TextStyleSpan.TextStyleRun run = new TextStyleSpan.TextStyleRun(); run.flags |= TextStyleSpan.FLAG_STYLE_STRIKE; @@ -2199,6 +2207,9 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (forwardHintView != null) { forwardHintView.hide(); } + if (slowModeHint != null) { + slowModeHint.hide(); + } } forceScrollToTop = false; if (chatAdapter.isBot) { @@ -3066,7 +3077,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); builder.setTitle(LocaleController.getString("UnpinMessageAlertTitle", R.string.UnpinMessageAlertTitle)); builder.setMessage(LocaleController.getString("UnpinMessageAlert", R.string.UnpinMessageAlert)); - builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), (dialogInterface, i) -> getMessagesController().pinMessage(currentChat, currentUser, 0, false)); + builder.setPositiveButton(LocaleController.getString("UnpinMessage", R.string.UnpinMessage), (dialogInterface, i) -> getMessagesController().pinMessage(currentChat, currentUser, 0, false)); builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); showDialog(builder.create()); } else { @@ -3711,6 +3722,9 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } } else if (object instanceof String) { if (mentionsAdapter.isBotCommands()) { + if (checkSlowMode(view)) { + return; + } getSendMessagesHelper().sendMessage((String) object, dialog_id, replyingMessageObject, null, false, null, null, null); chatActivityEnterView.setFieldText(""); hideFieldPanel(false); @@ -3718,7 +3732,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not chatActivityEnterView.replaceWithText(start, len, object + " ", false); } } else if (object instanceof TLRPC.BotInlineResult) { - if (chatActivityEnterView.getFieldText() == null) { + if (chatActivityEnterView.getFieldText() == null || checkSlowMode(view)) { return; } TLRPC.BotInlineResult result = (TLRPC.BotInlineResult) object; @@ -3909,6 +3923,9 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } }; chatActivityEnterView.setDialogId(dialog_id, currentAccount); + if (chatInfo != null) { + chatActivityEnterView.setChatInfo(chatInfo); + } chatActivityEnterView.setId(id_chat_compose_panel); chatActivityEnterView.setBotsCount(botsCount, hasBotsCommands); chatActivityEnterView.setMinimumHeight(AndroidUtilities.dp(51)); @@ -3937,6 +3954,11 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not showVoiceHint(true, false); } + @Override + public void onUpdateSlowModeButton(View button, boolean show, CharSequence time) { + showSlowModeHint(button, show, time); + } + @Override public void onTextSelectionChanged(int start, int end) { if (editTextItem == null) { @@ -4130,6 +4152,14 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not public void onStickersExpandedChange() { checkRaiseSensors(); } + + @Override + public void scrollToSendingMessage() { + int id = getSendMessagesHelper().getSendingMessageId(dialog_id); + if (id != 0) { + scrollToMessageId(id, 0, true, 0, false); + } + } }); FrameLayout replyLayout = new FrameLayout(context) { @@ -4203,6 +4233,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not Bundle args = new Bundle(); args.putBoolean("onlySelect", true); args.putInt("dialogsType", 3); + args.putInt("messagesCount", forwardingMessages.size()); DialogsActivity fragment = new DialogsActivity(args); fragment.setDelegate(this); presentFragment(fragment); @@ -4612,6 +4643,13 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not undoView = new UndoView(context); contentView.addView(undoView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.BOTTOM | Gravity.LEFT, 8, 0, 8, 8)); + if (currentChat != null) { + slowModeHint = new HintView(getParentActivity(), 2); + slowModeHint.setAlpha(0.0f); + slowModeHint.setVisibility(View.INVISIBLE); + contentView.addView(slowModeHint, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.LEFT | Gravity.TOP, 19, 0, 19, 0)); + } + chatAdapter.updateRows(); if (loading && messages.isEmpty()) { progressView.setVisibility(chatAdapter.botInfoRow == -1 ? View.VISIBLE : View.INVISIBLE); @@ -4753,6 +4791,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not Bundle args = new Bundle(); args.putBoolean("onlySelect", true); args.putInt("dialogsType", 3); + args.putInt("messagesCount", canForwardMessagesCount); DialogsActivity fragment = new DialogsActivity(args); fragment.setDelegate(ChatActivity.this); presentFragment(fragment); @@ -4970,10 +5009,25 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not return; } if (chatAttachAlert == null) { - chatAttachAlert = new ChatAttachAlert(getParentActivity(), this); + chatAttachAlert = new ChatAttachAlert(getParentActivity(), this) { + @Override + public void dismissInternal() { + if (chatAttachAlert.isShowing()) { + AndroidUtilities.requestAdjustResize(getParentActivity(), classGuid); + if (chatActivityEnterView.getVisibility() == View.VISIBLE && fragmentView != null) { + fragmentView.requestLayout(); + } + } + super.dismissInternal(); + if (openKeyboardOnAttachMenuClose) { + AndroidUtilities.runOnUIThread(() -> chatActivityEnterView.openKeyboard(), 50); + openKeyboardOnAttachMenuClose = false; + } + } + }; chatAttachAlert.setDelegate(new ChatAttachAlert.ChatAttachViewDelegate() { @Override - public void didPressedButton(int button) { + public void didPressedButton(int button, boolean arg) { if (getParentActivity() == null || chatAttachAlert == null) { return; } @@ -5010,7 +5064,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not photoEntry.reset(); } fillEditingMediaWithCaption(photos.get(0).caption, photos.get(0).entities); - SendMessagesHelper.prepareSendingMedia(getAccountInstance(), photos, dialog_id, replyingMessageObject, null, button == 4, SharedConfig.groupPhotosEnabled, editingMessageObject); + SendMessagesHelper.prepareSendingMedia(getAccountInstance(), photos, dialog_id, replyingMessageObject, null, button == 4, arg, editingMessageObject); hideFieldPanel(false); getMediaDataController().cleanDraft(dialog_id, true); @@ -5042,8 +5096,13 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } @Override - public boolean allowGroupPhotos() { - return ChatActivity.this.allowGroupPhotos(); + public void needEnterComment() { + if (chatActivityEnterView.isKeyboardVisible()) { + chatActivityEnterView.showEmojiView(); + openKeyboardOnAttachMenuClose = true; + } + AndroidUtilities.setAdjustResizeToNothing(getParentActivity(), classGuid); + fragmentView.requestLayout(); } }); } @@ -5155,6 +5214,9 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not Object item = stickersAdapter.getItem(position); Object parent = stickersAdapter.getItemParent(position); if (item instanceof TLRPC.TL_document) { + if (checkSlowMode(view)) { + return; + } TLRPC.TL_document document = (TLRPC.TL_document) item; getSendMessagesHelper().sendSticker(document, dialog_id, replyingMessageObject, parent); hideFieldPanel(false); @@ -5222,7 +5284,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not @Override public void onAnimationCancel(Animator animation) { if (animation.equals(voiceHintAnimation)) { - voiceHintHideRunnable = null; + voiceHintAnimation = null; voiceHintHideRunnable = null; } } @@ -5303,6 +5365,25 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not voiceHintAnimation.start(); } + private boolean checkSlowMode(View view) { + CharSequence time = chatActivityEnterView.getSlowModeTimer(); + if (time != null) { + showSlowModeHint(view, true, time); + return true; + } + return false; + } + + private void showSlowModeHint(View view, boolean show, CharSequence time) { + if (getParentActivity() == null || fragmentView == null || !show && (slowModeHint == null || slowModeHint.getVisibility() != View.VISIBLE)) { + return; + } + slowModeHint.setText(AndroidUtilities.replaceTags(LocaleController.formatString("SlowModeHint", R.string.SlowModeHint, time))); + if (show) { + slowModeHint.showForView(view, true); + } + } + private void showMediaBannedHint() { if (getParentActivity() == null || currentChat == null || fragmentView == null || mediaBanTooltip != null && mediaBanTooltip.getVisibility() == View.VISIBLE) { return; @@ -5506,6 +5587,11 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (Build.VERSION.SDK_INT == 21 || Build.VERSION.SDK_INT == 22) { chatActivityEnterView.closeKeyboard(); } + if (currentChat != null && !ChatObject.hasAdminRights(currentChat) && currentChat.slowmode_enabled) { + chatAttachAlert.setMaxSelectedPhotos(10, true); + } else { + chatAttachAlert.setMaxSelectedPhotos(-1, true); + } chatAttachAlert.init(); showDialog(chatAttachAlert); } @@ -5773,13 +5859,13 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } else if (mergeDialogId != 0 && !endReached[1]) { loading = true; waitingForLoad.add(lastLoadIndex); - getMessagesController().loadMessages(mergeDialogId, 50, maxMessageId[1], 0, !cacheEndReached[1], minDate[1], classGuid, 0, 0, ChatObject.isChannel(currentChat), lastLoadIndex++); + getMessagesController().loadMessages(mergeDialogId, 50, maxMessageId[1], 0, !cacheEndReached[1], minDate[1], classGuid, 0, 0, false, lastLoadIndex++); } } if (visibleItemCount > 0 && !loadingForward && firstVisibleItem <= 10) { if (mergeDialogId != 0 && !forwardEndReached[1]) { waitingForLoad.add(lastLoadIndex); - getMessagesController().loadMessages(mergeDialogId, 50, minMessageId[1], 0, true, maxDate[1], classGuid, 1, 0, ChatObject.isChannel(currentChat), lastLoadIndex++); + getMessagesController().loadMessages(mergeDialogId, 50, minMessageId[1], 0, true, maxDate[1], classGuid, 1, 0, false, lastLoadIndex++); loadingForward = true; } else if (!forwardEndReached[0]) { waitingForLoad.add(lastLoadIndex); @@ -5828,7 +5914,11 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not allowGifs = currentEncryptedChat == null || AndroidUtilities.getPeerLayerVersion(currentEncryptedChat.layer) >= 46; } PhotoAlbumPickerActivity fragment = new PhotoAlbumPickerActivity(0, allowGifs, true, ChatActivity.this); - fragment.setMaxSelectedPhotos(editingMessageObject != null ? 1 : 0); + if (currentChat != null && !ChatObject.hasAdminRights(currentChat) && currentChat.slowmode_enabled) { + fragment.setMaxSelectedPhotos(10, true); + } else { + fragment.setMaxSelectedPhotos(editingMessageObject != null ? 1 : 0, editingMessageObject == null); + } fragment.setDelegate(new PhotoAlbumPickerActivity.PhotoAlbumPickerActivityDelegate() { @Override public void didSelectPhotos(ArrayList photos) { @@ -5836,7 +5926,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not return; } fillEditingMediaWithCaption(photos.get(0).caption, photos.get(0).entities); - SendMessagesHelper.prepareSendingMedia(getAccountInstance(), photos, dialog_id, replyingMessageObject, null, false, SharedConfig.groupPhotosEnabled, editingMessageObject); + SendMessagesHelper.prepareSendingMedia(getAccountInstance(), photos, dialog_id, replyingMessageObject, null, false, true, editingMessageObject); hideFieldPanel(false); getMediaDataController().cleanDraft(dialog_id, true); } @@ -5906,7 +5996,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not return; } DocumentSelectActivity fragment = new DocumentSelectActivity(true); - fragment.setMaxSelectedFiles(editingMessageObject != null ? 1 : -1); + fragment.setMaxSelectedFiles(currentChat != null && !ChatObject.hasAdminRights(currentChat) && currentChat.slowmode_enabled || editingMessageObject != null ? 1 : -1); fragment.setDelegate(new DocumentSelectActivity.DocumentSelectActivityDelegate() { @Override public void didSelectFiles(DocumentSelectActivity activity, ArrayList files) { @@ -6212,6 +6302,9 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (forwardHintView != null) { forwardHintView.hide(); } + if (slowModeHint != null) { + slowModeHint.hide(); + } if (searchItem != null && actionBar.isSearchFieldVisible()) { actionBar.closeSearchField(false); chatActivityEnterView.setFieldFocused(); @@ -6328,7 +6421,8 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not uids.add(-object.messageOwner.to_id.channel_id); } } - int type = messageObjectsToForward.get(0).type; + + int type = object.isAnimatedEmoji() ? 0 : object.type; for (int a = 1; a < messageObjectsToForward.size(); a++) { object = messageObjectsToForward.get(a); int uid; @@ -7304,7 +7398,9 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (mentionsAdapter != null) { mentionsAdapter.onRequestPermissionsResultFragment(requestCode, permissions, grantResults); } - if (requestCode == 17 && chatAttachAlert != null) { + if (requestCode == 4 && chatAttachAlert != null) { + chatAttachAlert.checkStorage(); + } else if ((requestCode == 17 || requestCode == 18) && chatAttachAlert != null) { chatAttachAlert.checkCamera(grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED); } else if (requestCode == 21) { if (getParentActivity() == null) { @@ -7382,7 +7478,9 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not return -1; } } else { - if (messageObject.type == 6) { + if (messageObject.isAnimatedEmoji()) { + return 2; + } else if (messageObject.type == 6) { return -1; } else if (messageObject.type == 10 || messageObject.type == 11) { if (messageObject.getId() == 0) { @@ -7445,7 +7543,9 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (messageObject.isSending()) { return -1; } - if (messageObject.type == 6) { + if (messageObject.isAnimatedEmoji()) { + return 2; + } else if (messageObject.type == 6) { return -1; } else if (messageObject.isSendError()) { if (!messageObject.isMediaEmpty()) { @@ -7462,7 +7562,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } else { if (messageObject.isVoice()) { return 2; - } else if (messageObject.isSticker() || messageObject.isAnimatedSticker()) { + } else if (!messageObject.isAnimatedEmoji() && (messageObject.isSticker() || messageObject.isAnimatedSticker())) { TLRPC.InputStickerSet inputStickerSet = messageObject.getInputStickerSet(); if (inputStickerSet instanceof TLRPC.TL_inputStickerSetShortName) { if (!getMediaDataController().isStickerPackInstalled(inputStickerSet.short_name)) { @@ -7540,10 +7640,10 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } if (selectedMessagesIds[index].indexOfKey(messageObject.getId()) >= 0) { selectedMessagesIds[index].remove(messageObject.getId()); - if (messageObject.type == 0 || messageObject.caption != null) { + if (messageObject.type == 0 || messageObject.isAnimatedEmoji() || messageObject.caption != null) { selectedMessagesCanCopyIds[index].remove(messageObject.getId()); } - if (messageObject.isSticker() || messageObject.isAnimatedSticker()) { + if (!messageObject.isAnimatedEmoji() && (messageObject.isSticker() || messageObject.isAnimatedSticker())) { selectedMessagesCanStarIds[index].remove(messageObject.getId()); } if (messageObject.canEditMessage(currentChat)) { @@ -7554,16 +7654,18 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } if (!messageObject.canForwardMessage()) { cantForwardMessagesCount--; + } else { + canForwardMessagesCount--; } } else { if (selectedMessagesIds[0].size() + selectedMessagesIds[1].size() >= 100) { return; } selectedMessagesIds[index].put(messageObject.getId(), messageObject); - if (messageObject.type == 0 || messageObject.caption != null) { + if (messageObject.type == 0 || messageObject.isAnimatedEmoji() || messageObject.caption != null) { selectedMessagesCanCopyIds[index].put(messageObject.getId(), messageObject); } - if (messageObject.isSticker() || messageObject.isAnimatedSticker()) { + if (!messageObject.isAnimatedEmoji() && (messageObject.isSticker() || messageObject.isAnimatedSticker())) { selectedMessagesCanStarIds[index].put(messageObject.getId(), messageObject); } if (messageObject.canEditMessage(currentChat)) { @@ -7574,6 +7676,8 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } if (!messageObject.canForwardMessage()) { cantForwardMessagesCount++; + } else { + canForwardMessagesCount++; } } } @@ -8127,6 +8231,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not int fnid = (Integer) args[4]; int last_unread_date = (Integer) args[7]; int load_type = (Integer) args[8]; + boolean isEnd = (Boolean) args[9]; int loaded_max_id = (Integer) args[12]; int loaded_mentions_count = (Integer) args[13]; if (loaded_mentions_count < 0) { @@ -8516,7 +8621,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } else { if (messArr.size() < count && load_type != 3 && load_type != 4) { if (isCache) { - if (currentEncryptedChat != null || isBroadcast) { + if (currentEncryptedChat != null || isBroadcast || loadIndex == 1 && mergeDialogId != 0 && isEnd) { endReached[loadIndex] = true; } if (load_type != 2) { @@ -8807,9 +8912,24 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not boolean notifiedSearch = false; for (int a = 0; a < arr.size(); a++) { MessageObject messageObject = arr.get(a); - if (!notifiedSearch && messageObject.isOut()) { - notifiedSearch = true; - NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.closeSearchByActiveAction); + if (messageObject.isOut()) { + if (!notifiedSearch) { + notifiedSearch = true; + NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.closeSearchByActiveAction); + } + if (currentChat != null && currentChat.slowmode_enabled && messageObject.isSent()) { + if (chatInfo != null) { + int date = messageObject.messageOwner.date + chatInfo.slowmode_seconds; + int currentTime = getConnectionsManager().getCurrentTime(); + if (date > getConnectionsManager().getCurrentTime()) { + chatInfo.slowmode_next_send_date = Math.max(chatInfo.slowmode_next_send_date, Math.min(currentTime + chatInfo.slowmode_seconds, date)); + if (chatActivityEnterView != null) { + chatActivityEnterView.setSlowModeTimer(chatInfo.slowmode_next_send_date); + } + } + } + getMessagesController().loadFullChat(currentChat.id, 0, true); + } } if (currentChat != null) { if (messageObject.messageOwner.action instanceof TLRPC.TL_messageActionChatDeleteUser && messageObject.messageOwner.action.user_id == currentUserId || @@ -10514,7 +10634,13 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not startLoadFromMessageId = 0; needSelectFromMessageId = false; waitingForLoad.add(lastLoadIndex); - getMessagesController().loadMessages(dialog_id, AndroidUtilities.isTablet() ? 30 : 20, 0, 0, true, 0, classGuid, 2, 0, ChatObject.isChannel(currentChat), lastLoadIndex++); + if (startLoadFromMessageIdSaved != 0) { + startLoadFromMessageId = startLoadFromMessageIdSaved; + startLoadFromMessageIdSaved = 0; + getMessagesController().loadMessages(dialog_id, AndroidUtilities.isTablet() ? 30 : 20, startLoadFromMessageId, 0, true, 0, classGuid, 3, 0, ChatObject.isChannel(currentChat), lastLoadIndex++); + } else { + getMessagesController().loadMessages(dialog_id, AndroidUtilities.isTablet() ? 30 : 20, 0, 0, true, 0, classGuid, 2, 0, ChatObject.isChannel(currentChat), lastLoadIndex++); + } } else { if (progressView != null) { progressView.setVisibility(View.INVISIBLE); @@ -10755,7 +10881,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not stringBuilder = new SpannableStringBuilder(LocaleController.getString("Mono", R.string.Mono)); stringBuilder.setSpan(new TypefaceSpan(Typeface.MONOSPACE), 0, stringBuilder.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); menu.add(R.id.menu_groupbolditalic, R.id.menu_mono, 8, stringBuilder); - if (currentEncryptedChat != null && AndroidUtilities.getPeerLayerVersion(currentEncryptedChat.layer) >= 101) { + if (currentEncryptedChat == null || currentEncryptedChat != null && AndroidUtilities.getPeerLayerVersion(currentEncryptedChat.layer) >= 101) { stringBuilder = new SpannableStringBuilder(LocaleController.getString("Strike", R.string.Strike)); TextStyleSpan.TextStyleRun run = new TextStyleSpan.TextStyleRun(); run.flags |= TextStyleSpan.FLAG_STYLE_STRIKE; @@ -11946,6 +12072,9 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (forwardHintView != null) { forwardHintView.hide(); } + if (slowModeHint != null) { + slowModeHint.hide(); + } MediaController.getInstance().resetGoingToShowMessageObject(); } } else if (PhotoViewer.hasInstance() && PhotoViewer.getInstance().isOpenedFullScreenVideo()) { @@ -12081,7 +12210,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not selectedObjectGroup = groupedMessages; if (type == -1) { - if (selectedObject.type == 0 || selectedObject.caption != null) { + if (selectedObject.type == 0 || selectedObject.isAnimatedEmoji() || selectedObject.caption != null) { items.add(LocaleController.getString("Copy", R.string.Copy)); options.add(3); icons.add(R.drawable.msg_copy); @@ -12167,7 +12296,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not options.add(8); icons.add(R.drawable.msg_reply); } - if (selectedObject.type == 0 || selectedObject.caption != null) { + if (selectedObject.type == 0 || selectedObject.isAnimatedEmoji() || selectedObject.caption != null) { items.add(LocaleController.getString("Copy", R.string.Copy)); options.add(3); icons.add(R.drawable.msg_copy); @@ -12346,7 +12475,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not options.add(8); icons.add(R.drawable.msg_reply); } - if (selectedObject.type == 0 || selectedObject.caption != null) { + if (selectedObject.type == 0 || selectedObject.isAnimatedEmoji() || selectedObject.caption != null) { items.add(LocaleController.getString("Copy", R.string.Copy)); options.add(3); icons.add(R.drawable.msg_copy); @@ -12577,6 +12706,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (scrimView instanceof ChatMessageCell) { ChatMessageCell cell = (ChatMessageCell) scrimView; cell.setInvalidatesParent(true); + restartSticker(cell); } contentView.invalidate(); chatListView.invalidate(); @@ -12601,6 +12731,9 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (noSoundHintView != null) { noSoundHintView.hide(); } + if (slowModeHint != null) { + slowModeHint.hide(); + } if (chatActivityEnterView != null) { chatActivityEnterView.getEditField().setAllowDrawCursor(false); } @@ -12711,6 +12844,31 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not })); } + private void restartSticker(ChatMessageCell cell) { + MessageObject message = cell.getMessageObject(); + TLRPC.Document document = message.getDocument(); + if (message.isAnimatedEmoji() || MessageObject.isAnimatedStickerDocument(document) && !SharedConfig.loopStickers) { + ImageReceiver imageReceiver = cell.getPhotoImage(); + RLottieDrawable drawable = imageReceiver.getLottieAnimation(); + if (drawable != null) { + drawable.restart(); + if (message.isAnimatedEmoji()) { + String emoji = message.getStickerEmoji(); + if ("❤".equals(emoji)) { + HashMap pattern = new HashMap<>(); + pattern.put(1, 1); + pattern.put(13, 0); + pattern.put(59, 1); + pattern.put(71, 0); + pattern.put(128, 1); + pattern.put(140, 0); + drawable.setVibrationPattern(pattern); + } + } + } + } + } + private String getMessageContent(MessageObject messageObject, int previousUid, boolean name) { String str = ""; if (name) { @@ -12728,7 +12886,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } } } - if (messageObject.type == 0 && messageObject.messageOwner.message != null) { + if ((messageObject.type == 0 || messageObject.isAnimatedEmoji()) && messageObject.messageOwner.message != null) { str += messageObject.messageOwner.message; } else if (messageObject.messageOwner.media != null && messageObject.messageOwner.message != null) { str += messageObject.messageOwner.message; @@ -12792,6 +12950,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not Bundle args = new Bundle(); args.putBoolean("onlySelect", true); args.putInt("dialogsType", 3); + args.putInt("messagesCount", forwardingMessageGroup == null ? 1 : forwardingMessageGroup.messages.size()); DialogsActivity fragment = new DialogsActivity(args); fragment.setDelegate(this); presentFragment(fragment); @@ -13026,7 +13185,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); builder.setTitle(LocaleController.getString("UnpinMessageAlertTitle", R.string.UnpinMessageAlertTitle)); builder.setMessage(LocaleController.getString("UnpinMessageAlert", R.string.UnpinMessageAlert)); - builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), (dialogInterface, i) -> getMessagesController().pinMessage(currentChat, currentUser, 0, false)); + builder.setPositiveButton(LocaleController.getString("UnpinMessage", R.string.UnpinMessage), (dialogInterface, i) -> getMessagesController().pinMessage(currentChat, currentUser, 0, false)); builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); showDialog(builder.create()); break; @@ -13743,10 +13902,11 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } private void updateMessageListAccessibilityVisibility() { - if (currentEncryptedChat != null) + if (currentEncryptedChat != null) { return; + } if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { - chatListView.setImportantForAccessibility(mentionContainer.getVisibility()==View.VISIBLE || (scrimPopupWindow!=null && scrimPopupWindow.isShowing()) ? View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS : View.IMPORTANT_FOR_ACCESSIBILITY_AUTO); + chatListView.setImportantForAccessibility(mentionContainer.getVisibility() == View.VISIBLE || (scrimPopupWindow != null && scrimPopupWindow.isShowing()) ? View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS : View.IMPORTANT_FOR_ACCESSIBILITY_AUTO); } } @@ -13975,10 +14135,11 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } @Override - public void didPressUrl(MessageObject messageObject, final CharacterStyle url, boolean longPress) { + public void didPressUrl(ChatMessageCell cell, final CharacterStyle url, boolean longPress) { if (url == null || getParentActivity() == null) { return; } + MessageObject messageObject = cell.getMessageObject(); if (url instanceof URLSpanMono) { ((URLSpanMono) url).copyToClipboard(); Toast.makeText(getParentActivity(), LocaleController.getString("TextCopied", R.string.TextCopied), Toast.LENGTH_SHORT).show(); @@ -14025,6 +14186,26 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not hideFieldPanel(false); } } + } else if (str.startsWith("video")) { + int seekTime = Utilities.parseInt(str); + TLRPC.WebPage webPage; + if (messageObject.isYouTubeVideo()) { + webPage = messageObject.messageOwner.media.webpage; + } else if (messageObject.replyMessageObject != null && messageObject.replyMessageObject.isYouTubeVideo()) { + webPage = messageObject.replyMessageObject.messageOwner.media.webpage; + } else { + webPage = null; + } + if (webPage != null) { + EmbedBottomSheet.show(mContext, webPage.site_name, webPage.title, webPage.url, webPage.embed_url, webPage.embed_width, webPage.embed_height, seekTime); + } else { + if (!messageObject.isVideo() && messageObject.replyMessageObject != null) { + messageObject = messagesDict[messageObject.replyMessageObject.getDialogId() == dialog_id ? 0 : 1].get(messageObject.replyMessageObject.getId()); + cell = null; + } + messageObject.forceSeekTo = seekTime / (float) messageObject.getDuration(); + openPhotoViewerForMessage(cell, messageObject); + } } } else { final String urlFinal = ((URLSpan) url).getURL(); @@ -14099,6 +14280,60 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } } + void openPhotoViewerForMessage(ChatMessageCell cell, MessageObject message) { + if (cell == null) { + int count = chatListView.getChildCount(); + for (int a = 0; a < count; a++) { + View child = chatListView.getChildAt(a); + if (child instanceof ChatMessageCell) { + ChatMessageCell messageCell = (ChatMessageCell) child; + if (messageCell.getMessageObject().equals(message)) { + cell = messageCell; + break; + } + } + } + } + if (message.isVideo()) { + sendSecretMessageRead(message); + } + PhotoViewer.getInstance().setParentActivity(getParentActivity()); + MessageObject playingObject = MediaController.getInstance().getPlayingMessageObject(); + if (cell != null && playingObject != null && playingObject.isVideo()) { + getFileLoader().setLoadingVideoForPlayer(playingObject.getDocument(), false); + if (playingObject.equals(message)) { + AnimatedFileDrawable animation = cell.getPhotoImage().getAnimation(); + if (animation != null && videoTextureView != null && videoPlayerContainer.getTag() != null) { + Bitmap bitmap = animation.getAnimatedBitmap(); + if (bitmap != null) { + try { + Bitmap src = videoTextureView.getBitmap(bitmap.getWidth(), bitmap.getHeight()); + Canvas canvas = new Canvas(bitmap); + canvas.drawBitmap(src, 0, 0, null); + src.recycle(); + } catch (Throwable e) { + FileLog.e(e); + } + } + } + } + MediaController.getInstance().cleanupPlayer(true, true, false, playingObject.equals(message)); + } + if (PhotoViewer.getInstance().openPhoto(message, message.type != 0 ? dialog_id : 0, message.type != 0 ? mergeDialogId : 0, photoViewerProvider)) { + PhotoViewer.getInstance().setParentChatActivity(ChatActivity.this); + } + if (noSoundHintView != null) { + noSoundHintView.hide(); + } + if (forwardHintView != null) { + forwardHintView.hide(); + } + if (slowModeHint != null) { + slowModeHint.hide(); + } + MediaController.getInstance().resetGoingToShowMessageObject(); + } + @Override public void didPressImage(ChatMessageCell cell, float x, float y) { MessageObject message = cell.getMessageObject(); @@ -14108,7 +14343,9 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } else if (message.isSending()) { return; } - if (message.needDrawBluredPreview()) { + if (message.isAnimatedEmoji()) { + restartSticker(cell); + } else if (message.needDrawBluredPreview()) { if (sendSecretMessageRead(message)) { cell.invalidate(); } @@ -14117,41 +14354,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } else if (message.type == MessageObject.TYPE_STICKER || message.type == MessageObject.TYPE_ANIMATED_STICKER) { showDialog(new StickersAlert(getParentActivity(), ChatActivity.this, message.getInputStickerSet(), null, bottomOverlayChat.getVisibility() != View.VISIBLE && (currentChat == null || ChatObject.canSendStickers(currentChat)) ? chatActivityEnterView : null)); } else if (message.isVideo() || message.type == 1 || message.type == 0 && !message.isWebpageDocument() || message.isGif()) { - if (message.isVideo()) { - sendSecretMessageRead(message); - } - PhotoViewer.getInstance().setParentActivity(getParentActivity()); - MessageObject playingObject = MediaController.getInstance().getPlayingMessageObject(); - if (playingObject != null && playingObject.isVideo()) { - getFileLoader().setLoadingVideoForPlayer(playingObject.getDocument(), false); - if (playingObject.equals(message)) { - AnimatedFileDrawable animation = cell.getPhotoImage().getAnimation(); - if (animation != null && videoTextureView != null && videoPlayerContainer.getTag() != null) { - Bitmap bitmap = animation.getAnimatedBitmap(); - if (bitmap != null) { - try { - Bitmap src = videoTextureView.getBitmap(bitmap.getWidth(), bitmap.getHeight()); - Canvas canvas = new Canvas(bitmap); - canvas.drawBitmap(src, 0, 0, null); - src.recycle(); - } catch (Throwable e) { - FileLog.e(e); - } - } - } - } - MediaController.getInstance().cleanupPlayer(true, true, false, playingObject.equals(message)); - } - if (PhotoViewer.getInstance().openPhoto(message, message.type != 0 ? dialog_id : 0, message.type != 0 ? mergeDialogId : 0, photoViewerProvider)) { - PhotoViewer.getInstance().setParentChatActivity(ChatActivity.this); - } - if (noSoundHintView != null) { - noSoundHintView.hide(); - } - if (forwardHintView != null) { - forwardHintView.hide(); - } - MediaController.getInstance().resetGoingToShowMessageObject(); + openPhotoViewerForMessage(cell, message); } else if (message.type == 3) { sendSecretMessageRead(message); try { @@ -14261,11 +14464,21 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } @Override - public boolean isChatAdminCell(int uid) { + public String getAdminRank(int uid) { if (ChatObject.isChannel(currentChat) && currentChat.megagroup) { - return getMessagesController().isChannelAdmin(currentChat.id, uid); + return getMessagesController().getAdminRank(currentChat.id, uid); } - return false; + return null; + } + + @Override + public boolean shouldRepeatSticker(MessageObject message) { + return !alredyPlayedStickers.containsKey(message); + } + + @Override + public void setShouldNotRepeatSticker(MessageObject message) { + alredyPlayedStickers.put(message, true); } }); if (currentEncryptedChat == null) { @@ -14280,7 +14493,8 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not PhotoViewer.getInstance().setParentActivity(getParentActivity()); TLRPC.PhotoSize photoSize = FileLoader.getClosestPhotoSizeWithSize(message.photoThumbs, 640); if (photoSize != null) { - PhotoViewer.getInstance().openPhoto(photoSize.location, photoViewerProvider); + ImageLocation imageLocation = ImageLocation.getForPhoto(photoSize, message.messageOwner.action.photo); + PhotoViewer.getInstance().openPhoto(photoSize.location, imageLocation, photoViewerProvider); } else { PhotoViewer.getInstance().openPhoto(message, 0, 0, photoViewerProvider); } @@ -14747,7 +14961,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not ThemeDescription.ThemeDescriptionDelegate selectedBackgroundDelegate = () -> { updateVisibleRows(); if (chatActivityEnterView != null && chatActivityEnterView.getEmojiView() != null) { - chatActivityEnterView.getEmojiView().updateUIColors(); + chatActivityEnterView.getEmojiView().updateColors(); } if (chatAttachAlert != null) { chatAttachAlert.checkColors(); @@ -14992,7 +15206,9 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not new ThemeDescription(chatActivityEnterView, ThemeDescription.FLAG_TEXTCOLOR, new Class[]{ChatActivityEnterView.class}, new String[]{"messageEditText"}, null, null, null, Theme.key_chat_messagePanelText), new ThemeDescription(chatActivityEnterView, ThemeDescription.FLAG_TEXTCOLOR, new Class[]{ChatActivityEnterView.class}, new String[]{"recordSendText"}, null, null, null, Theme.key_chat_fieldOverlayText), new ThemeDescription(chatActivityEnterView, ThemeDescription.FLAG_HINTTEXTCOLOR, new Class[]{ChatActivityEnterView.class}, new String[]{"messageEditText"}, null, null, null, Theme.key_chat_messagePanelHint), - new ThemeDescription(chatActivityEnterView, 0, new Class[]{ChatActivityEnterView.class}, new String[]{"sendButton"}, null, null, null, Theme.key_chat_messagePanelSend), + new ThemeDescription(chatActivityEnterView, ThemeDescription.FLAG_IMAGECOLOR, new Class[]{ChatActivityEnterView.class}, new String[]{"sendButton"}, null, null, null, Theme.key_chat_messagePanelSend), + new ThemeDescription(chatActivityEnterView, ThemeDescription.FLAG_IMAGECOLOR, new Class[]{ChatActivityEnterView.class}, new String[]{"sendButton"}, null, null, null, Theme.key_chat_messagePanelSendPressed), + new ThemeDescription(chatActivityEnterView, ThemeDescription.FLAG_BACKGROUNDFILTER, new Class[]{ChatActivityEnterView.class}, new String[]{"sendButton"}, null, null, 24, null, Theme.key_chat_messagePanelSend), new ThemeDescription(chatActivityEnterView, 0, new Class[]{ChatActivityEnterView.class}, new String[]{"emojiButton"}, null, null, null, Theme.key_chat_messagePanelIcons), new ThemeDescription(chatActivityEnterView, 0, new Class[]{ChatActivityEnterView.class}, new String[]{"botButton"}, null, null, null, Theme.key_chat_messagePanelIcons), new ThemeDescription(chatActivityEnterView, 0, new Class[]{ChatActivityEnterView.class}, new String[]{"notifyButton"}, null, null, null, Theme.key_chat_messagePanelIcons), @@ -15160,37 +15376,20 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not new ThemeDescription(avatarContainer != null ? avatarContainer.getTimeItem() : null, 0, null, null, null, null, Theme.key_chat_secretTimerBackground), new ThemeDescription(avatarContainer != null ? avatarContainer.getTimeItem() : null, 0, null, null, null, null, Theme.key_chat_secretTimerText), - new ThemeDescription(null, 0, null, null, new Drawable[]{Theme.chat_attachButtonDrawables[0]}, null, Theme.key_chat_attachCameraIcon1), - new ThemeDescription(null, 0, null, null, new Drawable[]{Theme.chat_attachButtonDrawables[0]}, null, Theme.key_chat_attachCameraIcon2), - new ThemeDescription(null, 0, null, null, new Drawable[]{Theme.chat_attachButtonDrawables[0]}, null, Theme.key_chat_attachCameraIcon3), - new ThemeDescription(null, 0, null, null, new Drawable[]{Theme.chat_attachButtonDrawables[0]}, null, Theme.key_chat_attachCameraIcon4), - new ThemeDescription(null, 0, null, null, new Drawable[]{Theme.chat_attachButtonDrawables[0]}, null, Theme.key_chat_attachCameraIcon5), - new ThemeDescription(null, 0, null, null, new Drawable[]{Theme.chat_attachButtonDrawables[0]}, null, Theme.key_chat_attachCameraIcon6), - - new ThemeDescription(null, ThemeDescription.FLAG_BACKGROUNDFILTER, null, null, new Drawable[]{Theme.chat_attachButtonDrawables[1]}, null, Theme.key_chat_attachGalleryBackground), - //new ThemeDescription(null, 0, null, null, new Drawable[]{Theme.chat_attachButtonDrawables[1]}, null, Theme.key_chat_attachGalleryBackgroundPressed), - new ThemeDescription(null, 0, null, null, new Drawable[]{Theme.chat_attachButtonDrawables[1]}, null, Theme.key_chat_attachGalleryIcon), - new ThemeDescription(null, ThemeDescription.FLAG_BACKGROUNDFILTER, null, null, new Drawable[]{Theme.chat_attachButtonDrawables[2]}, null, Theme.key_chat_attachVideoBackground), - //new ThemeDescription(null, 0, null, null, new Drawable[]{Theme.chat_attachButtonDrawables[2]}, null, Theme.key_chat_attachVideoBackgroundPressed), - new ThemeDescription(null, 0, null, null, new Drawable[]{Theme.chat_attachButtonDrawables[2]}, null, Theme.key_chat_attachVideoIcon), - new ThemeDescription(null, ThemeDescription.FLAG_BACKGROUNDFILTER, null, null, new Drawable[]{Theme.chat_attachButtonDrawables[3]}, null, Theme.key_chat_attachAudioBackground), - //new ThemeDescription(null, 0, null, null, new Drawable[]{Theme.chat_attachButtonDrawables[3]}, null, Theme.key_chat_attachAudioBackgroundPressed), - new ThemeDescription(null, 0, null, null, new Drawable[]{Theme.chat_attachButtonDrawables[3]}, null, Theme.key_chat_attachAudioIcon), - new ThemeDescription(null, ThemeDescription.FLAG_BACKGROUNDFILTER, null, null, new Drawable[]{Theme.chat_attachButtonDrawables[4]}, null, Theme.key_chat_attachFileBackground), - //new ThemeDescription(null, 0, null, null, new Drawable[]{Theme.chat_attachButtonDrawables[4]}, null, Theme.key_chat_attachFileBackgroundPressed), - new ThemeDescription(null, 0, null, null, new Drawable[]{Theme.chat_attachButtonDrawables[4]}, null, Theme.key_chat_attachFileIcon), - new ThemeDescription(null, ThemeDescription.FLAG_BACKGROUNDFILTER, null, null, new Drawable[]{Theme.chat_attachButtonDrawables[5]}, null, Theme.key_chat_attachContactBackground), - //new ThemeDescription(null, 0, null, null, new Drawable[]{Theme.chat_attachButtonDrawables[5]}, null, Theme.key_chat_attachContactBackgroundPressed), - new ThemeDescription(null, 0, null, null, new Drawable[]{Theme.chat_attachButtonDrawables[5]}, null, Theme.key_chat_attachContactIcon), - new ThemeDescription(null, ThemeDescription.FLAG_BACKGROUNDFILTER, null, null, new Drawable[]{Theme.chat_attachButtonDrawables[6]}, null, Theme.key_chat_attachLocationBackground), - //new ThemeDescription(null, 0, null, null, new Drawable[]{Theme.chat_attachButtonDrawables[6]}, null, Theme.key_chat_attachLocationBackgroundPressed), - new ThemeDescription(null, 0, null, null, new Drawable[]{Theme.chat_attachButtonDrawables[6]}, null, Theme.key_chat_attachLocationIcon), - new ThemeDescription(null, ThemeDescription.FLAG_BACKGROUNDFILTER, null, null, new Drawable[]{Theme.chat_attachButtonDrawables[7]}, null, Theme.key_chat_attachHideBackground), - //new ThemeDescription(null, 0, null, null, new Drawable[]{Theme.chat_attachButtonDrawables[6]}, null, Theme.key_chat_attachHideBackgroundPressed), - new ThemeDescription(null, 0, null, null, new Drawable[]{Theme.chat_attachButtonDrawables[7]}, null, Theme.key_chat_attachHideIcon), - new ThemeDescription(null, ThemeDescription.FLAG_BACKGROUNDFILTER, null, null, new Drawable[]{Theme.chat_attachButtonDrawables[8]}, null, Theme.key_chat_attachSendBackground), - //new ThemeDescription(null, 0, null, null, new Drawable[]{Theme.chat_attachButtonDrawables[7]}, null, Theme.key_chat_attachSendBackgroundPressed), - new ThemeDescription(null, 0, null, null, new Drawable[]{Theme.chat_attachButtonDrawables[8]}, null, Theme.key_chat_attachSendIcon), + new ThemeDescription(null, ThemeDescription.FLAG_BACKGROUNDFILTER, null, null, new Drawable[]{Theme.chat_attachButtonDrawables[0]}, null, Theme.key_chat_attachGalleryBackground), + new ThemeDescription(null, 0, null, null, new Drawable[]{Theme.chat_attachButtonDrawables[0]}, null, Theme.key_chat_attachGalleryIcon), + new ThemeDescription(null, ThemeDescription.FLAG_BACKGROUNDFILTER, null, null, new Drawable[]{Theme.chat_attachButtonDrawables[1]}, null, Theme.key_chat_attachAudioBackground), + new ThemeDescription(null, 0, null, null, new Drawable[]{Theme.chat_attachButtonDrawables[1]}, null, Theme.key_chat_attachAudioIcon), + new ThemeDescription(null, ThemeDescription.FLAG_BACKGROUNDFILTER, null, null, new Drawable[]{Theme.chat_attachButtonDrawables[2]}, null, Theme.key_chat_attachFileBackground), + new ThemeDescription(null, 0, null, null, new Drawable[]{Theme.chat_attachButtonDrawables[2]}, null, Theme.key_chat_attachFileIcon), + new ThemeDescription(null, ThemeDescription.FLAG_BACKGROUNDFILTER, null, null, new Drawable[]{Theme.chat_attachButtonDrawables[3]}, null, Theme.key_chat_attachContactBackground), + new ThemeDescription(null, 0, null, null, new Drawable[]{Theme.chat_attachButtonDrawables[3]}, null, Theme.key_chat_attachContactIcon), + new ThemeDescription(null, ThemeDescription.FLAG_BACKGROUNDFILTER, null, null, new Drawable[]{Theme.chat_attachButtonDrawables[4]}, null, Theme.key_chat_attachLocationBackground), + new ThemeDescription(null, 0, null, null, new Drawable[]{Theme.chat_attachButtonDrawables[4]}, null, Theme.key_chat_attachLocationIcon), + new ThemeDescription(null, ThemeDescription.FLAG_BACKGROUNDFILTER, null, null, new Drawable[]{Theme.chat_attachButtonDrawables[5]}, null, Theme.key_chat_attachPollBackground), + new ThemeDescription(null, 0, null, null, new Drawable[]{Theme.chat_attachButtonDrawables[5]}, null, Theme.key_chat_attachPollIcon), + new ThemeDescription(null, 0, null, null, new Drawable[]{Theme.chat_attachEmptyDrawable}, null, Theme.key_chat_attachEmptyImage), + new ThemeDescription(null, 0, null, null, null, selectedBackgroundDelegate, Theme.key_chat_attachPhotoBackground), new ThemeDescription(null, 0, null, null, null, selectedBackgroundDelegate, Theme.key_dialogBackground), new ThemeDescription(null, 0, null, null, null, selectedBackgroundDelegate, Theme.key_dialogBackgroundGray), diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ChatEditActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ChatEditActivity.java index 2b44d647b..933d7ad6d 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ChatEditActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ChatEditActivity.java @@ -144,28 +144,14 @@ public class ChatEditActivity extends BaseFragment implements ImageUpdater.Image public boolean onFragmentCreate() { currentChat = MessagesController.getInstance(currentAccount).getChat(chatId); if (currentChat == null) { - final CountDownLatch countDownLatch = new CountDownLatch(1); - MessagesStorage.getInstance(currentAccount).getStorageQueue().postRunnable(() -> { - currentChat = MessagesStorage.getInstance(currentAccount).getChat(chatId); - countDownLatch.countDown(); - }); - try { - countDownLatch.await(); - } catch (Exception e) { - FileLog.e(e); - } + currentChat = MessagesStorage.getInstance(currentAccount).getChatSync(chatId); if (currentChat != null) { MessagesController.getInstance(currentAccount).putChat(currentChat, true); } else { return false; } if (info == null) { - MessagesStorage.getInstance(currentAccount).loadChatInfo(chatId, countDownLatch, false, false); - try { - countDownLatch.await(); - } catch (Exception e) { - FileLog.e(e); - } + info = MessagesStorage.getInstance(currentAccount).loadChatInfo(chatId, new CountDownLatch(1), false, false); if (info == null) { return false; } @@ -897,7 +883,7 @@ public class ChatEditActivity extends BaseFragment implements ImageUpdater.Image } donePressed = true; if (!ChatObject.isChannel(currentChat) && !historyHidden) { - MessagesController.getInstance(currentAccount).convertToMegaGroup(getParentActivity(), chatId, param -> { + MessagesController.getInstance(currentAccount).convertToMegaGroup(getParentActivity(), chatId, this, param -> { chatId = param; currentChat = MessagesController.getInstance(currentAccount).getChat(param); donePressed = false; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ChatEditTypeActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ChatEditTypeActivity.java index 2a67b6189..ac654a665 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ChatEditTypeActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ChatEditTypeActivity.java @@ -118,28 +118,14 @@ public class ChatEditTypeActivity extends BaseFragment implements NotificationCe public boolean onFragmentCreate() { currentChat = getMessagesController().getChat(chatId); if (currentChat == null) { - final CountDownLatch countDownLatch = new CountDownLatch(1); - getMessagesStorage().getStorageQueue().postRunnable(() -> { - currentChat = getMessagesStorage().getChat(chatId); - countDownLatch.countDown(); - }); - try { - countDownLatch.await(); - } catch (Exception e) { - FileLog.e(e); - } + currentChat = getMessagesStorage().getChatSync(chatId); if (currentChat != null) { getMessagesController().putChat(currentChat, true); } else { return false; } if (info == null) { - getMessagesStorage().loadChatInfo(chatId, countDownLatch, false, false); - try { - countDownLatch.await(); - } catch (Exception e) { - FileLog.e(e); - } + info = getMessagesStorage().loadChatInfo(chatId, new CountDownLatch(1), false, false); if (info == null) { return false; } @@ -497,7 +483,7 @@ public class ChatEditTypeActivity extends BaseFragment implements NotificationCe String newUserName = isPrivate ? "" : usernameTextView.getText().toString(); if (!oldUserName.equals(newUserName)) { if (!ChatObject.isChannel(currentChat)) { - getMessagesController().convertToMegaGroup(getParentActivity(), chatId, param -> { + getMessagesController().convertToMegaGroup(getParentActivity(), chatId, this, param -> { chatId = param; currentChat = getMessagesController().getChat(param); processDone(); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ChatLinkActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ChatLinkActivity.java index 9494ddd7f..69f4a134e 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ChatLinkActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ChatLinkActivity.java @@ -444,7 +444,7 @@ public class ChatLinkActivity extends BaseFragment implements NotificationCenter return; } if (!ChatObject.isChannel(chat)) { - MessagesController.getInstance(currentAccount).convertToMegaGroup(getParentActivity(), chat.id, param -> { + MessagesController.getInstance(currentAccount).convertToMegaGroup(getParentActivity(), chat.id, this, param -> { MessagesController.getInstance(currentAccount).toogleChannelInvitesHistory(param, false); linkChat(getMessagesController().getChat(param), createFragment); }); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ChatRightsEditActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ChatRightsEditActivity.java index 554d91e29..b160faab0 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ChatRightsEditActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ChatRightsEditActivity.java @@ -17,10 +17,14 @@ import android.graphics.PorterDuffColorFilter; import android.graphics.drawable.Drawable; import android.os.Build; import android.os.Bundle; +import android.os.Vibrator; +import android.text.Editable; +import android.text.TextWatcher; import android.util.TypedValue; import android.view.Gravity; import android.view.View; import android.view.ViewGroup; +import android.view.inputmethod.EditorInfo; import android.widget.DatePicker; import android.widget.FrameLayout; import android.widget.ImageView; @@ -42,10 +46,12 @@ import org.telegram.ui.ActionBar.ActionBarMenu; import org.telegram.ui.ActionBar.AlertDialog; import org.telegram.ui.ActionBar.BaseFragment; import org.telegram.ui.ActionBar.BottomSheet; +import org.telegram.ui.ActionBar.SimpleTextView; import org.telegram.ui.ActionBar.Theme; import org.telegram.ui.ActionBar.ThemeDescription; import org.telegram.ui.Cells.DialogRadioCell; import org.telegram.ui.Cells.HeaderCell; +import org.telegram.ui.Cells.PollEditTextCell; import org.telegram.ui.Cells.ShadowSectionCell; import org.telegram.ui.Cells.TextCheckCell2; import org.telegram.ui.Cells.TextDetailCell; @@ -80,6 +86,8 @@ public class ChatRightsEditActivity extends BaseFragment { private TLRPC.TL_chatBannedRights bannedRights; private TLRPC.TL_chatBannedRights defaultBannedRights; private String currentBannedRights = ""; + private String currentRank; + private String initialRank; private int rowCount; private int changeInfoRow; @@ -96,6 +104,9 @@ public class ChatRightsEditActivity extends BaseFragment { private int cantEditInfoRow; private int transferOwnerShadowRow; private int transferOwnerRow; + private int rankHeaderRow; + private int rankRow; + private int rankInfoRow; private int sendMessagesRow; private int sendMediaRow; @@ -114,13 +125,13 @@ public class ChatRightsEditActivity extends BaseFragment { public static final int TYPE_BANNED = 1; public interface ChatRightsEditActivityDelegate { - void didSetRights(int rights, TLRPC.TL_chatAdminRights rightsAdmin, TLRPC.TL_chatBannedRights rightsBanned); + void didSetRights(int rights, TLRPC.TL_chatAdminRights rightsAdmin, TLRPC.TL_chatBannedRights rightsBanned, String rank); void didChangeOwner(TLRPC.User user); } private final static int done_button = 1; - public ChatRightsEditActivity(int userId, int channelId, TLRPC.TL_chatAdminRights rightsAdmin, TLRPC.TL_chatBannedRights rightsBannedDefault, TLRPC.TL_chatBannedRights rightsBanned, int type, boolean edit, boolean addingNew) { + public ChatRightsEditActivity(int userId, int channelId, TLRPC.TL_chatAdminRights rightsAdmin, TLRPC.TL_chatBannedRights rightsBannedDefault, TLRPC.TL_chatBannedRights rightsBanned, String rank, int type, boolean edit, boolean addingNew) { super(); isAddingNew = addingNew; chatId = channelId; @@ -128,6 +139,10 @@ public class ChatRightsEditActivity extends BaseFragment { currentType = type; canEdit = edit; currentChat = MessagesController.getInstance(currentAccount).getChat(chatId); + if (rank == null) { + rank = ""; + } + initialRank = currentRank = rank; if (currentChat != null) { isChannel = ChatObject.isChannel(currentChat) && !currentChat.megagroup; myAdminRights = currentChat.admin_rights; @@ -261,7 +276,7 @@ public class ChatRightsEditActivity extends BaseFragment { } }); - if (canEdit) { + if (canEdit || !isChannel && currentChat.creator && UserObject.isUserSelf(currentUser)) { ActionBarMenu menu = actionBar.createMenu(); menu.addItemWithWidth(done_button, R.drawable.ic_done, AndroidUtilities.dp(56), LocaleController.getString("Done", R.string.Done)); } @@ -269,6 +284,7 @@ public class ChatRightsEditActivity extends BaseFragment { fragmentView = new FrameLayout(context); fragmentView.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundGray)); FrameLayout frameLayout = (FrameLayout) fragmentView; + fragmentView.setFocusableInTouchMode(true); listView = new RecyclerListView(context); LinearLayoutManager linearLayoutManager = new LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false); @@ -288,7 +304,7 @@ public class ChatRightsEditActivity extends BaseFragment { presentFragment(new ProfileActivity(args)); } else if (position == removeAdminRow) { if (currentType == TYPE_ADMIN) { - MessagesController.getInstance(currentAccount).setUserAdminRole(chatId, currentUser, new TLRPC.TL_chatAdminRights(), isChannel, getFragmentForAlert(0), isAddingNew); + MessagesController.getInstance(currentAccount).setUserAdminRole(chatId, currentUser, new TLRPC.TL_chatAdminRights(), currentRank, isChannel, getFragmentForAlert(0), isAddingNew); } else if (currentType == TYPE_BANNED) { bannedRights = new TLRPC.TL_chatBannedRights(); bannedRights.view_messages = true; @@ -307,7 +323,7 @@ public class ChatRightsEditActivity extends BaseFragment { MessagesController.getInstance(currentAccount).setUserBannedRole(chatId, currentUser, bannedRights, isChannel, getFragmentForAlert(0)); } if (delegate != null) { - delegate.didSetRights(0, adminRights, bannedRights); + delegate.didSetRights(0, adminRights, bannedRights, currentRank); } finishFragment(); } else if (position == transferOwnerRow) { @@ -560,6 +576,7 @@ public class ChatRightsEditActivity extends BaseFragment { if (listViewAdapter != null) { listViewAdapter.notifyDataSetChanged(); } + AndroidUtilities.requestAdjustResize(getParentActivity(), classGuid); } private boolean isDefaultAdminRights() { @@ -580,7 +597,7 @@ public class ChatRightsEditActivity extends BaseFragment { return; } if (srp != null && !ChatObject.isChannel(currentChat)) { - MessagesController.getInstance(currentAccount).convertToMegaGroup(getParentActivity(), chatId, param -> { + MessagesController.getInstance(currentAccount).convertToMegaGroup(getParentActivity(), chatId, this, param -> { chatId = param; currentChat = MessagesController.getInstance(currentAccount).getChat(param); initTransfer(srp, passwordFragment); @@ -729,7 +746,7 @@ public class ChatRightsEditActivity extends BaseFragment { } private void updateRows(boolean update) { - int transferOwnerShadowRowPrev = transferOwnerShadowRow; + int transferOwnerShadowRowPrev = Math.min(transferOwnerShadowRow, transferOwnerRow); changeInfoRow = -1; postMessagesRow = -1; @@ -745,6 +762,9 @@ public class ChatRightsEditActivity extends BaseFragment { cantEditInfoRow = -1; transferOwnerShadowRow = -1; transferOwnerRow = -1; + rankHeaderRow = -1; + rankRow = -1; + rankInfoRow = -1; sendMessagesRow = -1; sendMediaRow = -1; @@ -785,29 +805,45 @@ public class ChatRightsEditActivity extends BaseFragment { } if (canEdit) { + if (!isChannel && currentType == TYPE_ADMIN) { + rightsShadowRow = rowCount++; + rankHeaderRow = rowCount++; + rankRow = rowCount++; + rankInfoRow = rowCount++; + } if (currentChat != null && currentChat.creator && currentType == TYPE_ADMIN && hasAllAdminRights() && !currentUser.bot) { - transferOwnerShadowRow = rowCount++; + if (rightsShadowRow == -1) { + transferOwnerShadowRow = rowCount++; + } transferOwnerRow = rowCount++; + if (rightsShadowRow != -1) { + transferOwnerShadowRow = rowCount++; + } } if (initialIsSet) { - rightsShadowRow = rowCount++; + if (rightsShadowRow == -1) { + rightsShadowRow = rowCount++; + } removeAdminRow = rowCount++; removeAdminShadowRow = rowCount++; - cantEditInfoRow = -1; } } else { - removeAdminRow = -1; - removeAdminShadowRow = -1; - if (currentType == TYPE_ADMIN && !canEdit) { - rightsShadowRow = -1; - cantEditInfoRow = rowCount++; + if (currentType == TYPE_ADMIN) { + if (!isChannel && currentType == TYPE_ADMIN && (!currentRank.isEmpty() || currentChat.creator && UserObject.isUserSelf(currentUser))) { + rightsShadowRow = rowCount++; + rankHeaderRow = rowCount++; + rankRow = rowCount++; + rankInfoRow = rowCount++; + } else { + cantEditInfoRow = rowCount++; + } } else { rightsShadowRow = rowCount++; } } if (update) { if (transferOwnerShadowRowPrev == -1 && transferOwnerShadowRow != -1) { - listViewAdapter.notifyItemRangeInserted(transferOwnerShadowRow, 2); + listViewAdapter.notifyItemRangeInserted(Math.min(transferOwnerShadowRow, transferOwnerRow), 2); } else if (transferOwnerShadowRowPrev != -1 && transferOwnerShadowRow == -1) { listViewAdapter.notifyItemRangeRemoved(transferOwnerShadowRowPrev, 2); } @@ -815,8 +851,8 @@ public class ChatRightsEditActivity extends BaseFragment { } private void onDonePressed() { - if (!ChatObject.isChannel(currentChat) && (currentType == TYPE_BANNED || currentType == TYPE_ADMIN && !isDefaultAdminRights())) { - MessagesController.getInstance(currentAccount).convertToMegaGroup(getParentActivity(), chatId, param -> { + if (!ChatObject.isChannel(currentChat) && (currentType == TYPE_BANNED || currentType == TYPE_ADMIN && (!isDefaultAdminRights() || rankRow != -1 && currentRank.codePointCount(0, currentRank.length()) > MAX_RANK_LENGTH))) { + MessagesController.getInstance(currentAccount).convertToMegaGroup(getParentActivity(), chatId, this, param -> { chatId = param; currentChat = MessagesController.getInstance(currentAccount).getChat(param); onDonePressed(); @@ -824,17 +860,29 @@ public class ChatRightsEditActivity extends BaseFragment { return; } if (currentType == TYPE_ADMIN) { + if (rankRow != -1 && currentRank.codePointCount(0, currentRank.length()) > MAX_RANK_LENGTH) { + listView.smoothScrollToPosition(rankRow); + Vibrator v = (Vibrator) getParentActivity().getSystemService(Context.VIBRATOR_SERVICE); + if (v != null) { + v.vibrate(200); + } + RecyclerView.ViewHolder holder = listView.findViewHolderForAdapterPosition(rankHeaderRow); + if (holder != null) { + AndroidUtilities.shakeView(holder.itemView, 2, 0); + } + return; + } if (isChannel) { adminRights.pin_messages = adminRights.ban_users = false; } else { adminRights.post_messages = adminRights.edit_messages = false; } - MessagesController.getInstance(currentAccount).setUserAdminRole(chatId, currentUser, adminRights, isChannel, getFragmentForAlert(1), isAddingNew); + MessagesController.getInstance(currentAccount).setUserAdminRole(chatId, currentUser, adminRights, currentRank, isChannel, getFragmentForAlert(1), isAddingNew); if (delegate != null) { delegate.didSetRights( adminRights.change_info || adminRights.post_messages || adminRights.edit_messages || adminRights.delete_messages || adminRights.ban_users || adminRights.invite_users || - adminRights.pin_messages || adminRights.add_admins ? 1 : 0, adminRights, bannedRights); + adminRights.pin_messages || adminRights.add_admins ? 1 : 0, adminRights, bannedRights, currentRank); } } else if (currentType == TYPE_BANNED) { MessagesController.getInstance(currentAccount).setUserBannedRole(chatId, currentUser, bannedRights, isChannel, getFragmentForAlert(1)); @@ -847,7 +895,7 @@ public class ChatRightsEditActivity extends BaseFragment { rights = 2; } if (delegate != null) { - delegate.didSetRights(rights, adminRights, bannedRights); + delegate.didSetRights(rights, adminRights, bannedRights, currentRank); } } finishFragment(); @@ -858,11 +906,14 @@ public class ChatRightsEditActivity extends BaseFragment { } private boolean checkDiscard() { - if (currentType != TYPE_BANNED) { - return true; + boolean changed; + if (currentType == TYPE_BANNED) { + String newBannedRights = ChatObject.getBannedRightsString(bannedRights); + changed = !currentBannedRights.equals(newBannedRights); + } else { + changed = !initialRank.equals(currentRank); } - String newBannedRights = ChatObject.getBannedRightsString(bannedRights); - if (!currentBannedRights.equals(newBannedRights)) { + if (changed) { AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); builder.setTitle(LocaleController.getString("UserRestrictionsApplyChanges", R.string.UserRestrictionsApplyChanges)); TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(chatId); @@ -875,6 +926,24 @@ public class ChatRightsEditActivity extends BaseFragment { return true; } + private final static int MAX_RANK_LENGTH = 16; + + private void setTextLeft(View cell) { + if (cell instanceof HeaderCell) { + HeaderCell headerCell = (HeaderCell) cell; + int left = MAX_RANK_LENGTH - (currentRank != null ? currentRank.codePointCount(0, currentRank.length()) : 0); + if (left <= MAX_RANK_LENGTH - MAX_RANK_LENGTH * 0.7f) { + headerCell.setText2(String.format("%d", left)); + SimpleTextView textView = headerCell.getTextView2(); + String key = left < 0 ? Theme.key_windowBackgroundWhiteRedText5 : Theme.key_windowBackgroundWhiteGrayText3; + textView.setTextColor(Theme.getColor(key)); + textView.setTag(key); + } else { + headerCell.setText2(""); + } + } + } + @Override public boolean onBackPressed() { return checkDiscard(); @@ -883,6 +952,7 @@ public class ChatRightsEditActivity extends BaseFragment { private class ListAdapter extends RecyclerListView.SelectionAdapter { private Context mContext; + private boolean ignoreTextChange; public ListAdapter(Context context) { mContext = context; @@ -939,7 +1009,7 @@ public class ChatRightsEditActivity extends BaseFragment { view.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); break; case 3: - view = new HeaderCell(mContext); + view = new HeaderCell(mContext, false, 21, 15, true); view.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); break; case 4: @@ -950,10 +1020,38 @@ public class ChatRightsEditActivity extends BaseFragment { view = new ShadowSectionCell(mContext); break; case 6: - default: view = new TextDetailCell(mContext); view.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); break; + case 7: + default: + PollEditTextCell cell = new PollEditTextCell(mContext, null); + cell.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); + cell.addTextWatcher(new TextWatcher() { + @Override + public void beforeTextChanged(CharSequence s, int start, int count, int after) { + + } + + @Override + public void onTextChanged(CharSequence s, int start, int before, int count) { + + } + + @Override + public void afterTextChanged(Editable s) { + if (ignoreTextChange) { + return; + } + currentRank = s.toString(); + RecyclerView.ViewHolder holder = listView.findViewHolderForAdapterPosition(rankHeaderRow); + if (holder != null) { + setTextLeft(holder.itemView); + } + } + }); + view = cell; + break; } return new RecyclerListView.Holder(view); } @@ -969,6 +1067,14 @@ public class ChatRightsEditActivity extends BaseFragment { TextInfoPrivacyCell privacyCell = (TextInfoPrivacyCell) holder.itemView; if (position == cantEditInfoRow) { privacyCell.setText(LocaleController.getString("EditAdminCantEdit", R.string.EditAdminCantEdit)); + } else if (position == rankInfoRow) { + String hint; + if (UserObject.isUserSelf(currentUser) && currentChat.creator) { + hint = LocaleController.getString("ChannelCreator", R.string.ChannelCreator); + } else { + hint = LocaleController.getString("ChannelAdmin", R.string.ChannelAdmin); + } + privacyCell.setText(LocaleController.formatString("EditAdminRankInfo", R.string.EditAdminRankInfo, hint)); } break; case 2: @@ -993,10 +1099,14 @@ public class ChatRightsEditActivity extends BaseFragment { break; case 3: HeaderCell headerCell = (HeaderCell) holder.itemView; - if (currentType == TYPE_ADMIN) { - headerCell.setText(LocaleController.getString("EditAdminWhatCanDo", R.string.EditAdminWhatCanDo)); - } else if (currentType == TYPE_BANNED) { - headerCell.setText(LocaleController.getString("UserRestrictionsCanDo", R.string.UserRestrictionsCanDo)); + if (position == 2) { + if (currentType == TYPE_ADMIN) { + headerCell.setText(LocaleController.getString("EditAdminWhatCanDo", R.string.EditAdminWhatCanDo)); + } else if (currentType == TYPE_BANNED) { + headerCell.setText(LocaleController.getString("UserRestrictionsCanDo", R.string.UserRestrictionsCanDo)); + } + } else if (position == rankHeaderRow) { + headerCell.setText(LocaleController.getString("EditAdminRank", R.string.EditAdminRank)); } break; case 4: @@ -1070,9 +1180,11 @@ public class ChatRightsEditActivity extends BaseFragment { case 5: ShadowSectionCell shadowCell = (ShadowSectionCell) holder.itemView; if (position == rightsShadowRow) { - shadowCell.setBackgroundDrawable(Theme.getThemedDrawable(mContext, removeAdminRow == -1 ? R.drawable.greydivider_bottom : R.drawable.greydivider, Theme.key_windowBackgroundGrayShadow)); + shadowCell.setBackgroundDrawable(Theme.getThemedDrawable(mContext, removeAdminRow == -1 && rankRow == -1 ? R.drawable.greydivider_bottom : R.drawable.greydivider, Theme.key_windowBackgroundGrayShadow)); } else if (position == removeAdminShadowRow) { shadowCell.setBackgroundDrawable(Theme.getThemedDrawable(mContext, R.drawable.greydivider_bottom, Theme.key_windowBackgroundGrayShadow)); + } else if (position == rankInfoRow) { + shadowCell.setBackgroundDrawable(Theme.getThemedDrawable(mContext, canEdit ? R.drawable.greydivider : R.drawable.greydivider_bottom, Theme.key_windowBackgroundGrayShadow)); } else { shadowCell.setBackgroundDrawable(Theme.getThemedDrawable(mContext, R.drawable.greydivider, Theme.key_windowBackgroundGrayShadow)); } @@ -1089,6 +1201,35 @@ public class ChatRightsEditActivity extends BaseFragment { detailCell.setTextAndValue(LocaleController.getString("UserRestrictionsDuration", R.string.UserRestrictionsDuration), value, false); } break; + case 7: + PollEditTextCell textCell = (PollEditTextCell) holder.itemView; + String hint; + if (UserObject.isUserSelf(currentUser) && currentChat.creator) { + hint = LocaleController.getString("ChannelCreator", R.string.ChannelCreator); + } else { + hint = LocaleController.getString("ChannelAdmin", R.string.ChannelAdmin); + } + ignoreTextChange = true; + textCell.getTextView().setEnabled(canEdit || currentChat.creator); + textCell.getTextView().setSingleLine(true); + textCell.getTextView().setImeOptions(EditorInfo.IME_ACTION_DONE); + textCell.setTextAndHint(currentRank, hint, false); + ignoreTextChange = false; + break; + } + } + + @Override + public void onViewAttachedToWindow(RecyclerView.ViewHolder holder) { + if (holder.getAdapterPosition() == rankHeaderRow) { + setTextLeft(holder.itemView); + } + } + + @Override + public void onViewDetachedFromWindow(RecyclerView.ViewHolder holder) { + if (holder.getAdapterPosition() == rankRow && getParentActivity() != null) { + AndroidUtilities.hideKeyboard(getParentActivity().getCurrentFocus()); } } @@ -1098,17 +1239,19 @@ public class ChatRightsEditActivity extends BaseFragment { return 0; } else if (position == 1 || position == rightsShadowRow || position == removeAdminShadowRow || position == untilSectionRow || position == transferOwnerShadowRow) { return 5; - } else if (position == 2) { + } else if (position == 2 || position == rankHeaderRow) { return 3; } else if (position == changeInfoRow || position == postMessagesRow || position == editMesagesRow || position == deleteMessagesRow || position == addAdminsRow || position == banUsersRow || position == addUsersRow || position == pinMessagesRow || position == sendMessagesRow || position == sendMediaRow || position == sendStickersRow || position == embedLinksRow || position == sendPollsRow) { return 4; - } else if (position == cantEditInfoRow) { + } else if (position == cantEditInfoRow || position == rankInfoRow) { return 1; } else if (position == untilDateRow) { return 6; + } else if (position == rankRow) { + return 7; } else { return 2; } @@ -1130,7 +1273,7 @@ public class ChatRightsEditActivity extends BaseFragment { }; return new ThemeDescription[]{ - new ThemeDescription(listView, ThemeDescription.FLAG_CELLBACKGROUNDCOLOR, new Class[]{UserCell2.class, TextSettingsCell.class, TextCheckCell2.class, HeaderCell.class, TextDetailCell.class}, null, null, null, Theme.key_windowBackgroundWhite), + new ThemeDescription(listView, ThemeDescription.FLAG_CELLBACKGROUNDCOLOR, new Class[]{UserCell2.class, TextSettingsCell.class, TextCheckCell2.class, HeaderCell.class, TextDetailCell.class, PollEditTextCell.class}, null, null, null, Theme.key_windowBackgroundWhite), new ThemeDescription(fragmentView, ThemeDescription.FLAG_BACKGROUND, null, null, null, null, Theme.key_windowBackgroundGray), new ThemeDescription(actionBar, ThemeDescription.FLAG_BACKGROUND, null, null, null, null, Theme.key_actionBarDefault), @@ -1162,6 +1305,11 @@ public class ChatRightsEditActivity extends BaseFragment { new ThemeDescription(listView, ThemeDescription.FLAG_BACKGROUNDFILTER, new Class[]{ShadowSectionCell.class}, null, null, null, Theme.key_windowBackgroundGrayShadow), new ThemeDescription(listView, 0, new Class[]{HeaderCell.class}, new String[]{"textView"}, null, null, null, Theme.key_windowBackgroundWhiteBlueHeader), + new ThemeDescription(listView, ThemeDescription.FLAG_CHECKTAG, new Class[]{HeaderCell.class}, new String[]{"textView2"}, null, null, null, Theme.key_windowBackgroundWhiteRedText5), + new ThemeDescription(listView, ThemeDescription.FLAG_CHECKTAG, new Class[]{HeaderCell.class}, new String[]{"textView2"}, null, null, null, Theme.key_windowBackgroundWhiteGrayText3), + + new ThemeDescription(listView, ThemeDescription.FLAG_TEXTCOLOR, new Class[]{PollEditTextCell.class}, new String[]{"textView"}, null, null, null, Theme.key_windowBackgroundWhiteBlackText), + new ThemeDescription(listView, ThemeDescription.FLAG_HINTTEXTCOLOR, new Class[]{PollEditTextCell.class}, new String[]{"textView"}, null, null, null, Theme.key_windowBackgroundWhiteHintText), new ThemeDescription(listView, 0, new Class[]{UserCell2.class}, new String[]{"nameTextView"}, null, null, null, Theme.key_windowBackgroundWhiteBlackText), new ThemeDescription(listView, 0, new Class[]{UserCell2.class}, new String[]{"statusColor"}, null, null, cellDelegate, Theme.key_windowBackgroundWhiteGrayText), diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ChatUsersActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ChatUsersActivity.java index d30227028..07d92627d 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ChatUsersActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ChatUsersActivity.java @@ -9,17 +9,21 @@ package org.telegram.ui; import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Paint; import android.graphics.PorterDuff; import android.graphics.PorterDuffColorFilter; import android.graphics.drawable.Drawable; import android.os.Bundle; import android.text.SpannableStringBuilder; import android.text.Spanned; +import android.text.TextPaint; import android.text.TextUtils; import android.text.style.ForegroundColorSpan; import android.util.SparseArray; import android.util.TypedValue; import android.view.Gravity; +import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; import android.widget.EditText; @@ -37,10 +41,8 @@ import org.telegram.messenger.LocaleController; import org.telegram.messenger.MessagesController; import org.telegram.messenger.NotificationCenter; import org.telegram.messenger.R; -import org.telegram.messenger.UserConfig; import org.telegram.messenger.UserObject; import org.telegram.messenger.Utilities; -import org.telegram.tgnet.ConnectionsManager; import org.telegram.tgnet.TLObject; import org.telegram.tgnet.TLRPC; import org.telegram.ui.ActionBar.ActionBar; @@ -121,6 +123,10 @@ public class ChatUsersActivity extends BaseFragment implements NotificationCente private int participantsDividerRow; private int participantsDivider2Row; + private int slowmodeRow; + private int slowmodeSelectRow; + private int slowmodeInfoRow; + private int contactsHeaderRow; private int contactsStartRow; private int contactsEndRow; @@ -143,6 +149,9 @@ public class ChatUsersActivity extends BaseFragment implements NotificationCente private boolean searchWas; private boolean searching; + private int selectedSlowmode; + private int initialSlowmode; + private final static int search_button = 0; private final static int done_button = 1; @@ -156,13 +165,187 @@ public class ChatUsersActivity extends BaseFragment implements NotificationCente void didChangeOwner(TLRPC.User user); } + private class ChooseView extends View { + + private Paint paint; + private TextPaint textPaint; + + private int circleSize; + private int gapSize; + private int sideSide; + private int lineSize; + + private boolean moving; + private boolean startMoving; + private float startX; + + private int startMovingItem; + + private ArrayList strings = new ArrayList<>(); + private ArrayList sizes = new ArrayList<>(); + + public ChooseView(Context context) { + super(context); + + paint = new Paint(Paint.ANTI_ALIAS_FLAG); + textPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG); + textPaint.setTextSize(AndroidUtilities.dp(13)); + + for (int a = 0; a < 7; a++) { + String string; + switch (a) { + case 0: + string = LocaleController.getString("SlowmodeOff", R.string.SlowmodeOff); + break; + case 1: + string = LocaleController.formatString("SlowmodeSeconds", R.string.SlowmodeSeconds, 10); + break; + case 2: + string = LocaleController.formatString("SlowmodeSeconds", R.string.SlowmodeSeconds, 30); + break; + case 3: + string = LocaleController.formatString("SlowmodeMinutes", R.string.SlowmodeMinutes, 1); + break; + case 4: + string = LocaleController.formatString("SlowmodeMinutes", R.string.SlowmodeMinutes, 5); + break; + case 5: + string = LocaleController.formatString("SlowmodeMinutes", R.string.SlowmodeMinutes, 15); + break; + case 6: + default: + string = LocaleController.formatString("SlowmodeHours", R.string.SlowmodeHours, 1); + break; + } + strings.add(string); + sizes.add((int) Math.ceil(textPaint.measureText(string))); + } + } + + @Override + public boolean onTouchEvent(MotionEvent event) { + float x = event.getX(); + if (event.getAction() == MotionEvent.ACTION_DOWN) { + getParent().requestDisallowInterceptTouchEvent(true); + for (int a = 0; a < strings.size(); a++) { + int cx = sideSide + (lineSize + gapSize * 2 + circleSize) * a + circleSize / 2; + if (x > cx - AndroidUtilities.dp(15) && x < cx + AndroidUtilities.dp(15)) { + startMoving = a == selectedSlowmode; + startX = x; + startMovingItem = selectedSlowmode; + break; + } + } + } else if (event.getAction() == MotionEvent.ACTION_MOVE) { + if (startMoving) { + if (Math.abs(startX - x) >= AndroidUtilities.getPixelsInCM(0.5f, true)) { + moving = true; + startMoving = false; + } + } else if (moving) { + for (int a = 0; a < strings.size(); a++) { + int cx = sideSide + (lineSize + gapSize * 2 + circleSize) * a + circleSize / 2; + int diff = lineSize / 2 + circleSize / 2 + gapSize; + if (x > cx - diff && x < cx + diff) { + if (selectedSlowmode != a) { + setItem(a); + } + break; + } + } + } + } else if (event.getAction() == MotionEvent.ACTION_UP || event.getAction() == MotionEvent.ACTION_CANCEL) { + if (!moving) { + for (int a = 0; a < strings.size(); a++) { + int cx = sideSide + (lineSize + gapSize * 2 + circleSize) * a + circleSize / 2; + if (x > cx - AndroidUtilities.dp(15) && x < cx + AndroidUtilities.dp(15)) { + if (selectedSlowmode != a) { + setItem(a); + } + break; + } + } + } else { + if (selectedSlowmode != startMovingItem) { + setItem(selectedSlowmode); + } + } + startMoving = false; + moving = false; + } + return true; + } + + private void setItem(int index) { + if (info == null) { + return; + } + selectedSlowmode = index; + info.slowmode_seconds = getSecondsForIndex(index); + info.flags |= 131072; + for (int a = 0; a < 3; a++) { + RecyclerView.ViewHolder holder = listView.findViewHolderForAdapterPosition(slowmodeInfoRow); + if (holder != null) { + listViewAdapter.onBindViewHolder(holder, slowmodeInfoRow); + } + } + invalidate(); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(74), MeasureSpec.EXACTLY)); + int width = MeasureSpec.getSize(widthMeasureSpec); + circleSize = AndroidUtilities.dp(6); + gapSize = AndroidUtilities.dp(2); + sideSide = AndroidUtilities.dp(22); + lineSize = (getMeasuredWidth() - circleSize * strings.size() - gapSize * 2 * (strings.size() - 1) - sideSide * 2) / (strings.size() - 1); + } + + @Override + protected void onDraw(Canvas canvas) { + textPaint.setColor(Theme.getColor(Theme.key_windowBackgroundWhiteGrayText)); + int cy = getMeasuredHeight() / 2 + AndroidUtilities.dp(11); + + for (int a = 0; a < strings.size(); a++) { + int cx = sideSide + (lineSize + gapSize * 2 + circleSize) * a + circleSize / 2; + if (a <= selectedSlowmode) { + paint.setColor(Theme.getColor(Theme.key_switchTrackChecked)); + } else { + paint.setColor(Theme.getColor(Theme.key_switchTrack)); + } + canvas.drawCircle(cx, cy, a == selectedSlowmode ? AndroidUtilities.dp(6) : circleSize / 2, paint); + if (a != 0) { + int x = cx - circleSize / 2 - gapSize - lineSize; + int width = lineSize; + if (a == selectedSlowmode || a == selectedSlowmode + 1) { + width -= AndroidUtilities.dp(3); + } + if (a == selectedSlowmode + 1) { + x += AndroidUtilities.dp(3); + } + canvas.drawRect(x, cy - AndroidUtilities.dp(1), x + width, cy + AndroidUtilities.dp(1), paint); + } + int size = sizes.get(a); + String text = strings.get(a); + if (a == 0) { + canvas.drawText(text, AndroidUtilities.dp(22), AndroidUtilities.dp(28), textPaint); + } else if (a == strings.size() - 1) { + canvas.drawText(text, getMeasuredWidth() - size - AndroidUtilities.dp(22), AndroidUtilities.dp(28), textPaint); + } else { + canvas.drawText(text, cx - size / 2, AndroidUtilities.dp(28), textPaint); + } + } + } + } + public ChatUsersActivity(Bundle args) { super(args); chatId = arguments.getInt("chat_id"); type = arguments.getInt("type"); needOpenSearch = arguments.getBoolean("open_search"); selectType = arguments.getInt("selectType"); - currentChat = MessagesController.getInstance(currentAccount).getChat(chatId); + currentChat = getMessagesController().getChat(chatId); if (currentChat != null && currentChat.default_banned_rights != null) { defaultBannedRights.view_messages = currentChat.default_banned_rights.view_messages; defaultBannedRights.send_stickers = currentChat.default_banned_rights.send_stickers; @@ -182,7 +365,7 @@ public class ChatUsersActivity extends BaseFragment implements NotificationCente } private void updateRows() { - currentChat = MessagesController.getInstance(currentAccount).getChat(chatId); + currentChat = getMessagesController().getChat(chatId); if (currentChat == null) { return; } @@ -214,6 +397,9 @@ public class ChatUsersActivity extends BaseFragment implements NotificationCente botStartRow = -1; botEndRow = -1; membersHeaderRow = -1; + slowmodeRow = -1; + slowmodeSelectRow = -1; + slowmodeInfoRow = -1; rowCount = 0; if (type == TYPE_KICKED) { @@ -226,8 +412,16 @@ public class ChatUsersActivity extends BaseFragment implements NotificationCente addUsersRow = rowCount++; pinMessagesRow = rowCount++; changeInfoRow = rowCount++; - if (ChatObject.isChannel(currentChat)) { + if (!ChatObject.isChannel(currentChat) && currentChat.creator || currentChat.megagroup && ChatObject.canBlockUsers(currentChat)) { participantsDivider2Row = rowCount++; + slowmodeRow = rowCount++; + slowmodeSelectRow = rowCount++; + slowmodeInfoRow = rowCount++; + } + if (ChatObject.isChannel(currentChat)) { + if (participantsDivider2Row == -1) { + participantsDivider2Row = rowCount++; + } removedUsersRow = rowCount++; } participantsDividerRow = rowCount++; @@ -318,7 +512,7 @@ public class ChatUsersActivity extends BaseFragment implements NotificationCente @Override public boolean onFragmentCreate() { super.onFragmentCreate(); - NotificationCenter.getInstance(currentAccount).addObserver(this, NotificationCenter.chatInfoDidLoad); + getNotificationCenter().addObserver(this, NotificationCenter.chatInfoDidLoad); loadChatParticipants(0, 200); return true; } @@ -326,7 +520,7 @@ public class ChatUsersActivity extends BaseFragment implements NotificationCente @Override public void onFragmentDestroy() { super.onFragmentDestroy(); - NotificationCenter.getInstance(currentAccount).removeObserver(this, NotificationCenter.chatInfoDidLoad); + getNotificationCenter().removeObserver(this, NotificationCenter.chatInfoDidLoad); } @Override @@ -505,13 +699,13 @@ public class ChatUsersActivity extends BaseFragment implements NotificationCente public void didSelectUsers(ArrayList users, int fwdCount) { for (int a = 0, N = users.size(); a < N; a++) { TLRPC.User user = users.get(a); - MessagesController.getInstance(currentAccount).addUserToChat(chatId, user, null, fwdCount, null, ChatUsersActivity.this, null); + getMessagesController().addUserToChat(chatId, user, null, fwdCount, null, ChatUsersActivity.this, null); } } @Override public void needAddBot(TLRPC.User user) { - openRightsEdit(user.id, null, null, null, true, ChatRightsEditActivity.TYPE_ADMIN, false); + openRightsEdit(user.id, null, null, null, "", true, ChatRightsEditActivity.TYPE_ADMIN, false); } }); presentFragment(fragment); @@ -616,6 +810,7 @@ public class ChatUsersActivity extends BaseFragment implements NotificationCente TLRPC.TL_chatBannedRights bannedRights = null; TLRPC.TL_chatAdminRights adminRights = null; + String rank = ""; final TLObject participant; int user_id = 0; int promoted_by = 0; @@ -627,6 +822,7 @@ public class ChatUsersActivity extends BaseFragment implements NotificationCente user_id = channelParticipant.user_id; bannedRights = channelParticipant.banned_rights; adminRights = channelParticipant.admin_rights; + rank = channelParticipant.rank; canEditAdmin = !(channelParticipant instanceof TLRPC.TL_channelParticipantAdmin || channelParticipant instanceof TLRPC.TL_channelParticipantCreator) || channelParticipant.can_edit; if (participant instanceof TLRPC.TL_channelParticipantCreator) { adminRights = new TLRPC.TL_chatAdminRights(); @@ -649,7 +845,7 @@ public class ChatUsersActivity extends BaseFragment implements NotificationCente TLObject object = searchListViewAdapter.getItem(position); if (object instanceof TLRPC.User) { TLRPC.User user = (TLRPC.User) object; - MessagesController.getInstance(currentAccount).putUser(user, false); + getMessagesController().putUser(user, false); participant = getAnyParticipant(user_id = user.id); } else if (object instanceof TLRPC.ChannelParticipant || object instanceof TLRPC.ChatParticipant) { participant = object; @@ -665,6 +861,7 @@ public class ChatUsersActivity extends BaseFragment implements NotificationCente canEditAdmin = !(channelParticipant instanceof TLRPC.TL_channelParticipantAdmin || channelParticipant instanceof TLRPC.TL_channelParticipantCreator) || channelParticipant.can_edit; bannedRights = channelParticipant.banned_rights; adminRights = channelParticipant.admin_rights; + rank = channelParticipant.rank; } else if (participant instanceof TLRPC.ChatParticipant) { if (participant instanceof TLRPC.TL_chatParticipantCreator) { return; @@ -682,18 +879,19 @@ public class ChatUsersActivity extends BaseFragment implements NotificationCente if (selectType != 0) { if (selectType == 3 || selectType == 1) { if (selectType != 1 && canEditAdmin && (participant instanceof TLRPC.TL_channelParticipantAdmin || participant instanceof TLRPC.TL_chatParticipantAdmin)) { - final TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(user_id); + final TLRPC.User user = getMessagesController().getUser(user_id); final TLRPC.TL_chatBannedRights br = bannedRights; final TLRPC.TL_chatAdminRights ar = adminRights; final boolean canEdit = canEditAdmin; + final String rankFinal = rank; AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); builder.setMessage(LocaleController.formatString("AdminWillBeRemoved", R.string.AdminWillBeRemoved, ContactsController.formatName(user.first_name, user.last_name))); - builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), (dialog, which) -> openRightsEdit(user.id, participant, ar, br, canEdit, selectType == 1 ? 0 : 1, false)); + builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), (dialog, which) -> openRightsEdit(user.id, participant, ar, br, rankFinal, canEdit, selectType == 1 ? 0 : 1, false)); builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); showDialog(builder.create()); } else { - openRightsEdit(user_id, participant, adminRights, bannedRights, canEditAdmin, selectType == 1 ? 0 : 1, selectType == 1); + openRightsEdit(user_id, participant, adminRights, bannedRights, rank, canEditAdmin, selectType == 1 ? 0 : 1, selectType == 1 || selectType == 3); } } else { removeUser(user_id); @@ -701,7 +899,7 @@ public class ChatUsersActivity extends BaseFragment implements NotificationCente } else { boolean canEdit = false; if (type == TYPE_ADMIN) { - canEdit = user_id != UserConfig.getInstance(currentAccount).getClientUserId() && (currentChat.creator || canEditAdmin); + canEdit = user_id != getUserConfig().getClientUserId() && (currentChat.creator || canEditAdmin); } else if (type == TYPE_BANNED || type == TYPE_KICKED) { canEdit = ChatObject.canBlockUsers(currentChat); } @@ -728,14 +926,15 @@ public class ChatUsersActivity extends BaseFragment implements NotificationCente bannedRights.invite_users = true; bannedRights.change_info = true; } - ChatRightsEditActivity fragment = new ChatRightsEditActivity(user_id, chatId, adminRights, defaultBannedRights, bannedRights, type == TYPE_ADMIN ? ChatRightsEditActivity.TYPE_ADMIN : ChatRightsEditActivity.TYPE_BANNED, canEdit, participant == null); + ChatRightsEditActivity fragment = new ChatRightsEditActivity(user_id, chatId, adminRights, defaultBannedRights, bannedRights, rank, type == TYPE_ADMIN ? ChatRightsEditActivity.TYPE_ADMIN : ChatRightsEditActivity.TYPE_BANNED, canEdit, participant == null); fragment.setDelegate(new ChatRightsEditActivity.ChatRightsEditActivityDelegate() { @Override - public void didSetRights(int rights, TLRPC.TL_chatAdminRights rightsAdmin, TLRPC.TL_chatBannedRights rightsBanned) { + public void didSetRights(int rights, TLRPC.TL_chatAdminRights rightsAdmin, TLRPC.TL_chatBannedRights rightsBanned, String rank) { if (participant instanceof TLRPC.ChannelParticipant) { TLRPC.ChannelParticipant channelParticipant = (TLRPC.ChannelParticipant) participant; channelParticipant.admin_rights = rightsAdmin; channelParticipant.banned_rights = rightsBanned; + channelParticipant.rank = rank; updateParticipantWithRights(channelParticipant, rightsAdmin, rightsBanned, 0, false); } } @@ -867,11 +1066,11 @@ public class ChatUsersActivity extends BaseFragment implements NotificationCente } } - private void openRightsEdit2(int userId, int date, TLObject participant, TLRPC.TL_chatAdminRights adminRights, TLRPC.TL_chatBannedRights bannedRights, boolean canEditAdmin, int type, boolean removeFragment) { - ChatRightsEditActivity fragment = new ChatRightsEditActivity(userId, chatId, adminRights, defaultBannedRights, bannedRights, type, true, false); + private void openRightsEdit2(int userId, int date, TLObject participant, TLRPC.TL_chatAdminRights adminRights, TLRPC.TL_chatBannedRights bannedRights, String rank, boolean canEditAdmin, int type, boolean removeFragment) { + ChatRightsEditActivity fragment = new ChatRightsEditActivity(userId, chatId, adminRights, defaultBannedRights, bannedRights, rank, type, true, false); fragment.setDelegate(new ChatRightsEditActivity.ChatRightsEditActivityDelegate() { @Override - public void didSetRights(int rights, TLRPC.TL_chatAdminRights rightsAdmin, TLRPC.TL_chatBannedRights rightsBanned) { + public void didSetRights(int rights, TLRPC.TL_chatAdminRights rightsAdmin, TLRPC.TL_chatBannedRights rightsBanned, String rank) { if (type == 0) { for (int a = 0; a < participants.size(); a++) { TLObject p = participants.get(a); @@ -886,9 +1085,11 @@ public class ChatUsersActivity extends BaseFragment implements NotificationCente } newPart.admin_rights = rightsAdmin; newPart.banned_rights = rightsBanned; - newPart.inviter_id = UserConfig.getInstance(currentAccount).getClientUserId(); + newPart.inviter_id = getUserConfig().getClientUserId(); newPart.user_id = userId; newPart.date = date; + newPart.flags |= 4; + newPart.rank = rank; participants.set(a, newPart); break; } @@ -925,15 +1126,16 @@ public class ChatUsersActivity extends BaseFragment implements NotificationCente presentFragment(fragment); } - private void openRightsEdit(int user_id, TLObject participant, TLRPC.TL_chatAdminRights adminRights, TLRPC.TL_chatBannedRights bannedRights, boolean canEditAdmin, int type, boolean removeFragment) { - ChatRightsEditActivity fragment = new ChatRightsEditActivity(user_id, chatId, adminRights, defaultBannedRights, bannedRights, type, canEditAdmin, participant == null); + private void openRightsEdit(int user_id, TLObject participant, TLRPC.TL_chatAdminRights adminRights, TLRPC.TL_chatBannedRights bannedRights, String rank, boolean canEditAdmin, int type, boolean removeFragment) { + ChatRightsEditActivity fragment = new ChatRightsEditActivity(user_id, chatId, adminRights, defaultBannedRights, bannedRights, rank, type, canEditAdmin, participant == null); fragment.setDelegate(new ChatRightsEditActivity.ChatRightsEditActivityDelegate() { @Override - public void didSetRights(int rights, TLRPC.TL_chatAdminRights rightsAdmin, TLRPC.TL_chatBannedRights rightsBanned) { + public void didSetRights(int rights, TLRPC.TL_chatAdminRights rightsAdmin, TLRPC.TL_chatBannedRights rightsBanned, String rank) { if (participant instanceof TLRPC.ChannelParticipant) { TLRPC.ChannelParticipant channelParticipant = (TLRPC.ChannelParticipant) participant; channelParticipant.admin_rights = rightsAdmin; channelParticipant.banned_rights = rightsBanned; + channelParticipant.rank = rank; } if (removeFragment) { removeSelfFromStack(); @@ -952,8 +1154,8 @@ public class ChatUsersActivity extends BaseFragment implements NotificationCente if (!ChatObject.isChannel(currentChat)) { return; } - TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(userId); - MessagesController.getInstance(currentAccount).deleteUserFromChat(chatId, user, null); + TLRPC.User user = getMessagesController().getUser(userId); + getMessagesController().deleteUserFromChat(chatId, user, null); finishFragment(); } @@ -1031,7 +1233,7 @@ public class ChatUsersActivity extends BaseFragment implements NotificationCente channelParticipant.admin_rights = rightsAdmin; channelParticipant.banned_rights = rightsBanned; if (withDelegate) { - channelParticipant.promoted_by = UserConfig.getInstance(currentAccount).getClientUserId(); + channelParticipant.promoted_by = getUserConfig().getClientUserId(); } } if (withDelegate && p != null && !delegateCalled && delegate != null) { @@ -1050,6 +1252,7 @@ public class ChatUsersActivity extends BaseFragment implements NotificationCente int date; TLRPC.TL_chatBannedRights bannedRights; TLRPC.TL_chatAdminRights adminRights; + String rank; if (participant instanceof TLRPC.ChannelParticipant) { TLRPC.ChannelParticipant channelParticipant = (TLRPC.ChannelParticipant) participant; userId = channelParticipant.user_id; @@ -1057,6 +1260,7 @@ public class ChatUsersActivity extends BaseFragment implements NotificationCente bannedRights = channelParticipant.banned_rights; adminRights = channelParticipant.admin_rights; date = channelParticipant.date; + rank = channelParticipant.rank; } else if (participant instanceof TLRPC.ChatParticipant) { TLRPC.ChatParticipant chatParticipant = (TLRPC.ChatParticipant) participant; userId = chatParticipant.user_id; @@ -1064,18 +1268,20 @@ public class ChatUsersActivity extends BaseFragment implements NotificationCente canEdit = ChatObject.canAddAdmins(currentChat); bannedRights = null; adminRights = null; + rank = ""; } else { userId = 0; canEdit = false; bannedRights = null; adminRights = null; date = 0; + rank = null; } - if (userId == 0 || userId == UserConfig.getInstance(currentAccount).getClientUserId()) { + if (userId == 0 || userId == getUserConfig().getClientUserId()) { return false; } if (type == TYPE_USERS) { - final TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(userId); + final TLRPC.User user = getMessagesController().getUser(userId); boolean allowSetAdmin = ChatObject.canAddAdmins(currentChat) && (participant instanceof TLRPC.TL_channelParticipant || participant instanceof TLRPC.TL_channelParticipantBanned || participant instanceof TLRPC.TL_chatParticipant || canEdit); boolean canEditAdmin = !(participant instanceof TLRPC.TL_channelParticipantAdmin || participant instanceof TLRPC.TL_channelParticipantCreator || participant instanceof TLRPC.TL_chatParticipantCreator || participant instanceof TLRPC.TL_chatParticipantAdmin) || canEdit; boolean editingAdmin = participant instanceof TLRPC.TL_channelParticipantAdmin || participant instanceof TLRPC.TL_chatParticipantAdmin; @@ -1129,7 +1335,7 @@ public class ChatUsersActivity extends BaseFragment implements NotificationCente AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); builder.setItems(items.toArray(new CharSequence[actions.size()]), AndroidUtilities.toIntArray(icons), (dialogInterface, i) -> { if (actions.get(i) == 2) { - MessagesController.getInstance(currentAccount).deleteUserFromChat(chatId, user, null); + getMessagesController().deleteUserFromChat(chatId, user, null); removeParticipants(userId); if (searchItem != null && actionBar.isSearchFieldVisible()) { actionBar.closeSearchField(); @@ -1139,11 +1345,11 @@ public class ChatUsersActivity extends BaseFragment implements NotificationCente AlertDialog.Builder builder2 = new AlertDialog.Builder(getParentActivity()); builder2.setTitle(LocaleController.getString("AppName", R.string.AppName)); builder2.setMessage(LocaleController.formatString("AdminWillBeRemoved", R.string.AdminWillBeRemoved, ContactsController.formatName(user.first_name, user.last_name))); - builder2.setPositiveButton(LocaleController.getString("OK", R.string.OK), (dialog, which) -> openRightsEdit2(userId, date, participant, adminRights, bannedRights, canEditAdmin, actions.get(i), false)); + builder2.setPositiveButton(LocaleController.getString("OK", R.string.OK), (dialog, which) -> openRightsEdit2(userId, date, participant, adminRights, bannedRights, rank, canEditAdmin, actions.get(i), false)); builder2.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); showDialog(builder2.create()); } else { - openRightsEdit2(userId, date, participant, adminRights, bannedRights, canEditAdmin, actions.get(i), false); + openRightsEdit2(userId, date, participant, adminRights, bannedRights, rank, canEditAdmin, actions.get(i), false); } } }); @@ -1203,14 +1409,15 @@ public class ChatUsersActivity extends BaseFragment implements NotificationCente builder.setItems(items, icons, (dialogInterface, i) -> { if (type == TYPE_ADMIN) { if (i == 0 && items.length == 2) { - ChatRightsEditActivity fragment = new ChatRightsEditActivity(userId, chatId, adminRights, null, null, ChatRightsEditActivity.TYPE_ADMIN, true, false); + ChatRightsEditActivity fragment = new ChatRightsEditActivity(userId, chatId, adminRights, null, null, rank, ChatRightsEditActivity.TYPE_ADMIN, true, false); fragment.setDelegate(new ChatRightsEditActivity.ChatRightsEditActivityDelegate() { @Override - public void didSetRights(int rights, TLRPC.TL_chatAdminRights rightsAdmin, TLRPC.TL_chatBannedRights rightsBanned) { + public void didSetRights(int rights, TLRPC.TL_chatAdminRights rightsAdmin, TLRPC.TL_chatBannedRights rightsBanned, String rank) { if (participant instanceof TLRPC.ChannelParticipant) { TLRPC.ChannelParticipant channelParticipant = (TLRPC.ChannelParticipant) participant; channelParticipant.admin_rights = rightsAdmin; channelParticipant.banned_rights = rightsBanned; + channelParticipant.rank = rank; updateParticipantWithRights(channelParticipant, rightsAdmin, rightsBanned, 0, false); } } @@ -1222,20 +1429,21 @@ public class ChatUsersActivity extends BaseFragment implements NotificationCente }); presentFragment(fragment); } else { - MessagesController.getInstance(currentAccount).setUserAdminRole(chatId, MessagesController.getInstance(currentAccount).getUser(userId), new TLRPC.TL_chatAdminRights(), !isChannel, ChatUsersActivity.this, false); + getMessagesController().setUserAdminRole(chatId, getMessagesController().getUser(userId), new TLRPC.TL_chatAdminRights(), "", !isChannel, ChatUsersActivity.this, false); removeParticipants(userId); } } else if (type == TYPE_BANNED || type == TYPE_KICKED) { if (i == 0) { if (type == TYPE_KICKED) { - ChatRightsEditActivity fragment = new ChatRightsEditActivity(userId, chatId, null, defaultBannedRights, bannedRights, ChatRightsEditActivity.TYPE_BANNED, true, false); + ChatRightsEditActivity fragment = new ChatRightsEditActivity(userId, chatId, null, defaultBannedRights, bannedRights, rank, ChatRightsEditActivity.TYPE_BANNED, true, false); fragment.setDelegate(new ChatRightsEditActivity.ChatRightsEditActivityDelegate() { @Override - public void didSetRights(int rights, TLRPC.TL_chatAdminRights rightsAdmin, TLRPC.TL_chatBannedRights rightsBanned) { + public void didSetRights(int rights, TLRPC.TL_chatAdminRights rightsAdmin, TLRPC.TL_chatBannedRights rightsBanned, String rank) { if (participant instanceof TLRPC.ChannelParticipant) { TLRPC.ChannelParticipant channelParticipant = (TLRPC.ChannelParticipant) participant; channelParticipant.admin_rights = rightsAdmin; channelParticipant.banned_rights = rightsBanned; + channelParticipant.rank = rank; updateParticipantWithRights(channelParticipant, rightsAdmin, rightsBanned, 0, false); } } @@ -1247,22 +1455,22 @@ public class ChatUsersActivity extends BaseFragment implements NotificationCente }); presentFragment(fragment); } else if (type == TYPE_BANNED) { - TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(userId); - MessagesController.getInstance(currentAccount).addUserToChat(chatId, user, null, 0, null, ChatUsersActivity.this, null); + TLRPC.User user = getMessagesController().getUser(userId); + getMessagesController().addUserToChat(chatId, user, null, 0, null, ChatUsersActivity.this, null); } } else if (i == 1) { TLRPC.TL_channels_editBanned req = new TLRPC.TL_channels_editBanned(); - req.user_id = MessagesController.getInstance(currentAccount).getInputUser(userId); - req.channel = MessagesController.getInstance(currentAccount).getInputChannel(chatId); + req.user_id = getMessagesController().getInputUser(userId); + req.channel = getMessagesController().getInputChannel(chatId); req.banned_rights = new TLRPC.TL_chatBannedRights(); - ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> { + getConnectionsManager().sendRequest(req, (response, error) -> { if (response != null) { final TLRPC.Updates updates = (TLRPC.Updates) response; - MessagesController.getInstance(currentAccount).processUpdates(updates, false); + getMessagesController().processUpdates(updates, false); if (!updates.chats.isEmpty()) { AndroidUtilities.runOnUIThread(() -> { TLRPC.Chat chat = updates.chats.get(0); - MessagesController.getInstance(currentAccount).loadFullChat(chat.id, 0, true); + getMessagesController().loadFullChat(chat.id, 0, true); }, 1000); } } @@ -1276,7 +1484,7 @@ public class ChatUsersActivity extends BaseFragment implements NotificationCente } } else { if (i == 0) { - MessagesController.getInstance(currentAccount).deleteUserFromChat(chatId, MessagesController.getInstance(currentAccount).getUser(userId), null); + getMessagesController().deleteUserFromChat(chatId, getMessagesController().getUser(userId), null); } } }); @@ -1295,7 +1503,11 @@ public class ChatUsersActivity extends BaseFragment implements NotificationCente TLRPC.ChatFull chatFull = (TLRPC.ChatFull) args[0]; boolean byChannelUsers = (Boolean) args[2]; if (chatFull.id == chatId && (!byChannelUsers || !ChatObject.isChannel(currentChat))) { + boolean hadInfo = info != null; info = chatFull; + if (!hadInfo) { + selectedSlowmode = initialSlowmode = getCurrentSlowmode(); + } AndroidUtilities.runOnUIThread(() -> loadChatParticipants(0, 200)); } } @@ -1309,10 +1521,46 @@ public class ChatUsersActivity extends BaseFragment implements NotificationCente public void setDelegate(ChatUsersActivityDelegate chatUsersActivityDelegate) { delegate = chatUsersActivityDelegate; } + + private int getCurrentSlowmode() { + if (info != null) { + if (info.slowmode_seconds == 10) { + return 1; + } else if (info.slowmode_seconds == 30) { + return 2; + } else if (info.slowmode_seconds == 60) { + return 3; + } else if (info.slowmode_seconds == 5 * 60) { + return 4; + } else if (info.slowmode_seconds == 15 * 60) { + return 5; + } else if (info.slowmode_seconds == 60 * 60) { + return 6; + } + } + return 0; + } + + private int getSecondsForIndex(int index) { + if (index == 1) { + return 10; + } else if (index == 2) { + return 30; + } else if (index == 3) { + return 60; + } else if (index == 4) { + return 5 * 60; + } else if (index == 5) { + return 15 * 60; + } else if (index == 6) { + return 60 * 60; + } + return 0; + } private boolean checkDiscard() { String newBannedRights = ChatObject.getBannedRightsString(defaultBannedRights); - if (!newBannedRights.equals(initialBannedRights)) { + if (!newBannedRights.equals(initialBannedRights) || initialSlowmode != selectedSlowmode) { AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); builder.setTitle(LocaleController.getString("UserRestrictionsApplyChanges", R.string.UserRestrictionsApplyChanges)); if (isChannel) { @@ -1399,19 +1647,33 @@ public class ChatUsersActivity extends BaseFragment implements NotificationCente if (type != TYPE_KICKED) { return; } + if (!ChatObject.isChannel(currentChat) && selectedSlowmode != initialSlowmode && info != null) { + MessagesController.getInstance(currentAccount).convertToMegaGroup(getParentActivity(), chatId, this, param -> { + chatId = param; + currentChat = MessagesController.getInstance(currentAccount).getChat(param); + processDone(); + }); + return; + } String newBannedRights = ChatObject.getBannedRightsString(defaultBannedRights); if (!newBannedRights.equals(initialBannedRights)) { - MessagesController.getInstance(currentAccount).setDefaultBannedRole(chatId, defaultBannedRights, ChatObject.isChannel(currentChat), this); - TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(chatId); + getMessagesController().setDefaultBannedRole(chatId, defaultBannedRights, ChatObject.isChannel(currentChat), this); + TLRPC.Chat chat = getMessagesController().getChat(chatId); if (chat != null) { chat.default_banned_rights = defaultBannedRights; } } + if (selectedSlowmode != initialSlowmode && info != null) { + getMessagesController().setChannelSlowMode(chatId, info.slowmode_seconds); + } finishFragment(); } public void setInfo(TLRPC.ChatFull chatFull) { info = chatFull; + if (info != null) { + selectedSlowmode = initialSlowmode = getCurrentSlowmode(); + } } private int getChannelAdminParticipantType(TLObject participant) { @@ -1454,14 +1716,14 @@ public class ChatUsersActivity extends BaseFragment implements NotificationCente } } else if (type == TYPE_USERS) { if (info != null) { - int selfUserId = UserConfig.getInstance(currentAccount).clientUserId; + int selfUserId = getUserConfig().clientUserId; for (int a = 0, size = info.participants.participants.size(); a < size; a++) { TLRPC.ChatParticipant participant = info.participants.participants.get(a); if (selectType != 0 && participant.user_id == selfUserId) { continue; } if (selectType == 1) { - if (ContactsController.getInstance(currentAccount).isContact(participant.user_id)) { + if (getContactsController().isContact(participant.user_id)) { contacts.add(participant); contactsMap.put(participant.user_id, participant); } else { @@ -1469,11 +1731,11 @@ public class ChatUsersActivity extends BaseFragment implements NotificationCente participantsMap.put(participant.user_id, participant); } } else { - if (ContactsController.getInstance(currentAccount).isContact(participant.user_id)) { + if (getContactsController().isContact(participant.user_id)) { contacts.add(participant); contactsMap.put(participant.user_id, participant); } else { - TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(participant.user_id); + TLRPC.User user = getMessagesController().getUser(participant.user_id); if (user != null && user.bot) { bots.add(participant); botsMap.put(participant.user_id, participant); @@ -1502,7 +1764,7 @@ public class ChatUsersActivity extends BaseFragment implements NotificationCente listViewAdapter.notifyDataSetChanged(); } TLRPC.TL_channels_getParticipants req = new TLRPC.TL_channels_getParticipants(); - req.channel = MessagesController.getInstance(currentAccount).getInputChannel(chatId); + req.channel = getMessagesController().getInputChannel(chatId); if (type == TYPE_BANNED) { req.filter = new TLRPC.TL_channelParticipantsKicked(); } else if (type == TYPE_ADMIN) { @@ -1541,11 +1803,14 @@ public class ChatUsersActivity extends BaseFragment implements NotificationCente req.filter.q = ""; req.offset = offset; req.limit = count; - int reqId = ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> AndroidUtilities.runOnUIThread(() -> { + int reqId = getConnectionsManager().sendRequest(req, (response, error) -> AndroidUtilities.runOnUIThread(() -> { if (error == null) { TLRPC.TL_channels_channelParticipants res = (TLRPC.TL_channels_channelParticipants) response; - MessagesController.getInstance(currentAccount).putUsers(res.users, false); - int selfId = UserConfig.getInstance(currentAccount).getClientUserId(); + if (type == TYPE_ADMIN) { + getMessagesController().processLoadedAdminsResponse(chatId, (TLRPC.TL_channels_channelParticipants) response); + } + getMessagesController().putUsers(res.users, false); + int selfId = getUserConfig().getClientUserId(); if (selectType != 0) { for (int a = 0; a < res.participants.size(); a++) { if (res.participants.get(a).user_id == selfId) { @@ -1601,12 +1866,12 @@ public class ChatUsersActivity extends BaseFragment implements NotificationCente } try { if ((type == TYPE_BANNED || type == TYPE_KICKED || type == TYPE_USERS) && currentChat != null && currentChat.megagroup && info instanceof TLRPC.TL_channelFull && info.participants_count <= 200) { - int currentTime = ConnectionsManager.getInstance(currentAccount).getCurrentTime(); + int currentTime = getConnectionsManager().getCurrentTime(); Collections.sort(objects, (lhs, rhs) -> { TLRPC.ChannelParticipant p1 = (TLRPC.ChannelParticipant) lhs; TLRPC.ChannelParticipant p2 = (TLRPC.ChannelParticipant) rhs; - TLRPC.User user1 = MessagesController.getInstance(currentAccount).getUser(p1.user_id); - TLRPC.User user2 = MessagesController.getInstance(currentAccount).getUser(p2.user_id); + TLRPC.User user1 = getMessagesController().getUser(p1.user_id); + TLRPC.User user2 = getMessagesController().getUser(p2.user_id); int status1 = 0; int status2 = 0; if (user1 != null && user1.status != null) { @@ -1669,7 +1934,7 @@ public class ChatUsersActivity extends BaseFragment implements NotificationCente listViewAdapter.notifyDataSetChanged(); } })); - ConnectionsManager.getInstance(currentAccount).bindRequestToGuid(reqId, classGuid); + getConnectionsManager().bindRequestToGuid(reqId, classGuid); } } @@ -1677,7 +1942,7 @@ public class ChatUsersActivity extends BaseFragment implements NotificationCente public void onResume() { super.onResume(); AndroidUtilities.requestAdjustResize(getParentActivity(), classGuid); - AndroidUtilities.removeAdjustResize(getParentActivity(), classGuid); + //AndroidUtilities.removeAdjustResize(getParentActivity(), classGuid); if (listViewAdapter != null) { listViewAdapter.notifyDataSetChanged(); } @@ -1756,7 +2021,7 @@ public class ChatUsersActivity extends BaseFragment implements NotificationCente int kickedType; final ArrayList participantsCopy = !ChatObject.isChannel(currentChat) && info != null ? new ArrayList<>(info.participants.participants) : null; - final ArrayList contactsCopy = selectType == 1 ? new ArrayList<>(ContactsController.getInstance(currentAccount).contacts) : null; + final ArrayList contactsCopy = selectType == 1 ? new ArrayList<>(getContactsController().contacts) : null; searchAdapterHelper.queryServerSearch(query, selectType != 0, false, true, false, ChatObject.isChannel(currentChat) ? chatId : 0, false, type); if (participantsCopy != null || contactsCopy != null) { @@ -1782,8 +2047,8 @@ public class ChatUsersActivity extends BaseFragment implements NotificationCente if (participantsCopy != null) { for (int a = 0; a < participantsCopy.size(); a++) { TLRPC.ChatParticipant participant = participantsCopy.get(a); - TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(participant.user_id); - if (user.id == UserConfig.getInstance(currentAccount).getClientUserId()) { + TLRPC.User user = getMessagesController().getUser(participant.user_id); + if (user.id == getUserConfig().getClientUserId()) { continue; } @@ -1817,8 +2082,8 @@ public class ChatUsersActivity extends BaseFragment implements NotificationCente if (contactsCopy != null) { for (int a = 0; a < contactsCopy.size(); a++) { TLRPC.TL_contact contact = contactsCopy.get(a); - TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(contact.user_id); - if (user.id == UserConfig.getInstance(currentAccount).getClientUserId()) { + TLRPC.User user = getMessagesController().getUser(contact.user_id); + if (user.id == getUserConfig().getClientUserId()) { continue; } @@ -1990,9 +2255,9 @@ public class ChatUsersActivity extends BaseFragment implements NotificationCente if (object instanceof TLRPC.User) { user = (TLRPC.User) object; } else if (object instanceof TLRPC.ChannelParticipant) { - user = MessagesController.getInstance(currentAccount).getUser(((TLRPC.ChannelParticipant) object).user_id); + user = getMessagesController().getUser(((TLRPC.ChannelParticipant) object).user_id); } else if (object instanceof TLRPC.ChatParticipant) { - user = MessagesController.getInstance(currentAccount).getUser(((TLRPC.ChatParticipant) object).user_id); + user = getMessagesController().getUser(((TLRPC.ChatParticipant) object).user_id); } else { return; } @@ -2228,9 +2493,13 @@ public class ChatUsersActivity extends BaseFragment implements NotificationCente view.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); break; case 8: - default: view = new GraySectionCell(mContext); break; + case 9: + default: + view = new ChooseView(mContext); + view.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); + break; } return new RecyclerListView.Holder(view); } @@ -2278,14 +2547,14 @@ public class ChatUsersActivity extends BaseFragment implements NotificationCente creator = participant instanceof TLRPC.TL_chatParticipantCreator; admin = participant instanceof TLRPC.TL_chatParticipantAdmin; } - TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(userId); + TLRPC.User user = getMessagesController().getUser(userId); if (user != null) { if (type == TYPE_KICKED) { userCell.setData(user, null, formatUserPermissions(bannedRights), position != lastRow - 1); } else if (type == TYPE_BANNED) { String role = null; if (banned) { - TLRPC.User user1 = MessagesController.getInstance(currentAccount).getUser(kickedBy); + TLRPC.User user1 = getMessagesController().getUser(kickedBy); if (user1 != null) { role = LocaleController.formatString("UserRemovedBy", R.string.UserRemovedBy, ContactsController.formatName(user1.first_name, user1.last_name)); } @@ -2296,7 +2565,7 @@ public class ChatUsersActivity extends BaseFragment implements NotificationCente if (creator) { role = LocaleController.getString("ChannelCreator", R.string.ChannelCreator); } else if (admin) { - TLRPC.User user1 = MessagesController.getInstance(currentAccount).getUser(promotedBy); + TLRPC.User user1 = getMessagesController().getUser(promotedBy); if (user1 != null) { if (user1.id == user.id) { role = LocaleController.getString("ChannelAdministrator", R.string.ChannelAdministrator); @@ -2349,6 +2618,19 @@ public class ChatUsersActivity extends BaseFragment implements NotificationCente } privacyCell.setBackgroundDrawable(Theme.getThemedDrawable(mContext, R.drawable.greydivider_bottom, Theme.key_windowBackgroundGrayShadow)); } + } else if (position == slowmodeInfoRow) { + privacyCell.setBackgroundDrawable(Theme.getThemedDrawable(mContext, R.drawable.greydivider, Theme.key_windowBackgroundGrayShadow)); + if (info == null || info.slowmode_seconds == 0) { + privacyCell.setText(LocaleController.getString("SlowmodeInfoOff", R.string.SlowmodeInfoOff)); + } else { + if (info.slowmode_seconds < 60) { + privacyCell.setText(LocaleController.formatString("SlowmodeInfoSelected", R.string.SlowmodeInfoSelected, LocaleController.formatPluralString("Seconds", info.slowmode_seconds))); + } else if (info.slowmode_seconds < 60 * 60) { + privacyCell.setText(LocaleController.formatString("SlowmodeInfoSelected", R.string.SlowmodeInfoSelected, LocaleController.formatPluralString("Minutes", info.slowmode_seconds / 60))); + } else { + privacyCell.setText(LocaleController.formatString("SlowmodeInfoSelected", R.string.SlowmodeInfoSelected, LocaleController.formatPluralString("Hours", info.slowmode_seconds / 60 / 60))); + } + } } break; case 2: @@ -2357,7 +2639,7 @@ public class ChatUsersActivity extends BaseFragment implements NotificationCente if (position == addNewRow) { if (type == TYPE_KICKED) { actionCell.setColors(Theme.key_windowBackgroundWhiteBlueIcon, Theme.key_windowBackgroundWhiteBlueButton); - actionCell.setText(LocaleController.getString("ChannelAddException", R.string.ChannelAddException), null, R.drawable.actions_removed, participantsStartRow != -1); + actionCell.setText(LocaleController.getString("ChannelAddException", R.string.ChannelAddException), null, R.drawable.actions_addmember2, participantsStartRow != -1); } else if (type == TYPE_BANNED) { actionCell.setText(LocaleController.getString("ChannelBlockUser", R.string.ChannelBlockUser), null, R.drawable.actions_removed, false); } else if (type == TYPE_ADMIN) { @@ -2399,6 +2681,8 @@ public class ChatUsersActivity extends BaseFragment implements NotificationCente } } else if (position == permissionsSectionRow) { headerCell.setText(LocaleController.getString("ChannelPermissionsHeader", R.string.ChannelPermissionsHeader)); + } else if (position == slowmodeRow) { + headerCell.setText(LocaleController.getString("Slowmode", R.string.Slowmode)); } break; case 6: @@ -2481,9 +2765,9 @@ public class ChatUsersActivity extends BaseFragment implements NotificationCente return 0; } else if (position == addNewSectionRow || position == participantsDividerRow || position == participantsDivider2Row) { return 3; - } else if (position == restricted1SectionRow || position == permissionsSectionRow) { + } else if (position == restricted1SectionRow || position == permissionsSectionRow || position == slowmodeRow) { return 5; - } else if (position == participantsInfoRow) { + } else if (position == participantsInfoRow || position == slowmodeInfoRow) { return 1; } else if (position == blockedEmptyRow) { return 4; @@ -2494,6 +2778,8 @@ public class ChatUsersActivity extends BaseFragment implements NotificationCente return 7; } else if (position == membersHeaderRow || position == contactsHeaderRow || position == botHeaderRow) { return 8; + } else if (position == slowmodeSelectRow) { + return 9; } return 0; } @@ -2525,7 +2811,7 @@ public class ChatUsersActivity extends BaseFragment implements NotificationCente }; return new ThemeDescription[]{ - new ThemeDescription(listView, ThemeDescription.FLAG_CELLBACKGROUNDCOLOR, new Class[]{HeaderCell.class, ManageChatUserCell.class, ManageChatTextCell.class, TextCheckCell2.class, TextSettingsCell.class}, null, null, null, Theme.key_windowBackgroundWhite), + new ThemeDescription(listView, ThemeDescription.FLAG_CELLBACKGROUNDCOLOR, new Class[]{HeaderCell.class, ManageChatUserCell.class, ManageChatTextCell.class, TextCheckCell2.class, TextSettingsCell.class, ChooseView.class}, null, null, null, Theme.key_windowBackgroundWhite), new ThemeDescription(fragmentView, ThemeDescription.FLAG_BACKGROUND, null, null, null, null, Theme.key_windowBackgroundGray), new ThemeDescription(actionBar, ThemeDescription.FLAG_BACKGROUND, null, null, null, null, Theme.key_actionBarDefault), diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/AlertsCreator.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/AlertsCreator.java index 2e8c0df7f..611735eb8 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/AlertsCreator.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/AlertsCreator.java @@ -78,6 +78,7 @@ import org.telegram.ui.ReportOtherActivity; import java.util.ArrayList; import java.util.Calendar; import java.util.Locale; +import java.util.concurrent.CountDownLatch; public class AlertsCreator { @@ -101,10 +102,11 @@ public class AlertsCreator { request instanceof TLRPC.TL_messages_addChatUser || request instanceof TLRPC.TL_messages_startBot || request instanceof TLRPC.TL_channels_editBanned || - request instanceof TLRPC.TL_messages_editChatDefaultBannedRights|| - request instanceof TLRPC.TL_messages_editChatAdmin) { + request instanceof TLRPC.TL_messages_editChatDefaultBannedRights || + request instanceof TLRPC.TL_messages_editChatAdmin || + request instanceof TLRPC.TL_messages_migrateChat) { if (fragment != null) { - AlertsCreator.showAddUserAlert(error.text, fragment, (Boolean) args[0]); + AlertsCreator.showAddUserAlert(error.text, fragment, args != null && args.length > 0 ? (Boolean) args[0] : false); } else { if (error.text.equals("PEER_FLOOD")) { NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.needShowAlert, 1); @@ -388,22 +390,53 @@ public class AlertsCreator { return builder; } + public static boolean checkSlowMode(Context context, int currentAccount, long did, boolean few) { + int lowerId = (int) did; + if (lowerId < 0) { + TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(-lowerId); + if (chat != null && chat.slowmode_enabled && !ChatObject.hasAdminRights(chat)) { + if (!few) { + TLRPC.ChatFull chatFull = MessagesController.getInstance(currentAccount).getChatFull(chat.id); + if (chatFull == null) { + chatFull = MessagesStorage.getInstance(currentAccount).loadChatInfo(chat.id, new CountDownLatch(1), false, false); + } + if (chatFull != null && chatFull.slowmode_next_send_date >= ConnectionsManager.getInstance(currentAccount).getCurrentTime()) { + few = true; + } + } + if (few) { + AlertsCreator.createSimpleAlert(context, chat.title, LocaleController.getString("SlowmodeSendError", R.string.SlowmodeSendError)).show(); + return true; + } + } + } + return false; + } + public static AlertDialog.Builder createSimpleAlert(Context context, final String text) { + return createSimpleAlert(context, null, text); + } + + public static AlertDialog.Builder createSimpleAlert(Context context, final String title, final String text) { if (text == null) { return null; } AlertDialog.Builder builder = new AlertDialog.Builder(context); - builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); + builder.setTitle(title == null ? LocaleController.getString("AppName", R.string.AppName) : title); builder.setMessage(text); builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), null); return builder; } public static Dialog showSimpleAlert(BaseFragment baseFragment, final String text) { + return showSimpleAlert(baseFragment, null, text); + } + + public static Dialog showSimpleAlert(BaseFragment baseFragment, final String title, final String text) { if (text == null || baseFragment == null || baseFragment.getParentActivity() == null) { return null; } - AlertDialog.Builder builder = createSimpleAlert(baseFragment.getParentActivity(), text); + AlertDialog.Builder builder = createSimpleAlert(baseFragment.getParentActivity(), title, text); Dialog dialog = builder.create(); baseFragment.showDialog(dialog); return dialog; @@ -1646,15 +1679,13 @@ public class AlertsCreator { public static Dialog createFreeSpaceDialog(final LaunchActivity parentActivity) { final int[] selected = new int[1]; - SharedPreferences preferences = MessagesController.getGlobalMainSettings(); - int keepMedia = preferences.getInt("keep_media", 2); - if (keepMedia == 2) { + if (SharedConfig.keepMedia == 2) { selected[0] = 3; - } else if (keepMedia == 0) { + } else if (SharedConfig.keepMedia == 0) { selected[0] = 1; - } else if (keepMedia == 1) { + } else if (SharedConfig.keepMedia == 1) { selected[0] = 2; - } else if (keepMedia == 3) { + } else if (SharedConfig.keepMedia == 3) { selected[0] = 0; } @@ -1707,7 +1738,7 @@ public class AlertsCreator { builder.setTitle(LocaleController.getString("LowDiskSpaceTitle", R.string.LowDiskSpaceTitle)); builder.setMessage(LocaleController.getString("LowDiskSpaceMessage", R.string.LowDiskSpaceMessage)); builder.setView(linearLayout); - builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), (dialog, which) -> MessagesController.getGlobalMainSettings().edit().putInt("keep_media", selected[0]).commit()); + builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), (dialog, which) -> SharedConfig.setKeepMedia(selected[0])); builder.setNeutralButton(LocaleController.getString("ClearMediaCache", R.string.ClearMediaCache), (dialog, which) -> parentActivity.presentFragment(new CacheControlActivity())); return builder.create(); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/AnimatedFileDrawable.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/AnimatedFileDrawable.java index 9bfd4838c..6ae701233 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/AnimatedFileDrawable.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/AnimatedFileDrawable.java @@ -37,11 +37,11 @@ import java.util.concurrent.TimeUnit; public class AnimatedFileDrawable extends BitmapDrawable implements Animatable { - private static native long createDecoder(String src, int[] params, int account, long streamFileSize, Object readCallback); + private static native long createDecoder(String src, int[] params, int account, long streamFileSize, Object readCallback, boolean preview); private static native void destroyDecoder(long ptr); private static native void stopDecoder(long ptr); - private static native int getVideoFrame(long ptr, Bitmap bitmap, int[] params, int stride); - private static native void seekToMs(long ptr, long ms); + private static native int getVideoFrame(long ptr, Bitmap bitmap, int[] params, int stride, boolean preview); + private static native void seekToMs(long ptr, long ms, boolean precise); private static native void prepareToSeek(long ptr); public static native void getVideoInfo(String src, int[] params); @@ -102,8 +102,8 @@ public class AnimatedFileDrawable extends BitmapDrawable implements Animatable { public volatile long nativePtr; private DispatchQueue decodeQueue; - private View parentView = null; - private View secondParentView = null; + private View parentView; + private View secondParentView; private AnimatedFileDrawableStream stream; @@ -206,7 +206,7 @@ public class AnimatedFileDrawable extends BitmapDrawable implements Animatable { public void run() { if (!isRecycled) { if (!decoderCreated && nativePtr == 0) { - nativePtr = createDecoder(path.getAbsolutePath(), metaData, currentAccount, streamFileSize, stream); + nativePtr = createDecoder(path.getAbsolutePath(), metaData, currentAccount, streamFileSize, stream, false); decoderCreated = true; } try { @@ -232,11 +232,11 @@ public class AnimatedFileDrawable extends BitmapDrawable implements Animatable { if (stream != null) { stream.reset(); } - seekToMs(nativePtr, seekTo); + seekToMs(nativePtr, seekTo, true); } if (backgroundBitmap != null) { lastFrameDecodeTime = System.currentTimeMillis(); - if (getVideoFrame(nativePtr, backgroundBitmap, metaData, backgroundBitmap.getRowBytes()) == 0) { + if (getVideoFrame(nativePtr, backgroundBitmap, metaData, backgroundBitmap.getRowBytes(), false) == 0) { AndroidUtilities.runOnUIThread(uiRunnableNoFrame); return; } @@ -265,20 +265,36 @@ public class AnimatedFileDrawable extends BitmapDrawable implements Animatable { } }; - public AnimatedFileDrawable(File file, boolean createDecoder, long streamSize, TLRPC.Document document, Object parentObject, int account) { + public AnimatedFileDrawable(File file, boolean createDecoder, long streamSize, TLRPC.Document document, Object parentObject, int account, boolean preview) { path = file; streamFileSize = streamSize; currentAccount = account; getPaint().setFlags(Paint.FILTER_BITMAP_FLAG); if (streamSize != 0 && document != null) { - stream = new AnimatedFileDrawableStream(document, parentObject, account); + stream = new AnimatedFileDrawableStream(document, parentObject, account, preview); } if (createDecoder) { - nativePtr = createDecoder(file.getAbsolutePath(), metaData, currentAccount, streamFileSize, stream); + nativePtr = createDecoder(file.getAbsolutePath(), metaData, currentAccount, streamFileSize, stream, preview); decoderCreated = true; } } + public Bitmap getFrameAtTime(long ms) { + if (!decoderCreated || nativePtr == 0) { + return null; + } + if (stream != null) { + stream.cancel(false); + stream.reset(); + } + seekToMs(nativePtr, ms, false); + if (backgroundBitmap == null) { + backgroundBitmap = Bitmap.createBitmap(metaData[0], metaData[1], Bitmap.Config.ARGB_8888); + } + int result = getVideoFrame(nativePtr, backgroundBitmap, metaData, backgroundBitmap.getRowBytes(), true); + return result != 0 ? backgroundBitmap : null; + } + public void setParentView(View view) { if (parentView != null) { return; @@ -345,6 +361,19 @@ public class AnimatedFileDrawable extends BitmapDrawable implements Animatable { } } + public void resetStream(boolean stop) { + if (stream != null) { + stream.cancel(true); + } + if (nativePtr != 0) { + if (stop) { + stopDecoder(nativePtr); + } else { + prepareToSeek(nativePtr); + } + } + } + protected static void runOnUiThread(Runnable task) { if (Looper.myLooper() == uiHandler.getLooper()) { task.run(); @@ -606,9 +635,9 @@ public class AnimatedFileDrawable extends BitmapDrawable implements Animatable { public AnimatedFileDrawable makeCopy() { AnimatedFileDrawable drawable; if (stream != null) { - drawable = new AnimatedFileDrawable(path, false, streamFileSize, stream.getDocument(), stream.getParentObject(), currentAccount); + drawable = new AnimatedFileDrawable(path, false, streamFileSize, stream.getDocument(), stream.getParentObject(), currentAccount, stream != null && stream.isPreview()); } else { - drawable = new AnimatedFileDrawable(path, false, streamFileSize, null, null, currentAccount); + drawable = new AnimatedFileDrawable(path, false, streamFileSize, null, null, currentAccount, stream != null && stream.isPreview()); } drawable.metaData[0] = metaData[0]; drawable.metaData[1] = metaData[1]; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/AudioPlayerAlert.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/AudioPlayerAlert.java index b3a09d477..8c6a775cc 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/AudioPlayerAlert.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/AudioPlayerAlert.java @@ -299,11 +299,11 @@ public class AudioPlayerAlert extends BottomSheet implements NotificationCenter. actionBar.addView(avatarContainer, 0, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.MATCH_PARENT, Gravity.TOP | Gravity.LEFT, 56, 0, 40, 0)); ActionBarMenu menu = actionBar.createMenu(); - menu.setContentDescription(LocaleController.getString("AccDescrMoreOptions", R.string.AccDescrMoreOptions)); menuItem = menu.addItem(0, R.drawable.ic_ab_other); menuItem.addSubItem(1, R.drawable.msg_forward, LocaleController.getString("Forward", R.string.Forward)); menuItem.addSubItem(2, R.drawable.msg_shareout, LocaleController.getString("ShareFile", R.string.ShareFile)); menuItem.addSubItem(4, R.drawable.msg_message, LocaleController.getString("ShowInChat", R.string.ShowInChat)); + menuItem.setContentDescription(LocaleController.getString("AccDescrMoreOptions", R.string.AccDescrMoreOptions)); menuItem.setTranslationX(AndroidUtilities.dp(48)); menuItem.setAlpha(0.0f); @@ -449,9 +449,9 @@ public class AudioPlayerAlert extends BottomSheet implements NotificationCenter. isInFullMode = !isInFullMode; listView.setScrollEnabled(false); if (isInFullMode) { - shuffleButton.setAdditionalOffset(-AndroidUtilities.dp(20 + 48)); + shuffleButton.setAdditionalYOffset(-AndroidUtilities.dp(20 + 48)); } else { - shuffleButton.setAdditionalOffset(-AndroidUtilities.dp(10)); + shuffleButton.setAdditionalYOffset(-AndroidUtilities.dp(10)); } }); @@ -473,7 +473,7 @@ public class AudioPlayerAlert extends BottomSheet implements NotificationCenter. optionsButton = new ActionBarMenuItem(context, null, 0, Theme.getColor(Theme.key_player_actionBarItems)); optionsButton.setLongClickEnabled(false); optionsButton.setIcon(R.drawable.ic_ab_other); - optionsButton.setAdditionalOffset(-AndroidUtilities.dp(120)); + optionsButton.setAdditionalYOffset(-AndroidUtilities.dp(120)); playerLayout.addView(optionsButton, LayoutHelper.createFrame(40, 40, Gravity.TOP | Gravity.RIGHT, 0, 19, 10, 0)); optionsButton.addSubItem(1, R.drawable.msg_forward, LocaleController.getString("Forward", R.string.Forward)); optionsButton.addSubItem(2, R.drawable.msg_shareout, LocaleController.getString("ShareFile", R.string.ShareFile)); @@ -519,7 +519,7 @@ public class AudioPlayerAlert extends BottomSheet implements NotificationCenter. buttons[0] = shuffleButton = new ActionBarMenuItem(context, null, 0, 0); shuffleButton.setLongClickEnabled(false); - shuffleButton.setAdditionalOffset(-AndroidUtilities.dp(10)); + shuffleButton.setAdditionalYOffset(-AndroidUtilities.dp(10)); bottomView.addView(shuffleButton, LayoutHelper.createFrame(48, 48, Gravity.LEFT | Gravity.TOP)); shuffleButton.setOnClickListener(v -> shuffleButton.toggleSubMenu()); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/BlockingUpdateView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/BlockingUpdateView.java index fbd12f3dc..611757886 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/BlockingUpdateView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/BlockingUpdateView.java @@ -34,6 +34,7 @@ import org.telegram.messenger.NotificationCenter; import org.telegram.messenger.R; import org.telegram.messenger.UserConfig; import org.telegram.messenger.browser.Browser; +import org.telegram.tgnet.ConnectionsManager; import org.telegram.tgnet.TLRPC; import org.telegram.ui.ActionBar.AlertDialog; import org.telegram.ui.ActionBar.Theme; @@ -291,7 +292,7 @@ public class BlockingUpdateView extends FrameLayout implements NotificationCente progressAnimation.start(); } - public void show(int account, TLRPC.TL_help_appUpdate update) { + public void show(int account, TLRPC.TL_help_appUpdate update, boolean check) { pressCount = 0; appUpdate = update; accountNum = account; @@ -312,5 +313,28 @@ public class BlockingUpdateView extends FrameLayout implements NotificationCente NotificationCenter.getInstance(accountNum).addObserver(this, NotificationCenter.fileDidLoad); NotificationCenter.getInstance(accountNum).addObserver(this, NotificationCenter.fileDidFailedLoad); NotificationCenter.getInstance(accountNum).addObserver(this, NotificationCenter.FileLoadProgressChanged); + if (check) { + TLRPC.TL_help_getAppUpdate req = new TLRPC.TL_help_getAppUpdate(); + try { + req.source = ApplicationLoader.applicationContext.getPackageManager().getInstallerPackageName(ApplicationLoader.applicationContext.getPackageName()); + } catch (Exception ignore) { + + } + if (req.source == null) { + req.source = ""; + } + ConnectionsManager.getInstance(accountNum).sendRequest(req, (response, error) -> { + AndroidUtilities.runOnUIThread(() -> { + if (response instanceof TLRPC.TL_help_appUpdate) { + final TLRPC.TL_help_appUpdate res = (TLRPC.TL_help_appUpdate) response; + if (!res.can_not_skip) { + setVisibility(GONE); + UserConfig.getInstance(0).pendingAppUpdate = null; + UserConfig.getInstance(0).saveConfig(false); + } + } + }); + }); + } } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatActivityEnterView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatActivityEnterView.java index 0e389f2fd..41457a525 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatActivityEnterView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatActivityEnterView.java @@ -20,6 +20,7 @@ import android.content.Context; import android.content.SharedPreferences; import android.content.pm.PackageManager; import android.graphics.Canvas; +import android.graphics.Color; import android.graphics.ColorFilter; import android.graphics.Paint; import android.graphics.PixelFormat; @@ -40,6 +41,8 @@ import androidx.core.os.BuildCompat; import androidx.core.view.ViewCompat; import androidx.core.view.accessibility.AccessibilityNodeInfoCompat; import androidx.customview.widget.ExploreByTouchHelper; + +import android.os.SystemClock; import android.text.Editable; import android.text.InputFilter; import android.text.Layout; @@ -54,6 +57,7 @@ import android.view.HapticFeedbackConstants; import android.view.KeyEvent; import android.view.MotionEvent; import android.view.View; +import android.view.WindowManager; import android.view.accessibility.AccessibilityEvent; import android.view.accessibility.AccessibilityManager; import android.view.accessibility.AccessibilityNodeInfo; @@ -64,7 +68,6 @@ import android.view.inputmethod.InputConnection; import android.widget.FrameLayout; import android.widget.ImageView; import android.widget.LinearLayout; -import android.widget.PopupWindow; import android.widget.TextView; import android.widget.Toast; @@ -83,6 +86,7 @@ import org.telegram.messenger.FileLog; import org.telegram.messenger.NotificationCenter; import org.telegram.messenger.R; import org.telegram.messenger.SharedConfig; +import org.telegram.messenger.UserObject; import org.telegram.messenger.VideoEditedInfo; import org.telegram.messenger.camera.CameraController; import org.telegram.tgnet.ConnectionsManager; @@ -90,7 +94,10 @@ import org.telegram.tgnet.TLRPC; import org.telegram.messenger.UserConfig; import org.telegram.ui.ActionBar.ActionBar; import org.telegram.messenger.ApplicationLoader; +import org.telegram.ui.ActionBar.ActionBarMenuSubItem; +import org.telegram.ui.ActionBar.ActionBarPopupWindow; import org.telegram.ui.ActionBar.AlertDialog; +import org.telegram.ui.ActionBar.SimpleTextView; import org.telegram.ui.ActionBar.Theme; import org.telegram.ui.ChatActivity; import org.telegram.ui.DialogsActivity; @@ -125,6 +132,10 @@ public class ChatActivityEnterView extends FrameLayout implements NotificationCe void needStartRecordAudio(int state); void needShowMediaBanHint(); void onStickersExpandedChange(); + void onUpdateSlowModeButton(View button, boolean show, CharSequence time); + default void scrollToSendingMessage() { + + } } private int currentAccount = UserConfig.selectedAccount; @@ -197,7 +208,15 @@ public class ChatActivityEnterView extends FrameLayout implements NotificationCe }; private EditTextCaption messageEditText; - private ImageView sendButton; + private SimpleTextView slowModeButton; + private int slowModeTimer; + private Runnable updateSlowModeRunnable; + private View sendButton; + private Drawable sendButtonDrawable; + private Drawable inactinveSendButtonDrawable; + private Drawable sendButtonInverseDrawable; + private ActionBarPopupWindow sendPopupWindow; + private ActionBarPopupWindow.ActionBarPopupWindowLayout sendPopupLayout; private ImageView cancelBotButton; private ImageView[] emojiButton = new ImageView[2]; private ImageView expandStickersButton; @@ -240,7 +259,6 @@ public class ChatActivityEnterView extends FrameLayout implements NotificationCe private ContextProgressView doneButtonProgress; private View topView; private View topLineView; - private PopupWindow botKeyboardPopup; private BotKeyboardView botKeyboardView; private ImageView notifyButton; private RecordCircle recordCircle; @@ -827,6 +845,8 @@ public class ChatActivityEnterView extends FrameLayout implements NotificationCe NotificationCenter.getInstance(currentAccount).addObserver(this, NotificationCenter.messagePlayingDidReset); NotificationCenter.getInstance(currentAccount).addObserver(this, NotificationCenter.messagePlayingProgressDidChanged); NotificationCenter.getInstance(currentAccount).addObserver(this, NotificationCenter.featuredStickersDidLoad); + NotificationCenter.getInstance(currentAccount).addObserver(this, NotificationCenter.messageReceivedByServer); + NotificationCenter.getInstance(currentAccount).addObserver(this, NotificationCenter.sendingMessagesChanged); NotificationCenter.getGlobalInstance().addObserver(this, NotificationCenter.emojiDidLoad); parentActivity = context; @@ -838,6 +858,8 @@ public class ChatActivityEnterView extends FrameLayout implements NotificationCe textFieldContainer = new LinearLayout(context); textFieldContainer.setOrientation(LinearLayout.HORIZONTAL); + textFieldContainer.setClipChildren(false); + textFieldContainer.setClipToPadding(false); addView(textFieldContainer, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.LEFT | Gravity.BOTTOM, 0, 2, 0, 0)); FrameLayout frameLayout = new FrameLayout(context); @@ -946,7 +968,7 @@ public class ChatActivityEnterView extends FrameLayout implements NotificationCe } }); TLRPC.EncryptedChat encryptedChat = parentFragment != null ? parentFragment.getCurrentEncryptedChat() : null; - messageEditText.setAllowTextEntitiesIntersection(encryptedChat != null && AndroidUtilities.getPeerLayerVersion(encryptedChat.layer) >= 101); + messageEditText.setAllowTextEntitiesIntersection(encryptedChat == null || encryptedChat != null && AndroidUtilities.getPeerLayerVersion(encryptedChat.layer) >= 101); updateFieldHint(); int flags = EditorInfo.IME_FLAG_NO_EXTRACT_UI; if (encryptedChat != null) { @@ -986,7 +1008,7 @@ public class ChatActivityEnterView extends FrameLayout implements NotificationCe } return true; } else if (i == KeyEvent.KEYCODE_ENTER && (ctrlPressed || sendByEnter) && keyEvent.getAction() == KeyEvent.ACTION_DOWN && editingMessageObject == null) { - sendMessage(); + sendMessage(false); return true; } else if (i == KeyEvent.KEYCODE_CTRL_LEFT || i == KeyEvent.KEYCODE_CTRL_RIGHT) { ctrlPressed = keyEvent.getAction() == KeyEvent.ACTION_DOWN; @@ -1002,11 +1024,11 @@ public class ChatActivityEnterView extends FrameLayout implements NotificationCe @Override public boolean onEditorAction(TextView textView, int i, KeyEvent keyEvent) { if (i == EditorInfo.IME_ACTION_SEND) { - sendMessage(); + sendMessage(false); return true; } else if (keyEvent != null && i == EditorInfo.IME_NULL) { if ((ctrlPressed || sendByEnter) && keyEvent.getAction() == KeyEvent.ACTION_DOWN && editingMessageObject == null) { - sendMessage(); + sendMessage(false); return true; } else if (i == KeyEvent.KEYCODE_CTRL_LEFT || i == KeyEvent.KEYCODE_CTRL_RIGHT) { ctrlPressed = keyEvent.getAction() == KeyEvent.ACTION_DOWN; @@ -1046,9 +1068,9 @@ public class ChatActivityEnterView extends FrameLayout implements NotificationCe int currentTime = ConnectionsManager.getInstance(currentAccount).getCurrentTime(); TLRPC.User currentUser = null; if ((int) dialog_id > 0) { - currentUser = MessagesController.getInstance(currentAccount).getUser((int) dialog_id); + currentUser = accountInstance.getMessagesController().getUser((int) dialog_id); } - if (currentUser != null && (currentUser.id == UserConfig.getInstance(currentAccount).getClientUserId() || currentUser.status != null && currentUser.status.expires < currentTime && !MessagesController.getInstance(currentAccount).onlinePrivacy.containsKey(currentUser.id))) { + if (currentUser != null && (currentUser.id == UserConfig.getInstance(currentAccount).getClientUserId() || currentUser.status != null && currentUser.status.expires < currentTime && !accountInstance.getMessagesController().onlinePrivacy.containsKey(currentUser.id))) { return; } lastTypingTimeSend = System.currentTimeMillis(); @@ -1064,7 +1086,7 @@ public class ChatActivityEnterView extends FrameLayout implements NotificationCe return; } if (sendByEnter && editable.length() > 0 && editable.charAt(editable.length() - 1) == '\n' && editingMessageObject == null) { - sendMessage(); + sendMessage(false); } if (processChange) { ImageSpan[] spans = editable.getSpans(0, editable.length(), ImageSpan.class); @@ -1323,6 +1345,8 @@ public class ChatActivityEnterView extends FrameLayout implements NotificationCe recordTimeContainer.addView(recordTimeText, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_VERTICAL, 6, 0, 0, 0)); sendButtonContainer = new FrameLayout(context); + sendButtonContainer.setClipChildren(false); + sendButtonContainer.setClipToPadding(false); textFieldContainer.addView(sendButtonContainer, LayoutHelper.createLinear(48, 48, Gravity.BOTTOM)); audioVideoButtonContainer = new FrameLayout(context); @@ -1494,18 +1518,207 @@ public class ChatActivityEnterView extends FrameLayout implements NotificationCe } }); - sendButton = new ImageView(context); + + sendButtonDrawable = context.getResources().getDrawable(R.drawable.ic_send).mutate(); + sendButtonInverseDrawable = context.getResources().getDrawable(R.drawable.ic_send).mutate(); + inactinveSendButtonDrawable = context.getResources().getDrawable(R.drawable.ic_send).mutate(); + sendButton = new View(context) { + + private int drawableColor; + private float animationProgress; + private float animateBounce; + private long lastAnimationTime; + private float animationDuration; + + @Override + protected void onDraw(Canvas canvas) { + int x = (getMeasuredWidth() - sendButtonDrawable.getIntrinsicWidth()) / 2 + AndroidUtilities.dp(2); + int y = (getMeasuredHeight() - sendButtonDrawable.getIntrinsicHeight()) / 2; + + int color; + boolean showingPopup; + if (showingPopup = (sendPopupWindow != null && sendPopupWindow.isShowing())) { + color = Theme.getColor(Theme.key_chat_messagePanelBackground); + } else { + color = Theme.getColor(Theme.key_chat_messagePanelSend); + } + if (color != drawableColor) { + lastAnimationTime = SystemClock.uptimeMillis(); + if (showingPopup) { + animationProgress = 0.0f; + animationDuration = 200.0f; + } else if (drawableColor != 0) { + animationProgress = 0.0f; + animationDuration = 120.0f; + } else { + animationProgress = 1.0f; + } + drawableColor = color; + sendButtonDrawable.setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_chat_messagePanelSend), PorterDuff.Mode.MULTIPLY)); + int c = Theme.getColor(Theme.key_chat_messagePanelIcons); + inactinveSendButtonDrawable.setColorFilter(new PorterDuffColorFilter(Color.argb(0xb4, Color.red(c), Color.green(c), Color.blue(c)), PorterDuff.Mode.MULTIPLY)); + sendButtonInverseDrawable.setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_chat_messagePanelVoicePressed), PorterDuff.Mode.MULTIPLY)); + } + if (animationProgress < 1.0f) { + long newTime = SystemClock.uptimeMillis(); + long dt = newTime - lastAnimationTime; + animationProgress += dt / animationDuration; + if (animationProgress > 1.0f) { + animationProgress = 1.0f; + } + lastAnimationTime = newTime; + invalidate(); + } + if (!showingPopup) { + if (slowModeTimer == Integer.MAX_VALUE) { + inactinveSendButtonDrawable.setBounds(x, y, x + sendButtonDrawable.getIntrinsicWidth(), y + sendButtonDrawable.getIntrinsicHeight()); + inactinveSendButtonDrawable.draw(canvas); + } else { + sendButtonDrawable.setBounds(x, y, x + sendButtonDrawable.getIntrinsicWidth(), y + sendButtonDrawable.getIntrinsicHeight()); + sendButtonDrawable.draw(canvas); + } + } + if (showingPopup || animationProgress != 1.0f) { + Theme.dialogs_onlineCirclePaint.setColor(Theme.getColor(Theme.key_chat_messagePanelSend)); + int rad = AndroidUtilities.dp(20); + if (showingPopup) { + sendButtonInverseDrawable.setAlpha(255); + float p = animationProgress; + if (p <= 0.25f) { + float progress = p / 0.25f; + rad += AndroidUtilities.dp(2) * CubicBezierInterpolator.EASE_IN.getInterpolation(progress); + } else { + p -= 0.25f; + if (p <= 0.5f) { + float progress = p / 0.5f; + rad += AndroidUtilities.dp(2) - AndroidUtilities.dp(3) * CubicBezierInterpolator.EASE_IN.getInterpolation(progress); + } else { + p -= 0.5f; + float progress = p / 0.25f; + rad += -AndroidUtilities.dp(1) + AndroidUtilities.dp(1) * CubicBezierInterpolator.EASE_IN.getInterpolation(progress); + } + } + } else { + int alpha = (int) (255 * (1.0f - animationProgress)); + Theme.dialogs_onlineCirclePaint.setAlpha(alpha); + sendButtonInverseDrawable.setAlpha(alpha); + } + canvas.drawCircle(getMeasuredWidth() / 2, getMeasuredHeight() / 2, rad, Theme.dialogs_onlineCirclePaint); + sendButtonInverseDrawable.setBounds(x, y, x + sendButtonDrawable.getIntrinsicWidth(), y + sendButtonDrawable.getIntrinsicHeight()); + sendButtonInverseDrawable.draw(canvas); + } + } + }; sendButton.setVisibility(INVISIBLE); - sendButton.setScaleType(ImageView.ScaleType.CENTER_INSIDE); - sendButton.setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_chat_messagePanelSend), PorterDuff.Mode.MULTIPLY)); - sendButton.setImageResource(R.drawable.ic_send); + int color = Theme.getColor(Theme.key_chat_messagePanelSend); sendButton.setContentDescription(LocaleController.getString("Send", R.string.Send)); sendButton.setSoundEffectsEnabled(false); sendButton.setScaleX(0.1f); sendButton.setScaleY(0.1f); sendButton.setAlpha(0.0f); + if (Build.VERSION.SDK_INT >= 21) { + sendButton.setBackgroundDrawable(Theme.createSelectorDrawable(Color.argb(24, Color.red(color), Color.green(color), Color.blue(color)), 1)); + } sendButtonContainer.addView(sendButton, LayoutHelper.createFrame(48, 48)); - sendButton.setOnClickListener(view -> sendMessage()); + sendButton.setOnClickListener(view -> sendMessage(false)); + sendButton.setOnLongClickListener(view -> { + if (parentFragment == null) { + return false; + } + TLRPC.Chat chat = parentFragment.getCurrentChat(); + TLRPC.User user = parentFragment.getCurrentUser(); + if (slowModeTimer > 0 || parentFragment.getCurrentEncryptedChat() != null || ChatObject.isChannel(chat) && !chat.megagroup || UserObject.isUserSelf(user)) { + return false; + } + + if (sendPopupLayout == null) { + sendPopupLayout = new ActionBarPopupWindow.ActionBarPopupWindowLayout(parentActivity); + sendPopupLayout.setAnimationEnabled(false); + sendPopupLayout.setOnTouchListener(new OnTouchListener() { + + private android.graphics.Rect popupRect = new android.graphics.Rect(); + + @Override + public boolean onTouch(View v, MotionEvent event) { + if (event.getActionMasked() == MotionEvent.ACTION_DOWN) { + if (sendPopupWindow != null && sendPopupWindow.isShowing()) { + v.getHitRect(popupRect); + if (!popupRect.contains((int) event.getX(), (int) event.getY())) { + sendPopupWindow.dismiss(); + } + } + } + return false; + } + }); + sendPopupLayout.setDispatchKeyEventListener(keyEvent -> { + if (keyEvent.getKeyCode() == KeyEvent.KEYCODE_BACK && keyEvent.getRepeatCount() == 0 && sendPopupWindow != null && sendPopupWindow.isShowing()) { + sendPopupWindow.dismiss(); + } + }); + sendPopupLayout.setShowedFromBotton(false); + + ActionBarMenuSubItem cell = new ActionBarMenuSubItem(getContext()); + cell.setTextAndIcon(LocaleController.getString("SendWithoutSound", R.string.SendWithoutSound), R.drawable.input_notify_off); + cell.setMinimumWidth(AndroidUtilities.dp(196)); + sendPopupLayout.addView(cell, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 48, LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT)); + cell.setOnClickListener(v -> { + if (sendPopupWindow != null && sendPopupWindow.isShowing()) { + sendPopupWindow.dismiss(); + } + sendMessage(true); + }); + + sendPopupWindow = new ActionBarPopupWindow(sendPopupLayout, LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT) { + @Override + public void dismiss() { + super.dismiss(); + sendButton.invalidate(); + } + }; + sendPopupWindow.setAnimationEnabled(false); + sendPopupWindow.setAnimationStyle(R.style.PopupContextAnimation2); + sendPopupWindow.setOutsideTouchable(true); + sendPopupWindow.setClippingEnabled(true); + sendPopupWindow.setInputMethodMode(ActionBarPopupWindow.INPUT_METHOD_NOT_NEEDED); + sendPopupWindow.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED); + sendPopupWindow.getContentView().setFocusableInTouchMode(true); + } + + sendPopupLayout.measure(MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(1000), MeasureSpec.AT_MOST), MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(1000), MeasureSpec.AT_MOST)); + sendPopupWindow.setFocusable(true); + int[] location = new int[2]; + view.getLocationInWindow(location); + int y; + if (keyboardVisible && ChatActivityEnterView.this.getMeasuredHeight() > AndroidUtilities.dp(topView != null && topView.getVisibility() == VISIBLE ? 48 + 58 : 58)) { + y = location[1] + view.getMeasuredHeight(); + } else { + y = location[1] - sendPopupLayout.getMeasuredHeight() - AndroidUtilities.dp(2); + } + sendPopupWindow.showAtLocation(view, Gravity.LEFT | Gravity.TOP, location[0] + view.getMeasuredWidth() - sendPopupLayout.getMeasuredWidth() + AndroidUtilities.dp(8), y); + sendPopupWindow.dimBehind(); + sendButton.invalidate(); + view.performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP, HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING); + + return false; + }); + + slowModeButton = new SimpleTextView(context); + slowModeButton.setTextSize(18); + slowModeButton.setVisibility(INVISIBLE); + slowModeButton.setSoundEffectsEnabled(false); + slowModeButton.setScaleX(0.1f); + slowModeButton.setScaleY(0.1f); + slowModeButton.setAlpha(0.0f); + slowModeButton.setPadding(0, 0, AndroidUtilities.dp(13), 0); + slowModeButton.setGravity(Gravity.RIGHT | Gravity.CENTER_VERTICAL); + slowModeButton.setTextColor(Theme.getColor(Theme.key_chat_messagePanelIcons)); + sendButtonContainer.addView(slowModeButton, LayoutHelper.createFrame(64, 48, Gravity.RIGHT | Gravity.TOP)); + slowModeButton.setOnClickListener(v -> { + if (delegate != null) { + delegate.onUpdateSlowModeButton(slowModeButton, true, slowModeButton.getText()); + } + }); expandStickersButton = new ImageView(context); expandStickersButton.setPadding(0, 0, AndroidUtilities.dp(4), 0); @@ -1549,7 +1762,7 @@ public class ChatActivityEnterView extends FrameLayout implements NotificationCe Drawable drawable = Theme.createCircleDrawable(AndroidUtilities.dp(16), Theme.getColor(Theme.key_chat_messagePanelSend)); Drawable checkDrawable = context.getResources().getDrawable(R.drawable.input_done).mutate(); - checkDrawable.setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_chat_messagePanelBackground), PorterDuff.Mode.MULTIPLY)); + checkDrawable.setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_chat_messagePanelVoicePressed), PorterDuff.Mode.MULTIPLY)); CombinedDrawable combinedDrawable = new CombinedDrawable(drawable, checkDrawable, 0, AndroidUtilities.dp(1)); combinedDrawable.setCustomSize(AndroidUtilities.dp(32), AndroidUtilities.dp(32)); @@ -1616,7 +1829,7 @@ public class ChatActivityEnterView extends FrameLayout implements NotificationCe SharedPreferences preferences = MessagesController.getGlobalMainSettings(); boolean isChannel = false; if ((int) dialog_id < 0) { - TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(-(int) dialog_id); + TLRPC.Chat chat = accountInstance.getMessagesController().getChat(-(int) dialog_id); isChannel = ChatObject.isChannel(chat) && !chat.megagroup; } preferences.edit().putBoolean(isChannel ? "currentModeVideoChannel" : "currentModeVideo", visible).commit(); @@ -1688,6 +1901,56 @@ public class ChatActivityEnterView extends FrameLayout implements NotificationCe } } + public void setSlowModeTimer(int time) { + slowModeTimer = time; + updateSlowModeText(); + } + + public CharSequence getSlowModeTimer() { + return slowModeTimer > 0 ? slowModeButton.getText() : null; + } + + private void updateSlowModeText() { + int serverTime = ConnectionsManager.getInstance(currentAccount).getCurrentTime(); + AndroidUtilities.cancelRunOnUIThread(updateSlowModeRunnable); + updateSlowModeRunnable = null; + int currentTime; + boolean isUploading; + if (info != null && info.slowmode_seconds != 0 && info.slowmode_next_send_date <= serverTime && ( + (isUploading = SendMessagesHelper.getInstance(currentAccount).isUploadingMessageIdDialog(dialog_id)) || + SendMessagesHelper.getInstance(currentAccount).isSendingMessageIdDialog(dialog_id))) { + TLRPC.Chat chat = accountInstance.getMessagesController().getChat(info.id); + if (!ChatObject.hasAdminRights(chat)) { + currentTime = info.slowmode_seconds; + slowModeTimer = isUploading ? Integer.MAX_VALUE : Integer.MAX_VALUE - 1; + } else { + currentTime = 0; + } + } else if (slowModeTimer >= Integer.MAX_VALUE - 1) { + currentTime = 0; + if (info != null) { + accountInstance.getMessagesController().loadFullChat(info.id, 0, true); + } + } else { + currentTime = slowModeTimer - serverTime; + } + if (slowModeTimer != 0 && currentTime > 0) { + int minutes = currentTime / 60; + int seconds = currentTime - minutes * 60; + if (minutes == 0 && seconds == 0) { + seconds = 1; + } + slowModeButton.setText(String.format("%d:%02d", minutes, seconds)); + if (delegate != null) { + delegate.onUpdateSlowModeButton(slowModeButton, false, slowModeButton.getText()); + } + AndroidUtilities.runOnUIThread(updateSlowModeRunnable = this::updateSlowModeText, 100); + } else { + slowModeTimer = 0; + } + checkSendButton(true); + } + public void addTopView(View view, View lineView, int height) { if (view == null) { return; @@ -1968,10 +2231,16 @@ public class ChatActivityEnterView extends FrameLayout implements NotificationCe NotificationCenter.getInstance(currentAccount).removeObserver(this, NotificationCenter.messagePlayingDidReset); NotificationCenter.getInstance(currentAccount).removeObserver(this, NotificationCenter.messagePlayingProgressDidChanged); NotificationCenter.getInstance(currentAccount).removeObserver(this, NotificationCenter.featuredStickersDidLoad); + NotificationCenter.getInstance(currentAccount).removeObserver(this, NotificationCenter.messageReceivedByServer); + NotificationCenter.getInstance(currentAccount).removeObserver(this, NotificationCenter.sendingMessagesChanged); NotificationCenter.getGlobalInstance().removeObserver(this, NotificationCenter.emojiDidLoad); if (emojiView != null) { emojiView.onDestroy(); } + if (updateSlowModeRunnable != null) { + AndroidUtilities.cancelRunOnUIThread(updateSlowModeRunnable); + updateSlowModeRunnable = null; + } if (wakeLock != null) { try { wakeLock.release(); @@ -2046,7 +2315,10 @@ public class ChatActivityEnterView extends FrameLayout implements NotificationCe NotificationCenter.getInstance(currentAccount).removeObserver(this, NotificationCenter.messagePlayingDidReset); NotificationCenter.getInstance(currentAccount).removeObserver(this, NotificationCenter.messagePlayingProgressDidChanged); NotificationCenter.getInstance(currentAccount).removeObserver(this, NotificationCenter.featuredStickersDidLoad); + NotificationCenter.getInstance(currentAccount).removeObserver(this, NotificationCenter.messageReceivedByServer); + NotificationCenter.getInstance(currentAccount).removeObserver(this, NotificationCenter.sendingMessagesChanged); currentAccount = account; + accountInstance = AccountInstance.getInstance(currentAccount); NotificationCenter.getInstance(currentAccount).addObserver(this, NotificationCenter.recordStarted); NotificationCenter.getInstance(currentAccount).addObserver(this, NotificationCenter.recordStartError); NotificationCenter.getInstance(currentAccount).addObserver(this, NotificationCenter.recordStopped); @@ -2057,12 +2329,14 @@ public class ChatActivityEnterView extends FrameLayout implements NotificationCe NotificationCenter.getInstance(currentAccount).addObserver(this, NotificationCenter.messagePlayingDidReset); NotificationCenter.getInstance(currentAccount).addObserver(this, NotificationCenter.messagePlayingProgressDidChanged); NotificationCenter.getInstance(currentAccount).addObserver(this, NotificationCenter.featuredStickersDidLoad); + NotificationCenter.getInstance(currentAccount).addObserver(this, NotificationCenter.messageReceivedByServer); + NotificationCenter.getInstance(currentAccount).addObserver(this, NotificationCenter.sendingMessagesChanged); } int lower_id = (int) dialog_id; int high_id = (int) (dialog_id >> 32); if ((int) dialog_id < 0) { - TLRPC.Chat currentChat = MessagesController.getInstance(currentAccount).getChat(-(int) dialog_id); + TLRPC.Chat currentChat = accountInstance.getMessagesController().getChat(-(int) dialog_id); silent = MessagesController.getNotificationsSettings(currentAccount).getBoolean("silent_" + dialog_id, false); canWriteToChannel = ChatObject.isChannel(currentChat) && (currentChat.creator || currentChat.admin_rights != null && currentChat.admin_rights.post_messages) && !currentChat.megagroup; if (notifyButton != null) { @@ -2083,6 +2357,7 @@ public class ChatActivityEnterView extends FrameLayout implements NotificationCe if (emojiView != null) { emojiView.setChatInfo(info); } + setSlowModeTimer(chatInfo.slowmode_next_send_date); } public void checkRoundVideo() { @@ -2097,7 +2372,7 @@ public class ChatActivityEnterView extends FrameLayout implements NotificationCe int lower_id = (int) dialog_id; int high_id = (int) (dialog_id >> 32); if (lower_id == 0 && high_id != 0) { - TLRPC.EncryptedChat encryptedChat = MessagesController.getInstance(currentAccount).getEncryptedChat(high_id); + TLRPC.EncryptedChat encryptedChat = accountInstance.getMessagesController().getEncryptedChat(high_id); if (AndroidUtilities.getPeerLayerVersion(encryptedChat.layer) >= 66) { hasRecordVideo = true; } @@ -2106,7 +2381,7 @@ public class ChatActivityEnterView extends FrameLayout implements NotificationCe } boolean isChannel = false; if ((int) dialog_id < 0) { - TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(-(int) dialog_id); + TLRPC.Chat chat = accountInstance.getMessagesController().getChat(-(int) dialog_id); isChannel = ChatObject.isChannel(chat) && !chat.megagroup; if (isChannel && !chat.creator && (chat.admin_rights == null || !chat.admin_rights.post_messages)) { hasRecordVideo = false; @@ -2138,7 +2413,7 @@ public class ChatActivityEnterView extends FrameLayout implements NotificationCe private void updateFieldHint() { boolean isChannel = false; if ((int) dialog_id < 0) { - TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(-(int) dialog_id); + TLRPC.Chat chat = accountInstance.getMessagesController().getChat(-(int) dialog_id); isChannel = ChatObject.isChannel(chat) && !chat.megagroup; } if (editingMessageObject != null) { @@ -2201,7 +2476,23 @@ public class ChatActivityEnterView extends FrameLayout implements NotificationCe AnimatorSet.start(); } - private void sendMessage() { + private void sendMessage(boolean forceSilent) { + if (slowModeTimer == Integer.MAX_VALUE) { + if (delegate != null) { + delegate.scrollToSendingMessage(); + } + return; + } + if (forceShowSendButton && messageEditText.length() > 0) { + + } + if (parentFragment != null) { + TLRPC.Chat chat = parentFragment.getCurrentChat(); + TLRPC.User user = parentFragment.getCurrentUser(); + if (user != null || ChatObject.isChannel(chat) && chat.megagroup || !ChatObject.isChannel(chat)) { + MessagesController.getNotificationsSettings(currentAccount).edit().putBoolean("silent_" + dialog_id, forceSilent).commit(); + } + } if (stickersExpanded) { setStickersExpanded(false, true, false); if (searchingType != 0) { @@ -2228,6 +2519,18 @@ public class ChatActivityEnterView extends FrameLayout implements NotificationCe return; } CharSequence message = messageEditText.getText(); + if (parentFragment != null) { + TLRPC.Chat chat = parentFragment.getCurrentChat(); + if (chat != null && chat.slowmode_enabled && !ChatObject.hasAdminRights(chat)) { + if (message.length() > accountInstance.getMessagesController().maxMessageLength) { + AlertsCreator.showSimpleAlert(parentFragment, LocaleController.getString("Slowmode", R.string.Slowmode), LocaleController.getString("SlowmodeSendErrorTooLong", R.string.SlowmodeSendErrorTooLong)); + return; + } else if (forceShowSendButton && message.length() > 0) { + AlertsCreator.showSimpleAlert(parentFragment, LocaleController.getString("Slowmode", R.string.Slowmode), LocaleController.getString("SlowmodeSendError", R.string.SlowmodeSendError)); + return; + } + } + } if (processSendingText(message)) { messageEditText.setText(""); lastTypingTimeSend = 0; @@ -2256,7 +2559,7 @@ public class ChatActivityEnterView extends FrameLayout implements NotificationCe public boolean processSendingText(CharSequence text) { text = AndroidUtilities.getTrimmedString(text); - int maxLength = MessagesController.getInstance(currentAccount).maxMessageLength; + int maxLength = accountInstance.getMessagesController().maxMessageLength; if (text.length() != 0) { int count = (int) Math.ceil(text.length() / (float) maxLength); for (int a = 0; a < count; a++) { @@ -2277,11 +2580,143 @@ public class ChatActivityEnterView extends FrameLayout implements NotificationCe animated = false; } CharSequence message = AndroidUtilities.getTrimmedString(messageEditText.getText()); - if (message.length() > 0 || forceShowSendButton || audioToSend != null || videoToSendMessageObject != null) { + if (slowModeTimer > 0 && slowModeTimer != Integer.MAX_VALUE) { + if (audioVideoButtonContainer.getVisibility() == VISIBLE || expandStickersButton.getVisibility() == VISIBLE || sendButton.getVisibility() == VISIBLE || cancelBotButton.getVisibility() == VISIBLE) { + if (animated) { + if (runningAnimationType == 5) { + return; + } + if (runningAnimation != null) { + runningAnimation.cancel(); + runningAnimation = null; + } + if (runningAnimation2 != null) { + runningAnimation2.cancel(); + runningAnimation2 = null; + } + + if (attachLayout != null) { + runningAnimation2 = new AnimatorSet(); + runningAnimation2.playTogether( + ObjectAnimator.ofFloat(attachLayout, View.ALPHA, 0.0f), + ObjectAnimator.ofFloat(attachLayout, View.SCALE_X, 0.0f) + ); + runningAnimation2.setDuration(100); + runningAnimation2.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + if (runningAnimation2 != null && runningAnimation2.equals(animation)) { + attachLayout.setVisibility(GONE); + } + } + + @Override + public void onAnimationCancel(Animator animation) { + if (runningAnimation2 != null && runningAnimation2.equals(animation)) { + runningAnimation2 = null; + } + } + }); + runningAnimation2.start(); + updateFieldRight(0); + } + + runningAnimationType = 5; + runningAnimation = new AnimatorSet(); + + ArrayList animators = new ArrayList<>(); + if (audioVideoButtonContainer.getVisibility() == VISIBLE) { + animators.add(ObjectAnimator.ofFloat(audioVideoButtonContainer, View.SCALE_X, 0.1f)); + animators.add(ObjectAnimator.ofFloat(audioVideoButtonContainer, View.SCALE_Y, 0.1f)); + animators.add(ObjectAnimator.ofFloat(audioVideoButtonContainer, View.ALPHA, 0.0f)); + } + if (expandStickersButton.getVisibility() == VISIBLE) { + animators.add(ObjectAnimator.ofFloat(expandStickersButton, View.SCALE_X, 0.1f)); + animators.add(ObjectAnimator.ofFloat(expandStickersButton, View.SCALE_Y, 0.1f)); + animators.add(ObjectAnimator.ofFloat(expandStickersButton, View.ALPHA, 0.0f)); + } + if (sendButton.getVisibility() == VISIBLE) { + animators.add(ObjectAnimator.ofFloat(sendButton, View.SCALE_X, 0.1f)); + animators.add(ObjectAnimator.ofFloat(sendButton, View.SCALE_Y, 0.1f)); + animators.add(ObjectAnimator.ofFloat(sendButton, View.ALPHA, 0.0f)); + } + if (cancelBotButton.getVisibility() == VISIBLE) { + animators.add(ObjectAnimator.ofFloat(cancelBotButton, View.SCALE_X, 0.1f)); + animators.add(ObjectAnimator.ofFloat(cancelBotButton, View.SCALE_Y, 0.1f)); + animators.add(ObjectAnimator.ofFloat(cancelBotButton, View.ALPHA, 0.0f)); + } + animators.add(ObjectAnimator.ofFloat(slowModeButton, View.SCALE_X, 1.0f)); + animators.add(ObjectAnimator.ofFloat(slowModeButton, View.SCALE_Y, 1.0f)); + animators.add(ObjectAnimator.ofFloat(slowModeButton, View.ALPHA, 1.0f)); + slowModeButton.setVisibility(VISIBLE); + runningAnimation.playTogether(animators); + runningAnimation.setDuration(150); + runningAnimation.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + if (runningAnimation != null && runningAnimation.equals(animation)) { + sendButton.setVisibility(GONE); + cancelBotButton.setVisibility(GONE); + audioVideoButtonContainer.setVisibility(GONE); + expandStickersButton.setVisibility(GONE); + runningAnimation = null; + runningAnimationType = 0; + } + } + + @Override + public void onAnimationCancel(Animator animation) { + if (runningAnimation != null && runningAnimation.equals(animation)) { + runningAnimation = null; + } + } + }); + runningAnimation.start(); + } else { + slowModeButton.setScaleX(1.0f); + slowModeButton.setScaleY(1.0f); + slowModeButton.setAlpha(1.0f); + slowModeButton.setVisibility(VISIBLE); + + audioVideoButtonContainer.setScaleX(0.1f); + audioVideoButtonContainer.setScaleY(0.1f); + audioVideoButtonContainer.setAlpha(0.0f); + audioVideoButtonContainer.setVisibility(GONE); + + sendButton.setScaleX(0.1f); + sendButton.setScaleY(0.1f); + sendButton.setAlpha(0.0f); + sendButton.setVisibility(GONE); + + cancelBotButton.setScaleX(0.1f); + cancelBotButton.setScaleY(0.1f); + cancelBotButton.setAlpha(0.0f); + cancelBotButton.setVisibility(GONE); + + if (expandStickersButton.getVisibility() == VISIBLE) { + expandStickersButton.setScaleX(0.1f); + expandStickersButton.setScaleY(0.1f); + expandStickersButton.setAlpha(0.0f); + expandStickersButton.setVisibility(GONE); + } + if (attachLayout != null) { + attachLayout.setVisibility(GONE); + updateFieldRight(0); + } + } + } + } else if (message.length() > 0 || forceShowSendButton || audioToSend != null || videoToSendMessageObject != null || slowModeTimer == Integer.MAX_VALUE) { final String caption = messageEditText.getCaption(); boolean showBotButton = caption != null && (sendButton.getVisibility() == VISIBLE || expandStickersButton.getVisibility() == VISIBLE); boolean showSendButton = caption == null && (cancelBotButton.getVisibility() == VISIBLE || expandStickersButton.getVisibility() == VISIBLE); - if (audioVideoButtonContainer.getVisibility() == VISIBLE || showBotButton || showSendButton) { + int color; + if (slowModeTimer == Integer.MAX_VALUE) { + color = Theme.getColor(Theme.key_chat_messagePanelIcons); + } else { + color = Theme.getColor(Theme.key_chat_messagePanelSend); + } + Theme.setSelectorDrawableColor(sendButton.getBackground(), Color.argb(24, Color.red(color), Color.green(color), Color.blue(color)), true); + if (audioVideoButtonContainer.getVisibility() == VISIBLE || slowModeButton.getVisibility() == VISIBLE || showBotButton || showSendButton) { if (animated) { if (runningAnimationType == 1 && messageEditText.getCaption() == null || runningAnimationType == 3 && caption != null) { return; @@ -2337,6 +2772,11 @@ public class ChatActivityEnterView extends FrameLayout implements NotificationCe animators.add(ObjectAnimator.ofFloat(expandStickersButton, View.SCALE_Y, 0.1f)); animators.add(ObjectAnimator.ofFloat(expandStickersButton, View.ALPHA, 0.0f)); } + if (slowModeButton.getVisibility() == VISIBLE) { + animators.add(ObjectAnimator.ofFloat(slowModeButton, View.SCALE_X, 0.1f)); + animators.add(ObjectAnimator.ofFloat(slowModeButton, View.SCALE_Y, 0.1f)); + animators.add(ObjectAnimator.ofFloat(slowModeButton, View.ALPHA, 0.0f)); + } if (showBotButton) { animators.add(ObjectAnimator.ofFloat(sendButton, View.SCALE_X, 0.1f)); animators.add(ObjectAnimator.ofFloat(sendButton, View.SCALE_Y, 0.1f)); @@ -2375,6 +2815,7 @@ public class ChatActivityEnterView extends FrameLayout implements NotificationCe } audioVideoButtonContainer.setVisibility(GONE); expandStickersButton.setVisibility(GONE); + slowModeButton.setVisibility(GONE); runningAnimation = null; runningAnimationType = 0; } @@ -2392,23 +2833,30 @@ public class ChatActivityEnterView extends FrameLayout implements NotificationCe audioVideoButtonContainer.setScaleX(0.1f); audioVideoButtonContainer.setScaleY(0.1f); audioVideoButtonContainer.setAlpha(0.0f); + audioVideoButtonContainer.setVisibility(GONE); + if (slowModeButton.getVisibility() == VISIBLE) { + slowModeButton.setScaleX(0.1f); + slowModeButton.setScaleY(0.1f); + slowModeButton.setAlpha(0.0f); + slowModeButton.setVisibility(GONE); + } if (caption != null) { sendButton.setScaleX(0.1f); sendButton.setScaleY(0.1f); sendButton.setAlpha(0.0f); + sendButton.setVisibility(GONE); cancelBotButton.setScaleX(1.0f); cancelBotButton.setScaleY(1.0f); cancelBotButton.setAlpha(1.0f); cancelBotButton.setVisibility(VISIBLE); - sendButton.setVisibility(GONE); } else { cancelBotButton.setScaleX(0.1f); cancelBotButton.setScaleY(0.1f); cancelBotButton.setAlpha(0.0f); + sendButton.setVisibility(VISIBLE); sendButton.setScaleX(1.0f); sendButton.setScaleY(1.0f); sendButton.setAlpha(1.0f); - sendButton.setVisibility(VISIBLE); cancelBotButton.setVisibility(GONE); } if (expandStickersButton.getVisibility() == VISIBLE) { @@ -2417,7 +2865,6 @@ public class ChatActivityEnterView extends FrameLayout implements NotificationCe expandStickersButton.setAlpha(0.0f); expandStickersButton.setVisibility(GONE); } - audioVideoButtonContainer.setVisibility(GONE); if (attachLayout != null) { attachLayout.setVisibility(GONE); if (delegate != null && getVisibility() == VISIBLE) { @@ -2473,6 +2920,10 @@ public class ChatActivityEnterView extends FrameLayout implements NotificationCe animators.add(ObjectAnimator.ofFloat(audioVideoButtonContainer, View.SCALE_X, 0.1f)); animators.add(ObjectAnimator.ofFloat(audioVideoButtonContainer, View.SCALE_Y, 0.1f)); animators.add(ObjectAnimator.ofFloat(audioVideoButtonContainer, View.ALPHA, 0.0f)); + } else if (slowModeButton.getVisibility() == VISIBLE) { + animators.add(ObjectAnimator.ofFloat(slowModeButton, View.SCALE_X, 0.1f)); + animators.add(ObjectAnimator.ofFloat(slowModeButton, View.SCALE_Y, 0.1f)); + animators.add(ObjectAnimator.ofFloat(slowModeButton, View.ALPHA, 0.0f)); } else { animators.add(ObjectAnimator.ofFloat(sendButton, View.SCALE_X, 0.1f)); animators.add(ObjectAnimator.ofFloat(sendButton, View.SCALE_Y, 0.1f)); @@ -2487,6 +2938,7 @@ public class ChatActivityEnterView extends FrameLayout implements NotificationCe if (runningAnimation != null && runningAnimation.equals(animation)) { sendButton.setVisibility(GONE); cancelBotButton.setVisibility(GONE); + slowModeButton.setVisibility(GONE); audioVideoButtonContainer.setVisibility(GONE); expandStickersButton.setVisibility(VISIBLE); runningAnimation = null; @@ -2503,21 +2955,25 @@ public class ChatActivityEnterView extends FrameLayout implements NotificationCe }); runningAnimation.start(); } else { + slowModeButton.setScaleX(0.1f); + slowModeButton.setScaleY(0.1f); + slowModeButton.setAlpha(0.0f); + slowModeButton.setVisibility(GONE); sendButton.setScaleX(0.1f); sendButton.setScaleY(0.1f); sendButton.setAlpha(0.0f); + sendButton.setVisibility(GONE); cancelBotButton.setScaleX(0.1f); cancelBotButton.setScaleY(0.1f); cancelBotButton.setAlpha(0.0f); + cancelBotButton.setVisibility(GONE); audioVideoButtonContainer.setScaleX(0.1f); audioVideoButtonContainer.setScaleY(0.1f); audioVideoButtonContainer.setAlpha(0.0f); + audioVideoButtonContainer.setVisibility(GONE); expandStickersButton.setScaleX(1.0f); expandStickersButton.setScaleY(1.0f); expandStickersButton.setAlpha(1.0f); - cancelBotButton.setVisibility(GONE); - sendButton.setVisibility(GONE); - audioVideoButtonContainer.setVisibility(GONE); expandStickersButton.setVisibility(VISIBLE); if (attachLayout != null) { if (getVisibility() == VISIBLE) { @@ -2527,12 +2983,7 @@ public class ChatActivityEnterView extends FrameLayout implements NotificationCe updateFieldRight(1); } } - /*expandStickersButton.setAlpha(1f); - expandStickersButton.setScaleX(1); - expandStickersButton.setScaleY(1); - expandStickersButton.setVisibility(VISIBLE); - audioVideoButtonContainer.setVisibility(GONE);*/ - } else if (sendButton.getVisibility() == VISIBLE || cancelBotButton.getVisibility() == VISIBLE || expandStickersButton.getVisibility() == VISIBLE) { + } else if (sendButton.getVisibility() == VISIBLE || cancelBotButton.getVisibility() == VISIBLE || expandStickersButton.getVisibility() == VISIBLE || slowModeButton.getVisibility() == VISIBLE) { if (animated) { if (runningAnimationType == 2) { return; @@ -2578,6 +3029,10 @@ public class ChatActivityEnterView extends FrameLayout implements NotificationCe animators.add(ObjectAnimator.ofFloat(expandStickersButton, View.SCALE_X, 0.1f)); animators.add(ObjectAnimator.ofFloat(expandStickersButton, View.SCALE_Y, 0.1f)); animators.add(ObjectAnimator.ofFloat(expandStickersButton, View.ALPHA, 0.0f)); + } else if (slowModeButton.getVisibility() == VISIBLE) { + animators.add(ObjectAnimator.ofFloat(slowModeButton, View.SCALE_X, 0.1f)); + animators.add(ObjectAnimator.ofFloat(slowModeButton, View.SCALE_Y, 0.1f)); + animators.add(ObjectAnimator.ofFloat(slowModeButton, View.ALPHA, 0.0f)); } else { animators.add(ObjectAnimator.ofFloat(sendButton, View.SCALE_X, 0.1f)); animators.add(ObjectAnimator.ofFloat(sendButton, View.SCALE_Y, 0.1f)); @@ -2592,6 +3047,7 @@ public class ChatActivityEnterView extends FrameLayout implements NotificationCe if (runningAnimation != null && runningAnimation.equals(animation)) { sendButton.setVisibility(GONE); cancelBotButton.setVisibility(GONE); + slowModeButton.setVisibility(GONE); audioVideoButtonContainer.setVisibility(VISIBLE); runningAnimation = null; runningAnimationType = 0; @@ -2607,26 +3063,32 @@ public class ChatActivityEnterView extends FrameLayout implements NotificationCe }); runningAnimation.start(); } else { + slowModeButton.setScaleX(0.1f); + slowModeButton.setScaleY(0.1f); + slowModeButton.setAlpha(0.0f); + slowModeButton.setVisibility(GONE); sendButton.setScaleX(0.1f); sendButton.setScaleY(0.1f); sendButton.setAlpha(0.0f); + sendButton.setVisibility(GONE); cancelBotButton.setScaleX(0.1f); cancelBotButton.setScaleY(0.1f); cancelBotButton.setAlpha(0.0f); + cancelBotButton.setVisibility(GONE); expandStickersButton.setScaleX(0.1f); expandStickersButton.setScaleY(0.1f); expandStickersButton.setAlpha(0.0f); + expandStickersButton.setVisibility(GONE); audioVideoButtonContainer.setScaleX(1.0f); audioVideoButtonContainer.setScaleY(1.0f); audioVideoButtonContainer.setAlpha(1.0f); - cancelBotButton.setVisibility(GONE); - sendButton.setVisibility(GONE); - expandStickersButton.setVisibility(GONE); audioVideoButtonContainer.setVisibility(VISIBLE); if (attachLayout != null) { if (getVisibility() == VISIBLE) { delegate.onAttachButtonShow(); } + attachLayout.setAlpha(1.0f); + attachLayout.setScaleX(1.0f); attachLayout.setVisibility(VISIBLE); updateFieldRight(1); } @@ -2772,7 +3234,7 @@ public class ChatActivityEnterView extends FrameLayout implements NotificationCe } if (longPress) { String text = messageEditText.getText().toString(); - TLRPC.User user = messageObject != null && (int) dialog_id < 0 ? MessagesController.getInstance(currentAccount).getUser(messageObject.messageOwner.from_id) : null; + TLRPC.User user = messageObject != null && (int) dialog_id < 0 ? accountInstance.getMessagesController().getUser(messageObject.messageOwner.from_id) : null; if ((botCount != 1 || username) && user != null && user.bot && !command.contains("@")) { text = String.format(Locale.US, "%s@%s", command, user.username) + " " + text.replaceFirst("^/[a-zA-Z@\\d_]{1,255}(\\s|$)", ""); } else { @@ -2789,7 +3251,7 @@ public class ChatActivityEnterView extends FrameLayout implements NotificationCe openKeyboard(); } } else { - TLRPC.User user = messageObject != null && (int) dialog_id < 0 ? MessagesController.getInstance(currentAccount).getUser(messageObject.messageOwner.from_id) : null; + TLRPC.User user = messageObject != null && (int) dialog_id < 0 ? accountInstance.getMessagesController().getUser(messageObject.messageOwner.from_id) : null; if ((botCount != 1 || username) && user != null && user.bot && !command.contains("@")) { SendMessagesHelper.getInstance(currentAccount).sendMessage(String.format(Locale.US, "%s@%s", command, user.username), dialog_id, replyingMessageObject, null, false, null, null, null); } else { @@ -2819,10 +3281,10 @@ public class ChatActivityEnterView extends FrameLayout implements NotificationCe InputFilter[] inputFilters = new InputFilter[1]; CharSequence editingText; if (caption) { - inputFilters[0] = new InputFilter.LengthFilter(MessagesController.getInstance(currentAccount).maxCaptionLength); + inputFilters[0] = new InputFilter.LengthFilter(accountInstance.getMessagesController().maxCaptionLength); editingText = editingMessageObject.caption; } else { - inputFilters[0] = new InputFilter.LengthFilter(MessagesController.getInstance(currentAccount).maxMessageLength); + inputFilters[0] = new InputFilter.LengthFilter(accountInstance.getMessagesController().maxMessageLength); editingText = editingMessageObject.messageText; } if (editingText != null) { @@ -2890,6 +3352,7 @@ public class ChatActivityEnterView extends FrameLayout implements NotificationCe layoutParams.rightMargin = AndroidUtilities.dp(4); messageEditText.setLayoutParams(layoutParams); sendButton.setVisibility(GONE); + slowModeButton.setVisibility(GONE); cancelBotButton.setVisibility(GONE); audioVideoButtonContainer.setVisibility(GONE); attachLayout.setVisibility(GONE); @@ -2898,22 +3361,55 @@ public class ChatActivityEnterView extends FrameLayout implements NotificationCe doneButtonContainer.setVisibility(View.GONE); messageEditText.setFilters(new InputFilter[0]); delegate.onMessageEditEnd(false); - audioVideoButtonContainer.setVisibility(VISIBLE); - attachLayout.setVisibility(VISIBLE); sendButtonContainer.setVisibility(VISIBLE); - attachLayout.setScaleX(1.0f); - attachLayout.setAlpha(1.0f); - sendButton.setScaleX(0.1f); - sendButton.setScaleY(0.1f); - sendButton.setAlpha(0.0f); cancelBotButton.setScaleX(0.1f); cancelBotButton.setScaleY(0.1f); cancelBotButton.setAlpha(0.0f); - audioVideoButtonContainer.setScaleX(1.0f); - audioVideoButtonContainer.setScaleY(1.0f); - audioVideoButtonContainer.setAlpha(1.0f); - sendButton.setVisibility(GONE); cancelBotButton.setVisibility(GONE); + if (slowModeTimer > 0) { + if (slowModeTimer == Integer.MAX_VALUE) { + sendButton.setScaleX(1.0f); + sendButton.setScaleY(1.0f); + sendButton.setAlpha(1.0f); + sendButton.setVisibility(VISIBLE); + slowModeButton.setScaleX(0.1f); + slowModeButton.setScaleY(0.1f); + slowModeButton.setAlpha(0.0f); + slowModeButton.setVisibility(GONE); + } else { + sendButton.setScaleX(0.1f); + sendButton.setScaleY(0.1f); + sendButton.setAlpha(0.0f); + sendButton.setVisibility(GONE); + slowModeButton.setScaleX(1.0f); + slowModeButton.setScaleY(1.0f); + slowModeButton.setAlpha(1.0f); + slowModeButton.setVisibility(VISIBLE); + } + attachLayout.setScaleX(0.01f); + attachLayout.setAlpha(0.0f); + attachLayout.setVisibility(GONE); + audioVideoButtonContainer.setScaleX(0.1f); + audioVideoButtonContainer.setScaleY(0.1f); + audioVideoButtonContainer.setAlpha(0.0f); + audioVideoButtonContainer.setVisibility(GONE); + } else { + sendButton.setScaleX(0.1f); + sendButton.setScaleY(0.1f); + sendButton.setAlpha(0.0f); + sendButton.setVisibility(GONE); + slowModeButton.setScaleX(0.1f); + slowModeButton.setScaleY(0.1f); + slowModeButton.setAlpha(0.0f); + slowModeButton.setVisibility(GONE); + attachLayout.setScaleX(1.0f); + attachLayout.setAlpha(1.0f); + attachLayout.setVisibility(VISIBLE); + audioVideoButtonContainer.setScaleX(1.0f); + audioVideoButtonContainer.setScaleY(1.0f); + audioVideoButtonContainer.setAlpha(1.0f); + audioVideoButtonContainer.setVisibility(VISIBLE); + } messageEditText.setText(""); if (getVisibility() == VISIBLE) { delegate.onAttachButtonShow(); @@ -3129,7 +3625,7 @@ public class ChatActivityEnterView extends FrameLayout implements NotificationCe delegate.onMessageSend(null); } }); - sizeNotifierLayout.addView(botKeyboardView); + sizeNotifierLayout.addView(botKeyboardView, sizeNotifierLayout.getChildCount() - 1); } botButtonsMessageObject = messageObject; botReplyMarkup = messageObject != null && messageObject.messageOwner.reply_markup instanceof TLRPC.TL_replyKeyboardMarkup ? (TLRPC.TL_replyKeyboardMarkup) messageObject.messageOwner.reply_markup : null; @@ -3196,7 +3692,7 @@ public class ChatActivityEnterView extends FrameLayout implements NotificationCe if (messageObject.messageOwner.via_bot_id != 0) { uid = messageObject.messageOwner.via_bot_id; } - TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(uid); + TLRPC.User user = accountInstance.getMessagesController().getUser(uid); if (user == null) { return; } @@ -3211,7 +3707,7 @@ public class ChatActivityEnterView extends FrameLayout implements NotificationCe if (messageObject.messageOwner.via_bot_id != 0) { uid = messageObject.messageOwner.via_bot_id; } - TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(uid); + TLRPC.User user = accountInstance.getMessagesController().getUser(uid); if (user == null) { fragment1.finishFragment(); return; @@ -3227,7 +3723,7 @@ public class ChatActivityEnterView extends FrameLayout implements NotificationCe } else if (lower_part < 0) { args1.putInt("chat_id", -lower_part); } - if (!MessagesController.getInstance(currentAccount).checkCanOpenChat(args1, fragment1)) { + if (!accountInstance.getMessagesController().checkCanOpenChat(args1, fragment1)) { return; } ChatActivity chatActivity = new ChatActivity(args1); @@ -3295,7 +3791,13 @@ public class ChatActivityEnterView extends FrameLayout implements NotificationCe } @Override - public void onStickerSelected(TLRPC.Document sticker, Object parent) { + public void onStickerSelected(View view, TLRPC.Document sticker, Object parent) { + if (slowModeTimer > 0) { + if (delegate != null) { + delegate.onUpdateSlowModeButton(view != null ? view : slowModeButton, true, slowModeButton.getText()); + } + return; + } if (stickersExpanded) { if (searchingType != 0) { searchingType = 0; @@ -3306,7 +3808,7 @@ public class ChatActivityEnterView extends FrameLayout implements NotificationCe } ChatActivityEnterView.this.onStickerSelected(sticker, parent, false); if ((int) dialog_id == 0 && MessageObject.isGifDocument(sticker)) { - MessagesController.getInstance(currentAccount).saveGif(parent, sticker); + accountInstance.getMessagesController().saveGif(parent, sticker); } } @@ -3318,7 +3820,13 @@ public class ChatActivityEnterView extends FrameLayout implements NotificationCe } @Override - public void onGifSelected(Object gif, Object parent) { + public void onGifSelected(View view, Object gif, Object parent) { + if (slowModeTimer > 0) { + if (delegate != null) { + delegate.onUpdateSlowModeButton(view != null ? view : slowModeButton, true, slowModeButton.getText()); + } + return; + } if (stickersExpanded) { if (searchingType != 0) { emojiView.hideSearchKeyboard(); @@ -3330,7 +3838,7 @@ public class ChatActivityEnterView extends FrameLayout implements NotificationCe SendMessagesHelper.getInstance(currentAccount).sendSticker(document, dialog_id, replyingMessageObject, parent); MediaDataController.getInstance(currentAccount).addRecentGif(document, (int) (System.currentTimeMillis() / 1000)); if ((int) dialog_id == 0) { - MessagesController.getInstance(currentAccount).saveGif(parent, document); + accountInstance.getMessagesController().saveGif(parent, document); } } else if (gif instanceof TLRPC.BotInlineResult) { TLRPC.BotInlineResult result = (TLRPC.BotInlineResult) gif; @@ -3338,7 +3846,7 @@ public class ChatActivityEnterView extends FrameLayout implements NotificationCe if (result.document != null) { MediaDataController.getInstance(currentAccount).addRecentGif(result.document, (int) (System.currentTimeMillis() / 1000)); if ((int) dialog_id == 0) { - MessagesController.getInstance(currentAccount).saveGif(parent, result.document); + accountInstance.getMessagesController().saveGif(parent, result.document); } } @@ -3505,12 +4013,18 @@ public class ChatActivityEnterView extends FrameLayout implements NotificationCe return stickersTabOpen && !(!stickersExpanded && messageEditText.length() > 0) && emojiView.areThereAnyStickers(); } }); - sizeNotifierLayout.addView(emojiView); + sizeNotifierLayout.addView(emojiView, sizeNotifierLayout.getChildCount() - 1); checkChannelRights(); } @Override public void onStickerSelected(TLRPC.Document sticker, Object parent, boolean clearsInputField) { + if (slowModeTimer > 0) { + if (delegate != null) { + delegate.onUpdateSlowModeButton(slowModeButton, true, slowModeButton.getText()); + } + return; + } if (searchingType != 0) { searchingType = 0; emojiView.closeSearch(true); @@ -3539,6 +4053,10 @@ public class ChatActivityEnterView extends FrameLayout implements NotificationCe } } + public void showEmojiView() { + showPopup(1, 0); + } + private void showPopup(int show, int contentType) { if (show == 1) { if (contentType == 0 && emojiView == null) { @@ -3551,7 +4069,7 @@ public class ChatActivityEnterView extends FrameLayout implements NotificationCe View currentView = null; if (contentType == 0) { if (emojiView.getParent() == null) { - sizeNotifierLayout.addView(emojiView); + sizeNotifierLayout.addView(emojiView, sizeNotifierLayout.getChildCount() - 1); } emojiView.setVisibility(VISIBLE); emojiViewVisible = true; @@ -3882,7 +4400,7 @@ public class ChatActivityEnterView extends FrameLayout implements NotificationCe if (lastTimeString == null || !lastTimeString.equals(str)) { if (lastTypingSendTime != time && time % 5 == 0) { lastTypingSendTime = time; - MessagesController.getInstance(currentAccount).sendTyping(dialog_id, videoSendButton != null && videoSendButton.getTag() != null ? 7 : 1, 0); + accountInstance.getMessagesController().sendTyping(dialog_id, videoSendButton != null && videoSendButton.getTag() != null ? 7 : 1, 0); } if (recordTimeText != null) { recordTimeText.setText(str); @@ -3901,7 +4419,7 @@ public class ChatActivityEnterView extends FrameLayout implements NotificationCe } } else if (id == NotificationCenter.recordStartError || id == NotificationCenter.recordStopped) { if (recordingAudioVideo) { - MessagesController.getInstance(currentAccount).sendTyping(dialog_id, 2, 0); + accountInstance.getMessagesController().sendTyping(dialog_id, 2, 0); recordingAudioVideo = false; updateRecordIntefrace(); } @@ -4035,6 +4553,20 @@ public class ChatActivityEnterView extends FrameLayout implements NotificationCe emojiButton[a].invalidate(); } } + } else if (id == NotificationCenter.messageReceivedByServer) { + long did = (Long) args[3]; + if (did == dialog_id && info != null && info.slowmode_seconds != 0) { + TLRPC.Chat chat = accountInstance.getMessagesController().getChat(info.id); + if (chat != null && !ChatObject.hasAdminRights(chat)) { + info.slowmode_next_send_date = ConnectionsManager.getInstance(currentAccount).getCurrentTime() + info.slowmode_seconds; + info.flags |= 262144; + setSlowModeTimer(info.slowmode_next_send_date); + } + } + } else if (id == NotificationCenter.sendingMessagesChanged) { + if (info != null) { + updateSlowModeText(); + } } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlert.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlert.java index 201490108..54ad4759e 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlert.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlert.java @@ -16,87 +16,108 @@ import android.animation.ObjectAnimator; import android.annotation.SuppressLint; import android.content.Context; import android.content.Intent; -import android.content.SharedPreferences; import android.content.pm.PackageManager; import android.graphics.Bitmap; import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Outline; import android.graphics.Paint; import android.graphics.PorterDuff; import android.graphics.PorterDuffColorFilter; import android.graphics.Rect; +import android.graphics.RectF; import android.graphics.drawable.Drawable; import android.hardware.Camera; import android.media.MediaMetadataRetriever; import android.media.ThumbnailUtils; import android.net.Uri; -import android.provider.MediaStore; -import androidx.exifinterface.media.ExifInterface; import android.os.Build; +import android.provider.MediaStore; import android.provider.Settings; -import androidx.annotation.Keep; -import androidx.recyclerview.widget.LinearLayoutManager; -import androidx.recyclerview.widget.RecyclerView; - +import android.text.InputFilter; +import android.text.TextPaint; import android.text.TextUtils; +import android.util.Property; import android.util.TypedValue; import android.view.Gravity; import android.view.HapticFeedbackConstants; import android.view.KeyEvent; import android.view.MotionEvent; -import android.view.SoundEffectConstants; +import android.view.TextureView; import android.view.View; -import android.view.ViewAnimationUtils; -import android.view.ViewConfiguration; import android.view.ViewGroup; +import android.view.ViewOutlineProvider; +import android.view.WindowManager; import android.view.accessibility.AccessibilityEvent; import android.view.animation.DecelerateInterpolator; +import android.view.animation.OvershootInterpolator; import android.widget.FrameLayout; import android.widget.ImageView; import android.widget.TextView; import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.ApplicationLoader; import org.telegram.messenger.BuildVars; import org.telegram.messenger.ChatObject; -import org.telegram.messenger.MediaDataController; +import org.telegram.messenger.ContactsController; import org.telegram.messenger.FileLoader; +import org.telegram.messenger.FileLog; import org.telegram.messenger.ImageLocation; import org.telegram.messenger.ImageReceiver; -import org.telegram.messenger.MessagesController; -import org.telegram.messenger.ContactsController; -import org.telegram.messenger.FileLog; import org.telegram.messenger.LocaleController; import org.telegram.messenger.MediaController; +import org.telegram.messenger.MediaDataController; import org.telegram.messenger.MessageObject; +import org.telegram.messenger.MessagesController; import org.telegram.messenger.NotificationCenter; +import org.telegram.messenger.R; import org.telegram.messenger.SharedConfig; import org.telegram.messenger.UserConfig; +import org.telegram.messenger.UserObject; +import org.telegram.messenger.Utilities; import org.telegram.messenger.VideoEditedInfo; -import org.telegram.messenger.camera.*; -import org.telegram.messenger.R; +import org.telegram.messenger.camera.CameraController; +import org.telegram.messenger.camera.CameraView; import org.telegram.tgnet.TLRPC; +import org.telegram.ui.ActionBar.ActionBar; +import org.telegram.ui.ActionBar.ActionBarMenu; +import org.telegram.ui.ActionBar.ActionBarMenuItem; +import org.telegram.ui.ActionBar.ActionBarMenuSubItem; +import org.telegram.ui.ActionBar.ActionBarPopupWindow; import org.telegram.ui.ActionBar.AlertDialog; import org.telegram.ui.ActionBar.BaseFragment; import org.telegram.ui.ActionBar.BottomSheet; import org.telegram.ui.ActionBar.Theme; import org.telegram.ui.Cells.PhotoAttachCameraCell; +import org.telegram.ui.Cells.PhotoAttachPermissionCell; import org.telegram.ui.Cells.PhotoAttachPhotoCell; -import org.telegram.ui.Cells.ShadowSectionCell; import org.telegram.ui.ChatActivity; import org.telegram.ui.PhotoViewer; import java.io.File; import java.io.FileOutputStream; import java.util.ArrayList; +import java.util.Collections; import java.util.HashMap; +import androidx.annotation.Keep; +import androidx.exifinterface.media.ExifInterface; +import androidx.recyclerview.widget.GridLayoutManager; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; + public class ChatAttachAlert extends BottomSheet implements NotificationCenter.NotificationCenterDelegate, BottomSheet.BottomSheetDelegateInterface { public interface ChatAttachViewDelegate { - void didPressedButton(int button); + void didPressedButton(int button, boolean arg); + View getRevealView(); + void didSelectBot(TLRPC.User user); + void onCameraOpened(); - boolean allowGroupPhotos(); + + void needEnterComment(); } private class InnerAnimator { @@ -105,28 +126,61 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N } private BaseFragment baseFragment; - private AttachButton sendPhotosButton; - private AttachButton sendDocumentsButton; - private View[] views = new View[20]; - private RecyclerListView attachPhotoRecyclerView; - private LinearLayoutManager attachPhotoLayoutManager; - private PhotoAttachAdapter photoAttachAdapter; + private ActionBarPopupWindow sendPopupWindow; + private ActionBarPopupWindow.ActionBarPopupWindowLayout sendPopupLayout; + private ActionBarMenuSubItem itemCell; + + private View shadow; + + private FrameLayout frameLayout2; + private EditTextEmoji commentTextView; + private FrameLayout writeButtonContainer; + private ImageView writeButton; + private Drawable writeButtonDrawable; + private View selectedCountView; + private TextPaint textPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG); + private RectF rect = new RectF(); + private Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG); + private AnimatorSet animatorSet; + private MediaController.AlbumEntry selectedAlbumEntry; + private MediaController.AlbumEntry galleryAlbumEntry; + + private float cornerRadius = 1.0f; + + private ActionBar actionBar; + private ActionBarMenuItem dropDownContainer; + private TextView dropDown; + private Drawable dropDownDrawable; + private View actionBarShadow; + private AnimatorSet actionBarAnimation; + private AnimatorSet menuAnimator; + private ActionBarMenuItem selectedMenuItem; + private EmptyTextProgressView progressView; + private TextView selectedTextView; + private boolean menuShowed; + private int currentSelectedCount; + private ArrayList dropDownAlbums; + private Drawable cameraDrawable; + private SizeNotifierFrameLayout sizeNotifierFrameLayout; + + private boolean enterCommentEventSent; + + private RecyclerListView gridView; + private GridLayoutManager layoutManager; + private PhotoAttachAdapter adapter; + private int gridExtraSpace; + private RecyclerListView cameraPhotoRecyclerView; - private boolean cameraPhotoRecyclerViewIgnoreLayout; private LinearLayoutManager cameraPhotoLayoutManager; private PhotoAttachAdapter cameraAttachAdapter; - private View lineView; - private EmptyTextProgressView progressView; - private RecyclerListView listView; - private LinearLayoutManager layoutManager; - private Drawable shadowDrawable; - private ViewGroup attachView; - private ArrayList attachButtons = new ArrayList<>(); - private ListAdapter adapter; - private TextView hintTextView; - private ArrayList innerAnimators = new ArrayList<>(); + + private RecyclerListView buttonsRecyclerView; + private LinearLayoutManager buttonsLayoutManager; + private ButtonsAdapter buttonsAdapter; + + private boolean cameraPhotoRecyclerViewIgnoreLayout; + private boolean requestingPermissions; - private Paint ciclePaint = new Paint(Paint.ANTI_ALIAS_FLAG); private MessageObject editingMessageObject; @@ -134,13 +188,12 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N private int currentAccount = UserConfig.selectedAccount; - private CorrectlyMeasuringTextView mediaBanTooltip; - private boolean mediaEnabled = true; + private boolean pollsEnabled = true; + private AnimatorSet cameraInitAnimation; private CameraView cameraView; private FrameLayout cameraIcon; - private ImageView cameraImageView; private TextView recordTime; private ImageView[] flashModeButton = new ImageView[2]; private boolean flashAnimationInProgress; @@ -148,6 +201,7 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N private int[] viewPosition = new int[2]; private int cameraViewOffsetX; private int cameraViewOffsetY; + private int cameraViewOffsetBottomY; private boolean cameraOpened; private boolean cameraInitied; private boolean cameraAnimationInProgress; @@ -158,7 +212,11 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N private DecelerateInterpolator interpolator = new DecelerateInterpolator(1.5f); private FrameLayout cameraPanel; private ShutterButton shutterButton; + private ZoomControlView zoomControlView; + private AnimatorSet zoomControlAnimation; + private Runnable zoomControlHideRunnable; private TextView counterTextView; + private TextView tooltipTextView; private ImageView switchCameraButton; private boolean takingPhoto; private boolean mediaCaptured; @@ -170,18 +228,28 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N private boolean cancelTakingPhotos; private int maxSelectedPhotos = -1; + private boolean allowOrder = true; private boolean openWithFrontFaceCamera; + private float pinchStartDistance; + private float cameraZoom; + private boolean zooming; + private boolean zoomWas; + private android.graphics.Rect hitRect = new Rect(); + private float lastY; private boolean pressed; private boolean maybeStartDraging; private boolean dragging; - private AnimatorSet currentHintAnimation; - private boolean hintShowed; - private Runnable hideHintRunnable; + private int itemSize = AndroidUtilities.dp(80); + private int lastItemSize = itemSize; + private int attachItemSize = AndroidUtilities.dp(85); + private int itemsPerRow = 3; private boolean deviceHasGoodCamera; + private boolean noCameraPermissions; + private boolean noGalleryPermissions; private DecelerateInterpolator decelerateInterpolator = new DecelerateInterpolator(); @@ -190,16 +258,12 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N private ChatAttachViewDelegate delegate; private int scrollOffsetY; - private boolean ignoreLayout; - - private boolean useRevealAnimation; - private float revealRadius; - private int revealX; - private int revealY; - private boolean revealAnimationInProgress; private boolean paused; + private final static int group = 0; + private final static int compress = 1; + private class BasePhotoProvider extends PhotoViewer.EmptyPhotoViewerProvider { @Override public boolean isPhotoChecked(int index) { @@ -226,13 +290,13 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N } photoEntry.editedInfo = videoEditedInfo; - int count = attachPhotoRecyclerView.getChildCount(); + int count = gridView.getChildCount(); for (int a = 0; a < count; a++) { - View view = attachPhotoRecyclerView.getChildAt(a); + View view = gridView.getChildAt(a); if (view instanceof PhotoAttachPhotoCell) { int tag = (Integer) view.getTag(); if (tag == index) { - if (baseFragment instanceof ChatActivity && maxSelectedPhotos < 0) { + if (baseFragment instanceof ChatActivity && allowOrder) { ((PhotoAttachPhotoCell) view).setChecked(num, add, false); } else { ((PhotoAttachPhotoCell) view).setChecked(-1, add, false); @@ -247,7 +311,7 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N if (view instanceof PhotoAttachPhotoCell) { int tag = (Integer) view.getTag(); if (tag == index) { - if (baseFragment instanceof ChatActivity && maxSelectedPhotos < 0) { + if (baseFragment instanceof ChatActivity && allowOrder) { ((PhotoAttachPhotoCell) view).setChecked(num, add, false); } else { ((PhotoAttachPhotoCell) view).setChecked(-1, add, false); @@ -256,15 +320,10 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N } } } - updatePhotosButton(); + updatePhotosButton(add ? 1 : 2); return num; } - @Override - public boolean allowGroupPhotos() { - return delegate.allowGroupPhotos(); - } - @Override public int getSelectedCount() { return selectedPhotos.size(); @@ -303,10 +362,10 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N PhotoViewer.PlaceProviderObject object = new PhotoViewer.PlaceProviderObject(); object.viewX = coords[0]; object.viewY = coords[1]; - object.parentView = attachPhotoRecyclerView; + object.parentView = gridView; object.imageReceiver = cell.getImageView().getImageReceiver(); object.thumb = object.imageReceiver.getBitmapSafe(); - object.scale = cell.getImageView().getScaleX(); + object.scale = cell.getScale(); cell.showCheck(false); return object; } @@ -323,16 +382,16 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N return; } if (photoEntry.thumbPath != null) { - cell.getImageView().setImage(photoEntry.thumbPath, null, cell.getContext().getResources().getDrawable(R.drawable.nophotos)); + cell.getImageView().setImage(photoEntry.thumbPath, null, Theme.chat_attachEmptyDrawable); } else if (photoEntry.path != null) { cell.getImageView().setOrientation(photoEntry.orientation, true); if (photoEntry.isVideo) { - cell.getImageView().setImage("vthumb://" + photoEntry.imageId + ":" + photoEntry.path, null, cell.getContext().getResources().getDrawable(R.drawable.nophotos)); + cell.getImageView().setImage("vthumb://" + photoEntry.imageId + ":" + photoEntry.path, null, Theme.chat_attachEmptyDrawable); } else { - cell.getImageView().setImage("thumb://" + photoEntry.imageId + ":" + photoEntry.path, null, cell.getContext().getResources().getDrawable(R.drawable.nophotos)); + cell.getImageView().setImage("thumb://" + photoEntry.imageId + ":" + photoEntry.path, null, Theme.chat_attachEmptyDrawable); } } else { - cell.getImageView().setImageResource(R.drawable.nophotos); + cell.getImageView().setImageDrawable(Theme.chat_attachEmptyDrawable); } } } @@ -356,9 +415,9 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N @Override public void willHidePhotoViewer() { - int count = attachPhotoRecyclerView.getChildCount(); + int count = gridView.getChildCount(); for (int a = 0; a < count; a++) { - View view = attachPhotoRecyclerView.getChildAt(a); + View view = gridView.getChildAt(a); if (view instanceof PhotoAttachPhotoCell) { PhotoAttachPhotoCell cell = (PhotoAttachPhotoCell) view; cell.showCheck(true); @@ -380,7 +439,8 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N if (selectedPhotos.isEmpty() && photoEntry != null) { addToSelectedPhotos(photoEntry, -1); } - delegate.didPressedButton(7); + applyCaption(); + delegate.didPressedButton(7, true); } }; @@ -388,9 +448,9 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N if (!(baseFragment instanceof ChatActivity)) { return; } - int count = attachPhotoRecyclerView.getChildCount(); + int count = gridView.getChildCount(); for (int a = 0; a < count; a++) { - View view = attachPhotoRecyclerView.getChildAt(a); + View view = gridView.getChildAt(a); if (view instanceof PhotoAttachPhotoCell) { PhotoAttachPhotoCell cell = (PhotoAttachPhotoCell) view; MediaController.PhotoEntry photoEntry = getPhotoEntryAtPosition((Integer) cell.getTag()); @@ -421,14 +481,8 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N return (MediaController.PhotoEntry) cameraPhotos.get(position); } position -= cameraCount; - MediaController.AlbumEntry albumEntry; - if (baseFragment instanceof ChatActivity) { - albumEntry = MediaController.allMediaAlbumEntry; - } else { - albumEntry = MediaController.allPhotosAlbumEntry; - } - if (position < albumEntry.photos.size()) { - return albumEntry.photos.get(position); + if (position < selectedAlbumEntry.photos.size()) { + return selectedAlbumEntry.photos.get(position); } return null; } @@ -436,19 +490,13 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N @SuppressWarnings("unchecked") private ArrayList getAllPhotosArray() { ArrayList arrayList; - MediaController.AlbumEntry albumEntry; - if (baseFragment instanceof ChatActivity) { - albumEntry = MediaController.allMediaAlbumEntry; - } else { - albumEntry = MediaController.allPhotosAlbumEntry; - } - if (albumEntry != null) { + if (selectedAlbumEntry != null) { if (!cameraPhotos.isEmpty()) { - arrayList = new ArrayList<>(albumEntry.photos.size() + cameraPhotos.size()); + arrayList = new ArrayList<>(selectedAlbumEntry.photos.size() + cameraPhotos.size()); arrayList.addAll(cameraPhotos); - arrayList.addAll(albumEntry.photos); + arrayList.addAll(selectedAlbumEntry.photos); } else { - arrayList = (ArrayList) albumEntry.photos; + arrayList = (ArrayList) selectedAlbumEntry.photos; } } else if (!cameraPhotos.isEmpty()) { arrayList = cameraPhotos; @@ -468,7 +516,10 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N imageView = new ImageView(context); imageView.setScaleType(ImageView.ScaleType.CENTER); - addView(imageView, LayoutHelper.createFrame(54, 54, Gravity.CENTER_HORIZONTAL | Gravity.TOP, 0, 5, 0, 0)); + if (Build.VERSION.SDK_INT >= 21) { + imageView.setImageDrawable(Theme.createSelectorDrawable(Theme.getColor(Theme.key_dialogButtonSelector), 1, AndroidUtilities.dp(25))); + } + addView(imageView, LayoutHelper.createFrame(50, 50, Gravity.CENTER_HORIZONTAL | Gravity.TOP, 0, 12, 0, 0)); textView = new TextView(context); textView.setMaxLines(2); @@ -477,12 +528,12 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N textView.setTextColor(Theme.getColor(Theme.key_dialogTextGray2)); textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 12); textView.setLineSpacing(-AndroidUtilities.dp(2), 1.0f); - addView(textView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.LEFT | Gravity.TOP, 0, 64, 0, 0)); + addView(textView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.LEFT | Gravity.TOP, 0, 66, 0, 0)); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - super.onMeasure(MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(85), MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(92), MeasureSpec.EXACTLY)); + super.onMeasure(MeasureSpec.makeMeasureSpec(attachItemSize, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(92), MeasureSpec.EXACTLY)); } public void setTextAndIcon(CharSequence text, Drawable drawable) { @@ -501,71 +552,34 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N private BackupImageView imageView; private TextView nameTextView; private AvatarDrawable avatarDrawable = new AvatarDrawable(); - private boolean pressed; - - private boolean checkingForLongPress = false; - private CheckForLongPress pendingCheckForLongPress = null; - private int pressCount = 0; - private CheckForTap pendingCheckForTap = null; private TLRPC.User currentUser; - private final class CheckForTap implements Runnable { - public void run() { - if (pendingCheckForLongPress == null) { - pendingCheckForLongPress = new CheckForLongPress(); - } - pendingCheckForLongPress.currentPressCount = ++pressCount; - postDelayed(pendingCheckForLongPress, ViewConfiguration.getLongPressTimeout() - ViewConfiguration.getTapTimeout()); - } - } - - class CheckForLongPress implements Runnable { - public int currentPressCount; - - public void run() { - if (checkingForLongPress && getParent() != null && currentPressCount == pressCount) { - checkingForLongPress = false; - performHapticFeedback(HapticFeedbackConstants.LONG_PRESS); - onLongPress(); - MotionEvent event = MotionEvent.obtain(0, 0, MotionEvent.ACTION_CANCEL, 0, 0, 0); - onTouchEvent(event); - event.recycle(); - } - } - } - public AttachBotButton(Context context) { super(context); imageView = new BackupImageView(context); - imageView.setRoundRadius(AndroidUtilities.dp(27)); - addView(imageView, LayoutHelper.createFrame(54, 54, Gravity.TOP | Gravity.CENTER_HORIZONTAL, 0, 7, 0, 0)); + imageView.setRoundRadius(AndroidUtilities.dp(25)); + addView(imageView, LayoutHelper.createFrame(50, 50, Gravity.TOP | Gravity.CENTER_HORIZONTAL, 0, 12, 0, 0)); + + if (Build.VERSION.SDK_INT >= 21) { + View selector = new View(context); + selector.setBackgroundDrawable(Theme.createSelectorDrawable(Theme.getColor(Theme.key_dialogButtonSelector), 1, AndroidUtilities.dp(25))); + addView(selector, LayoutHelper.createFrame(50, 50, Gravity.TOP | Gravity.CENTER_HORIZONTAL, 0, 12, 0, 0)); + } nameTextView = new TextView(context); nameTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 12); - nameTextView.setMaxLines(2); nameTextView.setGravity(Gravity.TOP | Gravity.CENTER_HORIZONTAL); - nameTextView.setLines(2); + nameTextView.setLines(1); + nameTextView.setSingleLine(true); nameTextView.setEllipsize(TextUtils.TruncateAt.END); - addView(nameTextView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.LEFT | Gravity.TOP, 6, 65, 6, 0)); + addView(nameTextView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.LEFT | Gravity.TOP, 6, 66, 6, 0)); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - super.onMeasure(MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(85), MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(100), MeasureSpec.EXACTLY)); - } - - private void onLongPress() { - if (baseFragment == null || currentUser == null) { - return; - } - AlertDialog.Builder builder = new AlertDialog.Builder(getContext()); - builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); - builder.setMessage(LocaleController.formatString("ChatHintsDelete", R.string.ChatHintsDelete, ContactsController.formatName(currentUser.first_name, currentUser.last_name))); - builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), (dialogInterface, i) -> MediaDataController.getInstance(currentAccount).removeInline(currentUser.id)); - builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); - builder.show(); + super.onMeasure(MeasureSpec.makeMeasureSpec(attachItemSize, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(100), MeasureSpec.EXACTLY)); } public void setUser(TLRPC.User user) { @@ -579,91 +593,26 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N imageView.setImage(ImageLocation.getForUser(user, false), "50_50", avatarDrawable, user); requestLayout(); } - - @Override - public boolean onTouchEvent(MotionEvent event) { - boolean result = false; - - if (event.getAction() == MotionEvent.ACTION_DOWN) { - pressed = true; - invalidate(); - result = true; - } else if (pressed) { - if (event.getAction() == MotionEvent.ACTION_UP) { - getParent().requestDisallowInterceptTouchEvent(true); - pressed = false; - playSoundEffect(SoundEffectConstants.CLICK); - delegate.didSelectBot(MessagesController.getInstance(currentAccount).getUser(MediaDataController.getInstance(currentAccount).inlineBots.get((Integer) getTag()).peer.user_id)); - setUseRevealAnimation(false); - dismiss(); - setUseRevealAnimation(true); - invalidate(); - } else if (event.getAction() == MotionEvent.ACTION_CANCEL) { - pressed = false; - invalidate(); - } - } - if (!result) { - result = super.onTouchEvent(event); - } else { - if (event.getAction() == MotionEvent.ACTION_DOWN) { - startCheckLongPress(); - } - } - if (event.getAction() != MotionEvent.ACTION_DOWN && event.getAction() != MotionEvent.ACTION_MOVE) { - cancelCheckLongPress(); - } - - return result; - } - - protected void startCheckLongPress() { - if (checkingForLongPress) { - return; - } - checkingForLongPress = true; - if (pendingCheckForTap == null) { - pendingCheckForTap = new CheckForTap(); - } - postDelayed(pendingCheckForTap, ViewConfiguration.getTapTimeout()); - } - - protected void cancelCheckLongPress() { - checkingForLongPress = false; - if (pendingCheckForLongPress != null) { - removeCallbacks(pendingCheckForLongPress); - } - if (pendingCheckForTap != null) { - removeCallbacks(pendingCheckForTap); - } - } } public ChatAttachAlert(Context context, final BaseFragment parentFragment) { - super(context, false, 0); + super(context, false, 1); + openInterpolator = new OvershootInterpolator(0.7f); baseFragment = parentFragment; - ciclePaint.setColor(Theme.getColor(Theme.key_dialogBackground)); setDelegate(this); - setUseRevealAnimation(true); checkCamera(false); NotificationCenter.getInstance(currentAccount).addObserver(this, NotificationCenter.albumsDidLoad); NotificationCenter.getInstance(currentAccount).addObserver(this, NotificationCenter.reloadInlineHints); NotificationCenter.getGlobalInstance().addObserver(this, NotificationCenter.cameraInitied); - shadowDrawable = context.getResources().getDrawable(R.drawable.sheet_shadow).mutate(); - Theme.setDrawableColor(shadowDrawable, Theme.getColor(Theme.key_dialogBackground)); - containerView = listView = new RecyclerListView(context) { + cameraDrawable = context.getResources().getDrawable(R.drawable.instant_camera).mutate(); - private int lastWidth; - private int lastHeight; + sizeNotifierFrameLayout = new SizeNotifierFrameLayout(context) { - @Override - public void requestLayout() { - if (ignoreLayout) { - return; - } - super.requestLayout(); - } + private int lastNotifyWidth; + private RectF rect = new RectF(); + private boolean ignoreLayout; + private float initialTranslationY; @Override public boolean onInterceptTouchEvent(MotionEvent ev) { @@ -671,7 +620,7 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N return true; } else if (cameraOpened) { return processTouchEvent(ev); - } else if (ev.getAction() == MotionEvent.ACTION_DOWN && scrollOffsetY != 0 && ev.getY() < scrollOffsetY) { + } else if (ev.getAction() == MotionEvent.ACTION_DOWN && scrollOffsetY != 0 && ev.getY() < scrollOffsetY - AndroidUtilities.dp(36) && actionBar.getAlpha() == 0.0f) { dismiss(); return true; } @@ -690,196 +639,478 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - int height = MeasureSpec.getSize(heightMeasureSpec); + int totalHeight = MeasureSpec.getSize(heightMeasureSpec); if (Build.VERSION.SDK_INT >= 21) { - height -= AndroidUtilities.statusBarHeight; - } - int h; - if (baseFragment instanceof ChatActivity) { - h = 298; - } else { - h = 203; - } - int contentSize = backgroundPaddingTop + AndroidUtilities.dp(h) + (MediaDataController.getInstance(currentAccount).inlineBots.isEmpty() ? 0 : ((int) Math.ceil(MediaDataController.getInstance(currentAccount).inlineBots.size() / 4.0f) * AndroidUtilities.dp(100) + AndroidUtilities.dp(12))); - int padding = contentSize == AndroidUtilities.dp(h) ? 0 : Math.max(0, (height - AndroidUtilities.dp(h))); - if (padding != 0 && contentSize < height) { - padding -= (height - contentSize); - } - if (padding == 0) { - padding = backgroundPaddingTop; - } - if (getPaddingTop() != padding) { ignoreLayout = true; - setPadding(backgroundPaddingLeft, padding, backgroundPaddingLeft, 0); + setPadding(backgroundPaddingLeft, AndroidUtilities.statusBarHeight, backgroundPaddingLeft, 0); ignoreLayout = false; } - super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(Math.min(contentSize, height), MeasureSpec.EXACTLY)); + int availableHeight = totalHeight - getPaddingTop(); + int keyboardSize = getKeyboardHeight(); + if (!AndroidUtilities.isInMultiwindow && keyboardSize <= AndroidUtilities.dp(20)) { + availableHeight -= commentTextView.getEmojiPadding(); + } + int availableWidth = MeasureSpec.getSize(widthMeasureSpec) - backgroundPaddingLeft * 2; + if (AndroidUtilities.isTablet()) { + itemsPerRow = 4; + selectedMenuItem.setAdditionalYOffset(-AndroidUtilities.dp(3)); + } else if (AndroidUtilities.displaySize.x > AndroidUtilities.displaySize.y) { + itemsPerRow = 4; + selectedMenuItem.setAdditionalYOffset(0); + } else { + itemsPerRow = 3; + selectedMenuItem.setAdditionalYOffset(-AndroidUtilities.dp(3)); + } + LayoutParams layoutParams = (LayoutParams) gridView.getLayoutParams(); + layoutParams.topMargin = ActionBar.getCurrentActionBarHeight(); + + layoutParams = (LayoutParams) actionBarShadow.getLayoutParams(); + layoutParams.topMargin = ActionBar.getCurrentActionBarHeight(); + + ignoreLayout = true; + itemSize = (availableWidth - AndroidUtilities.dp(6 * 2) - AndroidUtilities.dp(5 * 2)) / itemsPerRow; + int newSize = availableWidth / Math.min(4, buttonsAdapter.getItemCount()); + if (attachItemSize != newSize) { + attachItemSize = newSize; + AndroidUtilities.runOnUIThread(() -> buttonsAdapter.notifyDataSetChanged()); + } + if (lastItemSize != itemSize) { + lastItemSize = itemSize; + AndroidUtilities.runOnUIThread(() -> adapter.notifyDataSetChanged()); + } + dropDown.setTextSize(!AndroidUtilities.isTablet() && AndroidUtilities.displaySize.x > AndroidUtilities.displaySize.y ? 18 : 20); + layoutManager.setSpanCount(itemSize * itemsPerRow + AndroidUtilities.dp(5) * (itemsPerRow - 1)); + int rows = (int) Math.ceil((adapter.getItemCount() - 1) / (float) itemsPerRow); + int contentSize = rows * itemSize + (rows - 1) * AndroidUtilities.dp(5); + newSize = Math.max(0, availableHeight - contentSize - ActionBar.getCurrentActionBarHeight() - AndroidUtilities.dp(48 + 12)); + if (gridExtraSpace != newSize) { + gridExtraSpace = newSize; + adapter.notifyDataSetChanged(); + } + int padding; + if (!AndroidUtilities.isTablet() && AndroidUtilities.displaySize.x > AndroidUtilities.displaySize.y) { + padding = (availableHeight / 6); + } else { + padding = (availableHeight / 5 * 2); + } + if (gridView.getPaddingTop() != padding) { + gridView.setPadding(AndroidUtilities.dp(6), padding, AndroidUtilities.dp(6), AndroidUtilities.dp(48)); + } + ignoreLayout = false; + onMeasureInternal(widthMeasureSpec, MeasureSpec.makeMeasureSpec(totalHeight, MeasureSpec.EXACTLY)); + } + + private void onMeasureInternal(int widthMeasureSpec, int heightMeasureSpec) { + int widthSize = MeasureSpec.getSize(widthMeasureSpec); + int heightSize = MeasureSpec.getSize(heightMeasureSpec); + + setMeasuredDimension(widthSize, heightSize); + widthSize -= backgroundPaddingLeft * 2; + + int keyboardSize = getKeyboardHeight(); + if (keyboardSize <= AndroidUtilities.dp(20)) { + if (!AndroidUtilities.isInMultiwindow) { + heightSize -= commentTextView.getEmojiPadding(); + heightMeasureSpec = MeasureSpec.makeMeasureSpec(heightSize, MeasureSpec.EXACTLY); + } + } else { + ignoreLayout = true; + commentTextView.hideEmojiView(); + ignoreLayout = false; + } + + int childCount = getChildCount(); + for (int i = 0; i < childCount; i++) { + View child = getChildAt(i); + if (child == null || child.getVisibility() == GONE) { + continue; + } + if (commentTextView != null && commentTextView.isPopupView(child)) { + if (AndroidUtilities.isInMultiwindow || AndroidUtilities.isTablet()) { + if (AndroidUtilities.isTablet()) { + child.measure(MeasureSpec.makeMeasureSpec(widthSize, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(Math.min(AndroidUtilities.dp(AndroidUtilities.isTablet() ? 200 : 320), heightSize - AndroidUtilities.statusBarHeight + getPaddingTop()), MeasureSpec.EXACTLY)); + } else { + child.measure(MeasureSpec.makeMeasureSpec(widthSize, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(heightSize - AndroidUtilities.statusBarHeight + getPaddingTop(), MeasureSpec.EXACTLY)); + } + } else { + child.measure(MeasureSpec.makeMeasureSpec(widthSize, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(child.getLayoutParams().height, MeasureSpec.EXACTLY)); + } + } else { + measureChildWithMargins(child, widthMeasureSpec, 0, heightMeasureSpec, 0); + } + } } @Override - protected void onLayout(boolean changed, int left, int top, int right, int bottom) { - int width = right - left; - int height = bottom - top; - - int newPosition = -1; - int newTop = 0; - - int count = listView.getChildCount(); - int lastVisibleItemPosition = -1; - int lastVisibleItemPositionTop = 0; - if (count > 0) { - View child = listView.getChildAt(listView.getChildCount() - 1); - Holder holder = (Holder) listView.findContainingViewHolder(child); - if (holder != null) { - lastVisibleItemPosition = holder.getAdapterPosition(); - lastVisibleItemPositionTop = child.getTop(); + protected void onLayout(boolean changed, int l, int t, int r, int b) { + if (lastNotifyWidth != r - l) { + lastNotifyWidth = r - l; + if (adapter != null) { + adapter.notifyDataSetChanged(); + } + if (sendPopupWindow != null && sendPopupWindow.isShowing()) { + sendPopupWindow.dismiss(); } } + final int count = getChildCount(); - if (lastVisibleItemPosition >= 0 && height - lastHeight != 0) { - newPosition = lastVisibleItemPosition; - newTop = lastVisibleItemPositionTop + height - lastHeight - getPaddingTop(); + int paddingBottom = getKeyboardHeight() <= AndroidUtilities.dp(20) && !AndroidUtilities.isInMultiwindow && !AndroidUtilities.isTablet() ? commentTextView.getEmojiPadding() : 0; + setBottomClip(paddingBottom); + + for (int i = 0; i < count; i++) { + final View child = getChildAt(i); + if (child.getVisibility() == GONE) { + continue; + } + final LayoutParams lp = (LayoutParams) child.getLayoutParams(); + + final int width = child.getMeasuredWidth(); + final int height = child.getMeasuredHeight(); + + int childLeft; + int childTop; + + int gravity = lp.gravity; + if (gravity == -1) { + gravity = Gravity.TOP | Gravity.LEFT; + } + + final int absoluteGravity = gravity & Gravity.HORIZONTAL_GRAVITY_MASK; + final int verticalGravity = gravity & Gravity.VERTICAL_GRAVITY_MASK; + + switch (absoluteGravity & Gravity.HORIZONTAL_GRAVITY_MASK) { + case Gravity.CENTER_HORIZONTAL: + childLeft = (r - l - width) / 2 + lp.leftMargin - lp.rightMargin; + break; + case Gravity.RIGHT: + childLeft = (r - l) - width - lp.rightMargin - getPaddingRight() - backgroundPaddingLeft; + break; + case Gravity.LEFT: + default: + childLeft = lp.leftMargin + getPaddingLeft(); + } + + switch (verticalGravity) { + case Gravity.TOP: + childTop = lp.topMargin + getPaddingTop(); + break; + case Gravity.CENTER_VERTICAL: + childTop = ((b - paddingBottom) - t - height) / 2 + lp.topMargin - lp.bottomMargin; + break; + case Gravity.BOTTOM: + childTop = ((b - paddingBottom) - t) - height - lp.bottomMargin; + break; + default: + childTop = lp.topMargin; + } + + if (commentTextView != null && commentTextView.isPopupView(child)) { + if (AndroidUtilities.isTablet()) { + childTop = getMeasuredHeight() - child.getMeasuredHeight(); + } else { + childTop = getMeasuredHeight() + getKeyboardHeight() - child.getMeasuredHeight(); + } + } + child.layout(childLeft, childTop, childLeft + width, childTop + height); } - super.onLayout(changed, left, top, right, bottom); - - if (newPosition != -1) { - ignoreLayout = true; - layoutManager.scrollToPositionWithOffset(newPosition, newTop); - super.onLayout(false, left, top, right, bottom); - ignoreLayout = false; - } - - lastHeight = height; - lastWidth = width; - - updateLayout(); + notifyHeightChanged(); + updateLayout(false); checkCameraViewPosition(); } @Override - public void onDraw(Canvas canvas) { - if (useRevealAnimation && Build.VERSION.SDK_INT <= 19) { - canvas.save(); - canvas.clipRect(backgroundPaddingLeft, scrollOffsetY, getMeasuredWidth() - backgroundPaddingLeft, getMeasuredHeight()); - if (revealAnimationInProgress) { - canvas.drawCircle(revealX, revealY, revealRadius, ciclePaint); - } else { - canvas.drawRect(backgroundPaddingLeft, scrollOffsetY, getMeasuredWidth() - backgroundPaddingLeft, getMeasuredHeight(), ciclePaint); - } - canvas.restore(); - } else { - shadowDrawable.setBounds(0, scrollOffsetY - backgroundPaddingTop, getMeasuredWidth(), getMeasuredHeight()); - shadowDrawable.draw(canvas); + public void requestLayout() { + if (ignoreLayout) { + return; } + super.requestLayout(); + } + + @Override + protected void onDraw(Canvas canvas) { + int offset = AndroidUtilities.dp(13) + (selectedMenuItem != null ? AndroidUtilities.dp(selectedMenuItem.getAlpha() * 26) : 0); + int top = scrollOffsetY - backgroundPaddingTop - offset; + if (currentSheetAnimationType == 1) { + top += gridView.getTranslationY(); + } + int y = top + AndroidUtilities.dp(20); + + int height = getMeasuredHeight() + AndroidUtilities.dp(15) + backgroundPaddingTop; + float rad = 1.0f; + + if (top + backgroundPaddingTop < ActionBar.getCurrentActionBarHeight()) { + float toMove = offset + AndroidUtilities.dp(11 - 7); + float moveProgress = Math.min(1.0f, (ActionBar.getCurrentActionBarHeight() - top - backgroundPaddingTop) / toMove); + float availableToMove = ActionBar.getCurrentActionBarHeight() - toMove; + + int diff = (int) (availableToMove * moveProgress); + top -= diff; + y -= diff; + height += diff; + rad = 1.0f - moveProgress; + } + + if (Build.VERSION.SDK_INT >= 21) { + top += AndroidUtilities.statusBarHeight; + y += AndroidUtilities.statusBarHeight; + height -= AndroidUtilities.statusBarHeight; + } + + shadowDrawable.setBounds(0, top, getMeasuredWidth(), height); + shadowDrawable.draw(canvas); + + if (rad != 1.0f) { + Theme.dialogs_onlineCirclePaint.setColor(Theme.getColor(Theme.key_dialogBackground)); + rect.set(backgroundPaddingLeft, backgroundPaddingTop + top, getMeasuredWidth() - backgroundPaddingLeft, backgroundPaddingTop + top + AndroidUtilities.dp(24)); + canvas.drawRoundRect(rect, AndroidUtilities.dp(12) * rad, AndroidUtilities.dp(12) * rad, Theme.dialogs_onlineCirclePaint); + } + + if ((selectedMenuItem == null || selectedMenuItem.getAlpha() != 1.0f) && rad != 0) { + float alphaProgress = selectedMenuItem == null ? 1.0f : 1.0f - selectedMenuItem.getAlpha(); + int w = AndroidUtilities.dp(36); + rect.set((getMeasuredWidth() - w) / 2, y, (getMeasuredWidth() + w) / 2, y + AndroidUtilities.dp(4)); + int color = Theme.getColor(Theme.key_sheet_scrollUp); + int alpha = Color.alpha(color); + Theme.dialogs_onlineCirclePaint.setColor(color); + Theme.dialogs_onlineCirclePaint.setAlpha((int) (alpha * alphaProgress * rad)); + canvas.drawRoundRect(rect, AndroidUtilities.dp(2), AndroidUtilities.dp(2), Theme.dialogs_onlineCirclePaint); + } + + int color1 = Theme.getColor(Theme.key_dialogBackground); + int finalColor = Color.argb((int) (255 * actionBar.getAlpha()), (int) (Color.red(color1) * 0.8f), (int) (Color.green(color1) * 0.8f), (int) (Color.blue(color1) * 0.8f)); + Theme.dialogs_onlineCirclePaint.setColor(finalColor); + canvas.drawRect(backgroundPaddingLeft, 0, getMeasuredWidth() - backgroundPaddingLeft, AndroidUtilities.statusBarHeight, Theme.dialogs_onlineCirclePaint); } @Override public void setTranslationY(float translationY) { + if (currentSheetAnimationType == 0) { + initialTranslationY = translationY; + } + if (currentSheetAnimationType == 1) { + if (translationY < 0) { + gridView.setTranslationY(translationY); + float scale = -0.1f * (translationY / 40.0f); + for (int a = 0, N = gridView.getChildCount(); a < N; a++) { + View child = gridView.getChildAt(a); + if (child instanceof PhotoAttachCameraCell) { + PhotoAttachCameraCell cell = (PhotoAttachCameraCell) child; + cell.getImageView().setScaleX(1.0f + scale); + cell.getImageView().setScaleY(1.0f + scale); + } else if (child instanceof PhotoAttachPhotoCell) { + PhotoAttachPhotoCell cell = (PhotoAttachPhotoCell) child; + cell.getCheckBox().setScaleX(1.0f + scale); + cell.getCheckBox().setScaleY(1.0f + scale); + } + } + translationY = 0; + buttonsRecyclerView.setTranslationY(0); + } else { + gridView.setTranslationY(0); + buttonsRecyclerView.setTranslationY(-translationY + buttonsRecyclerView.getMeasuredHeight() * (translationY / initialTranslationY)); + } + } super.setTranslationY(translationY); checkCameraViewPosition(); } }; - - nestedScrollChild = listView; - listView.setWillNotDraw(false); - listView.setClipToPadding(false); - listView.setLayoutManager(layoutManager = new LinearLayoutManager(getContext())); - layoutManager.setOrientation(LinearLayoutManager.VERTICAL); - listView.setAdapter(adapter = new ListAdapter(context)); - listView.setVerticalScrollBarEnabled(false); - listView.setEnabled(true); - listView.setGlowColor(Theme.getColor(Theme.key_dialogScrollGlow)); - listView.addItemDecoration(new RecyclerView.ItemDecoration() { - @Override - public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) { - outRect.left = 0; - outRect.right = 0; - outRect.top = 0; - outRect.bottom = 0; - } - }); - - listView.setOnScrollListener(new RecyclerView.OnScrollListener() { - @Override - public void onScrolled(RecyclerView recyclerView, int dx, int dy) { - if (listView.getChildCount() <= 0) { - return; - } - if (hintShowed) { - if (layoutManager.findLastVisibleItemPosition() > 1) { - hideHint(); - hintShowed = false; - MessagesController.getGlobalMainSettings().edit().putBoolean("bothint", true).commit(); - } - } - updateLayout(); - checkCameraViewPosition(); - } - }); + containerView = sizeNotifierFrameLayout; + containerView.setWillNotDraw(false); containerView.setPadding(backgroundPaddingLeft, 0, backgroundPaddingLeft, 0); - containerView.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO); - attachView = new FrameLayout(context) { + selectedTextView = new TextView(context); + selectedTextView.setTextColor(Theme.getColor(Theme.key_dialogTextBlack)); + selectedTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16); + selectedTextView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); + selectedTextView.setGravity(Gravity.LEFT | Gravity.TOP); + selectedTextView.setVisibility(View.INVISIBLE); + selectedTextView.setAlpha(0.0f); + containerView.addView(selectedTextView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.TOP | Gravity.LEFT, 23, 0, 48, 0)); + + actionBar = new ActionBar(context) { @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - if (baseFragment instanceof ChatActivity) { - super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(298), MeasureSpec.EXACTLY)); - } else { - super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(203), MeasureSpec.EXACTLY)); - } - } - - @Override - protected void onLayout(boolean changed, int left, int top, int right, int bottom) { - int width = right - left; - int height = bottom - top; - int t = AndroidUtilities.dp(8); - attachPhotoRecyclerView.layout(0, t, width, t + attachPhotoRecyclerView.getMeasuredHeight()); - progressView.layout(0, t, width, t + progressView.getMeasuredHeight()); - lineView.layout(0, AndroidUtilities.dp(96), width, AndroidUtilities.dp(96) + lineView.getMeasuredHeight()); - hintTextView.layout(width - hintTextView.getMeasuredWidth() - AndroidUtilities.dp(5), height - hintTextView.getMeasuredHeight() - AndroidUtilities.dp(5), width - AndroidUtilities.dp(5), height - AndroidUtilities.dp(5)); - int x = (width - mediaBanTooltip.getMeasuredWidth()) / 2; - int y = t + (attachPhotoRecyclerView.getMeasuredHeight() - mediaBanTooltip.getMeasuredHeight()) / 2; - mediaBanTooltip.layout(x, y, x + mediaBanTooltip.getMeasuredWidth(), y + mediaBanTooltip.getMeasuredHeight()); - - int diff = (width - AndroidUtilities.dp(85 * 4 + 20)) / 3; - int num = 0; - for (int a = 0; a < 8; a++) { - if (views[a] == null) { - continue; + public void setAlpha(float alpha) { + super.setAlpha(alpha); + containerView.invalidate(); + if (frameLayout2 != null && buttonsRecyclerView != null) { + if (frameLayout2.getTag() == null) { + buttonsRecyclerView.setAlpha(1.0f - alpha); + shadow.setAlpha(1.0f - alpha); + buttonsRecyclerView.setTranslationY(AndroidUtilities.dp(44) * alpha); + frameLayout2.setTranslationY(AndroidUtilities.dp(48) * alpha); + shadow.setTranslationY(AndroidUtilities.dp(92) * alpha); + } else { + float value = alpha == 0.0f ? 1.0f : 0.0f; + if (buttonsRecyclerView.getAlpha() != value) { + buttonsRecyclerView.setAlpha(value); + } } - y = AndroidUtilities.dp(105 + 97 * (num / 4)); - x = AndroidUtilities.dp(10) + (num % 4) * (AndroidUtilities.dp(85) + diff); - views[a].layout(x, y, x + views[a].getMeasuredWidth(), y + views[a].getMeasuredHeight()); - num++; } } }; + actionBar.setBackgroundColor(Theme.getColor(Theme.key_dialogBackground)); + actionBar.setBackButtonImage(R.drawable.ic_ab_back); + actionBar.setItemsColor(Theme.getColor(Theme.key_dialogTextBlack), false); + actionBar.setItemsBackgroundColor(Theme.getColor(Theme.key_dialogButtonSelector), false); + actionBar.setTitleColor(Theme.getColor(Theme.key_dialogTextBlack)); + actionBar.setOccupyStatusBar(false); + actionBar.setAlpha(0.0f); + containerView.addView(actionBar, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); + actionBar.setActionBarMenuOnItemClick(new ActionBar.ActionBarMenuOnItemClick() { + @Override + public void onItemClick(int id) { + if (id == -1) { + dismiss(); + } else { + if (id == group || id == compress) { + if (maxSelectedPhotos > 0 && selectedPhotosOrder.size() > 1 && baseFragment instanceof ChatActivity) { + ChatActivity chatActivity = (ChatActivity) baseFragment; + TLRPC.Chat chat = chatActivity.getCurrentChat(); + if (chat != null && !ChatObject.hasAdminRights(chat) && chat.slowmode_enabled) { + AlertsCreator.createSimpleAlert(getContext(), LocaleController.getString("Slowmode", R.string.Slowmode), LocaleController.getString("SlowmodeSendError", R.string.SlowmodeSendError)).show(); + return; + } + } + } + if (id == group) { + applyCaption(); + delegate.didPressedButton(7, false); + } else if (id == compress) { + applyCaption(); + delegate.didPressedButton(4, true); + } else if (id >= 10) { + selectedAlbumEntry = dropDownAlbums.get(id - 10); + if (selectedAlbumEntry == galleryAlbumEntry) { + dropDown.setText(LocaleController.getString("ChatGallery", R.string.ChatGallery)); + } else { + dropDown.setText(selectedAlbumEntry.bucketName); + } + adapter.notifyDataSetChanged(); + cameraAttachAdapter.notifyDataSetChanged(); + layoutManager.scrollToPositionWithOffset(0, -gridView.getPaddingTop() + AndroidUtilities.dp(7)); + } + } + } + }); - views[8] = attachPhotoRecyclerView = new RecyclerListView(context); - attachPhotoRecyclerView.setVerticalScrollBarEnabled(true); - attachPhotoRecyclerView.setAdapter(photoAttachAdapter = new PhotoAttachAdapter(context, true)); - attachPhotoRecyclerView.setClipToPadding(false); - attachPhotoRecyclerView.setPadding(AndroidUtilities.dp(8), 0, AndroidUtilities.dp(8), 0); - attachPhotoRecyclerView.setItemAnimator(null); - attachPhotoRecyclerView.setLayoutAnimation(null); - attachPhotoRecyclerView.setOverScrollMode(RecyclerListView.OVER_SCROLL_NEVER); - attachView.addView(attachPhotoRecyclerView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 80)); - attachPhotoLayoutManager = new LinearLayoutManager(context) { + selectedMenuItem = new ActionBarMenuItem(context, null, 0, Theme.getColor(Theme.key_dialogTextBlack)) { + @Override + public void setAlpha(float alpha) { + super.setAlpha(alpha); + updateSelectedPosition(); + containerView.invalidate(); + } + }; + selectedMenuItem.setLongClickEnabled(false); + selectedMenuItem.setIcon(R.drawable.ic_ab_other); + selectedMenuItem.setContentDescription(LocaleController.getString("AccDescrMoreOptions", R.string.AccDescrMoreOptions)); + selectedMenuItem.addSubItem(group, LocaleController.getString("SendWithoutGrouping", R.string.SendWithoutGrouping)); + selectedMenuItem.addSubItem(compress, LocaleController.getString("SendWithoutCompression", R.string.SendWithoutCompression)); + selectedMenuItem.setVisibility(View.INVISIBLE); + selectedMenuItem.setAlpha(0.0f); + selectedMenuItem.setSubMenuOpenSide(2); + selectedMenuItem.setDelegate(id -> actionBar.getActionBarMenuOnItemClick().onItemClick(id)); + selectedMenuItem.setAdditionalYOffset(AndroidUtilities.dp(72)); + selectedMenuItem.setTranslationX(AndroidUtilities.dp(6)); + selectedMenuItem.setBackgroundDrawable(Theme.createSelectorDrawable(Theme.getColor(Theme.key_dialogButtonSelector), 6)); + containerView.addView(selectedMenuItem, LayoutHelper.createFrame(48, 48, Gravity.TOP | Gravity.RIGHT)); + selectedMenuItem.setOnClickListener(v -> selectedMenuItem.toggleSubMenu()); + + gridView = new RecyclerListView(context) { + @Override + public void setTranslationY(float translationY) { + super.setTranslationY(translationY); + containerView.invalidate(); + } + + @Override + public boolean onTouchEvent(MotionEvent e) { + if (e.getAction() == MotionEvent.ACTION_DOWN && e.getY() < scrollOffsetY - AndroidUtilities.dp(44)) { + return false; + } + return super.onTouchEvent(e); + } + + @Override + public boolean onInterceptTouchEvent(MotionEvent e) { + if (e.getAction() == MotionEvent.ACTION_DOWN && e.getY() < scrollOffsetY - AndroidUtilities.dp(44)) { + return false; + } + return super.onInterceptTouchEvent(e); + } + }; + gridView.setAdapter(adapter = new PhotoAttachAdapter(context, true)); + gridView.setClipToPadding(false); + gridView.setItemAnimator(null); + gridView.setLayoutAnimation(null); + gridView.setVerticalScrollBarEnabled(false); + gridView.setGlowColor(Theme.getColor(Theme.key_dialogScrollGlow)); + containerView.addView(gridView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.TOP | Gravity.LEFT, 0, 11, 0, 0)); + gridView.setOnScrollListener(new RecyclerView.OnScrollListener() { + @Override + public void onScrolled(RecyclerView recyclerView, int dx, int dy) { + if (gridView.getChildCount() <= 0) { + return; + } + updateLayout(true); + checkCameraViewPosition(); + } + + @Override + public void onScrollStateChanged(RecyclerView recyclerView, int newState) { + if (newState == RecyclerView.SCROLL_STATE_IDLE) { + int offset = AndroidUtilities.dp(13) + (selectedMenuItem != null ? AndroidUtilities.dp(selectedMenuItem.getAlpha() * 26) : 0); + int top = scrollOffsetY - backgroundPaddingTop - offset; + if (top + backgroundPaddingTop < ActionBar.getCurrentActionBarHeight()) { + View child = gridView.getChildAt(0); + RecyclerListView.Holder holder = (RecyclerListView.Holder) gridView.findViewHolderForAdapterPosition(0); + if (holder != null && holder.itemView.getTop() > AndroidUtilities.dp(7)) { + gridView.smoothScrollBy(0, holder.itemView.getTop() - AndroidUtilities.dp(7)); + } + } + } + } + }); + layoutManager = new GridLayoutManager(context, itemSize) { @Override public boolean supportsPredictiveItemAnimations() { return false; } }; - attachPhotoLayoutManager.setOrientation(LinearLayoutManager.HORIZONTAL); - attachPhotoRecyclerView.setLayoutManager(attachPhotoLayoutManager); - attachPhotoRecyclerView.setOnItemClickListener((view, position) -> { - if (baseFragment == null || baseFragment.getParentActivity() == null) { + layoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() { + @Override + public int getSpanSize(int position) { + if (position == adapter.itemsCount - 1) { + return layoutManager.getSpanCount(); + } + return itemSize + (position % itemsPerRow != itemsPerRow - 1 ? AndroidUtilities.dp(5) : 0); + } + }); + gridView.setLayoutManager(layoutManager); + gridView.setOnItemClickListener((view, position) -> { + if (!mediaEnabled || baseFragment == null || baseFragment.getParentActivity() == null) { return; } - if (!deviceHasGoodCamera || position != 0) { - if (deviceHasGoodCamera) { + if (Build.VERSION.SDK_INT >= 23) { + if (position == 0 && noCameraPermissions) { + try { + baseFragment.getParentActivity().requestPermissions(new String[]{Manifest.permission.CAMERA}, 18); + } catch (Exception ignore) { + + } + return; + } else if (noGalleryPermissions) { + try { + baseFragment.getParentActivity().requestPermissions(new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, 4); + } catch (Exception ignore) { + + } + return; + } + } + if (position != 0 || selectedAlbumEntry != galleryAlbumEntry) { + if (selectedAlbumEntry == galleryAlbumEntry) { position--; } ArrayList arrayList = getAllPhotosArray(); @@ -888,7 +1119,7 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N } PhotoViewer.getInstance().setParentActivity(baseFragment.getParentActivity()); PhotoViewer.getInstance().setParentAlert(ChatAttachAlert.this); - PhotoViewer.getInstance().setMaxSelectedPhotos(maxSelectedPhotos); + PhotoViewer.getInstance().setMaxSelectedPhotos(maxSelectedPhotos, allowOrder); ChatActivity chatActivity; int type; if (baseFragment instanceof ChatActivity) { @@ -901,98 +1132,57 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N PhotoViewer.getInstance().openPhotoForSelect(arrayList, position, type, photoViewerProvider, chatActivity); AndroidUtilities.hideKeyboard(baseFragment.getFragmentView().findFocus()); } else { - openCamera(true); - } - }); - attachPhotoRecyclerView.setOnScrollListener(new RecyclerView.OnScrollListener() { - @Override - public void onScrolled(RecyclerView recyclerView, int dx, int dy) { - checkCameraViewPosition(); - } - }); - - views[11] = mediaBanTooltip = new CorrectlyMeasuringTextView(context); - mediaBanTooltip.setBackgroundDrawable(Theme.createRoundRectDrawable(AndroidUtilities.dp(3), Theme.getColor(Theme.key_chat_attachMediaBanBackground))); - mediaBanTooltip.setTextColor(Theme.getColor(Theme.key_chat_attachMediaBanText)); - mediaBanTooltip.setPadding(AndroidUtilities.dp(8), AndroidUtilities.dp(8), AndroidUtilities.dp(8), AndroidUtilities.dp(8)); - mediaBanTooltip.setGravity(Gravity.CENTER_VERTICAL); - mediaBanTooltip.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); - mediaBanTooltip.setVisibility(View.INVISIBLE); - attachView.addView(mediaBanTooltip, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.LEFT | Gravity.TOP, 14, 0, 14, 0)); - - views[9] = progressView = new EmptyTextProgressView(context); - if (Build.VERSION.SDK_INT >= 23 && getContext().checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { - progressView.setText(LocaleController.getString("PermissionStorage", R.string.PermissionStorage)); - progressView.setTextSize(16); - } else { - progressView.setText(LocaleController.getString("NoPhotos", R.string.NoPhotos)); - progressView.setTextSize(20); - } - attachView.addView(progressView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 80)); - attachPhotoRecyclerView.setEmptyView(progressView); - - views[10] = lineView = new View(getContext()) { - @Override - public boolean hasOverlappingRendering() { - return false; - } - }; - lineView.setBackgroundColor(Theme.getColor(Theme.key_dialogGrayLine)); - attachView.addView(lineView, new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 1, Gravity.TOP | Gravity.LEFT)); - - CharSequence[] items = new CharSequence[]{ - LocaleController.getString("ChatCamera", R.string.ChatCamera), - LocaleController.getString("ChatGallery", R.string.ChatGallery), - LocaleController.getString("ChatVideo", R.string.ChatVideo), - LocaleController.getString("AttachMusic", R.string.AttachMusic), - LocaleController.getString("ChatDocument", R.string.ChatDocument), - LocaleController.getString("AttachContact", R.string.AttachContact), - LocaleController.getString("ChatLocation", R.string.ChatLocation), - "" - }; - for (int a = 0; a < 8; a++) { - if (!(baseFragment instanceof ChatActivity)) { - if (a == 2 || a == 3 || a == 5 || a == 6) { - continue; - } - } - AttachButton attachButton = new AttachButton(context); - attachButtons.add(attachButton); - attachButton.setTextAndIcon(items[a], Theme.chat_attachButtonDrawables[a]); - attachView.addView(attachButton, LayoutHelper.createFrame(85, 91, Gravity.LEFT | Gravity.TOP)); - attachButton.setTag(a); - views[a] = attachButton; - if (a == 7) { - sendPhotosButton = attachButton; - sendPhotosButton.imageView.setPadding(0, AndroidUtilities.dp(4), 0, 0); - } else if (a == 4) { - sendDocumentsButton = attachButton; - } - attachButton.setOnClickListener(v -> { - if (buttonPressed) { - return; - } - Integer num = (Integer) v.getTag(); - if (deviceHasGoodCamera && num == 0 && baseFragment instanceof ChatActivity && ((ChatActivity) parentFragment).isSecretChat()) { + if (SharedConfig.inappCamera) { openCamera(true); } else { - buttonPressed = true; - delegate.didPressedButton(num); + if (delegate != null) { + delegate.didPressedButton(0, false); + } } - }); - } + } + }); + gridView.setOnItemLongClickListener((view, position) -> { + if (position == 0 && selectedAlbumEntry == galleryAlbumEntry) { + if (delegate != null) { + delegate.didPressedButton(0, false); + } + return true; + } + return false; + }); - hintTextView = new TextView(context); - hintTextView.setBackgroundDrawable(Theme.createRoundRectDrawable(AndroidUtilities.dp(3), Theme.getColor(Theme.key_chat_gifSaveHintBackground))); - hintTextView.setTextColor(Theme.getColor(Theme.key_chat_gifSaveHintText)); - hintTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); - hintTextView.setPadding(AndroidUtilities.dp(10), 0, AndroidUtilities.dp(10), 0); - hintTextView.setText(LocaleController.getString("AttachBotsHelp", R.string.AttachBotsHelp)); - hintTextView.setGravity(Gravity.CENTER_VERTICAL); - hintTextView.setVisibility(View.INVISIBLE); - hintTextView.setCompoundDrawablesWithIntrinsicBounds(R.drawable.scroll_tip, 0, 0, 0); - hintTextView.setCompoundDrawablePadding(AndroidUtilities.dp(8)); - attachView.addView(hintTextView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, 32, Gravity.RIGHT | Gravity.BOTTOM, 5, 0, 5, 5)); + ActionBarMenu menu = actionBar.createMenu(); + + dropDownContainer = new ActionBarMenuItem(context, menu, 0, 0); + dropDownContainer.setSubMenuOpenSide(1); + actionBar.addView(dropDownContainer, 0, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.MATCH_PARENT, Gravity.TOP | Gravity.LEFT, AndroidUtilities.isTablet() ? 64 : 56, 0, 40, 0)); + dropDownContainer.setOnClickListener(view -> dropDownContainer.toggleSubMenu()); + + dropDown = new TextView(context); + dropDown.setGravity(Gravity.LEFT); + dropDown.setSingleLine(true); + dropDown.setLines(1); + dropDown.setMaxLines(1); + dropDown.setEllipsize(TextUtils.TruncateAt.END); + dropDown.setTextColor(Theme.getColor(Theme.key_dialogTextBlack)); + dropDown.setText(LocaleController.getString("ChatGallery", R.string.ChatGallery)); + dropDown.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); + dropDownDrawable = context.getResources().getDrawable(R.drawable.ic_arrow_drop_down).mutate(); + dropDownDrawable.setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_dialogTextBlack), PorterDuff.Mode.MULTIPLY)); + dropDown.setCompoundDrawablePadding(AndroidUtilities.dp(4)); + dropDown.setPadding(0, 0, AndroidUtilities.dp(10), 0); + dropDownContainer.addView(dropDown, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_VERTICAL, 16, 0, 0, 0)); + + actionBarShadow = new View(context); + actionBarShadow.setAlpha(0.0f); + actionBarShadow.setBackgroundColor(Theme.getColor(Theme.key_dialogShadowLine)); + containerView.addView(actionBarShadow, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 1)); + + progressView = new EmptyTextProgressView(context); + progressView.setText(LocaleController.getString("NoPhotos", R.string.NoPhotos)); + progressView.setOnTouchListener(null); + progressView.setTextSize(20); + containerView.addView(progressView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 80)); if (loading) { progressView.showProgress(); @@ -1000,6 +1190,214 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N progressView.showTextView(); } + shadow = new View(context); + shadow.setBackgroundResource(R.drawable.header_shadow_reverse); + containerView.addView(shadow, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 3, Gravity.BOTTOM | Gravity.LEFT, 0, 0, 0, 92)); + + buttonsRecyclerView = new RecyclerListView(context) { + @Override + public void setTranslationY(float translationY) { + super.setTranslationY(translationY); + checkCameraViewPosition(); + } + }; + buttonsRecyclerView.setAdapter(buttonsAdapter = new ButtonsAdapter(context)); + buttonsRecyclerView.setLayoutManager(buttonsLayoutManager = new LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false)); + buttonsRecyclerView.setVerticalScrollBarEnabled(false); + buttonsRecyclerView.setHorizontalScrollBarEnabled(false); + buttonsRecyclerView.setItemAnimator(null); + buttonsRecyclerView.setLayoutAnimation(null); + buttonsRecyclerView.setGlowColor(Theme.getColor(Theme.key_dialogScrollGlow)); + buttonsRecyclerView.setBackgroundColor(Theme.getColor(Theme.key_dialogBackground)); + containerView.addView(buttonsRecyclerView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 92, Gravity.BOTTOM | Gravity.LEFT)); + buttonsRecyclerView.setOnItemClickListener((view, position) -> { + if (view instanceof AttachButton) { + AttachButton attachButton = (AttachButton) view; + delegate.didPressedButton((Integer) attachButton.getTag(), true); + } else if (view instanceof AttachBotButton) { + AttachBotButton button = (AttachBotButton) view; + delegate.didSelectBot(button.currentUser); + dismiss(); + } + }); + buttonsRecyclerView.setOnItemLongClickListener((view, position) -> { + if (view instanceof AttachBotButton) { + AttachBotButton button = (AttachBotButton) view; + if (baseFragment == null || button.currentUser == null) { + return false; + } + AlertDialog.Builder builder = new AlertDialog.Builder(getContext()); + builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); + builder.setMessage(LocaleController.formatString("ChatHintsDelete", R.string.ChatHintsDelete, ContactsController.formatName(button.currentUser.first_name, button.currentUser.last_name))); + builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), (dialogInterface, i) -> MediaDataController.getInstance(currentAccount).removeInline(button.currentUser.id)); + builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); + builder.show(); + return true; + } + return false; + }); + + frameLayout2 = new FrameLayout(context); + frameLayout2.setBackgroundColor(Theme.getColor(Theme.key_dialogBackground)); + frameLayout2.setVisibility(View.INVISIBLE); + frameLayout2.setAlpha(0.0f); + containerView.addView(frameLayout2, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 48, Gravity.LEFT | Gravity.BOTTOM)); + frameLayout2.setOnTouchListener((v, event) -> true); + + commentTextView = new EditTextEmoji(context, sizeNotifierFrameLayout, null, EditTextEmoji.STYLE_DIALOG) { + @Override + public boolean onInterceptTouchEvent(MotionEvent ev) { + if (!enterCommentEventSent) { + delegate.needEnterComment(); + ChatAttachAlert.this.setFocusable(true); + enterCommentEventSent = true; + AndroidUtilities.runOnUIThread(() -> commentTextView.openKeyboard()); + } + return super.onInterceptTouchEvent(ev); + } + }; + InputFilter[] inputFilters = new InputFilter[1]; + inputFilters[0] = new InputFilter.LengthFilter(MessagesController.getInstance(UserConfig.selectedAccount).maxCaptionLength); + commentTextView.setFilters(inputFilters); + commentTextView.setHint(LocaleController.getString("AddCaption", R.string.AddCaption)); + commentTextView.onResume(); + EditTextBoldCursor editText = commentTextView.getEditText(); + editText.setMaxLines(1); + editText.setSingleLine(true); + frameLayout2.addView(commentTextView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.TOP | Gravity.LEFT, 0, 0, 84, 0)); + + writeButtonContainer = new FrameLayout(context); + writeButtonContainer.setVisibility(View.INVISIBLE); + writeButtonContainer.setScaleX(0.2f); + writeButtonContainer.setScaleY(0.2f); + writeButtonContainer.setAlpha(0.0f); + writeButtonContainer.setContentDescription(LocaleController.getString("Send", R.string.Send)); + containerView.addView(writeButtonContainer, LayoutHelper.createFrame(60, 60, Gravity.RIGHT | Gravity.BOTTOM, 0, 0, 6, 10)); + writeButtonContainer.setOnClickListener(v -> sendPressed(false)); + writeButtonContainer.setOnLongClickListener(view -> { + if (!(baseFragment instanceof ChatActivity) || editingMessageObject != null) { + return false; + } + ChatActivity chatActivity = (ChatActivity) baseFragment; + TLRPC.Chat chat = chatActivity.getCurrentChat(); + TLRPC.User user = chatActivity.getCurrentUser(); + if (chatActivity.getCurrentEncryptedChat() != null || ChatObject.isChannel(chat) && !chat.megagroup || UserObject.isUserSelf(user)) { + return false; + } + + if (sendPopupLayout == null) { + sendPopupLayout = new ActionBarPopupWindow.ActionBarPopupWindowLayout(getContext()); + sendPopupLayout.setAnimationEnabled(false); + sendPopupLayout.setOnTouchListener(new View.OnTouchListener() { + + private android.graphics.Rect popupRect = new android.graphics.Rect(); + + @Override + public boolean onTouch(View v, MotionEvent event) { + if (event.getActionMasked() == MotionEvent.ACTION_DOWN) { + if (sendPopupWindow != null && sendPopupWindow.isShowing()) { + v.getHitRect(popupRect); + if (!popupRect.contains((int) event.getX(), (int) event.getY())) { + sendPopupWindow.dismiss(); + } + } + } + return false; + } + }); + sendPopupLayout.setDispatchKeyEventListener(keyEvent -> { + if (keyEvent.getKeyCode() == KeyEvent.KEYCODE_BACK && keyEvent.getRepeatCount() == 0 && sendPopupWindow != null && sendPopupWindow.isShowing()) { + sendPopupWindow.dismiss(); + } + }); + sendPopupLayout.setShowedFromBotton(false); + + itemCell = new ActionBarMenuSubItem(getContext()); + itemCell.setTextAndIcon(LocaleController.getString("SendWithoutSound", R.string.SendWithoutSound), R.drawable.input_notify_off); + itemCell.setMinimumWidth(AndroidUtilities.dp(196)); + + sendPopupLayout.addView(itemCell, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 48, LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT)); + itemCell.setOnClickListener(v -> { + if (sendPopupWindow != null && sendPopupWindow.isShowing()) { + sendPopupWindow.dismiss(); + } + sendPressed(true); + }); + + sendPopupWindow = new ActionBarPopupWindow(sendPopupLayout, LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT); + sendPopupWindow.setAnimationEnabled(false); + sendPopupWindow.setAnimationStyle(R.style.PopupContextAnimation2); + sendPopupWindow.setOutsideTouchable(true); + sendPopupWindow.setClippingEnabled(true); + sendPopupWindow.setInputMethodMode(ActionBarPopupWindow.INPUT_METHOD_NOT_NEEDED); + sendPopupWindow.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED); + sendPopupWindow.getContentView().setFocusableInTouchMode(true); + } + + sendPopupLayout.measure(View.MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(1000), View.MeasureSpec.AT_MOST), View.MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(1000), View.MeasureSpec.AT_MOST)); + sendPopupWindow.setFocusable(true); + int[] location = new int[2]; + view.getLocationInWindow(location); + sendPopupWindow.showAtLocation(view, Gravity.LEFT | Gravity.TOP, location[0] + view.getMeasuredWidth() - sendPopupLayout.getMeasuredWidth() + AndroidUtilities.dp(8), location[1] - sendPopupLayout.getMeasuredHeight() - AndroidUtilities.dp(2)); + sendPopupWindow.dimBehind(); + view.performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP, HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING); + + return false; + }); + + writeButton = new ImageView(context); + writeButtonDrawable = Theme.createSimpleSelectorCircleDrawable(AndroidUtilities.dp(56), Theme.getColor(Theme.key_dialogFloatingButton), Theme.getColor(Theme.key_dialogFloatingButtonPressed)); + if (Build.VERSION.SDK_INT < 21) { + Drawable shadowDrawable = context.getResources().getDrawable(R.drawable.floating_shadow_profile).mutate(); + shadowDrawable.setColorFilter(new PorterDuffColorFilter(0xff000000, PorterDuff.Mode.MULTIPLY)); + CombinedDrawable combinedDrawable = new CombinedDrawable(shadowDrawable, writeButtonDrawable, 0, 0); + combinedDrawable.setIconSize(AndroidUtilities.dp(56), AndroidUtilities.dp(56)); + writeButtonDrawable = combinedDrawable; + } + writeButton.setBackgroundDrawable(writeButtonDrawable); + writeButton.setImageResource(R.drawable.attach_send); + writeButton.setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_dialogFloatingIcon), PorterDuff.Mode.MULTIPLY)); + writeButton.setScaleType(ImageView.ScaleType.CENTER); + if (Build.VERSION.SDK_INT >= 21) { + writeButton.setOutlineProvider(new ViewOutlineProvider() { + @SuppressLint("NewApi") + @Override + public void getOutline(View view, Outline outline) { + outline.setOval(0, 0, AndroidUtilities.dp(56), AndroidUtilities.dp(56)); + } + }); + } + writeButtonContainer.addView(writeButton, LayoutHelper.createFrame(Build.VERSION.SDK_INT >= 21 ? 56 : 60, Build.VERSION.SDK_INT >= 21 ? 56 : 60, Gravity.LEFT | Gravity.TOP, Build.VERSION.SDK_INT >= 21 ? 2 : 0, 0, 0, 0)); + + textPaint.setTextSize(AndroidUtilities.dp(12)); + textPaint.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); + + selectedCountView = new View(context) { + @Override + protected void onDraw(Canvas canvas) { + String text = String.format("%d", Math.max(1, selectedPhotosOrder.size())); + int textSize = (int) Math.ceil(textPaint.measureText(text)); + int size = Math.max(AndroidUtilities.dp(16) + textSize, AndroidUtilities.dp(24)); + int cx = getMeasuredWidth() / 2; + int cy = getMeasuredHeight() / 2; + + textPaint.setColor(Theme.getColor(Theme.key_dialogRoundCheckBoxCheck)); + paint.setColor(Theme.getColor(Theme.key_dialogBackground)); + rect.set(cx - size / 2, 0, cx + size / 2, getMeasuredHeight()); + canvas.drawRoundRect(rect, AndroidUtilities.dp(12), AndroidUtilities.dp(12), paint); + + paint.setColor(Theme.getColor(Theme.key_dialogRoundCheckBox)); + rect.set(cx - size / 2 + AndroidUtilities.dp(2), AndroidUtilities.dp(2), cx + size / 2 - AndroidUtilities.dp(2), getMeasuredHeight() - AndroidUtilities.dp(2)); + canvas.drawRoundRect(rect, AndroidUtilities.dp(10), AndroidUtilities.dp(10), paint); + + canvas.drawText(text, cx - textSize / 2, AndroidUtilities.dp(16.2f), textPaint); + } + }; + selectedCountView.setAlpha(0.0f); + selectedCountView.setScaleX(0.2f); + selectedCountView.setScaleY(0.2f); + containerView.addView(selectedCountView, LayoutHelper.createFrame(42, 24, Gravity.RIGHT | Gravity.BOTTOM, 0, 0, -8, 9)); + recordTime = new TextView(context); recordTime.setBackgroundResource(R.drawable.system); recordTime.getBackground().setColorFilter(new PorterDuffColorFilter(0x66000000, PorterDuff.Mode.MULTIPLY)); @@ -1013,29 +1411,43 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N cameraPanel = new FrameLayout(context) { @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { - int cx = getMeasuredWidth() / 2; - int cy = getMeasuredHeight() / 2; + int cx; + int cy; int cx2; int cy2; - shutterButton.layout(cx - shutterButton.getMeasuredWidth() / 2, cy - shutterButton.getMeasuredHeight() / 2, cx + shutterButton.getMeasuredWidth() / 2, cy + shutterButton.getMeasuredHeight() / 2); - if (getMeasuredWidth() == AndroidUtilities.dp(100)) { - cx = cx2 = getMeasuredWidth() / 2; + int cx3; + int cy3; + + if (getMeasuredWidth() == AndroidUtilities.dp(126)) { + cx = getMeasuredWidth() / 2; + cy = getMeasuredHeight() / 2; + cx3 = cx2 = getMeasuredWidth() / 2; cy2 = cy + cy / 2 + AndroidUtilities.dp(17); - cy = cy / 2 - AndroidUtilities.dp(17); + cy3 = cy / 2 - AndroidUtilities.dp(17); } else { + cx = getMeasuredWidth() / 2; + cy = getMeasuredHeight() / 2 - AndroidUtilities.dp(13); cx2 = cx + cx / 2 + AndroidUtilities.dp(17); - cx = cx / 2 - AndroidUtilities.dp(17); - cy = cy2 = getMeasuredHeight() / 2; + cx3 = cx / 2 - AndroidUtilities.dp(17); + cy3 = cy2 = getMeasuredHeight() / 2 - AndroidUtilities.dp(13); } + + int y = getMeasuredHeight() - tooltipTextView.getMeasuredHeight() - AndroidUtilities.dp(12); + if (getMeasuredWidth() == AndroidUtilities.dp(126)) { + tooltipTextView.layout(cx - tooltipTextView.getMeasuredWidth() / 2, getMeasuredHeight(), cx + tooltipTextView.getMeasuredWidth() / 2, getMeasuredHeight() + tooltipTextView.getMeasuredHeight()); + } else { + tooltipTextView.layout(cx - tooltipTextView.getMeasuredWidth() / 2, y, cx + tooltipTextView.getMeasuredWidth() / 2, y + tooltipTextView.getMeasuredHeight()); + } + shutterButton.layout(cx - shutterButton.getMeasuredWidth() / 2, cy - shutterButton.getMeasuredHeight() / 2, cx + shutterButton.getMeasuredWidth() / 2, cy + shutterButton.getMeasuredHeight() / 2); switchCameraButton.layout(cx2 - switchCameraButton.getMeasuredWidth() / 2, cy2 - switchCameraButton.getMeasuredHeight() / 2, cx2 + switchCameraButton.getMeasuredWidth() / 2, cy2 + switchCameraButton.getMeasuredHeight() / 2); for (int a = 0; a < 2; a++) { - flashModeButton[a].layout(cx - flashModeButton[a].getMeasuredWidth() / 2, cy - flashModeButton[a].getMeasuredHeight() / 2, cx + flashModeButton[a].getMeasuredWidth() / 2, cy + flashModeButton[a].getMeasuredHeight() / 2); + flashModeButton[a].layout(cx3 - flashModeButton[a].getMeasuredWidth() / 2, cy3 - flashModeButton[a].getMeasuredHeight() / 2, cx3 + flashModeButton[a].getMeasuredWidth() / 2, cy3 + flashModeButton[a].getMeasuredHeight() / 2); } } }; cameraPanel.setVisibility(View.GONE); cameraPanel.setAlpha(0.0f); - container.addView(cameraPanel, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 100, Gravity.LEFT | Gravity.BOTTOM)); + container.addView(cameraPanel, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 126, Gravity.LEFT | Gravity.BOTTOM)); counterTextView = new TextView(context); counterTextView.setBackgroundResource(R.drawable.photos_rounded); @@ -1057,11 +1469,23 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N CameraController.getInstance().stopPreview(cameraView.getCameraSession()); }); + zoomControlView = new ZoomControlView(context); + zoomControlView.setVisibility(View.GONE); + zoomControlView.setAlpha(0.0f); + container.addView(zoomControlView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, 50, Gravity.LEFT | Gravity.TOP, 0, 0, 0, 100 + 16)); + zoomControlView.setDelegate(zoom -> { + if (cameraView != null) { + cameraView.setZoom(cameraZoom = zoom); + } + showZoomControls(true, true); + }); + shutterButton = new ShutterButton(context); cameraPanel.addView(shutterButton, LayoutHelper.createFrame(84, 84, Gravity.CENTER)); shutterButton.setDelegate(new ShutterButton.ShutterButtonDelegate() { private File outputFile; + private boolean zoomingWas; @Override public boolean shutterLongPressed() { @@ -1079,6 +1503,7 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N flashModeButton[a].setAlpha(0.0f); } switchCameraButton.setAlpha(0.0f); + tooltipTextView.setAlpha(0.0f); outputFile = AndroidUtilities.generateVideoPath(baseFragment instanceof ChatActivity && ((ChatActivity) baseFragment).isSecretChat()); recordTime.setAlpha(1.0f); recordTime.setText(String.format("%02d:%02d", 0, 0)); @@ -1163,6 +1588,27 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N openPhotoViewer(photoEntry, sameTakePictureOrientation, false); }); } + + @Override + public boolean onTranslationChanged(float x, float y) { + boolean isPortrait = container.getWidth() < container.getHeight(); + float val1 = isPortrait ? x : y; + float val2 = isPortrait ? y : x; + if (!zoomingWas && Math.abs(val1) > Math.abs(val2)) { + return zoomControlView.getTag() == null; + } + if (val2 < 0) { + showZoomControls(true, true); + zoomControlView.setZoom(-val2 / AndroidUtilities.dp(200), true); + zoomingWas = true; + return false; + } + zoomControlView.setZoom(0, true); + if (x == 0 && y == 0) { + zoomingWas = false; + } + return !zoomingWas && (x != 0 || y != 0); + } }); shutterButton.setFocusable(true); shutterButton.setContentDescription(LocaleController.getString("AccDescrShutter", R.string.AccDescrShutter)); @@ -1176,12 +1622,12 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N } cameraInitied = false; cameraView.switchCamera(); - ObjectAnimator animator = ObjectAnimator.ofFloat(switchCameraButton, "scaleX", 0.0f).setDuration(100); + ObjectAnimator animator = ObjectAnimator.ofFloat(switchCameraButton, View.SCALE_X, 0.0f).setDuration(100); animator.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animator) { switchCameraButton.setImageResource(cameraView != null && cameraView.isFrontface() ? R.drawable.camera_revert1 : R.drawable.camera_revert2); - ObjectAnimator.ofFloat(switchCameraButton, "scaleX", 1.0f).setDuration(100).start(); + ObjectAnimator.ofFloat(switchCameraButton, View.SCALE_X, 1.0f).setDuration(100).start(); } }); animator.start(); @@ -1209,10 +1655,10 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N setCameraFlashModeIcon(nextImage, next); AnimatorSet animatorSet = new AnimatorSet(); animatorSet.playTogether( - ObjectAnimator.ofFloat(currentImage, "translationY", 0, AndroidUtilities.dp(48)), - ObjectAnimator.ofFloat(nextImage, "translationY", -AndroidUtilities.dp(48), 0), - ObjectAnimator.ofFloat(currentImage, "alpha", 1.0f, 0.0f), - ObjectAnimator.ofFloat(nextImage, "alpha", 0.0f, 1.0f)); + ObjectAnimator.ofFloat(currentImage, View.TRANSLATION_Y, 0, AndroidUtilities.dp(48)), + ObjectAnimator.ofFloat(nextImage, View.TRANSLATION_Y, -AndroidUtilities.dp(48), 0), + ObjectAnimator.ofFloat(currentImage, View.ALPHA, 1.0f, 0.0f), + ObjectAnimator.ofFloat(nextImage, View.ALPHA, 0.0f, 1.0f)); animatorSet.setDuration(200); animatorSet.addListener(new AnimatorListenerAdapter() { @Override @@ -1224,9 +1670,17 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N }); animatorSet.start(); }); - flashModeButton[a].setContentDescription("flash mode "+a); + flashModeButton[a].setContentDescription("flash mode " + a); } + tooltipTextView = new TextView(context); + tooltipTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 15); + tooltipTextView.setTextColor(0xffffffff); + tooltipTextView.setText(LocaleController.getString("TapForVideo", R.string.TapForVideo)); + tooltipTextView.setShadowLayer(AndroidUtilities.dp(3.33333f), 0, AndroidUtilities.dp(0.666f), 0x4c000000); + tooltipTextView.setPadding(AndroidUtilities.dp(6), 0, AndroidUtilities.dp(6), 0); + cameraPanel.addView(tooltipTextView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM, 0, 0, 0, 16)); + cameraPhotoRecyclerView = new RecyclerListView(context) { @Override public void requestLayout() { @@ -1273,64 +1727,227 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N editingMessageObject = messageObject; if (editingMessageObject != null) { maxSelectedPhotos = 1; + allowOrder = false; } else { maxSelectedPhotos = -1; + allowOrder = true; } - adapter.notifyDataSetChanged(); - for (int a = 0; a < 4; a++) { - boolean enabled; - AttachButton attachButton = attachButtons.get(3 + a); - if (a < 2) { - enabled = editingMessageObject == null || !editingMessageObject.hasValidGroupId(); - } else { - enabled = editingMessageObject == null; - } - attachButton.setEnabled(enabled); - attachButton.setAlpha(enabled ? 1.0f : 0.2f); - } - updatePollMusicButton(); + buttonsAdapter.notifyDataSetChanged(); } public MessageObject getEditingMessageObject() { return editingMessageObject; } - private void updatePollMusicButton() { - if (baseFragment instanceof ChatActivity) { - if (attachButtons.isEmpty()) { - return; - } - boolean allowPoll; - if (editingMessageObject != null) { - allowPoll = false; - } else { - TLRPC.Chat currentChat = ((ChatActivity) baseFragment).getCurrentChat(); - allowPoll = currentChat != null && ChatObject.canSendPolls(currentChat); - } - String text = allowPoll ? LocaleController.getString("Poll", R.string.Poll) : LocaleController.getString("AttachMusic", R.string.AttachMusic); - AttachButton attachButton = attachButtons.get(3); - attachButton.setTag(allowPoll ? 9 : 3); - attachButton.setTextAndIcon(text, Theme.chat_attachButtonDrawables[allowPoll ? 9 : 3]); + private void applyCaption() { + if (commentTextView.length() <= 0) { + return; + } + int imageId = (Integer) selectedPhotosOrder.get(0); + Object entry = selectedPhotos.get(imageId); + if (entry instanceof MediaController.PhotoEntry) { + MediaController.PhotoEntry photoEntry = (MediaController.PhotoEntry) entry; + photoEntry.caption = commentTextView.getText().toString(); + } else if (entry instanceof MediaController.SearchImage) { + MediaController.SearchImage searchImage = (MediaController.SearchImage) entry; + searchImage.caption = commentTextView.getText().toString(); } } - private void updatePhotosCounter() { + private void sendPressed(boolean forceSilent) { + if (buttonPressed) { + return; + } + if (baseFragment instanceof ChatActivity) { + ChatActivity chatActivity = (ChatActivity) baseFragment; + TLRPC.Chat chat = chatActivity.getCurrentChat(); + TLRPC.User user = chatActivity.getCurrentUser(); + if (user != null || ChatObject.isChannel(chat) && chat.megagroup || !ChatObject.isChannel(chat)) { + MessagesController.getNotificationsSettings(currentAccount).edit().putBoolean("silent_" + chatActivity.getDialogId(), forceSilent).commit(); + } + } + applyCaption(); + buttonPressed = true; + delegate.didPressedButton(7, true); + } + + private void updatePhotosCounter(boolean added) { if (counterTextView == null) { return; } boolean hasVideo = false; + boolean hasPhotos = false; for (HashMap.Entry entry : selectedPhotos.entrySet()) { MediaController.PhotoEntry photoEntry = (MediaController.PhotoEntry) entry.getValue(); if (photoEntry.isVideo) { hasVideo = true; + } else { + hasPhotos = true; + } + if (hasVideo && hasPhotos) { break; } } - if (hasVideo) { + int newSelectedCount = Math.max(1, selectedPhotos.size()); + if (hasVideo && hasPhotos) { counterTextView.setText(LocaleController.formatPluralString("Media", selectedPhotos.size()).toUpperCase()); + if (newSelectedCount != currentSelectedCount || added) { + selectedTextView.setText(LocaleController.formatPluralString("MediaSelected", newSelectedCount)); + } + } else if (hasVideo) { + counterTextView.setText(LocaleController.formatPluralString("Videos", selectedPhotos.size()).toUpperCase()); + if (newSelectedCount != currentSelectedCount || added) { + selectedTextView.setText(LocaleController.formatPluralString("VideosSelected", newSelectedCount)); + } } else { counterTextView.setText(LocaleController.formatPluralString("Photos", selectedPhotos.size()).toUpperCase()); + if (newSelectedCount != currentSelectedCount || added) { + selectedTextView.setText(LocaleController.formatPluralString("PhotosSelected", newSelectedCount)); + } } + currentSelectedCount = newSelectedCount; + } + + private boolean showCommentTextView(boolean show, boolean animated) { + if (show == (frameLayout2.getTag() != null)) { + return false; + } + if (animatorSet != null) { + animatorSet.cancel(); + } + frameLayout2.setTag(show ? 1 : null); + if (commentTextView.getEditText().isFocused()) { + AndroidUtilities.hideKeyboard(commentTextView.getEditText()); + } + commentTextView.hidePopup(true); + if (show) { + frameLayout2.setVisibility(View.VISIBLE); + writeButtonContainer.setVisibility(View.VISIBLE); + } + if (animated) { + animatorSet = new AnimatorSet(); + ArrayList animators = new ArrayList<>(); + animators.add(ObjectAnimator.ofFloat(frameLayout2, View.ALPHA, show ? 1.0f : 0.0f)); + animators.add(ObjectAnimator.ofFloat(writeButtonContainer, View.SCALE_X, show ? 1.0f : 0.2f)); + animators.add(ObjectAnimator.ofFloat(writeButtonContainer, View.SCALE_Y, show ? 1.0f : 0.2f)); + animators.add(ObjectAnimator.ofFloat(writeButtonContainer, View.ALPHA, show ? 1.0f : 0.0f)); + animators.add(ObjectAnimator.ofFloat(selectedCountView, View.SCALE_X, show ? 1.0f : 0.2f)); + animators.add(ObjectAnimator.ofFloat(selectedCountView, View.SCALE_Y, show ? 1.0f : 0.2f)); + animators.add(ObjectAnimator.ofFloat(selectedCountView, View.ALPHA, show ? 1.0f : 0.0f)); + if (actionBar.getTag() != null) { + animators.add(ObjectAnimator.ofFloat(frameLayout2, View.TRANSLATION_Y, show ? 0.0f : AndroidUtilities.dp(48))); + animators.add(ObjectAnimator.ofFloat(shadow, View.TRANSLATION_Y, show ? AndroidUtilities.dp(44) : AndroidUtilities.dp(48 + 44))); + animators.add(ObjectAnimator.ofFloat(shadow, View.ALPHA, show ? 1.0f : 0.0f)); + } else { + animators.add(ObjectAnimator.ofFloat(buttonsRecyclerView, View.TRANSLATION_Y, show ? AndroidUtilities.dp(44) : 0)); + animators.add(ObjectAnimator.ofFloat(shadow, View.TRANSLATION_Y, show ? AndroidUtilities.dp(44) : 0)); + } + + animatorSet.playTogether(animators); + animatorSet.setInterpolator(new DecelerateInterpolator()); + animatorSet.setDuration(180); + animatorSet.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + if (animation.equals(animatorSet)) { + if (!show) { + frameLayout2.setVisibility(View.INVISIBLE); + writeButtonContainer.setVisibility(View.INVISIBLE); + } + animatorSet = null; + } + } + + @Override + public void onAnimationCancel(Animator animation) { + if (animation.equals(animatorSet)) { + animatorSet = null; + } + } + }); + animatorSet.start(); + } else { + frameLayout2.setAlpha(show ? 1.0f : 0.0f); + writeButtonContainer.setScaleX(show ? 1.0f : 0.2f); + writeButtonContainer.setScaleY(show ? 1.0f : 0.2f); + writeButtonContainer.setAlpha(show ? 1.0f : 0.0f); + selectedCountView.setScaleX(show ? 1.0f : 0.2f); + selectedCountView.setScaleY(show ? 1.0f : 0.2f); + selectedCountView.setAlpha(show ? 1.0f : 0.0f); + if (actionBar.getTag() != null) { + frameLayout2.setTranslationY(show ? 0.0f : AndroidUtilities.dp(48)); + shadow.setTranslationY(show ? AndroidUtilities.dp(44) : AndroidUtilities.dp(48 + 44)); + shadow.setAlpha(show ? 1.0f : 0.0f); + } else { + buttonsRecyclerView.setTranslationY(show ? AndroidUtilities.dp(44) : 0); + shadow.setTranslationY(show ? AndroidUtilities.dp(44) : 0); + } + if (!show) { + frameLayout2.setVisibility(View.INVISIBLE); + writeButtonContainer.setVisibility(View.INVISIBLE); + } + } + return true; + } + + private final Property ATTACH_ALERT_PROGRESS = new AnimationProperties.FloatProperty("openProgress") { + + private float openProgress; + + @Override + public void setValue(ChatAttachAlert object, float value) { + for (int a = 0, N = buttonsRecyclerView.getChildCount(); a < N; a++) { + float startTime = 32.0f * (3 - a); + View child = buttonsRecyclerView.getChildAt(a); + float scale; + if (value > startTime) { + float elapsedTime = value - startTime; + if (elapsedTime <= 200.0f) { + scale = 1.1f * CubicBezierInterpolator.EASE_OUT.getInterpolation(elapsedTime / 200.0f); + child.setAlpha(CubicBezierInterpolator.EASE_BOTH.getInterpolation(elapsedTime / 200.0f)); + } else { + child.setAlpha(1.0f); + elapsedTime -= 200.0f; + if (elapsedTime <= 100.0f) { + scale = 1.1f - 0.1f * CubicBezierInterpolator.EASE_IN.getInterpolation(elapsedTime / 100.0f); + } else { + scale = 1.0f; + } + } + } else { + scale = 0; + } + if (child instanceof AttachButton) { + AttachButton attachButton = (AttachButton) child; + attachButton.textView.setScaleX(scale); + attachButton.textView.setScaleY(scale); + attachButton.imageView.setScaleX(scale); + attachButton.imageView.setScaleY(scale); + } else if (child instanceof AttachBotButton) { + AttachBotButton attachButton = (AttachBotButton) child; + attachButton.nameTextView.setScaleX(scale); + attachButton.nameTextView.setScaleY(scale); + attachButton.imageView.setScaleX(scale); + attachButton.imageView.setScaleY(scale); + } + } + } + + @Override + public Float get(ChatAttachAlert object) { + return openProgress; + } + }; + + @Override + protected boolean onCustomOpenAnimation() { + AnimatorSet animatorSet = new AnimatorSet(); + animatorSet.playTogether( + ObjectAnimator.ofFloat(this, ATTACH_ALERT_PROGRESS, 0.0f, 400.0f)); + animatorSet.setDuration(400); + animatorSet.setStartDelay(20); + animatorSet.start(); + return false; } private void openPhotoViewer(MediaController.PhotoEntry entry, final boolean sameTakePictureOrientation, boolean external) { @@ -1338,13 +1955,16 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N cameraPhotos.add(entry); selectedPhotos.put(entry.imageId, entry); selectedPhotosOrder.add(entry.imageId); - updatePhotosButton(); - photoAttachAdapter.notifyDataSetChanged(); + updatePhotosButton(0); + adapter.notifyDataSetChanged(); cameraAttachAdapter.notifyDataSetChanged(); } if (entry != null && !external && cameraPhotos.size() > 1) { - updatePhotosCounter(); + updatePhotosCounter(false); if (cameraView != null) { + zoomControlView.setZoom(0.0f, false); + cameraZoom = 0.0f; + cameraView.setZoom(0.0f); CameraController.getInstance().startPreview(cameraView.getCameraSession()); } mediaCaptured = false; @@ -1356,7 +1976,7 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N cancelTakingPhotos = true; PhotoViewer.getInstance().setParentActivity(baseFragment.getParentActivity()); PhotoViewer.getInstance().setParentAlert(ChatAttachAlert.this); - PhotoViewer.getInstance().setMaxSelectedPhotos(maxSelectedPhotos); + PhotoViewer.getInstance().setMaxSelectedPhotos(maxSelectedPhotos, allowOrder); ChatActivity chatActivity; int type; @@ -1382,6 +2002,9 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N cameraView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_FULLSCREEN); } }, 1000); + zoomControlView.setZoom(0.0f, false); + cameraZoom = 0.0f; + cameraView.setZoom(0.0f); CameraController.getInstance().startPreview(cameraView.getCameraSession()); } if (cancelTakingPhotos && cameraPhotos.size() == 1) { @@ -1400,9 +2023,9 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N selectedPhotos.clear(); counterTextView.setVisibility(View.INVISIBLE); cameraPhotoRecyclerView.setVisibility(View.GONE); - photoAttachAdapter.notifyDataSetChanged(); + adapter.notifyDataSetChanged(); cameraAttachAdapter.notifyDataSetChanged(); - updatePhotosButton(); + updatePhotosButton(0); } return true; } @@ -1411,7 +2034,7 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N public void needAddMorePhotos() { cancelTakingPhotos = false; if (mediaFromExternalCamera) { - delegate.didPressedButton(0); + delegate.didPressedButton(0, true); return; } if (!cameraOpened) { @@ -1420,7 +2043,7 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N counterTextView.setVisibility(View.VISIBLE); cameraPhotoRecyclerView.setVisibility(View.VISIBLE); counterTextView.setAlpha(1.0f); - updatePhotosCounter(); + updatePhotosCounter(false); } @Override @@ -1437,11 +2060,12 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N AndroidUtilities.addMediaToGallery(((MediaController.PhotoEntry) cameraPhotos.get(a)).path); } } - delegate.didPressedButton(8); + applyCaption(); + delegate.didPressedButton(8, true); cameraPhotos.clear(); selectedPhotosOrder.clear(); selectedPhotos.clear(); - photoAttachAdapter.notifyDataSetChanged(); + adapter.notifyDataSetChanged(); cameraAttachAdapter.notifyDataSetChanged(); closeCamera(false); dismiss(); @@ -1459,9 +2083,9 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N @Override public void willHidePhotoViewer() { mediaCaptured = false; - int count = attachPhotoRecyclerView.getChildCount(); + int count = gridView.getChildCount(); for (int a = 0; a < count; a++) { - View view = attachPhotoRecyclerView.getChildAt(a); + View view = gridView.getChildAt(a); if (view instanceof PhotoAttachPhotoCell) { PhotoAttachPhotoCell cell = (PhotoAttachPhotoCell) view; cell.showImage(); @@ -1482,46 +2106,124 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N }, chatActivity); } + private void showZoomControls(boolean show, boolean animated) { + if (zoomControlView.getTag() != null && show || zoomControlView.getTag() == null && !show) { + if (show) { + if (zoomControlHideRunnable != null) { + AndroidUtilities.cancelRunOnUIThread(zoomControlHideRunnable); + } + AndroidUtilities.runOnUIThread(zoomControlHideRunnable = () -> { + showZoomControls(false, true); + zoomControlHideRunnable = null; + }, 2000); + } + return; + } + if (zoomControlAnimation != null) { + zoomControlAnimation.cancel(); + } + zoomControlView.setTag(show ? 1 : null); + zoomControlAnimation = new AnimatorSet(); + zoomControlAnimation.setDuration(180); + zoomControlAnimation.playTogether(ObjectAnimator.ofFloat(zoomControlView, View.ALPHA, show ? 1.0f : 0.0f)); + zoomControlAnimation.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + zoomControlAnimation = null; + } + }); + zoomControlAnimation.start(); + if (show) { + AndroidUtilities.runOnUIThread(zoomControlHideRunnable = () -> { + showZoomControls(false, true); + zoomControlHideRunnable = null; + }, 2000); + } + } + private boolean processTouchEvent(MotionEvent event) { if (event == null) { return false; } if (!pressed && event.getActionMasked() == MotionEvent.ACTION_DOWN || event.getActionMasked() == MotionEvent.ACTION_POINTER_DOWN) { - if (!takingPhoto) { + zoomControlView.getHitRect(hitRect); + if (zoomControlView.getTag() != null && hitRect.contains((int) event.getX(), (int) event.getY())) { + return false; + } + if (!takingPhoto && !dragging) { + if (event.getPointerCount() == 2) { + pinchStartDistance = (float) Math.hypot(event.getX(1) - event.getX(0), event.getY(1) - event.getY(0)); + zooming = true; + } else { + maybeStartDraging = true; + lastY = event.getY(); + zooming = false; + } + zoomWas = false; pressed = true; - maybeStartDraging = true; - lastY = event.getY(); } } else if (pressed) { if (event.getActionMasked() == MotionEvent.ACTION_MOVE) { - float newY = event.getY(); - float dy = (newY - lastY); - if (maybeStartDraging) { - if (Math.abs(dy) > AndroidUtilities.getPixelsInCM(0.4f, false)) { - maybeStartDraging = false; - dragging = true; + if (zooming && event.getPointerCount() == 2 && !dragging) { + float newDistance = (float) Math.hypot(event.getX(1) - event.getX(0), event.getY(1) - event.getY(0)); + if (!zoomWas) { + if (Math.abs(newDistance - pinchStartDistance) >= AndroidUtilities.getPixelsInCM(0.4f, false)) { + pinchStartDistance = newDistance; + zoomWas = true; + } + } else { + float diff = (newDistance - pinchStartDistance) / AndroidUtilities.dp(100); + pinchStartDistance = newDistance; + cameraZoom += diff; + if (cameraZoom < 0.0f) { + cameraZoom = 0.0f; + } else if (cameraZoom > 1.0f) { + cameraZoom = 1.0f; + } + zoomControlView.setZoom(cameraZoom, false); + containerView.invalidate(); + cameraView.setZoom(cameraZoom); + showZoomControls(true, true); } - } else if (dragging) { - if (cameraView != null) { - cameraView.setTranslationY(cameraView.getTranslationY() + dy); - lastY = newY; - if (cameraPanel.getTag() == null) { - cameraPanel.setTag(1); - AnimatorSet animatorSet = new AnimatorSet(); - animatorSet.playTogether( - ObjectAnimator.ofFloat(cameraPanel, "alpha", 0.0f), - ObjectAnimator.ofFloat(counterTextView, "alpha", 0.0f), - ObjectAnimator.ofFloat(flashModeButton[0], "alpha", 0.0f), - ObjectAnimator.ofFloat(flashModeButton[1], "alpha", 0.0f), - ObjectAnimator.ofFloat(cameraPhotoRecyclerView, "alpha", 0.0f)); - animatorSet.setDuration(200); - animatorSet.start(); + } else { + float newY = event.getY(); + float dy = (newY - lastY); + if (maybeStartDraging) { + if (Math.abs(dy) > AndroidUtilities.getPixelsInCM(0.4f, false)) { + maybeStartDraging = false; + dragging = true; + } + } else if (dragging) { + if (cameraView != null) { + cameraView.setTranslationY(cameraView.getTranslationY() + dy); + lastY = newY; + zoomControlView.setTag(null); + if (zoomControlHideRunnable != null) { + AndroidUtilities.cancelRunOnUIThread(zoomControlHideRunnable); + zoomControlHideRunnable = null; + } + if (cameraPanel.getTag() == null) { + cameraPanel.setTag(1); + AnimatorSet animatorSet = new AnimatorSet(); + animatorSet.playTogether( + ObjectAnimator.ofFloat(cameraPanel, View.ALPHA, 0.0f), + ObjectAnimator.ofFloat(zoomControlView, View.ALPHA, 0.0f), + ObjectAnimator.ofFloat(counterTextView, View.ALPHA, 0.0f), + ObjectAnimator.ofFloat(flashModeButton[0], View.ALPHA, 0.0f), + ObjectAnimator.ofFloat(flashModeButton[1], View.ALPHA, 0.0f), + ObjectAnimator.ofFloat(cameraPhotoRecyclerView, View.ALPHA, 0.0f)); + animatorSet.setDuration(200); + animatorSet.start(); + } } } } } else if (event.getActionMasked() == MotionEvent.ACTION_CANCEL || event.getActionMasked() == MotionEvent.ACTION_UP || event.getActionMasked() == MotionEvent.ACTION_POINTER_UP) { pressed = false; - if (dragging) { + zooming = false; + if (zooming) { + zooming = false; + } else if (dragging) { dragging = false; if (cameraView != null) { if (Math.abs(cameraView.getTranslationY()) > cameraView.getMeasuredHeight() / 6.0f) { @@ -1529,19 +2231,19 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N } else { AnimatorSet animatorSet = new AnimatorSet(); animatorSet.playTogether( - ObjectAnimator.ofFloat(cameraView, "translationY", 0.0f), - ObjectAnimator.ofFloat(cameraPanel, "alpha", 1.0f), - ObjectAnimator.ofFloat(counterTextView, "alpha", 1.0f), - ObjectAnimator.ofFloat(flashModeButton[0], "alpha", 1.0f), - ObjectAnimator.ofFloat(flashModeButton[1], "alpha", 1.0f), - ObjectAnimator.ofFloat(cameraPhotoRecyclerView, "alpha", 1.0f)); + ObjectAnimator.ofFloat(cameraView, View.TRANSLATION_Y, 0.0f), + ObjectAnimator.ofFloat(cameraPanel, View.ALPHA, 1.0f), + ObjectAnimator.ofFloat(counterTextView, View.ALPHA, 1.0f), + ObjectAnimator.ofFloat(flashModeButton[0], View.ALPHA, 1.0f), + ObjectAnimator.ofFloat(flashModeButton[1], View.ALPHA, 1.0f), + ObjectAnimator.ofFloat(cameraPhotoRecyclerView, View.ALPHA, 1.0f)); animatorSet.setDuration(250); animatorSet.setInterpolator(interpolator); animatorSet.start(); cameraPanel.setTag(null); } } - } else if (cameraView != null) { + } else if (cameraView != null && !zoomWas) { cameraView.getLocationOnScreen(viewPosition); float viewX = event.getRawX() - viewPosition[0]; float viewY = event.getRawY() - viewPosition[1]; @@ -1557,41 +2259,78 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N return cameraOpened && processTouchEvent(event); } + private void applyAttachButtonColors(View view) { + if (view instanceof AttachButton) { + AttachButton button = (AttachButton) view; + button.textView.setTextColor(Theme.getColor(Theme.key_dialogTextGray2)); + } else if (view instanceof AttachBotButton) { + AttachBotButton button = (AttachBotButton) view; + button.nameTextView.setTextColor(Theme.getColor(Theme.key_dialogTextGray2)); + } + } + public void checkColors() { - for (int a = 0, count = attachButtons.size(); a < count; a++) { - attachButtons.get(a).textView.setTextColor(Theme.getColor(Theme.key_dialogTextGray2)); + if (buttonsRecyclerView == null) { + return; } - lineView.setBackgroundColor(Theme.getColor(Theme.key_dialogGrayLine)); - if (hintTextView != null) { - Theme.setDrawableColor(hintTextView.getBackground(), Theme.getColor(Theme.key_chat_gifSaveHintBackground)); - hintTextView.setTextColor(Theme.getColor(Theme.key_chat_gifSaveHintText)); + int count = buttonsRecyclerView.getChildCount(); + for (int a = 0; a < count; a++) { + applyAttachButtonColors(buttonsRecyclerView.getChildAt(a)); } - if (mediaBanTooltip != null) { - Theme.setDrawableColor(mediaBanTooltip.getBackground(), Theme.getColor(Theme.key_chat_attachMediaBanBackground)); - mediaBanTooltip.setTextColor(Theme.getColor(Theme.key_chat_attachMediaBanText)); - } - if (listView != null) { - listView.setGlowColor(Theme.getColor(Theme.key_dialogScrollGlow)); - RecyclerView.ViewHolder holder = listView.findViewHolderForAdapterPosition(1); - if (holder != null) { - holder.itemView.setBackgroundColor(Theme.getColor(Theme.key_dialogBackgroundGray)); - } else { - adapter.notifyItemChanged(1); - } - } - if (ciclePaint != null) { - ciclePaint.setColor(Theme.getColor(Theme.key_dialogBackground)); + selectedTextView.setTextColor(Theme.getColor(Theme.key_dialogTextBlack)); + + selectedMenuItem.setIconColor(Theme.getColor(Theme.key_dialogTextBlack)); + Theme.setDrawableColor(selectedMenuItem.getBackground(), Theme.getColor(Theme.key_dialogButtonSelector)); + selectedMenuItem.setPopupItemsColor(Theme.getColor(Theme.key_actionBarDefaultSubmenuItem), false); + selectedMenuItem.setPopupItemsColor(Theme.getColor(Theme.key_actionBarDefaultSubmenuItem), true); + selectedMenuItem.redrawPopup(Theme.getColor(Theme.key_actionBarDefaultSubmenuBackground)); + + commentTextView.updateColors(); + + if (sendPopupLayout != null) { + sendPopupLayout.getBackgroundDrawable().setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_actionBarDefaultSubmenuBackground), PorterDuff.Mode.MULTIPLY)); + itemCell.setColors(Theme.getColor(Theme.key_actionBarDefaultSubmenuItem), Theme.getColor(Theme.key_actionBarDefaultSubmenuItem)); } + + Theme.setSelectorDrawableColor(writeButtonDrawable, Theme.getColor(Theme.key_dialogFloatingButton), false); + Theme.setSelectorDrawableColor(writeButtonDrawable, Theme.getColor(Theme.key_dialogFloatingButtonPressed), true); + writeButton.setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_dialogFloatingIcon), PorterDuff.Mode.MULTIPLY)); + + dropDown.setTextColor(Theme.getColor(Theme.key_dialogTextBlack)); + dropDownContainer.setPopupItemsColor(Theme.getColor(Theme.key_actionBarDefaultSubmenuItem), false); + dropDownContainer.setPopupItemsColor(Theme.getColor(Theme.key_actionBarDefaultSubmenuItem), true); + dropDownContainer.redrawPopup(Theme.getColor(Theme.key_actionBarDefaultSubmenuBackground)); + + actionBarShadow.setBackgroundColor(Theme.getColor(Theme.key_dialogShadowLine)); + + progressView.setTextColor(Theme.getColor(Theme.key_emptyListPlaceholder)); + + buttonsRecyclerView.setGlowColor(Theme.getColor(Theme.key_dialogScrollGlow)); + buttonsRecyclerView.setBackgroundColor(Theme.getColor(Theme.key_dialogBackground)); + + frameLayout2.setBackgroundColor(Theme.getColor(Theme.key_dialogBackground)); + + selectedCountView.invalidate(); + + Theme.setDrawableColor(dropDownDrawable, Theme.getColor(Theme.key_dialogTextBlack)); + + actionBar.setBackgroundColor(Theme.getColor(Theme.key_dialogBackground)); + actionBar.setItemsColor(Theme.getColor(Theme.key_dialogTextBlack), false); + actionBar.setItemsBackgroundColor(Theme.getColor(Theme.key_dialogButtonSelector), false); + actionBar.setTitleColor(Theme.getColor(Theme.key_dialogTextBlack)); + Theme.setDrawableColor(shadowDrawable, Theme.getColor(Theme.key_dialogBackground)); - if (cameraImageView != null) { - cameraImageView.setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_dialogCameraIcon), PorterDuff.Mode.MULTIPLY)); + Theme.setDrawableColor(cameraDrawable, Theme.getColor(Theme.key_dialogCameraIcon)); + if (cameraIcon != null) { + cameraIcon.invalidate(); } - if (attachPhotoRecyclerView != null) { - RecyclerView.ViewHolder holder = attachPhotoRecyclerView.findViewHolderForAdapterPosition(0); - if (holder != null && holder.itemView instanceof PhotoAttachCameraCell) { - ((PhotoAttachCameraCell) holder.itemView).getImageView().setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_dialogCameraIcon), PorterDuff.Mode.MULTIPLY)); - } + + gridView.setGlowColor(Theme.getColor(Theme.key_dialogScrollGlow)); + RecyclerView.ViewHolder holder = gridView.findViewHolderForAdapterPosition(0); + if (holder != null && holder.itemView instanceof PhotoAttachCameraCell) { + ((PhotoAttachCameraCell) holder.itemView).getImageView().setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_dialogCameraIcon), PorterDuff.Mode.MULTIPLY)); } + containerView.invalidate(); } @@ -1603,6 +2342,7 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N flashModeButton[a].setAlpha(1.0f); } switchCameraButton.setAlpha(1.0f); + tooltipTextView.setAlpha(1.0f); recordTime.setAlpha(0.0f); AndroidUtilities.cancelRunOnUIThread(videoRecordRunnable); videoRecordRunnable = null; @@ -1629,16 +2369,26 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N @Override protected boolean onCustomMeasure(View view, int width, int height) { boolean isPortrait = width < height; - if (view == cameraView) { + if (view == cameraIcon) { + cameraIcon.measure(View.MeasureSpec.makeMeasureSpec(itemSize, View.MeasureSpec.EXACTLY), View.MeasureSpec.makeMeasureSpec(itemSize - cameraViewOffsetBottomY - cameraViewOffsetY, View.MeasureSpec.EXACTLY)); + return true; + } else if (view == cameraView) { if (cameraOpened && !cameraAnimationInProgress) { cameraView.measure(View.MeasureSpec.makeMeasureSpec(width, View.MeasureSpec.EXACTLY), View.MeasureSpec.makeMeasureSpec(height, View.MeasureSpec.EXACTLY)); return true; } } else if (view == cameraPanel) { if (isPortrait) { - cameraPanel.measure(View.MeasureSpec.makeMeasureSpec(width, View.MeasureSpec.EXACTLY), View.MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(100), View.MeasureSpec.EXACTLY)); + cameraPanel.measure(View.MeasureSpec.makeMeasureSpec(width, View.MeasureSpec.EXACTLY), View.MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(126), View.MeasureSpec.EXACTLY)); } else { - cameraPanel.measure(View.MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(100), View.MeasureSpec.EXACTLY), View.MeasureSpec.makeMeasureSpec(height, View.MeasureSpec.EXACTLY)); + cameraPanel.measure(View.MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(126), View.MeasureSpec.EXACTLY), View.MeasureSpec.makeMeasureSpec(height, View.MeasureSpec.EXACTLY)); + } + return true; + } else if (view == zoomControlView) { + if (isPortrait) { + zoomControlView.measure(View.MeasureSpec.makeMeasureSpec(width, View.MeasureSpec.EXACTLY), View.MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(50), View.MeasureSpec.EXACTLY)); + } else { + zoomControlView.measure(View.MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(50), View.MeasureSpec.EXACTLY), View.MeasureSpec.makeMeasureSpec(height, View.MeasureSpec.EXACTLY)); } return true; } else if (view == cameraPhotoRecyclerView) { @@ -1672,15 +2422,30 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N if (view == cameraPanel) { if (isPortrait) { if (cameraPhotoRecyclerView.getVisibility() == View.VISIBLE) { - cameraPanel.layout(0, bottom - AndroidUtilities.dp(100 + 96), width, bottom - AndroidUtilities.dp(96)); + cameraPanel.layout(0, bottom - AndroidUtilities.dp(126 + 96), width, bottom - AndroidUtilities.dp(96)); } else { - cameraPanel.layout(0, bottom - AndroidUtilities.dp(100), width, bottom); + cameraPanel.layout(0, bottom - AndroidUtilities.dp(126), width, bottom); } } else { if (cameraPhotoRecyclerView.getVisibility() == View.VISIBLE) { - cameraPanel.layout(right - AndroidUtilities.dp(100 + 96), 0, right - AndroidUtilities.dp(96), height); + cameraPanel.layout(right - AndroidUtilities.dp(126 + 96), 0, right - AndroidUtilities.dp(96), height); } else { - cameraPanel.layout(right - AndroidUtilities.dp(100), 0, right, height); + cameraPanel.layout(right - AndroidUtilities.dp(126), 0, right, height); + } + } + return true; + } else if (view == zoomControlView) { + if (isPortrait) { + if (cameraPhotoRecyclerView.getVisibility() == View.VISIBLE) { + zoomControlView.layout(0, bottom - AndroidUtilities.dp(126 + 96 + 38 + 50), width, bottom - AndroidUtilities.dp(126 + 96 + 38)); + } else { + zoomControlView.layout(0, bottom - AndroidUtilities.dp(126 + 50), width, bottom - AndroidUtilities.dp(126)); + } + } else { + if (cameraPhotoRecyclerView.getVisibility() == View.VISIBLE) { + zoomControlView.layout(right - AndroidUtilities.dp(126 + 96 + 38 + 50), 0, right - AndroidUtilities.dp(126 + 96 + 38), height); + } else { + zoomControlView.layout(right - AndroidUtilities.dp(126 + 50), 0, right - AndroidUtilities.dp(126), height); } } return true; @@ -1689,13 +2454,13 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N int cy; if (isPortrait) { cx = (width - counterTextView.getMeasuredWidth()) / 2; - cy = bottom - AndroidUtilities.dp(100 + 16 + 38); + cy = bottom - AndroidUtilities.dp(113 + 16 + 38); counterTextView.setRotation(0); if (cameraPhotoRecyclerView.getVisibility() == View.VISIBLE) { cy -= AndroidUtilities.dp(96); } } else { - cx = right - AndroidUtilities.dp(100 + 16 + 38); + cx = right - AndroidUtilities.dp(113 + 16 + 38); cy = height / 2 + counterTextView.getMeasuredWidth() / 2; counterTextView.setRotation(-90); if (cameraPhotoRecyclerView.getVisibility() == View.VISIBLE) { @@ -1717,42 +2482,6 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N return false; } - private void hideHint() { - if (hideHintRunnable != null) { - AndroidUtilities.cancelRunOnUIThread(hideHintRunnable); - hideHintRunnable = null; - } - if (hintTextView == null) { - return; - } - currentHintAnimation = new AnimatorSet(); - currentHintAnimation.playTogether( - ObjectAnimator.ofFloat(hintTextView, "alpha", 0.0f) - ); - currentHintAnimation.setInterpolator(decelerateInterpolator); - currentHintAnimation.addListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator animation) { - if (currentHintAnimation == null || !currentHintAnimation.equals(animation)) { - return; - } - currentHintAnimation = null; - if (hintTextView != null) { - hintTextView.setVisibility(View.INVISIBLE); - } - } - - @Override - public void onAnimationCancel(Animator animation) { - if (currentHintAnimation != null && currentHintAnimation.equals(animation)) { - currentHintAnimation = null; - } - } - }); - currentHintAnimation.setDuration(300); - currentHintAnimation.start(); - } - public void onPause() { if (shutterButton == null) { return; @@ -1784,7 +2513,7 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N } private void openCamera(boolean animated) { - if (cameraView == null) { + if (cameraView == null || cameraInitAnimation != null || !cameraView.isInitied()) { return; } if (cameraPhotos.isEmpty()) { @@ -1794,11 +2523,16 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N counterTextView.setVisibility(View.VISIBLE); cameraPhotoRecyclerView.setVisibility(View.VISIBLE); } + if (commentTextView.isKeyboardVisible() && isFocusable()) { + commentTextView.closeKeyboard(); + } + zoomControlView.setVisibility(View.VISIBLE); + zoomControlView.setAlpha(0.0f); cameraPanel.setVisibility(View.VISIBLE); cameraPanel.setTag(null); animateCameraValues[0] = 0; - animateCameraValues[1] = AndroidUtilities.dp(80) - cameraViewOffsetX; - animateCameraValues[2] = AndroidUtilities.dp(80) - cameraViewOffsetY; + animateCameraValues[1] = itemSize - cameraViewOffsetX; + animateCameraValues[2] = itemSize - cameraViewOffsetY - cameraViewOffsetBottomY; if (animated) { cameraAnimationInProgress = true; ArrayList animators = new ArrayList<>(); @@ -1819,6 +2553,9 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N @Override public void onAnimationEnd(Animator animator) { cameraAnimationInProgress = false; + if (Build.VERSION.SDK_INT >= 21 && cameraView != null) { + cameraView.invalidateOutline(); + } if (cameraOpened) { delegate.onCameraOpened(); } @@ -1844,10 +2581,7 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N cameraOpened = true; cameraView.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO); if (Build.VERSION.SDK_INT >= 19) { - attachPhotoRecyclerView.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS); - for (AttachButton button : attachButtons) { - button.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS); - } + gridView.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS); } } @@ -1858,7 +2592,7 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N mediaFromExternalCamera = true; if (requestCode == 0) { PhotoViewer.getInstance().setParentActivity(baseFragment.getParentActivity()); - PhotoViewer.getInstance().setMaxSelectedPhotos(maxSelectedPhotos); + PhotoViewer.getInstance().setMaxSelectedPhotos(maxSelectedPhotos, allowOrder); final ArrayList arrayList = new ArrayList<>(); int orientation = 0; try { @@ -1961,8 +2695,12 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N if (takingPhoto || cameraView == null) { return; } - animateCameraValues[1] = AndroidUtilities.dp(80) - cameraViewOffsetX; - animateCameraValues[2] = AndroidUtilities.dp(80) - cameraViewOffsetY; + animateCameraValues[1] = itemSize - cameraViewOffsetX; + animateCameraValues[2] = itemSize - cameraViewOffsetY - cameraViewOffsetBottomY; + if (zoomControlHideRunnable != null) { + AndroidUtilities.cancelRunOnUIThread(zoomControlHideRunnable); + zoomControlHideRunnable = null; + } if (animated) { FrameLayout.LayoutParams layoutParams = (FrameLayout.LayoutParams) cameraView.getLayoutParams(); animateCameraValues[0] = layoutParams.topMargin = (int) cameraView.getTranslationY(); @@ -1972,12 +2710,13 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N cameraAnimationInProgress = true; ArrayList animators = new ArrayList<>(); animators.add(ObjectAnimator.ofFloat(ChatAttachAlert.this, "cameraOpenProgress", 0.0f)); - animators.add(ObjectAnimator.ofFloat(cameraPanel, "alpha", 0.0f)); - animators.add(ObjectAnimator.ofFloat(counterTextView, "alpha", 0.0f)); - animators.add(ObjectAnimator.ofFloat(cameraPhotoRecyclerView, "alpha", 0.0f)); + animators.add(ObjectAnimator.ofFloat(cameraPanel, View.ALPHA, 0.0f)); + animators.add(ObjectAnimator.ofFloat(zoomControlView, View.ALPHA, 0.0f)); + animators.add(ObjectAnimator.ofFloat(counterTextView, View.ALPHA, 0.0f)); + animators.add(ObjectAnimator.ofFloat(cameraPhotoRecyclerView, View.ALPHA, 0.0f)); for (int a = 0; a < 2; a++) { if (flashModeButton[a].getVisibility() == View.VISIBLE) { - animators.add(ObjectAnimator.ofFloat(flashModeButton[a], "alpha", 0.0f)); + animators.add(ObjectAnimator.ofFloat(flashModeButton[a], View.ALPHA, 0.0f)); break; } } @@ -1988,10 +2727,17 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N @Override public void onAnimationEnd(Animator animator) { cameraAnimationInProgress = false; + if (Build.VERSION.SDK_INT >= 21 && cameraView != null) { + cameraView.invalidateOutline(); + } cameraOpened = false; if (cameraPanel != null) { cameraPanel.setVisibility(View.GONE); } + if (zoomControlView != null) { + zoomControlView.setVisibility(View.GONE); + zoomControlView.setTag(null); + } if (cameraPhotoRecyclerView != null) { cameraPhotoRecyclerView.setVisibility(View.GONE); } @@ -2005,9 +2751,12 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N animateCameraValues[0] = 0; setCameraOpenProgress(0); cameraPanel.setAlpha(0); + cameraPanel.setVisibility(View.GONE); + zoomControlView.setAlpha(0); + zoomControlView.setTag(null); + zoomControlView.setVisibility(View.GONE); cameraPhotoRecyclerView.setAlpha(0); counterTextView.setAlpha(0); - cameraPanel.setVisibility(View.GONE); cameraPhotoRecyclerView.setVisibility(View.GONE); for (int a = 0; a < 2; a++) { if (flashModeButton[a].getVisibility() == View.VISIBLE) { @@ -2022,10 +2771,7 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N } cameraView.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_AUTO); if (Build.VERSION.SDK_INT >= 19) { - attachPhotoRecyclerView.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_AUTO); - for (AttachButton button : attachButtons) { - button.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_AUTO); - } + gridView.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_AUTO); } } @@ -2048,8 +2794,8 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N endHeight = container.getHeight(); } if (value == 0) { - cameraView.setClipLeft(cameraViewOffsetX); cameraView.setClipTop(cameraViewOffsetY); + cameraView.setClipBottom(cameraViewOffsetBottomY); cameraView.setTranslationX(cameraViewLocation[0]); cameraView.setTranslationY(cameraViewLocation[1]); cameraIcon.setTranslationX(cameraViewLocation[0]); @@ -2062,8 +2808,8 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N layoutParams.width = (int) (startWidth + (endWidth - startWidth) * value); layoutParams.height = (int) (startHeight + (endHeight - startHeight) * value); if (value != 0) { - cameraView.setClipLeft((int) (cameraViewOffsetX * (1.0f - value))); cameraView.setClipTop((int) (cameraViewOffsetY * (1.0f - value))); + cameraView.setClipBottom((int) (cameraViewOffsetBottomY * (1.0f - value))); layoutParams.leftMargin = (int) (cameraViewLocation[0] * (1.0f - value)); layoutParams.topMargin = (int) (animateCameraValues[0] + (cameraViewLocation[1] - animateCameraValues[0]) * (1.0f - value)); } else { @@ -2076,6 +2822,9 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N } else { cameraIcon.setAlpha(0.0f); } + if (Build.VERSION.SDK_INT >= 21) { + cameraView.invalidateOutline(); + } } @Keep @@ -2084,12 +2833,27 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N } private void checkCameraViewPosition() { + if (Build.VERSION.SDK_INT >= 21) { + if (cameraView != null) { + cameraView.invalidateOutline(); + } + RecyclerView.ViewHolder holder = gridView.findViewHolderForAdapterPosition(itemsPerRow - 1); + if (holder != null) { + holder.itemView.invalidateOutline(); + } + if (!adapter.needCamera || !deviceHasGoodCamera || selectedAlbumEntry != galleryAlbumEntry) { + holder = gridView.findViewHolderForAdapterPosition(0); + if (holder != null) { + holder.itemView.invalidateOutline(); + } + } + } if (!deviceHasGoodCamera) { return; } - int count = attachPhotoRecyclerView.getChildCount(); + int count = gridView.getChildCount(); for (int a = 0; a < count; a++) { - View child = attachPhotoRecyclerView.getChildAt(a); + View child = gridView.getChildAt(a); if (child instanceof PhotoAttachCameraCell) { if (Build.VERSION.SDK_INT >= 19) { if (!child.isAttachedToWindow()) { @@ -2098,12 +2862,12 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N } child.getLocationInWindow(cameraViewLocation); cameraViewLocation[0] -= getLeftInset(); - float listViewX = listView.getX() + backgroundPaddingLeft - getLeftInset(); + float listViewX = gridView.getX() - getLeftInset(); if (cameraViewLocation[0] < listViewX) { cameraViewOffsetX = (int) (listViewX - cameraViewLocation[0]); - if (cameraViewOffsetX >= AndroidUtilities.dp(80)) { + if (cameraViewOffsetX >= itemSize) { cameraViewOffsetX = 0; - cameraViewLocation[0] = AndroidUtilities.dp(-150); + cameraViewLocation[0] = AndroidUtilities.dp(-400); cameraViewLocation[1] = 0; } else { cameraViewLocation[0] += cameraViewOffsetX; @@ -2111,11 +2875,12 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N } else { cameraViewOffsetX = 0; } - if (Build.VERSION.SDK_INT >= 21 && cameraViewLocation[1] < AndroidUtilities.statusBarHeight) { - cameraViewOffsetY = AndroidUtilities.statusBarHeight - cameraViewLocation[1]; - if (cameraViewOffsetY >= AndroidUtilities.dp(80)) { + int maxY = (Build.VERSION.SDK_INT >= 21 ? AndroidUtilities.statusBarHeight : 0) + ActionBar.getCurrentActionBarHeight(); + if (cameraViewLocation[1] < maxY) { + cameraViewOffsetY = maxY - cameraViewLocation[1]; + if (cameraViewOffsetY >= itemSize) { cameraViewOffsetY = 0; - cameraViewLocation[0] = AndroidUtilities.dp(-150); + cameraViewLocation[0] = AndroidUtilities.dp(-400); cameraViewLocation[1] = 0; } else { cameraViewLocation[1] += cameraViewOffsetY; @@ -2123,13 +2888,29 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N } else { cameraViewOffsetY = 0; } + int containerHeight = containerView.getMeasuredHeight(); + int keyboardSize = sizeNotifierFrameLayout.getKeyboardHeight(); + if (!AndroidUtilities.isInMultiwindow && keyboardSize <= AndroidUtilities.dp(20)) { + containerHeight -= commentTextView.getEmojiPadding(); + } + maxY = (int) (containerHeight - buttonsRecyclerView.getMeasuredHeight() + buttonsRecyclerView.getTranslationY() + containerView.getTranslationY()); + if (cameraViewLocation[1] + itemSize > maxY) { + cameraViewOffsetBottomY = cameraViewLocation[1] + itemSize - maxY; + if (cameraViewOffsetBottomY >= itemSize) { + cameraViewOffsetBottomY = 0; + cameraViewLocation[0] = AndroidUtilities.dp(-400); + cameraViewLocation[1] = 0; + } + } else { + cameraViewOffsetBottomY = 0; + } applyCameraViewPosition(); return; } } cameraViewOffsetX = 0; cameraViewOffsetY = 0; - cameraViewLocation[0] = AndroidUtilities.dp(-150); + cameraViewLocation[0] = AndroidUtilities.dp(-400); cameraViewLocation[1] = 0; applyCameraViewPosition(); } @@ -2142,13 +2923,13 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N } cameraIcon.setTranslationX(cameraViewLocation[0]); cameraIcon.setTranslationY(cameraViewLocation[1]); - int finalWidth = AndroidUtilities.dp(80) - cameraViewOffsetX; - int finalHeight = AndroidUtilities.dp(80) - cameraViewOffsetY; + int finalWidth = itemSize - cameraViewOffsetX; + int finalHeight = itemSize - cameraViewOffsetY - cameraViewOffsetBottomY; FrameLayout.LayoutParams layoutParams; if (!cameraOpened) { - cameraView.setClipLeft(cameraViewOffsetX); cameraView.setClipTop(cameraViewOffsetY); + cameraView.setClipBottom(cameraViewOffsetBottomY); layoutParams = (FrameLayout.LayoutParams) cameraView.getLayoutParams(); if (layoutParams.height != finalHeight || layoutParams.width != finalWidth) { layoutParams.width = finalWidth; @@ -2185,8 +2966,25 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N if (cameraView == null) { cameraView = new CameraView(baseFragment.getParentActivity(), openWithFrontFaceCamera); cameraView.setFocusable(true); + if (Build.VERSION.SDK_INT >= 21) { + cameraView.setOutlineProvider(new ViewOutlineProvider() { + @Override + public void getOutline(View view, Outline outline) { + if (cameraAnimationInProgress) { + int rad = AndroidUtilities.dp(8 * cornerRadius * cameraOpenProgress); + outline.setRoundRect(0, 0, view.getMeasuredWidth() + rad, view.getMeasuredHeight() + rad, rad); + } else if (!cameraAnimationInProgress && !cameraOpened) { + int rad = AndroidUtilities.dp(8 * cornerRadius); + outline.setRoundRect(0, 0, view.getMeasuredWidth() + rad, view.getMeasuredHeight() + rad, rad); + } else { + outline.setRect(0, 0, view.getMeasuredWidth(), view.getMeasuredHeight()); + } + } + }); + cameraView.setClipToOutline(true); + } cameraView.setContentDescription(LocaleController.getString("AccDescrInstantCamera", R.string.AccDescrInstantCamera)); - container.addView(cameraView, 1, LayoutHelper.createFrame(80, 80)); + container.addView(cameraView, 1, new FrameLayout.LayoutParams(itemSize, itemSize)); cameraView.setDelegate(new CameraView.CameraViewDelegate() { @Override public void onCameraCreated(Camera camera) { @@ -2195,15 +2993,6 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N @Override public void onCameraInit() { - int count = attachPhotoRecyclerView.getChildCount(); - for (int a = 0; a < count; a++) { - View child = attachPhotoRecyclerView.getChildAt(a); - if (child instanceof PhotoAttachCameraCell) { - child.setVisibility(View.INVISIBLE); - break; - } - } - String current = cameraView.getCameraSession().getCurrentFlashMode(); String next = cameraView.getCameraSession().getNextFlashMode(); if (current.equals(next)) { @@ -2222,24 +3011,67 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N } switchCameraButton.setImageResource(cameraView.isFrontface() ? R.drawable.camera_revert1 : R.drawable.camera_revert2); switchCameraButton.setVisibility(cameraView.hasFrontFaceCamera() ? View.VISIBLE : View.INVISIBLE); + if (!cameraOpened) { + cameraInitAnimation = new AnimatorSet(); + cameraInitAnimation.playTogether( + ObjectAnimator.ofFloat(cameraView, View.ALPHA, 0.0f, 1.0f), + ObjectAnimator.ofFloat(cameraIcon, View.ALPHA, 0.0f, 1.0f)); + cameraInitAnimation.setDuration(180); + cameraInitAnimation.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + if (animation.equals(cameraInitAnimation)) { + cameraInitAnimation = null; + int count = gridView.getChildCount(); + for (int a = 0; a < count; a++) { + View child = gridView.getChildAt(a); + if (child instanceof PhotoAttachCameraCell) { + child.setVisibility(View.INVISIBLE); + break; + } + } + } + } + + @Override + public void onAnimationCancel(Animator animation) { + cameraInitAnimation = null; + } + }); + cameraInitAnimation.start(); + } } }); if (cameraIcon == null) { - cameraIcon = new FrameLayout(baseFragment.getParentActivity()); - - cameraImageView = new ImageView(baseFragment.getParentActivity()); - cameraImageView.setScaleType(ImageView.ScaleType.CENTER); - cameraImageView.setImageResource(R.drawable.instant_camera); - cameraImageView.setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_dialogCameraIcon), PorterDuff.Mode.MULTIPLY)); - cameraIcon.addView(cameraImageView, LayoutHelper.createFrame(80, 80, Gravity.RIGHT | Gravity.BOTTOM)); + cameraIcon = new FrameLayout(baseFragment.getParentActivity()) { + @Override + protected void onDraw(Canvas canvas) { + int w = cameraDrawable.getIntrinsicWidth(); + int h = cameraDrawable.getIntrinsicHeight(); + int x = (itemSize - w) / 2; + int y = (itemSize - h) / 2; + if (cameraViewOffsetY != 0) { + y -= cameraViewOffsetY; + } + cameraDrawable.setBounds(x, y, x + w, y + h); + cameraDrawable.draw(canvas); + } + }; + cameraIcon.setWillNotDraw(false); + cameraIcon.setClipChildren(true); } - container.addView(cameraIcon, 2, LayoutHelper.createFrame(80, 80)); + container.addView(cameraIcon, 2, new FrameLayout.LayoutParams(itemSize, itemSize)); cameraView.setAlpha(mediaEnabled ? 1.0f : 0.2f); cameraView.setEnabled(mediaEnabled); cameraIcon.setAlpha(mediaEnabled ? 1.0f : 0.2f); cameraIcon.setEnabled(mediaEnabled); + checkCameraViewPosition(); + } + if (zoomControlView != null) { + zoomControlView.setZoom(0.0f, false); + cameraZoom = 0.0f; } cameraView.setTranslationX(cameraViewLocation[0]); cameraView.setTranslationY(cameraViewLocation[1]); @@ -2251,14 +3083,19 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N if (!deviceHasGoodCamera || cameraView == null) { return; } + saveLastCameraBitmap(); cameraView.destroy(async, null); + if (cameraInitAnimation != null) { + cameraInitAnimation.cancel(); + cameraInitAnimation = null; + } container.removeView(cameraView); container.removeView(cameraIcon); cameraView = null; cameraIcon = null; - int count = attachPhotoRecyclerView.getChildCount(); + int count = gridView.getChildCount(); for (int a = 0; a < count; a++) { - View child = attachPhotoRecyclerView.getChildAt(a); + View child = gridView.getChildAt(a); if (child instanceof PhotoAttachCameraCell) { child.setVisibility(View.VISIBLE); return; @@ -2266,105 +3103,183 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N } } - private void showHint() { - if (editingMessageObject != null || !(baseFragment instanceof ChatActivity) || MediaDataController.getInstance(currentAccount).inlineBots.isEmpty()) { - return; - } - SharedPreferences preferences = MessagesController.getGlobalMainSettings(); - if (preferences.getBoolean("bothint", false)) { - return; - } - hintShowed = true; - - hintTextView.setVisibility(View.VISIBLE); - currentHintAnimation = new AnimatorSet(); - currentHintAnimation.playTogether( - ObjectAnimator.ofFloat(hintTextView, "alpha", 0.0f, 1.0f) - ); - currentHintAnimation.setInterpolator(decelerateInterpolator); - currentHintAnimation.addListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator animation) { - if (currentHintAnimation == null || !currentHintAnimation.equals(animation)) { - return; - } - currentHintAnimation = null; - AndroidUtilities.runOnUIThread(hideHintRunnable = new Runnable() { - @Override - public void run() { - if (hideHintRunnable != this) { - return; - } - hideHintRunnable = null; - hideHint(); + private void saveLastCameraBitmap() { + try { + TextureView textureView = cameraView.getTextureView(); + Bitmap bitmap = textureView.getBitmap(); + if (bitmap != null) { + Bitmap newBitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), cameraView.getMatrix(), true); + bitmap.recycle(); + bitmap = newBitmap; + Bitmap lastBitmap = Bitmap.createScaledBitmap(bitmap, 80, (int) (bitmap.getHeight() / (bitmap.getWidth() / 80.0f)), true); + if (lastBitmap != null) { + if (lastBitmap != bitmap) { + bitmap.recycle(); } - }, 2000); - } - - @Override - public void onAnimationCancel(Animator animation) { - if (currentHintAnimation != null && currentHintAnimation.equals(animation)) { - currentHintAnimation = null; + Utilities.blurBitmap(lastBitmap, 7, 1, lastBitmap.getWidth(), lastBitmap.getHeight(), lastBitmap.getRowBytes()); + File file = new File(ApplicationLoader.getFilesDirFixed(), "cthumb.jpg"); + FileOutputStream stream = new FileOutputStream(file); + lastBitmap.compress(Bitmap.CompressFormat.JPEG, 87, stream); + lastBitmap.recycle(); } } - }); - currentHintAnimation.setDuration(300); - currentHintAnimation.start(); + } catch (Throwable ignore) { + + } } @Override public void didReceivedNotification(int id, int account, Object... args) { if (id == NotificationCenter.albumsDidLoad) { - if (photoAttachAdapter != null) { - loading = false; - progressView.showTextView(); - photoAttachAdapter.notifyDataSetChanged(); - cameraAttachAdapter.notifyDataSetChanged(); - if (!selectedPhotosOrder.isEmpty()) { - MediaController.AlbumEntry albumEntry; - if (baseFragment instanceof ChatActivity) { - albumEntry = MediaController.allMediaAlbumEntry; - } else { - albumEntry = MediaController.allPhotosAlbumEntry; - } - if (albumEntry != null) { - for (int a = 0, N = selectedPhotosOrder.size(); a < N; a++) { - int imageId = (Integer) selectedPhotosOrder.get(a); - MediaController.PhotoEntry entry = albumEntry.photosByIds.get(imageId); - if (entry != null) { - selectedPhotos.put(imageId, entry); - } + if (adapter != null) { + if (baseFragment instanceof ChatActivity) { + galleryAlbumEntry = MediaController.allMediaAlbumEntry; + } else { + galleryAlbumEntry = MediaController.allPhotosAlbumEntry; + } + if (selectedAlbumEntry == null) { + selectedAlbumEntry = galleryAlbumEntry; + } else { + for (int a = 0; a < MediaController.allMediaAlbums.size(); a++) { + MediaController.AlbumEntry entry = MediaController.allMediaAlbums.get(a); + if (entry.bucketId == selectedAlbumEntry.bucketId && entry.videoOnly == selectedAlbumEntry.videoOnly) { + selectedAlbumEntry = entry; + break; } } } + loading = false; + progressView.showTextView(); + adapter.notifyDataSetChanged(); + cameraAttachAdapter.notifyDataSetChanged(); + if (!selectedPhotosOrder.isEmpty() && galleryAlbumEntry != null) { + for (int a = 0, N = selectedPhotosOrder.size(); a < N; a++) { + int imageId = (Integer) selectedPhotosOrder.get(a); + MediaController.PhotoEntry entry = galleryAlbumEntry.photosByIds.get(imageId); + if (entry != null) { + selectedPhotos.put(imageId, entry); + } + } + } + updateAlbumsDropDown(); } } else if (id == NotificationCenter.reloadInlineHints) { - if (adapter != null) { - adapter.notifyDataSetChanged(); + if (buttonsAdapter != null) { + buttonsAdapter.notifyDataSetChanged(); } } else if (id == NotificationCenter.cameraInitied) { checkCamera(false); } } + private void updateAlbumsDropDown() { + dropDownContainer.removeAllSubItems(); + if (mediaEnabled) { + ArrayList albums; + if (baseFragment instanceof ChatActivity) { + albums = MediaController.allMediaAlbums; + } else { + albums = MediaController.allPhotoAlbums; + } + dropDownAlbums = new ArrayList<>(albums); + Collections.sort(dropDownAlbums, (o1, o2) -> { + if (o1.bucketId == 0 && o2.bucketId != 0) { + return -1; + } else if (o1.bucketId != 0 && o2.bucketId == 0) { + return 1; + } + int index1 = albums.indexOf(o1); + int index2 = albums.indexOf(o2); + if (index1 > index2) { + return 1; + } else if (index1 < index2) { + return -1; + } else { + return 0; + } + + }); + } else { + dropDownAlbums = new ArrayList<>(); + } + if (dropDownAlbums.isEmpty()) { + dropDown.setCompoundDrawablesWithIntrinsicBounds(null, null, null, null); + } else { + dropDown.setCompoundDrawablesWithIntrinsicBounds(null, null, dropDownDrawable, null); + for (int a = 0, N = dropDownAlbums.size(); a < N; a++) { + dropDownContainer.addSubItem(10 + a, dropDownAlbums.get(a).bucketName); + } + } + } + + private void updateSelectedPosition() { + float moveProgress; + int t = scrollOffsetY - backgroundPaddingTop - AndroidUtilities.dp(39); + if (t + backgroundPaddingTop < ActionBar.getCurrentActionBarHeight()) { + float toMove = AndroidUtilities.dp(43); + moveProgress = Math.min(1.0f, (ActionBar.getCurrentActionBarHeight() - t - backgroundPaddingTop) / toMove); + cornerRadius = 1.0f - moveProgress; + } else { + moveProgress = 0.0f; + cornerRadius = 1.0f; + } + + int finalMove; + if (AndroidUtilities.isTablet()) { + finalMove = 16; + } else if (AndroidUtilities.displaySize.x > AndroidUtilities.displaySize.y) { + finalMove = 6; + } else { + finalMove = 12; + } + + float offset = actionBar.getAlpha() != 0 ? 0.0f : AndroidUtilities.dp(26 * (1.0f - selectedMenuItem.getAlpha())); + selectedMenuItem.setTranslationY(scrollOffsetY - AndroidUtilities.dp(37 + finalMove * moveProgress) + offset); + selectedTextView.setTranslationY(scrollOffsetY - AndroidUtilities.dp(25 + finalMove * moveProgress) + offset); + } + @SuppressLint("NewApi") - private void updateLayout() { - if (listView.getChildCount() <= 0) { - listView.setTopGlowOffset(scrollOffsetY = listView.getPaddingTop()); - listView.invalidate(); + private void updateLayout(boolean animated) { + if (gridView.getChildCount() <= 0) { + gridView.setTopGlowOffset(scrollOffsetY = gridView.getPaddingTop()); + containerView.invalidate(); return; } - View child = listView.getChildAt(0); - RecyclerListView.Holder holder = (RecyclerListView.Holder) listView.findContainingViewHolder(child); + View child = gridView.getChildAt(0); + RecyclerListView.Holder holder = (RecyclerListView.Holder) gridView.findContainingViewHolder(child); int top = child.getTop(); - int newOffset = 0; - if (top >= 0 && holder != null && holder.getAdapterPosition() == 0) { + int newOffset = AndroidUtilities.dp(7); + if (top >= AndroidUtilities.dp(7) && holder != null && holder.getAdapterPosition() == 0) { newOffset = top; } - if (scrollOffsetY != newOffset) { - listView.setTopGlowOffset(scrollOffsetY = newOffset); - listView.invalidate(); + boolean show = newOffset <= AndroidUtilities.dp(12); + if (show && actionBar.getTag() == null || !show && actionBar.getTag() != null) { + actionBar.setTag(show ? 1 : null); + if (actionBarAnimation != null) { + actionBarAnimation.cancel(); + actionBarAnimation = null; + } + actionBarAnimation = new AnimatorSet(); + actionBarAnimation.setDuration(180); + actionBarAnimation.playTogether( + ObjectAnimator.ofFloat(actionBar, View.ALPHA, show ? 1.0f : 0.0f), + ObjectAnimator.ofFloat(actionBarShadow, View.ALPHA, show ? 1.0f : 0.0f)); + actionBarAnimation.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + actionBarAnimation = null; + } + }); + actionBarAnimation.start(); } + FrameLayout.LayoutParams layoutParams = (FrameLayout.LayoutParams) gridView.getLayoutParams(); + newOffset += layoutParams.topMargin - AndroidUtilities.dp(11); + if (scrollOffsetY != newOffset) { + gridView.setTopGlowOffset((scrollOffsetY = newOffset) - layoutParams.topMargin); + updateSelectedPosition(); + containerView.invalidate(); + } + progressView.setTranslationY(scrollOffsetY + (gridView.getMeasuredHeight() - scrollOffsetY - AndroidUtilities.dp(50) - progressView.getMeasuredHeight()) / 2); } @Override @@ -2372,34 +3287,67 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N return false; } - public void updatePhotosButton() { + public void updatePhotosButton(int animated) { int count = selectedPhotos.size(); + if (count == 0) { - sendPhotosButton.imageView.setBackgroundDrawable(Theme.chat_attachButtonDrawables[7]); - sendPhotosButton.textView.setText(""); - sendPhotosButton.textView.setContentDescription(LocaleController.getString("Close", R.string.Close)); - if (baseFragment instanceof ChatActivity) { - sendDocumentsButton.textView.setText(LocaleController.getString("ChatDocument", R.string.ChatDocument)); - } + selectedCountView.setPivotX(0); + selectedCountView.setPivotY(0); + showCommentTextView(false, animated != 0); } else { - sendPhotosButton.imageView.setBackgroundDrawable(Theme.chat_attachButtonDrawables[8]); - sendPhotosButton.textView.setContentDescription(null); - if (baseFragment instanceof ChatActivity) { - sendPhotosButton.textView.setText(LocaleController.formatString("SendItems", R.string.SendItems, String.format("(%d)", count))); - if (editingMessageObject == null || !editingMessageObject.hasValidGroupId()) { - sendDocumentsButton.textView.setText(count == 1 ? LocaleController.getString("SendAsFile", R.string.SendAsFile) : LocaleController.getString("SendAsFiles", R.string.SendAsFiles)); - } + selectedCountView.invalidate(); + if (animated != 0 && !showCommentTextView(true, animated != 0)) { + selectedCountView.setPivotX(AndroidUtilities.dp(21)); + selectedCountView.setPivotY(AndroidUtilities.dp(12)); + AnimatorSet animatorSet = new AnimatorSet(); + animatorSet.playTogether( + ObjectAnimator.ofFloat(selectedCountView, View.SCALE_X, animated == 1 ? 1.1f : 0.9f, 1.0f), + ObjectAnimator.ofFloat(selectedCountView, View.SCALE_Y, animated == 1 ? 1.1f : 0.9f, 1.0f)); + animatorSet.setInterpolator(new OvershootInterpolator()); + animatorSet.setDuration(180); + animatorSet.start(); } else { - sendPhotosButton.textView.setText(LocaleController.formatString("UploadItems", R.string.UploadItems, String.format("(%d)", count))); + selectedCountView.setPivotX(0); + selectedCountView.setPivotY(0); + } + if (count == 1 || editingMessageObject != null) { + selectedMenuItem.hideSubItem(group); + } else { + selectedMenuItem.showSubItem(group); } } - if (Build.VERSION.SDK_INT >= 23 && getContext().checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { - progressView.setText(LocaleController.getString("PermissionStorage", R.string.PermissionStorage)); - progressView.setTextSize(16); - } else { - progressView.setText(LocaleController.getString("NoPhotos", R.string.NoPhotos)); - progressView.setTextSize(20); + if ((baseFragment instanceof ChatActivity) && (count == 0 && menuShowed || count != 0 && !menuShowed)) { + menuShowed = count != 0; + if (menuAnimator != null) { + menuAnimator.cancel(); + menuAnimator = null; + } + if (menuShowed) { + selectedMenuItem.setVisibility(View.VISIBLE); + selectedTextView.setVisibility(View.VISIBLE); + } + if (animated == 0) { + selectedMenuItem.setAlpha(menuShowed ? 1.0f : 0.0f); + selectedTextView.setAlpha(menuShowed ? 1.0f : 0.0f); + } else { + menuAnimator = new AnimatorSet(); + menuAnimator.playTogether( + ObjectAnimator.ofFloat(selectedMenuItem, View.ALPHA, menuShowed ? 1.0f : 0.0f), + ObjectAnimator.ofFloat(selectedTextView, View.ALPHA, menuShowed ? 1.0f : 0.0f)); + menuAnimator.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + menuAnimator = null; + if (!menuShowed) { + selectedMenuItem.setVisibility(View.INVISIBLE); + selectedTextView.setVisibility(View.INVISIBLE); + } + } + }); + menuAnimator.setDuration(180); + menuAnimator.start(); + } } } @@ -2420,29 +3368,66 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N } public void init() { - MediaController.AlbumEntry albumEntry; if (baseFragment instanceof ChatActivity) { - albumEntry = MediaController.allMediaAlbumEntry; + galleryAlbumEntry = MediaController.allMediaAlbumEntry; + TLRPC.Chat chat = ((ChatActivity) baseFragment).getCurrentChat(); + if (chat != null) { + mediaEnabled = ChatObject.canSendMedia(chat); + pollsEnabled = ChatObject.canSendPolls(chat); + if (mediaEnabled) { + progressView.setText(LocaleController.getString("NoPhotos", R.string.NoPhotos)); + } else { + if (ChatObject.isActionBannedByDefault(chat, ChatObject.ACTION_SEND_MEDIA)) { + progressView.setText(LocaleController.getString("GlobalAttachMediaRestricted", R.string.GlobalAttachMediaRestricted)); + } else if (AndroidUtilities.isBannedForever(chat.banned_rights)) { + progressView.setText(LocaleController.formatString("AttachMediaRestrictedForever", R.string.AttachMediaRestrictedForever)); + } else { + progressView.setText(LocaleController.formatString("AttachMediaRestricted", R.string.AttachMediaRestricted, LocaleController.formatDateForBan(chat.banned_rights.until_date))); + } + } + if (cameraView != null) { + cameraView.setAlpha(mediaEnabled ? 1.0f : 0.2f); + cameraView.setEnabled(mediaEnabled); + } + if (cameraIcon != null) { + cameraIcon.setAlpha(mediaEnabled ? 1.0f : 0.2f); + cameraIcon.setEnabled(mediaEnabled); + } + } else { + pollsEnabled = false; + } } else { - albumEntry = MediaController.allPhotosAlbumEntry; + galleryAlbumEntry = MediaController.allPhotosAlbumEntry; + commentTextView.setVisibility(View.INVISIBLE); } - if (albumEntry != null) { - for (int a = 0; a < Math.min(100, albumEntry.photos.size()); a++) { - MediaController.PhotoEntry photoEntry = albumEntry.photos.get(a); + if (Build.VERSION.SDK_INT >= 23) { + noGalleryPermissions = baseFragment.getParentActivity().checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED; + } + if (galleryAlbumEntry != null) { + for (int a = 0; a < Math.min(100, galleryAlbumEntry.photos.size()); a++) { + MediaController.PhotoEntry photoEntry = galleryAlbumEntry.photos.get(a); photoEntry.reset(); } } - if (currentHintAnimation != null) { - currentHintAnimation.cancel(); - currentHintAnimation = null; + commentTextView.hidePopup(true); + enterCommentEventSent = false; + setFocusable(false); + selectedAlbumEntry = galleryAlbumEntry; + if (selectedAlbumEntry != null) { + loading = false; + if (progressView != null) { + progressView.showTextView(); + } } - hintTextView.setAlpha(0.0f); - hintTextView.setVisibility(View.INVISIBLE); - attachPhotoLayoutManager.scrollToPositionWithOffset(0, 1000000); - cameraPhotoLayoutManager.scrollToPositionWithOffset(0, 1000000); + dropDown.setText(LocaleController.getString("ChatGallery", R.string.ChatGallery)); clearSelectedPhotos(); + updatePhotosCounter(false); + buttonsAdapter.notifyDataSetChanged(); + commentTextView.setText(""); + cameraPhotoLayoutManager.scrollToPositionWithOffset(0, 1000000); + buttonsLayoutManager.scrollToPositionWithOffset(0, 1000000); layoutManager.scrollToPositionWithOffset(0, 1000000); - updatePhotosButton(); + updateAlbumsDropDown(); } public HashMap getSelectedPhotos() { @@ -2458,12 +3443,15 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N NotificationCenter.getInstance(currentAccount).removeObserver(this, NotificationCenter.reloadInlineHints); NotificationCenter.getGlobalInstance().removeObserver(this, NotificationCenter.cameraInitied); baseFragment = null; + if (commentTextView != null) { + commentTextView.onDestroy(); + } } private PhotoAttachPhotoCell getCellForIndex(int index) { - int count = attachPhotoRecyclerView.getChildCount(); + int count = gridView.getChildCount(); for (int a = 0; a < count; a++) { - View view = attachPhotoRecyclerView.getChildAt(a); + View view = gridView.getChildAt(a); if (view instanceof PhotoAttachPhotoCell) { PhotoAttachPhotoCell cell = (PhotoAttachPhotoCell) view; if ((Integer) cell.getImageView().getTag() == index) { @@ -2474,22 +3462,14 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N return null; } - private void onRevealAnimationEnd(boolean open) { - NotificationCenter.getInstance(currentAccount).setAnimationInProgress(false); - revealAnimationInProgress = false; - MediaController.AlbumEntry albumEntry; - if (baseFragment instanceof ChatActivity) { - albumEntry = MediaController.allMediaAlbumEntry; - } else { - albumEntry = MediaController.allPhotosAlbumEntry; - } - if (open && Build.VERSION.SDK_INT <= 19 && albumEntry == null) { - MediaController.loadGalleryPhotosAlbums(0); - } - if (open) { - checkCamera(true); - showHint(); - AndroidUtilities.makeAccessibilityAnnouncement(LocaleController.getString("AccDescrAttachButton", R.string.AccDescrAttachButton)); + public void checkStorage() { + if (noGalleryPermissions && Build.VERSION.SDK_INT >= 23) { + noGalleryPermissions = baseFragment.getParentActivity().checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED; + if (!noGalleryPermissions) { + loadGalleryPhotos(); + } + adapter.notifyDataSetChanged(); + cameraAttachAdapter.notifyDataSetChanged(); } } @@ -2498,11 +3478,12 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N return; } boolean old = deviceHasGoodCamera; + boolean old2 = noCameraPermissions; if (!SharedConfig.inappCamera) { deviceHasGoodCamera = false; } else { if (Build.VERSION.SDK_INT >= 23) { - if (baseFragment.getParentActivity().checkSelfPermission(Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) { + if (noCameraPermissions = (baseFragment.getParentActivity().checkSelfPermission(Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED)) { if (request) { try { baseFragment.getParentActivity().requestPermissions(new String[]{Manifest.permission.CAMERA}, 17); @@ -2524,17 +3505,28 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N deviceHasGoodCamera = CameraController.getInstance().isCameraInitied(); } } - if (old != deviceHasGoodCamera && photoAttachAdapter != null) { - photoAttachAdapter.notifyDataSetChanged(); + if ((old != deviceHasGoodCamera || old2 != noCameraPermissions) && adapter != null) { + adapter.notifyDataSetChanged(); } - if (isShowing() && deviceHasGoodCamera && baseFragment != null && backDrawable.getAlpha() != 0 && !revealAnimationInProgress && !cameraOpened) { + if (isShowing() && deviceHasGoodCamera && baseFragment != null && backDrawable.getAlpha() != 0 && !cameraOpened) { showCamera(); } } @Override public void onOpenAnimationEnd() { - onRevealAnimationEnd(true); + NotificationCenter.getInstance(currentAccount).setAnimationInProgress(false); + MediaController.AlbumEntry albumEntry; + if (baseFragment instanceof ChatActivity) { + albumEntry = MediaController.allMediaAlbumEntry; + } else { + albumEntry = MediaController.allPhotosAlbumEntry; + } + if (Build.VERSION.SDK_INT <= 19 && albumEntry == null) { + MediaController.loadGalleryPhotosAlbums(0); + } + checkCamera(true); + AndroidUtilities.makeAccessibilityAnnouncement(LocaleController.getString("AccDescrAttachButton", R.string.AccDescrAttachButton)); } @Override @@ -2553,99 +3545,12 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N checkCameraViewPosition(); } - private class ListAdapter extends RecyclerListView.SelectionAdapter { - - private Context mContext; - - public ListAdapter(Context context) { - mContext = context; + public void setMaxSelectedPhotos(int value, boolean order) { + if (editingMessageObject != null) { + return; } - - @Override - public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { - View view; - switch (viewType) { - case 0: - view = attachView; - break; - case 1: { - FrameLayout frameLayout = new FrameLayout(mContext); - frameLayout.addView(new ShadowSectionCell(mContext), LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); - view = frameLayout; - break; - } - default: - FrameLayout frameLayout = new FrameLayout(mContext) { - @Override - protected void onLayout(boolean changed, int left, int top, int right, int bottom) { - int diff = (right - left - AndroidUtilities.dp(85 * 4 + 20)) / 3; - for (int a = 0; a < 4; a++) { - int x = AndroidUtilities.dp(10) + (a % 4) * (AndroidUtilities.dp(85) + diff); - View child = getChildAt(a); - child.layout(x, 0, x + child.getMeasuredWidth(), child.getMeasuredHeight()); - } - } - }; - for (int a = 0; a < 4; a++) { - frameLayout.addView(new AttachBotButton(mContext)); - } - view = frameLayout; - frameLayout.setLayoutParams(new RecyclerView.LayoutParams(LayoutHelper.MATCH_PARENT, AndroidUtilities.dp(100))); - break; - } - return new RecyclerListView.Holder(view); - } - - @Override - public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { - if (position == 1) { - holder.itemView.setBackgroundColor(Theme.getColor(Theme.key_dialogBackgroundGray)); - } else if (position > 1) { - position -= 2; - position *= 4; - FrameLayout frameLayout = (FrameLayout) holder.itemView; - for (int a = 0; a < 4; a++) { - AttachBotButton child = (AttachBotButton) frameLayout.getChildAt(a); - if (position + a >= MediaDataController.getInstance(currentAccount).inlineBots.size()) { - child.setVisibility(View.INVISIBLE); - } else { - child.setVisibility(View.VISIBLE); - child.setTag(position + a); - child.setUser(MessagesController.getInstance(currentAccount).getUser(MediaDataController.getInstance(currentAccount).inlineBots.get(position + a).peer.user_id)); - } - } - } - } - - @Override - public boolean isEnabled(RecyclerView.ViewHolder holder) { - return false; - } - - @Override - public int getItemCount() { - if (editingMessageObject == null && baseFragment instanceof ChatActivity) { - return 1 + (!MediaDataController.getInstance(currentAccount).inlineBots.isEmpty() ? 1 + (int) Math.ceil(MediaDataController.getInstance(currentAccount).inlineBots.size() / 4.0f) : 0); - } else { - return 1; - } - } - - @Override - public int getItemViewType(int position) { - switch (position) { - case 0: - return 0; - case 1: - return 1; - default: - return 2; - } - } - } - - public void setMaxSelectedPhotos(int value) { maxSelectedPhotos = value; + allowOrder = order; } public void setOpenWithFrontFaceCamera(boolean value) { @@ -2660,7 +3565,7 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N if (position >= 0) { selectedPhotosOrder.remove(position); } - updatePhotosCounter(); + updatePhotosCounter(false); updateCheckedPhotoIndices(); if (index >= 0) { object.reset(); @@ -2670,13 +3575,12 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N } else { selectedPhotos.put(key, object); selectedPhotosOrder.add(key); - updatePhotosCounter(); + updatePhotosCounter(true); return -1; } } private void clearSelectedPhotos() { - boolean changed = false; if (!selectedPhotos.isEmpty()) { for (HashMap.Entry entry : selectedPhotos.entrySet()) { MediaController.PhotoEntry photoEntry = (MediaController.PhotoEntry) entry.getValue(); @@ -2684,8 +3588,6 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N } selectedPhotos.clear(); selectedPhotosOrder.clear(); - updatePhotosButton(); - changed = true; } if (!cameraPhotos.isEmpty()) { for (int a = 0, size = cameraPhotos.size(); a < size; a++) { @@ -2699,11 +3601,139 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N } } cameraPhotos.clear(); - changed = true; } - if (changed) { - photoAttachAdapter.notifyDataSetChanged(); - cameraAttachAdapter.notifyDataSetChanged(); + updatePhotosButton(0); + adapter.notifyDataSetChanged(); + cameraAttachAdapter.notifyDataSetChanged(); + } + + private class ButtonsAdapter extends RecyclerListView.SelectionAdapter { + + private Context mContext; + private int galleryButton; + private int documentButton; + private int musicButton; + private int pollButton; + private int contactButton; + private int locationButton; + private int buttonsCount; + + public ButtonsAdapter(Context context) { + mContext = context; + } + + @Override + public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { + View view; + switch (viewType) { + case 0: + view = new AttachButton(mContext); + break; + case 1: + default: + view = new AttachBotButton(mContext); + break; + } + return new RecyclerListView.Holder(view); + } + + @Override + public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { + switch (holder.getItemViewType()) { + case 0: + AttachButton attachButton = (AttachButton) holder.itemView; + if (position == galleryButton) { + attachButton.setTextAndIcon(LocaleController.getString("ChatGallery", R.string.ChatGallery), Theme.chat_attachButtonDrawables[0]); + attachButton.setTag(1); + } else if (position == documentButton) { + attachButton.setTextAndIcon(LocaleController.getString("ChatDocument", R.string.ChatDocument), Theme.chat_attachButtonDrawables[2]); + attachButton.setTag(4); + } else if (position == locationButton) { + attachButton.setTextAndIcon(LocaleController.getString("ChatLocation", R.string.ChatLocation), Theme.chat_attachButtonDrawables[4]); + attachButton.setTag(6); + } else if (position == musicButton) { + attachButton.setTextAndIcon(LocaleController.getString("AttachMusic", R.string.AttachMusic), Theme.chat_attachButtonDrawables[1]); + attachButton.setTag(3); + } else if (position == pollButton) { + attachButton.setTextAndIcon(LocaleController.getString("Poll", R.string.Poll), Theme.chat_attachButtonDrawables[5]); + attachButton.setTag(9); + } else if (position == contactButton) { + attachButton.setTextAndIcon(LocaleController.getString("AttachContact", R.string.AttachContact), Theme.chat_attachButtonDrawables[3]); + attachButton.setTag(5); + } + break; + case 1: + position -= buttonsCount; + AttachBotButton child = (AttachBotButton) holder.itemView; + child.setTag(position); + child.setUser(MessagesController.getInstance(currentAccount).getUser(MediaDataController.getInstance(currentAccount).inlineBots.get(position).peer.user_id)); + break; + } + } + + @Override + public void onViewAttachedToWindow(RecyclerView.ViewHolder holder) { + applyAttachButtonColors(holder.itemView); + } + + @Override + public boolean isEnabled(RecyclerView.ViewHolder holder) { + return false; + } + + @Override + public int getItemCount() { + int count = buttonsCount; + if (editingMessageObject == null && baseFragment instanceof ChatActivity) { + count += MediaDataController.getInstance(currentAccount).inlineBots.size(); + } + return count; + } + + @Override + public void notifyDataSetChanged() { + buttonsCount = 0; + galleryButton = -1; + documentButton = -1; + musicButton = -1; + pollButton = -1; + contactButton = -1; + locationButton = -1; + if (!(baseFragment instanceof ChatActivity)) { + galleryButton = buttonsCount++; + documentButton = buttonsCount++; + } else if (editingMessageObject != null) { + galleryButton = buttonsCount++; + documentButton = buttonsCount++; + musicButton = buttonsCount++; + } else { + if (mediaEnabled) { + galleryButton = buttonsCount++; + documentButton = buttonsCount++; + } + locationButton = buttonsCount++; + if (pollsEnabled) { + pollButton = buttonsCount++; + } else { + contactButton = buttonsCount++; + } + if (mediaEnabled) { + musicButton = buttonsCount++; + } + } + super.notifyDataSetChanged(); + } + + public int getButtonsCount() { + return buttonsCount; + } + + @Override + public int getItemViewType(int position) { + if (position < buttonsCount) { + return 0; + } + return 1; } } @@ -2712,6 +3742,7 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N private Context mContext; private boolean needCamera; private ArrayList viewsCache = new ArrayList<>(8); + private int itemsCount; public PhotoAttachAdapter(Context context, boolean camera) { mContext = context; @@ -2723,6 +3754,28 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N public RecyclerListView.Holder createHolder() { PhotoAttachPhotoCell cell = new PhotoAttachPhotoCell(mContext); + if (Build.VERSION.SDK_INT >= 21 && this == adapter) { + cell.setOutlineProvider(new ViewOutlineProvider() { + @Override + public void getOutline(View view, Outline outline) { + PhotoAttachPhotoCell photoCell = (PhotoAttachPhotoCell) view; + int position = (Integer) photoCell.getTag(); + if (needCamera && selectedAlbumEntry == galleryAlbumEntry) { + position++; + } + if (position == 0) { + int rad = AndroidUtilities.dp(8 * cornerRadius); + outline.setRoundRect(0, 0, view.getMeasuredWidth() + rad, view.getMeasuredHeight() + rad, rad); + } else if (position == itemsPerRow - 1) { + int rad = AndroidUtilities.dp(8 * cornerRadius); + outline.setRoundRect(-rad, 0, view.getMeasuredWidth(), view.getMeasuredHeight() + rad, rad); + } else { + outline.setRect(0, 0, view.getMeasuredWidth(), view.getMeasuredHeight()); + } + } + }); + cell.setClipToOutline(true); + } cell.setDelegate(v -> { if (!mediaEnabled) { return; @@ -2731,10 +3784,17 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N MediaController.PhotoEntry photoEntry = v.getPhotoEntry(); boolean added = !selectedPhotos.containsKey(photoEntry.imageId); if (added && maxSelectedPhotos >= 0 && selectedPhotos.size() >= maxSelectedPhotos) { + if (allowOrder && baseFragment instanceof ChatActivity) { + ChatActivity chatActivity = (ChatActivity) baseFragment; + TLRPC.Chat chat = chatActivity.getCurrentChat(); + if (chat != null && !ChatObject.hasAdminRights(chat) && chat.slowmode_enabled) { + AlertsCreator.createSimpleAlert(getContext(), LocaleController.getString("Slowmode", R.string.Slowmode), LocaleController.getString("SlowmodeSelectSendError", R.string.SlowmodeSelectSendError)).show(); + } + } return; } int num = added ? selectedPhotosOrder.size() : -1; - if (baseFragment instanceof ChatActivity && maxSelectedPhotos < 0) { + if (baseFragment instanceof ChatActivity && allowOrder) { v.setChecked(num, added, true); } else { v.setChecked(-1, added, true); @@ -2742,40 +3802,58 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N addToSelectedPhotos(photoEntry, index); int updateIndex = index; if (PhotoAttachAdapter.this == cameraAttachAdapter) { - if (photoAttachAdapter.needCamera && deviceHasGoodCamera) { + if (adapter.needCamera && selectedAlbumEntry == galleryAlbumEntry) { updateIndex++; } - photoAttachAdapter.notifyItemChanged(updateIndex); + adapter.notifyItemChanged(updateIndex); } else { cameraAttachAdapter.notifyItemChanged(updateIndex); } - updatePhotosButton(); + updatePhotosButton(added ? 1 : 2); }); return new RecyclerListView.Holder(cell); } @Override public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { - if (!needCamera || !deviceHasGoodCamera || position != 0) { - if (needCamera && deviceHasGoodCamera) { - position--; + switch (holder.getItemViewType()) { + case 0: { + if (needCamera && selectedAlbumEntry == galleryAlbumEntry) { + position--; + } + PhotoAttachPhotoCell cell = (PhotoAttachPhotoCell) holder.itemView; + if (this == adapter) { + cell.setItemSize(itemSize); + } else { + cell.setIsVertical(cameraPhotoLayoutManager.getOrientation() == LinearLayoutManager.VERTICAL); + } + + MediaController.PhotoEntry photoEntry = getPhotoEntryAtPosition(position); + cell.setPhotoEntry(photoEntry, needCamera && selectedAlbumEntry == galleryAlbumEntry, position == getItemCount() - 1); + if (baseFragment instanceof ChatActivity && allowOrder) { + cell.setChecked(selectedPhotosOrder.indexOf(photoEntry.imageId), selectedPhotos.containsKey(photoEntry.imageId), false); + } else { + cell.setChecked(-1, selectedPhotos.containsKey(photoEntry.imageId), false); + } + cell.getImageView().setTag(position); + cell.setTag(position); + break; } - PhotoAttachPhotoCell cell = (PhotoAttachPhotoCell) holder.itemView; - MediaController.PhotoEntry photoEntry = getPhotoEntryAtPosition(position); - cell.setPhotoEntry(photoEntry, needCamera, position == getItemCount() - 1); - if (baseFragment instanceof ChatActivity && maxSelectedPhotos < 0) { - cell.setChecked(selectedPhotosOrder.indexOf(photoEntry.imageId), selectedPhotos.containsKey(photoEntry.imageId), false); - } else { - cell.setChecked(-1, selectedPhotos.containsKey(photoEntry.imageId), false); + case 1: { + PhotoAttachCameraCell cameraCell = (PhotoAttachCameraCell) holder.itemView; + if (cameraView != null && cameraView.isInitied()) { + cameraCell.setVisibility(View.INVISIBLE); + } else { + cameraCell.setVisibility(View.VISIBLE); + } + cameraCell.setItemSize(itemSize); + break; } - cell.getImageView().setTag(position); - cell.setTag(position); - cell.setIsVertical(this == cameraAttachAdapter && cameraPhotoLayoutManager.getOrientation() == LinearLayoutManager.VERTICAL); - } else if (needCamera && deviceHasGoodCamera && position == 0) { - if (cameraView != null && cameraView.isInitied()) { - holder.itemView.setVisibility(View.INVISIBLE); - } else { - holder.itemView.setVisibility(View.VISIBLE); + case 3: { + PhotoAttachPermissionCell cell = (PhotoAttachPermissionCell) holder.itemView; + cell.setItemSize(itemSize); + cell.setType(needCamera && noCameraPermissions && position == 0 ? 0 : 1); + break; } } } @@ -2789,10 +3867,7 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { RecyclerListView.Holder holder; switch (viewType) { - case 1: - holder = new RecyclerListView.Holder(new PhotoAttachCameraCell(mContext)); - break; - default: + case 0: if (!viewsCache.isEmpty()) { holder = viewsCache.get(0); viewsCache.remove(0); @@ -2800,236 +3875,95 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N holder = createHolder(); } break; + case 1: + PhotoAttachCameraCell cameraCell = new PhotoAttachCameraCell(mContext); + if (Build.VERSION.SDK_INT >= 21) { + cameraCell.setOutlineProvider(new ViewOutlineProvider() { + @Override + public void getOutline(View view, Outline outline) { + int rad = AndroidUtilities.dp(8 * cornerRadius); + outline.setRoundRect(0, 0, view.getMeasuredWidth() + rad, view.getMeasuredHeight() + rad, rad); + } + }); + cameraCell.setClipToOutline(true); + } + holder = new RecyclerListView.Holder(cameraCell); + break; + case 2: + holder = new RecyclerListView.Holder(new View(mContext) { + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(gridExtraSpace, MeasureSpec.EXACTLY)); + } + }); + break; + case 3: + default: + holder = new RecyclerListView.Holder(new PhotoAttachPermissionCell(mContext)); + break; } - return holder; } + @Override + public void onViewAttachedToWindow(RecyclerView.ViewHolder holder) { + if (holder.itemView instanceof PhotoAttachCameraCell) { + PhotoAttachCameraCell cell = (PhotoAttachCameraCell) holder.itemView; + cell.updateBitmap(); + } + } + @Override public int getItemCount() { + if (!mediaEnabled) { + return 1; + } int count = 0; - if (needCamera && deviceHasGoodCamera) { + if (needCamera && selectedAlbumEntry == galleryAlbumEntry) { + count++; + } + if (noGalleryPermissions && this == adapter) { count++; } count += cameraPhotos.size(); - MediaController.AlbumEntry albumEntry; - if (baseFragment instanceof ChatActivity) { - albumEntry = MediaController.allMediaAlbumEntry; - } else { - albumEntry = MediaController.allPhotosAlbumEntry; + if (selectedAlbumEntry != null) { + count += selectedAlbumEntry.photos.size(); } - if (albumEntry != null) { - count += albumEntry.photos.size(); + if (this == adapter) { + count++; } - return count; + return itemsCount = count; } @Override public int getItemViewType(int position) { - if (needCamera && deviceHasGoodCamera && position == 0) { - return 1; + if (!mediaEnabled) { + return 2; + } + if (needCamera && position == 0 && selectedAlbumEntry == galleryAlbumEntry) { + if (noCameraPermissions) { + return 3; + } else { + return 1; + } + } + if (this == adapter && position == itemsCount - 1) { + return 2; + } else if (noGalleryPermissions) { + return 3; } return 0; } - } - private void setUseRevealAnimation(boolean value) { - if (!value || value && Build.VERSION.SDK_INT >= 18 && !AndroidUtilities.isTablet() && AndroidUtilities.shouldEnableAnimation() && baseFragment instanceof ChatActivity) { - useRevealAnimation = value; - } - } - - @Keep - @SuppressLint("NewApi") - protected void setRevealRadius(float radius) { - revealRadius = radius; - if (Build.VERSION.SDK_INT <= 19) { - listView.invalidate(); - } - if (!isDismissed()) { - for (int a = 0; a < innerAnimators.size(); a++) { - InnerAnimator innerAnimator = innerAnimators.get(a); - if (innerAnimator.startRadius > radius) { - continue; - } - innerAnimator.animatorSet.start(); - innerAnimators.remove(a); - a--; + @Override + public void notifyDataSetChanged() { + super.notifyDataSetChanged(); + if (this == adapter) { + progressView.setVisibility(getItemCount() == 1 && selectedAlbumEntry == null || !mediaEnabled ? View.VISIBLE : View.INVISIBLE); } } } - @Keep - protected float getRevealRadius() { - return revealRadius; - } - - @SuppressLint("NewApi") - private void startRevealAnimation(final boolean open) { - containerView.setTranslationY(0); - - final AnimatorSet animatorSet = new AnimatorSet(); - - View view = delegate.getRevealView(); - if (view.getVisibility() == View.VISIBLE && ((ViewGroup) view.getParent()).getVisibility() == View.VISIBLE) { - final int[] coords = new int[2]; - view.getLocationInWindow(coords); - float top; - if (Build.VERSION.SDK_INT <= 19) { - top = AndroidUtilities.displaySize.y - containerView.getMeasuredHeight() - AndroidUtilities.statusBarHeight; - } else { - top = containerView.getY(); - } - revealX = coords[0] + view.getMeasuredWidth() / 2; - revealY = (int) (coords[1] + view.getMeasuredHeight() / 2 - top); - if (Build.VERSION.SDK_INT <= 19) { - revealY -= AndroidUtilities.statusBarHeight; - } - } else { - revealX = AndroidUtilities.displaySize.x / 2 + backgroundPaddingLeft; - revealY = (int) (AndroidUtilities.displaySize.y - containerView.getY()); - } - - int[][] corners = new int[][]{ - {0, 0}, - {0, AndroidUtilities.dp(304)}, - {containerView.getMeasuredWidth(), 0}, - {containerView.getMeasuredWidth(), AndroidUtilities.dp(304)} - }; - int finalRevealRadius = 0; - int y = revealY - scrollOffsetY + backgroundPaddingTop; - for (int a = 0; a < 4; a++) { - finalRevealRadius = Math.max(finalRevealRadius, (int) Math.ceil(Math.sqrt((revealX - corners[a][0]) * (revealX - corners[a][0]) + (y - corners[a][1]) * (y - corners[a][1])))); - } - int finalRevealX = revealX <= containerView.getMeasuredWidth() ? revealX : containerView.getMeasuredWidth(); - - ArrayList animators = new ArrayList<>(3); - animators.add(ObjectAnimator.ofFloat(this, "revealRadius", open ? 0 : finalRevealRadius, open ? finalRevealRadius : 0)); - animators.add(ObjectAnimator.ofInt(backDrawable, "alpha", open ? 51 : 0)); - if (Build.VERSION.SDK_INT >= 21) { - try { - animators.add(ViewAnimationUtils.createCircularReveal(containerView, finalRevealX, revealY, open ? 0 : finalRevealRadius, open ? finalRevealRadius : 0)); - } catch (Exception e) { - FileLog.e(e); - } - animatorSet.setDuration(320); - } else { - if (!open) { - animatorSet.setDuration(200); - containerView.setPivotX(revealX <= containerView.getMeasuredWidth() ? revealX : containerView.getMeasuredWidth()); - containerView.setPivotY(revealY); - animators.add(ObjectAnimator.ofFloat(containerView, View.SCALE_X, 0.0f)); - animators.add(ObjectAnimator.ofFloat(containerView, View.SCALE_Y, 0.0f)); - animators.add(ObjectAnimator.ofFloat(containerView, View.ALPHA, 0.0f)); - } else { - animatorSet.setDuration(250); - containerView.setScaleX(1); - containerView.setScaleY(1); - containerView.setAlpha(1); - if (Build.VERSION.SDK_INT <= 19) { - animatorSet.setStartDelay(20); - } - } - } - animatorSet.playTogether(animators); - animatorSet.addListener(new AnimatorListenerAdapter() { - public void onAnimationEnd(Animator animation) { - if (currentSheetAnimation != null && currentSheetAnimation.equals(animation)) { - currentSheetAnimation = null; - onRevealAnimationEnd(open); - containerView.invalidate(); - containerView.setLayerType(View.LAYER_TYPE_NONE, null); - if (!open) { - try { - dismissInternal(); - } catch (Exception e) { - FileLog.e(e); - } - } - } - NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.startAllHeavyOperations, 512); - } - - @Override - public void onAnimationCancel(Animator animation) { - if (currentSheetAnimation != null && animatorSet.equals(animation)) { - currentSheetAnimation = null; - } - } - }); - - if (open) { - innerAnimators.clear(); - NotificationCenter.getInstance(currentAccount).setAllowedNotificationsDutingAnimation(new int[]{NotificationCenter.dialogsNeedReload}); - NotificationCenter.getInstance(currentAccount).setAnimationInProgress(true); - revealAnimationInProgress = true; - - int count = Build.VERSION.SDK_INT <= 19 ? 12 : 8; - for (int a = 0; a < count; a++) { - if (views[a] == null) { - continue; - } - if (Build.VERSION.SDK_INT <= 19) { - if (a < 8) { - views[a].setScaleX(0.1f); - views[a].setScaleY(0.1f); - } - views[a].setAlpha(0.0f); - } else { - views[a].setScaleX(0.7f); - views[a].setScaleY(0.7f); - } - - InnerAnimator innerAnimator = new InnerAnimator(); - - int buttonX = views[a].getLeft() + views[a].getMeasuredWidth() / 2; - int buttonY = views[a].getTop() + attachView.getTop() + views[a].getMeasuredHeight() / 2; - float dist = (float) Math.sqrt((revealX - buttonX) * (revealX - buttonX) + (revealY - buttonY) * (revealY - buttonY)); - float vecX = (revealX - buttonX) / dist; - float vecY = (revealY - buttonY) / dist; - views[a].setPivotX(views[a].getMeasuredWidth() / 2 + vecX * AndroidUtilities.dp(20)); - views[a].setPivotY(views[a].getMeasuredHeight() / 2 + vecY * AndroidUtilities.dp(20)); - innerAnimator.startRadius = dist - AndroidUtilities.dp(27 * 3); - - views[a].setTag(R.string.AppName, 1); - animators = new ArrayList<>(); - final AnimatorSet animatorSetInner; - if (a < 8) { - animators.add(ObjectAnimator.ofFloat(views[a], View.SCALE_X, 0.7f, 1.05f)); - animators.add(ObjectAnimator.ofFloat(views[a], View.SCALE_Y, 0.7f, 1.05f)); - - animatorSetInner = new AnimatorSet(); - animatorSetInner.playTogether( - ObjectAnimator.ofFloat(views[a], View.SCALE_X, 1.0f), - ObjectAnimator.ofFloat(views[a], View.SCALE_Y, 1.0f)); - animatorSetInner.setDuration(100); - animatorSetInner.setInterpolator(CubicBezierInterpolator.EASE_OUT); - } else { - animatorSetInner = null; - } - if (Build.VERSION.SDK_INT <= 19) { - animators.add(ObjectAnimator.ofFloat(views[a], View.ALPHA, 1.0f)); - } - innerAnimator.animatorSet = new AnimatorSet(); - innerAnimator.animatorSet.playTogether(animators); - innerAnimator.animatorSet.setDuration(150); - innerAnimator.animatorSet.setInterpolator(CubicBezierInterpolator.EASE_OUT); - innerAnimator.animatorSet.addListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator animation) { - if (animatorSetInner != null) { - animatorSetInner.start(); - } - } - }); - innerAnimators.add(innerAnimator); - } - } - currentSheetAnimation = animatorSet; - NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.stopAllHeavyOperations, 512); - animatorSet.start(); - } - @Override public void dismissInternal() { if (containerView != null) { @@ -3039,67 +3973,12 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N } @Override - protected boolean onCustomOpenAnimation() { - if (useRevealAnimation) { - setUseRevealAnimation(true); + public void onBackPressed() { + if (commentTextView != null && commentTextView.isPopupShowing()) { + commentTextView.hidePopup(true); + return; } - if (baseFragment instanceof ChatActivity) { - updatePollMusicButton(); - TLRPC.Chat chat = ((ChatActivity) baseFragment).getCurrentChat(); - if (chat != null) { - mediaEnabled = ChatObject.canSendMedia(chat); - for (int a = 0; a < 5; a++) { - boolean enabled; - if (a > 2 && editingMessageObject != null && editingMessageObject.hasValidGroupId()) { - attachButtons.get(a).setEnabled(false); - attachButtons.get(a).setAlpha(0.2f); - } else { - AttachButton attachButton = attachButtons.get(a); - Integer tag = (Integer) attachButton.getTag(); - attachButton.setAlpha(mediaEnabled || tag == 9 ? 1.0f : 0.2f); - attachButton.setEnabled(mediaEnabled || tag == 9); - } - } - attachPhotoRecyclerView.setAlpha(mediaEnabled ? 1.0f : 0.2f); - attachPhotoRecyclerView.setEnabled(mediaEnabled); - if (!mediaEnabled) { - if (ChatObject.isActionBannedByDefault(chat, ChatObject.ACTION_SEND_MEDIA)) { - mediaBanTooltip.setText(LocaleController.getString("GlobalAttachMediaRestricted", R.string.GlobalAttachMediaRestricted)); - } else if (AndroidUtilities.isBannedForever(chat.banned_rights)) { - mediaBanTooltip.setText(LocaleController.formatString("AttachMediaRestrictedForever", R.string.AttachMediaRestrictedForever)); - } else { - mediaBanTooltip.setText(LocaleController.formatString("AttachMediaRestricted", R.string.AttachMediaRestricted, LocaleController.formatDateForBan(chat.banned_rights.until_date))); - } - } - mediaBanTooltip.setVisibility(mediaEnabled ? View.INVISIBLE : View.VISIBLE); - if (cameraView != null) { - cameraView.setAlpha(mediaEnabled ? 1.0f : 0.2f); - cameraView.setEnabled(mediaEnabled); - } - if (cameraIcon != null) { - cameraIcon.setAlpha(mediaEnabled ? 1.0f : 0.2f); - cameraIcon.setEnabled(mediaEnabled); - } - } - } - if (useRevealAnimation) { - startRevealAnimation(true); - return true; - } - return false; - } - - @Override - protected boolean onCustomCloseAnimation() { - if (useRevealAnimation) { - setUseRevealAnimation(true); - } - if (useRevealAnimation) { - backDrawable.setAlpha(51); - startRevealAnimation(false); - return true; - } - return false; + super.onBackPressed(); } @Override @@ -3122,6 +4001,9 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N closeCamera(true); return; } + if (commentTextView != null) { + AndroidUtilities.hideKeyboard(commentTextView.getEditText()); + } hideCamera(true); super.dismiss(); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/CheckBox.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/CheckBox.java index d66b16816..154265616 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/CheckBox.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/CheckBox.java @@ -126,6 +126,10 @@ public class CheckBox extends View { } } + public void setStrokeWidth(int value) { + backgroundPaint.setStrokeWidth(value); + } + public float getProgress() { return progress; } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/CheckBox2.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/CheckBox2.java index bb298c85f..fee9df963 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/CheckBox2.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/CheckBox2.java @@ -8,20 +8,28 @@ public class CheckBox2 extends View { private CheckBoxBase checkBoxBase; - public CheckBox2(Context context) { + public CheckBox2(Context context, int sz) { super(context); - checkBoxBase = new CheckBoxBase(this); + checkBoxBase = new CheckBoxBase(this, sz); } public void setProgressDelegate(CheckBoxBase.ProgressDelegate delegate) { checkBoxBase.setProgressDelegate(delegate); } + public void setChecked(int num, boolean checked, boolean animated) { + checkBoxBase.setChecked(num, checked, animated); + } + public void setChecked(boolean checked, boolean animated) { checkBoxBase.setChecked(checked, animated); } + public void setNum(int num) { + checkBoxBase.setNum(num); + } + public boolean isChecked() { return checkBoxBase.isChecked(); } @@ -30,10 +38,6 @@ public class CheckBox2 extends View { checkBoxBase.setColor(background, background2, check); } - public void setSize(int size) { - checkBoxBase.setSize(size); - } - @Override public void setEnabled(boolean enabled) { checkBoxBase.setEnabled(enabled); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/CheckBoxBase.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/CheckBoxBase.java index 76e708b0b..49c5dadab 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/CheckBoxBase.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/CheckBoxBase.java @@ -13,6 +13,8 @@ import android.graphics.PorterDuffXfermode; import android.graphics.Rect; import android.graphics.RectF; import androidx.annotation.Keep; + +import android.text.TextPaint; import android.view.View; import org.telegram.messenger.AndroidUtilities; @@ -26,8 +28,9 @@ public class CheckBoxBase { private static Paint paint; private static Paint eraser; - private static Paint checkPaint; - private static Paint backgroundPaint; + private Paint checkPaint; + private Paint backgroundPaint; + private TextPaint textPaint; private Path path = new Path(); @@ -56,6 +59,8 @@ public class CheckBoxBase { private float size = 21; + private String checkedText; + private ProgressDelegate progressDelegate; public interface ProgressDelegate { @@ -63,23 +68,27 @@ public class CheckBoxBase { } public CheckBoxBase(View parent) { + this(parent, 21); + } + + public CheckBoxBase(View parent, int sz) { parentView = parent; + size = sz; if (paint == null) { paint = new Paint(Paint.ANTI_ALIAS_FLAG); eraser = new Paint(Paint.ANTI_ALIAS_FLAG); eraser.setColor(0); eraser.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR)); - - backgroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG); - backgroundPaint.setStyle(Paint.Style.STROKE); - - checkPaint = new Paint(Paint.ANTI_ALIAS_FLAG); - checkPaint.setStrokeCap(Paint.Cap.ROUND); - checkPaint.setStyle(Paint.Style.STROKE); - checkPaint.setStrokeJoin(Paint.Join.ROUND); } + checkPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + checkPaint.setStrokeCap(Paint.Cap.ROUND); + checkPaint.setStyle(Paint.Style.STROKE); + checkPaint.setStrokeJoin(Paint.Join.ROUND); checkPaint.setStrokeWidth(AndroidUtilities.dp(1.9f)); + + backgroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + backgroundPaint.setStyle(Paint.Style.STROKE); backgroundPaint.setStrokeWidth(AndroidUtilities.dp(1.2f)); drawBitmap = Bitmap.createBitmap(AndroidUtilities.dp(size), AndroidUtilities.dp(size), Bitmap.Config.ARGB_4444); @@ -111,22 +120,22 @@ public class CheckBoxBase { return; } progress = value; - if (parentView.getParent() != null) { - View parent = (View) parentView.getParent(); - parent.invalidate(); - } - parentView.invalidate(); + invalidate(); if (progressDelegate != null) { progressDelegate.setProgress(value); } } - public void setProgressDelegate(ProgressDelegate delegate) { - progressDelegate = delegate; + private void invalidate() { + if (parentView.getParent() != null) { + View parent = (View) parentView.getParent(); + parent.invalidate(); + } + parentView.invalidate(); } - public void setSize(int value) { - size = value; + public void setProgressDelegate(ProgressDelegate delegate) { + progressDelegate = delegate; } public float getProgress() { @@ -170,6 +179,9 @@ public class CheckBoxBase { if (animation.equals(checkAnimator)) { checkAnimator = null; } + if (!isChecked) { + checkedText = null; + } } }); checkAnimator.setInterpolator(CubicBezierInterpolator.EASE_OUT); @@ -191,7 +203,24 @@ public class CheckBoxBase { backgroundAlpha = alpha; } + public void setNum(int num) { + if (num >= 0) { + checkedText = "" + (num + 1); + } else if (checkAnimator == null) { + checkedText = null; + } + invalidate(); + } + public void setChecked(boolean checked, boolean animated) { + setChecked(-1, checked, animated); + } + + public void setChecked(int num, boolean checked, boolean animated) { + if (num >= 0) { + checkedText = "" + (num + 1); + invalidate(); + } if (checked == isChecked) { return; } @@ -239,29 +268,53 @@ public class CheckBoxBase { } if (drawUnchecked) { - canvas.drawCircle(cx, cy, rad, paint); + if (drawBackgroundAsArc == 6 || drawBackgroundAsArc == 7) { + canvas.drawCircle(cx, cy, rad - AndroidUtilities.dp(1), paint); + canvas.drawCircle(cx, cy, rad - AndroidUtilities.dp(1.5f), backgroundPaint); + } else { + canvas.drawCircle(cx, cy, rad, paint); + } } paint.setColor(Theme.getColor(checkColorKey)); - if (drawBackgroundAsArc == 0) { - canvas.drawCircle(cx, cy, rad, backgroundPaint); - } else { - rect.set(cx - outerRad, cy - outerRad, cx + outerRad, cy + outerRad); - int startAngle; - int sweepAngle; - if (drawBackgroundAsArc == 1) { - startAngle = -90; - sweepAngle = (int) (-270 * progress); + if (drawBackgroundAsArc != 7) { + if (drawBackgroundAsArc == 0) { + canvas.drawCircle(cx, cy, rad, backgroundPaint); } else { - startAngle = 90; - sweepAngle = (int) (270 * progress); + rect.set(cx - outerRad, cy - outerRad, cx + outerRad, cy + outerRad); + int startAngle; + int sweepAngle; + if (drawBackgroundAsArc == 6) { + startAngle = 0; + sweepAngle = (int) (-360 * progress); + } else if (drawBackgroundAsArc == 1) { + startAngle = -90; + sweepAngle = (int) (-270 * progress); + } else { + startAngle = 90; + sweepAngle = (int) (270 * progress); + } + + if (drawBackgroundAsArc == 6) { + int color = Theme.getColor(Theme.key_dialogBackground); + int alpha = Color.alpha(color); + backgroundPaint.setColor(color); + backgroundPaint.setAlpha((int) (alpha * progress)); + canvas.drawArc(rect, startAngle, sweepAngle, false, backgroundPaint); + color = Theme.getColor(Theme.key_chat_attachPhotoBackground); + alpha = Color.alpha(color); + backgroundPaint.setColor(color); + backgroundPaint.setAlpha((int) (alpha * progress)); + canvas.drawArc(rect, startAngle, sweepAngle, false, backgroundPaint); + } else { + canvas.drawArc(rect, startAngle, sweepAngle, false, backgroundPaint); + } } - canvas.drawArc(rect, startAngle, sweepAngle, false, backgroundPaint); } if (roundProgress > 0) { float checkProgress = progress < 0.5f ? 0.0f : (progress - 0.5f) / 0.5f; - if (!drawUnchecked && backgroundColorKey != null) { + if (drawBackgroundAsArc == 6 || drawBackgroundAsArc == 7 || !drawUnchecked && backgroundColorKey != null) { paint.setColor(Theme.getColor(backgroundColorKey)); } else { paint.setColor(Theme.getColor(enabled ? Theme.key_checkbox : Theme.key_checkboxDisabled)); @@ -278,19 +331,35 @@ public class CheckBoxBase { canvas.drawBitmap(drawBitmap, cx - drawBitmap.getWidth() / 2, cy - drawBitmap.getHeight() / 2, null); if (checkProgress != 0) { - path.reset(); + if (checkedText != null) { + if (textPaint == null) { + textPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG); + textPaint.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); + } + int color = Theme.getColor(checkColorKey); + int alpha = Color.alpha(color); + textPaint.setColor(color); + textPaint.setTextSize(AndroidUtilities.dp(14)); + int w = (int) Math.ceil(textPaint.measureText(checkedText)); + canvas.save(); + canvas.scale(checkProgress, 1.0f, cx, cy); + canvas.drawText(checkedText, cx - w / 2, AndroidUtilities.dp(18), textPaint); + canvas.restore(); + } else { + path.reset(); - float scale = drawBackgroundAsArc == 5 ? 0.8f : 1.0f; - float checkSide = AndroidUtilities.dp(9 * scale) * checkProgress; - float smallCheckSide = AndroidUtilities.dp(4 * scale) * checkProgress; - int x = cx - AndroidUtilities.dp(1.5f); - int y = cy + AndroidUtilities.dp(4); - float side = (float) Math.sqrt(smallCheckSide * smallCheckSide / 2.0f); - path.moveTo(x - side, y - side); - path.lineTo(x, y); - side = (float) Math.sqrt(checkSide * checkSide / 2.0f); - path.lineTo(x + side, y - side); - canvas.drawPath(path, checkPaint); + float scale = drawBackgroundAsArc == 5 ? 0.8f : 1.0f; + float checkSide = AndroidUtilities.dp(9 * scale) * checkProgress; + float smallCheckSide = AndroidUtilities.dp(4 * scale) * checkProgress; + int x = cx - AndroidUtilities.dp(1.5f); + int y = cy + AndroidUtilities.dp(4); + float side = (float) Math.sqrt(smallCheckSide * smallCheckSide / 2.0f); + path.moveTo(x - side, y - side); + path.lineTo(x, y); + side = (float) Math.sqrt(checkSide * checkSide / 2.0f); + path.lineTo(x + side, y - side); + canvas.drawPath(path, checkPaint); + } } } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/EditTextEmoji.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/EditTextEmoji.java index 1db7e62c1..30765b65e 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/EditTextEmoji.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/EditTextEmoji.java @@ -214,6 +214,21 @@ public class EditTextEmoji extends FrameLayout implements NotificationCenter.Not } } + public void updateColors() { + if (currentStyle == STYLE_FRAGMENT) { + editText.setHintTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteHintText)); + editText.setCursorColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlackText)); + editText.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlackText)); + } else { + editText.setHintTextColor(Theme.getColor(Theme.key_dialogTextHint)); + editText.setTextColor(Theme.getColor(Theme.key_dialogTextBlack)); + } + emojiButton.setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_chat_messagePanelIcons), PorterDuff.Mode.MULTIPLY)); + if (emojiView != null) { + emojiView.updateColors(); + } + } + public void setMaxLines(int value) { editText.setMaxLines(value); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/EmbedBottomSheet.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/EmbedBottomSheet.java index 96e3c7d95..7fc8e64bb 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/EmbedBottomSheet.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/EmbedBottomSheet.java @@ -13,7 +13,6 @@ import android.animation.AnimatorListenerAdapter; import android.animation.AnimatorSet; import android.animation.ObjectAnimator; import android.annotation.SuppressLint; -import android.annotation.TargetApi; import android.app.Activity; import android.content.Context; import android.content.DialogInterface; @@ -29,7 +28,6 @@ import android.provider.Settings; import android.text.TextUtils; import android.util.TypedValue; import android.view.Gravity; -import android.view.MotionEvent; import android.view.OrientationEventListener; import android.view.Surface; import android.view.TextureView; @@ -78,10 +76,8 @@ public class EmbedBottomSheet extends BottomSheet { private PipVideoView pipVideoView; private LinearLayout imageButtonsContainer; private TextView copyTextButton; - private TextView openInButton; private FrameLayout containerLayout; private ImageView pipButton; - private ImageView youtubeLogoImage; private boolean isYouTube; private int[] position = new int[2]; @@ -101,20 +97,19 @@ public class EmbedBottomSheet extends BottomSheet { private int waitingForDraw; + private int seekTimeOverride; + private class YoutubeProxy { @JavascriptInterface public void postEvent(final String eventName, final String eventData) { - AndroidUtilities.runOnUIThread(() -> { - switch (eventName) { - case "loaded": - progressBar.setVisibility(View.INVISIBLE); - progressBarBlackBackground.setVisibility(View.INVISIBLE); - pipButton.setEnabled(true); - pipButton.setAlpha(1.0f); - showOrHideYoutubeLogo(false); - break; - } - }); + if ("loaded".equals(eventName)) { + AndroidUtilities.runOnUIThread(() -> { + progressBar.setVisibility(View.INVISIBLE); + progressBarBlackBackground.setVisibility(View.INVISIBLE); + pipButton.setEnabled(true); + pipButton.setAlpha(1.0f); + }); + } } } @@ -237,18 +232,23 @@ public class EmbedBottomSheet extends BottomSheet { private static EmbedBottomSheet instance; public static void show(Context context, String title, String description, String originalUrl, final String url, int w, int h) { + show(context, title, description, originalUrl, url, w, h, -1); + } + + public static void show(Context context, String title, String description, String originalUrl, final String url, int w, int h, int seekTime) { if (instance != null) { instance.destroy(); } - new EmbedBottomSheet(context, title, description, originalUrl, url, w, h).show(); + new EmbedBottomSheet(context, title, description, originalUrl, url, w, h, seekTime).show(); } @SuppressLint("SetJavaScriptEnabled") - private EmbedBottomSheet(Context context, String title, String description, String originalUrl, final String url, int w, int h) { + private EmbedBottomSheet(Context context, String title, String description, String originalUrl, final String url, int w, int h, int seekTime) { super(context, false, 0); fullWidth = true; setApplyTopPadding(false); setApplyBottomPadding(false); + seekTimeOverride = seekTime; if (context instanceof Activity) { parentActivity = (Activity) context; @@ -311,15 +311,7 @@ public class EmbedBottomSheet extends BottomSheet { containerLayout.setOnTouchListener((v, event) -> true); setCustomView(containerLayout); - webView = new WebView(context) { - @Override - public boolean onTouchEvent(MotionEvent event) { - if (isYouTube && event.getAction() == MotionEvent.ACTION_DOWN) { - showOrHideYoutubeLogo(true); - } - return super.onTouchEvent(event); - } - }; + webView = new WebView(context); webView.getSettings().setJavaScriptEnabled(true); webView.getSettings().setDomStorageEnabled(true); if (Build.VERSION.SDK_INT >= 17) { @@ -392,16 +384,6 @@ public class EmbedBottomSheet extends BottomSheet { containerLayout.addView(webView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.TOP | Gravity.LEFT, 0, 0, 0, 48 + 36 + (hasDescription ? 22 : 0))); - youtubeLogoImage = new ImageView(context); - youtubeLogoImage.setVisibility(View.GONE); - containerLayout.addView(youtubeLogoImage, LayoutHelper.createFrame(66, 28, Gravity.RIGHT | Gravity.TOP, 0, 8, 8, 0)); - youtubeLogoImage.setOnClickListener(v -> { - if (youtubeLogoImage.getAlpha() == 0) { - return; - } - openInButton.callOnClick(); - }); - videoView = new WebPlayerView(context, true, false, new WebPlayerView.WebPlayerViewDelegate() { @Override public void onInitFailed() { @@ -513,18 +495,18 @@ public class EmbedBottomSheet extends BottomSheet { AnimatorSet animatorSet = new AnimatorSet(); animatorSet.playTogether( - ObjectAnimator.ofFloat(textureImageView, "scaleX", scale), - ObjectAnimator.ofFloat(textureImageView, "scaleY", scale), - ObjectAnimator.ofFloat(textureImageView, "translationX", rect.x), - ObjectAnimator.ofFloat(textureImageView, "translationY", rect.y), - ObjectAnimator.ofFloat(textureView, "scaleX", scale), - ObjectAnimator.ofFloat(textureView, "scaleY", scale), - ObjectAnimator.ofFloat(textureView, "translationX", rect.x), - ObjectAnimator.ofFloat(textureView, "translationY", rect.y), - ObjectAnimator.ofFloat(containerView, "translationY", containerView.getMeasuredHeight() + AndroidUtilities.dp(10)), - ObjectAnimator.ofInt(backDrawable, "alpha", 0), - ObjectAnimator.ofFloat(fullscreenVideoContainer, "alpha", 0), - ObjectAnimator.ofFloat(controlsView, "alpha", 0) + ObjectAnimator.ofFloat(textureImageView, View.SCALE_X, scale), + ObjectAnimator.ofFloat(textureImageView, View.SCALE_Y, scale), + ObjectAnimator.ofFloat(textureImageView, View.TRANSLATION_X, rect.x), + ObjectAnimator.ofFloat(textureImageView, View.TRANSLATION_Y, rect.y), + ObjectAnimator.ofFloat(textureView, View.SCALE_X, scale), + ObjectAnimator.ofFloat(textureView, View.SCALE_Y, scale), + ObjectAnimator.ofFloat(textureView, View.TRANSLATION_X, rect.x), + ObjectAnimator.ofFloat(textureView, View.TRANSLATION_Y, rect.y), + ObjectAnimator.ofFloat(containerView, View.TRANSLATION_Y, containerView.getMeasuredHeight() + AndroidUtilities.dp(10)), + ObjectAnimator.ofInt(backDrawable, AnimationProperties.COLOR_DRAWABLE_ALPHA, 0), + ObjectAnimator.ofFloat(fullscreenVideoContainer, View.ALPHA, 0), + ObjectAnimator.ofFloat(controlsView, View.ALPHA, 0) ); animatorSet.setInterpolator(new DecelerateInterpolator()); animatorSet.setDuration(250); @@ -608,16 +590,16 @@ public class EmbedBottomSheet extends BottomSheet { ImageView textureImageView = videoView.getTextureImageView(); AnimatorSet animatorSet = new AnimatorSet(); animatorSet.playTogether( - ObjectAnimator.ofFloat(textureImageView, "scaleX", 1.0f), - ObjectAnimator.ofFloat(textureImageView, "scaleY", 1.0f), - ObjectAnimator.ofFloat(textureImageView, "translationX", position[0]), - ObjectAnimator.ofFloat(textureImageView, "translationY", position[1]), - ObjectAnimator.ofFloat(textureView, "scaleX", 1.0f), - ObjectAnimator.ofFloat(textureView, "scaleY", 1.0f), - ObjectAnimator.ofFloat(textureView, "translationX", position[0]), - ObjectAnimator.ofFloat(textureView, "translationY", position[1]), - ObjectAnimator.ofFloat(containerView, "translationY", 0), - ObjectAnimator.ofInt(backDrawable, "alpha", 51) + ObjectAnimator.ofFloat(textureImageView, View.SCALE_X, 1.0f), + ObjectAnimator.ofFloat(textureImageView, View.SCALE_Y, 1.0f), + ObjectAnimator.ofFloat(textureImageView, View.TRANSLATION_X, position[0]), + ObjectAnimator.ofFloat(textureImageView, View.TRANSLATION_Y, position[1]), + ObjectAnimator.ofFloat(textureView, View.SCALE_X, 1.0f), + ObjectAnimator.ofFloat(textureView, View.SCALE_Y, 1.0f), + ObjectAnimator.ofFloat(textureView, View.TRANSLATION_X, position[0]), + ObjectAnimator.ofFloat(textureView, View.TRANSLATION_Y, position[1]), + ObjectAnimator.ofFloat(containerView, View.TRANSLATION_Y, 0), + ObjectAnimator.ofInt(backDrawable, AnimationProperties.COLOR_DRAWABLE_ALPHA, 51) ); animatorSet.setInterpolator(new DecelerateInterpolator()); animatorSet.setDuration(250); @@ -765,16 +747,16 @@ public class EmbedBottomSheet extends BottomSheet { ImageView textureImageView = videoView.getTextureImageView(); AnimatorSet animatorSet = new AnimatorSet(); animatorSet.playTogether( - ObjectAnimator.ofFloat(textureImageView, "scaleX", 1.0f), - ObjectAnimator.ofFloat(textureImageView, "scaleY", 1.0f), - ObjectAnimator.ofFloat(textureImageView, "translationX", position[0]), - ObjectAnimator.ofFloat(textureImageView, "translationY", position[1]), - ObjectAnimator.ofFloat(textureView, "scaleX", 1.0f), - ObjectAnimator.ofFloat(textureView, "scaleY", 1.0f), - ObjectAnimator.ofFloat(textureView, "translationX", position[0]), - ObjectAnimator.ofFloat(textureView, "translationY", position[1]), - ObjectAnimator.ofFloat(containerView, "translationY", 0), - ObjectAnimator.ofInt(backDrawable, "alpha", 51) + ObjectAnimator.ofFloat(textureImageView, View.SCALE_X, 1.0f), + ObjectAnimator.ofFloat(textureImageView, View.SCALE_Y, 1.0f), + ObjectAnimator.ofFloat(textureImageView, View.TRANSLATION_X, position[0]), + ObjectAnimator.ofFloat(textureImageView, View.TRANSLATION_Y, position[1]), + ObjectAnimator.ofFloat(textureView, View.SCALE_X, 1.0f), + ObjectAnimator.ofFloat(textureView, View.SCALE_Y, 1.0f), + ObjectAnimator.ofFloat(textureView, View.TRANSLATION_X, position[0]), + ObjectAnimator.ofFloat(textureView, View.TRANSLATION_Y, position[1]), + ObjectAnimator.ofFloat(containerView, View.TRANSLATION_Y, 0), + ObjectAnimator.ofInt(backDrawable, AnimationProperties.COLOR_DRAWABLE_ALPHA, 51) ); animatorSet.setInterpolator(new DecelerateInterpolator()); animatorSet.setDuration(250); @@ -824,7 +806,7 @@ public class EmbedBottomSheet extends BottomSheet { linearLayout.addView(copyTextButton, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.MATCH_PARENT, Gravity.TOP | Gravity.LEFT)); copyTextButton.setOnClickListener(copyClickListener); - openInButton = new TextView(context); + TextView openInButton = new TextView(context); openInButton.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); openInButton.setTextColor(Theme.getColor(Theme.key_dialogTextBlue4)); openInButton.setGravity(Gravity.CENTER); @@ -867,8 +849,6 @@ public class EmbedBottomSheet extends BottomSheet { String currentYoutubeId = videoView.getYoutubeId(); if (currentYoutubeId != null) { progressBarBlackBackground.setVisibility(View.VISIBLE); - youtubeLogoImage.setVisibility(View.VISIBLE); - youtubeLogoImage.setImageResource(R.drawable.ytlogo); isYouTube = true; if (Build.VERSION.SDK_INT >= 17) { webView.addJavascriptInterface(new YoutubeProxy(), "YoutubeProxy"); @@ -877,13 +857,16 @@ public class EmbedBottomSheet extends BottomSheet { if (openUrl != null) { try { Uri uri = Uri.parse(openUrl); - String t = uri.getQueryParameter("t"); + String t = seekTimeOverride > 0 ? "" + seekTimeOverride : null; if (t == null) { - t = uri.getQueryParameter("time_continue"); + t = uri.getQueryParameter("t"); + if (t == null) { + t = uri.getQueryParameter("time_continue"); + } } if (t != null) { if (t.contains("m")) { - String arg[] = t.split("m"); + String[] arg = t.split("m"); seekToTime = Utilities.parseInt(arg[0]) * 60 + Utilities.parseInt(arg[1]); } else { seekToTime = Utilities.parseInt(t); @@ -936,6 +919,22 @@ public class EmbedBottomSheet extends BottomSheet { } }; + String currentYoutubeId = videoView.getYouTubeVideoId(embedUrl); + if (currentYoutubeId != null) { + progressBar.setVisibility(View.VISIBLE); + webView.setVisibility(View.VISIBLE); + imageButtonsContainer.setVisibility(View.VISIBLE); + progressBarBlackBackground.setVisibility(View.VISIBLE); + copyTextButton.setVisibility(View.INVISIBLE); + webView.setKeepScreenOn(true); + videoView.setVisibility(View.INVISIBLE); + videoView.getControlsView().setVisibility(View.INVISIBLE); + videoView.getTextureView().setVisibility(View.INVISIBLE); + if (videoView.getTextureImageView() != null) { + videoView.getTextureImageView().setVisibility(View.INVISIBLE); + } + } + if (orientationEventListener.canDetectOrientation()) { orientationEventListener.enable(); } else { @@ -957,17 +956,6 @@ public class EmbedBottomSheet extends BottomSheet { } } - private void showOrHideYoutubeLogo(final boolean show) { - youtubeLogoImage.animate().alpha(show ? 1.0f : 0.0f).setDuration(200).setStartDelay(show ? 0 : 2900).setInterpolator(new DecelerateInterpolator()).setListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator animation) { - if (show) { - showOrHideYoutubeLogo(false); - } - } - }).start(); - } - public boolean checkInlinePermissions() { if (parentActivity == null) { return false; @@ -977,13 +965,9 @@ public class EmbedBottomSheet extends BottomSheet { } else { new AlertDialog.Builder(parentActivity).setTitle(LocaleController.getString("AppName", R.string.AppName)) .setMessage(LocaleController.getString("PermissionDrawAboveOtherApps", R.string.PermissionDrawAboveOtherApps)) - .setPositiveButton(LocaleController.getString("PermissionOpenSettings", R.string.PermissionOpenSettings), new DialogInterface.OnClickListener() { - @TargetApi(Build.VERSION_CODES.M) - @Override - public void onClick(DialogInterface dialog, int which) { - if (parentActivity != null) { - parentActivity.startActivity(new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:" + parentActivity.getPackageName()))); - } + .setPositiveButton(LocaleController.getString("PermissionOpenSettings", R.string.PermissionOpenSettings), (dialog, which) -> { + if (parentActivity != null) { + parentActivity.startActivity(new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:" + parentActivity.getPackageName()))); } }).show(); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/EmojiView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/EmojiView.java index 174a6465f..66c8d1149 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/EmojiView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/EmojiView.java @@ -228,7 +228,7 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific } - default void onStickerSelected(TLRPC.Document sticker, Object parent) { + default void onStickerSelected(View view, TLRPC.Document sticker, Object parent) { } @@ -240,7 +240,7 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific } - default void onGifSelected(Object gif, Object parent) { + default void onGifSelected(View view, Object gif, Object parent) { } @@ -287,7 +287,7 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific private ContentPreviewViewer.ContentPreviewViewerDelegate contentPreviewViewerDelegate = new ContentPreviewViewer.ContentPreviewViewerDelegate() { @Override public void sendSticker(TLRPC.Document sticker, Object parent) { - delegate.onStickerSelected(sticker, parent); + delegate.onStickerSelected(null, sticker, parent); } @Override @@ -306,9 +306,9 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific @Override public void sendGif(Object gif) { if (gifGridView.getAdapter() == gifAdapter) { - delegate.onGifSelected(gif, "gif"); + delegate.onGifSelected(null, gif, "gif"); } else if (gifGridView.getAdapter() == gifSearchAdapter) { - delegate.onGifSelected(gif, gifSearchAdapter.bot); + delegate.onGifSelected(null, gif, gifSearchAdapter.bot); } } @@ -1264,12 +1264,12 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific if (position < 0 || position >= recentGifs.size()) { return; } - delegate.onGifSelected(recentGifs.get(position), "gif"); + delegate.onGifSelected(view, recentGifs.get(position), "gif"); } else if (gifGridView.getAdapter() == gifSearchAdapter) { if (position < 0 || position >= gifSearchAdapter.results.size()) { return; } - delegate.onGifSelected(gifSearchAdapter.results.get(position), gifSearchAdapter.bot); + delegate.onGifSelected(view, gifSearchAdapter.results.get(position), gifSearchAdapter.bot); recentGifs = MediaDataController.getInstance(currentAccount).getRecentGifs(); if (gifAdapter != null) { gifAdapter.notifyDataSetChanged(); @@ -1377,7 +1377,7 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific return; } cell.disable(); - delegate.onStickerSelected(cell.getSticker(), cell.getParentObject()); + delegate.onStickerSelected(cell, cell.getSticker(), cell.getParentObject()); }; stickersGridView.setOnItemClickListener(stickersOnItemClickListener); stickersGridView.setGlowColor(Theme.getColor(Theme.key_chat_emojiPanelBackground)); @@ -2782,7 +2782,7 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific super.requestLayout(); } - public void updateUIColors() { + public void updateColors() { if (AndroidUtilities.isInMultiwindow || forseMultiwindowLayout) { Drawable background = getBackground(); if (background != null) { @@ -2839,6 +2839,8 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific } if (backspaceButton != null) { backspaceButton.setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_chat_emojiPanelBackspace), PorterDuff.Mode.MULTIPLY)); + Theme.setSelectorDrawableColor(backspaceButton.getBackground(), Theme.getColor(Theme.key_chat_emojiPanelBackground), false); + Theme.setSelectorDrawableColor(backspaceButton.getBackground(), Theme.getColor(Theme.key_chat_emojiPanelBackground), true); } if (stickerSettingsButton != null) { stickerSettingsButton.setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_chat_emojiPanelBackspace), PorterDuff.Mode.MULTIPLY)); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/HintView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/HintView.java index 53c486885..bef795770 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/HintView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/HintView.java @@ -7,6 +7,7 @@ import android.animation.ObjectAnimator; import android.content.Context; import android.graphics.PorterDuff; import android.graphics.PorterDuffColorFilter; +import android.os.Build; import android.util.TypedValue; import android.view.Gravity; import android.view.View; @@ -19,6 +20,7 @@ import org.telegram.messenger.ImageReceiver; import org.telegram.messenger.LocaleController; import org.telegram.messenger.MessageObject; import org.telegram.messenger.R; +import org.telegram.ui.ActionBar.ActionBar; import org.telegram.ui.ActionBar.Theme; import org.telegram.ui.Cells.ChatMessageCell; @@ -30,6 +32,7 @@ public class HintView extends FrameLayout { private ImageView imageView; private ImageView arrowImageView; private ChatMessageCell messageCell; + private View currentView; private AnimatorSet animatorSet; private Runnable hideRunnable; private int currentType; @@ -53,7 +56,11 @@ public class HintView extends FrameLayout { textView.setMaxWidth(AndroidUtilities.dp(250)); textView.setGravity(Gravity.LEFT | Gravity.TOP); textView.setBackgroundDrawable(Theme.createRoundRectDrawable(AndroidUtilities.dp(3), Theme.getColor(Theme.key_chat_gifSaveHintBackground))); - textView.setPadding(AndroidUtilities.dp(currentType == 0 ? 54 : 5), AndroidUtilities.dp(6), AndroidUtilities.dp(5), AndroidUtilities.dp(7)); + if (currentType == 2) { + textView.setPadding(AndroidUtilities.dp(7), AndroidUtilities.dp(6), AndroidUtilities.dp(7), AndroidUtilities.dp(7)); + } else { + textView.setPadding(AndroidUtilities.dp(currentType == 0 ? 54 : 5), AndroidUtilities.dp(6), AndroidUtilities.dp(5), AndroidUtilities.dp(7)); + } addView(textView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.LEFT | Gravity.TOP, 0, topArrow ? 6 : 0, 0, topArrow ? 0 : 6)); if (type == 0) { @@ -186,6 +193,96 @@ public class HintView extends FrameLayout { return true; } + public boolean showForView(View view, boolean animated) { + if (currentView == view || getTag() != null) { + return false; + } + if (hideRunnable != null) { + AndroidUtilities.cancelRunOnUIThread(hideRunnable); + hideRunnable = null; + } + measure(MeasureSpec.makeMeasureSpec(1000, MeasureSpec.AT_MOST), MeasureSpec.makeMeasureSpec(1000, MeasureSpec.AT_MOST)); + + int[] position = new int[2]; + view.getLocationInWindow(position); + + int centerX = position[0] + view.getMeasuredWidth() / 2; + int top = position[1] - AndroidUtilities.dp(4); + + View parentView = (View) getParent(); + parentView.getLocationInWindow(position); + centerX -= position[0]; + top -= position[1]; + + if (Build.VERSION.SDK_INT >= 21) { + top -= AndroidUtilities.statusBarHeight; + } + + + int parentWidth = parentView.getMeasuredWidth(); + if (isTopArrow) { + setTranslationY(AndroidUtilities.dp(44)); + } else { + setTranslationY(top - getMeasuredHeight() - ActionBar.getCurrentActionBarHeight()); + } + int iconX = centerX; + int left = AndroidUtilities.dp(19); + if (iconX > parentView.getMeasuredWidth() / 2) { + int offset = parentWidth - getMeasuredWidth() - AndroidUtilities.dp(28); + setTranslationX(offset); + left += offset; + } else { + setTranslationX(0); + } + float arrowX = centerX - left - arrowImageView.getMeasuredWidth() / 2; + arrowImageView.setTranslationX(arrowX); + if (iconX > parentView.getMeasuredWidth() / 2) { + if (arrowX < AndroidUtilities.dp(10)) { + float diff = arrowX - AndroidUtilities.dp(10); + setTranslationX(getTranslationX() + diff); + arrowImageView.setTranslationX(arrowX - diff); + } + } else { + if (arrowX > getMeasuredWidth() - AndroidUtilities.dp(14 + 10)) { + float diff = arrowX - getMeasuredWidth() + AndroidUtilities.dp(14 + 10); + setTranslationX(diff); + arrowImageView.setTranslationX(arrowX - diff); + } else if (arrowX < AndroidUtilities.dp(10)) { + float diff = arrowX - AndroidUtilities.dp(10); + setTranslationX(getTranslationX() + diff); + arrowImageView.setTranslationX(arrowX - diff); + } + } + + currentView = view; + if (animatorSet != null) { + animatorSet.cancel(); + animatorSet = null; + } + + setTag(1); + setVisibility(VISIBLE); + if (animated) { + animatorSet = new AnimatorSet(); + animatorSet.playTogether( + ObjectAnimator.ofFloat(this, "alpha", 0.0f, 1.0f) + ); + animatorSet.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + animatorSet = null; + AndroidUtilities.runOnUIThread(hideRunnable = () -> hide(), 2000); + } + }); + animatorSet.setDuration(300); + animatorSet.start(); + } else { + setAlpha(1.0f); + } + + return true; + } + public void hide() { if (getTag() == null) { return; @@ -207,6 +304,7 @@ public class HintView extends FrameLayout { @Override public void onAnimationEnd(Animator animation) { setVisibility(View.INVISIBLE); + currentView = null; messageCell = null; animatorSet = null; } @@ -215,6 +313,10 @@ public class HintView extends FrameLayout { animatorSet.start(); } + public void setText(CharSequence text) { + textView.setText(text); + } + public ChatMessageCell getMessageCell() { return messageCell; } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/LetterDrawable.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/LetterDrawable.java index 7af989bc3..b3bf1c24b 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/LetterDrawable.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/LetterDrawable.java @@ -96,7 +96,8 @@ public class LetterDrawable extends Drawable { @Override public void setAlpha(int alpha) { - + namePaint.setAlpha(alpha); + paint.setAlpha(alpha); } @Override diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Paint/PhotoFace.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Paint/PhotoFace.java index 9a3cd1b52..b35777a2c 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Paint/PhotoFace.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Paint/PhotoFace.java @@ -60,6 +60,11 @@ public class PhotoFace { } if (leftEyePoint != null && rightEyePoint != null) { + if (leftEyePoint.x < rightEyePoint.x) { + Point temp = leftEyePoint; + leftEyePoint = rightEyePoint; + rightEyePoint = temp; + } eyesCenterPoint = new Point(0.5f * leftEyePoint.x + 0.5f * rightEyePoint.x, 0.5f * leftEyePoint.y + 0.5f * rightEyePoint.y); eyesDistance = (float)Math.hypot(rightEyePoint.x - leftEyePoint.x, rightEyePoint.y - leftEyePoint.y); @@ -74,6 +79,11 @@ public class PhotoFace { } if (leftMouthPoint != null && rightMouthPoint != null) { + if (leftMouthPoint.x < rightMouthPoint.x) { + Point temp = leftMouthPoint; + leftMouthPoint = rightMouthPoint; + rightMouthPoint = temp; + } mouthPoint = new Point(0.5f * leftMouthPoint.x + 0.5f * rightMouthPoint.x, 0.5f * leftMouthPoint.y + 0.5f * rightMouthPoint.y); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/PasscodeView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/PasscodeView.java index bc9e1572f..f939b7fa9 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/PasscodeView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/PasscodeView.java @@ -977,7 +977,11 @@ public class PasscodeView extends FrameLayout { builder.setOnDismissListener(dialog -> { if (cancellationSignal != null) { selfCancelled = true; - cancellationSignal.cancel(); + try { + cancellationSignal.cancel(); + } catch (Exception e) { + FileLog.e(e); + } cancellationSignal = null; } }); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/PhotoViewerCaptionEnterView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/PhotoViewerCaptionEnterView.java index 7810d6e8c..a33723159 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/PhotoViewerCaptionEnterView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/PhotoViewerCaptionEnterView.java @@ -42,7 +42,6 @@ import org.telegram.messenger.NotificationCenter; import org.telegram.messenger.FileLog; import org.telegram.messenger.R; import org.telegram.messenger.UserConfig; -import org.telegram.tgnet.TLRPC; import org.telegram.ui.ActionBar.Theme; import java.lang.reflect.Field; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/PickerBottomLayout.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/PickerBottomLayout.java index 33e91fa63..88dc80926 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/PickerBottomLayout.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/PickerBottomLayout.java @@ -29,23 +29,20 @@ public class PickerBottomLayout extends FrameLayout { public TextView doneButtonTextView; public TextView doneButtonBadgeTextView; - private boolean isDarkTheme; - public PickerBottomLayout(Context context) { this(context, true); } public PickerBottomLayout(Context context, boolean darkTheme) { super(context); - isDarkTheme = darkTheme; - setBackgroundColor(isDarkTheme ? 0xff1a1a1a : Theme.getColor(Theme.key_windowBackgroundWhite)); + setBackgroundColor(Theme.getColor(darkTheme ? Theme.key_dialogBackground : Theme.key_windowBackgroundWhite)); cancelButton = new TextView(context); cancelButton.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); - cancelButton.setTextColor(isDarkTheme ? 0xffffffff : Theme.getColor(Theme.key_picker_enabledButton)); + cancelButton.setTextColor(Theme.getColor(Theme.key_picker_enabledButton)); cancelButton.setGravity(Gravity.CENTER); - cancelButton.setBackgroundDrawable(Theme.createSelectorDrawable(isDarkTheme ? Theme.ACTION_BAR_PICKER_SELECTOR_COLOR : Theme.ACTION_BAR_AUDIO_SELECTOR_COLOR, 0)); + cancelButton.setBackgroundDrawable(Theme.createSelectorDrawable(0x0f000000, 0)); cancelButton.setPadding(AndroidUtilities.dp(29), 0, AndroidUtilities.dp(29), 0); cancelButton.setText(LocaleController.getString("Cancel", R.string.Cancel).toUpperCase()); cancelButton.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); @@ -53,21 +50,16 @@ public class PickerBottomLayout extends FrameLayout { doneButton = new LinearLayout(context); doneButton.setOrientation(LinearLayout.HORIZONTAL); - doneButton.setBackgroundDrawable(Theme.createSelectorDrawable(isDarkTheme ? Theme.ACTION_BAR_PICKER_SELECTOR_COLOR : Theme.ACTION_BAR_AUDIO_SELECTOR_COLOR, 0)); + doneButton.setBackgroundDrawable(Theme.createSelectorDrawable(0x0f000000, 0)); doneButton.setPadding(AndroidUtilities.dp(29), 0, AndroidUtilities.dp(29), 0); addView(doneButton, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.MATCH_PARENT, Gravity.TOP | Gravity.RIGHT)); doneButtonBadgeTextView = new TextView(context); doneButtonBadgeTextView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); doneButtonBadgeTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 13); - doneButtonBadgeTextView.setTextColor(isDarkTheme ? 0xffffffff : Theme.getColor(Theme.key_picker_badgeText)); + doneButtonBadgeTextView.setTextColor(Theme.getColor(Theme.key_picker_badgeText)); doneButtonBadgeTextView.setGravity(Gravity.CENTER); - Drawable drawable; - if (isDarkTheme) { - drawable = Theme.createRoundRectDrawable(AndroidUtilities.dp(11), 0xff66bffa); - } else { - drawable = Theme.createRoundRectDrawable(AndroidUtilities.dp(11), Theme.getColor(Theme.key_picker_badge)); - } + Drawable drawable = Theme.createRoundRectDrawable(AndroidUtilities.dp(11), Theme.getColor(Theme.key_picker_badge)); doneButtonBadgeTextView.setBackgroundDrawable(drawable); doneButtonBadgeTextView.setMinWidth(AndroidUtilities.dp(23)); doneButtonBadgeTextView.setPadding(AndroidUtilities.dp(8), 0, AndroidUtilities.dp(8), AndroidUtilities.dp(1)); @@ -75,7 +67,7 @@ public class PickerBottomLayout extends FrameLayout { doneButtonTextView = new TextView(context); doneButtonTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); - doneButtonTextView.setTextColor(isDarkTheme ? 0xffffffff : Theme.getColor(Theme.key_picker_enabledButton)); + doneButtonTextView.setTextColor(Theme.getColor(Theme.key_picker_enabledButton)); doneButtonTextView.setGravity(Gravity.CENTER); doneButtonTextView.setCompoundDrawablePadding(AndroidUtilities.dp(8)); doneButtonTextView.setText(LocaleController.getString("Send", R.string.Send).toUpperCase()); @@ -88,19 +80,19 @@ public class PickerBottomLayout extends FrameLayout { doneButtonBadgeTextView.setVisibility(View.GONE); if (disable) { - doneButtonTextView.setTag(isDarkTheme ? null : Theme.key_picker_disabledButton); - doneButtonTextView.setTextColor(isDarkTheme ? 0xff999999 : Theme.getColor(Theme.key_picker_disabledButton)); + doneButtonTextView.setTag(Theme.key_picker_disabledButton); + doneButtonTextView.setTextColor(Theme.getColor(Theme.key_picker_disabledButton)); doneButton.setEnabled(false); } else { - doneButtonTextView.setTag(isDarkTheme ? null : Theme.key_picker_enabledButton); - doneButtonTextView.setTextColor(isDarkTheme ? 0xffffffff : Theme.getColor(Theme.key_picker_enabledButton)); + doneButtonTextView.setTag(Theme.key_picker_enabledButton); + doneButtonTextView.setTextColor(Theme.getColor(Theme.key_picker_enabledButton)); } } else { doneButtonBadgeTextView.setVisibility(View.VISIBLE); doneButtonBadgeTextView.setText(String.format("%d", count)); - doneButtonTextView.setTag(isDarkTheme ? null : Theme.key_picker_enabledButton); - doneButtonTextView.setTextColor(isDarkTheme ? 0xffffffff : Theme.getColor(Theme.key_picker_enabledButton)); + doneButtonTextView.setTag(Theme.key_picker_enabledButton); + doneButtonTextView.setTextColor(Theme.getColor(Theme.key_picker_enabledButton)); if (disable) { doneButton.setEnabled(true); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/RLottieDrawable.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/RLottieDrawable.java index 33424b5e2..42e38a868 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/RLottieDrawable.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/RLottieDrawable.java @@ -18,6 +18,7 @@ import android.graphics.drawable.BitmapDrawable; import android.os.Handler; import android.os.Looper; import android.os.SystemClock; +import android.view.HapticFeedbackConstants; import android.view.View; import org.telegram.messenger.ApplicationLoader; @@ -36,7 +37,7 @@ import java.util.concurrent.TimeUnit; public class RLottieDrawable extends BitmapDrawable implements Animatable { - private static native long create(String src, int[] params, boolean precache); + private static native long create(String src, int[] params, boolean precache, int[] colorReplacement); private static native long createWithJson(String json, String name, int[] params); private static native void destroy(long ptr); private static native void setLayerColor(long ptr, String layer, int color); @@ -49,10 +50,12 @@ public class RLottieDrawable extends BitmapDrawable implements Animatable { private int timeBetweenFrames; private HashMap newColorUpdates = new HashMap<>(); private volatile HashMap pendingColorUpdates = new HashMap<>(); + private HashMap vibrationPattern; private View currentParentView; - private boolean autoRepeat = true; + private int autoRepeat = 1; + private int autoRepeatPlayCount; private long lastFrameTime; private volatile boolean nextFrameIsLast; @@ -205,11 +208,15 @@ public class RLottieDrawable extends BitmapDrawable implements Animatable { return; } - if (!pendingColorUpdates.isEmpty()) { - for (HashMap.Entry entry : pendingColorUpdates.entrySet()) { - setLayerColor(nativePtr, entry.getKey(), entry.getValue()); + try { + if (!pendingColorUpdates.isEmpty()) { + for (HashMap.Entry entry : pendingColorUpdates.entrySet()) { + setLayerColor(nativePtr, entry.getKey(), entry.getValue()); + } + pendingColorUpdates.clear(); } - pendingColorUpdates.clear(); + } catch (Exception ignore) { + } getFrame(nativePtr, currentFrame, backgroundBitmap, width, height, backgroundBitmap.getRowBytes()); if (metaData[2] != 0) { @@ -219,11 +226,20 @@ public class RLottieDrawable extends BitmapDrawable implements Animatable { nextRenderingBitmap = backgroundBitmap; int framesPerUpdates = shouldLimitFps ? 2 : 1; if (currentFrame + framesPerUpdates < metaData[0]) { - currentFrame += framesPerUpdates; - nextFrameIsLast = false; - } else if (autoRepeat) { + if (autoRepeat == 3) { + nextFrameIsLast = true; + autoRepeatPlayCount++; + } else { + currentFrame += framesPerUpdates; + nextFrameIsLast = false; + } + } else if (autoRepeat == 1) { currentFrame = 0; nextFrameIsLast = false; + } else if (autoRepeat == 2) { + currentFrame = 0; + nextFrameIsLast = true; + autoRepeatPlayCount++; } else { nextFrameIsLast = true; } @@ -234,12 +250,16 @@ public class RLottieDrawable extends BitmapDrawable implements Animatable { }; public RLottieDrawable(File file, int w, int h, boolean precache, boolean limitFps) { + this(file, w, h, precache, limitFps, null); + } + + public RLottieDrawable(File file, int w, int h, boolean precache, boolean limitFps, int[] colorReplacement) { width = w; height = h; shouldLimitFps = limitFps; getPaint().setFlags(Paint.FILTER_BITMAP_FLAG); - nativePtr = create(file.getAbsolutePath(), metaData, precache); + nativePtr = create(file.getAbsolutePath(), metaData, precache, colorReplacement); if (precache && lottieCacheGenerateQueue == null) { lottieCacheGenerateQueue = new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>()); } @@ -278,7 +298,7 @@ public class RLottieDrawable extends BitmapDrawable implements Animatable { getPaint().setFlags(Paint.FILTER_BITMAP_FLAG); nativePtr = createWithJson(jsonString, name, metaData); timeBetweenFrames = Math.max(16, (int) (1000.0f / metaData[1])); - autoRepeat = false; + autoRepeat = 0; if (startDecode) { setAllowDecodeSingleFrame(true); } @@ -372,7 +392,10 @@ public class RLottieDrawable extends BitmapDrawable implements Animatable { } } - public void setAutoRepeat(boolean value) { + public void setAutoRepeat(int value) { + if (autoRepeat == 2 && value == 3 && currentFrame != 0) { + return; + } autoRepeat = value; } @@ -392,7 +415,7 @@ public class RLottieDrawable extends BitmapDrawable implements Animatable { @Override public void start() { - if (isRunning) { + if (isRunning || autoRepeat >= 2 && autoRepeatPlayCount != 0) { return; } isRunning = true; @@ -400,6 +423,20 @@ public class RLottieDrawable extends BitmapDrawable implements Animatable { invalidateInternal(); } + public boolean restart() { + if (autoRepeat < 2 || autoRepeatPlayCount == 0) { + return false; + } + autoRepeatPlayCount = 0; + autoRepeat = 2; + start(); + return true; + } + + public void setVibrationPattern(HashMap pattern) { + vibrationPattern = pattern; + } + public void beginApplyLayerColors() { applyingLayerColors = true; } @@ -523,6 +560,13 @@ public class RLottieDrawable extends BitmapDrawable implements Animatable { if (renderingBitmap == null && nextRenderingBitmap == null) { scheduleNextGetFrame(); } else if (nextRenderingBitmap != null && (renderingBitmap == null || timeDiff >= timeBetweenFrames - 6) && isCurrentParentViewMaster()) { + if (vibrationPattern != null && currentParentView != null) { + Integer force = vibrationPattern.get(currentFrame - 1); + if (force != null) { + currentParentView.performHapticFeedback(force == 1 ? HapticFeedbackConstants.LONG_PRESS : HapticFeedbackConstants.KEYBOARD_TAP, HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING); + } + } + backgroundBitmap = renderingBitmap; renderingBitmap = nextRenderingBitmap; if (nextFrameIsLast) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/ScrollSlidingTextTabStrip.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/ScrollSlidingTextTabStrip.java index 8e8b556eb..3a6183bae 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ScrollSlidingTextTabStrip.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ScrollSlidingTextTabStrip.java @@ -58,6 +58,11 @@ public class ScrollSlidingTextTabStrip extends HorizontalScrollView { private GradientDrawable selectorDrawable; + private String tabLineColorKey = Theme.key_actionBarTabLine; + private String activeTextColorKey = Theme.key_actionBarTabActiveText; + private String unactiveTextColorKey = Theme.key_actionBarTabUnactiveText; + private String selectorColorKey = Theme.key_actionBarTabSelector; + private CubicBezierInterpolator interpolator = CubicBezierInterpolator.EASE_OUT_QUINT; private SparseIntArray positionToId = new SparseIntArray(5); @@ -102,7 +107,7 @@ public class ScrollSlidingTextTabStrip extends HorizontalScrollView { selectorDrawable = new GradientDrawable(GradientDrawable.Orientation.LEFT_RIGHT, null); float rad = AndroidUtilities.dpf2(3); selectorDrawable.setCornerRadii(new float[]{rad, rad, rad, rad, 0, 0, 0, 0}); - selectorDrawable.setColor(Theme.getColor(Theme.key_actionBarTabLine)); + selectorDrawable.setColor(Theme.getColor(tabLineColorKey)); setFillViewport(true); setWillNotDraw(false); @@ -123,8 +128,8 @@ public class ScrollSlidingTextTabStrip extends HorizontalScrollView { } private void setAnimationProgressInernal(TextView newTab, TextView prevTab, float value) { - int newColor = Theme.getColor(Theme.key_actionBarTabActiveText); - int prevColor = Theme.getColor(Theme.key_actionBarTabUnactiveText); + int newColor = Theme.getColor(activeTextColorKey); + int prevColor = Theme.getColor(unactiveTextColorKey); int r1 = Color.red(newColor); int g1 = Color.green(newColor); @@ -207,7 +212,7 @@ public class ScrollSlidingTextTabStrip extends HorizontalScrollView { TextView tab = new TextView(getContext()); tab.setGravity(Gravity.CENTER); tab.setText(text); - tab.setBackgroundDrawable(Theme.createSelectorDrawable(Theme.getColor(Theme.key_actionBarTabSelector), 3)); + tab.setBackgroundDrawable(Theme.createSelectorDrawable(Theme.getColor(selectorColorKey), 3)); tab.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); tab.setSingleLine(true); tab.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); @@ -254,11 +259,19 @@ public class ScrollSlidingTextTabStrip extends HorizontalScrollView { int count = tabsContainer.getChildCount(); for (int a = 0; a < count; a++) { TextView tab = (TextView) tabsContainer.getChildAt(a); - tab.setTag(currentPosition == a ? Theme.key_actionBarTabActiveText : Theme.key_actionBarTabUnactiveText); - tab.setTextColor(Theme.getColor(currentPosition == a ? Theme.key_actionBarTabActiveText : Theme.key_actionBarTabUnactiveText)); + tab.setTag(currentPosition == a ? activeTextColorKey : unactiveTextColorKey); + tab.setTextColor(Theme.getColor(currentPosition == a ? activeTextColorKey : unactiveTextColorKey)); } } + public void setColors(String line, String active, String unactive, String selector) { + tabLineColorKey = line; + activeTextColorKey = active; + unactiveTextColorKey = unactive; + selectorColorKey = selector; + selectorDrawable.setColor(Theme.getColor(tabLineColorKey)); + } + public int getCurrentTabId() { return selectedTabId; } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/SeekBar.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/SeekBar.java index 85ccde770..8cc168cec 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/SeekBar.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/SeekBar.java @@ -20,11 +20,15 @@ public class SeekBar { public interface SeekBarDelegate { void onSeekBarDrag(float progress); + default void onSeekBarContinuousDrag(float progress) { + + } } private static Paint paint; private static int thumbWidth; private int thumbX = 0; + private int draggingThumbX = 0; private int thumbDX = 0; private boolean pressed = false; private int width; @@ -56,11 +60,13 @@ public class SeekBar { int additionWidth = (height - thumbWidth) / 2; if (thumbX - additionWidth <= x && x <= thumbX + thumbWidth + additionWidth && y >= 0 && y <= height) { pressed = true; + draggingThumbX = thumbX; thumbDX = (int) (x - thumbX); return true; } } else if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) { if (pressed) { + thumbX = draggingThumbX; if (action == MotionEvent.ACTION_UP && delegate != null) { delegate.onSeekBarDrag((float) thumbX / (float) (width - thumbWidth)); } @@ -69,11 +75,14 @@ public class SeekBar { } } else if (action == MotionEvent.ACTION_MOVE) { if (pressed) { - thumbX = (int) (x - thumbDX); - if (thumbX < 0) { - thumbX = 0; - } else if (thumbX > width - thumbWidth) { - thumbX = width - thumbWidth; + draggingThumbX = (int) (x - thumbDX); + if (draggingThumbX < 0) { + draggingThumbX = 0; + } else if (draggingThumbX > width - thumbWidth) { + draggingThumbX = width - thumbWidth; + } + if (delegate != null) { + delegate.onSeekBarContinuousDrag((float) draggingThumbX / (float) (width - thumbWidth)); } return true; } @@ -106,6 +115,10 @@ public class SeekBar { return (float) thumbX / (float) (width - thumbWidth); } + public int getThumbX() { + return (pressed ? draggingThumbX : thumbX) + thumbWidth / 2; + } + public boolean isDragging() { return pressed; } @@ -119,6 +132,10 @@ public class SeekBar { height = h; } + public int getWidth() { + return width - thumbWidth; + } + public void setLineHeight(int value) { lineHeight = value; } @@ -136,6 +153,6 @@ public class SeekBar { paint.setColor(progressColor); canvas.drawRoundRect(rect, thumbWidth / 2, thumbWidth / 2, paint); paint.setColor(circleColor); - canvas.drawCircle(thumbX + thumbWidth / 2, height / 2, AndroidUtilities.dp(pressed ? 8 : 6), paint); + canvas.drawCircle((pressed ? draggingThumbX : thumbX) + thumbWidth / 2, height / 2, AndroidUtilities.dp(pressed ? 8 : 6), paint); } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/ShareAlert.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/ShareAlert.java index ad1841dd3..44e627e23 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ShareAlert.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ShareAlert.java @@ -571,10 +571,10 @@ public class ShareAlert extends BottomSheet implements NotificationCenter.Notifi TLRPC.Dialog existingDialog = listAdapter.dialogsMap.get(dialog.id); if (existingDialog == null) { listAdapter.dialogsMap.put(dialog.id, dialog); - listAdapter.dialogs.add(1, dialog); + listAdapter.dialogs.add(listAdapter.dialogs.isEmpty() ? 0 : 1, dialog); } else if (existingDialog.id != selfUserId) { listAdapter.dialogs.remove(existingDialog); - listAdapter.dialogs.add(1, existingDialog); + listAdapter.dialogs.add(listAdapter.dialogs.isEmpty() ? 0 : 1, existingDialog); } searchView.searchEditText.setText(""); gridView.setAdapter(listAdapter); @@ -660,6 +660,13 @@ public class ShareAlert extends BottomSheet implements NotificationCenter.Notifi writeButtonContainer.setContentDescription(LocaleController.getString("Send", R.string.Send)); containerView.addView(writeButtonContainer, LayoutHelper.createFrame(60, 60, Gravity.RIGHT | Gravity.BOTTOM, 0, 0, 6, 10)); writeButtonContainer.setOnClickListener(v -> { + for (int a = 0; a < selectedDialogs.size(); a++) { + long key = selectedDialogs.keyAt(a); + if (AlertsCreator.checkSlowMode(getContext(), currentAccount, key, frameLayout2.getTag() != null && commentTextView.length() > 0)) { + return; + } + } + if (sendingMessageObjects != null) { for (int a = 0; a < selectedDialogs.size(); a++) { long key = selectedDialogs.keyAt(a); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/ShutterButton.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/ShutterButton.java index eaf3ddb74..581a2ff74 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ShutterButton.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ShutterButton.java @@ -24,6 +24,8 @@ import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.LocaleController; import org.telegram.messenger.R; +import androidx.annotation.Keep; + public class ShutterButton extends View { public enum State { @@ -60,6 +62,7 @@ public class ShutterButton extends View { boolean shutterLongPressed(); void shutterReleased(); void shutterCancel(); + boolean onTranslationChanged(float x, float y); } public ShutterButton(Context context) { @@ -86,12 +89,12 @@ public class ShutterButton extends View { AnimatorSet animatorSet = new AnimatorSet(); if (value) { animatorSet.playTogether( - ObjectAnimator.ofFloat(this, "scaleX", 1.06f), - ObjectAnimator.ofFloat(this, "scaleY", 1.06f)); + ObjectAnimator.ofFloat(this, View.SCALE_X, 1.06f), + ObjectAnimator.ofFloat(this, View.SCALE_Y, 1.06f)); } else { animatorSet.playTogether( - ObjectAnimator.ofFloat(this, "scaleX", 1.0f), - ObjectAnimator.ofFloat(this, "scaleY", 1.0f)); + ObjectAnimator.ofFloat(this, View.SCALE_X, 1.0f), + ObjectAnimator.ofFloat(this, View.SCALE_Y, 1.0f)); animatorSet.setStartDelay(40); } animatorSet.setDuration(120); @@ -99,6 +102,7 @@ public class ShutterButton extends View { animatorSet.start(); } + @Keep @Override public void setScaleX(float scaleX) { super.setScaleX(scaleX); @@ -151,7 +155,7 @@ public class ShutterButton extends View { @Override public boolean onTouchEvent(MotionEvent motionEvent) { float x = motionEvent.getX(); - float y = motionEvent.getX(); + float y = motionEvent.getY(); switch (motionEvent.getAction()) { case MotionEvent.ACTION_DOWN: AndroidUtilities.runOnUIThread(longPressed, LONG_PRESS_TIME); @@ -162,14 +166,17 @@ public class ShutterButton extends View { case MotionEvent.ACTION_UP: setHighlighted(false); AndroidUtilities.cancelRunOnUIThread(longPressed); - if (processRelease && x >= 0 && y >= 0 && x <= getMeasuredWidth() && y <= getMeasuredHeight()) { + if (processRelease) { delegate.shutterReleased(); } break; case MotionEvent.ACTION_MOVE: - if (x < 0 || y < 0 || x > getMeasuredWidth() || y > getMeasuredHeight()) { + float dx = x >= 0 && x <= getMeasuredWidth() ? 0 : x; + float dy = y >= 0 && y <= getMeasuredHeight() ? 0 : y; + if (delegate.onTranslationChanged(dx, dy)) { AndroidUtilities.cancelRunOnUIThread(longPressed); if (state == State.RECORDING) { + processRelease = false; setHighlighted(false); delegate.shutterCancel(); setState(State.DEFAULT, true); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/SizeNotifierFrameLayout.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/SizeNotifierFrameLayout.java index a307d629e..c8992dfde 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/SizeNotifierFrameLayout.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/SizeNotifierFrameLayout.java @@ -107,8 +107,11 @@ public class SizeNotifierFrameLayout extends FrameLayout { public int getKeyboardHeight() { View rootView = getRootView(); getWindowVisibleDisplayFrame(rect); + if (rect.bottom == 0 && rect.top == 0) { + return 0; + } int usableViewHeight = rootView.getHeight() - (rect.top != 0 ? AndroidUtilities.statusBarHeight : 0) - AndroidUtilities.getViewInset(rootView); - return usableViewHeight - (rect.bottom - rect.top); + return Math.max(0, usableViewHeight - (rect.bottom - rect.top)); } public void notifyHeightChanged() { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/StickersAlert.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/StickersAlert.java index cf66b6853..60efb9976 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/StickersAlert.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/StickersAlert.java @@ -17,7 +17,6 @@ import android.app.Activity; import android.content.Context; import android.graphics.*; import android.graphics.Rect; -import android.graphics.drawable.Drawable; import android.os.Build; import android.text.Selection; import android.text.Spannable; @@ -104,7 +103,6 @@ public class StickersAlert extends BottomSheet implements NotificationCenter.Not private BackupImageView stickerImageView; private TextView stickerEmojiTextView; private RecyclerListView.OnItemClickListener stickersOnItemClickListener; - private Drawable shadowDrawable; private AnimatorSet[] shadowAnimation = new AnimatorSet[2]; private View[] shadow = new View[2]; private FrameLayout emptyView; @@ -262,9 +260,6 @@ public class StickersAlert extends BottomSheet implements NotificationCenter.Not } private void init(Context context) { - shadowDrawable = context.getResources().getDrawable(R.drawable.sheet_shadow_round).mutate(); - shadowDrawable.setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_dialogBackground), PorterDuff.Mode.MULTIPLY)); - containerView = new FrameLayout(context) { private int lastNotifyWidth; @@ -293,7 +288,6 @@ public class StickersAlert extends BottomSheet implements NotificationCenter.Not setPadding(backgroundPaddingLeft, AndroidUtilities.statusBarHeight, backgroundPaddingLeft, 0); ignoreLayout = false; } - int measuredWidth = getMeasuredWidth(); itemSize = (MeasureSpec.getSize(widthMeasureSpec) - AndroidUtilities.dp(36)) / 5; int contentSize; if (stickerSetCovereds != null) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Switch.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Switch.java index 66cd0f5e1..3ee4b5dc2 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Switch.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Switch.java @@ -63,7 +63,7 @@ public class Switch extends View { private boolean drawRipple; private RippleDrawable rippleDrawable; private Paint ripplePaint; - private int pressedState[] = new int[]{android.R.attr.state_enabled, android.R.attr.state_pressed}; + private int[] pressedState = new int[]{android.R.attr.state_enabled, android.R.attr.state_pressed}; private int colorSet; private boolean bitmapsCreated; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/ThemeEditorView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/ThemeEditorView.java index 63e119ca1..be1c7cce5 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ThemeEditorView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ThemeEditorView.java @@ -947,6 +947,14 @@ public class ThemeEditorView { } } + @Override + public void dismissInternal() { + super.dismissInternal(); + if (searchField.searchEditText.isFocused()) { + AndroidUtilities.hideKeyboard(searchField.searchEditText); + } + } + private void setColorPickerVisible(boolean visible) { if (visible) { animationInProgress = true; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/URLSpanBrowser.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/URLSpanBrowser.java index e244d83e1..f99638b3d 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/URLSpanBrowser.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/URLSpanBrowser.java @@ -24,7 +24,7 @@ public class URLSpanBrowser extends URLSpan { } public URLSpanBrowser(String url, TextStyleSpan.TextStyleRun run) { - super(url); + super(url != null ? url.replace('\u202E', ' ') : url); style = run; } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/URLSpanNoUnderline.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/URLSpanNoUnderline.java index a22b8345c..130c74291 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/URLSpanNoUnderline.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/URLSpanNoUnderline.java @@ -24,7 +24,7 @@ public class URLSpanNoUnderline extends URLSpan { } public URLSpanNoUnderline(String url, TextStyleSpan.TextStyleRun run) { - super(url); + super(url != null ? url.replace('\u202E', ' ') : url); style = run; } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/URLSpanNoUnderlineBold.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/URLSpanNoUnderlineBold.java index 95867e0bc..6ed945170 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/URLSpanNoUnderlineBold.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/URLSpanNoUnderlineBold.java @@ -13,8 +13,9 @@ import android.text.TextPaint; import org.telegram.messenger.AndroidUtilities; public class URLSpanNoUnderlineBold extends URLSpanNoUnderline { + public URLSpanNoUnderlineBold(String url) { - super(url); + super(url != null ? url.replace('\u202E', ' ') : url); } @Override diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/URLSpanReplacement.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/URLSpanReplacement.java index 074c75442..d55d00fee 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/URLSpanReplacement.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/URLSpanReplacement.java @@ -24,7 +24,7 @@ public class URLSpanReplacement extends URLSpan { } public URLSpanReplacement(String url, TextStyleSpan.TextStyleRun run) { - super(url); + super(url != null ? url.replace('\u202E', ' ') : url); style = run; } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/UndoView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/UndoView.java index d699bd1ee..08d27b652 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/UndoView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/UndoView.java @@ -17,6 +17,7 @@ import android.text.TextUtils; import android.util.TypedValue; import android.view.Gravity; import android.view.View; +import android.view.ViewGroup; import android.view.animation.DecelerateInterpolator; import android.widget.FrameLayout; import android.widget.ImageView; @@ -42,6 +43,7 @@ public class UndoView extends FrameLayout { private ImageView undoImageView; private RLottieImageView leftImageView; private LinearLayout undoButton; + private int undoViewHeight; private int currentAccount = UserConfig.selectedAccount; @@ -190,7 +192,7 @@ public class UndoView extends FrameLayout { if (animated != 0) { AnimatorSet animatorSet = new AnimatorSet(); if (animated == 1) { - animatorSet.playTogether(ObjectAnimator.ofFloat(this, View.TRANSLATION_Y, AndroidUtilities.dp(8 + (hasSubInfo() ? 52 : 48)))); + animatorSet.playTogether(ObjectAnimator.ofFloat(this, View.TRANSLATION_Y, AndroidUtilities.dp(8) + undoViewHeight)); animatorSet.setDuration(250); } else { animatorSet.playTogether( @@ -211,7 +213,7 @@ public class UndoView extends FrameLayout { }); animatorSet.start(); } else { - setTranslationY(AndroidUtilities.dp(8 + (hasSubInfo() ? 52 : 48))); + setTranslationY(AndroidUtilities.dp(8) + undoViewHeight); setVisibility(INVISIBLE); } } @@ -354,11 +356,23 @@ public class UndoView extends FrameLayout { AndroidUtilities.makeAccessibilityAnnouncement(infoTextView.getText() + (subinfoTextView.getVisibility() == VISIBLE ? ". " + subinfoTextView.getText() : "")); + if (hasSubInfo()) { + undoViewHeight = AndroidUtilities.dp(52); + } else if (getParent() instanceof ViewGroup) { + ViewGroup parent = (ViewGroup) getParent(); + int width = parent.getMeasuredWidth(); + if (width == 0) { + width = AndroidUtilities.displaySize.x; + } + measureChildWithMargins(infoTextView, MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY), 0, MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED), 0); + undoViewHeight = infoTextView.getMeasuredHeight() + AndroidUtilities.dp(28); + } + if (getVisibility() != VISIBLE) { setVisibility(VISIBLE); - setTranslationY(AndroidUtilities.dp(8 + (hasSubInfo() ? 52 : 48))); + setTranslationY(AndroidUtilities.dp(8) + undoViewHeight); AnimatorSet animatorSet = new AnimatorSet(); - animatorSet.playTogether(ObjectAnimator.ofFloat(this, View.TRANSLATION_Y, AndroidUtilities.dp(8 + (hasSubInfo() ? 52 : 48)), -additionalTranslationY)); + animatorSet.playTogether(ObjectAnimator.ofFloat(this, View.TRANSLATION_Y, AndroidUtilities.dp(8) + undoViewHeight, -additionalTranslationY)); animatorSet.setInterpolator(new DecelerateInterpolator()); animatorSet.setDuration(180); animatorSet.start(); @@ -371,7 +385,7 @@ public class UndoView extends FrameLayout { @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - super.onMeasure(MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(hasSubInfo() ? 52 : 48), MeasureSpec.EXACTLY)); + super.onMeasure(MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(undoViewHeight, MeasureSpec.EXACTLY)); } @Override diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/VideoPlayer.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/VideoPlayer.java index db86d0f09..683dbc3e2 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/VideoPlayer.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/VideoPlayer.java @@ -75,6 +75,8 @@ public class VideoPlayer implements ExoPlayer.EventListener, SimpleExoPlayer.Vid private boolean autoplay; private boolean mixedAudio; + private Uri currentUri; + private boolean videoPlayerReady; private boolean audioPlayerReady; private boolean mixedPlayWhenReady; @@ -235,6 +237,7 @@ public class VideoPlayer implements ExoPlayer.EventListener, SimpleExoPlayer.Vid public void preparePlayer(Uri uri, String type) { videoPlayerReady = false; mixedAudio = false; + currentUri = uri; String scheme = uri.getScheme(); isStreaming = scheme != null && !scheme.startsWith("file"); ensurePleyaerCreated(); @@ -291,6 +294,10 @@ public class VideoPlayer implements ExoPlayer.EventListener, SimpleExoPlayer.Vid return player.getPlaybackState(); } + public Uri getCurrentUri() { + return currentUri; + } + public void play() { mixedPlayWhenReady = true; if (mixedAudio) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/VideoSeekPreviewImage.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/VideoSeekPreviewImage.java new file mode 100644 index 000000000..61581467f --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/VideoSeekPreviewImage.java @@ -0,0 +1,269 @@ +package org.telegram.ui.Components; + +import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.BitmapShader; +import android.graphics.Canvas; +import android.graphics.Matrix; +import android.graphics.Paint; +import android.graphics.RectF; +import android.graphics.Shader; +import android.graphics.drawable.Drawable; +import android.net.Uri; +import android.text.TextPaint; +import android.view.View; +import android.view.ViewGroup; + +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.Bitmaps; +import org.telegram.messenger.FileLoader; +import org.telegram.messenger.R; +import org.telegram.messenger.Utilities; +import org.telegram.tgnet.TLRPC; + +import java.io.File; + +public class VideoSeekPreviewImage extends View { + + private AnimatedFileDrawable fileDrawable; + private long duration; + private Uri videoUri; + private Runnable loadRunnable; + private Runnable progressRunnable; + private float pendingProgress; + private int currentPixel = -1; + private int pixelWidth; + private boolean ready; + private Bitmap bitmapToRecycle; + private Bitmap bitmapToDraw; + private Drawable frameDrawable; + + private String frameTime; + private int timeWidth; + private TextPaint textPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG); + + private BitmapShader bitmapShader; + private RectF dstR = new RectF(); + private Paint paint = new Paint(Paint.FILTER_BITMAP_FLAG); + private Paint bitmapPaint = new Paint(Paint.FILTER_BITMAP_FLAG); + private RectF bitmapRect = new RectF(); + private Matrix matrix = new Matrix(); + + private VideoSeekPreviewImageDelegate delegate; + + public interface VideoSeekPreviewImageDelegate { + void onReady(); + } + + public VideoSeekPreviewImage(Context context, VideoSeekPreviewImageDelegate videoSeekPreviewImageDelegate) { + super(context); + setVisibility(INVISIBLE); + + frameDrawable = context.getResources().getDrawable(R.drawable.videopreview); + textPaint.setTextSize(AndroidUtilities.dp(13)); + textPaint.setColor(0xffffffff); + + delegate = videoSeekPreviewImageDelegate; + } + + public void setProgress(float progress, int w) { + if (w != 0) { + pixelWidth = w; + int pixel = (int) (w * progress) / 5; + if (currentPixel == pixel) { + return; + } + currentPixel = pixel; + } + long time = (long) (duration * progress); + int minutes = (int) (time / 60 / 1000); + int seconds = (int) (time - minutes * 60 * 1000) / 1000; + frameTime = String.format("%d:%02d", minutes, seconds); + timeWidth = (int) Math.ceil(textPaint.measureText(frameTime)); + invalidate(); + + if (progressRunnable != null) { + Utilities.globalQueue.cancelRunnable(progressRunnable); + } + AnimatedFileDrawable file = fileDrawable; + if (file != null) { + file.resetStream(false); + } + Utilities.globalQueue.postRunnable(progressRunnable = () -> { + if (fileDrawable == null) { + pendingProgress = progress; + return; + } + int bitmapSize = Math.max(200, AndroidUtilities.dp(100)); + Bitmap bitmap = fileDrawable.getFrameAtTime(time); + if (bitmap != null) { + int width = bitmap.getWidth(); + int height = bitmap.getHeight(); + + if (width > height) { + float scale = width / (float) bitmapSize; + width = bitmapSize; + height /= scale; + } else { + float scale = height / (float) bitmapSize; + height = bitmapSize; + width /= scale; + } + try { + Bitmap backgroundBitmap = Bitmaps.createBitmap(width, height, Bitmap.Config.ARGB_8888); + dstR.set(0, 0, width, height); + Canvas canvas = new Canvas(backgroundBitmap); + canvas.drawBitmap(bitmap, null, dstR, paint); + canvas.setBitmap(null); + bitmap = backgroundBitmap; + } catch (Throwable ignore) { + bitmap = null; + } + } + Bitmap bitmapFinal = bitmap; + AndroidUtilities.runOnUIThread(() -> { + if (bitmapFinal != null) { + if (bitmapToDraw != null) { + if (bitmapToRecycle != null) { + bitmapToRecycle.recycle(); + } + bitmapToRecycle = bitmapToDraw; + } + bitmapToDraw = bitmapFinal; + bitmapShader = new BitmapShader(bitmapToDraw, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP); + bitmapShader.setLocalMatrix(matrix); + bitmapPaint.setShader(bitmapShader); + invalidate(); + int viewSize = AndroidUtilities.dp(150); + float bitmapWidth = bitmapFinal.getWidth(); + float bitmapHeight = bitmapFinal.getHeight(); + float aspect = bitmapWidth / bitmapHeight; + int viewWidth; + int viewHeight; + if (aspect > 1.0f) { + viewWidth = viewSize; + viewHeight = (int) (viewSize / aspect); + } else { + viewHeight = viewSize; + viewWidth = (int) (viewSize * aspect); + } + ViewGroup.LayoutParams layoutParams = getLayoutParams(); + if (getVisibility() != VISIBLE || layoutParams.width != viewWidth || layoutParams.height != viewHeight) { + layoutParams.width = viewWidth; + layoutParams.height = viewHeight; + setVisibility(VISIBLE); + requestLayout(); + } + } + progressRunnable = null; + }); + }); + } + + public void open(Uri uri) { + if (uri == null || uri.equals(videoUri)) { + return; + } + videoUri = uri; + Utilities.globalQueue.postRunnable(loadRunnable = () -> { + String scheme = uri.getScheme(); + String path; + if ("tg".equals(scheme)) { + int currentAccount = Utilities.parseInt(uri.getQueryParameter("account")); + Object parentObject = FileLoader.getInstance(currentAccount).getParentObject(Utilities.parseInt(uri.getQueryParameter("rid"))); + TLRPC.TL_document document = new TLRPC.TL_document(); + document.access_hash = Utilities.parseLong(uri.getQueryParameter("hash")); + document.id = Utilities.parseLong(uri.getQueryParameter("id")); + document.size = Utilities.parseInt(uri.getQueryParameter("size")); + document.dc_id = Utilities.parseInt(uri.getQueryParameter("dc")); + document.mime_type = uri.getQueryParameter("mime"); + document.file_reference = Utilities.hexToBytes(uri.getQueryParameter("reference")); + TLRPC.TL_documentAttributeFilename filename = new TLRPC.TL_documentAttributeFilename(); + filename.file_name = uri.getQueryParameter("name"); + document.attributes.add(filename); + document.attributes.add(new TLRPC.TL_documentAttributeVideo()); + String name = FileLoader.getAttachFileName(document); + if (FileLoader.getInstance(currentAccount).isLoadingFile(name)) { + path = new File(FileLoader.getDirectory(FileLoader.MEDIA_DIR_CACHE), document.dc_id + "_" + document.id + ".temp").getAbsolutePath(); + } else { + path = FileLoader.getPathToAttach(document, false).getAbsolutePath(); + } + fileDrawable = new AnimatedFileDrawable(new File(path), true, document.size, document, parentObject, currentAccount, true); + } else { + path = uri.getPath(); + fileDrawable = new AnimatedFileDrawable(new File(path), true, 0, null, null, 0, true); + } + duration = fileDrawable.getDurationMs(); + if (pendingProgress != 0.0f) { + setProgress(pendingProgress, pixelWidth); + pendingProgress = 0.0f; + } + AndroidUtilities.runOnUIThread(() -> { + loadRunnable = null; + if (fileDrawable != null) { + ready = true; + delegate.onReady(); + } + }); + }); + } + + public boolean isReady() { + return ready; + } + + @Override + protected void onDraw(Canvas canvas) { + if (bitmapToRecycle != null) { + bitmapToRecycle.recycle(); + bitmapToRecycle = null; + } + if (bitmapToDraw != null && bitmapShader != null) { + matrix.reset(); + float scale = getMeasuredWidth() / (float) bitmapToDraw.getWidth(); + matrix.preScale(scale, scale); + bitmapRect.set(0, 0, getMeasuredWidth(), getMeasuredHeight()); + canvas.drawRoundRect(bitmapRect, AndroidUtilities.dp(6), AndroidUtilities.dp(6), bitmapPaint); + frameDrawable.setBounds(0, 0, getMeasuredWidth(), getMeasuredHeight()); + frameDrawable.draw(canvas); + + canvas.drawText(frameTime, (getMeasuredWidth() - timeWidth) / 2, getMeasuredHeight() - AndroidUtilities.dp(9), textPaint); + } + } + + public void close() { + if (loadRunnable != null) { + Utilities.globalQueue.cancelRunnable(loadRunnable); + loadRunnable = null; + } + if (progressRunnable != null) { + Utilities.globalQueue.cancelRunnable(progressRunnable); + progressRunnable = null; + } + AnimatedFileDrawable drawable = fileDrawable; + if (drawable != null) { + drawable.resetStream(true); + } + Utilities.globalQueue.postRunnable(() -> { + pendingProgress = 0.0f; + if (fileDrawable != null) { + fileDrawable.recycle(); + fileDrawable = null; + } + }); + setVisibility(INVISIBLE); + /*if (bitmapToDraw != null) { + if (bitmapToRecycle != null) { + bitmapToRecycle.recycle(); + } + bitmapToRecycle = bitmapToDraw; + }*/ + bitmapToDraw = null; + bitmapShader = null; + invalidate(); + + currentPixel = -1; + videoUri = null; + ready = false; + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/VideoTimelinePlayView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/VideoTimelinePlayView.java index 417e45118..2aa15003e 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/VideoTimelinePlayView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/VideoTimelinePlayView.java @@ -245,11 +245,11 @@ public class VideoTimelinePlayView extends View { paint.setColor(color); } - public void setVideoPath(String path) { + public void setVideoPath(String path, float left, float right) { destroy(); mediaMetadataRetriever = new MediaMetadataRetriever(); - progressLeft = 0.0f; - progressRight = 1.0f; + progressLeft = left; + progressRight = right; try { mediaMetadataRetriever.setDataSource(path); String duration = mediaMetadataRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/WebPlayerView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/WebPlayerView.java index 3994b7ae4..cfb54bc70 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/WebPlayerView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/WebPlayerView.java @@ -70,6 +70,7 @@ import java.net.URLConnection; import java.net.URLDecoder; import java.net.URLEncoder; import java.net.UnknownHostException; +import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.HashMap; import java.util.Locale; @@ -297,7 +298,7 @@ public class WebPlayerView extends ViewGroup implements VideoPlayer.VideoPlayerD if (expr.charAt(expr.length() - 1) != ')') { throw new Exception("last char not ')'"); } - String argvals[]; + String[] argvals; if (arg_str.length() != 0) { String[] args = arg_str.split(","); for (int a = 0; a < args.length; a++) { @@ -392,8 +393,8 @@ public class WebPlayerView extends ViewGroup implements VideoPlayer.VideoPlayerD for (int a = 0; a < argNames.length; a++) { localVars.put(argNames[a], ""); } - String stmts[] = funcCode.split(";"); - boolean abort[] = new boolean[1]; + String[] stmts = funcCode.split(";"); + boolean[] abort = new boolean[1]; for (int a = 0; a < stmts.length; a++) { interpretStatement(stmts[a], localVars, abort, 100); if (abort[0]) { @@ -551,7 +552,7 @@ public class WebPlayerView extends ViewGroup implements VideoPlayer.VideoPlayerD if (result == null) { result = new StringBuilder(); } - result.append(new String(data, 0, read, "UTF-8")); + result.append(new String(data, 0, read, StandardCharsets.UTF_8)); } else if (read == -1) { done = true; break; @@ -616,7 +617,7 @@ public class WebPlayerView extends ViewGroup implements VideoPlayer.VideoPlayerD boolean encrypted = false; String otherUrl = null; - String extra[] = new String[] {"", "&el=leanback", "&el=embedded", "&el=detailpage", "&el=vevo"}; + String[] extra = new String[]{"", "&el=leanback", "&el=embedded", "&el=detailpage", "&el=vevo"}; for (int i = 0; i < extra.length; i++) { String videoInfo = downloadUrlContent(this, "https://www.youtube.com/get_video_info?" + params + extra[i]); if (isCancelled()) { @@ -626,11 +627,11 @@ public class WebPlayerView extends ViewGroup implements VideoPlayer.VideoPlayerD String hls = null; boolean isLive = false; if (videoInfo != null) { - String args[] = videoInfo.split("&"); + String[] args = videoInfo.split("&"); for (int a = 0; a < args.length; a++) { if (args[a].startsWith("dashmpd")) { exists = true; - String args2[] = args[a].split("="); + String[] args2 = args[a].split("="); if (args2.length == 2) { try { result[0] = URLDecoder.decode(args2[1], "UTF-8"); @@ -639,14 +640,14 @@ public class WebPlayerView extends ViewGroup implements VideoPlayer.VideoPlayerD } } } else if (args[a].startsWith("url_encoded_fmt_stream_map")) { - String args2[] = args[a].split("="); + String[] args2 = args[a].split("="); if (args2.length == 2) { try { - String args3[] = URLDecoder.decode(args2[1], "UTF-8").split("[&,]"); + String[] args3 = URLDecoder.decode(args2[1], "UTF-8").split("[&,]"); String currentUrl = null; boolean isMp4 = false; for (int c = 0; c < args3.length; c++) { - String args4[] = args3[c].split("="); + String[] args4 = args3[c].split("="); if (args4[0].startsWith("type")) { String type = URLDecoder.decode(args4[1], "UTF-8"); if (type.contains("video/mp4")) { @@ -668,14 +669,14 @@ public class WebPlayerView extends ViewGroup implements VideoPlayer.VideoPlayerD } } } else if (args[a].startsWith("use_cipher_signature")) { - String args2[] = args[a].split("="); + String[] args2 = args[a].split("="); if (args2.length == 2) { if (args2[1].toLowerCase().equals("true")) { encrypted = true; } } } else if (args[a].startsWith("hlsvp")) { - String args2[] = args[a].split("="); + String[] args2 = args[a].split("="); if (args2.length == 2) { try { hls = URLDecoder.decode(args2[1], "UTF-8"); @@ -684,7 +685,7 @@ public class WebPlayerView extends ViewGroup implements VideoPlayer.VideoPlayerD } } } else if (args[a].startsWith("livestream")) { - String args2[] = args[a].split("="); + String[] args2 = args[a].split("="); if (args2.length == 2) { if (args2[1].toLowerCase().equals("1")) { isLive = true; @@ -798,7 +799,7 @@ public class WebPlayerView extends ViewGroup implements VideoPlayer.VideoPlayerD } else { try { String javascript = ""; - byte[] data = javascript.getBytes("UTF-8"); + byte[] data = javascript.getBytes(StandardCharsets.UTF_8); final String base64 = Base64.encodeToString(data, Base64.DEFAULT); webView.loadUrl("data:text/html;charset=utf-8;base64," + base64); } catch (Exception e) { @@ -1093,7 +1094,7 @@ public class WebPlayerView extends ViewGroup implements VideoPlayer.VideoPlayerD source.setCharAt(a, c == lower ? Character.toUpperCase(c) : lower); } try { - return new String(Base64.decode(source.toString(), Base64.DEFAULT), "UTF-8"); + return new String(Base64.decode(source.toString(), Base64.DEFAULT), StandardCharsets.UTF_8); } catch (Exception ignore) { return null; } @@ -2068,6 +2069,15 @@ public class WebPlayerView extends ViewGroup implements VideoPlayer.VideoPlayerD return inFullscreen; } + public String getYouTubeVideoId(String url) { + Matcher matcher = youtubeIdRegex.matcher(url); + String id = null; + if (matcher.find()) { + id = matcher.group(1); + } + return id; + } + public boolean loadVideo(String url, TLRPC.Photo thumb, Object parentObject, String originalUrl, boolean autoplay) { String youtubeId = null; String vimeoId = null; @@ -2091,7 +2101,7 @@ public class WebPlayerView extends ViewGroup implements VideoPlayer.VideoPlayerD } if (t != null) { if (t.contains("m")) { - String args[] = t.split("m"); + String[] args = t.split("m"); seekToTime = Utilities.parseInt(args[0]) * 60 + Utilities.parseInt(args[1]); } else { seekToTime = Utilities.parseInt(t); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/ZoomControlView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/ZoomControlView.java new file mode 100644 index 000000000..9ea5ed563 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ZoomControlView.java @@ -0,0 +1,275 @@ +package org.telegram.ui.Components; + +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.animation.AnimatorSet; +import android.animation.ObjectAnimator; +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.drawable.Drawable; +import android.util.Property; +import android.view.HapticFeedbackConstants; +import android.view.MotionEvent; +import android.view.View; + +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.R; + +public class ZoomControlView extends View { + + private Drawable minusDrawable; + private Drawable plusDrawable; + private Drawable progressDrawable; + private Drawable filledProgressDrawable; + private Drawable knobDrawable; + private Drawable pressedKnobDrawable; + + private int minusCx; + private int minusCy; + private int plusCx; + private int plusCy; + + private int progressStartX; + private int progressStartY; + private int progressEndX; + private int progressEndY; + + private float zoom; + + private boolean pressed; + private boolean knobPressed; + private float knobStartX; + private float knobStartY; + + private float animatingToZoom; + private AnimatorSet animatorSet; + + private ZoomControlViewDelegate delegate; + + public interface ZoomControlViewDelegate { + void didSetZoom(float zoom); + } + + public final Property ZOOM_PROPERTY = new AnimationProperties.FloatProperty("clipProgress") { + @Override + public void setValue(ZoomControlView object, float value) { + zoom = value; + if (delegate != null) { + delegate.didSetZoom(zoom); + } + invalidate(); + } + + @Override + public Float get(ZoomControlView object) { + return zoom; + } + }; + + public ZoomControlView(Context context) { + super(context); + + minusDrawable = context.getResources().getDrawable(R.drawable.zoom_minus); + plusDrawable = context.getResources().getDrawable(R.drawable.zoom_plus); + progressDrawable = context.getResources().getDrawable(R.drawable.zoom_slide); + filledProgressDrawable = context.getResources().getDrawable(R.drawable.zoom_slide_a); + knobDrawable = context.getResources().getDrawable(R.drawable.zoom_round); + pressedKnobDrawable = context.getResources().getDrawable(R.drawable.zoom_round_b); + } + + public float getZoom() { + if (animatorSet != null) { + return animatingToZoom; + } + return zoom; + } + + public void setZoom(float value, boolean notify) { + if (value == zoom) { + return; + } + if (value < 0) { + value = 0; + } else if (value > 1.0f) { + value = 1.0f; + } + zoom = value; + if (notify && delegate != null) { + delegate.didSetZoom(zoom); + } + invalidate(); + } + + public void setDelegate(ZoomControlViewDelegate zoomControlViewDelegate) { + delegate = zoomControlViewDelegate; + } + + @Override + public boolean onTouchEvent(MotionEvent event) { + float x = event.getX(); + float y = event.getY(); + int action = event.getAction(); + boolean handled = false; + boolean isPortrait = getMeasuredWidth() > getMeasuredHeight(); + int knobX = (int) (progressStartX + (progressEndX - progressStartX) * zoom); + int knobY = (int) (progressStartY + (progressEndY - progressStartY) * zoom); + if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_DOWN) { + if (x >= knobX - AndroidUtilities.dp(20) && x <= knobX + AndroidUtilities.dp(20) && y >= knobY - AndroidUtilities.dp(25) && y <= knobY + AndroidUtilities.dp(25)) { + if (action == MotionEvent.ACTION_DOWN) { + knobPressed = true; + knobStartX = x - knobX; + knobStartY = y - knobY; + invalidate(); + } + handled = true; + } else if (x >= minusCx - AndroidUtilities.dp(16) && x <= minusCx + AndroidUtilities.dp(16) && y >= minusCy - AndroidUtilities.dp(16) && y <= minusCy + AndroidUtilities.dp(16)) { + if (action == MotionEvent.ACTION_UP && animateToZoom((float) Math.floor(getZoom() / 0.25f) * 0.25f - 0.25f)) { + performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP); + } else { + pressed = true; + } + handled = true; + } else if (x >= plusCx - AndroidUtilities.dp(16) && x <= plusCx + AndroidUtilities.dp(16) && y >= plusCy - AndroidUtilities.dp(16) && y <= plusCy + AndroidUtilities.dp(16)) { + if (action == MotionEvent.ACTION_UP && animateToZoom((float) Math.floor(getZoom() / 0.25f) * 0.25f + 0.25f)) { + performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP); + } else { + pressed = true; + } + handled = true; + } else if (isPortrait) { + if (x >= progressStartX && x <= progressEndX) { + if (action == MotionEvent.ACTION_DOWN) { + knobStartX = x; + pressed = true; + } else if (Math.abs(knobStartX - x) <= AndroidUtilities.dp(10)) { + zoom = (x - progressStartX) / (progressEndX - progressStartX); + if (delegate != null) { + delegate.didSetZoom(zoom); + } + invalidate(); + } + handled = true; + } + } else { + if (y >= progressStartY && y <= progressEndY) { + if (action == MotionEvent.ACTION_UP) { + knobStartY = y; + pressed = true; + } else if (Math.abs(knobStartY - y) <= AndroidUtilities.dp(10)) { + zoom = (y - progressStartY) / (progressEndY - progressStartY); + if (delegate != null) { + delegate.didSetZoom(zoom); + } + invalidate(); + } + handled = true; + } + } + } else if (action == MotionEvent.ACTION_MOVE) { + if (knobPressed) { + if (isPortrait) { + zoom = ((x + knobStartX) - progressStartX) / (progressEndX - progressStartX); + } else { + zoom = ((y + knobStartY) - progressStartY) / (progressEndY - progressStartY); + } + if (zoom < 0) { + zoom = 0; + } else if (zoom > 1.0f) { + zoom = 1.0f; + } + if (delegate != null) { + delegate.didSetZoom(zoom); + } + invalidate(); + } + } + if (action == MotionEvent.ACTION_UP) { + pressed = false; + knobPressed = false; + invalidate(); + } + return handled || pressed || knobPressed || super.onTouchEvent(event); + } + + private boolean animateToZoom(float zoom) { + if (zoom < 0 || zoom > 1.0f) { + return false; + } + if (animatorSet != null) { + animatorSet.cancel(); + } + animatingToZoom = zoom; + animatorSet = new AnimatorSet(); + animatorSet.playTogether(ObjectAnimator.ofFloat(this, ZOOM_PROPERTY, zoom)); + animatorSet.setDuration(180); + animatorSet.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + animatorSet = null; + } + }); + animatorSet.start(); + return true; + } + + @Override + protected void onDraw(Canvas canvas) { + int cx = getMeasuredWidth() / 2; + int cy = getMeasuredHeight() / 2; + boolean isPortrait = getMeasuredWidth() > getMeasuredHeight(); + + if (isPortrait) { + minusCx = AndroidUtilities.dp(16 + 25); + minusCy = cy; + plusCx = getMeasuredWidth() - AndroidUtilities.dp(16 + 25); + plusCy = cy; + + progressStartX = minusCx + AndroidUtilities.dp(18); + progressStartY = cy; + + progressEndX = plusCx - AndroidUtilities.dp(18); + progressEndY = cy; + } else { + minusCx = cx; + minusCy = AndroidUtilities.dp(16 + 25); + plusCx = cx; + plusCy = getMeasuredHeight() - AndroidUtilities.dp(16 + 25); + + progressStartX = cx; + progressStartY = minusCy + AndroidUtilities.dp(18); + + progressEndX = cx; + progressEndY = plusCy - AndroidUtilities.dp(18); + } + minusDrawable.setBounds(minusCx - AndroidUtilities.dp(7), minusCy - AndroidUtilities.dp(7), minusCx + AndroidUtilities.dp(7), minusCy + AndroidUtilities.dp(7)); + minusDrawable.draw(canvas); + plusDrawable.setBounds(plusCx - AndroidUtilities.dp(7), plusCy - AndroidUtilities.dp(7), plusCx + AndroidUtilities.dp(7), plusCy + AndroidUtilities.dp(7)); + plusDrawable.draw(canvas); + + int totalX = progressEndX - progressStartX; + int totalY = progressEndY - progressStartY; + int knobX = (int) (progressStartX + totalX * zoom); + int knobY = (int) (progressStartY + totalY * zoom); + + if (isPortrait) { + progressDrawable.setBounds(progressStartX, progressStartY - AndroidUtilities.dp(3), progressEndX, progressStartY + AndroidUtilities.dp(3)); + filledProgressDrawable.setBounds(progressStartX, progressStartY - AndroidUtilities.dp(3), knobX, progressStartY + AndroidUtilities.dp(3)); + } else { + progressDrawable.setBounds(progressStartY, 0, progressEndY, AndroidUtilities.dp(6)); + filledProgressDrawable.setBounds(progressStartY, 0, knobY, AndroidUtilities.dp(6)); + canvas.save(); + canvas.rotate(90); + canvas.translate(0, -progressStartX - AndroidUtilities.dp(3)); + } + progressDrawable.draw(canvas); + filledProgressDrawable.draw(canvas); + if (!isPortrait) { + canvas.restore(); + } + + Drawable drawable = knobPressed ? pressedKnobDrawable : knobDrawable; + int size = drawable.getIntrinsicWidth(); + drawable.setBounds(knobX - size / 2, knobY - size / 2, knobX + size / 2, knobY + size / 2); + drawable.draw(canvas); + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/DialogOrContactPickerActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/DialogOrContactPickerActivity.java index bd7c7f6e1..033d4f471 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/DialogOrContactPickerActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/DialogOrContactPickerActivity.java @@ -39,6 +39,7 @@ import org.telegram.ui.Components.RecyclerListView; import org.telegram.ui.Components.ScrollSlidingTextTabStrip; import java.util.ArrayList; +import java.util.Collections; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; @@ -650,24 +651,8 @@ public class DialogOrContactPickerActivity extends BaseFragment { arrayList.add(new ThemeDescription(scrollSlidingTextTabStrip.getTabsContainer(), ThemeDescription.FLAG_BACKGROUNDFILTER | ThemeDescription.FLAG_DRAWABLESELECTEDSTATE, new Class[]{TextView.class}, null, null, null, Theme.key_actionBarTabLine)); arrayList.add(new ThemeDescription(null, 0, null, null, new Drawable[]{scrollSlidingTextTabStrip.getSelectorDrawable()}, null, Theme.key_actionBarTabSelector)); - /*for (int a = 0; a < viewPages.length; a++) { TODO - arrayList.add(new ThemeDescription(viewPages[a].listView, ThemeDescription.FLAG_CELLBACKGROUNDCOLOR, new Class[]{TextSettingsCell.class, HeaderCell.class}, null, null, null, Theme.key_windowBackgroundWhite)); - arrayList.add(new ThemeDescription(viewPages[a].listView, ThemeDescription.FLAG_LISTGLOWCOLOR, null, null, null, null, Theme.key_actionBarDefault)); - arrayList.add(new ThemeDescription(viewPages[a].listView, ThemeDescription.FLAG_SELECTOR, null, null, null, null, Theme.key_listSelector)); - - arrayList.add(new ThemeDescription(viewPages[a].listView, 0, new Class[]{View.class}, Theme.dividerPaint, null, null, Theme.key_divider)); - - arrayList.add(new ThemeDescription(viewPages[a].listView, ThemeDescription.FLAG_BACKGROUNDFILTER, new Class[]{ShadowSectionCell.class}, null, null, null, Theme.key_windowBackgroundGrayShadow)); - - arrayList.add(new ThemeDescription(viewPages[a].listView, 0, new Class[]{HeaderCell.class}, new String[]{"textView"}, null, null, null, Theme.key_windowBackgroundWhiteBlueHeader)); - - arrayList.add(new ThemeDescription(viewPages[a].listView, ThemeDescription.FLAG_BACKGROUNDFILTER, new Class[]{TextInfoPrivacyCell.class}, null, null, null, Theme.key_windowBackgroundGrayShadow)); - arrayList.add(new ThemeDescription(viewPages[a].listView, 0, new Class[]{TextInfoPrivacyCell.class}, new String[]{"textView"}, null, null, null, Theme.key_windowBackgroundWhiteGrayText4)); - - arrayList.add(new ThemeDescription(viewPages[a].listView, ThemeDescription.FLAG_CHECKTAG, new Class[]{TextSettingsCell.class}, new String[]{"textView"}, null, null, null, Theme.key_windowBackgroundWhiteBlackText)); - arrayList.add(new ThemeDescription(viewPages[a].listView, 0, new Class[]{TextSettingsCell.class}, new String[]{"valueTextView"}, null, null, null, Theme.key_windowBackgroundWhiteValueText)); - arrayList.add(new ThemeDescription(viewPages[a].listView, ThemeDescription.FLAG_CHECKTAG, new Class[]{TextSettingsCell.class}, new String[]{"textView"}, null, null, null, Theme.key_windowBackgroundWhiteRedText2)); - }*/ + Collections.addAll(arrayList, dialogsActivity.getThemeDescriptions()); + Collections.addAll(arrayList, contactsActivity.getThemeDescriptions()); return arrayList.toArray(new ThemeDescription[0]); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/DialogsActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/DialogsActivity.java index c26421253..52e5c8782 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/DialogsActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/DialogsActivity.java @@ -152,6 +152,8 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. private int lastItemsCount; + private int messagesCount; + private PacmanAnimation pacmanAnimation; private DialogCell slidingView; @@ -525,8 +527,10 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. } } SharedPreferences preferences = MessagesController.getGlobalMainSettings(); - boolean hintShowed = preferences.getBoolean("archivehint_l", false); - preferences.edit().putBoolean("archivehint_l", true).commit(); + boolean hintShowed = preferences.getBoolean("archivehint_l", false) || SharedConfig.archiveHidden; + if (!hintShowed) { + preferences.edit().putBoolean("archivehint_l", true).commit(); + } getUndoView().showWithAction(dialog.id, hintShowed ? UndoView.ACTION_ARCHIVE : UndoView.ACTION_ARCHIVE_HINT, null, () -> { dialogsListFrozen = true; getMessagesController().addDialogToFolder(dialog.id, 0, pinnedNum, 0); @@ -641,6 +645,7 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. checkCanWrite = arguments.getBoolean("checkCanWrite", true); folderId = arguments.getInt("folderId", 0); resetDelegate = arguments.getBoolean("resetDelegate", true); + messagesCount = arguments.getInt("messagesCount", 0); } if (dialogsType == 0) { @@ -686,6 +691,7 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. getMediaDataController().checkFeaturedStickers(); dialogsLoaded[currentAccount] = true; } + getMediaDataController().checkStickers(MediaDataController.TYPE_EMOJI); getMessagesController().loadPinnedDialogs(folderId, 0, null); return true; } @@ -1265,6 +1271,9 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. } if (onlySelect) { + if (!validateSlowModeDialog(dialog_id)) { + return; + } if (dialogsAdapter.hasSelectedDialogs()) { dialogsAdapter.addOrRemoveSelectedDialog(dialog_id, view); updateSelectedCount(); @@ -1408,6 +1417,9 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. if (dialogsType != 3 || selectAlertString != null) { return false; } + if (!validateSlowModeDialog(dialog.id)) { + return false; + } dialogsAdapter.addOrRemoveSelectedDialog(dialog.id, view); updateSelectedCount(); } else { @@ -1692,6 +1704,9 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. @Override public void didPressedOnSubDialog(long did) { if (onlySelect) { + if (!validateSlowModeDialog(did)) { + return; + } if (dialogsAdapter.hasSelectedDialogs()) { dialogsAdapter.addOrRemoveSelectedDialog(did, null); updateSelectedCount(); @@ -1891,6 +1906,11 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. public void needShowMediaBanHint() { } + + @Override + public void onUpdateSlowModeButton(View button, boolean show, CharSequence time) { + + } }); } @@ -2115,8 +2135,10 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. hideActionMode(false); if (folderId == 0) { SharedPreferences preferences = MessagesController.getGlobalMainSettings(); - boolean hintShowed = preferences.getBoolean("archivehint_l", false); - preferences.edit().putBoolean("archivehint_l", true).commit(); + boolean hintShowed = preferences.getBoolean("archivehint_l", false) || SharedConfig.archiveHidden; + if (!hintShowed) { + preferences.edit().putBoolean("archivehint_l", true).commit(); + } int undoAction; if (hintShowed) { undoAction = copy.size() > 1 ? UndoView.ACTION_ARCHIVE_FEW : UndoView.ACTION_ARCHIVE; @@ -2175,7 +2197,7 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. maxPinnedCount = getMessagesController().maxPinnedDialogsCount; } if (newPinnedSecretCount + pinnedSecretCount > maxPinnedCount || newPinnedCount + pinnedCount > maxPinnedCount) { - AlertsCreator.showSimpleToast(DialogsActivity.this, LocaleController.formatString("PinToTopLimitReached", R.string.PinToTopLimitReached, LocaleController.formatPluralString("Chats", maxPinnedCount))); + AlertsCreator.showSimpleAlert(DialogsActivity.this, LocaleController.formatString("PinToTopLimitReached", R.string.PinToTopLimitReached, LocaleController.formatPluralString("Chats", maxPinnedCount))); AndroidUtilities.shakeView(pinItem, 2, 0); Vibrator v = (Vibrator) getParentActivity().getSystemService(Context.VIBRATOR_SERVICE); if (v != null) { @@ -2506,6 +2528,22 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. } } + private boolean validateSlowModeDialog(long dialogId) { + if (messagesCount <= 1 && (commentView == null || commentView.getVisibility() != View.VISIBLE || TextUtils.isEmpty(commentView.getFieldText()))) { + return true; + } + int lowerId = (int) dialogId; + if (lowerId >= 0) { + return true; + } + TLRPC.Chat chat = getMessagesController().getChat(-lowerId); + if (chat != null && !ChatObject.hasAdminRights(chat) && chat.slowmode_enabled) { + AlertsCreator.showSimpleAlert(DialogsActivity.this, LocaleController.getString("Slowmode", R.string.Slowmode), LocaleController.getString("SlowmodeSendError", R.string.SlowmodeSendError)); + return false; + } + return true; + } + private void showOrUpdateActionMode(TLRPC.Dialog dialog, View cell) { dialogsAdapter.addOrRemoveSelectedDialog(dialog.id, cell); ArrayList selectedDialogs = dialogsAdapter.getSelectedDialogs(); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/LaunchActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/LaunchActivity.java index d98448761..786c41baa 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/LaunchActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/LaunchActivity.java @@ -8,6 +8,7 @@ package org.telegram.ui; +import android.Manifest; import android.app.Activity; import android.app.ActivityManager; import android.content.DialogInterface; @@ -576,7 +577,7 @@ public class LaunchActivity extends Activity implements ActionBarLayout.ActionBa } else { os2 = ""; } - if (BuildVars.DEBUG_VERSION) { + if (BuildVars.LOGS_ENABLED) { FileLog.d("OS name " + os1 + " " + os2); } if (os1.contains("flyme") || os2.contains("flyme")) { @@ -584,6 +585,7 @@ public class LaunchActivity extends Activity implements ActionBarLayout.ActionBa final View view = getWindow().getDecorView().getRootView(); view.getViewTreeObserver().addOnGlobalLayoutListener(onGlobalLayoutListener = () -> { int height = view.getMeasuredHeight(); + FileLog.d("height = " + height + " displayHeight = " + AndroidUtilities.displaySize.y); if (Build.VERSION.SDK_INT >= 21) { height -= AndroidUtilities.statusBarHeight; } @@ -759,7 +761,7 @@ public class LaunchActivity extends Activity implements ActionBarLayout.ActionBa } } - private void showUpdateActivity(int account, TLRPC.TL_help_appUpdate update) { + private void showUpdateActivity(int account, TLRPC.TL_help_appUpdate update, boolean check) { if (blockingUpdateView == null) { blockingUpdateView = new BlockingUpdateView(LaunchActivity.this) { @Override @@ -772,7 +774,7 @@ public class LaunchActivity extends Activity implements ActionBarLayout.ActionBa }; drawerLayoutContainer.addView(blockingUpdateView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); } - blockingUpdateView.show(account, update); + blockingUpdateView.show(account, update, check); drawerLayoutContainer.setAllowOpenDrawer(false, false); } @@ -2118,12 +2120,7 @@ public class LaunchActivity extends Activity implements ActionBarLayout.ActionBa if (response instanceof TLRPC.TL_help_appUpdate) { final TLRPC.TL_help_appUpdate res = (TLRPC.TL_help_appUpdate) response; AndroidUtilities.runOnUIThread(() -> { - if (BuildVars.DEBUG_PRIVATE_VERSION) { - res.popup = Utilities.random.nextBoolean(); - } - if (!res.popup) { - (new UpdateAppAlertDialog(LaunchActivity.this, res, accountNum)).show(); - } else { + if (res.can_not_skip) { UserConfig.getInstance(0).pendingAppUpdate = res; UserConfig.getInstance(0).pendingAppUpdateBuildVersion = BuildVars.BUILD_VERSION; try { @@ -2134,7 +2131,9 @@ public class LaunchActivity extends Activity implements ActionBarLayout.ActionBa UserConfig.getInstance(0).pendingAppUpdateInstallTime = 0; } UserConfig.getInstance(0).saveConfig(false); - showUpdateActivity(accountNum, res); + showUpdateActivity(accountNum, res, false); + } else { + (new UpdateAppAlertDialog(LaunchActivity.this, res, accountNum)).show(); } }); } @@ -2199,6 +2198,29 @@ public class LaunchActivity extends Activity implements ActionBarLayout.ActionBa int lower_part = (int) did; int high_id = (int) (did >> 32); + int attachesCount = 0; + if (contactsToSend != null) { + attachesCount += contactsToSend.size(); + } + if (videoPath != null) { + attachesCount++; + } + if (photoPathsArray != null) { + attachesCount += photoPathsArray.size(); + } + if (documentsPathsArray != null) { + attachesCount += documentsPathsArray.size(); + } + if (documentsUrisArray != null) { + attachesCount += documentsUrisArray.size(); + } + if (videoPath == null && photoPathsArray == null && documentsPathsArray == null && documentsUrisArray == null && sendingText != null) { + attachesCount++; + } + if (AlertsCreator.checkSlowMode(this, currentAccount, did, attachesCount > 1)) { + return; + } + Bundle args = new Bundle(); final int account = dialogsFragment != null ? dialogsFragment.getCurrentAccount() : currentAccount; args.putBoolean("scrollToTopOnResume", true); @@ -2357,51 +2379,48 @@ public class LaunchActivity extends Activity implements ActionBarLayout.ActionBa @Override public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); - if (requestCode == 3 || requestCode == 4 || requestCode == 5 || requestCode == 19 || requestCode == 20 || requestCode == 22) { - boolean showAlert = true; - if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { - if (requestCode == 4) { - ImageLoader.getInstance().checkMediaPaths(); - return; - } else if (requestCode == 5) { - ContactsController.getInstance(currentAccount).forceImportContacts(); - return; - } else if (requestCode == 3) { - if (SharedConfig.inappCamera) { - CameraController.getInstance().initCamera(null); - } - return; - } else if (requestCode == 19 || requestCode == 20 || requestCode == 22) { - showAlert = false; - } + + boolean granted = grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED; + + if (requestCode == 4) { + if (!granted) { + showPermissionErrorAlert(LocaleController.getString("PermissionStorage", R.string.PermissionStorage)); + } else { + ImageLoader.getInstance().checkMediaPaths(); } - if (showAlert) { - AlertDialog.Builder builder = new AlertDialog.Builder(this); - builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); - if (requestCode == 3) { - builder.setMessage(LocaleController.getString("PermissionNoAudio", R.string.PermissionNoAudio)); - } else if (requestCode == 4) { - builder.setMessage(LocaleController.getString("PermissionStorage", R.string.PermissionStorage)); - } else if (requestCode == 5) { - builder.setMessage(LocaleController.getString("PermissionContacts", R.string.PermissionContacts)); - } else if (requestCode == 19 || requestCode == 20 || requestCode == 22) { - builder.setMessage(LocaleController.getString("PermissionNoCamera", R.string.PermissionNoCamera)); - } - builder.setNegativeButton(LocaleController.getString("PermissionOpenSettings", R.string.PermissionOpenSettings), (dialog, which) -> { - try { - Intent intent = new Intent(android.provider.Settings.ACTION_APPLICATION_DETAILS_SETTINGS); - intent.setData(Uri.parse("package:" + ApplicationLoader.applicationContext.getPackageName())); - startActivity(intent); - } catch (Exception e) { - FileLog.e(e); - } - }); - builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), null); - builder.show(); + } else if (requestCode == 5) { + if (!granted) { + ContactsController.getInstance(currentAccount).forceImportContacts(); + } else { + showPermissionErrorAlert(LocaleController.getString("PermissionContacts", R.string.PermissionContacts)); return; } + } else if (requestCode == 3) { + boolean audioGranted = true; + boolean cameraGranted = true; + for (int i = 0, size = permissions.length; i < size; i++) { + if (Manifest.permission.RECORD_AUDIO.equals(permissions[i])) { + audioGranted = grantResults[i] == PackageManager.PERMISSION_GRANTED; + } else if (Manifest.permission.CAMERA.equals(permissions[i])) { + cameraGranted = grantResults[i] == PackageManager.PERMISSION_GRANTED; + } + } + if (!audioGranted) { + showPermissionErrorAlert(LocaleController.getString("PermissionNoAudio", R.string.PermissionNoAudio)); + } else if (!cameraGranted) { + showPermissionErrorAlert(LocaleController.getString("PermissionNoCamera", R.string.PermissionNoCamera)); + } else { + if (SharedConfig.inappCamera) { + CameraController.getInstance().initCamera(null); + } + return; + } + } else if (requestCode == 18 || requestCode == 19 || requestCode == 20 || requestCode == 22) { + if (!granted) { + showPermissionErrorAlert(LocaleController.getString("PermissionNoCamera", R.string.PermissionNoCamera)); + } } else if (requestCode == 2) { - if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { + if (granted) { NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.locationPermissionGranted); } } @@ -2421,9 +2440,27 @@ public class LaunchActivity extends Activity implements ActionBarLayout.ActionBa } } + private void showPermissionErrorAlert(String message) { + AlertDialog.Builder builder = new AlertDialog.Builder(this); + builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); + builder.setMessage(message); + builder.setNegativeButton(LocaleController.getString("PermissionOpenSettings", R.string.PermissionOpenSettings), (dialog, which) -> { + try { + Intent intent = new Intent(android.provider.Settings.ACTION_APPLICATION_DETAILS_SETTINGS); + intent.setData(Uri.parse("package:" + ApplicationLoader.applicationContext.getPackageName())); + startActivity(intent); + } catch (Exception e) { + FileLog.e(e); + } + }); + builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), null); + builder.show(); + } + @Override protected void onPause() { super.onPause(); + NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.stopAllHeavyOperations, 4096); SharedConfig.lastAppPauseTime = System.currentTimeMillis(); ApplicationLoader.mainInterfacePaused = true; Utilities.stageQueue.postRunnable(() -> { @@ -2512,7 +2549,12 @@ public class LaunchActivity extends Activity implements ActionBarLayout.ActionBa @Override protected void onResume() { - super.onResume(); + try { + super.onResume(); + } catch (Throwable e) { + FileLog.e(e); + } + NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.startAllHeavyOperations, 4096); MediaController.getInstance().setFeedbackView(actionBarLayout, true); ApplicationLoader.mainInterfacePaused = false; showLanguageAlert(false); @@ -2554,7 +2596,7 @@ public class LaunchActivity extends Activity implements ActionBarLayout.ActionBa if (UserConfig.getInstance(UserConfig.selectedAccount).unacceptedTermsOfService != null) { showTosActivity(UserConfig.selectedAccount, UserConfig.getInstance(UserConfig.selectedAccount).unacceptedTermsOfService); } else if (UserConfig.getInstance(0).pendingAppUpdate != null) { - showUpdateActivity(UserConfig.selectedAccount, UserConfig.getInstance(0).pendingAppUpdate); + showUpdateActivity(UserConfig.selectedAccount, UserConfig.getInstance(0).pendingAppUpdate, true); } checkAppUpdate(false); } @@ -2789,6 +2831,7 @@ public class LaunchActivity extends Activity implements ActionBarLayout.ActionBa } private void checkFreeDiscSpace() { + SharedConfig.checkKeepMedia(); if (Build.VERSION.SDK_INT >= 26) { return; } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/LoginActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/LoginActivity.java index 2259ec71d..7dc849d1e 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/LoginActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/LoginActivity.java @@ -16,7 +16,6 @@ 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; @@ -33,7 +32,6 @@ import android.os.Build; import android.os.Bundle; import android.os.Vibrator; import android.telephony.PhoneNumberUtils; -import android.telephony.SmsManager; import android.telephony.TelephonyManager; import android.text.Editable; import android.text.InputFilter; @@ -75,7 +73,6 @@ import org.telegram.messenger.FileLog; import org.telegram.messenger.LocaleController; import org.telegram.messenger.R; import org.telegram.messenger.SRPHelper; -import org.telegram.messenger.SmsReceiver; import org.telegram.tgnet.ConnectionsManager; import org.telegram.tgnet.RequestDelegate; import org.telegram.tgnet.SerializedData; @@ -678,16 +675,12 @@ public class LoginActivity extends BaseFragment { MessagesStorage.getInstance(currentAccount).putUsersAndChats(users, null, true, true); MessagesController.getInstance(currentAccount).putUser(res.user, false); ContactsController.getInstance(currentAccount).checkAppAccount(); - MessagesController.getInstance(currentAccount).getBlockedUsers(true); MessagesController.getInstance(currentAccount).checkProxyInfo(true); ConnectionsManager.getInstance(currentAccount).updateDcSettings(); needFinishActivity(); } private void fillNextCodeParams(Bundle params, TLRPC.TL_auth_sentCode res) { - if (res.terms_of_service != null) { - currentTermsOfService = res.terms_of_service; - } params.putString("phoneHash", res.phone_code_hash); if (res.next_type instanceof TLRPC.TL_auth_codeTypeCall) { params.putInt("nextType", 4); @@ -1069,21 +1062,25 @@ public class LoginActivity extends BaseFragment { try { TelephonyManager telephonyManager = (TelephonyManager) ApplicationLoader.applicationContext.getSystemService(Context.TELEPHONY_SERVICE); if (telephonyManager != null) { - country = telephonyManager.getSimCountryIso().toUpperCase(); + country = null;//telephonyManager.getSimCountryIso().toUpperCase(); } } catch (Exception e) { FileLog.e(e); } if (country != null) { - String countryName = languageMap.get(country); - if (countryName != null) { - int index = countriesArray.indexOf(countryName); - if (index != -1) { - codeField.setText(countriesMap.get(countryName)); - countryState = 0; + setCountry(languageMap, country.toUpperCase()); + } else { + TLRPC.TL_help_getNearestDc req = new TLRPC.TL_help_getNearestDc(); + getAccountInstance().getConnectionsManager().sendRequest(req, (response, error) -> AndroidUtilities.runOnUIThread(() -> { + if (response == null) { + return; } - } + TLRPC.TL_nearestDc res = (TLRPC.TL_nearestDc) response; + if (codeField.length() == 0) { + setCountry(languageMap, res.country.toUpperCase()); + } + }), ConnectionsManager.RequestFlagWithoutLogin | ConnectionsManager.RequestFlagFailOnServerErrors); } if (codeField.length() == 0) { countryButton.setText(LocaleController.getString("ChooseCountry", R.string.ChooseCountry)); @@ -1113,6 +1110,17 @@ public class LoginActivity extends BaseFragment { } } + private void setCountry(HashMap languageMap, String country) { + String countryName = languageMap.get(country); + if (countryName != null) { + int index = countriesArray.indexOf(countryName); + if (index != -1) { + codeField.setText(countriesMap.get(countryName)); + countryState = 0; + } + } + } + @Override public void onCancelPressed() { nextPressed = false; @@ -1147,9 +1155,12 @@ public class LoginActivity extends BaseFragment { int state = tm.getSimState(); boolean simcardAvailable = state != TelephonyManager.SIM_STATE_ABSENT && state != TelephonyManager.SIM_STATE_UNKNOWN && tm.getPhoneType() != TelephonyManager.PHONE_TYPE_NONE && !AndroidUtilities.isAirplaneModeOn(); boolean allowCall = true; + boolean allowCancelCall = true; + boolean allowReadCallLog = true; if (Build.VERSION.SDK_INT >= 23 && simcardAvailable) { allowCall = getParentActivity().checkSelfPermission(Manifest.permission.READ_PHONE_STATE) == PackageManager.PERMISSION_GRANTED; - boolean allowCancelCall = getParentActivity().checkSelfPermission(Manifest.permission.CALL_PHONE) == PackageManager.PERMISSION_GRANTED; + allowCancelCall = getParentActivity().checkSelfPermission(Manifest.permission.CALL_PHONE) == PackageManager.PERMISSION_GRANTED; + allowReadCallLog = Build.VERSION.SDK_INT < 28 || getParentActivity().checkSelfPermission(Manifest.permission.READ_CALL_LOG) == PackageManager.PERMISSION_GRANTED; if (checkPermissions) { permissionsItems.clear(); if (!allowCall) { @@ -1158,17 +1169,24 @@ public class LoginActivity extends BaseFragment { if (!allowCancelCall) { permissionsItems.add(Manifest.permission.CALL_PHONE); } + if (!allowReadCallLog) { + permissionsItems.add(Manifest.permission.READ_CALL_LOG); + } boolean ok = true; if (!permissionsItems.isEmpty()) { SharedPreferences preferences = MessagesController.getGlobalMainSettings(); - if (!allowCancelCall && allowCall) { - getParentActivity().requestPermissions(permissionsItems.toArray(new String[0]), 6); - } else if (preferences.getBoolean("firstlogin", true) || getParentActivity().shouldShowRequestPermissionRationale(Manifest.permission.READ_PHONE_STATE)) { + if (preferences.getBoolean("firstlogin", true) || getParentActivity().shouldShowRequestPermissionRationale(Manifest.permission.READ_PHONE_STATE) || getParentActivity().shouldShowRequestPermissionRationale(Manifest.permission.READ_CALL_LOG)) { preferences.edit().putBoolean("firstlogin", false).commit(); AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), null); - builder.setMessage(LocaleController.getString("AllowReadCall", R.string.AllowReadCall)); + if (!allowCall && (!allowCancelCall || !allowReadCallLog)) { + builder.setMessage(LocaleController.getString("AllowReadCallAndLog", R.string.AllowReadCallAndLog)); + } else if (!allowCancelCall || !allowReadCallLog) { + builder.setMessage(LocaleController.getString("AllowReadCallLog", R.string.AllowReadCallLog)); + } else { + builder.setMessage(LocaleController.getString("AllowReadCall", R.string.AllowReadCall)); + } permissionsDialog = showDialog(builder.create()); } else { try { @@ -1227,24 +1245,8 @@ public class LoginActivity extends BaseFragment { req.api_id = BuildVars.APP_ID; req.phone_number = phone; req.settings = new TLRPC.TL_codeSettings(); - req.settings.allow_flashcall = 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_flashcall = simcardAvailable && allowCall && allowCancelCall && allowReadCallLog; + req.settings.allow_app_hash = ApplicationLoader.hasPlayServices; if (req.settings.allow_flashcall) { try { String number = tm.getLine1Number(); @@ -1857,7 +1859,7 @@ public class LoginActivity extends BaseFragment { } else if (nextType == 2) { timeText.setText(LocaleController.formatString("SmsText", R.string.SmsText, 1, 0)); } - String callLogNumber = null; + String callLogNumber = isRestored ? AndroidUtilities.obtainLoginPhoneCall(pattern) : null; if (callLogNumber != null) { ignoreOnTextChange = true; codeField[0].setText(callLogNumber); @@ -2068,21 +2070,22 @@ public class LoginActivity extends BaseFragment { needHideProgress(false); destroyTimer(); destroyCodeTimer(); - onAuthSuccess((TLRPC.TL_auth_authorization) response); - } else { - lastError = error.text; - - if (error.text.contains("PHONE_NUMBER_UNOCCUPIED")) { - ok = true; - needHideProgress(false); + if (response instanceof TLRPC.TL_auth_authorizationSignUpRequired) { + TLRPC.TL_auth_authorizationSignUpRequired authorization = (TLRPC.TL_auth_authorizationSignUpRequired) response; + if (authorization.terms_of_service != null) { + currentTermsOfService = authorization.terms_of_service; + } Bundle params = new Bundle(); params.putString("phoneFormated", requestPhone); params.putString("phoneHash", phoneHash); params.putString("code", req.phone_code); setPage(5, true, params, false); - destroyTimer(); - destroyCodeTimer(); - } else if (error.text.contains("SESSION_PASSWORD_NEEDED")) { + } else { + onAuthSuccess((TLRPC.TL_auth_authorization) response); + } + } else { + lastError = error.text; + if (error.text.contains("SESSION_PASSWORD_NEEDED")) { ok = true; TLRPC.TL_account_getPassword req2 = new TLRPC.TL_account_getPassword(); ConnectionsManager.getInstance(currentAccount).sendRequest(req2, (response1, error1) -> AndroidUtilities.runOnUIThread(() -> { @@ -2591,7 +2594,7 @@ public class LoginActivity extends BaseFragment { return; } needHideProgress(false); - if (error == null) { + if (response instanceof TLRPC.TL_auth_authorization) { onAuthSuccess((TLRPC.TL_auth_authorization) response); } else { if (error.text.equals("PASSWORD_HASH_INVALID")) { @@ -2981,7 +2984,7 @@ public class LoginActivity extends BaseFragment { ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> AndroidUtilities.runOnUIThread(() -> { needHideProgress(false); nextPressed = false; - if (error == null) { + if (response instanceof TLRPC.TL_auth_authorization) { AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), (dialogInterface, i) -> onAuthSuccess((TLRPC.TL_auth_authorization) response)); builder.setMessage(LocaleController.getString("PasswordReset", R.string.PasswordReset)); @@ -3445,7 +3448,6 @@ public class LoginActivity extends BaseFragment { } nextPressed = true; TLRPC.TL_auth_signUp req = new TLRPC.TL_auth_signUp(); - req.phone_code = phoneCode; req.phone_code_hash = phoneHash; req.phone_number = requestPhone; req.first_name = firstNameField.getText().toString(); @@ -3454,7 +3456,7 @@ public class LoginActivity extends BaseFragment { ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> AndroidUtilities.runOnUIThread(() -> { nextPressed = false; needHideProgress(false); - if (error == null) { + if (response instanceof TLRPC.TL_auth_authorization) { onAuthSuccess((TLRPC.TL_auth_authorization) response); if (avatarBig != null) { MessagesController.getInstance(currentAccount).uploadAndApplyUserAvatar(avatarBig); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/MediaActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/MediaActivity.java index e271187f8..0da9347ef 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/MediaActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/MediaActivity.java @@ -128,7 +128,6 @@ public class MediaActivity extends BaseFragment implements NotificationCenter.No private Drawable pinnedHeaderShadowDrawable; private boolean ignoreSearchCollapse; private NumberTextView selectedMessagesCountTextView; - private ActionBarPopupWindow.ActionBarPopupWindowLayout popupLayout; private ArrayList cellCache = new ArrayList<>(10); private ArrayList cache = new ArrayList<>(10); private ArrayList audioCellCache = new ArrayList<>(10); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/NotificationsSettingsActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/NotificationsSettingsActivity.java index fe17a769d..116d587e9 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/NotificationsSettingsActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/NotificationsSettingsActivity.java @@ -384,6 +384,9 @@ public class NotificationsSettingsActivity extends BaseFragment implements Notif type = NotificationsController.TYPE_CHANNEL; exceptions = exceptionChannels; } + if (exceptions == null) { + return; + } NotificationsCheckCell checkCell = (NotificationsCheckCell) view; enabled = NotificationsController.getInstance(currentAccount).isGlobalNotificationsEnabled(type); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/PassportActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/PassportActivity.java index fb69b3299..78ec5cbc4 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/PassportActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/PassportActivity.java @@ -8,10 +8,8 @@ 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.content.pm.PackageManager; import android.graphics.Bitmap; @@ -30,7 +28,6 @@ import android.provider.MediaStore; import androidx.core.content.FileProvider; import android.telephony.PhoneNumberUtils; -import android.telephony.SmsManager; import android.telephony.TelephonyManager; import android.text.Editable; import android.text.InputFilter; @@ -70,7 +67,6 @@ import org.telegram.PhoneFormat.PhoneFormat; import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.ApplicationLoader; import org.telegram.messenger.BuildConfig; -import org.telegram.messenger.BuildVars; import org.telegram.messenger.DownloadController; import org.telegram.messenger.FileLoader; import org.telegram.messenger.FileLog; @@ -87,7 +83,6 @@ import org.telegram.messenger.SecureDocument; import org.telegram.messenger.SecureDocumentKey; import org.telegram.messenger.SendMessagesHelper; import org.telegram.messenger.SharedConfig; -import org.telegram.messenger.SmsReceiver; import org.telegram.messenger.UserConfig; import org.telegram.messenger.UserObject; import org.telegram.messenger.Utilities; @@ -6281,23 +6276,7 @@ public class PassportActivity extends BaseFragment implements NotificationCenter req.phone_number = phone; req.settings = new TLRPC.TL_codeSettings(); req.settings.allow_flashcall = 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") @@ -6807,7 +6786,7 @@ public class PassportActivity extends BaseFragment implements NotificationCenter } createChatAttachView(); chatAttachAlert.setOpenWithFrontFaceCamera(uploadingFileType == UPLOADING_TYPE_SELFIE); - chatAttachAlert.setMaxSelectedPhotos(getMaxSelectedDocuments()); + chatAttachAlert.setMaxSelectedPhotos(getMaxSelectedDocuments(), false); chatAttachAlert.loadGalleryPhotos(); if (Build.VERSION.SDK_INT == 21 || Build.VERSION.SDK_INT == 22) { AndroidUtilities.hideKeyboard(fragmentView.findFocus()); @@ -6825,7 +6804,7 @@ public class PassportActivity extends BaseFragment implements NotificationCenter chatAttachAlert.setDelegate(new ChatAttachAlert.ChatAttachViewDelegate() { @Override - public void didPressedButton(int button) { + public void didPressedButton(int button, boolean arg) { if (getParentActivity() == null || chatAttachAlert == null) { return; } @@ -6874,8 +6853,8 @@ public class PassportActivity extends BaseFragment implements NotificationCenter } @Override - public boolean allowGroupPhotos() { - return false; + public void needEnterComment() { + } }); } @@ -6921,7 +6900,7 @@ public class PassportActivity extends BaseFragment implements NotificationCenter } PhotoAlbumPickerActivity fragment = new PhotoAlbumPickerActivity(0, false, false, null); fragment.setCurrentAccount(currentAccount); - fragment.setMaxSelectedPhotos(getMaxSelectedDocuments()); + fragment.setMaxSelectedPhotos(getMaxSelectedDocuments(), false); fragment.setAllowSearchImages(false); fragment.setDelegate(new PhotoAlbumPickerActivity.PhotoAlbumPickerActivityDelegate() { @Override diff --git a/TMessagesProj/src/main/java/org/telegram/ui/PaymentFormActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/PaymentFormActivity.java index 6264c87c6..2738bd8b3 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/PaymentFormActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/PaymentFormActivity.java @@ -3033,7 +3033,7 @@ public class PaymentFormActivity extends BaseFragment implements NotificationCen if (response instanceof TLRPC.TL_payments_paymentResult) { MessagesController.getInstance(currentAccount).processUpdates(((TLRPC.TL_payments_paymentResult) response).updates, false); AndroidUtilities.runOnUIThread(this::goToNextStep); - } else if (response instanceof TLRPC.TL_payments_paymentVerficationNeeded) { + } else if (response instanceof TLRPC.TL_payments_paymentVerificationNeeded) { AndroidUtilities.runOnUIThread(() -> { NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.paymentFinished); setDonePressed(false); @@ -3043,7 +3043,7 @@ public class PaymentFormActivity extends BaseFragment implements NotificationCen progressView.setVisibility(View.VISIBLE); doneItem.setEnabled(false); doneItem.getContentView().setVisibility(View.INVISIBLE); - webView.loadUrl(webViewUrl = ((TLRPC.TL_payments_paymentVerficationNeeded) response).url); + webView.loadUrl(webViewUrl = ((TLRPC.TL_payments_paymentVerificationNeeded) response).url); }); } } else { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/PhotoAlbumPickerActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/PhotoAlbumPickerActivity.java index f3b754852..9723d13a6 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/PhotoAlbumPickerActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/PhotoAlbumPickerActivity.java @@ -10,6 +10,7 @@ package org.telegram.ui; import android.app.Activity; import android.content.Context; +import android.graphics.drawable.Drawable; import android.view.Gravity; import android.view.Surface; import android.view.View; @@ -31,8 +32,8 @@ import org.telegram.ui.ActionBar.ActionBar; import org.telegram.ui.ActionBar.ActionBarMenu; import org.telegram.ui.ActionBar.BaseFragment; import org.telegram.ui.ActionBar.Theme; +import org.telegram.ui.ActionBar.ThemeDescription; import org.telegram.ui.Cells.PhotoPickerAlbumsCell; -import org.telegram.ui.Cells.PhotoPickerSearchCell; import org.telegram.ui.Components.LayoutHelper; import org.telegram.ui.Components.PickerBottomLayout; import org.telegram.ui.Components.RadialProgressView; @@ -48,6 +49,7 @@ public class PhotoAlbumPickerActivity extends BaseFragment implements Notificati public interface PhotoAlbumPickerActivityDelegate { void didSelectPhotos(ArrayList photos); + void startPhotoSelectActivity(); } @@ -66,6 +68,7 @@ public class PhotoAlbumPickerActivity extends BaseFragment implements Notificati private RecyclerListView listView; private ListAdapter listAdapter; private FrameLayout progressView; + private View shadowView; private TextView emptyView; private PickerBottomLayout pickerBottomLayout; private boolean sendPressed; @@ -75,6 +78,7 @@ public class PhotoAlbumPickerActivity extends BaseFragment implements Notificati private boolean allowCaption; private ChatActivity chatActivity; private int maxSelectedPhotos; + private boolean allowOrder = true; private PhotoAlbumPickerActivityDelegate delegate; @@ -88,7 +92,12 @@ public class PhotoAlbumPickerActivity extends BaseFragment implements Notificati @Override public boolean onFragmentCreate() { - loading = true; + if (selectPhotoType != 0 || !allowSearchImages) { + albumsSorted = MediaController.allPhotoAlbums; + } else { + albumsSorted = MediaController.allMediaAlbums; + } + loading = albumsSorted == null; MediaController.loadGalleryPhotosAlbums(classGuid); NotificationCenter.getInstance(currentAccount).addObserver(this, NotificationCenter.albumsDidLoad); NotificationCenter.getInstance(currentAccount).addObserver(this, NotificationCenter.recentImagesDidLoad); @@ -106,10 +115,10 @@ public class PhotoAlbumPickerActivity extends BaseFragment implements Notificati @Override public View createView(Context context) { - actionBar.setBackgroundColor(Theme.ACTION_BAR_MEDIA_PICKER_COLOR); - actionBar.setTitleColor(0xffffffff); - actionBar.setItemsColor(0xffffffff, false); - actionBar.setItemsBackgroundColor(Theme.ACTION_BAR_PICKER_SELECTOR_COLOR, false); + actionBar.setBackgroundColor(Theme.getColor(Theme.key_dialogBackground)); + actionBar.setTitleColor(Theme.getColor(Theme.key_dialogTextBlack)); + actionBar.setItemsColor(Theme.getColor(Theme.key_dialogTextBlack), false); + actionBar.setItemsBackgroundColor(Theme.getColor(Theme.key_dialogButtonSelector), false); actionBar.setBackButtonImage(R.drawable.ic_ab_back); actionBar.setActionBarMenuOnItemClick(new ActionBar.ActionBarMenuOnItemClick() { @Override @@ -121,17 +130,22 @@ public class PhotoAlbumPickerActivity extends BaseFragment implements Notificati finishFragment(false); delegate.startPhotoSelectActivity(); } + } else if (id == 2) { + openPhotoPicker(null, 0); } } }); ActionBarMenu menu = actionBar.createMenu(); + if (allowSearchImages) { + menu.addItem(2, R.drawable.ic_ab_search).setContentDescription(LocaleController.getString("Search", R.string.Search)); + } menu.addItem(1, R.drawable.ic_ab_other).setContentDescription(LocaleController.getString("AccDescrMoreOptions", R.string.AccDescrMoreOptions)); fragmentView = new FrameLayout(context); FrameLayout frameLayout = (FrameLayout) fragmentView; - frameLayout.setBackgroundColor(0xff000000); + frameLayout.setBackgroundColor(Theme.getColor(Theme.key_dialogBackground)); actionBar.setTitle(LocaleController.getString("Gallery", R.string.Gallery)); @@ -142,14 +156,9 @@ public class PhotoAlbumPickerActivity extends BaseFragment implements Notificati listView.setVerticalScrollBarEnabled(false); listView.setLayoutManager(new LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false)); listView.setDrawingCacheEnabled(false); - frameLayout.addView(listView); - FrameLayout.LayoutParams layoutParams = (FrameLayout.LayoutParams) listView.getLayoutParams(); - layoutParams.width = LayoutHelper.MATCH_PARENT; - layoutParams.height = LayoutHelper.MATCH_PARENT; - layoutParams.bottomMargin = AndroidUtilities.dp(48); - listView.setLayoutParams(layoutParams); + frameLayout.addView(listView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.LEFT | Gravity.TOP, 0, 0, 0, 48)); listView.setAdapter(listAdapter = new ListAdapter(context)); - listView.setGlowColor(0xff333333); + listView.setGlowColor(Theme.getColor(Theme.key_dialogBackground)); emptyView = new TextView(context); emptyView.setTextColor(0xff808080); @@ -157,38 +166,23 @@ public class PhotoAlbumPickerActivity extends BaseFragment implements Notificati emptyView.setGravity(Gravity.CENTER); emptyView.setVisibility(View.GONE); emptyView.setText(LocaleController.getString("NoPhotos", R.string.NoPhotos)); - frameLayout.addView(emptyView); - layoutParams = (FrameLayout.LayoutParams) emptyView.getLayoutParams(); - layoutParams.width = LayoutHelper.MATCH_PARENT; - layoutParams.height = LayoutHelper.MATCH_PARENT; - layoutParams.bottomMargin = AndroidUtilities.dp(48); - emptyView.setLayoutParams(layoutParams); + frameLayout.addView(emptyView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.LEFT | Gravity.TOP, 0, 0, 0, 48)); emptyView.setOnTouchListener((v, event) -> true); progressView = new FrameLayout(context); progressView.setVisibility(View.GONE); - frameLayout.addView(progressView); - layoutParams = (FrameLayout.LayoutParams) progressView.getLayoutParams(); - layoutParams.width = LayoutHelper.MATCH_PARENT; - layoutParams.height = LayoutHelper.MATCH_PARENT; - layoutParams.bottomMargin = AndroidUtilities.dp(48); - progressView.setLayoutParams(layoutParams); + frameLayout.addView(progressView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.LEFT | Gravity.TOP, 0, 0, 0, 48)); RadialProgressView progressBar = new RadialProgressView(context); - progressView.addView(progressBar); - layoutParams = (FrameLayout.LayoutParams) progressView.getLayoutParams(); - layoutParams.width = LayoutHelper.WRAP_CONTENT; - layoutParams.height = LayoutHelper.WRAP_CONTENT; - layoutParams.gravity = Gravity.CENTER; - progressView.setLayoutParams(layoutParams); + progressBar.setProgressColor(0xff527da3); + progressView.addView(progressBar, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER)); + + shadowView = new View(context); + shadowView.setBackgroundColor(Theme.getColor(Theme.key_dialogShadowLine)); + frameLayout.addView(shadowView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 1, Gravity.LEFT | Gravity.BOTTOM, 0, 0, 0, 48)); pickerBottomLayout = new PickerBottomLayout(context); - frameLayout.addView(pickerBottomLayout); - layoutParams = (FrameLayout.LayoutParams) pickerBottomLayout.getLayoutParams(); - layoutParams.width = LayoutHelper.MATCH_PARENT; - layoutParams.height = AndroidUtilities.dp(48); - layoutParams.gravity = Gravity.BOTTOM; - pickerBottomLayout.setLayoutParams(layoutParams); + frameLayout.addView(pickerBottomLayout, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 48, Gravity.LEFT | Gravity.BOTTOM)); pickerBottomLayout.cancelButton.setOnClickListener(view -> finishFragment()); pickerBottomLayout.doneButton.setOnClickListener(view -> { sendSelectedPhotos(selectedPhotos, selectedPhotosOrder); @@ -264,8 +258,9 @@ public class PhotoAlbumPickerActivity extends BaseFragment implements Notificati } } - public void setMaxSelectedPhotos(int value) { + public void setMaxSelectedPhotos(int value, boolean order) { maxSelectedPhotos = value; + allowOrder = order; } public void setAllowSearchImages(boolean value) { @@ -389,10 +384,8 @@ public class PhotoAlbumPickerActivity extends BaseFragment implements Notificati recentImages = recentGifImages; } } - - PhotoPickerActivity fragment; if (albumEntry != null) { - fragment = new PhotoPickerActivity(type, albumEntry, selectedPhotos, selectedPhotosOrder, recentImages, selectPhotoType, allowCaption, chatActivity); + PhotoPickerActivity fragment = new PhotoPickerActivity(type, albumEntry, selectedPhotos, selectedPhotosOrder, recentImages, selectPhotoType, allowCaption, chatActivity); fragment.setDelegate(new PhotoPickerActivity.PhotoPickerActivityDelegate() { @Override public void selectedPhotosChanged() { @@ -409,27 +402,49 @@ public class PhotoAlbumPickerActivity extends BaseFragment implements Notificati } } }); + fragment.setMaxSelectedPhotos(maxSelectedPhotos, allowOrder); + presentFragment(fragment); } else { final HashMap photos = new HashMap<>(); final ArrayList order = new ArrayList<>(); - fragment = new PhotoPickerActivity(type, albumEntry, photos, order, recentImages, selectPhotoType, allowCaption, chatActivity); - fragment.setDelegate(new PhotoPickerActivity.PhotoPickerActivityDelegate() { - @Override - public void selectedPhotosChanged() { + if (allowGifs) { + PhotoPickerSearchActivity fragment = new PhotoPickerSearchActivity(photos, order, recentImages, selectPhotoType, allowCaption, chatActivity); + fragment.setDelegate(new PhotoPickerActivity.PhotoPickerActivityDelegate() { + @Override + public void selectedPhotosChanged() { - } - - @Override - public void actionButtonPressed(boolean canceled) { - removeSelfFromStack(); - if (!canceled) { - sendSelectedPhotos(photos, order); } - } - }); + + @Override + public void actionButtonPressed(boolean canceled) { + removeSelfFromStack(); + if (!canceled) { + sendSelectedPhotos(photos, order); + } + } + }); + fragment.setMaxSelectedPhotos(maxSelectedPhotos, allowOrder); + presentFragment(fragment); + } else { + PhotoPickerActivity fragment = new PhotoPickerActivity(0, albumEntry, photos, order, recentImages, selectPhotoType, allowCaption, chatActivity); + fragment.setDelegate(new PhotoPickerActivity.PhotoPickerActivityDelegate() { + @Override + public void selectedPhotosChanged() { + + } + + @Override + public void actionButtonPressed(boolean canceled) { + removeSelfFromStack(); + if (!canceled) { + sendSelectedPhotos(photos, order); + } + } + }); + fragment.setMaxSelectedPhotos(maxSelectedPhotos, allowOrder); + presentFragment(fragment); + } } - fragment.setMaxSelectedPhotos(maxSelectedPhotos); - presentFragment(fragment); } private class ListAdapter extends RecyclerListView.SelectionAdapter { @@ -447,65 +462,61 @@ public class PhotoAlbumPickerActivity extends BaseFragment implements Notificati @Override public int getItemCount() { - if (!allowSearchImages) { - return albumsSorted != null ? (int) Math.ceil(albumsSorted.size() / (float) columnsCount) : 0; - } - return 1 + (albumsSorted != null ? (int) Math.ceil(albumsSorted.size() / (float) columnsCount) : 0); + return albumsSorted != null ? (int) Math.ceil(albumsSorted.size() / (float) columnsCount) : 0; } @Override public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { - View view; - switch (viewType) { - case 0: { - PhotoPickerAlbumsCell cell = new PhotoPickerAlbumsCell(mContext); - cell.setDelegate(albumEntry -> openPhotoPicker(albumEntry, 0)); - view = cell; - break; - } - case 1: - default: { - PhotoPickerSearchCell cell = new PhotoPickerSearchCell(mContext, allowGifs); - cell.setDelegate(index -> openPhotoPicker(null, index)); - view = cell; - break; - } - } - return new RecyclerListView.Holder(view); + PhotoPickerAlbumsCell cell = new PhotoPickerAlbumsCell(mContext); + cell.setDelegate(albumEntry -> openPhotoPicker(albumEntry, 0)); + return new RecyclerListView.Holder(cell); } @Override public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { - if (holder.getItemViewType() == 0) { - PhotoPickerAlbumsCell photoPickerAlbumsCell = (PhotoPickerAlbumsCell) holder.itemView; - photoPickerAlbumsCell.setAlbumsCount(columnsCount); - for (int a = 0; a < columnsCount; a++) { - int index; - if (!allowSearchImages) { - index = position * columnsCount + a; - } else { - index = (position - 1) * columnsCount + a; - } - if (index < albumsSorted.size()) { - MediaController.AlbumEntry albumEntry = albumsSorted.get(index); - photoPickerAlbumsCell.setAlbum(a, albumEntry); - } else { - photoPickerAlbumsCell.setAlbum(a, null); - } + PhotoPickerAlbumsCell photoPickerAlbumsCell = (PhotoPickerAlbumsCell) holder.itemView; + photoPickerAlbumsCell.setAlbumsCount(columnsCount); + for (int a = 0; a < columnsCount; a++) { + int index = position * columnsCount + a; + if (index < albumsSorted.size()) { + MediaController.AlbumEntry albumEntry = albumsSorted.get(index); + photoPickerAlbumsCell.setAlbum(a, albumEntry); + } else { + photoPickerAlbumsCell.setAlbum(a, null); } - photoPickerAlbumsCell.requestLayout(); } + photoPickerAlbumsCell.requestLayout(); } @Override public int getItemViewType(int i) { - if (!allowSearchImages) { - return 0; - } - if (i == 0) { - return 1; - } return 0; } } + + @Override + public ThemeDescription[] getThemeDescriptions() { + return new ThemeDescription[]{ + new ThemeDescription(fragmentView, ThemeDescription.FLAG_BACKGROUND, null, null, null, null, Theme.key_dialogBackground), + + new ThemeDescription(actionBar, ThemeDescription.FLAG_BACKGROUND, null, null, null, null, Theme.key_dialogBackground), + new ThemeDescription(actionBar, ThemeDescription.FLAG_AB_ITEMSCOLOR, null, null, null, null, Theme.key_dialogTextBlack), + new ThemeDescription(actionBar, ThemeDescription.FLAG_AB_TITLECOLOR, null, null, null, null, Theme.key_dialogTextBlack), + new ThemeDescription(actionBar, ThemeDescription.FLAG_AB_SELECTORCOLOR, null, null, null, null, Theme.key_dialogButtonSelector), + + new ThemeDescription(listView, ThemeDescription.FLAG_LISTGLOWCOLOR, null, null, null, null, Theme.key_dialogBackground), + + new ThemeDescription(shadowView, ThemeDescription.FLAG_BACKGROUND, null, null, null, null, Theme.key_dialogShadowLine), + + new ThemeDescription(pickerBottomLayout, ThemeDescription.FLAG_BACKGROUND, null, null, null, null, Theme.key_dialogBackground), + new ThemeDescription(pickerBottomLayout, ThemeDescription.FLAG_TEXTCOLOR, new Class[]{PickerBottomLayout.class}, new String[]{"cancelButton"}, null, null, null, Theme.key_picker_enabledButton), + new ThemeDescription(pickerBottomLayout, ThemeDescription.FLAG_TEXTCOLOR | ThemeDescription.FLAG_CHECKTAG, new Class[]{PickerBottomLayout.class}, new String[]{"doneButtonTextView"}, null, null, null, Theme.key_picker_enabledButton), + new ThemeDescription(pickerBottomLayout, ThemeDescription.FLAG_TEXTCOLOR | ThemeDescription.FLAG_CHECKTAG, new Class[]{PickerBottomLayout.class}, new String[]{"doneButtonTextView"}, null, null, null, Theme.key_picker_disabledButton), + new ThemeDescription(pickerBottomLayout, ThemeDescription.FLAG_TEXTCOLOR, new Class[]{PickerBottomLayout.class}, new String[]{"doneButtonBadgeTextView"}, null, null, null, Theme.key_picker_badgeText), + new ThemeDescription(pickerBottomLayout, ThemeDescription.FLAG_USEBACKGROUNDDRAWABLE, new Class[]{PickerBottomLayout.class}, new String[]{"doneButtonBadgeTextView"}, null, null, null, Theme.key_picker_badge), + + new ThemeDescription(listView, 0, new Class[]{View.class}, null, new Drawable[]{Theme.chat_attachEmptyDrawable}, null, Theme.key_chat_attachEmptyImage), + new ThemeDescription(listView, 0, new Class[]{View.class}, null, null, null, Theme.key_chat_attachPhotoBackground), + }; + } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/PhotoPickerActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/PhotoPickerActivity.java index 1e3f9af2b..ecc8b9e49 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/PhotoPickerActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/PhotoPickerActivity.java @@ -8,18 +8,12 @@ package org.telegram.ui; -import android.animation.Animator; -import android.animation.AnimatorListenerAdapter; -import android.animation.AnimatorSet; -import android.animation.ObjectAnimator; import android.app.Activity; import android.content.Context; -import android.graphics.PorterDuff; -import android.graphics.PorterDuffColorFilter; import android.graphics.Rect; +import android.graphics.drawable.Drawable; import android.os.Build; import android.text.TextUtils; -import android.util.TypedValue; import android.view.Gravity; import android.view.Surface; import android.view.View; @@ -28,10 +22,9 @@ import android.view.ViewTreeObserver; import android.view.WindowManager; import android.widget.EditText; import android.widget.FrameLayout; -import android.widget.ImageView; -import android.widget.TextView; import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.ChatObject; import org.telegram.messenger.FileLoader; import org.telegram.messenger.ImageReceiver; import org.telegram.messenger.LocaleController; @@ -39,7 +32,6 @@ import org.telegram.messenger.MediaController; import org.telegram.messenger.MessagesController; import org.telegram.messenger.MessagesStorage; import org.telegram.messenger.NotificationCenter; -import org.telegram.messenger.SharedConfig; import org.telegram.messenger.VideoEditedInfo; import org.telegram.messenger.ApplicationLoader; import org.telegram.messenger.R; @@ -50,11 +42,14 @@ import org.telegram.messenger.MessageObject; import org.telegram.ui.ActionBar.ActionBarMenu; import org.telegram.ui.ActionBar.ActionBarMenuItem; import org.telegram.ui.ActionBar.AlertDialog; -import org.telegram.ui.ActionBar.Theme; import org.telegram.ui.ActionBar.ActionBar; import org.telegram.ui.ActionBar.BaseFragment; +import org.telegram.ui.ActionBar.Theme; +import org.telegram.ui.ActionBar.ThemeDescription; import org.telegram.ui.Cells.PhotoPickerPhotoCell; +import org.telegram.ui.Components.AlertsCreator; import org.telegram.ui.Components.BackupImageView; +import org.telegram.ui.Components.EditTextBoldCursor; import org.telegram.ui.Components.EmptyTextProgressView; import org.telegram.ui.Components.LayoutHelper; import org.telegram.ui.Components.PickerBottomLayout; @@ -84,10 +79,6 @@ public class PhotoPickerActivity extends BaseFragment implements NotificationCen private HashMap searchResultKeys = new HashMap<>(); private HashMap searchResultUrls = new HashMap<>(); - private TextView hintTextView; - private Runnable hintHideRunnable; - private AnimatorSet hintAnimation; - private boolean searching; private boolean imageSearchEndReached = true; private String lastSearchString; @@ -100,6 +91,7 @@ public class PhotoPickerActivity extends BaseFragment implements NotificationCen private String lastSearchImageString; private int maxSelectedPhotos; + private boolean allowOrder = true; private MediaController.AlbumEntry selectedAlbum; @@ -107,10 +99,9 @@ public class PhotoPickerActivity extends BaseFragment implements NotificationCen private ListAdapter listAdapter; private GridLayoutManager layoutManager; private PickerBottomLayout pickerBottomLayout; - private ImageView imageOrderToggleButton; private EmptyTextProgressView emptyView; + private View shadowView; private ActionBarMenuItem searchItem; - private FrameLayout frameLayout; private int itemWidth = 100; private boolean sendPressed; private int selectPhotoType; @@ -118,6 +109,8 @@ public class PhotoPickerActivity extends BaseFragment implements NotificationCen private String initialSearchString; + private boolean needsBottomLayout = true; + private PhotoPickerActivityDelegate delegate; private PhotoViewer.PhotoViewerProvider provider = new PhotoViewer.EmptyPhotoViewerProvider() { @@ -131,14 +124,14 @@ public class PhotoPickerActivity extends BaseFragment implements NotificationCen PhotoPickerPhotoCell cell = getCellForIndex(index); if (cell != null) { int[] coords = new int[2]; - cell.photoImage.getLocationInWindow(coords); + cell.imageView.getLocationInWindow(coords); PhotoViewer.PlaceProviderObject object = new PhotoViewer.PlaceProviderObject(); object.viewX = coords[0]; object.viewY = coords[1] - (Build.VERSION.SDK_INT >= 21 ? 0 : AndroidUtilities.statusBarHeight); object.parentView = listView; - object.imageReceiver = cell.photoImage.getImageReceiver(); + object.imageReceiver = cell.imageView.getImageReceiver(); object.thumb = object.imageReceiver.getBitmapSafe(); - object.scale = cell.photoImage.getScaleX(); + object.scale = cell.imageView.getScaleX(); cell.showCheck(false); return object; } @@ -150,19 +143,19 @@ public class PhotoPickerActivity extends BaseFragment implements NotificationCen PhotoPickerPhotoCell cell = getCellForIndex(index); if (cell != null) { if (selectedAlbum != null) { - cell.photoImage.setOrientation(0, true); + cell.imageView.setOrientation(0, true); MediaController.PhotoEntry photoEntry = selectedAlbum.photos.get(index); if (photoEntry.thumbPath != null) { - cell.photoImage.setImage(photoEntry.thumbPath, null, cell.getContext().getResources().getDrawable(R.drawable.nophotos)); + cell.imageView.setImage(photoEntry.thumbPath, null, Theme.chat_attachEmptyDrawable); } else if (photoEntry.path != null) { - cell.photoImage.setOrientation(photoEntry.orientation, true); + cell.imageView.setOrientation(photoEntry.orientation, true); if (photoEntry.isVideo) { - cell.photoImage.setImage("vthumb://" + photoEntry.imageId + ":" + photoEntry.path, null, cell.getContext().getResources().getDrawable(R.drawable.nophotos)); + cell.imageView.setImage("vthumb://" + photoEntry.imageId + ":" + photoEntry.path, null, Theme.chat_attachEmptyDrawable); } else { - cell.photoImage.setImage("thumb://" + photoEntry.imageId + ":" + photoEntry.path, null, cell.getContext().getResources().getDrawable(R.drawable.nophotos)); + cell.imageView.setImage("thumb://" + photoEntry.imageId + ":" + photoEntry.path, null, Theme.chat_attachEmptyDrawable); } } else { - cell.photoImage.setImageResource(R.drawable.nophotos); + cell.imageView.setImageDrawable(Theme.chat_attachEmptyDrawable); } } else { ArrayList array; @@ -185,7 +178,7 @@ public class PhotoPickerActivity extends BaseFragment implements NotificationCen public ImageReceiver.BitmapHolder getThumbForPhoto(MessageObject messageObject, TLRPC.FileLocation fileLocation, int index) { PhotoPickerPhotoCell cell = getCellForIndex(index); if (cell != null) { - return cell.photoImage.getImageReceiver().getBitmapSafe(); + return cell.imageView.getImageReceiver().getBitmapSafe(); } return null; } @@ -359,13 +352,6 @@ public class PhotoPickerActivity extends BaseFragment implements NotificationCen sendSelectedPhotos(); } - @Override - public void toggleGroupPhotosEnabled() { - if (imageOrderToggleButton != null) { - imageOrderToggleButton.setColorFilter(SharedConfig.groupPhotosEnabled ? new PorterDuffColorFilter(0xff66bffa, PorterDuff.Mode.MULTIPLY) : null); - } - } - @Override public ArrayList getSelectedPhotosOrder() { return selectedPhotosOrder; @@ -375,11 +361,6 @@ public class PhotoPickerActivity extends BaseFragment implements NotificationCen public HashMap getSelectedPhotos() { return selectedPhotos; } - - @Override - public boolean allowGroupPhotos() { - return imageOrderToggleButton != null; - } }; public PhotoPickerActivity(int type, MediaController.AlbumEntry selectedAlbum, HashMap selectedPhotos, ArrayList selectedPhotosOrder, ArrayList recentImages, int selectPhotoType, boolean allowCaption, ChatActivity chatActivity) { @@ -421,10 +402,10 @@ public class PhotoPickerActivity extends BaseFragment implements NotificationCen @SuppressWarnings("unchecked") @Override public View createView(Context context) { - actionBar.setBackgroundColor(Theme.ACTION_BAR_MEDIA_PICKER_COLOR); - actionBar.setItemsBackgroundColor(Theme.ACTION_BAR_PICKER_SELECTOR_COLOR, false); - actionBar.setTitleColor(0xffffffff); - actionBar.setItemsColor(0xffffffff, false); + actionBar.setBackgroundColor(Theme.getColor(Theme.key_dialogBackground)); + actionBar.setTitleColor(Theme.getColor(Theme.key_dialogTextBlack)); + actionBar.setItemsColor(Theme.getColor(Theme.key_dialogTextBlack), false); + actionBar.setItemsBackgroundColor(Theme.getColor(Theme.key_dialogButtonSelector), false); actionBar.setBackButtonImage(R.drawable.ic_ab_back); if (selectedAlbum != null) { actionBar.setTitle(selectedAlbum.bucketName); @@ -483,6 +464,10 @@ public class PhotoPickerActivity extends BaseFragment implements NotificationCen processSearch(editText); } }); + EditTextBoldCursor editText = searchItem.getSearchField(); + editText.setTextColor(Theme.getColor(Theme.key_dialogTextBlack)); + editText.setCursorColor(Theme.getColor(Theme.key_dialogTextBlack)); + editText.setHintTextColor(Theme.getColor(Theme.key_chat_messagePanelHint)); } if (selectedAlbum == null) { @@ -493,10 +478,9 @@ public class PhotoPickerActivity extends BaseFragment implements NotificationCen } } - fragmentView = new FrameLayout(context); - - frameLayout = (FrameLayout) fragmentView; - frameLayout.setBackgroundColor(0xff000000); + FrameLayout frameLayout = new FrameLayout(context); + frameLayout.setBackgroundColor(Theme.getColor(Theme.key_dialogBackground)); + fragmentView = frameLayout; listView = new RecyclerListView(context); listView.setPadding(AndroidUtilities.dp(4), AndroidUtilities.dp(4), AndroidUtilities.dp(4), AndroidUtilities.dp(4)); @@ -527,7 +511,7 @@ public class PhotoPickerActivity extends BaseFragment implements NotificationCen }); frameLayout.addView(listView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.LEFT | Gravity.TOP, 0, 0, 0, selectPhotoType != 0 ? 0 : 48)); listView.setAdapter(listAdapter = new ListAdapter(context)); - listView.setGlowColor(0xff333333); + listView.setGlowColor(Theme.getColor(Theme.key_dialogBackground)); listView.setOnItemClickListener((view, position) -> { ArrayList arrayList; if (selectedAlbum != null) { @@ -556,7 +540,7 @@ public class PhotoPickerActivity extends BaseFragment implements NotificationCen type = 0; } PhotoViewer.getInstance().setParentActivity(getParentActivity()); - PhotoViewer.getInstance().setMaxSelectedPhotos(maxSelectedPhotos); + PhotoViewer.getInstance().setMaxSelectedPhotos(maxSelectedPhotos, allowOrder); PhotoViewer.getInstance().openPhotoForSelect(arrayList, position, type, provider, chatActivity); }); @@ -583,8 +567,8 @@ public class PhotoPickerActivity extends BaseFragment implements NotificationCen emptyView = new EmptyTextProgressView(context); emptyView.setTextColor(0xff808080); - emptyView.setProgressBarColor(0xffffffff); - emptyView.setShowAtCenter(true); + emptyView.setProgressBarColor(0xff527da3); + emptyView.setShowAtCenter(false); if (selectedAlbum != null) { emptyView.setText(LocaleController.getString("NoPhotos", R.string.NoPhotos)); } else { @@ -624,31 +608,24 @@ public class PhotoPickerActivity extends BaseFragment implements NotificationCen updateSearchInterface(); } - pickerBottomLayout = new PickerBottomLayout(context); - frameLayout.addView(pickerBottomLayout, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 48, Gravity.BOTTOM)); - pickerBottomLayout.cancelButton.setOnClickListener(view -> { - delegate.actionButtonPressed(true); - finishFragment(); - }); - pickerBottomLayout.doneButton.setOnClickListener(view -> sendSelectedPhotos()); - if (selectPhotoType != 0) { - pickerBottomLayout.setVisibility(View.GONE); - } else if ((selectedAlbum != null || type == 0) && chatActivity != null && chatActivity.allowGroupPhotos()) { - imageOrderToggleButton = new ImageView(context); - imageOrderToggleButton.setScaleType(ImageView.ScaleType.CENTER); - imageOrderToggleButton.setImageResource(R.drawable.photos_group); - imageOrderToggleButton.setContentDescription(SharedConfig.groupPhotosEnabled ? LocaleController.getString("GroupPhotosHelp", R.string.GroupPhotosHelp) : LocaleController.getString("SinglePhotosHelp", R.string.SinglePhotosHelp)); - pickerBottomLayout.addView(imageOrderToggleButton, LayoutHelper.createFrame(48, LayoutHelper.MATCH_PARENT, Gravity.CENTER)); - imageOrderToggleButton.setOnClickListener(v -> { - SharedConfig.toggleGroupPhotosEnabled(); - imageOrderToggleButton.setColorFilter(SharedConfig.groupPhotosEnabled ? new PorterDuffColorFilter(0xff66bffa, PorterDuff.Mode.MULTIPLY) : null); - showHint(false, SharedConfig.groupPhotosEnabled); - updateCheckedPhotoIndices(); - imageOrderToggleButton.setContentDescription(SharedConfig.groupPhotosEnabled ? LocaleController.getString("GroupPhotosHelp", R.string.GroupPhotosHelp) : LocaleController.getString("SinglePhotosHelp", R.string.SinglePhotosHelp)); + if (needsBottomLayout) { + shadowView = new View(context); + shadowView.setBackgroundColor(Theme.getColor(Theme.key_dialogShadowLine)); + frameLayout.addView(shadowView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 1, Gravity.LEFT | Gravity.BOTTOM, 0, 0, 0, 48)); + + pickerBottomLayout = new PickerBottomLayout(context); + frameLayout.addView(pickerBottomLayout, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 48, Gravity.BOTTOM)); + pickerBottomLayout.cancelButton.setOnClickListener(view -> { + delegate.actionButtonPressed(true); + finishFragment(); }); - imageOrderToggleButton.setColorFilter(SharedConfig.groupPhotosEnabled ? new PorterDuffColorFilter(0xff66bffa, PorterDuff.Mode.MULTIPLY) : null); + pickerBottomLayout.doneButton.setOnClickListener(view -> sendSelectedPhotos()); + if (selectPhotoType != 0) { + pickerBottomLayout.setVisibility(View.GONE); + shadowView.setVisibility(View.GONE); + } } - allowIndices = (selectedAlbum != null || type == 0) && maxSelectedPhotos <= 0; + allowIndices = (selectedAlbum != null || type == 0) && allowOrder; listView.setEmptyView(emptyView); pickerBottomLayout.updateSelectedCount(selectedPhotos.size(), true); @@ -656,6 +633,15 @@ public class PhotoPickerActivity extends BaseFragment implements NotificationCen return fragmentView; } + public void setPickerBottomLayout(PickerBottomLayout bottomLayout) { + pickerBottomLayout = bottomLayout; + needsBottomLayout = false; + } + + public PickerBottomLayout getPickerBottomLayout() { + return pickerBottomLayout; + } + @Override public void onResume() { super.onResume(); @@ -694,33 +680,8 @@ public class PhotoPickerActivity extends BaseFragment implements NotificationCen } } - private void hideHint() { - hintAnimation = new AnimatorSet(); - hintAnimation.playTogether( - ObjectAnimator.ofFloat(hintTextView, "alpha", 0.0f) - ); - hintAnimation.addListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator animation) { - if (animation.equals(hintAnimation)) { - hintAnimation = null; - hintHideRunnable = null; - if (hintTextView != null) { - hintTextView.setVisibility(View.GONE); - } - } - } - - @Override - public void onAnimationCancel(Animator animation) { - if (animation.equals(hintAnimation)) { - hintHideRunnable = null; - hintHideRunnable = null; - } - } - }); - hintAnimation.setDuration(300); - hintAnimation.start(); + public RecyclerListView getListView() { + return listView; } public void setInitialSearchString(String text) { @@ -750,73 +711,12 @@ public class PhotoPickerActivity extends BaseFragment implements NotificationCen updateSearchInterface(); } - public void setMaxSelectedPhotos(int value) { + public void setMaxSelectedPhotos(int value, boolean order) { maxSelectedPhotos = value; - } - - private void showHint(boolean hide, boolean enabled) { - if (getParentActivity() == null || fragmentView == null || hide && hintTextView == null) { - return; + allowOrder = order; + if (value >= 0 && type == 1) { + maxSelectedPhotos = 1; } - if (hintTextView == null) { - hintTextView = new TextView(getParentActivity()); - hintTextView.setBackgroundDrawable(Theme.createRoundRectDrawable(AndroidUtilities.dp(3), Theme.getColor(Theme.key_chat_gifSaveHintBackground))); - hintTextView.setTextColor(Theme.getColor(Theme.key_chat_gifSaveHintText)); - hintTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); - hintTextView.setPadding(AndroidUtilities.dp(8), AndroidUtilities.dp(7), AndroidUtilities.dp(8), AndroidUtilities.dp(7)); - hintTextView.setGravity(Gravity.CENTER_VERTICAL); - hintTextView.setAlpha(0.0f); - frameLayout.addView(hintTextView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM, 5, 0, 5, 48 + 3)); - } - if (hide) { - if (hintAnimation != null) { - hintAnimation.cancel(); - hintAnimation = null; - } - AndroidUtilities.cancelRunOnUIThread(hintHideRunnable); - hintHideRunnable = null; - hideHint(); - return; - } - - hintTextView.setText(enabled ? LocaleController.getString("GroupPhotosHelp", R.string.GroupPhotosHelp) : LocaleController.getString("SinglePhotosHelp", R.string.SinglePhotosHelp)); - - if (hintHideRunnable != null) { - if (hintAnimation != null) { - hintAnimation.cancel(); - hintAnimation = null; - } else { - AndroidUtilities.cancelRunOnUIThread(hintHideRunnable); - AndroidUtilities.runOnUIThread(hintHideRunnable = this::hideHint, 2000); - return; - } - } else if (hintAnimation != null) { - return; - } - - hintTextView.setVisibility(View.VISIBLE); - hintAnimation = new AnimatorSet(); - hintAnimation.playTogether( - ObjectAnimator.ofFloat(hintTextView, "alpha", 1.0f) - ); - hintAnimation.addListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator animation) { - if (animation.equals(hintAnimation)) { - hintAnimation = null; - AndroidUtilities.runOnUIThread(hintHideRunnable = () -> hideHint(), 2000); - } - } - - @Override - public void onAnimationCancel(Animator animation) { - if (animation.equals(hintAnimation)) { - hintAnimation = null; - } - } - }); - hintAnimation.setDuration(300); - hintAnimation.start(); } private void updateCheckedPhotoIndices() { @@ -852,7 +752,7 @@ public class PhotoPickerActivity extends BaseFragment implements NotificationCen View view = listView.getChildAt(a); if (view instanceof PhotoPickerPhotoCell) { PhotoPickerPhotoCell cell = (PhotoPickerPhotoCell) view; - int num = (Integer) cell.photoImage.getTag(); + int num = (Integer) cell.imageView.getTag(); if (selectedAlbum != null) { if (num < 0 || num >= selectedAlbum.photos.size()) { continue; @@ -1147,10 +1047,6 @@ public class PhotoPickerActivity extends BaseFragment implements NotificationCen listAdapter.notifyDataSetChanged(); layoutManager.scrollToPosition(position); - - if (selectedAlbum == null) { - emptyView.setPadding(0, 0, 0, (int) ((AndroidUtilities.displaySize.y - ActionBar.getCurrentActionBarHeight()) * 0.4f)); - } } private class ListAdapter extends RecyclerListView.SelectionAdapter { @@ -1177,8 +1073,8 @@ public class PhotoPickerActivity extends BaseFragment implements NotificationCen @Override public int getItemCount() { if (selectedAlbum == null) { - if (searchResult.isEmpty() && lastSearchString == null) { - return recentImages.size(); + if (searchResult.isEmpty()) { + return 0; } else { return searchResult.size() + (imageSearchEndReached ? 0 : 1); } @@ -1203,6 +1099,12 @@ public class PhotoPickerActivity extends BaseFragment implements NotificationCen MediaController.PhotoEntry photoEntry = selectedAlbum.photos.get(index); boolean added = !selectedPhotos.containsKey(photoEntry.imageId); if (added && maxSelectedPhotos > 0 && selectedPhotos.size() >= maxSelectedPhotos) { + if (allowOrder && chatActivity != null) { + TLRPC.Chat chat = chatActivity.getCurrentChat(); + if (chat != null && !ChatObject.hasAdminRights(chat) && chat.slowmode_enabled) { + AlertsCreator.showSimpleAlert(PhotoPickerActivity.this, LocaleController.getString("Slowmode", R.string.Slowmode), LocaleController.getString("SlowmodeSelectSendError", R.string.SlowmodeSelectSendError)); + } + } return; } int num = allowIndices && added ? selectedPhotosOrder.size() : -1; @@ -1218,6 +1120,12 @@ public class PhotoPickerActivity extends BaseFragment implements NotificationCen } boolean added = !selectedPhotos.containsKey(photoEntry.id); if (added && maxSelectedPhotos > 0 && selectedPhotos.size() >= maxSelectedPhotos) { + if (allowOrder && chatActivity != null) { + TLRPC.Chat chat = chatActivity.getCurrentChat(); + if (chat != null && !ChatObject.hasAdminRights(chat) && chat.slowmode_enabled) { + AlertsCreator.showSimpleAlert(PhotoPickerActivity.this, LocaleController.getString("Slowmode", R.string.Slowmode), LocaleController.getString("SlowmodeSelectSendError", R.string.SlowmodeSelectSendError)); + } + } return; } int num = allowIndices && added ? selectedPhotosOrder.size() : -1; @@ -1235,7 +1143,7 @@ public class PhotoPickerActivity extends BaseFragment implements NotificationCen FrameLayout frameLayout = new FrameLayout(mContext); view = frameLayout; RadialProgressView progressBar = new RadialProgressView(mContext); - progressBar.setProgressColor(0xffffffff); + progressBar.setProgressColor(0xff527da3); frameLayout.addView(progressBar, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); break; } @@ -1248,7 +1156,7 @@ public class PhotoPickerActivity extends BaseFragment implements NotificationCen case 0: PhotoPickerPhotoCell cell = (PhotoPickerPhotoCell) holder.itemView; cell.itemWidth = itemWidth; - BackupImageView imageView = cell.photoImage; + BackupImageView imageView = cell.imageView; imageView.setTag(position); cell.setTag(position); boolean showing; @@ -1256,25 +1164,7 @@ public class PhotoPickerActivity extends BaseFragment implements NotificationCen if (selectedAlbum != null) { MediaController.PhotoEntry photoEntry = selectedAlbum.photos.get(position); - if (photoEntry.thumbPath != null) { - imageView.setImage(photoEntry.thumbPath, null, mContext.getResources().getDrawable(R.drawable.nophotos)); - } else if (photoEntry.path != null) { - imageView.setOrientation(photoEntry.orientation, true); - if (photoEntry.isVideo) { - cell.videoInfoContainer.setVisibility(View.VISIBLE); - int minutes = photoEntry.duration / 60; - int seconds = photoEntry.duration - minutes * 60; - cell.videoTextView.setText(String.format("%d:%02d", minutes, seconds)); - cell.setContentDescription(LocaleController.getString("AttachVideo", R.string.AttachVideo) + ", " + LocaleController.formatCallDuration(photoEntry.duration)); - imageView.setImage("vthumb://" + photoEntry.imageId + ":" + photoEntry.path, null, mContext.getResources().getDrawable(R.drawable.nophotos)); - } else { - cell.videoInfoContainer.setVisibility(View.INVISIBLE); - cell.setContentDescription(LocaleController.getString("AttachPhoto", R.string.AttachPhoto)); - imageView.setImage("thumb://" + photoEntry.imageId + ":" + photoEntry.path, null, mContext.getResources().getDrawable(R.drawable.nophotos)); - } - } else { - imageView.setImageResource(R.drawable.nophotos); - } + cell.setImage(photoEntry); cell.setChecked(allowIndices ? selectedPhotosOrder.indexOf(photoEntry.imageId) : -1, selectedPhotos.containsKey(photoEntry.imageId), false); showing = PhotoViewer.isShowingImage(photoEntry.path); } else { @@ -1311,4 +1201,33 @@ public class PhotoPickerActivity extends BaseFragment implements NotificationCen return 1; } } + + @Override + public ThemeDescription[] getThemeDescriptions() { + return new ThemeDescription[]{ + new ThemeDescription(fragmentView, ThemeDescription.FLAG_BACKGROUND, null, null, null, null, Theme.key_dialogBackground), + + new ThemeDescription(actionBar, ThemeDescription.FLAG_BACKGROUND, null, null, null, null, Theme.key_dialogBackground), + new ThemeDescription(actionBar, ThemeDescription.FLAG_AB_ITEMSCOLOR, null, null, null, null, Theme.key_dialogTextBlack), + new ThemeDescription(actionBar, ThemeDescription.FLAG_AB_TITLECOLOR, null, null, null, null, Theme.key_dialogTextBlack), + new ThemeDescription(actionBar, ThemeDescription.FLAG_AB_SELECTORCOLOR, null, null, null, null, Theme.key_dialogButtonSelector), + new ThemeDescription(actionBar, ThemeDescription.FLAG_AB_SEARCH, null, null, null, null, Theme.key_dialogTextBlack), + new ThemeDescription(actionBar, ThemeDescription.FLAG_AB_SEARCHPLACEHOLDER, null, null, null, null, Theme.key_chat_messagePanelHint), + new ThemeDescription(searchItem != null ? searchItem.getSearchField() : null, ThemeDescription.FLAG_CURSORCOLOR, null, null, null, null, Theme.key_dialogTextBlack), + + new ThemeDescription(listView, ThemeDescription.FLAG_LISTGLOWCOLOR, null, null, null, null, Theme.key_dialogBackground), + + new ThemeDescription(shadowView, ThemeDescription.FLAG_BACKGROUND, null, null, null, null, Theme.key_dialogShadowLine), + + new ThemeDescription(pickerBottomLayout, ThemeDescription.FLAG_BACKGROUND, null, null, null, null, Theme.key_dialogBackground), + new ThemeDescription(pickerBottomLayout, ThemeDescription.FLAG_TEXTCOLOR, new Class[]{PickerBottomLayout.class}, new String[]{"cancelButton"}, null, null, null, Theme.key_picker_enabledButton), + new ThemeDescription(pickerBottomLayout, ThemeDescription.FLAG_TEXTCOLOR | ThemeDescription.FLAG_CHECKTAG, new Class[]{PickerBottomLayout.class}, new String[]{"doneButtonTextView"}, null, null, null, Theme.key_picker_enabledButton), + new ThemeDescription(pickerBottomLayout, ThemeDescription.FLAG_TEXTCOLOR | ThemeDescription.FLAG_CHECKTAG, new Class[]{PickerBottomLayout.class}, new String[]{"doneButtonTextView"}, null, null, null, Theme.key_picker_disabledButton), + new ThemeDescription(pickerBottomLayout, ThemeDescription.FLAG_TEXTCOLOR, new Class[]{PickerBottomLayout.class}, new String[]{"doneButtonBadgeTextView"}, null, null, null, Theme.key_picker_badgeText), + new ThemeDescription(pickerBottomLayout, ThemeDescription.FLAG_USEBACKGROUNDDRAWABLE, new Class[]{PickerBottomLayout.class}, new String[]{"doneButtonBadgeTextView"}, null, null, null, Theme.key_picker_badge), + + new ThemeDescription(listView, 0, new Class[]{View.class}, null, new Drawable[]{Theme.chat_attachEmptyDrawable}, null, Theme.key_chat_attachEmptyImage), + new ThemeDescription(listView, 0, new Class[]{View.class}, null, null, null, Theme.key_chat_attachPhotoBackground), + }; + } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/PhotoPickerSearchActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/PhotoPickerSearchActivity.java new file mode 100644 index 000000000..f387d243c --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/PhotoPickerSearchActivity.java @@ -0,0 +1,666 @@ +package org.telegram.ui; + +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.animation.AnimatorSet; +import android.animation.ObjectAnimator; +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.drawable.Drawable; +import android.view.Gravity; +import android.view.MotionEvent; +import android.view.VelocityTracker; +import android.view.View; +import android.view.ViewConfiguration; +import android.view.ViewGroup; +import android.view.WindowManager; +import android.view.animation.Interpolator; +import android.widget.EditText; +import android.widget.FrameLayout; +import android.widget.TextView; + +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.ActionBar; +import org.telegram.ui.ActionBar.ActionBarMenu; +import org.telegram.ui.ActionBar.ActionBarMenuItem; +import org.telegram.ui.ActionBar.BaseFragment; +import org.telegram.ui.ActionBar.Theme; +import org.telegram.ui.ActionBar.ThemeDescription; +import org.telegram.ui.Components.EditTextBoldCursor; +import org.telegram.ui.Components.LayoutHelper; +import org.telegram.ui.Components.PickerBottomLayout; +import org.telegram.ui.Components.RecyclerListView; +import org.telegram.ui.Components.ScrollSlidingTextTabStrip; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; + +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; + +public class PhotoPickerSearchActivity extends BaseFragment { + + private class ViewPage extends FrameLayout { + private BaseFragment parentFragment; + private FrameLayout fragmentView; + private ActionBar actionBar; + private RecyclerListView listView; + private int selectedType; + + public ViewPage(Context context) { + super(context); + } + } + + private PhotoPickerActivity imagesSearch; + private PhotoPickerActivity gifsSearch; + private ActionBarMenuItem searchItem; + + private boolean sendPressed; + private int selectPhotoType; + private ChatActivity chatActivity; + + private final static int search_button = 0; + + private Paint backgroundPaint = new Paint(); + private ScrollSlidingTextTabStrip scrollSlidingTextTabStrip; + private ViewPage[] viewPages = new ViewPage[2]; + private AnimatorSet tabsAnimation; + private boolean tabsAnimationInProgress; + private boolean animatingForward; + private boolean backAnimation; + private int maximumVelocity; + private static final Interpolator interpolator = t -> { + --t; + return t * t * t * t * t + 1.0F; + }; + + public PhotoPickerSearchActivity(HashMap selectedPhotos, ArrayList selectedPhotosOrder, ArrayList recentImages, int selectPhotoType, boolean allowCaption, ChatActivity chatActivity) { + super(); + + imagesSearch = new PhotoPickerActivity(0, null, selectedPhotos, selectedPhotosOrder, recentImages, selectPhotoType, allowCaption, chatActivity); + gifsSearch = new PhotoPickerActivity(1, null, selectedPhotos, selectedPhotosOrder, recentImages, selectPhotoType, allowCaption, chatActivity); + } + + @Override + public View createView(Context context) { + actionBar.setBackgroundColor(Theme.getColor(Theme.key_dialogBackground)); + actionBar.setTitleColor(Theme.getColor(Theme.key_dialogTextBlack)); + actionBar.setItemsColor(Theme.getColor(Theme.key_dialogTextBlack), false); + actionBar.setItemsBackgroundColor(Theme.getColor(Theme.key_dialogButtonSelector), false); + actionBar.setBackButtonImage(R.drawable.ic_ab_back); + if (AndroidUtilities.isTablet()) { + actionBar.setOccupyStatusBar(false); + } + actionBar.setExtraHeight(AndroidUtilities.dp(44)); + actionBar.setAllowOverlayTitle(false); + actionBar.setAddToContainer(false); + actionBar.setClipContent(true); + actionBar.setActionBarMenuOnItemClick(new ActionBar.ActionBarMenuOnItemClick() { + @Override + public void onItemClick(int id) { + if (id == -1) { + finishFragment(); + } + } + }); + hasOwnBackground = true; + + ActionBarMenu menu = actionBar.createMenu(); + searchItem = menu.addItem(search_button, R.drawable.ic_ab_search).setIsSearchField(true).setActionBarMenuItemSearchListener(new ActionBarMenuItem.ActionBarMenuItemSearchListener() { + @Override + public void onSearchExpand() { + imagesSearch.getActionBar().openSearchField("", false); + gifsSearch.getActionBar().openSearchField("", false); + searchItem.getSearchField().requestFocus(); + + } + + @Override + public boolean canCollapseSearch() { + finishFragment(); + return false; + } + + @Override + public void onTextChanged(EditText editText) { + imagesSearch.getActionBar().setSearchFieldText(editText.getText().toString()); + gifsSearch.getActionBar().setSearchFieldText(editText.getText().toString()); + } + + @Override + public void onSearchPressed(EditText editText) { + imagesSearch.getActionBar().onSearchPressed(); + gifsSearch.getActionBar().onSearchPressed(); + } + }); + searchItem.setSearchFieldHint(LocaleController.getString("SearchImagesTitle", R.string.SearchImagesTitle)); + EditTextBoldCursor editText = searchItem.getSearchField(); + editText.setTextColor(Theme.getColor(Theme.key_dialogTextBlack)); + editText.setCursorColor(Theme.getColor(Theme.key_dialogTextBlack)); + editText.setHintTextColor(Theme.getColor(Theme.key_chat_messagePanelHint)); + + scrollSlidingTextTabStrip = new ScrollSlidingTextTabStrip(context); + scrollSlidingTextTabStrip.setUseSameWidth(true); + scrollSlidingTextTabStrip.setColors(Theme.key_chat_attachActiveTab, Theme.key_chat_attachActiveTab, Theme.key_chat_attachUnactiveTab, Theme.key_dialogButtonSelector); + actionBar.addView(scrollSlidingTextTabStrip, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 44, Gravity.LEFT | Gravity.BOTTOM)); + scrollSlidingTextTabStrip.setDelegate(new ScrollSlidingTextTabStrip.ScrollSlidingTabStripDelegate() { + @Override + public void onPageSelected(int id, boolean forward) { + if (viewPages[0].selectedType == id) { + return; + } + swipeBackEnabled = id == scrollSlidingTextTabStrip.getFirstTabId(); + viewPages[1].selectedType = id; + viewPages[1].setVisibility(View.VISIBLE); + switchToCurrentSelectedMode(true); + animatingForward = forward; + if (id == 0) { + searchItem.setSearchFieldHint(LocaleController.getString("SearchImagesTitle", R.string.SearchImagesTitle)); + } else { + searchItem.setSearchFieldHint(LocaleController.getString("SearchGifsTitle", R.string.SearchGifsTitle)); + } + } + + @Override + public void onPageScrolled(float progress) { + if (progress == 1 && viewPages[1].getVisibility() != View.VISIBLE) { + return; + } + if (animatingForward) { + viewPages[0].setTranslationX(-progress * viewPages[0].getMeasuredWidth()); + viewPages[1].setTranslationX(viewPages[0].getMeasuredWidth() - progress * viewPages[0].getMeasuredWidth()); + } else { + viewPages[0].setTranslationX(progress * viewPages[0].getMeasuredWidth()); + viewPages[1].setTranslationX(progress * viewPages[0].getMeasuredWidth() - viewPages[0].getMeasuredWidth()); + } + if (progress == 1) { + ViewPage tempPage = viewPages[0]; + viewPages[0] = viewPages[1]; + viewPages[1] = tempPage; + viewPages[1].setVisibility(View.GONE); + } + } + }); + + ViewConfiguration configuration = ViewConfiguration.get(context); + maximumVelocity = configuration.getScaledMaximumFlingVelocity(); + + FrameLayout frameLayout; + fragmentView = frameLayout = new FrameLayout(context) { + + private int startedTrackingPointerId; + private boolean startedTracking; + private boolean maybeStartTracking; + private int startedTrackingX; + private int startedTrackingY; + private VelocityTracker velocityTracker; + private boolean globalIgnoreLayout; + + private boolean prepareForMoving(MotionEvent ev, boolean forward) { + int id = scrollSlidingTextTabStrip.getNextPageId(forward); + if (id < 0) { + return false; + } + getParent().requestDisallowInterceptTouchEvent(true); + maybeStartTracking = false; + startedTracking = true; + startedTrackingX = (int) ev.getX(); + actionBar.setEnabled(false); + scrollSlidingTextTabStrip.setEnabled(false); + viewPages[1].selectedType = id; + viewPages[1].setVisibility(View.VISIBLE); + animatingForward = forward; + switchToCurrentSelectedMode(true); + if (forward) { + viewPages[1].setTranslationX(viewPages[0].getMeasuredWidth()); + } else { + viewPages[1].setTranslationX(-viewPages[0].getMeasuredWidth()); + } + return true; + } + + @Override + public void forceHasOverlappingRendering(boolean hasOverlappingRendering) { + super.forceHasOverlappingRendering(hasOverlappingRendering); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + int widthSize = MeasureSpec.getSize(widthMeasureSpec); + int heightSize = MeasureSpec.getSize(heightMeasureSpec); + + setMeasuredDimension(widthSize, heightSize); + + measureChildWithMargins(actionBar, widthMeasureSpec, 0, heightMeasureSpec, 0); + int actionBarHeight = actionBar.getMeasuredHeight(); + globalIgnoreLayout = true; + for (int a = 0; a < viewPages.length; a++) { + if (viewPages[a] == null) { + continue; + } + if (viewPages[a].listView != null) { + viewPages[a].listView.setPadding(AndroidUtilities.dp(4), actionBarHeight + AndroidUtilities.dp(4), AndroidUtilities.dp(4), AndroidUtilities.dp(4)); + } + } + globalIgnoreLayout = false; + + int childCount = getChildCount(); + for (int i = 0; i < childCount; i++) { + View child = getChildAt(i); + if (child == null || child.getVisibility() == GONE || child == actionBar) { + continue; + } + measureChildWithMargins(child, widthMeasureSpec, 0, heightMeasureSpec, 0); + } + } + + @Override + protected void dispatchDraw(Canvas canvas) { + super.dispatchDraw(canvas); + if (parentLayout != null) { + parentLayout.drawHeaderShadow(canvas, actionBar.getMeasuredHeight() + (int) actionBar.getTranslationY()); + } + } + + @Override + public void requestLayout() { + if (globalIgnoreLayout) { + return; + } + super.requestLayout(); + } + + public boolean checkTabsAnimationInProgress() { + if (tabsAnimationInProgress) { + boolean cancel = false; + if (backAnimation) { + if (Math.abs(viewPages[0].getTranslationX()) < 1) { + viewPages[0].setTranslationX(0); + viewPages[1].setTranslationX(viewPages[0].getMeasuredWidth() * (animatingForward ? 1 : -1)); + cancel = true; + } + } else if (Math.abs(viewPages[1].getTranslationX()) < 1) { + viewPages[0].setTranslationX(viewPages[0].getMeasuredWidth() * (animatingForward ? -1 : 1)); + viewPages[1].setTranslationX(0); + cancel = true; + } + if (cancel) { + if (tabsAnimation != null) { + tabsAnimation.cancel(); + tabsAnimation = null; + } + tabsAnimationInProgress = false; + } + return tabsAnimationInProgress; + } + return false; + } + + @Override + public boolean onInterceptTouchEvent(MotionEvent ev) { + return checkTabsAnimationInProgress() || scrollSlidingTextTabStrip.isAnimatingIndicator() || onTouchEvent(ev); + } + + @Override + protected void onDraw(Canvas canvas) { + backgroundPaint.setColor(Theme.getColor(Theme.key_windowBackgroundGray)); + canvas.drawRect(0, actionBar.getMeasuredHeight() + actionBar.getTranslationY(), getMeasuredWidth(), getMeasuredHeight(), backgroundPaint); + } + + @Override + public boolean onTouchEvent(MotionEvent ev) { + if (!parentLayout.checkTransitionAnimation() && !checkTabsAnimationInProgress()) { + if (ev != null && ev.getAction() == MotionEvent.ACTION_DOWN && !startedTracking && !maybeStartTracking) { + startedTrackingPointerId = ev.getPointerId(0); + maybeStartTracking = true; + startedTrackingX = (int) ev.getX(); + startedTrackingY = (int) ev.getY(); + if (velocityTracker != null) { + velocityTracker.clear(); + } + } else if (ev != null && ev.getAction() == MotionEvent.ACTION_MOVE && ev.getPointerId(0) == startedTrackingPointerId) { + if (velocityTracker == null) { + velocityTracker = VelocityTracker.obtain(); + } + int dx = (int) (ev.getX() - startedTrackingX); + int dy = Math.abs((int) ev.getY() - startedTrackingY); + velocityTracker.addMovement(ev); + if (startedTracking && (animatingForward && dx > 0 || !animatingForward && dx < 0)) { + if (!prepareForMoving(ev, dx < 0)) { + maybeStartTracking = true; + startedTracking = false; + } + } + if (maybeStartTracking && !startedTracking) { + float touchSlop = AndroidUtilities.getPixelsInCM(0.3f, true); + if (Math.abs(dx) >= touchSlop && Math.abs(dx) / 3 > dy) { + prepareForMoving(ev, dx < 0); + } + } else if (startedTracking) { + if (animatingForward) { + viewPages[0].setTranslationX(dx); + viewPages[1].setTranslationX(viewPages[0].getMeasuredWidth() + dx); + } else { + viewPages[0].setTranslationX(dx); + viewPages[1].setTranslationX(dx - viewPages[0].getMeasuredWidth()); + } + float scrollProgress = Math.abs(dx) / (float) viewPages[0].getMeasuredWidth(); + scrollSlidingTextTabStrip.selectTabWithId(viewPages[1].selectedType, scrollProgress); + } + } else if (ev != null && ev.getPointerId(0) == startedTrackingPointerId && (ev.getAction() == MotionEvent.ACTION_CANCEL || ev.getAction() == MotionEvent.ACTION_UP || ev.getAction() == MotionEvent.ACTION_POINTER_UP)) { + if (velocityTracker == null) { + velocityTracker = VelocityTracker.obtain(); + } + velocityTracker.computeCurrentVelocity(1000, maximumVelocity); + if (!startedTracking) { + float velX = velocityTracker.getXVelocity(); + float velY = velocityTracker.getYVelocity(); + if (Math.abs(velX) >= 3000 && Math.abs(velX) > Math.abs(velY)) { + prepareForMoving(ev, velX < 0); + } + } + if (startedTracking) { + float x = viewPages[0].getX(); + tabsAnimation = new AnimatorSet(); + float velX = velocityTracker.getXVelocity(); + float velY = velocityTracker.getYVelocity(); + backAnimation = Math.abs(x) < viewPages[0].getMeasuredWidth() / 3.0f && (Math.abs(velX) < 3500 || Math.abs(velX) < Math.abs(velY)); + float distToMove; + float dx; + if (backAnimation) { + dx = Math.abs(x); + if (animatingForward) { + tabsAnimation.playTogether( + ObjectAnimator.ofFloat(viewPages[0], View.TRANSLATION_X, 0), + ObjectAnimator.ofFloat(viewPages[1], View.TRANSLATION_X, viewPages[1].getMeasuredWidth()) + ); + } else { + tabsAnimation.playTogether( + ObjectAnimator.ofFloat(viewPages[0], View.TRANSLATION_X, 0), + ObjectAnimator.ofFloat(viewPages[1], View.TRANSLATION_X, -viewPages[1].getMeasuredWidth()) + ); + } + } else { + dx = viewPages[0].getMeasuredWidth() - Math.abs(x); + if (animatingForward) { + tabsAnimation.playTogether( + ObjectAnimator.ofFloat(viewPages[0], View.TRANSLATION_X, -viewPages[0].getMeasuredWidth()), + ObjectAnimator.ofFloat(viewPages[1], View.TRANSLATION_X, 0) + ); + } else { + tabsAnimation.playTogether( + ObjectAnimator.ofFloat(viewPages[0], View.TRANSLATION_X, viewPages[0].getMeasuredWidth()), + ObjectAnimator.ofFloat(viewPages[1], View.TRANSLATION_X, 0) + ); + } + } + tabsAnimation.setInterpolator(interpolator); + + int width = getMeasuredWidth(); + int halfWidth = width / 2; + float distanceRatio = Math.min(1.0f, 1.0f * dx / (float) width); + float distance = (float) halfWidth + (float) halfWidth * AndroidUtilities.distanceInfluenceForSnapDuration(distanceRatio); + velX = Math.abs(velX); + int duration; + if (velX > 0) { + duration = 4 * Math.round(1000.0f * Math.abs(distance / velX)); + } else { + float pageDelta = dx / getMeasuredWidth(); + duration = (int) ((pageDelta + 1.0f) * 100.0f); + } + duration = Math.max(150, Math.min(duration, 600)); + + tabsAnimation.setDuration(duration); + tabsAnimation.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animator) { + tabsAnimation = null; + if (backAnimation) { + viewPages[1].setVisibility(View.GONE); + } else { + ViewPage tempPage = viewPages[0]; + viewPages[0] = viewPages[1]; + viewPages[1] = tempPage; + viewPages[1].setVisibility(View.GONE); + swipeBackEnabled = viewPages[0].selectedType == scrollSlidingTextTabStrip.getFirstTabId(); + scrollSlidingTextTabStrip.selectTabWithId(viewPages[0].selectedType, 1.0f); + } + tabsAnimationInProgress = false; + maybeStartTracking = false; + startedTracking = false; + actionBar.setEnabled(true); + scrollSlidingTextTabStrip.setEnabled(true); + } + }); + tabsAnimation.start(); + tabsAnimationInProgress = true; + } else { + maybeStartTracking = false; + startedTracking = false; + actionBar.setEnabled(true); + scrollSlidingTextTabStrip.setEnabled(true); + } + if (velocityTracker != null) { + velocityTracker.recycle(); + velocityTracker = null; + } + } + return startedTracking; + } + return false; + } + }; + frameLayout.setWillNotDraw(false); + + imagesSearch.setParentFragment(this); + PickerBottomLayout pickerBottomLayout = imagesSearch.getPickerBottomLayout(); + ViewGroup parent = (ViewGroup) pickerBottomLayout.getParent(); + parent.removeView(pickerBottomLayout); + gifsSearch.setPickerBottomLayout(pickerBottomLayout); + gifsSearch.setParentFragment(this); + + for (int a = 0; a < viewPages.length; a++) { + viewPages[a] = new ViewPage(context) { + @Override + public void setTranslationX(float translationX) { + super.setTranslationX(translationX); + if (tabsAnimationInProgress) { + if (viewPages[0] == this) { + float scrollProgress = Math.abs(viewPages[0].getTranslationX()) / (float) viewPages[0].getMeasuredWidth(); + scrollSlidingTextTabStrip.selectTabWithId(viewPages[1].selectedType, scrollProgress); + } + } + } + }; + frameLayout.addView(viewPages[a], LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); + if (a == 0) { + viewPages[a].parentFragment = imagesSearch; + viewPages[a].listView = imagesSearch.getListView(); + } else if (a == 1) { + viewPages[a].parentFragment = gifsSearch; + viewPages[a].listView = gifsSearch.getListView(); + viewPages[a].setVisibility(View.GONE); + } + viewPages[a].fragmentView = (FrameLayout) viewPages[a].parentFragment.getFragmentView(); + viewPages[a].listView.setClipToPadding(false); + viewPages[a].actionBar = viewPages[a].parentFragment.getActionBar(); + viewPages[a].addView(viewPages[a].fragmentView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); + viewPages[a].addView(viewPages[a].actionBar, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); + viewPages[a].actionBar.setVisibility(View.GONE); + + RecyclerView.OnScrollListener onScrollListener = viewPages[a].listView.getOnScrollListener(); + viewPages[a].listView.setOnScrollListener(new RecyclerView.OnScrollListener() { + @Override + public void onScrollStateChanged(RecyclerView recyclerView, int newState) { + onScrollListener.onScrollStateChanged(recyclerView, newState); + if (newState != RecyclerView.SCROLL_STATE_DRAGGING) { + int scrollY = (int) -actionBar.getTranslationY(); + int actionBarHeight = ActionBar.getCurrentActionBarHeight(); + if (scrollY != 0 && scrollY != actionBarHeight) { + if (scrollY < actionBarHeight / 2) { + viewPages[0].listView.smoothScrollBy(0, -scrollY); + } else { + viewPages[0].listView.smoothScrollBy(0, actionBarHeight - scrollY); + } + } + } + } + + @Override + public void onScrolled(RecyclerView recyclerView, int dx, int dy) { + onScrollListener.onScrolled(recyclerView, dx, dy); + if (recyclerView == viewPages[0].listView) { + float currentTranslation = actionBar.getTranslationY(); + float newTranslation = currentTranslation - dy; + if (newTranslation < -ActionBar.getCurrentActionBarHeight()) { + newTranslation = -ActionBar.getCurrentActionBarHeight(); + } else if (newTranslation > 0) { + newTranslation = 0; + } + if (newTranslation != currentTranslation) { + setScrollY(newTranslation); + } + } + } + }); + } + + frameLayout.addView(actionBar, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); + + View shadowView = new View(context); + shadowView.setBackgroundColor(Theme.getColor(Theme.key_dialogShadowLine)); + frameLayout.addView(shadowView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 1, Gravity.LEFT | Gravity.BOTTOM, 0, 0, 0, 48)); + + frameLayout.addView(pickerBottomLayout, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 48, Gravity.LEFT | Gravity.BOTTOM)); + + updateTabs(); + switchToCurrentSelectedMode(false); + swipeBackEnabled = scrollSlidingTextTabStrip.getCurrentTabId() == scrollSlidingTextTabStrip.getFirstTabId(); + + return fragmentView; + } + + @Override + public void onResume() { + super.onResume(); + if (searchItem != null) { + searchItem.openSearch(true); + getParentActivity().getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN); + } + if (imagesSearch != null) { + imagesSearch.onResume(); + } + if (gifsSearch != null) { + gifsSearch.onResume(); + } + } + + @Override + public void onPause() { + super.onPause(); + if (imagesSearch != null) { + imagesSearch.onPause(); + } + if (gifsSearch != null) { + gifsSearch.onPause(); + } + } + + @Override + public void onFragmentDestroy() { + if (imagesSearch != null) { + imagesSearch.onFragmentDestroy(); + } + if (gifsSearch != null) { + gifsSearch.onFragmentDestroy(); + } + super.onFragmentDestroy(); + } + + @Override + public void onConfigurationChanged(android.content.res.Configuration newConfig) { + super.onConfigurationChanged(newConfig); + if (imagesSearch != null) { + imagesSearch.onConfigurationChanged(newConfig); + } + if (gifsSearch != null) { + gifsSearch.onConfigurationChanged(newConfig); + } + } + + private void setScrollY(float value) { + actionBar.setTranslationY(value); + for (int a = 0; a < viewPages.length; a++) { + viewPages[a].listView.setPinnedSectionOffsetY((int) value); + } + fragmentView.invalidate(); + } + + public void setDelegate(PhotoPickerActivity.PhotoPickerActivityDelegate delegate) { + imagesSearch.setDelegate(delegate); + gifsSearch.setDelegate(delegate); + } + + public void setMaxSelectedPhotos(int value, boolean order) { + imagesSearch.setMaxSelectedPhotos(value, order); + gifsSearch.setMaxSelectedPhotos(value, order); + } + + private void updateTabs() { + if (scrollSlidingTextTabStrip == null) { + return; + } + scrollSlidingTextTabStrip.addTextTab(0, LocaleController.getString("ImagesTab", R.string.ImagesTab)); + scrollSlidingTextTabStrip.addTextTab(1, LocaleController.getString("GifsTab", R.string.GifsTab)); + scrollSlidingTextTabStrip.setVisibility(View.VISIBLE); + actionBar.setExtraHeight(AndroidUtilities.dp(44)); + int id = scrollSlidingTextTabStrip.getCurrentTabId(); + if (id >= 0) { + viewPages[0].selectedType = id; + } + scrollSlidingTextTabStrip.finishAddingTabs(); + } + + private void switchToCurrentSelectedMode(boolean animated) { + for (int a = 0; a < viewPages.length; a++) { + viewPages[a].listView.stopScroll(); + } + int a = animated ? 1 : 0; + RecyclerView.Adapter currentAdapter = viewPages[a].listView.getAdapter(); + viewPages[a].listView.setPinnedHeaderShadowDrawable(null); + if (actionBar.getTranslationY() != 0) { + LinearLayoutManager layoutManager = (LinearLayoutManager) viewPages[a].listView.getLayoutManager(); + layoutManager.scrollToPositionWithOffset(0, (int) actionBar.getTranslationY()); + } + } + + @Override + public ThemeDescription[] getThemeDescriptions() { + ArrayList arrayList = new ArrayList<>(); + + arrayList.add(new ThemeDescription(fragmentView, ThemeDescription.FLAG_BACKGROUND, null, null, null, null, Theme.key_dialogBackground)); + arrayList.add(new ThemeDescription(actionBar, ThemeDescription.FLAG_BACKGROUND, null, null, null, null, Theme.key_dialogBackground)); + arrayList.add(new ThemeDescription(actionBar, ThemeDescription.FLAG_AB_ITEMSCOLOR, null, null, null, null, Theme.key_dialogTextBlack)); + arrayList.add(new ThemeDescription(actionBar, ThemeDescription.FLAG_AB_TITLECOLOR, null, null, null, null, Theme.key_dialogTextBlack)); + arrayList.add(new ThemeDescription(actionBar, ThemeDescription.FLAG_AB_SELECTORCOLOR, null, null, null, null, Theme.key_dialogButtonSelector)); + arrayList.add(new ThemeDescription(actionBar, ThemeDescription.FLAG_AB_SEARCH, null, null, null, null, Theme.key_dialogTextBlack)); + arrayList.add(new ThemeDescription(actionBar, ThemeDescription.FLAG_AB_SEARCHPLACEHOLDER, null, null, null, null, Theme.key_chat_messagePanelHint)); + arrayList.add(new ThemeDescription(searchItem.getSearchField(), ThemeDescription.FLAG_CURSORCOLOR, null, null, null, null, Theme.key_dialogTextBlack)); + + arrayList.add(new ThemeDescription(scrollSlidingTextTabStrip.getTabsContainer(), ThemeDescription.FLAG_TEXTCOLOR | ThemeDescription.FLAG_CHECKTAG, new Class[]{TextView.class}, null, null, null, Theme.key_chat_attachActiveTab)); + arrayList.add(new ThemeDescription(scrollSlidingTextTabStrip.getTabsContainer(), ThemeDescription.FLAG_TEXTCOLOR | ThemeDescription.FLAG_CHECKTAG, new Class[]{TextView.class}, null, null, null, Theme.key_chat_attachUnactiveTab)); + arrayList.add(new ThemeDescription(scrollSlidingTextTabStrip.getTabsContainer(), ThemeDescription.FLAG_BACKGROUNDFILTER | ThemeDescription.FLAG_DRAWABLESELECTEDSTATE, new Class[]{TextView.class}, null, null, null, Theme.key_dialogButtonSelector)); + arrayList.add(new ThemeDescription(null, 0, null, null, new Drawable[]{scrollSlidingTextTabStrip.getSelectorDrawable()}, null, Theme.key_chat_attachActiveTab)); + + Collections.addAll(arrayList, imagesSearch.getThemeDescriptions()); + Collections.addAll(arrayList, gifsSearch.getThemeDescriptions()); + + return arrayList.toArray(new ThemeDescription[0]); + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/PhotoViewer.java b/TMessagesProj/src/main/java/org/telegram/ui/PhotoViewer.java index c9a9680e1..4bc4dba74 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/PhotoViewer.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/PhotoViewer.java @@ -64,6 +64,7 @@ import android.view.ActionMode; import android.view.ContextThemeWrapper; import android.view.GestureDetector; import android.view.Gravity; +import android.view.HapticFeedbackConstants; import android.view.KeyEvent; import android.view.MotionEvent; import android.view.Surface; @@ -123,6 +124,7 @@ import org.telegram.messenger.UserConfig; import org.telegram.messenger.MessageObject; import org.telegram.messenger.Utilities; import org.telegram.ui.ActionBar.ActionBarMenuSubItem; +import org.telegram.ui.ActionBar.ActionBarPopupWindow; import org.telegram.ui.ActionBar.AlertDialog; import org.telegram.ui.ActionBar.BottomSheet; import org.telegram.ui.ActionBar.SimpleTextView; @@ -133,6 +135,7 @@ import org.telegram.ui.ActionBar.ActionBarMenu; import org.telegram.ui.ActionBar.ActionBarMenuItem; import org.telegram.ui.Cells.CheckBoxCell; import org.telegram.ui.Cells.PhotoPickerPhotoCell; +import org.telegram.ui.Components.AlertsCreator; import org.telegram.ui.Components.AnimatedFileDrawable; import org.telegram.ui.Components.AnimationProperties; import org.telegram.ui.Components.BackupImageView; @@ -155,9 +158,11 @@ import org.telegram.ui.Components.RecyclerListView; import org.telegram.ui.Components.SeekBar; import org.telegram.ui.Components.SizeNotifierFrameLayoutPhoto; import org.telegram.ui.Components.StickersAlert; +import org.telegram.ui.Components.URLSpanNoUnderline; import org.telegram.ui.Components.URLSpanUserMentionPhotoViewer; import org.telegram.ui.Components.VideoForwardDrawable; import org.telegram.ui.Components.VideoPlayer; +import org.telegram.ui.Components.VideoSeekPreviewImage; import org.telegram.ui.Components.VideoTimelinePlayView; import java.io.ByteArrayInputStream; @@ -175,6 +180,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat private PhotoViewerProvider placeProvider; private boolean isVisible; private int maxSelectedPhotos = -1; + private boolean allowOrder = true; private boolean muteVideo; @@ -254,10 +260,6 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat private boolean pipAvailable; - private TextView hintTextView; - private Runnable hintHideRunnable; - private AnimatorSet hintAnimation; - private Object lastInsets; private boolean padImageForHorizontalInsets; @@ -292,6 +294,9 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat private ImageView videoBackwardButton; private SimpleTextView videoPlayerTime; private SeekBar videoPlayerSeekbar; + private VideoSeekPreviewImage videoPreviewFrame; + private AnimatorSet videoPreviewFrameAnimation; + private boolean needShowOnReady; private PipVideoView pipVideoView; private int waitingForDraw; private TextureView changedTextureView; @@ -316,12 +321,27 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat public final static int SELECT_TYPE_AVATAR = 1; public final static int SELECT_TYPE_WALLPAPER = 3; - public static class LinkMovementMethodMy extends LinkMovementMethod { + 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) { + URLSpanNoUnderline[] links = buffer.getSpans(widget.getSelectionStart(), widget.getSelectionEnd(), URLSpanNoUnderline.class); + if (links != null && links.length > 0) { + String url = links[0].getURL(); + if (url.startsWith("video")) { + if (videoPlayer != null && currentMessageObject != null) { + int seconds = Utilities.parseInt(url); + if (videoPlayer.getDuration() == C.TIME_UNSET) { + seekToProgressPending = seconds / (float) currentMessageObject.getDuration(); + } else { + videoPlayer.seekTo(seconds * 1000L); + } + } + + } + } Selection.removeSelection(buffer); } return result; @@ -366,51 +386,49 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat updateVideoPlayerTime(); } } else { - if (!videoPlayerSeekbar.isDragging()) { - float progress = videoPlayer.getCurrentPosition() / (float) videoPlayer.getDuration(); - float bufferedProgress; - if (currentVideoFinishedLoading) { - bufferedProgress = 1.0f; + float progress = videoPlayer.getCurrentPosition() / (float) videoPlayer.getDuration(); + float bufferedProgress; + if (currentVideoFinishedLoading) { + bufferedProgress = 1.0f; + } else { + long newTime = SystemClock.elapsedRealtime(); + if (Math.abs(newTime - lastBufferedPositionCheck) >= 500) { + bufferedProgress = isStreaming ? FileLoader.getInstance(currentAccount).getBufferedProgressFromPosition(seekToProgressPending != 0 ? seekToProgressPending : progress, currentFileNames[0]) : 1.0f; + lastBufferedPositionCheck = newTime; } else { - long newTime = SystemClock.elapsedRealtime(); - if (Math.abs(newTime - lastBufferedPositionCheck) >= 500) { - bufferedProgress = isStreaming ? FileLoader.getInstance(currentAccount).getBufferedProgressFromPosition(seekToProgressPending != 0 ? seekToProgressPending : progress, currentFileNames[0]) : 1.0f; - lastBufferedPositionCheck = newTime; - } else { - bufferedProgress = -1; - } + bufferedProgress = -1; } - if (!inPreview && videoTimelineView.getVisibility() == View.VISIBLE) { - if (progress >= videoTimelineView.getRightProgress()) { - videoPlayer.pause(); - videoPlayerSeekbar.setProgress(0); - videoPlayer.seekTo((int) (videoTimelineView.getLeftProgress() * videoPlayer.getDuration())); - containerView.invalidate(); - } else { - progress -= videoTimelineView.getLeftProgress(); - if (progress < 0) { - progress = 0; - } - progress /= (videoTimelineView.getRightProgress() - videoTimelineView.getLeftProgress()); - if (progress > 1) { - progress = 1; - } - videoPlayerSeekbar.setProgress(progress); - } - } else { - if (seekToProgressPending == 0) { - videoPlayerSeekbar.setProgress(progress); - } - if (bufferedProgress != -1) { - videoPlayerSeekbar.setBufferedProgress(bufferedProgress); - if (pipVideoView != null) { - pipVideoView.setBufferedProgress(bufferedProgress); - } - } - } - videoPlayerControlFrameLayout.invalidate(); - updateVideoPlayerTime(); } + if (!inPreview && videoTimelineView.getVisibility() == View.VISIBLE) { + if (progress >= videoTimelineView.getRightProgress()) { + videoPlayer.pause(); + videoPlayerSeekbar.setProgress(0); + videoPlayer.seekTo((int) (videoTimelineView.getLeftProgress() * videoPlayer.getDuration())); + containerView.invalidate(); + } else { + progress -= videoTimelineView.getLeftProgress(); + if (progress < 0) { + progress = 0; + } + progress /= (videoTimelineView.getRightProgress() - videoTimelineView.getLeftProgress()); + if (progress > 1) { + progress = 1; + } + videoPlayerSeekbar.setProgress(progress); + } + } else { + if (seekToProgressPending == 0) { + videoPlayerSeekbar.setProgress(progress); + } + if (bufferedProgress != -1) { + videoPlayerSeekbar.setBufferedProgress(bufferedProgress); + if (pipVideoView != null) { + pipVideoView.setBufferedProgress(bufferedProgress); + } + } + } + videoPlayerControlFrameLayout.invalidate(); + updateVideoPlayerTime(); } } if (isPlaying) { @@ -525,6 +543,9 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat private AnimatorSet mentionListAnimation; private boolean allowMentions; + private ActionBarPopupWindow sendPopupWindow; + private ActionBarPopupWindow.ActionBarPopupWindowLayout sendPopupLayout; + private int animationInProgress; private long transitionAnimationStartTime; private Runnable animationEndRunnable; @@ -1015,11 +1036,6 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat return false; } - @Override - public void toggleGroupPhotosEnabled() { - - } - @Override public ArrayList getSelectedPhotosOrder() { return null; @@ -1035,11 +1051,6 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat return true; } - @Override - public boolean allowGroupPhotos() { - return true; - } - @Override public void needAddMorePhotos() { @@ -1095,16 +1106,12 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat boolean scaleToFill(); - void toggleGroupPhotosEnabled(); - ArrayList getSelectedPhotosOrder(); HashMap getSelectedPhotos(); boolean canScrollAway(); - boolean allowGroupPhotos(); - int getPhotoIndex(int index); void deleteImageAtIndex(int index); @@ -1117,6 +1124,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat private class FrameLayoutDrawer extends SizeNotifierFrameLayoutPhoto { private Paint paint = new Paint(); + private boolean ignoreLayout; public FrameLayoutDrawer(Context context) { super(context); @@ -1131,11 +1139,15 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat setMeasuredDimension(widthSize, heightSize); + ignoreLayout = true; + captionTextView.setMaxLines(AndroidUtilities.displaySize.x > AndroidUtilities.displaySize.y ? 5 : 10); + ignoreLayout = false; + measureChildWithMargins(captionEditText, widthMeasureSpec, 0, heightMeasureSpec, 0); int inputFieldHeight = captionEditText.getMeasuredHeight(); - widthSize-=(getPaddingRight()+getPaddingLeft()); - heightSize-=getPaddingBottom(); + widthSize -= (getPaddingRight() + getPaddingLeft()); + heightSize -= getPaddingBottom(); int childCount = getChildCount(); for (int i = 0; i < childCount; i++) { @@ -1145,7 +1157,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat } if (child == aspectRatioFrameLayout) { int heightSpec = MeasureSpec.makeMeasureSpec(AndroidUtilities.displaySize.y + (Build.VERSION.SDK_INT >= 21 ? AndroidUtilities.statusBarHeight : 0), MeasureSpec.EXACTLY); - child.measure(widthMeasureSpec, heightSpec); + child.measure(widthMeasureSpec, heightSpec); } else if (captionEditText.isPopupView(child)) { if (AndroidUtilities.isInMultiwindow) { if (AndroidUtilities.isTablet()) { @@ -1238,10 +1250,15 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat if (!groupedPhotosListView.currentPhotos.isEmpty()) { childTop -= groupedPhotosListView.getMeasuredHeight(); } - } else if (hintTextView != null && child == hintTextView) { - childTop = selectedPhotosListView.getBottom() + AndroidUtilities.dp(3); } else if (child == cameraItem) { childTop = pickerView.getTop() - AndroidUtilities.dp(sendPhotoType == 4 || sendPhotoType == 5 ? 40 : 15) - cameraItem.getMeasuredHeight(); + } else if (child == videoPreviewFrame) { + if (!groupedPhotosListView.currentPhotos.isEmpty()) { + childTop -= groupedPhotosListView.getMeasuredHeight(); + } + if (captionTextView.getVisibility() == VISIBLE) { + childTop -= captionTextView.getMeasuredHeight(); + } } child.layout(childLeft + l, childTop, childLeft + width + l, childTop + height); } @@ -1274,7 +1291,10 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat } } else if (child == cameraItem || child == pickerView || child == pickerViewSendButton || child == captionTextView || muteItem.getVisibility() == VISIBLE && child == bottomLayout) { int paddingBottom = getKeyboardHeight() <= AndroidUtilities.dp(20) && !AndroidUtilities.isInMultiwindow ? captionEditText.getEmojiPadding() : 0; - if (captionEditText.isPopupShowing() || AndroidUtilities.usingHardwareInput && captionEditText.getTag() != null || getKeyboardHeight() > 0 || paddingBottom != 0) { + if (captionEditText.isPopupShowing() || AndroidUtilities.usingHardwareInput && captionEditText.getTag() != null || getKeyboardHeight() > AndroidUtilities.dp(80) || paddingBottom != 0) { + if (BuildVars.DEBUG_VERSION) { + FileLog.d("keyboard height = " + getKeyboardHeight() + " padding = " + paddingBottom); + } bottomTouchEnabled = false; return false; } else { @@ -1296,6 +1316,14 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat return true; } } + + @Override + public void requestLayout() { + if (ignoreLayout) { + return; + } + super.requestLayout(); + } } @SuppressLint("StaticFieldLeak") @@ -2545,23 +2573,80 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat Drawable drawable = Theme.createSimpleSelectorCircleDrawable(AndroidUtilities.dp(56), 0xff66bffa, 0xff66bffa); pickerViewSendButton.setBackgroundDrawable(drawable); pickerViewSendButton.setColorFilter(new PorterDuffColorFilter(0xffffffff, PorterDuff.Mode.MULTIPLY)); - pickerViewSendButton.setPadding(AndroidUtilities.dp(4), 0, 0, 0); - pickerViewSendButton.setImageResource(R.drawable.ic_send); + pickerViewSendButton.setImageResource(R.drawable.attach_send); containerView.addView(pickerViewSendButton, LayoutHelper.createFrame(56, 56, Gravity.RIGHT | Gravity.BOTTOM, 0, 0, 14, 14)); pickerViewSendButton.setContentDescription(LocaleController.getString("Send", R.string.Send)); - pickerViewSendButton.setOnClickListener(v -> { - if (captionEditText.getTag() != null) { - return; + pickerViewSendButton.setOnClickListener(v -> sendPressed(false)); + pickerViewSendButton.setOnLongClickListener(view -> { + if (parentChatActivity == null) { + return false; } - if (sendPhotoType == SELECT_TYPE_AVATAR) { - applyCurrentEditMode(); + TLRPC.Chat chat = parentChatActivity.getCurrentChat(); + TLRPC.User user = parentChatActivity.getCurrentUser(); + if (parentChatActivity.getCurrentEncryptedChat() != null || ChatObject.isChannel(chat) && !chat.megagroup || UserObject.isUserSelf(user)) { + return false; } - if (placeProvider != null && !doneButtonPressed) { - VideoEditedInfo videoEditedInfo = getCurrentVideoEditedInfo(); - placeProvider.sendButtonPressed(currentIndex, videoEditedInfo); - doneButtonPressed = true; - closePhoto(false, false); + + if (sendPopupLayout == null) { + sendPopupLayout = new ActionBarPopupWindow.ActionBarPopupWindowLayout(parentActivity); + sendPopupLayout.setAnimationEnabled(false); + sendPopupLayout.setOnTouchListener(new View.OnTouchListener() { + + private android.graphics.Rect popupRect = new android.graphics.Rect(); + + @Override + public boolean onTouch(View v, MotionEvent event) { + if (event.getActionMasked() == MotionEvent.ACTION_DOWN) { + if (sendPopupWindow != null && sendPopupWindow.isShowing()) { + v.getHitRect(popupRect); + if (!popupRect.contains((int) event.getX(), (int) event.getY())) { + sendPopupWindow.dismiss(); + } + } + } + return false; + } + }); + sendPopupLayout.setDispatchKeyEventListener(keyEvent -> { + if (keyEvent.getKeyCode() == KeyEvent.KEYCODE_BACK && keyEvent.getRepeatCount() == 0 && sendPopupWindow != null && sendPopupWindow.isShowing()) { + sendPopupWindow.dismiss(); + } + }); + sendPopupLayout.setShowedFromBotton(false); + sendPopupLayout.getBackgroundDrawable().setColorFilter(new PorterDuffColorFilter(0xf9222222, PorterDuff.Mode.MULTIPLY)); + + ActionBarMenuSubItem cell = new ActionBarMenuSubItem(parentActivity); + cell.setBackgroundDrawable(Theme.createSelectorDrawable(0x24ffffff, 7)); + cell.setTextAndIcon(LocaleController.getString("SendWithoutSound", R.string.SendWithoutSound), R.drawable.input_notify_off); + cell.setMinimumWidth(AndroidUtilities.dp(196)); + cell.setColors(0xffffffff, 0xffffffff); + sendPopupLayout.addView(cell, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 48, LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT)); + cell.setOnClickListener(v -> { + if (sendPopupWindow != null && sendPopupWindow.isShowing()) { + sendPopupWindow.dismiss(); + } + sendPressed(true); + }); + + sendPopupWindow = new ActionBarPopupWindow(sendPopupLayout, LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT); + sendPopupWindow.setAnimationEnabled(false); + sendPopupWindow.setAnimationStyle(R.style.PopupContextAnimation2); + sendPopupWindow.setOutsideTouchable(true); + sendPopupWindow.setClippingEnabled(true); + sendPopupWindow.setInputMethodMode(ActionBarPopupWindow.INPUT_METHOD_NOT_NEEDED); + sendPopupWindow.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED); + sendPopupWindow.getContentView().setFocusableInTouchMode(true); } + + sendPopupLayout.measure(View.MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(1000), View.MeasureSpec.AT_MOST), View.MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(1000), View.MeasureSpec.AT_MOST)); + sendPopupWindow.setFocusable(true); + + int[] location = new int[2]; + view.getLocationInWindow(location); + sendPopupWindow.showAtLocation(view, Gravity.LEFT | Gravity.TOP, location[0] + view.getMeasuredWidth() - sendPopupLayout.getMeasuredWidth() + AndroidUtilities.dp(14), location[1] - sendPopupLayout.getMeasuredHeight() - AndroidUtilities.dp(18)); + view.performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP, HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING); + + return false; }); LinearLayout itemsLayout = new LinearLayout(parentActivity); @@ -2963,23 +3048,13 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat selectedPhotosListView.setAdapter(selectedPhotosAdapter = new ListAdapter(parentActivity)); containerView.addView(selectedPhotosListView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 88, Gravity.LEFT | Gravity.TOP)); selectedPhotosListView.setOnItemClickListener((view, position) -> { - if (position == 0 && placeProvider.allowGroupPhotos()) { - boolean enabled = SharedConfig.groupPhotosEnabled; - SharedConfig.toggleGroupPhotosEnabled(); - placeProvider.toggleGroupPhotosEnabled(); - ImageView imageView = (ImageView) view; - imageView.setColorFilter(!enabled ? new PorterDuffColorFilter(0xff66bffa, PorterDuff.Mode.MULTIPLY) : null); - imageView.setContentDescription(SharedConfig.groupPhotosEnabled ? LocaleController.getString("GroupPhotosHelp", R.string.GroupPhotosHelp) : LocaleController.getString("SinglePhotosHelp", R.string.SinglePhotosHelp)); - showHint(false, !enabled); - } else { - ignoreDidSetImage = true; - int idx = imagesArrLocals.indexOf(view.getTag()); - if (idx >= 0) { - currentIndex = -1; - setImageIndex(idx, true); - } - ignoreDidSetImage = false; + ignoreDidSetImage = true; + int idx = imagesArrLocals.indexOf(view.getTag()); + if (idx >= 0) { + currentIndex = -1; + setImageIndex(idx, true); } + ignoreDidSetImage = false; }); captionEditText = new PhotoViewerCaptionEnterView(actvityContext, containerView, windowView) { @@ -3201,6 +3276,28 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat } } + private void sendPressed(boolean forceSilent) { + if (captionEditText.getTag() != null) { + return; + } + if (sendPhotoType == SELECT_TYPE_AVATAR) { + applyCurrentEditMode(); + } + if (placeProvider != null && !doneButtonPressed) { + if (parentChatActivity != null) { + TLRPC.Chat chat = parentChatActivity.getCurrentChat(); + TLRPC.User user = parentChatActivity.getCurrentUser(); + if (user != null || ChatObject.isChannel(chat) && chat.megagroup || !ChatObject.isChannel(chat)) { + MessagesController.getNotificationsSettings(currentAccount).edit().putBoolean("silent_" + parentChatActivity.getDialogId(), forceSilent).commit(); + } + } + VideoEditedInfo videoEditedInfo = getCurrentVideoEditedInfo(); + placeProvider.sendButtonPressed(currentIndex, videoEditedInfo); + doneButtonPressed = true; + closePhoto(false, false); + } + } + private boolean checkInlinePermissions() { if (parentActivity == null) { return false; @@ -3232,7 +3329,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat }; textView.setMovementMethod(new LinkMovementMethodMy()); textView.setPadding(AndroidUtilities.dp(20), AndroidUtilities.dp(8), AndroidUtilities.dp(20), AndroidUtilities.dp(8)); - textView.setLinkTextColor(0xffffffff); + textView.setLinkTextColor(0xff76c2f1); textView.setTextColor(0xffffffff); textView.setHighlightColor(0x33ffffff); //textView.setEllipsize(TextUtils.TruncateAt.END); @@ -3413,21 +3510,71 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat } } + private void updateVideoSeekPreviewPosition() { + int x = videoPlayerSeekbar.getThumbX() + AndroidUtilities.dp(48) - videoPreviewFrame.getMeasuredWidth() / 2; + int min = AndroidUtilities.dp(10); + int max = videoPlayerControlFrameLayout.getMeasuredWidth() - AndroidUtilities.dp(10) - videoPreviewFrame.getMeasuredWidth() / 2; + if (x < min) { + x = min; + } else if (x >= max) { + x = max; + } + videoPreviewFrame.setTranslationX(x); + } + + private void showVideoSeekPreviewPosition(boolean show) { + if (show && videoPreviewFrame.getTag() != null || !show && videoPreviewFrame.getTag() == null) { + return; + } + if (show && !videoPreviewFrame.isReady()) { + needShowOnReady = show; + return; + } + if (videoPreviewFrameAnimation != null) { + videoPreviewFrameAnimation.cancel(); + } + videoPreviewFrame.setTag(show ? 1 : null); + videoPreviewFrameAnimation = new AnimatorSet(); + videoPreviewFrameAnimation.playTogether(ObjectAnimator.ofFloat(videoPreviewFrame, View.ALPHA, show ? 1.0f : 0.0f)); + videoPreviewFrameAnimation.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + videoPreviewFrameAnimation = null; + } + }); + videoPreviewFrameAnimation.setDuration(180); + videoPreviewFrameAnimation.start(); + } + private void createVideoControlsInterface() { videoPlayerSeekbar = new SeekBar(containerView.getContext()); videoPlayerSeekbar.setLineHeight(AndroidUtilities.dp(4)); videoPlayerSeekbar.setColors(0x66ffffff, 0x66ffffff, 0xffd5d0d7, 0xffffffff, 0xffffffff); - videoPlayerSeekbar.setDelegate(progress -> { - if (videoPlayer != null) { - if (!inPreview && videoTimelineView.getVisibility() == View.VISIBLE) { - progress = videoTimelineView.getLeftProgress() + (videoTimelineView.getRightProgress() - videoTimelineView.getLeftProgress()) * progress; + videoPlayerSeekbar.setDelegate(new SeekBar.SeekBarDelegate() { + @Override + public void onSeekBarDrag(float progress) { + if (videoPlayer != null) { + if (!inPreview && videoTimelineView.getVisibility() == View.VISIBLE) { + progress = videoTimelineView.getLeftProgress() + (videoTimelineView.getRightProgress() - videoTimelineView.getLeftProgress()) * progress; + } + long duration = videoPlayer.getDuration(); + if (duration == C.TIME_UNSET) { + seekToProgressPending = progress; + } else { + videoPlayer.seekTo((int) (progress * duration)); + } + showVideoSeekPreviewPosition(false); + needShowOnReady = false; } - long duration = videoPlayer.getDuration(); - if (duration == C.TIME_UNSET) { - seekToProgressPending = progress; - } else { - videoPlayer.seekTo((int) (progress * duration)); + } + + @Override + public void onSeekBarContinuousDrag(float progress) { + if (videoPlayer != null && videoPreviewFrame != null) { + videoPreviewFrame.setProgress(progress, videoPlayerSeekbar.getWidth()); } + showVideoSeekPreviewPosition(true); + updateVideoSeekPreviewPosition(); } }); @@ -3494,6 +3641,28 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat videoPlayerControlFrameLayout.setWillNotDraw(false); bottomLayout.addView(videoPlayerControlFrameLayout, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.TOP | Gravity.LEFT)); + videoPreviewFrame = new VideoSeekPreviewImage(containerView.getContext(), () -> { + if (needShowOnReady) { + showVideoSeekPreviewPosition(true); + } + }) { + @Override + protected void onLayout(boolean changed, int left, int top, int right, int bottom) { + super.onLayout(changed, left, top, right, bottom); + updateVideoSeekPreviewPosition(); + } + + @Override + public void setVisibility(int visibility) { + super.setVisibility(visibility); + if (visibility == VISIBLE) { + updateVideoSeekPreviewPosition(); + } + } + }; + videoPreviewFrame.setAlpha(0.0f); + containerView.addView(videoPreviewFrame, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.BOTTOM | Gravity.LEFT, 0, 0, 0, 48 + 10)); + videoPlayButton = new ImageView(containerView.getContext()); videoPlayButton.setScaleType(ImageView.ScaleType.CENTER); videoPlayerControlFrameLayout.addView(videoPlayButton, LayoutHelper.createFrame(48, 48, Gravity.LEFT | Gravity.TOP, 4, 0, 0, 0)); @@ -3556,6 +3725,8 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat VideoEditedInfo videoEditedInfo = new VideoEditedInfo(); videoEditedInfo.startTime = startTime; videoEditedInfo.endTime = endTime; + videoEditedInfo.start = videoCutStart; + videoEditedInfo.end = videoCutEnd; videoEditedInfo.rotationValue = rotationValue; videoEditedInfo.originalWidth = originalWidth; videoEditedInfo.originalHeight = originalHeight; @@ -3718,12 +3889,17 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat FileLog.e(e); } } - if (seekToProgressPending != 0 && (playbackState == ExoPlayer.STATE_READY || playbackState == ExoPlayer.STATE_IDLE)) { - int seekTo = (int) (videoPlayer.getDuration() * seekToProgressPending); - videoPlayer.seekTo(seekTo); - seekToProgressPending = 0; - if (currentMessageObject != null && !FileLoader.getInstance(currentMessageObject.currentAccount).isLoadingVideoAny(currentMessageObject.getDocument())) { - skipFirstBufferingProgress = true; + if (playbackState == ExoPlayer.STATE_READY || playbackState == ExoPlayer.STATE_IDLE) { + if (currentMessageObject != null) { + videoPreviewFrame.open(videoPlayer.getCurrentUri()); + } + if (seekToProgressPending != 0) { + int seekTo = (int) (videoPlayer.getDuration() * seekToProgressPending); + videoPlayer.seekTo(seekTo); + seekToProgressPending = 0; + if (currentMessageObject != null && !FileLoader.getInstance(currentMessageObject.currentAccount).isLoadingVideoAny(currentMessageObject.getDocument())) { + skipFirstBufferingProgress = true; + } } } if (playbackState == ExoPlayer.STATE_READY) { @@ -3776,16 +3952,14 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat if (!isActionBarVisible) { toggleActionBar(true, true); } - if (!videoPlayerSeekbar.isDragging()) { - videoPlayerSeekbar.setProgress(0.0f); - videoPlayerControlFrameLayout.invalidate(); - if (!inPreview && videoTimelineView.getVisibility() == View.VISIBLE) { - videoPlayer.seekTo((int) (videoTimelineView.getLeftProgress() * videoPlayer.getDuration())); - } else { - videoPlayer.seekTo(0); - } - videoPlayer.pause(); + videoPlayerSeekbar.setProgress(0.0f); + videoPlayerControlFrameLayout.invalidate(); + if (!inPreview && videoTimelineView.getVisibility() == View.VISIBLE) { + videoPlayer.seekTo((int) (videoTimelineView.getLeftProgress() * videoPlayer.getDuration())); + } else { + videoPlayer.seekTo(0); } + videoPlayer.pause(); } if (pipVideoView != null) { pipVideoView.onVideoCompleted(); @@ -3871,6 +4045,9 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat @Override public void onError(Exception e) { + if (videoPlayer == null) { + return; + } FileLog.e(e); if (!menuItem.isSubItemVisible(gallery_menu_openin)) { return; @@ -3990,6 +4167,10 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat videoPlayerSeekbar.setBufferedProgress(0); videoPlayer.setPlayWhenReady(playWhenReady); } + if (currentMessageObject != null && currentMessageObject.forceSeekTo >= 0) { + seekToProgressPending = currentMessageObject.forceSeekTo; + currentMessageObject.forceSeekTo = -1; + } if (currentBotInlineResult != null && (currentBotInlineResult.type.equals("video") || MessageObject.isVideoDocument(currentBotInlineResult.document))) { bottomLayout.setVisibility(View.VISIBLE); @@ -4019,6 +4200,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat videoPlayer = null; updateAccessibilityOverlayVisibility(); } + videoPreviewFrame.close(); toggleMiniProgress(false, false); pipAvailable = false; playerInjected = false; @@ -4077,7 +4259,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat } else { captionEditText.setFieldText(caption); } - captionEditText.setAllowTextEntitiesIntersection(parentChatActivity != null && (parentChatActivity.currentEncryptedChat != null && AndroidUtilities.getPeerLayerVersion(parentChatActivity.currentEncryptedChat.layer) >= 101)); + captionEditText.setAllowTextEntitiesIntersection(parentChatActivity != null && (parentChatActivity.currentEncryptedChat == null || parentChatActivity.currentEncryptedChat != null && AndroidUtilities.getPeerLayerVersion(parentChatActivity.currentEncryptedChat.layer) >= 101)); } public void showAlertDialog(AlertDialog.Builder builder) { @@ -4204,16 +4386,19 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat private void setPhotoChecked() { if (placeProvider != null) { - if (placeProvider.getSelectedPhotos() != null && maxSelectedPhotos > 0 && placeProvider.getSelectedPhotos().size() > maxSelectedPhotos && !placeProvider.isPhotoChecked(currentIndex)) { + if (placeProvider.getSelectedPhotos() != null && maxSelectedPhotos > 0 && placeProvider.getSelectedPhotos().size() >= maxSelectedPhotos && !placeProvider.isPhotoChecked(currentIndex)) { + if (allowOrder && parentChatActivity != null) { + TLRPC.Chat chat = parentChatActivity.getCurrentChat(); + if (chat != null && !ChatObject.hasAdminRights(chat) && chat.slowmode_enabled) { + AlertsCreator.createSimpleAlert(parentActivity, LocaleController.getString("Slowmode", R.string.Slowmode), LocaleController.getString("SlowmodeSelectSendError", R.string.SlowmodeSelectSendError)).show(); + } + } return; } int num = placeProvider.setPhotoChecked(currentIndex, getCurrentVideoEditedInfo()); boolean checked = placeProvider.isPhotoChecked(currentIndex); checkImageView.setChecked(checked, true); if (num >= 0) { - if (placeProvider.allowGroupPhotos()) { - num++; - } if (checked) { selectedPhotosAdapter.notifyItemInserted(num); selectedPhotosListView.smoothScrollToPosition(num); @@ -4815,6 +5000,9 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat } if (captionTextView.getTag() != null) { captionTextView.setVisibility(View.VISIBLE); + if (videoPreviewFrame != null) { + videoPreviewFrame.requestLayout(); + } } } isActionBarVisible = show; @@ -5122,7 +5310,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat } } - private void onPhotoShow(final MessageObject messageObject, final TLRPC.FileLocation fileLocation, final ArrayList messages, final ArrayList documents, final ArrayList photos, int index, final PlaceProviderObject object) { + private void onPhotoShow(final MessageObject messageObject, final TLRPC.FileLocation fileLocation, ImageLocation imageLocation, final ArrayList messages, final ArrayList documents, final ArrayList photos, int index, final PlaceProviderObject object) { classGuid = ConnectionsManager.generateClassGuid(); currentMessageObject = null; currentFileLocation = null; @@ -5296,13 +5484,14 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat setImageIndex(index, true); } else if (fileLocation != null) { avatarsDialogId = object.dialogId; - ImageLocation imageLocation; - if (avatarsDialogId > 0) { - TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(avatarsDialogId); - imageLocation = ImageLocation.getForUser(user, true); - } else { - TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(-avatarsDialogId); - imageLocation = ImageLocation.getForChat(chat, true); + if (imageLocation == null) { + if (avatarsDialogId > 0) { + TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(avatarsDialogId); + imageLocation = ImageLocation.getForUser(user, true); + } else { + TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(-avatarsDialogId); + imageLocation = ImageLocation.getForChat(chat, true); + } } if (imageLocation == null) { closePhoto(false, false); @@ -5680,11 +5869,17 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat isCurrentVideo = true; updateAccessibilityOverlayVisibility(); boolean isMuted = false; + float start = 0.0f; + float end = 1.0f; if (object instanceof MediaController.PhotoEntry) { MediaController.PhotoEntry photoEntry = ((MediaController.PhotoEntry) object); - isMuted = photoEntry.editedInfo != null && photoEntry.editedInfo.muted; + if (photoEntry.editedInfo != null) { + isMuted = photoEntry.editedInfo.muted; + start = photoEntry.editedInfo.start; + end = photoEntry.editedInfo.end; + } } - processOpenVideo(pathObject, isMuted); + processOpenVideo(pathObject, isMuted, start, end); videoTimelineView.setVisibility(View.VISIBLE); paintItem.setVisibility(View.GONE); cropItem.setVisibility(View.GONE); @@ -5856,6 +6051,10 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat if (object instanceof MediaController.PhotoEntry) { MediaController.PhotoEntry photoEntry = ((MediaController.PhotoEntry) object); currentPathObject = photoEntry.path; + if (currentPathObject == null) { + closePhoto(false, false); + return; + } isVideo = photoEntry.isVideo; videoPath = Uri.fromFile(new File(photoEntry.path)); } else if (object instanceof MediaController.SearchImage) { @@ -5979,7 +6178,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat captionTextView.setSingleLine(true); } else { captionTextView.setSingleLine(false); - captionTextView.setMaxLines(10); + captionTextView.setMaxLines(AndroidUtilities.displaySize.x > AndroidUtilities.displaySize.y ? 5 : 10); } boolean wasVisisble = captionTextView.getTag() != null; if (!TextUtils.isEmpty(caption)) { @@ -6366,7 +6565,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat placeHolder = currentThumb; } TLRPC.PhotoSize thumbLocation = messageObject != null ? FileLoader.getClosestPhotoSizeWithSize(messageObject.photoThumbs, 100) : null; - int size = (int) (4096 / AndroidUtilities.density); + int size = (int) (2048 / AndroidUtilities.density); imageReceiver.setImage(ImageLocation.getForDocument(document), String.format(Locale.US, "%d_%d", size, size), placeHolder == null ? ImageLocation.getForDocument(thumbLocation, document) : null, "b", placeHolder != null ? new BitmapDrawable(placeHolder.bitmap) : null, document.size, null, messageObject, 0); } else { OtherDocumentPlaceholderDrawable drawable = new OtherDocumentPlaceholderDrawable(parentActivity, containerView, messageObject); @@ -6472,28 +6671,33 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat parentChatActivity = chatActivity; } - public void setMaxSelectedPhotos(int value) { + public void setMaxSelectedPhotos(int value, boolean order) { maxSelectedPhotos = value; + allowOrder = order; } public boolean openPhoto(final MessageObject messageObject, long dialogId, long mergeDialogId, final PhotoViewerProvider provider) { - return openPhoto(messageObject, null, null, null, null, 0, provider, null, dialogId, mergeDialogId, true); + return openPhoto(messageObject, null, null, null, null, null, 0, provider, null, dialogId, mergeDialogId, true); } public boolean openPhoto(final MessageObject messageObject, long dialogId, long mergeDialogId, final PhotoViewerProvider provider, boolean fullScreenVideo) { - return openPhoto(messageObject, null, null, null, null, 0, provider, null, dialogId, mergeDialogId, fullScreenVideo); + return openPhoto(messageObject, null, null, null, null, null, 0, provider, null, dialogId, mergeDialogId, fullScreenVideo); } public boolean openPhoto(final TLRPC.FileLocation fileLocation, final PhotoViewerProvider provider) { - return openPhoto(null, fileLocation, null, null, null, 0, provider, null, 0, 0, true); + return openPhoto(null, fileLocation, null, null, null, null, 0, provider, null, 0, 0, true); + } + + public boolean openPhoto(final TLRPC.FileLocation fileLocation, final ImageLocation imageLocation, final PhotoViewerProvider provider) { + return openPhoto(null, fileLocation, imageLocation, null, null, null, 0, provider, null, 0, 0, true); } public boolean openPhoto(final ArrayList messages, final int index, long dialogId, long mergeDialogId, final PhotoViewerProvider provider) { - return openPhoto(messages.get(index), null, messages, null, null, index, provider, null, dialogId, mergeDialogId, true); + return openPhoto(messages.get(index), null, null, messages, null, null, index, provider, null, dialogId, mergeDialogId, true); } public boolean openPhoto(final ArrayList documents, final int index, final PhotoViewerProvider provider) { - return openPhoto(null, null, null, documents, null, index, provider, null, 0, 0, true); + return openPhoto(null, null, null, null, documents, null, index, provider, null, 0, 0, true); } public boolean openPhotoForSelect(final ArrayList photos, final int index, int type, final PhotoViewerProvider provider, ChatActivity chatActivity) { @@ -6501,21 +6705,19 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat if (pickerViewSendButton != null) { FrameLayout.LayoutParams layoutParams2 = (FrameLayout.LayoutParams) pickerViewSendButton.getLayoutParams(); if (sendPhotoType == 4 || sendPhotoType == 5) { - pickerViewSendButton.setImageResource(R.drawable.ic_send); - pickerViewSendButton.setPadding(AndroidUtilities.dp(4), 0, 0, 0); + pickerViewSendButton.setImageResource(R.drawable.attach_send); layoutParams2.bottomMargin = AndroidUtilities.dp(19); } else if (sendPhotoType == SELECT_TYPE_AVATAR || sendPhotoType == SELECT_TYPE_WALLPAPER) { pickerViewSendButton.setImageResource(R.drawable.floating_check); pickerViewSendButton.setPadding(0, AndroidUtilities.dp(1), 0, 0); layoutParams2.bottomMargin = AndroidUtilities.dp(19); } else { - pickerViewSendButton.setImageResource(R.drawable.ic_send); - pickerViewSendButton.setPadding(AndroidUtilities.dp(4), 0, 0, 0); + pickerViewSendButton.setImageResource(R.drawable.attach_send); layoutParams2.bottomMargin = AndroidUtilities.dp(14); } pickerViewSendButton.setLayoutParams(layoutParams2); } - return openPhoto(null, null, null, null, photos, index, provider, chatActivity, 0, 0, true); + return openPhoto(null, null, null, null, null, photos, index, provider, chatActivity, 0, 0, true); } private boolean checkAnimation() { @@ -6600,15 +6802,12 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat padImageForHorizontalInsets = true; } - public boolean openPhoto(final MessageObject messageObject, final TLRPC.FileLocation fileLocation, final ArrayList messages, final ArrayList documents, final ArrayList photos, final int index, final PhotoViewerProvider provider, ChatActivity chatActivity, long dialogId, long mDialogId, boolean fullScreenVideo) { - if (parentActivity == null || isVisible || provider == null && checkAnimation() || messageObject == null && fileLocation == null && messages == null && photos == null && documents == null) { + public boolean openPhoto(final MessageObject messageObject, final TLRPC.FileLocation fileLocation, final ImageLocation imageLocation, final ArrayList messages, final ArrayList documents, final ArrayList photos, final int index, final PhotoViewerProvider provider, ChatActivity chatActivity, long dialogId, long mDialogId, boolean fullScreenVideo) { + if (parentActivity == null || isVisible || provider == null && checkAnimation() || messageObject == null && fileLocation == null && messages == null && photos == null && documents == null && imageLocation == null) { return false; } final PlaceProviderObject object = provider.getPlaceForPhoto(messageObject, fileLocation, index, true); - if (object == null && photos == null) { - return false; - } lastInsets = null; WindowManager wm = (WindowManager) parentActivity.getSystemService(Context.WINDOW_SERVICE); if (attachedToWindow) { @@ -6700,7 +6899,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat } } - onPhotoShow(messageObject, fileLocation, messages, documents, photos, index, object); + onPhotoShow(messageObject, fileLocation, imageLocation, messages, documents, photos, index, object); if (sendPhotoType == SELECT_TYPE_AVATAR) { photoCropView.setVisibility(View.VISIBLE); photoCropView.setAlpha(0.0f); @@ -6918,7 +7117,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat backgroundDrawable.setAlpha(255); containerView.setAlpha(1.0f); - onPhotoShow(messageObject, fileLocation, messages, documents, photos, index, object); + onPhotoShow(messageObject, fileLocation, imageLocation, messages, documents, photos, index, object); initCropView(); setCropBitmap(); } @@ -7700,100 +7899,6 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat return animationValue; } - private void hideHint() { - hintAnimation = new AnimatorSet(); - hintAnimation.playTogether( - ObjectAnimator.ofFloat(hintTextView, View.ALPHA, 0.0f) - ); - hintAnimation.addListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator animation) { - if (animation.equals(hintAnimation)) { - hintAnimation = null; - hintHideRunnable = null; - if (hintTextView != null) { - hintTextView.setVisibility(View.GONE); - } - } - } - - @Override - public void onAnimationCancel(Animator animation) { - if (animation.equals(hintAnimation)) { - hintHideRunnable = null; - hintHideRunnable = null; - } - } - }); - hintAnimation.setDuration(300); - hintAnimation.start(); - } - - private void showHint(boolean hide, boolean enabled) { - if (containerView == null || hide && hintTextView == null) { - return; - } - if (hintTextView == null) { - hintTextView = new TextView(containerView.getContext()); - hintTextView.setBackgroundDrawable(Theme.createRoundRectDrawable(AndroidUtilities.dp(3), 0xcc111111)); - hintTextView.setTextColor(0xffffffff); - hintTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); - hintTextView.setPadding(AndroidUtilities.dp(8), AndroidUtilities.dp(7), AndroidUtilities.dp(8), AndroidUtilities.dp(7)); - hintTextView.setGravity(Gravity.CENTER_VERTICAL); - hintTextView.setAlpha(0.0f); - containerView.addView(hintTextView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.LEFT | Gravity.TOP, 5, 0, 5, 3)); - } - if (hide) { - if (hintAnimation != null) { - hintAnimation.cancel(); - hintAnimation = null; - } - AndroidUtilities.cancelRunOnUIThread(hintHideRunnable); - hintHideRunnable = null; - hideHint(); - return; - } - - hintTextView.setText(enabled ? LocaleController.getString("GroupPhotosHelp", R.string.GroupPhotosHelp) : LocaleController.getString("SinglePhotosHelp", R.string.SinglePhotosHelp)); - - if (hintHideRunnable != null) { - if (hintAnimation != null) { - hintAnimation.cancel(); - hintAnimation = null; - } else { - AndroidUtilities.cancelRunOnUIThread(hintHideRunnable); - AndroidUtilities.runOnUIThread(hintHideRunnable = this::hideHint, 2000); - return; - } - } else if (hintAnimation != null) { - return; - } - - hintTextView.setVisibility(View.VISIBLE); - hintAnimation = new AnimatorSet(); - hintAnimation.playTogether( - ObjectAnimator.ofFloat(hintTextView, View.ALPHA, 1.0f) - ); - hintAnimation.addListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator animation) { - if (animation.equals(hintAnimation)) { - hintAnimation = null; - AndroidUtilities.runOnUIThread(hintHideRunnable = () -> hideHint(), 2000); - } - } - - @Override - public void onAnimationCancel(Animator animation) { - if (animation.equals(hintAnimation)) { - hintAnimation = null; - } - } - }); - hintAnimation.setDuration(300); - hintAnimation.start(); - } - @SuppressLint({"NewApi", "DrawAllocation"}) private void onDraw(Canvas canvas) { if (animationInProgress == 1 || !isVisible && animationInProgress != 2 && !pipAnimationInProgress) { @@ -7848,6 +7953,12 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat } if (switchImageAfterAnimation != 0) { openedFullScreenVideo = false; + if (!imagesArrLocals.isEmpty() && currentIndex >= 0 && currentIndex < imagesArrLocals.size()) { + Object object = imagesArrLocals.get(currentIndex); + if (object instanceof MediaController.PhotoEntry) { + ((MediaController.PhotoEntry) object).editedInfo = getCurrentVideoEditedInfo(); + } + } if (switchImageAfterAnimation == 1) { AndroidUtilities.runOnUIThread(() -> setImageIndex(currentIndex + 1, false)); } else if (switchImageAfterAnimation == 2) { @@ -8356,6 +8467,8 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat private boolean videoHasAudio; private long startTime; private long endTime; + private float videoCutStart; + private float videoCutEnd; private long audioFramesSize; private long videoFramesSize; private int estimatedSize; @@ -8591,15 +8704,17 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat estimatedSize += estimatedSize / (32 * 1024) * 16; } - if (videoTimelineView.getLeftProgress() == 0) { + videoCutStart = videoTimelineView.getLeftProgress(); + videoCutEnd = videoTimelineView.getRightProgress(); + if (videoCutStart == 0) { startTime = -1; } else { - startTime = (long) (videoTimelineView.getLeftProgress() * videoDuration) * 1000; + startTime = (long) (videoCutStart * videoDuration) * 1000; } - if (videoTimelineView.getRightProgress() == 1) { + if (videoCutEnd == 1) { endTime = -1; } else { - endTime = (long) (videoTimelineView.getRightProgress() * videoDuration) * 1000; + endTime = (long) (videoCutEnd * videoDuration) * 1000; } String videoDimension = String.format("%dx%d", width, height); @@ -8699,7 +8814,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat break; case 3: default: - targetBitrate = 2500000; + targetBitrate = 2621440; maxSize = 1280.0f; break; } @@ -8802,15 +8917,20 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat return new ByteArrayInputStream(output, 0, outPos); } - private void processOpenVideo(final String videoPath, boolean muted) { + private void processOpenVideo(final String videoPath, boolean muted, float start, float end) { if (currentLoadingVideoRunnable != null) { Utilities.globalQueue.cancelRunnable(currentLoadingVideoRunnable); currentLoadingVideoRunnable = null; } + videoTimelineView.setVideoPath(videoPath, start, end); videoPreviewMessageObject = null; setCompressItemEnabled(false, true); muteVideo = muted; - videoTimelineView.setVideoPath(videoPath); + Object object = imagesArrLocals.get(currentIndex); + if (object instanceof MediaController.PhotoEntry) { + ((MediaController.PhotoEntry) object).editedInfo = getCurrentVideoEditedInfo(); + } + compressionsCount = -1; rotationValue = 0; videoFramerate = 25; @@ -8965,127 +9085,81 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat @Override public int getItemCount() { if (placeProvider != null && placeProvider.getSelectedPhotosOrder() != null) { - if (placeProvider.allowGroupPhotos()) { - return 1 + placeProvider.getSelectedPhotosOrder().size(); - } else { - return placeProvider.getSelectedPhotosOrder().size(); - } + return placeProvider.getSelectedPhotosOrder().size(); } return 0; } @Override public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { - View view; - switch (viewType) { - case 0: - PhotoPickerPhotoCell cell = new PhotoPickerPhotoCell(mContext, false); - cell.checkFrame.setOnClickListener(v -> { - Object photoEntry = ((View) v.getParent()).getTag(); - int idx = imagesArrLocals.indexOf(photoEntry); - if (idx >= 0) { - int num = placeProvider.setPhotoChecked(idx, getCurrentVideoEditedInfo()); - boolean checked = placeProvider.isPhotoChecked(idx); - if (idx == currentIndex) { - checkImageView.setChecked(-1, false, true); - } - if (num >= 0) { - if (placeProvider.allowGroupPhotos()) { - num++; - } - selectedPhotosAdapter.notifyItemRemoved(num); - } - updateSelectedCount(); - } else { - int num = placeProvider.setPhotoUnchecked(photoEntry); - if (num >= 0) { - if (placeProvider.allowGroupPhotos()) { - num++; - } - selectedPhotosAdapter.notifyItemRemoved(num); - updateSelectedCount(); - } - } - }); - view = cell; - break; - case 1: - default: - ImageView imageView = new ImageView(mContext) { - @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - super.onMeasure(MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(66), MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(heightMeasureSpec), MeasureSpec.EXACTLY)); - } - }; - imageView.setScaleType(ImageView.ScaleType.CENTER); - imageView.setImageResource(R.drawable.photos_group); - imageView.setFocusable(true); - view = imageView; - break; - } - return new RecyclerListView.Holder(view); + PhotoPickerPhotoCell cell = new PhotoPickerPhotoCell(mContext, false); + cell.checkFrame.setOnClickListener(v -> { + Object photoEntry = ((View) v.getParent()).getTag(); + int idx = imagesArrLocals.indexOf(photoEntry); + if (idx >= 0) { + int num = placeProvider.setPhotoChecked(idx, getCurrentVideoEditedInfo()); + boolean checked = placeProvider.isPhotoChecked(idx); + if (idx == currentIndex) { + checkImageView.setChecked(-1, false, true); + } + if (num >= 0) { + selectedPhotosAdapter.notifyItemRemoved(num); + } + updateSelectedCount(); + } else { + int num = placeProvider.setPhotoUnchecked(photoEntry); + if (num >= 0) { + selectedPhotosAdapter.notifyItemRemoved(num); + updateSelectedCount(); + } + } + }); + return new RecyclerListView.Holder(cell); } @Override public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { - switch (holder.getItemViewType()) { - case 0: { - PhotoPickerPhotoCell cell = (PhotoPickerPhotoCell) holder.itemView; - cell.itemWidth = AndroidUtilities.dp(82); - BackupImageView imageView = cell.photoImage; - boolean showing; - imageView.setOrientation(0, true); - ArrayList order = placeProvider.getSelectedPhotosOrder(); - if (placeProvider.allowGroupPhotos()) { - position--; + PhotoPickerPhotoCell cell = (PhotoPickerPhotoCell) holder.itemView; + cell.itemWidth = AndroidUtilities.dp(82); + BackupImageView imageView = cell.imageView; + boolean showing; + imageView.setOrientation(0, true); + ArrayList order = placeProvider.getSelectedPhotosOrder(); + Object object = placeProvider.getSelectedPhotos().get(order.get(position)); + if (object instanceof MediaController.PhotoEntry) { + MediaController.PhotoEntry photoEntry = (MediaController.PhotoEntry) object; + cell.setTag(photoEntry); + cell.videoInfoContainer.setVisibility(View.INVISIBLE); + if (photoEntry.thumbPath != null) { + imageView.setImage(photoEntry.thumbPath, null, mContext.getResources().getDrawable(R.drawable.nophotos)); + } else if (photoEntry.path != null) { + imageView.setOrientation(photoEntry.orientation, true); + if (photoEntry.isVideo) { + cell.videoInfoContainer.setVisibility(View.VISIBLE); + int minutes = photoEntry.duration / 60; + int seconds = photoEntry.duration - minutes * 60; + cell.videoTextView.setText(String.format("%d:%02d", minutes, seconds)); + imageView.setImage("vthumb://" + photoEntry.imageId + ":" + photoEntry.path, null, mContext.getResources().getDrawable(R.drawable.nophotos)); + } else { + imageView.setImage("thumb://" + photoEntry.imageId + ":" + photoEntry.path, null, mContext.getResources().getDrawable(R.drawable.nophotos)); } - Object object = placeProvider.getSelectedPhotos().get(order.get(position)); - if (object instanceof MediaController.PhotoEntry) { - MediaController.PhotoEntry photoEntry = (MediaController.PhotoEntry) object; - cell.setTag(photoEntry); - cell.videoInfoContainer.setVisibility(View.INVISIBLE); - if (photoEntry.thumbPath != null) { - imageView.setImage(photoEntry.thumbPath, null, mContext.getResources().getDrawable(R.drawable.nophotos)); - } else if (photoEntry.path != null) { - imageView.setOrientation(photoEntry.orientation, true); - if (photoEntry.isVideo) { - cell.videoInfoContainer.setVisibility(View.VISIBLE); - int minutes = photoEntry.duration / 60; - int seconds = photoEntry.duration - minutes * 60; - cell.videoTextView.setText(String.format("%d:%02d", minutes, seconds)); - imageView.setImage("vthumb://" + photoEntry.imageId + ":" + photoEntry.path, null, mContext.getResources().getDrawable(R.drawable.nophotos)); - } else { - imageView.setImage("thumb://" + photoEntry.imageId + ":" + photoEntry.path, null, mContext.getResources().getDrawable(R.drawable.nophotos)); - } - } else { - imageView.setImageResource(R.drawable.nophotos); - } - cell.setChecked(-1, true, false); - cell.checkBox.setVisibility(View.VISIBLE); - } else if (object instanceof MediaController.SearchImage) { - MediaController.SearchImage photoEntry = (MediaController.SearchImage) object; - cell.setTag(photoEntry); - cell.setImage(photoEntry); - cell.videoInfoContainer.setVisibility(View.INVISIBLE); - cell.setChecked(-1, true, false); - cell.checkBox.setVisibility(View.VISIBLE); - } - break; - } - case 1: { - ImageView imageView = (ImageView) holder.itemView; - imageView.setColorFilter(SharedConfig.groupPhotosEnabled ? new PorterDuffColorFilter(0xff66bffa, PorterDuff.Mode.MULTIPLY) : null); - imageView.setContentDescription(SharedConfig.groupPhotosEnabled ? LocaleController.getString("GroupPhotosHelp", R.string.GroupPhotosHelp) : LocaleController.getString("SinglePhotosHelp", R.string.SinglePhotosHelp)); - break; + } else { + imageView.setImageResource(R.drawable.nophotos); } + cell.setChecked(-1, true, false); + cell.checkBox.setVisibility(View.VISIBLE); + } else if (object instanceof MediaController.SearchImage) { + MediaController.SearchImage photoEntry = (MediaController.SearchImage) object; + cell.setTag(photoEntry); + cell.setImage(photoEntry); + cell.videoInfoContainer.setVisibility(View.INVISIBLE); + cell.setChecked(-1, true, false); + cell.checkBox.setVisibility(View.VISIBLE); } } @Override public int getItemViewType(int i) { - if (i == 0 && placeProvider.allowGroupPhotos()) { - return 1; - } return 0; } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/PollCreateActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/PollCreateActivity.java index f38218fba..a2f8e946e 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/PollCreateActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/PollCreateActivity.java @@ -495,11 +495,9 @@ public class PollCreateActivity extends BaseFragment { @Override public void onViewAttachedToWindow(RecyclerView.ViewHolder holder) { - switch (holder.getItemViewType()) { - case 0: { - setTextLeft(holder.itemView, holder.getAdapterPosition() == questionHeaderRow ? -1 : 0); - break; - } + int viewType = holder.getItemViewType(); + if (viewType == 0 || viewType == 5) { + setTextLeft(holder.itemView, holder.getAdapterPosition() == questionHeaderRow ? -1 : 0); } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/PopupNotificationActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/PopupNotificationActivity.java index f0087ce14..f85f72c6a 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/PopupNotificationActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/PopupNotificationActivity.java @@ -416,6 +416,11 @@ public class PopupNotificationActivity extends Activity implements NotificationC public void needShowMediaBanHint() { } + + @Override + public void onUpdateSlowModeButton(View button, boolean show, CharSequence time) { + + } }); messageContainer = new FrameLayoutTouch(this); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/PrivacyControlActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/PrivacyControlActivity.java index f6be4dcad..d697c3fff 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/PrivacyControlActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/PrivacyControlActivity.java @@ -806,7 +806,7 @@ public class PrivacyControlActivity extends BaseFragment implements Notification if (ContactsController.getInstance(currentAccount).getLoadingPrivicyInfo(ContactsController.PRIVACY_RULES_TYPE_P2P)) { value = LocaleController.getString("Loading", R.string.Loading); } else { - value = PrivacySettingsActivity.formatRulesString(currentAccount, ContactsController.PRIVACY_RULES_TYPE_P2P); + value = PrivacySettingsActivity.formatRulesString(getAccountInstance(), ContactsController.PRIVACY_RULES_TYPE_P2P); } textCell.setTextAndValue(LocaleController.getString("PrivacyP2P2", R.string.PrivacyP2P2), value, false); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/PrivacySettingsActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/PrivacySettingsActivity.java index ca52fa754..3c35fe0b4 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/PrivacySettingsActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/PrivacySettingsActivity.java @@ -15,9 +15,9 @@ import android.widget.FrameLayout; import android.widget.LinearLayout; import android.widget.Toast; +import org.telegram.messenger.AccountInstance; import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.ContactsController; -import org.telegram.messenger.MediaDataController; import org.telegram.messenger.LocaleController; import org.telegram.messenger.MessagesController; import org.telegram.messenger.NotificationCenter; @@ -26,7 +26,6 @@ import org.telegram.messenger.R; import org.telegram.messenger.SharedConfig; import org.telegram.tgnet.ConnectionsManager; import org.telegram.tgnet.TLRPC; -import org.telegram.messenger.UserConfig; import org.telegram.ui.ActionBar.ActionBar; import org.telegram.ui.ActionBar.AlertDialog; import org.telegram.ui.ActionBar.BaseFragment; @@ -100,14 +99,16 @@ public class PrivacySettingsActivity extends BaseFragment implements Notificatio public boolean onFragmentCreate() { super.onFragmentCreate(); - ContactsController.getInstance(currentAccount).loadPrivacySettings(); - currentSync = newSync = UserConfig.getInstance(currentAccount).syncContacts; - currentSuggest = newSuggest = UserConfig.getInstance(currentAccount).suggestContacts; + getContactsController().loadPrivacySettings(); + getMessagesController().getBlockedUsers(true); + currentSync = newSync = getUserConfig().syncContacts; + currentSuggest = newSuggest = getUserConfig().suggestContacts; updateRows(); loadPasswordSettings(); - NotificationCenter.getInstance(currentAccount).addObserver(this, NotificationCenter.privacyRulesUpdated); + getNotificationCenter().addObserver(this, NotificationCenter.privacyRulesUpdated); + getNotificationCenter().addObserver(this, NotificationCenter.blockedUsersDidLoad); return true; } @@ -115,12 +116,13 @@ public class PrivacySettingsActivity extends BaseFragment implements Notificatio @Override public void onFragmentDestroy() { super.onFragmentDestroy(); - NotificationCenter.getInstance(currentAccount).removeObserver(this, NotificationCenter.privacyRulesUpdated); + getNotificationCenter().removeObserver(this, NotificationCenter.privacyRulesUpdated); + getNotificationCenter().removeObserver(this, NotificationCenter.blockedUsersDidLoad); if (currentSync != newSync) { - UserConfig.getInstance(currentAccount).syncContacts = newSync; - UserConfig.getInstance(currentAccount).saveConfig(false); + getUserConfig().syncContacts = newSync; + getUserConfig().saveConfig(false); if (newSync) { - ContactsController.getInstance(currentAccount).forceImportContacts(); + getContactsController().forceImportContacts(); if (getParentActivity() != null) { Toast.makeText(getParentActivity(), LocaleController.getString("SyncContactsAdded", R.string.SyncContactsAdded), Toast.LENGTH_SHORT).show(); } @@ -128,13 +130,13 @@ public class PrivacySettingsActivity extends BaseFragment implements Notificatio } if (newSuggest != currentSuggest) { if (!newSuggest) { - MediaDataController.getInstance(currentAccount).clearTopPeers(); + getMediaDataController().clearTopPeers(); } - UserConfig.getInstance(currentAccount).suggestContacts = newSuggest; - UserConfig.getInstance(currentAccount).saveConfig(false); + getUserConfig().suggestContacts = newSuggest; + getUserConfig().saveConfig(false); TLRPC.TL_contacts_toggleTopPeers req = new TLRPC.TL_contacts_toggleTopPeers(); req.enabled = newSuggest; - ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> { + getConnectionsManager().sendRequest(req, (response, error) -> { }); } @@ -188,7 +190,7 @@ public class PrivacySettingsActivity extends BaseFragment implements Notificatio builder.setMessage(LocaleController.getString("AreYouSureClearDrafts", R.string.AreYouSureClearDrafts)); builder.setPositiveButton(LocaleController.getString("Delete", R.string.Delete), (dialogInterface, i) -> { TLRPC.TL_messages_clearAllDrafts req = new TLRPC.TL_messages_clearAllDrafts(); - ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> AndroidUtilities.runOnUIThread(() -> MediaDataController.getInstance(currentAccount).clearAllDrafts())); + getConnectionsManager().sendRequest(req, (response, error) -> AndroidUtilities.runOnUIThread(() -> getMediaDataController().clearAllDrafts())); }); builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); showDialog(builder.create()); @@ -221,14 +223,14 @@ public class PrivacySettingsActivity extends BaseFragment implements Notificatio final TLRPC.TL_account_setAccountTTL req = new TLRPC.TL_account_setAccountTTL(); req.ttl = new TLRPC.TL_accountDaysTTL(); req.ttl.days = value; - ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> AndroidUtilities.runOnUIThread(() -> { + getConnectionsManager().sendRequest(req, (response, error) -> AndroidUtilities.runOnUIThread(() -> { try { progressDialog.dismiss(); } catch (Exception e) { FileLog.e(e); } if (response instanceof TLRPC.TL_boolTrue) { - ContactsController.getInstance(currentAccount).setDeleteAccountTTL(req.ttl.days); + getContactsController().setDeleteAccountTTL(req.ttl.days); listAdapter.notifyDataSetChanged(); } })); @@ -256,14 +258,14 @@ public class PrivacySettingsActivity extends BaseFragment implements Notificatio presentFragment(new PasscodeActivity(0)); } } else if (position == secretWebpageRow) { - if (MessagesController.getInstance(currentAccount).secretWebpagePreview == 1) { - MessagesController.getInstance(currentAccount).secretWebpagePreview = 0; + if (getMessagesController().secretWebpagePreview == 1) { + getMessagesController().secretWebpagePreview = 0; } else { - MessagesController.getInstance(currentAccount).secretWebpagePreview = 1; + getMessagesController().secretWebpagePreview = 1; } - MessagesController.getGlobalMainSettings().edit().putInt("secretWebpage2", MessagesController.getInstance(currentAccount).secretWebpagePreview).commit(); + MessagesController.getGlobalMainSettings().edit().putInt("secretWebpage2", getMessagesController().secretWebpagePreview).commit(); if (view instanceof TextCheckCell) { - ((TextCheckCell) view).setChecked(MessagesController.getInstance(currentAccount).secretWebpagePreview == 1); + ((TextCheckCell) view).setChecked(getMessagesController().secretWebpagePreview == 1); } } else if (position == contactsDeleteRow) { if (getParentActivity() == null) { @@ -279,10 +281,10 @@ public class PrivacySettingsActivity extends BaseFragment implements Notificatio progressDialog.setCanCacnel(false); if (currentSync != newSync) { - currentSync = UserConfig.getInstance(currentAccount).syncContacts = newSync; - UserConfig.getInstance(currentAccount).saveConfig(false); + currentSync = getUserConfig().syncContacts = newSync; + getUserConfig().saveConfig(false); } - ContactsController.getInstance(currentAccount).deleteAllContacts(() -> progressDialog.dismiss()); + getContactsController().deleteAllContacts(() -> progressDialog.dismiss()); }); showDialog(builder.create()); } else if (position == contactsSuggestRow) { @@ -295,9 +297,9 @@ public class PrivacySettingsActivity extends BaseFragment implements Notificatio TLRPC.TL_payments_clearSavedInfo req = new TLRPC.TL_payments_clearSavedInfo(); req.credentials = clear[1]; req.info = clear[0]; - UserConfig.getInstance(currentAccount).tmpPassword = null; - UserConfig.getInstance(currentAccount).saveConfig(false); - ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> AndroidUtilities.runOnUIThread(() -> { + getUserConfig().tmpPassword = null; + getUserConfig().saveConfig(false); + getConnectionsManager().sendRequest(req, (response, error) -> AndroidUtilities.runOnUIThread(() -> { newSuggest = !newSuggest; cell.setChecked(newSuggest); })); @@ -361,9 +363,9 @@ public class PrivacySettingsActivity extends BaseFragment implements Notificatio TLRPC.TL_payments_clearSavedInfo req = new TLRPC.TL_payments_clearSavedInfo(); req.credentials = clear[1]; req.info = clear[0]; - UserConfig.getInstance(currentAccount).tmpPassword = null; - UserConfig.getInstance(currentAccount).saveConfig(false); - ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> { + getUserConfig().tmpPassword = null; + getUserConfig().saveConfig(false); + getConnectionsManager().sendRequest(req, (response, error) -> { }); }); @@ -387,6 +389,8 @@ public class PrivacySettingsActivity extends BaseFragment implements Notificatio if (listAdapter != null) { listAdapter.notifyDataSetChanged(); } + } else if (id == NotificationCenter.blockedUsersDidLoad) { + listAdapter.notifyItemChanged(blockedRow); } } @@ -411,7 +415,7 @@ public class PrivacySettingsActivity extends BaseFragment implements Notificatio deleteAccountRow = rowCount++; deleteAccountDetailRow = rowCount++; botsSectionRow = rowCount++; - if (UserConfig.getInstance(currentAccount).hasSecureData) { + if (getUserConfig().hasSecureData) { passportRow = rowCount++; } else { passportRow = -1; @@ -434,17 +438,17 @@ public class PrivacySettingsActivity extends BaseFragment implements Notificatio } private void loadPasswordSettings() { - if (UserConfig.getInstance(currentAccount).hasSecureData) { + if (getUserConfig().hasSecureData) { return; } TLRPC.TL_account_getPassword req = new TLRPC.TL_account_getPassword(); - ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> { + getConnectionsManager().sendRequest(req, (response, error) -> { if (response != null) { TLRPC.TL_account_password password = (TLRPC.TL_account_password) response; if (password.has_secure_values) { AndroidUtilities.runOnUIThread(() -> { - UserConfig.getInstance(currentAccount).hasSecureData = true; - UserConfig.getInstance(currentAccount).saveConfig(false); + getUserConfig().hasSecureData = true; + getUserConfig().saveConfig(false); updateRows(); }); } @@ -452,8 +456,8 @@ public class PrivacySettingsActivity extends BaseFragment implements Notificatio }, ConnectionsManager.RequestFlagFailOnServerErrors | ConnectionsManager.RequestFlagWithoutLogin); } - public static String formatRulesString(int currentAccount, int rulesType) { - ArrayList privacyRules = ContactsController.getInstance(currentAccount).getPrivacyRules(rulesType); + public static String formatRulesString(AccountInstance accountInstance, int rulesType) { + ArrayList privacyRules = accountInstance.getContactsController().getPrivacyRules(rulesType); if (privacyRules.size() == 0) { if (rulesType == 3) { return LocaleController.getString("P2PNobody", R.string.P2PNobody); @@ -469,7 +473,7 @@ public class PrivacySettingsActivity extends BaseFragment implements Notificatio if (rule instanceof TLRPC.TL_privacyValueAllowChatParticipants) { TLRPC.TL_privacyValueAllowChatParticipants participants = (TLRPC.TL_privacyValueAllowChatParticipants) rule; for (int b = 0, N = participants.chats.size(); b < N; b++) { - TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(participants.chats.get(b)); + TLRPC.Chat chat = accountInstance.getMessagesController().getChat(participants.chats.get(b)); if (chat == null) { continue; } @@ -478,7 +482,7 @@ public class PrivacySettingsActivity extends BaseFragment implements Notificatio } else if (rule instanceof TLRPC.TL_privacyValueDisallowChatParticipants) { TLRPC.TL_privacyValueDisallowChatParticipants participants = (TLRPC.TL_privacyValueDisallowChatParticipants) rule; for (int b = 0, N = participants.chats.size(); b < N; b++) { - TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(participants.chats.get(b)); + TLRPC.Chat chat = accountInstance.getMessagesController().getChat(participants.chats.get(b)); if (chat == null) { continue; } @@ -578,13 +582,13 @@ public class PrivacySettingsActivity extends BaseFragment implements Notificatio public boolean isEnabled(RecyclerView.ViewHolder holder) { int position = holder.getAdapterPosition(); return position == passcodeRow || position == passwordRow || position == blockedRow || position == sessionsRow || position == secretWebpageRow || position == webSessionsRow || position == clearDraftsRow || - position == groupsRow && !ContactsController.getInstance(currentAccount).getLoadingPrivicyInfo(ContactsController.PRIVACY_RULES_TYPE_INVITE) || - position == lastSeenRow && !ContactsController.getInstance(currentAccount).getLoadingPrivicyInfo(ContactsController.PRIVACY_RULES_TYPE_LASTSEEN) || - position == callsRow && !ContactsController.getInstance(currentAccount).getLoadingPrivicyInfo(ContactsController.PRIVACY_RULES_TYPE_CALLS) || - position == profilePhotoRow && !ContactsController.getInstance(currentAccount).getLoadingPrivicyInfo(ContactsController.PRIVACY_RULES_TYPE_PHOTO) || - position == forwardsRow && !ContactsController.getInstance(currentAccount).getLoadingPrivicyInfo(ContactsController.PRIVACY_RULES_TYPE_FORWARDS) || - position == phoneNumberRow && !ContactsController.getInstance(currentAccount).getLoadingPrivicyInfo(ContactsController.PRIVACY_RULES_TYPE_PHONE) || - position == deleteAccountRow && !ContactsController.getInstance(currentAccount).getLoadingDeleteInfo() || + position == groupsRow && !getContactsController().getLoadingPrivicyInfo(ContactsController.PRIVACY_RULES_TYPE_INVITE) || + position == lastSeenRow && !getContactsController().getLoadingPrivicyInfo(ContactsController.PRIVACY_RULES_TYPE_LASTSEEN) || + position == callsRow && !getContactsController().getLoadingPrivicyInfo(ContactsController.PRIVACY_RULES_TYPE_CALLS) || + position == profilePhotoRow && !getContactsController().getLoadingPrivicyInfo(ContactsController.PRIVACY_RULES_TYPE_PHOTO) || + position == forwardsRow && !getContactsController().getLoadingPrivicyInfo(ContactsController.PRIVACY_RULES_TYPE_FORWARDS) || + position == phoneNumberRow && !getContactsController().getLoadingPrivicyInfo(ContactsController.PRIVACY_RULES_TYPE_PHONE) || + position == deleteAccountRow && !getContactsController().getLoadingDeleteInfo() || position == paymentsClearRow || position == secretMapRow || position == contactsSyncRow || position == passportRow || position == contactsDeleteRow || position == contactsSuggestRow; } @@ -623,12 +627,11 @@ public class PrivacySettingsActivity extends BaseFragment implements Notificatio case 0: TextSettingsCell textCell = (TextSettingsCell) holder.itemView; if (position == blockedRow) { - if (!getMessagesController().loadingBlockedUsers) { - if (getMessagesController().blockedUsers.size() == 0) { - textCell.setTextAndValue(LocaleController.getString("BlockedUsers", R.string.BlockedUsers), LocaleController.getString("BlockedEmpty", R.string.BlockedEmpty), true); - } else { - textCell.setTextAndValue(LocaleController.getString("BlockedUsers", R.string.BlockedUsers), String.format("%d", getMessagesController().blockedUsers.size()), true); - } + int totalCount = getMessagesController().totalBlockedCount; + if (totalCount == 0) { + textCell.setTextAndValue(LocaleController.getString("BlockedUsers", R.string.BlockedUsers), LocaleController.getString("BlockedEmpty", R.string.BlockedEmpty), true); + } else if (totalCount > 0) { + textCell.setTextAndValue(LocaleController.getString("BlockedUsers", R.string.BlockedUsers), String.format("%d", totalCount), true); } else { textCell.setText(LocaleController.getString("BlockedUsers", R.string.BlockedUsers), true); } @@ -642,60 +645,60 @@ public class PrivacySettingsActivity extends BaseFragment implements Notificatio textCell.setText(LocaleController.getString("Passcode", R.string.Passcode), true); } else if (position == phoneNumberRow) { String value; - if (ContactsController.getInstance(currentAccount).getLoadingPrivicyInfo(ContactsController.PRIVACY_RULES_TYPE_PHONE)) { + if (getContactsController().getLoadingPrivicyInfo(ContactsController.PRIVACY_RULES_TYPE_PHONE)) { value = LocaleController.getString("Loading", R.string.Loading); } else { - value = formatRulesString(currentAccount, ContactsController.PRIVACY_RULES_TYPE_PHONE); + value = formatRulesString(getAccountInstance(), ContactsController.PRIVACY_RULES_TYPE_PHONE); } textCell.setTextAndValue(LocaleController.getString("PrivacyPhone", R.string.PrivacyPhone), value, true); } else if (position == lastSeenRow) { String value; - if (ContactsController.getInstance(currentAccount).getLoadingPrivicyInfo(ContactsController.PRIVACY_RULES_TYPE_LASTSEEN)) { + if (getContactsController().getLoadingPrivicyInfo(ContactsController.PRIVACY_RULES_TYPE_LASTSEEN)) { value = LocaleController.getString("Loading", R.string.Loading); } else { - value = formatRulesString(currentAccount, ContactsController.PRIVACY_RULES_TYPE_LASTSEEN); + value = formatRulesString(getAccountInstance(), ContactsController.PRIVACY_RULES_TYPE_LASTSEEN); } textCell.setTextAndValue(LocaleController.getString("PrivacyLastSeen", R.string.PrivacyLastSeen), value, true); } else if (position == groupsRow) { String value; - if (ContactsController.getInstance(currentAccount).getLoadingPrivicyInfo(ContactsController.PRIVACY_RULES_TYPE_INVITE)) { + if (getContactsController().getLoadingPrivicyInfo(ContactsController.PRIVACY_RULES_TYPE_INVITE)) { value = LocaleController.getString("Loading", R.string.Loading); } else { - value = formatRulesString(currentAccount, ContactsController.PRIVACY_RULES_TYPE_INVITE); + value = formatRulesString(getAccountInstance(), ContactsController.PRIVACY_RULES_TYPE_INVITE); } textCell.setTextAndValue(LocaleController.getString("GroupsAndChannels", R.string.GroupsAndChannels), value, false); } else if (position == callsRow) { String value; - if (ContactsController.getInstance(currentAccount).getLoadingPrivicyInfo(ContactsController.PRIVACY_RULES_TYPE_CALLS)) { + if (getContactsController().getLoadingPrivicyInfo(ContactsController.PRIVACY_RULES_TYPE_CALLS)) { value = LocaleController.getString("Loading", R.string.Loading); } else { - value = formatRulesString(currentAccount, ContactsController.PRIVACY_RULES_TYPE_CALLS); + value = formatRulesString(getAccountInstance(), ContactsController.PRIVACY_RULES_TYPE_CALLS); } textCell.setTextAndValue(LocaleController.getString("Calls", R.string.Calls), value, true); } else if (position == profilePhotoRow) { String value; - if (ContactsController.getInstance(currentAccount).getLoadingPrivicyInfo(ContactsController.PRIVACY_RULES_TYPE_PHOTO)) { + if (getContactsController().getLoadingPrivicyInfo(ContactsController.PRIVACY_RULES_TYPE_PHOTO)) { value = LocaleController.getString("Loading", R.string.Loading); } else { - value = formatRulesString(currentAccount, ContactsController.PRIVACY_RULES_TYPE_PHOTO); + value = formatRulesString(getAccountInstance(), ContactsController.PRIVACY_RULES_TYPE_PHOTO); } textCell.setTextAndValue(LocaleController.getString("PrivacyProfilePhoto", R.string.PrivacyProfilePhoto), value, true); } else if (position == forwardsRow) { String value; - if (ContactsController.getInstance(currentAccount).getLoadingPrivicyInfo(ContactsController.PRIVACY_RULES_TYPE_FORWARDS)) { + if (getContactsController().getLoadingPrivicyInfo(ContactsController.PRIVACY_RULES_TYPE_FORWARDS)) { value = LocaleController.getString("Loading", R.string.Loading); } else { - value = formatRulesString(currentAccount, ContactsController.PRIVACY_RULES_TYPE_FORWARDS); + value = formatRulesString(getAccountInstance(), ContactsController.PRIVACY_RULES_TYPE_FORWARDS); } textCell.setTextAndValue(LocaleController.getString("PrivacyForwards", R.string.PrivacyForwards), value, true); } else if (position == passportRow) { textCell.setText(LocaleController.getString("TelegramPassport", R.string.TelegramPassport), true); } else if (position == deleteAccountRow) { String value; - if (ContactsController.getInstance(currentAccount).getLoadingDeleteInfo()) { + if (getContactsController().getLoadingDeleteInfo()) { value = LocaleController.getString("Loading", R.string.Loading); } else { - int ttl = ContactsController.getInstance(currentAccount).getDeleteAccountTTL(); + int ttl = getContactsController().getDeleteAccountTTL(); if (ttl <= 182) { value = LocaleController.formatPluralString("Months", ttl / 30); } else if (ttl == 365) { @@ -774,7 +777,7 @@ public class PrivacySettingsActivity extends BaseFragment implements Notificatio case 3: TextCheckCell textCheckCell = (TextCheckCell) holder.itemView; if (position == secretWebpageRow) { - textCheckCell.setTextAndCheck(LocaleController.getString("SecretWebPage", R.string.SecretWebPage), MessagesController.getInstance(currentAccount).secretWebpagePreview == 1, false); + textCheckCell.setTextAndCheck(LocaleController.getString("SecretWebPage", R.string.SecretWebPage), getMessagesController().secretWebpagePreview == 1, false); } else if (position == contactsSyncRow) { textCheckCell.setTextAndCheck(LocaleController.getString("SyncContacts", R.string.SyncContacts), newSync, true); } else if (position == contactsSuggestRow) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/PrivacyUsersActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/PrivacyUsersActivity.java index 2826f1b29..b80d30423 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/PrivacyUsersActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/PrivacyUsersActivity.java @@ -44,6 +44,7 @@ import androidx.recyclerview.widget.RecyclerView; public class PrivacyUsersActivity extends BaseFragment implements NotificationCenter.NotificationCenterDelegate, ContactsActivity.ContactsActivityDelegate { private RecyclerListView listView; + private LinearLayoutManager layoutManager; private ListAdapter listViewAdapter; private EmptyTextProgressView emptyView; @@ -86,7 +87,6 @@ public class PrivacyUsersActivity extends BaseFragment implements NotificationCe NotificationCenter.getInstance(currentAccount).addObserver(this, NotificationCenter.updateInterfaces); if (blockedUsersActivity) { NotificationCenter.getInstance(currentAccount).addObserver(this, NotificationCenter.blockedUsersDidLoad); - getMessagesController().getBlockedUsers(false); } return true; } @@ -144,7 +144,7 @@ public class PrivacyUsersActivity extends BaseFragment implements NotificationCe listView = new RecyclerListView(context); listView.setEmptyView(emptyView); - listView.setLayoutManager(new LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false)); + listView.setLayoutManager(layoutManager = new LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false)); listView.setVerticalScrollBarEnabled(false); listView.setAdapter(listViewAdapter = new ListAdapter(context)); listView.setVerticalScrollbarPosition(LocaleController.isRTL ? RecyclerListView.SCROLLBAR_POSITION_LEFT : RecyclerListView.SCROLLBAR_POSITION_RIGHT); @@ -203,7 +203,26 @@ public class PrivacyUsersActivity extends BaseFragment implements NotificationCe return false; }); - if (getMessagesController().loadingBlockedUsers) { + if (blockedUsersActivity) { + listView.setOnScrollListener(new RecyclerView.OnScrollListener() { + @Override + public void onScrolled(RecyclerView recyclerView, int dx, int dy) { + if (getMessagesController().blockedEndReached) { + return; + } + int firstVisibleItem = layoutManager.findFirstVisibleItemPosition(); + int visibleItemCount = Math.abs(layoutManager.findLastVisibleItemPosition() - firstVisibleItem) + 1; + int totalItemCount = recyclerView.getAdapter().getItemCount(); + if (visibleItemCount > 0) { + if (layoutManager.findLastVisibleItemPosition() >= totalItemCount - 10) { + getMessagesController().getBlockedUsers(false); + } + } + } + }); + } + + if (getMessagesController().totalBlockedCount < 0) { emptyView.showProgress(); } else { emptyView.showTextView(); @@ -248,7 +267,7 @@ public class PrivacyUsersActivity extends BaseFragment implements NotificationCe private void updateRows() { rowCount = 0; - if (!blockedUsersActivity || !getMessagesController().loadingBlockedUsers) { + if (!blockedUsersActivity || getMessagesController().totalBlockedCount >= 0) { blockUserRow = rowCount++; blockUserDetailRow = rowCount++; @@ -442,7 +461,7 @@ public class PrivacyUsersActivity extends BaseFragment implements NotificationCe HeaderCell headerCell = (HeaderCell) holder.itemView; if (position == usersHeaderRow) { if (blockedUsersActivity) { - headerCell.setText(LocaleController.formatPluralString("BlockedUsersCount", getMessagesController().blockedUsers.size())); + headerCell.setText(LocaleController.formatPluralString("BlockedUsersCount", getMessagesController().totalBlockedCount)); } else { headerCell.setText(LocaleController.getString("PrivacyExceptions", R.string.PrivacyExceptions)); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ProfileActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ProfileActivity.java index a8c15e862..f0b54c27e 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ProfileActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ProfileActivity.java @@ -373,14 +373,13 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. sortedUsers = new ArrayList<>(); updateOnlineCount(); - + if (chatInfo == null) { + chatInfo = getMessagesController().getChatFull(chat_id); + } if (ChatObject.isChannel(currentChat)) { MessagesController.getInstance(currentAccount).loadFullChat(chat_id, classGuid, true); } else if (chatInfo == null) { - MessagesController.getInstance(currentAccount).loadChatInfo(chat_id, null, false); - } - if (chatInfo == null) { - chatInfo = getMessagesController().getChatFull(chat_id); + chatInfo = getMessagesStorage().loadChatInfo(chat_id, null, false, false); } } else { return false; @@ -995,11 +994,21 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. AlertDialog.Builder builder2 = new AlertDialog.Builder(getParentActivity()); builder2.setTitle(LocaleController.getString("AppName", R.string.AppName)); builder2.setMessage(LocaleController.formatString("AdminWillBeRemoved", R.string.AdminWillBeRemoved, ContactsController.formatName(user.first_name, user.last_name))); - builder2.setPositiveButton(LocaleController.getString("OK", R.string.OK), (dialog, which) -> openRightsEdit(action, user.id, participant, channelParticipant != null ? channelParticipant.admin_rights : null, channelParticipant != null ? channelParticipant.banned_rights : null)); + builder2.setPositiveButton(LocaleController.getString("OK", R.string.OK), (dialog, which) -> { + if (channelParticipant != null) { + openRightsEdit(action, user.id, participant, channelParticipant.admin_rights, channelParticipant.banned_rights, channelParticipant.rank); + } else { + openRightsEdit(action, user.id, participant, null, null, ""); + } + }); builder2.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); showDialog(builder2.create()); } else { - openRightsEdit(action, user.id, participant, channelParticipant != null ? channelParticipant.admin_rights : null, channelParticipant != null ? channelParticipant.banned_rights : null); + if (channelParticipant != null) { + openRightsEdit(action, user.id, participant, channelParticipant.admin_rights, channelParticipant.banned_rights, channelParticipant.rank); + } else { + openRightsEdit(action, user.id, participant, null, null, ""); + } } } }); @@ -1039,10 +1048,10 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. frameLayout.addView(frameLayout1, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 51, Gravity.LEFT | Gravity.BOTTOM)); frameLayout1.setOnClickListener(v -> { - ChatRightsEditActivity fragment = new ChatRightsEditActivity(user_id, banFromGroup, null, chat.default_banned_rights, currentChannelParticipant != null ? currentChannelParticipant.banned_rights : null, ChatRightsEditActivity.TYPE_BANNED, true, false); + ChatRightsEditActivity fragment = new ChatRightsEditActivity(user_id, banFromGroup, null, chat.default_banned_rights, currentChannelParticipant != null ? currentChannelParticipant.banned_rights : null, "", ChatRightsEditActivity.TYPE_BANNED, true, false); fragment.setDelegate(new ChatRightsEditActivity.ChatRightsEditActivityDelegate() { @Override - public void didSetRights(int rights, TLRPC.TL_chatAdminRights rightsAdmin, TLRPC.TL_chatBannedRights rightsBanned) { + public void didSetRights(int rights, TLRPC.TL_chatAdminRights rightsAdmin, TLRPC.TL_chatBannedRights rightsBanned, String rank) { removeSelfFromStack(); } @@ -1199,16 +1208,17 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. return fragmentView; } - private void openRightsEdit(int action, int user_id, TLRPC.ChatParticipant participant, TLRPC.TL_chatAdminRights adminRights, TLRPC.TL_chatBannedRights bannedRights) { - ChatRightsEditActivity fragment = new ChatRightsEditActivity(user_id, chat_id, adminRights, currentChat.default_banned_rights, bannedRights, action, true, false); + private void openRightsEdit(int action, int user_id, TLRPC.ChatParticipant participant, TLRPC.TL_chatAdminRights adminRights, TLRPC.TL_chatBannedRights bannedRights, String rank) { + ChatRightsEditActivity fragment = new ChatRightsEditActivity(user_id, chat_id, adminRights, currentChat.default_banned_rights, bannedRights, rank, action, true, false); fragment.setDelegate(new ChatRightsEditActivity.ChatRightsEditActivityDelegate() { @Override - public void didSetRights(int rights, TLRPC.TL_chatAdminRights rightsAdmin, TLRPC.TL_chatBannedRights rightsBanned) { + public void didSetRights(int rights, TLRPC.TL_chatAdminRights rightsAdmin, TLRPC.TL_chatBannedRights rightsBanned, String rank) { if (action == 0) { if (participant instanceof TLRPC.TL_chatChannelParticipant) { TLRPC.TL_chatChannelParticipant channelParticipant1 = ((TLRPC.TL_chatChannelParticipant) participant); if (rights == 1) { channelParticipant1.channelParticipant = new TLRPC.TL_channelParticipantAdmin(); + channelParticipant1.channelParticipant.flags |= 4; } else { channelParticipant1.channelParticipant = new TLRPC.TL_channelParticipant(); } @@ -1217,6 +1227,7 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. channelParticipant1.channelParticipant.date = participant.date; channelParticipant1.channelParticipant.banned_rights = rightsBanned; channelParticipant1.channelParticipant.admin_rights = rightsAdmin; + channelParticipant1.channelParticipant.rank = rank; } else if (participant instanceof TLRPC.ChatParticipant) { TLRPC.ChatParticipant newParticipant; if (rights == 1) { @@ -2025,10 +2036,8 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. @Override protected void onTransitionAnimationStart(boolean isOpen, boolean backward) { - if (!isOpen || !backward) { - if (!backward && playProfileAnimation && allowProfileAnimation) { - openAnimationInProgress = true; - } + if ((!isOpen && backward || isOpen && !backward) && playProfileAnimation && allowProfileAnimation) { + openAnimationInProgress = true; } if (isOpen) { NotificationCenter.getInstance(currentAccount).setAllowedNotificationsDutingAnimation(new int[]{NotificationCenter.dialogsNeedReload, NotificationCenter.closeChats, NotificationCenter.mediaCountDidLoad, NotificationCenter.mediaCountsDidLoad}); @@ -3376,24 +3385,30 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. part = chatInfo.participants.participants.get(position - membersStartRow); } if (part != null) { + String role; if (part instanceof TLRPC.TL_chatChannelParticipant) { TLRPC.ChannelParticipant channelParticipant = ((TLRPC.TL_chatChannelParticipant) part).channelParticipant; - if (channelParticipant instanceof TLRPC.TL_channelParticipantCreator) { - userCell.setIsAdmin(1); - } else if (channelParticipant instanceof TLRPC.TL_channelParticipantAdmin) { - userCell.setIsAdmin(2); + if (!TextUtils.isEmpty(channelParticipant.rank)) { + role = channelParticipant.rank; } else { - userCell.setIsAdmin(0); + if (channelParticipant instanceof TLRPC.TL_channelParticipantCreator) { + role = LocaleController.getString("ChannelCreator", R.string.ChannelCreator); + } else if (channelParticipant instanceof TLRPC.TL_channelParticipantAdmin) { + role = LocaleController.getString("ChannelAdmin", R.string.ChannelAdmin); + } else { + role = null; + } } } else { if (part instanceof TLRPC.TL_chatParticipantCreator) { - userCell.setIsAdmin(1); + role = LocaleController.getString("ChannelCreator", R.string.ChannelCreator); } else if (part instanceof TLRPC.TL_chatParticipantAdmin) { - userCell.setIsAdmin(2); + role = LocaleController.getString("ChannelAdmin", R.string.ChannelAdmin); } else { - userCell.setIsAdmin(0); + role = null; } } + userCell.setAdminRole(role); userCell.setData(MessagesController.getInstance(currentAccount).getUser(part.user_id), null, null, 0, position != membersEndRow - 1); } break; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/StickersActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/StickersActivity.java index c3daa0f20..6922962c6 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/StickersActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/StickersActivity.java @@ -35,6 +35,7 @@ import org.telegram.ui.ActionBar.Theme; import org.telegram.ui.ActionBar.ThemeDescription; import org.telegram.ui.Cells.ShadowSectionCell; import org.telegram.ui.Cells.StickerSetCell; +import org.telegram.ui.Cells.TextCheckCell; import org.telegram.ui.Cells.TextInfoPrivacyCell; import org.telegram.ui.Cells.TextSettingsCell; import org.telegram.ui.Components.LayoutHelper; @@ -60,6 +61,7 @@ public class StickersActivity extends BaseFragment implements NotificationCenter private int currentType; private int suggestRow; + private int loopRow; private int suggestInfoRow; private int featuredRow; private int featuredInfoRow; @@ -215,6 +217,11 @@ public class StickersActivity extends BaseFragment implements NotificationCenter listAdapter.notifyItemChanged(suggestRow); }); showDialog(builder.create()); + } else if (position == loopRow) { + SharedConfig.toggleLoopStickers(); + if (view instanceof TextCheckCell) { + ((TextCheckCell) view).setChecked(SharedConfig.loopStickers); + } } }); @@ -258,8 +265,11 @@ public class StickersActivity extends BaseFragment implements NotificationCenter private void updateRows() { rowCount = 0; + suggestInfoRow = -1; + if (currentType == MediaDataController.TYPE_IMAGE) { suggestRow = rowCount++; + loopRow = rowCount++; featuredRow = rowCount++; featuredInfoRow = rowCount++; masksRow = rowCount++; @@ -269,6 +279,7 @@ public class StickersActivity extends BaseFragment implements NotificationCenter featuredInfoRow = -1; masksRow = -1; masksInfoRow = -1; + loopRow = -1; } if (MediaDataController.getInstance(currentAccount).getArchivedStickersCount(currentType) != 0) { archivedRow = rowCount++; @@ -429,13 +440,19 @@ public class StickersActivity extends BaseFragment implements NotificationCenter holder.itemView.setBackgroundDrawable(Theme.getThemedDrawable(mContext, R.drawable.greydivider, Theme.key_windowBackgroundGrayShadow)); } break; + case 4: + if (position == loopRow) { + TextCheckCell cell = (TextCheckCell) holder.itemView; + cell.setTextAndCheck(LocaleController.getString("LoopAnimatedStickers", R.string.LoopAnimatedStickers), SharedConfig.loopStickers, true); + } + break; } } @Override public boolean isEnabled(RecyclerView.ViewHolder holder) { int type = holder.getItemViewType(); - return type == 0 || type == 2; + return type == 0 || type == 2 || type == 4; } @Override @@ -500,6 +517,10 @@ public class StickersActivity extends BaseFragment implements NotificationCenter case 3: view = new ShadowSectionCell(mContext); break; + case 4: + view = new TextCheckCell(mContext); + view.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); + break; } view.setLayoutParams(new RecyclerView.LayoutParams(RecyclerView.LayoutParams.MATCH_PARENT, RecyclerView.LayoutParams.WRAP_CONTENT)); return new RecyclerListView.Holder(view); @@ -515,6 +536,8 @@ public class StickersActivity extends BaseFragment implements NotificationCenter return 2; } else if (i == stickersShadowRow || i == suggestInfoRow) { return 3; + } else if (i == loopRow) { + return 4; } return 0; } @@ -534,7 +557,7 @@ public class StickersActivity extends BaseFragment implements NotificationCenter @Override public ThemeDescription[] getThemeDescriptions() { return new ThemeDescription[]{ - new ThemeDescription(listView, ThemeDescription.FLAG_CELLBACKGROUNDCOLOR, new Class[]{StickerSetCell.class, TextSettingsCell.class}, null, null, null, Theme.key_windowBackgroundWhite), + new ThemeDescription(listView, ThemeDescription.FLAG_CELLBACKGROUNDCOLOR, new Class[]{StickerSetCell.class, TextSettingsCell.class, TextCheckCell.class}, null, null, null, Theme.key_windowBackgroundWhite), new ThemeDescription(fragmentView, ThemeDescription.FLAG_BACKGROUND, null, null, null, null, Theme.key_windowBackgroundGray), new ThemeDescription(actionBar, ThemeDescription.FLAG_BACKGROUND, null, null, null, null, Theme.key_actionBarDefault), @@ -547,6 +570,10 @@ public class StickersActivity extends BaseFragment implements NotificationCenter new ThemeDescription(listView, 0, new Class[]{View.class}, Theme.dividerPaint, null, null, Theme.key_divider), + new ThemeDescription(listView, 0, new Class[]{TextCheckCell.class}, new String[]{"textView"}, null, null, null, Theme.key_windowBackgroundWhiteBlackText), + new ThemeDescription(listView, 0, new Class[]{TextCheckCell.class}, new String[]{"checkBox"}, null, null, null, Theme.key_switchTrack), + new ThemeDescription(listView, 0, new Class[]{TextCheckCell.class}, new String[]{"checkBox"}, null, null, null, Theme.key_switchTrackChecked), + new ThemeDescription(listView, ThemeDescription.FLAG_BACKGROUNDFILTER, new Class[]{TextInfoPrivacyCell.class}, null, null, null, Theme.key_windowBackgroundGrayShadow), new ThemeDescription(listView, 0, new Class[]{TextInfoPrivacyCell.class}, new String[]{"textView"}, null, null, null, Theme.key_windowBackgroundWhiteGrayText4), new ThemeDescription(listView, ThemeDescription.FLAG_LINKCOLOR, new Class[]{TextInfoPrivacyCell.class}, new String[]{"textView"}, null, null, null, Theme.key_windowBackgroundWhiteLinkText), diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ThemeActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ThemeActivity.java index 6682e5403..3ffdeb958 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ThemeActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ThemeActivity.java @@ -81,7 +81,6 @@ import org.telegram.ui.ActionBar.ThemeDescription; import org.telegram.ui.Cells.BrightnessControlCell; import org.telegram.ui.Cells.ChatListCell; import org.telegram.ui.Cells.ChatMessageCell; -import org.telegram.ui.Cells.CheckBoxCell; import org.telegram.ui.Cells.HeaderCell; import org.telegram.ui.Cells.NotificationsCheckCell; import org.telegram.ui.Cells.ShadowSectionCell; @@ -536,6 +535,7 @@ public class ThemeActivity extends BaseFragment implements NotificationCenter.No customTabsRow = rowCount++; directShareRow = rowCount++; enableAnimationsRow = rowCount++; + emojiRow = rowCount++; raiseToSpeakRow = rowCount++; sendByEnterRow = rowCount++; saveToGalleryRow = rowCount++; @@ -821,61 +821,10 @@ public class ThemeActivity extends BaseFragment implements NotificationCenter.No } else if (position == showThemesRows) { presentFragment(new ThemeActivity(THEME_TYPE_ALL)); } else if (position == emojiRow) { - if (getParentActivity() == null) { - return; + SharedConfig.toggleBigEmoji(); + if (view instanceof TextCheckCell) { + ((TextCheckCell) view).setChecked(SharedConfig.allowBigEmoji); } - final boolean[] maskValues = new boolean[2]; - BottomSheet.Builder builder = new BottomSheet.Builder(getParentActivity()); - - builder.setApplyTopPadding(false); - builder.setApplyBottomPadding(false); - LinearLayout linearLayout = new LinearLayout(getParentActivity()); - linearLayout.setOrientation(LinearLayout.VERTICAL); - for (int a = 0; a < (Build.VERSION.SDK_INT >= 19 ? 2 : 1); a++) { - String name = null; - if (a == 0) { - maskValues[a] = SharedConfig.allowBigEmoji; - name = LocaleController.getString("EmojiBigSize", R.string.EmojiBigSize); - } else if (a == 1) { - maskValues[a] = SharedConfig.useSystemEmoji; - name = LocaleController.getString("EmojiUseDefault", R.string.EmojiUseDefault); - } - CheckBoxCell checkBoxCell = new CheckBoxCell(getParentActivity(), 1, 21); - checkBoxCell.setTag(a); - checkBoxCell.setBackgroundDrawable(Theme.getSelectorDrawable(false)); - linearLayout.addView(checkBoxCell, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 50)); - checkBoxCell.setText(name, "", maskValues[a], true); - checkBoxCell.setTextColor(Theme.getColor(Theme.key_dialogTextBlack)); - checkBoxCell.setOnClickListener(v -> { - CheckBoxCell cell = (CheckBoxCell) v; - int num = (Integer) cell.getTag(); - maskValues[num] = !maskValues[num]; - cell.setChecked(maskValues[num], true); - }); - } - BottomSheet.BottomSheetCell cell = new BottomSheet.BottomSheetCell(getParentActivity(), 1); - cell.setBackgroundDrawable(Theme.getSelectorDrawable(false)); - cell.setTextAndIcon(LocaleController.getString("Save", R.string.Save).toUpperCase(), 0); - cell.setTextColor(Theme.getColor(Theme.key_dialogTextBlue2)); - cell.setOnClickListener(v -> { - try { - if (visibleDialog != null) { - visibleDialog.dismiss(); - } - } catch (Exception e) { - FileLog.e(e); - } - SharedPreferences.Editor editor = MessagesController.getGlobalMainSettings().edit(); - editor.putBoolean("allowBigEmoji", SharedConfig.allowBigEmoji = maskValues[0]); - editor.putBoolean("useSystemEmoji", SharedConfig.useSystemEmoji = maskValues[1]); - editor.commit(); - if (listAdapter != null) { - listAdapter.notifyItemChanged(position); - } - }); - linearLayout.addView(cell, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 50)); - builder.setCustomView(linearLayout); - showDialog(builder.create()); } else if (position >= themeStartRow && position < themeEndRow || position >= themeStart2Row && position < themeEnd2Row) { int p; ArrayList themes; @@ -1677,8 +1626,6 @@ public class ThemeActivity extends BaseFragment implements NotificationCenter.No cell.setText(LocaleController.getString("ImportContacts", R.string.ImportContacts), true); } else if (position == stickersRow) { cell.setText(LocaleController.getString("StickersAndMasks", R.string.StickersAndMasks), false); - } else if (position == emojiRow) { - cell.setText(LocaleController.getString("Emoji", R.string.Emoji), true); } else if (position == showThemesRows) { cell.setText(LocaleController.getString("ShowAllThemes", R.string.ShowAllThemes), false); } else if (position == distanceRow) { @@ -1770,6 +1717,8 @@ public class ThemeActivity extends BaseFragment implements NotificationCenter.No textCheckCell.setTextAndValueAndCheck(LocaleController.getString("ChromeCustomTabs", R.string.ChromeCustomTabs), LocaleController.getString("ChromeCustomTabsInfo", R.string.ChromeCustomTabsInfo), SharedConfig.customTabs, false, true); } else if (position == directShareRow) { textCheckCell.setTextAndValueAndCheck(LocaleController.getString("DirectShare", R.string.DirectShare), LocaleController.getString("DirectShareInfo", R.string.DirectShareInfo), SharedConfig.directShare, false, true); + } else if (position == emojiRow) { + textCheckCell.setTextAndCheck(LocaleController.getString("LargeEmoji", R.string.LargeEmoji), SharedConfig.allowBigEmoji, true); } break; } @@ -1804,10 +1753,9 @@ public class ThemeActivity extends BaseFragment implements NotificationCenter.No @Override public int getItemViewType(int position) { - if (position == scheduleFromRow || position == emojiRow || position == showThemesRows || + if (position == scheduleFromRow || position == showThemesRows || position == distanceRow || position == scheduleToRow || position == scheduleUpdateLocationRow || position == backgroundRow || - position == contactsReimportRow || position == contactsSortRow || position == stickersRow || - position == distanceRow) { + position == contactsReimportRow || position == contactsSortRow || position == stickersRow) { return 1; } else if (position == automaticBrightnessInfoRow || position == scheduleLocationInfoRow) { return 2; @@ -1825,7 +1773,7 @@ public class ThemeActivity extends BaseFragment implements NotificationCenter.No return 6; } else if (position == scheduleLocationRow || position == enableAnimationsRow || position == sendByEnterRow || position == saveToGalleryRow || position == raiseToSpeakRow || position == customTabsRow || - position == directShareRow) { + position == directShareRow || position == emojiRow) { return 7; } else if (position == textSizeRow) { return 8; diff --git a/TMessagesProj/src/main/res/drawable-hdpi/attach_audio.png b/TMessagesProj/src/main/res/drawable-hdpi/attach_audio.png old mode 100755 new mode 100644 index 66bfa5580..c9ee034cd Binary files a/TMessagesProj/src/main/res/drawable-hdpi/attach_audio.png and b/TMessagesProj/src/main/res/drawable-hdpi/attach_audio.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/attach_contact.png b/TMessagesProj/src/main/res/drawable-hdpi/attach_contact.png old mode 100755 new mode 100644 index 5b8ff8501..4ea12d4a6 Binary files a/TMessagesProj/src/main/res/drawable-hdpi/attach_contact.png and b/TMessagesProj/src/main/res/drawable-hdpi/attach_contact.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/attach_file.png b/TMessagesProj/src/main/res/drawable-hdpi/attach_file.png old mode 100755 new mode 100644 index 6e11322a6..c8229ee9d Binary files a/TMessagesProj/src/main/res/drawable-hdpi/attach_file.png and b/TMessagesProj/src/main/res/drawable-hdpi/attach_file.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/attach_gallery.png b/TMessagesProj/src/main/res/drawable-hdpi/attach_gallery.png old mode 100755 new mode 100644 index dd874454b..7b863c3e3 Binary files a/TMessagesProj/src/main/res/drawable-hdpi/attach_gallery.png and b/TMessagesProj/src/main/res/drawable-hdpi/attach_gallery.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/attach_location.png b/TMessagesProj/src/main/res/drawable-hdpi/attach_location.png old mode 100755 new mode 100644 index ab730e3cf..fdb81e1db Binary files a/TMessagesProj/src/main/res/drawable-hdpi/attach_location.png and b/TMessagesProj/src/main/res/drawable-hdpi/attach_location.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/attach_polls.png b/TMessagesProj/src/main/res/drawable-hdpi/attach_polls.png index 2f7db0923..740e007ad 100644 Binary files a/TMessagesProj/src/main/res/drawable-hdpi/attach_polls.png and b/TMessagesProj/src/main/res/drawable-hdpi/attach_polls.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/nophotos3.9.png b/TMessagesProj/src/main/res/drawable-hdpi/nophotos3.9.png new file mode 100644 index 000000000..2d8f1f980 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/nophotos3.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/permissions_camera1.png b/TMessagesProj/src/main/res/drawable-hdpi/permissions_camera1.png new file mode 100644 index 000000000..d43853083 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/permissions_camera1.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/permissions_camera2.png b/TMessagesProj/src/main/res/drawable-hdpi/permissions_camera2.png new file mode 100644 index 000000000..0584b0564 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/permissions_camera2.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/permissions_gallery1.png b/TMessagesProj/src/main/res/drawable-hdpi/permissions_gallery1.png new file mode 100644 index 000000000..e946a0151 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/permissions_gallery1.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/permissions_gallery2.png b/TMessagesProj/src/main/res/drawable-hdpi/permissions_gallery2.png new file mode 100644 index 000000000..5b7c9eab5 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/permissions_gallery2.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/photos_group.png b/TMessagesProj/src/main/res/drawable-hdpi/photos_group.png deleted file mode 100755 index 14071820b..000000000 Binary files a/TMessagesProj/src/main/res/drawable-hdpi/photos_group.png and /dev/null differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/videopreview.9.png b/TMessagesProj/src/main/res/drawable-hdpi/videopreview.9.png new file mode 100644 index 000000000..d5ecbdc0f Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/videopreview.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/zoom_minus.png b/TMessagesProj/src/main/res/drawable-hdpi/zoom_minus.png new file mode 100644 index 000000000..7027f5087 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/zoom_minus.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/zoom_plus.png b/TMessagesProj/src/main/res/drawable-hdpi/zoom_plus.png new file mode 100644 index 000000000..6544bd8fb Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/zoom_plus.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/zoom_round.png b/TMessagesProj/src/main/res/drawable-hdpi/zoom_round.png new file mode 100644 index 000000000..173ad976a Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/zoom_round.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/zoom_round_b.png b/TMessagesProj/src/main/res/drawable-hdpi/zoom_round_b.png new file mode 100644 index 000000000..4f46b152a Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/zoom_round_b.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/zoom_slide.9.png b/TMessagesProj/src/main/res/drawable-hdpi/zoom_slide.9.png new file mode 100644 index 000000000..a0d880534 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/zoom_slide.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/zoom_slide_a.9.png b/TMessagesProj/src/main/res/drawable-hdpi/zoom_slide_a.9.png new file mode 100644 index 000000000..e21ef0c1e Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/zoom_slide_a.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/attach_audio.png b/TMessagesProj/src/main/res/drawable-mdpi/attach_audio.png old mode 100755 new mode 100644 index 937cd187c..ed82179f7 Binary files a/TMessagesProj/src/main/res/drawable-mdpi/attach_audio.png and b/TMessagesProj/src/main/res/drawable-mdpi/attach_audio.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/attach_contact.png b/TMessagesProj/src/main/res/drawable-mdpi/attach_contact.png old mode 100755 new mode 100644 index b9407f555..39ddcdd28 Binary files a/TMessagesProj/src/main/res/drawable-mdpi/attach_contact.png and b/TMessagesProj/src/main/res/drawable-mdpi/attach_contact.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/attach_file.png b/TMessagesProj/src/main/res/drawable-mdpi/attach_file.png old mode 100755 new mode 100644 index 44e110e63..36fe2d9ea Binary files a/TMessagesProj/src/main/res/drawable-mdpi/attach_file.png and b/TMessagesProj/src/main/res/drawable-mdpi/attach_file.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/attach_gallery.png b/TMessagesProj/src/main/res/drawable-mdpi/attach_gallery.png old mode 100755 new mode 100644 index 32ca414a0..43ea949da Binary files a/TMessagesProj/src/main/res/drawable-mdpi/attach_gallery.png and b/TMessagesProj/src/main/res/drawable-mdpi/attach_gallery.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/attach_location.png b/TMessagesProj/src/main/res/drawable-mdpi/attach_location.png old mode 100755 new mode 100644 index 7385cdcc7..26535e7bb Binary files a/TMessagesProj/src/main/res/drawable-mdpi/attach_location.png and b/TMessagesProj/src/main/res/drawable-mdpi/attach_location.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/attach_polls.png b/TMessagesProj/src/main/res/drawable-mdpi/attach_polls.png index 4d33eccc8..d5b24d468 100644 Binary files a/TMessagesProj/src/main/res/drawable-mdpi/attach_polls.png and b/TMessagesProj/src/main/res/drawable-mdpi/attach_polls.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/nophotos3.9.png b/TMessagesProj/src/main/res/drawable-mdpi/nophotos3.9.png new file mode 100644 index 000000000..13be376c9 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/nophotos3.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/permissions_camera1.png b/TMessagesProj/src/main/res/drawable-mdpi/permissions_camera1.png new file mode 100644 index 000000000..5d4278ceb Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/permissions_camera1.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/permissions_camera2.png b/TMessagesProj/src/main/res/drawable-mdpi/permissions_camera2.png new file mode 100644 index 000000000..aa95da8d9 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/permissions_camera2.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/permissions_gallery1.png b/TMessagesProj/src/main/res/drawable-mdpi/permissions_gallery1.png new file mode 100644 index 000000000..0267a6c44 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/permissions_gallery1.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/permissions_gallery2.png b/TMessagesProj/src/main/res/drawable-mdpi/permissions_gallery2.png new file mode 100644 index 000000000..03332b1d4 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/permissions_gallery2.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/photos_group.png b/TMessagesProj/src/main/res/drawable-mdpi/photos_group.png deleted file mode 100755 index 9ca1783a3..000000000 Binary files a/TMessagesProj/src/main/res/drawable-mdpi/photos_group.png and /dev/null differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/videopreview.9.png b/TMessagesProj/src/main/res/drawable-mdpi/videopreview.9.png new file mode 100644 index 000000000..6d2336d63 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/videopreview.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/zoom_minus.png b/TMessagesProj/src/main/res/drawable-mdpi/zoom_minus.png new file mode 100644 index 000000000..11c467e00 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/zoom_minus.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/zoom_plus.png b/TMessagesProj/src/main/res/drawable-mdpi/zoom_plus.png new file mode 100644 index 000000000..2157ed3ca Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/zoom_plus.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/zoom_round.png b/TMessagesProj/src/main/res/drawable-mdpi/zoom_round.png new file mode 100644 index 000000000..47c84d3a2 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/zoom_round.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/zoom_round_b.png b/TMessagesProj/src/main/res/drawable-mdpi/zoom_round_b.png new file mode 100644 index 000000000..09f03b971 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/zoom_round_b.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/zoom_slide.9.png b/TMessagesProj/src/main/res/drawable-mdpi/zoom_slide.9.png new file mode 100644 index 000000000..ecc8b57cc Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/zoom_slide.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/zoom_slide_a.9.png b/TMessagesProj/src/main/res/drawable-mdpi/zoom_slide_a.9.png new file mode 100644 index 000000000..dda9d76e5 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/zoom_slide_a.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/attach_audio.png b/TMessagesProj/src/main/res/drawable-xhdpi/attach_audio.png old mode 100755 new mode 100644 index d35451fc0..0964c7cd0 Binary files a/TMessagesProj/src/main/res/drawable-xhdpi/attach_audio.png and b/TMessagesProj/src/main/res/drawable-xhdpi/attach_audio.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/attach_contact.png b/TMessagesProj/src/main/res/drawable-xhdpi/attach_contact.png old mode 100755 new mode 100644 index 9461209f2..bdc8e130e Binary files a/TMessagesProj/src/main/res/drawable-xhdpi/attach_contact.png and b/TMessagesProj/src/main/res/drawable-xhdpi/attach_contact.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/attach_file.png b/TMessagesProj/src/main/res/drawable-xhdpi/attach_file.png old mode 100755 new mode 100644 index beb8720c6..c408f8246 Binary files a/TMessagesProj/src/main/res/drawable-xhdpi/attach_file.png and b/TMessagesProj/src/main/res/drawable-xhdpi/attach_file.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/attach_gallery.png b/TMessagesProj/src/main/res/drawable-xhdpi/attach_gallery.png old mode 100755 new mode 100644 index d6a726246..45f79b615 Binary files a/TMessagesProj/src/main/res/drawable-xhdpi/attach_gallery.png and b/TMessagesProj/src/main/res/drawable-xhdpi/attach_gallery.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/attach_location.png b/TMessagesProj/src/main/res/drawable-xhdpi/attach_location.png old mode 100755 new mode 100644 index 6736d0457..2ab131ebe Binary files a/TMessagesProj/src/main/res/drawable-xhdpi/attach_location.png and b/TMessagesProj/src/main/res/drawable-xhdpi/attach_location.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/attach_polls.png b/TMessagesProj/src/main/res/drawable-xhdpi/attach_polls.png index fb4c09ddd..8d4edca4f 100644 Binary files a/TMessagesProj/src/main/res/drawable-xhdpi/attach_polls.png and b/TMessagesProj/src/main/res/drawable-xhdpi/attach_polls.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/nophotos3.9.png b/TMessagesProj/src/main/res/drawable-xhdpi/nophotos3.9.png new file mode 100644 index 000000000..06331824d Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/nophotos3.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/permissions_camera1.png b/TMessagesProj/src/main/res/drawable-xhdpi/permissions_camera1.png new file mode 100644 index 000000000..94bbc0ce4 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/permissions_camera1.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/permissions_camera2.png b/TMessagesProj/src/main/res/drawable-xhdpi/permissions_camera2.png new file mode 100644 index 000000000..4eeb07127 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/permissions_camera2.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/permissions_gallery1.png b/TMessagesProj/src/main/res/drawable-xhdpi/permissions_gallery1.png new file mode 100644 index 000000000..9ae790966 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/permissions_gallery1.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/permissions_gallery2.png b/TMessagesProj/src/main/res/drawable-xhdpi/permissions_gallery2.png new file mode 100644 index 000000000..76e53a1df Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/permissions_gallery2.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/photos_group.png b/TMessagesProj/src/main/res/drawable-xhdpi/photos_group.png deleted file mode 100755 index 751d5958c..000000000 Binary files a/TMessagesProj/src/main/res/drawable-xhdpi/photos_group.png and /dev/null differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/videopreview.9.png b/TMessagesProj/src/main/res/drawable-xhdpi/videopreview.9.png new file mode 100644 index 000000000..f9b1b3464 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/videopreview.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/zoom_minus.png b/TMessagesProj/src/main/res/drawable-xhdpi/zoom_minus.png new file mode 100644 index 000000000..d1a7d40f2 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/zoom_minus.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/zoom_plus.png b/TMessagesProj/src/main/res/drawable-xhdpi/zoom_plus.png new file mode 100644 index 000000000..8f3f8c5af Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/zoom_plus.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/zoom_round.png b/TMessagesProj/src/main/res/drawable-xhdpi/zoom_round.png new file mode 100644 index 000000000..cc9995209 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/zoom_round.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/zoom_round_b.png b/TMessagesProj/src/main/res/drawable-xhdpi/zoom_round_b.png new file mode 100644 index 000000000..db384182b Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/zoom_round_b.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/zoom_slide.9.png b/TMessagesProj/src/main/res/drawable-xhdpi/zoom_slide.9.png new file mode 100644 index 000000000..9dc3683b6 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/zoom_slide.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/zoom_slide_a.9.png b/TMessagesProj/src/main/res/drawable-xhdpi/zoom_slide_a.9.png new file mode 100644 index 000000000..bff11fbd8 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/zoom_slide_a.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/attach_audio.png b/TMessagesProj/src/main/res/drawable-xxhdpi/attach_audio.png old mode 100755 new mode 100644 index d58489eb3..809c5093b Binary files a/TMessagesProj/src/main/res/drawable-xxhdpi/attach_audio.png and b/TMessagesProj/src/main/res/drawable-xxhdpi/attach_audio.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/attach_contact.png b/TMessagesProj/src/main/res/drawable-xxhdpi/attach_contact.png old mode 100755 new mode 100644 index 84a1836b6..663ec7119 Binary files a/TMessagesProj/src/main/res/drawable-xxhdpi/attach_contact.png and b/TMessagesProj/src/main/res/drawable-xxhdpi/attach_contact.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/attach_file.png b/TMessagesProj/src/main/res/drawable-xxhdpi/attach_file.png old mode 100755 new mode 100644 index 03d328637..a20053a9d Binary files a/TMessagesProj/src/main/res/drawable-xxhdpi/attach_file.png and b/TMessagesProj/src/main/res/drawable-xxhdpi/attach_file.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/attach_gallery.png b/TMessagesProj/src/main/res/drawable-xxhdpi/attach_gallery.png old mode 100755 new mode 100644 index 4c095bf1c..7c648798e Binary files a/TMessagesProj/src/main/res/drawable-xxhdpi/attach_gallery.png and b/TMessagesProj/src/main/res/drawable-xxhdpi/attach_gallery.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/attach_location.png b/TMessagesProj/src/main/res/drawable-xxhdpi/attach_location.png old mode 100755 new mode 100644 index 12e9999a3..34f0c2937 Binary files a/TMessagesProj/src/main/res/drawable-xxhdpi/attach_location.png and b/TMessagesProj/src/main/res/drawable-xxhdpi/attach_location.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/attach_polls.png b/TMessagesProj/src/main/res/drawable-xxhdpi/attach_polls.png index ae401f903..e8025d532 100644 Binary files a/TMessagesProj/src/main/res/drawable-xxhdpi/attach_polls.png and b/TMessagesProj/src/main/res/drawable-xxhdpi/attach_polls.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/nophotos3.9.png b/TMessagesProj/src/main/res/drawable-xxhdpi/nophotos3.9.png new file mode 100644 index 000000000..bb4411bae Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/nophotos3.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/permissions_camera1.png b/TMessagesProj/src/main/res/drawable-xxhdpi/permissions_camera1.png new file mode 100644 index 000000000..7190c0423 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/permissions_camera1.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/permissions_camera2.png b/TMessagesProj/src/main/res/drawable-xxhdpi/permissions_camera2.png new file mode 100644 index 000000000..f2961f41d Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/permissions_camera2.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/permissions_gallery1.png b/TMessagesProj/src/main/res/drawable-xxhdpi/permissions_gallery1.png new file mode 100644 index 000000000..f81e394e5 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/permissions_gallery1.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/permissions_gallery2.png b/TMessagesProj/src/main/res/drawable-xxhdpi/permissions_gallery2.png new file mode 100644 index 000000000..79509abb5 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/permissions_gallery2.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/photos_group.png b/TMessagesProj/src/main/res/drawable-xxhdpi/photos_group.png deleted file mode 100755 index c671d9921..000000000 Binary files a/TMessagesProj/src/main/res/drawable-xxhdpi/photos_group.png and /dev/null differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/videopreview.9.png b/TMessagesProj/src/main/res/drawable-xxhdpi/videopreview.9.png new file mode 100644 index 000000000..ac3ba7a5b Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/videopreview.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/zoom_minus.png b/TMessagesProj/src/main/res/drawable-xxhdpi/zoom_minus.png new file mode 100644 index 000000000..e4a4f7296 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/zoom_minus.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/zoom_plus.png b/TMessagesProj/src/main/res/drawable-xxhdpi/zoom_plus.png new file mode 100644 index 000000000..62a00370a Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/zoom_plus.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/zoom_round.png b/TMessagesProj/src/main/res/drawable-xxhdpi/zoom_round.png new file mode 100644 index 000000000..3da5d80cb Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/zoom_round.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/zoom_round_b.png b/TMessagesProj/src/main/res/drawable-xxhdpi/zoom_round_b.png new file mode 100644 index 000000000..a4b69e121 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/zoom_round_b.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/zoom_slide.9.png b/TMessagesProj/src/main/res/drawable-xxhdpi/zoom_slide.9.png new file mode 100644 index 000000000..a04317e8d Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/zoom_slide.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/zoom_slide_a.9.png b/TMessagesProj/src/main/res/drawable-xxhdpi/zoom_slide_a.9.png new file mode 100644 index 000000000..76790e157 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/zoom_slide_a.9.png differ diff --git a/TMessagesProj/src/main/res/drawable/ytlogo.png b/TMessagesProj/src/main/res/drawable/ytlogo.png deleted file mode 100644 index ed1b4fb99..000000000 Binary files a/TMessagesProj/src/main/res/drawable/ytlogo.png and /dev/null differ diff --git a/TMessagesProj/src/main/res/values-ar/strings.xml b/TMessagesProj/src/main/res/values-ar/strings.xml index 8696287f0..a61129ebc 100644 --- a/TMessagesProj/src/main/res/values-ar/strings.xml +++ b/TMessagesProj/src/main/res/values-ar/strings.xml @@ -161,7 +161,7 @@ حذف وخروج إخفاء تثبيت - أرشفة + أرشفة-- إلغاء الأرشفة المحادثات المؤرشفة حذف المحادثة @@ -388,6 +388,8 @@ توقيع الرسائل إضافة أسماء المشرفين للمنشورات التي ينشرونها. صلاحيات المشرف + لقب مخصص + قم باختيار لقب مخصص كي يظهر لجميع الأعضاء بدلًا من \'%1$s\'. ما هي صلاحيات هذا المشرف؟ تغيير معلومات القناة تغيير معلومات المجموعة @@ -404,7 +406,7 @@ تستطيع نقل هذه القناة إلى **%1$s** فقط إذا: فعّلتَ **التحقق بخطوتين** منذ أكثر من **سبعة أيام**. سجّلتَ دخولك على هذا الجهاز منذ أكثر من **24 ساعة**. - قم المحاولة لاحقًا. + يرجى المحاولة لاحقًا. تعيين كلمة مرور سيؤدي هذا لنقل **جميع حقوق الملكية** الخاصة بـ **%1$s** إلى **%2$s**. تغيير المالك @@ -427,7 +429,7 @@ إرسال الوسائط إرسال الاستفتاءات إرسال الملصقات والصور المتحركة - تضمين روابط + تضمين الروابط تغيير معلومات المحادثة تثبيت الرسائل إضافة مستخدمين @@ -445,7 +447,7 @@ حظر وإزالة من المجموعة تطبيق التغييرات؟ لقد قمت بتغيير صلاحيات هذا المستخدم في **%1$s**؛ تطبيق التغييرات؟ - Custom + مخصصة إدارة المجموعة إدارة القناة إدارة المجموعة @@ -501,6 +503,16 @@ هل ترغب حقًا بإلغاء ربط **%1$s** من هذه القناة؟ مناقشة قناة + الوضع البطيء + معطَّل + %1$dثا + %1$dد + %1$dسا + اختر الفترة الزمنية التي يجب على كل عضو انتظارها قبل إرسال رسالته التالية. + سيتمكن الأعضاء من إرسال رسالة واحدة فقط كل %1$s. + تم تفعيل الوضع البطيء. لا يمكنك إرسال أكثر من رسالة مرةً واحدة. + تم تفعيل الوضع البطيء. لا يمكنك تحديد المزيد من العناصر. + Sorry, this text is too long to send as one message.\n\nSlow Mode is enabled. You can\'t send more than one message at once. استفتاء جديد استفتاء @@ -547,14 +559,14 @@ غيَّر un1 اسم المجموعة إلى «%1$s» غيَّر un1 اسمَ القناة إلى «%1$s» غادر un1 المجموعة - un1 غادر القناة + غادر un1 القناة un1 أضاف un2 un1 انضم للمجموعة حظر %1$s ألغى حظر %1$s un1 انضم للقناة - un1 عيّن صورة جديدة للمجموعة - un1 عيّن صورة جديدة للقناة + عيّن un1 صورة جديدة للمجموعة + عيّن un1 صورة جديدة للقناة أزال un1 صورة المجموعة أزال un1 صورة القناة عدّل un1 هذه الرسالة: @@ -570,7 +582,7 @@ حذف un1 هذه الرسالة: غيّرَ un1 موقع المجموعة ليصبح «%1$s» أزال un1 موقع المجموعة - نقلَ ملكية المجموعة لـ %1$s + نقلَ الملكية لـ %1$s un1 غير حزمة ملصقات المجموعة \nun1 أزال حزمة ملصقات المجموعة جعل un1 un2 مجموعة نقاشات هذه القناة @@ -600,7 +612,7 @@ تثبيت الرسائل إرسال الاستفتاءات إرسال الرسائل - تضمين روابط + تضمين الروابط قراءة الرسائل غيّرَ صلاحيات %1$s تغيير معلومات القناة @@ -611,6 +623,8 @@ إضافة مشرفين حظر المستخدمين إضافة مستخدمين + اللقب: %1$s + اللقب تثبيت الرسائل كافة الأحداث استثناءات جديدة @@ -622,6 +636,8 @@ رسائل معدلة رسائل مثبتة الأعضاء المغادرون + عيّن un1 عداد الوضع البطيء ليصبح %1$s + عطّل un1 الوضع البطيء رسالة جماعية جديدة أدخل اسم القائمة @@ -732,8 +748,8 @@ فتح باستخدام... إرسال %1$s رفع %1$s - إرسال كملف - إرسال كملفات + إرسال دون ضغط + إرسال بدون ضغط فتح الرابط هل ترغب في فتح %1$s؟ تسجيل الدخول إلى %1$s من حساب **%2$s** @@ -830,12 +846,12 @@ هل ترغب حقًا في إيقاف التسجيل وتجاهل الرسالة المرئية؟ تجاهل مشرفو هذه المجموعة قيدوك من إرسال الوسائط إليها حتى %1$s - مشرفو هذه المجموعة قيدوك من من إرسال محتوى استعلامي إليها حتى %1$s + قام مشرفو هذه المجموعة بتقييدك من إرسال أي محتوى استعلامي إليها حتى %1$s مشرفو هذه المجموعة قيدوك من إرسال الملصقات إليها حتى %1$s قام مشرفو هذه المجموعة بتقييدك من إرسال الصور المتحركة إليها حتى %1$s مشرفو هذه المجموعة قيدوك من الكتابة فيها حتى %1$s قام مشرفو هذه المجموعة بتقييدك من إرسال الوسائط إليها. - مشرفو هذه المجموعة قيدوك من إرسال محتوى استعلامي إليها + قام مشرفو هذه المجموعة بتقييدك من إرسال أي محتوى استعلامي إليها قام مشرفو هذه المجموعة بتقييدك من إرسال الملصقات. قام مشرفو هذه المجموعة بتقييدك من إرسال الصور المتحركة إليها. قام مشرفو هذه المجموعة بتقييدك من الكتابة هنا. @@ -859,7 +875,10 @@ تثبيت خرائط جوجل؟ احتيالي عبر - Message doesn\'t exist + الرسالة غير موجودة + تم تفعيل الوضع البطيء. يمكنك إرسال\nرسالتك التالية خلال %1$s + انقر لأخذ صورة، اضغط باستمرار لتصوير مقطع مرئي + إرسال بدون صوت عيّن %1$s عداد التدمير الذاتي ليصبح %2$s قمت بتعيين عداد التدمير الذاتي ليصبح %1$s @@ -1113,6 +1132,7 @@ حدث خطأ ما. الملصقات والأقنعة + تكرار الملصقات المتحركة إضافة الملصقات إضافة %1$s إزالة %1$s @@ -1465,7 +1485,7 @@ مشاركة مباشرة إظهار آخر المحادثات في قائمة المشاركة الرموز التعبيرية - رسمُ رمز تعبيري واحد كبير + رموز تعبيرية كبيرة استخدم الرموز التعبيرية الافتراضية تيليجرام للأندرويد %1$s قائمة المعالجة @@ -1558,11 +1578,11 @@ لم يتم العثور على نتائج ما من عمليات بحث تمت مؤخرًا الأسئلة الشائعة - Distance Units - Distance units - Automatic - Kilometers - Miles + وحدة القياس + وحدة القياس + تلقائي + كيلومتر + ميل قاعدة البيانات على الجهاز هل ترغب في مسح الرسائل النصية من الذاكرة المؤقتة؟ @@ -1854,10 +1874,10 @@ الخريطة قمر صناعي مختلطة - %1$s m away - %1$s km away - %1$s ft away - %1$s mi away + على بُعد %1$s م + على بُعد %1$s ك.م + على بُعد %1$s قدم + على بُعد %1$s ميل إرسال موقعي الحالي شارك موقعي الحي لمدة... إيقاف مشاركة الموقع @@ -1922,12 +1942,16 @@ هذا المقطع ليس معالَجا ليتم عرضُه فورَ تشغيله، قد تحتاج لتنزيله بالكامل قبل مشاهدته. لم يتمكن التطبيق من تشغيل هذا المقطع المرئي، هل ترغب في تشغيله بمشغل خارجي؟ لا توجد صور حديثة + الصور + الصور المتحركة لا يوجد صور متحركة حديثة بحث الصور البحث في الويب بحث الصور المتحركة البحث في الويب بحث عن صور متحركة + انقر للسماح بالوصول إلى الكاميرا + انقر للسماح بالوصول إلى المعرض قص الصورة تحسين التفتيح @@ -1972,6 +1996,8 @@ مربع إرسال الوسائط في رسائل متفرقة تجميع الوسائط في رسالة واحدة + إرسال دون تجميع + إرسال دون ضغط التحقق بخطوتين التحقق بخطوتين @@ -2218,7 +2244,7 @@ un1 أزالك un1 قام بإضافتك عاد un1 للمجموعة - un1 انضم للمجموعة + انضم un1 للمجموعة لقد عُدتَ للمجموعة لقد سمحت لهذا البوت بمراسلتك عندما تسجل دخولك إلى %1$s استلم %1$s الوثائق التالية: %2$s @@ -2346,10 +2372,10 @@ هل ترغب في تفعيل معاينة الروابط المطولة في المحادثات السرية؟ علمًا أنه يتم توليدها في خوادم تيليجرام. يرجى ملاحظة أن بوتات المحتوى الاستعلامي يتم تطويرها من مطورين مستقلين. لكي تعمل هذه البوتات، ما تكتبه بعد اسم مستخدم البوت يذهب لمطور البوت. المعذرة، لا يمكنك تعديل هذه الرسالة. - فضلًا قم بالسماح لتيليجرام بتلقي رسائل SMS القصيرة ليتمكن من تفعيل حسابك تلقائيًا. - فصلًا قم بالسماح لتيليجرام باستقبال اتصالات ليتمكن من إدخال الرمز لك تلقائيًا. + رجاءً قم بالسماح لتيليجرام بتلقي المكالمات للتمكن من إدخال الرمز تلقائيًا. + رجاءً قم بالسماح لتيليجرام بتلقي المكالمات وقراءة سجل المكالمات للتمكن من إدخال الرمز تلقائيًا. + رجاءً قم بالسماح لتيليجرام بقراءة سجل المكالمات للتمكن من إدخال الرمز تلقائيًا. رجاءً قم بالسماح لتيليجرام بتلقي المكالمات للتمكن من تفعيل رقم هاتفك تلقائيًا. - رجاءً قم بالسماح لتيليجرام بتلقي المكالمات للتمكن من تفعيل رقم هاتفك تلقائيًا. المعذرة، ليس من المسموح لك القيام بهذا. المعذرة، لا يمكنك إضافة هذا المستخدم أو البوت للمجموعات بسبب أنك قمت بحظره. فضلًا قم بإزالة الحظر للاستمرار. انضمام للمجموعة @@ -2815,6 +2841,24 @@ و%1$d آخرون و%1$d آخرون و%1$d آخرون + %1$d صورة محددة + صورة واحدة محددة + صورتان محددتان + %1$d صور محددة + %1$d صورةً محددة + %1$d صورة محددة + %1$d مقطع مرئي محدد + مقطع مرئي واحد محدد + مقطعان مرئيان محددان + %1$d مقاطع مرئية محددة + %1$d مقطعًا مرئيًا محددًا + %1$d مقطع مرئي محدد + %1$d عنصر محدد + عنصر واحد محدد + عنصران محددان + %1$d عناصر محددة + %1$d عنصرًا محددًا + %1$d عنصر محدد مجموعة قناة diff --git a/TMessagesProj/src/main/res/values-de/strings.xml b/TMessagesProj/src/main/res/values-de/strings.xml index 6aecac767..6ec4be24e 100644 --- a/TMessagesProj/src/main/res/values-de/strings.xml +++ b/TMessagesProj/src/main/res/values-de/strings.xml @@ -195,7 +195,7 @@ GIF senden Paket anzeigen Oben anheften - Mehr als %1$s kann man leider nicht oben anheften. + Bis zu %1$s kann man in der Chatliste oben anheften.\n\nWenn du mehr Ordnung brauchst, versuche einige Chats zu archivieren. Der Ordner \"Archivierte Chats\" erlaubt das Anheften von beliebig vielen Chats. Oben entfernen Als ungelesen markieren Als gelesen markieren @@ -231,7 +231,7 @@ Wirklich **%1$s** verlassen? Du kannst diesen Nutzer nicht hinzufügen. Leider ist diese Gruppe schon voll. - Dieser Nutzer hat die Gruppe verlassen, deshalb kannst du ihn nicht wieder hinzufügen. + Wenn jemand eine Gruppe verlassen hat, musst du in der Kontaktliste der Person sein, um sie wieder hinzufügen zu können.\n\nMan kann die Gruppe auch über einen Einladungslink betreten, so lange die Person nicht in der Liste \"Entfernte Nutzer\" der Gruppe steht. Es gibt bereits zu viele Administratoren. Der ausgewählte Nutzer hat zu viele öffentliche Gruppen oder Kanäle. Bitte die Person, einfach einen Kanal oder eine Gruppe privat zu stellen. Der ausgewählte Nutzer hat zu viele lokale Gruppen. Bitte die Person, Gruppen bei sich zu löschen oder Inhaber-Rechte an andere zu vergeben. @@ -336,7 +336,7 @@ Admin STUMM STUMM AUS - Administrator hinzufügen + Admin hinzufügen Nutzer entfernen Entsperren Gedrückt halten um zu entsperren @@ -388,6 +388,8 @@ Nachrichten unterschreiben Zeigt Namen der Admins in ausgehenden Nachrichten. Adminrechte + Eigene Bezeichnung + Diese Bezeichnung wird anstatt \'%1$s\' angezeigt. Was kann dieser Admin machen? Kanal-Info ändern Gruppen-Info ändern @@ -445,7 +447,7 @@ Sperren und aus der Gruppe entfernen Änderungen anwenden Du hast die Rechte des Nutzers bei ** %1$s** geändert. Änderungen anwenden? - Custom + Eigener Gruppe verwalten Kanal verwalten Gruppe verwalten @@ -501,6 +503,16 @@ Wirklich Verknüpfung von **%1$s** mit diesem Kanal entfernen? DISKUTIEREN Kanal + Langsamer Modus + Aus + %1$ds + %1$dm + %1$dh + Wie lange jedes Mitglied warten muss, bevor es seine nächste Nachricht senden darf. + Intervall zwischen einzelnen Nachrichten: %1$s + Langsamer Modus ist aktiv, du kannst nicht mehr als eine Nachricht gleichzeitig senden. + Langsamer Modus ist aktiv, du kannst nicht mehr Elemente auswählen. + Dieser Text ist für eine einzelne Nachricht leider zu lang.\n\nLangsamer Modus ist aktiv, du kannst nicht mehr als eine gleichzeitig senden. Neue Umfrage Umfrage @@ -611,6 +623,8 @@ Admins hinzufügen Nutzer sperren Nutzer hinzufügen + Bezeichnung: %1$s + Bezeichnung Nachrichten anheften Alle Aktionen Neue Ausnahmen @@ -622,6 +636,8 @@ Bearbeitete Nachrichten Angeheftete Nachrichten Ehemalige Mitglieder + un1 hat den Timer des langsamen Modus auf %1$s gestellt + un1 hat den langsamen Modus deaktiviert Neue Broadcast Liste Listenname @@ -686,7 +702,7 @@ schickt Audio... schickt Bild... spielt ein Spiel... - schickt Video... + sendet ein Video... schickt Datei... Hast du eine Frage\nzu Telegram? Galerie @@ -860,6 +876,9 @@ BETRUG via Nachricht existiert nicht + Langsamer Modus aktiv.\nBitte warte %1$s. + Tippen für Foto, halten für Video + Ohne Ton senden %1$s hat den Selbstzerstörungs-Timer auf %2$s gesetzt Du hast den Selbstzerstörungs-Timer auf %1$s gesetzt @@ -1075,7 +1094,7 @@ Geheimen Chat starten Gemeinsame Gruppen Gemeinsame Gruppen - Noch keine gemeinsamen Gruppen + Keine gemeinsamen Gruppen Es ist ein Fehler aufgetreten. Geheimer Schlüssel Selbstzerstörungs-Timer @@ -1113,6 +1132,7 @@ Es ist ein Fehler aufgetreten. Sticker + Animationen wiederholen Sticker hinzufügen %1$s HINZUFÜGEN %1$s ENTFERNEN @@ -1465,7 +1485,7 @@ Direktes Teilen Letzte Chats im Teilen-Menü anzeigen Emoji - Draw single big emoji + Große Emoji Benutze System-Emoji Telegram für Android %1$s Debug-Menü @@ -1700,11 +1720,11 @@ Scans Dokument löschen Löschen - Möchtest du diesen Scan wirklich löschen? - Möchtest du dieses Selfie wirklich löschen? - Bist du sicher, dass du dieses Dokument wirklich löschen willst? + Möchtest du diesen Scan löschen? + Möchtest du dieses Selfie löschen? + Möchtest du dieses Dokument löschen? Möchtest du wirklich deine persönlichen Daten löschen? - Deine Adressinformationen wirklich löschen? + Möchtest du deine Adressdaten löschen? Persönliche Daten löschen Adressinformationen löschen Scan löschen? @@ -1774,7 +1794,7 @@ Aktuelle Sitzung Keine anderen Sitzungen Du kannst dich von jedem Handy, Tablet und Computer bei Telegram mit derselben Telefonnummer anmelden. Alles wird immer sofort synchronisiert. - Andere Sitzungen + Aktive Sitzungen Überprüfe alle deine angemeldeten Sitzungen. Tippe auf eine Sitzung um sie zu beenden. Diese Sitzung abmelden? @@ -1816,7 +1836,7 @@ Fingerabdruck wurde nicht erkannt. Bitte erneut versuchen. App-Inhalte nach Sperrung anzeigen Wenn du diese Funktion deaktivierst, wirst du keine Bildschirmfotos mehr in der App aufnehmen können und Chatinhalte werden in der Liste der geöffneten App ausgeblendet. - Das wird die Inhalte der Chatliste oder Chats in der Liste der geöffneten Apps verstecken, du wirst jedch keine Bildschirmfotos aufnehmen können. \n\nDu wirst die App nach der Änderung neu starten müssen. + Das wird die Inhalte der Chatliste oder Chats in der Liste der geöffneten Apps verstecken, du wirst jedoch keine Bildschirmfotos aufnehmen können. \n\nDu wirst die App nach der Änderung neu starten müssen. Zu viele Versuche.\nBitte erneut in %1$s versuchen. Januar @@ -1922,12 +1942,16 @@ Dieses Video ist nicht für Streaming optimiert. Du musst es vollständig herunterladen, um es abzuspielen. App konnte dieses Video nicht abspielen. Möchtest du es mit einem externen Player abspielen? Suchverlauf + BILDER + GIFS Suchverlauf BILDERSUCHE SUCHE IM WEB GIF-SUCHE Suche Bilder Suche GIFs + Antippen, um Zugriff auf deine Kamera zu erlauben + Antippen, um Zugriff auf deine Galerie zu erlauben Bild zuschneiden Verbessern Lichter @@ -1972,6 +1996,8 @@ Quadrat Zeigt Medien als einzelne Nachrichten Zeigt alle Medien in einer Nachricht + Ohne Gruppierung senden + Ohne Komprimierung senden Zweistufige Bestätigung Zweistufige Bestätigung @@ -2192,7 +2218,7 @@ JETZT LÖSCHEN Zurück Registrieren - Ablehnen & Deaktivieren + Ablehnen & Löschen Weiter Du bist der Gruppe per Link beigetreten @@ -2220,7 +2246,7 @@ un1 ist in die Gruppe zurückgekehrt un1 ist der Gruppe beigetreten Du bist in die Gruppe zurückgekehrt - Du hast diesem Bot erlaubt, dich anschreiben, als du dich auf %1$s angemeldet hast. + Du hast diesem Bot erlaubt, dich anzuschreiben, als du dich auf %1$s angemeldet hast. %1$s hat die folgenden Dokumente erhalten: %2$s Persönliche Daten Adresse @@ -2346,15 +2372,15 @@ Möchtest du die erweiterte Linkvorschau in Geheimen Chats aktivieren? Die Vorschau wird auf den Telegram Servern generiert. Inline Bots werden von Drittentwicklern erstellt. Symbole, die du nach dem Botnamen eingibst, werden an den jeweiligen Entwickler geschickt, damit der Bot funktioniert. Du kannst diese Nachricht nicht bearbeiten. - Bitte erlaube Telegram den Zugriff auf SMS, so dass wir den Code automatisch in der App für dich eingeben können. Bitte erlaube Telegram den Zugriff auf Anrufe, so dass wir den Code automatisch in der App eingeben können. + Bitte erlaube Telegram, Anrufe zu empfangen und die Anrufliste einzusehen , so dass wir den Code automatisch für dich eingeben können. + Bitte erlaube Telegram auf die Anrufliste zuzugreifen, so dass wir den Code für dich automatisch eingeben können. Bitte erlaube Telegram, Anrufe zu empfangen, damit wir deine Telefonnummer automatisch bestätigen können. - Bitte erlaube Telegram Anrufe zu empfangen, damit wir deine Telefonnummer automatisch bestätigen können. Du kannst diese Aktion nicht durchführen. Du kannst diesen Nutzer oder Bot Gruppen leider nicht hinzufügen, da du ihn blockiert hast. Gebe ihn wieder frei, um fortzufahren. GRUPPE BEITRETEN Du kannst diesen Nutzer nicht als Admin festlegen, da er kein Mitglied dieser Gruppe ist oder du keine Erlaubnis hast, ihn einzuladen. - Du kannst diesen Nutzer nicht als Admin festlegen, da er sich in der Sperrliste befindet und du ihn nicht entsperren darfst. + Du kannst diesen Nutzer nicht als Admin festlegen, da er sich in der Liste \"Entfernte Nutzer\" befindet und du ihn nicht entfernen darfst. Du kannst diesen Nutzer nicht sperren, da er ein Admin dieser Gruppe ist und du keine Berechtigung hast, ihn zurückzustufen. Die Admins dieser Gruppe haben dir die Berechtigung entzogen, Sticker zu senden. Die Admins dieser Gruppe haben dir die Berechtigung entzogen, Medien zu senden. @@ -2815,6 +2841,24 @@ und %1$d andere und %1$d andere und %1$d andere + %1$d Bilder ausgewählt + %1$d Bild ausgewählt + %1$d Bilder ausgewählt + %1$d Bilder ausgewählt + %1$d Bilder ausgewählt + %1$d Bilder ausgewählt + %1$d Videos ausgewählt + %1$d Video ausgewählt + %1$d Videos ausgewählt + %1$d Videos ausgewählt + %1$d Videos ausgewählt + %1$d Videos ausgewählt + %1$d Medien ausgewählt + %1$d Medium ausgewählt + %1$d Medien ausgewählt + %1$d Medien ausgewählt + %1$d Medien ausgewählt + %1$d Medien ausgewählt Gruppe Kanal diff --git a/TMessagesProj/src/main/res/values-es/strings.xml b/TMessagesProj/src/main/res/values-es/strings.xml index 606ff3127..330bdd015 100644 --- a/TMessagesProj/src/main/res/values-es/strings.xml +++ b/TMessagesProj/src/main/res/values-es/strings.xml @@ -23,7 +23,7 @@ Los contactos de este dispositivo fueron añadidos a tu cuenta. Verificación - Enviamos un SMS con el código de activación al **%1$s**. + Enviamos un SMS con un código de activación a tu teléfono **%1$s**. Enviamos el código a la app de **Telegram** en tu otro dispositivo. Revisa tus mensajes en Telegram Pon el código @@ -49,7 +49,7 @@ Tu código de inicio de sesión es **%1$s**. Ponlo en la app de Telegram en la que estás intentando iniciar sesión.\n\nNo le des este código a nadie. Tu nombre - Pon tu nombre completo y sube una foto de perfil. + Pon tu nombre y añade una foto de perfil. Nombre (requerido) Apellidos (opcional) Cancelar registro @@ -195,7 +195,7 @@ Enviar GIF Ver pack Anclar - Lo sentimos, no puedes anclar más de %1$s chats arriba. + Lo sentimos, sólo puedes anclar %1$s chats en la lista principal. Si buscas más organización, prueba archivando algunos chats. La carpeta de Chats archivados permite un número ilimitado de anclados. Desanclar Marcar como no leído Marcar como leído @@ -231,7 +231,7 @@ ¿Quieres salir de **%1$s**? Lo sentimos, no puedes añadir a este usuario a grupos. Lo sentimos, el grupo está lleno. - Lo sentimos, este usuario decidió salir del grupo, así que no puedes añadirlo otra vez. + Lo sentimos, si una persona ya no forma parte de un grupo, deben añadirse como contactos para que pueda regresar.\n\nTen en cuenta que se puede unir al grupo con un enlace de invitación si no está en la lista de usuarios eliminados. Hay demasiados administradores en el grupo. Lo sentimos, el usuario objetivo tiene demasiados grupos o canales públicos. Por favor, pídele que haga privado uno de sus grupos o canales existentes primero. Lo sentimos, el usuario objetivo tiene demasiados grupos por ubicación. Por favor, pídele eliminar o transferir uno de los existentes primero. @@ -388,6 +388,8 @@ Firmar los mensajes Añade los nombres de los administradores a sus publicaciones. Permisos de administrador + Título personalizado + Un título personalizado se mostrará a todos los miembros en lugar de “%1$s”. ¿Qué puede hacer este administrador? Cambiar info. del canal Cambiar info. del grupo @@ -445,7 +447,7 @@ Suspender y eliminar del grupo ¿Aplicar cambios? Cambiaste los permisos de este usuario en **%1$s**. ¿Aplicar cambios? - Personalizados + Personalizada Administrar grupo Administrar canal Administrar grupo @@ -501,6 +503,16 @@ ¿Quieres desvincular a **%1$s** de este canal? CONVERSAR canal + Modo lento + No + %1$ds + %1$dm + %1$dh + Elige el tiempo que cada miembro debe esperar antes de enviar su siguiente mensaje. + Los miembros podrán enviar sólo un mensaje cada %1$s. + El modo lento está activado. No puedes enviar más de un mensaje a la vez. + El modo lento está activado. No puedes seleccionar más ítems. + Lo sentimos, este texto es muy largo para ser enviado en un mensaje.\n\nEl modo lento está activado. No puedes enviar más de un mensaje a la vez. Nueva encuesta Encuesta @@ -582,8 +594,8 @@ un1 eliminó el enlace del grupo un1 eliminó el enlace del canal Enlace anterior - un1 editó la descripción del grupo: - un1 editó la descripción del canal: + un1 cambió la descripción del grupo: + un1 cambió la descripción del canal: Descripción anterior un1 dejó visible el historial para nuevos miembros un1 ocultó el historial para nuevos miembros @@ -611,6 +623,8 @@ Añadir administradores Suspender usuarios Añadir usuarios + Título: %1$s + Título Anclar mensajes Todas las acciones Nuevas excepciones @@ -622,6 +636,8 @@ Mensajes editados Mensajes anclados Miembros que se fueron + un1 estableció el modo lento a %1$s + un1 desactivó el modo lento Nueva difusión Nombre de la lista @@ -656,7 +672,7 @@ Puedes elegir un pack para que los miembros del grupo lo utilicen en él. ELIGE UN PACK DE STICKERS stickerset - Puedes crear tu pack de stickers personalizado usando el bot @stickers. + Puedes crear tus packs de stickers personalizados usando el bot @stickers. El pack no ha sido encontrado Reinténtalo o elige uno de la lista de abajo @@ -712,12 +728,12 @@ No dejan rastro en el servidor Tienen autodestrucción de mensajes Impiden reenviar mensajes - Te eliminaron de este grupo + te eliminaron del grupo Dejaste este grupo Eliminar este grupo Eliminar este chat DESLIZA PARA CANCELAR - Guardar en descargas + Guardar en Descargas Guardar GIF ¿Eliminar GIF? Guardar en música @@ -860,6 +876,9 @@ ESTAFA vía El mensaje no existe + Modo lento activado. Puedes enviar\ntu próximo mensaje en %1$s. + Toca para foto, mantén para video + Enviar sin sonido %1$s activó la autodestrucción en %2$s Activaste la autodestrucción en %1$s @@ -1075,7 +1094,7 @@ Iniciar chat secreto Grupos en común Grupos en común - Aún no hay grupos en común + Sin grupos en común Ocurrió un error. Clave de cifrado Autodestrucción @@ -1113,6 +1132,7 @@ Ocurrió un error. Stickers y máscaras + Stickers animados en bucle Añadir stickers AÑADIR %1$s ELIMINAR %1$s @@ -1465,7 +1485,7 @@ Direct Share Ver chats recientes al compartir en Android Emoji - Usar un emoji grande + Emojis grandes Usar emoji predeterminado Telegram para Android %1$s Menú de depuración @@ -1602,7 +1622,7 @@ Sube un escaneo de tu factura de servicios. Sube un escaneo de tu extracto de cuenta bancaria. Sube un escaneo de tu contrato de alquiler. - Sube un escaneo de la página de tu registro del pasaporte. + Sube un escaneo de la página de registro de tu pasaporte. Sube un escaneo de tu registro temporal. Para confirmar tu dirección, por favor, sube un escaneo o foto del documento seleccionado (todas las páginas). Sube escaneos de una traducción certificada al inglés de tu factura de servicios. @@ -1713,7 +1733,7 @@ No puedes subir más de %1$s. Sólo puedes subir archivos de imagen. Escanea tu pasaporte - Escanea tu pasaporte o tarjeta de identificación con la zona legible para máquinas para completar los datos personales automáticamente. + Escanea tu pasaporte o tarjeta de identificación con zona legible para máquinas para completar los datos personales automáticamente. Añadir un documento No tienes documentos aún Puedes añadir un número de teléfono, dirección de correo, documento de identificación o dirección residencial. @@ -1922,12 +1942,16 @@ Este video no está optimizado para streaming. Tendrás que descargarlo completamente para reproducirlo. La app no logró reproducir este video. ¿Quieres intentarlo con un reproductor externo? No hay fotos recientes + IMÁGENES + GIF No hay GIF recientes BUSCAR FOTOS BÚSQUEDA WEB BUSCAR GIF Buscar foto Buscar GIF + Toca para permitir el acceso a tu Cámara + Toca para permitir el acceso a tu Galería Recortar imagen Realzar Iluminación @@ -1972,6 +1996,8 @@ Cuadrada Mostrar multimedia en mensajes por separado Agrupar multimedia en un mensaje + Enviar sin agrupar + Enviar sin compresión Verificación en dos pasos Verificación @@ -2192,7 +2218,7 @@ ELIMINAR AHORA Atrás Registrarse - Rechazar y desactivar + Rechazar y eliminar Siguiente Te uniste al grupo con un enlace de invitación @@ -2346,10 +2372,10 @@ ¿Quieres permitir las vistas previas ampliadas en chats secretos? Ten en cuenta que son generadas en los servidores de Telegram. Ten en cuenta que los bots integrados son hechos por terceros. Para que funcione, los símbolos escritos después del alias del bot, son enviados al desarrollador respectivo. Lo sentimos, no puedes editar este mensaje. - Por favor, permite a Telegram recibir SMS para que podamos ingresar automáticamente el código por ti. Por favor, permite a Telegram recibir llamadas para que podamos ingresar automáticamente el código por ti. + Por favor, permite a Telegram recibir llamadas y leer el registro de llamadas para que podamos poner automáticamente el código por ti. + Por favor, permite a Telegram leer el registro de llamadas para que podamos poner automáticamente el código por ti. Por favor, permite a Telegram recibir llamadas para que podamos confirmar tu número de teléfono automáticamente. - Por favor, permite a Telegram recibir llamadas para que podamos confirmar tu número de teléfono automáticamente. Lo sentimos, no tienes permitido hacer esto. No puedes añadir a este usuario o bot al grupo porque lo has bloqueado. Por favor, desbloquéalo para continuar. UNIRME AL GRUPO @@ -2410,7 +2436,7 @@ Llamada de Telegram en curso Finalizar llamada Otra llamada en curso - Actualmente tienes una llamada en curso con **%1$s**. ¿Quieres colgar esa llamada y empezar una nueva con **%2$s**? + Actualmente tienes una llamada en curso con **%1$s**. ¿Quieres colgar y empezar una nueva con **%2$s**? Llamadas de voz Tono de llamada Puedes personalizar el tono de llamada desde este contacto en Telegram. @@ -2459,7 +2485,7 @@ Incluir información técnica Esto no revela los contenidos de tu chat y nos ayuda a resolver el problema antes. Gracias por ayudarnos a mejorar las llamadas de Telegram. - Contestando como %s + contestando como %s Responder con mensaje Estas respuestas rápidas estarán disponibles cuando respondas a una llamada entrante con un mensaje de Telegram. Puedes modificarlas para decir lo que tú quieras. No puedo hablar ahora. ¿Qué pasa? @@ -2815,6 +2841,24 @@ y otros %1$d y otros %1$d y otros %1$d + %1$d fotos seleccionadas + %1$d foto seleccionada + %1$d fotos seleccionadas + %1$d fotos seleccionadas + %1$d fotos seleccionadas + %1$d fotos seleccionadas + %1$d videos seleccionados + %1$d video seleccionado + %1$d videos seleccionados + %1$d videos seleccionados + %1$d videos seleccionados + %1$d videos seleccionados + %1$d archivos multimedia seleccionados + %1$d archivo multimedia seleccionado + %1$d archivos multimedia seleccionados + %1$d archivos multimedia seleccionados + %1$d archivos multimedia seleccionados + %1$d archivos multimedia seleccionados Grupo Canal diff --git a/TMessagesProj/src/main/res/values-it/strings.xml b/TMessagesProj/src/main/res/values-it/strings.xml index 42240a772..209749fb5 100644 --- a/TMessagesProj/src/main/res/values-it/strings.xml +++ b/TMessagesProj/src/main/res/values-it/strings.xml @@ -23,7 +23,7 @@ I contatti da questo dispositivo sono stati aggiunti al tuo account. Verifica numero - Abbiamo inviato un SMS con un codice di attivazione al tuo numero **%1$s**. + Abbiamo inviato un SMS con un codice di accesso al tuo numero **%1$s**. Abbiamo inviato il codice su **Telegram** nel tuo altro dispositivo. Controlla i tuoi messaggi Telegram Inserisci codice @@ -49,7 +49,7 @@ Il tuo codice di accesso è **%1$s**. Inseriscilo nell\'app Telegram in cui stai cercando di accedere.\n\nNon dare questo codice a nessuno. Il tuo nome - Inserisci il tuo nome completo e carica una foto profilo. + Inserisci il tuo nome e aggiungi una foto profilo. Nome (obbligatorio) Cognome (facoltativo) Annulla iscrizione @@ -195,7 +195,7 @@ Invia GIF Visualizza pacchetto Fissa in alto - Spiacenti, non puoi fissare più di %1$s in alto. + Spiacenti, puoi fissare solo %1$s nella tua lista principale. Se stai cercando più organizzazione prova ad archiviare alcune chat – la lista Chat archiviate non ha limiti di chat fissate. Togli dall\'alto Segna come non letto Segna come letto @@ -231,10 +231,10 @@ Sei sicuro di voler lasciare **%1$s**? Spiacenti, non puoi aggiungere questo utente ai gruppi. Spiacenti, questo gruppo è pieno. - Spiacenti, questo utente ha deciso di lasciare il gruppo, quindi non puoi riaggiungerlo. + Spiacenti, se una persona non fa più parte di un gruppo, devi essere nei suoi contatti di Telegram per poterla aggiungere di nuovo.\n\nTieni presente che può comunque partecipare tramite link di invito del gruppo purché non sia nell\'elenco Utenti rimossi. Spiacenti, troppi amministratori in questo gruppo. Spiacenti, l\'utente in oggetto ha già troppi gruppi o canali pubblici. Per favore chiedigli di rendere privato uno dei suoi gruppi o canali. - Spiacenti, l\'utente in oggetto ha già troppi gruppi basati sulla posizione. Per favore chiedigli di eliminare prima uno di quelli. + Spiacenti, l\'utente in oggetto ha già troppi gruppi basati sulla posizione. Per favore chiedigli di eliminare o trasferire prima uno di quelli. Spiacenti, hai già troppi gruppi basati sulla posizione. Per favore eliminane prima uno dei tuoi. Spiacenti, troppi bot in questo gruppo. un1 ha fissato \"%1$s\" @@ -388,6 +388,8 @@ Firma messaggi " Aggiungi i nomi degli amministratori nei messaggi da loro pubblicati." Permessi amministratore + Titolo personalizzato + Sarà mostrato un titolo personalizzato a tutti i membri invece di \'%1$s\'. Cosa può fare questo amministratore? Cambiare le info del canale Cambiare le info del gruppo @@ -403,7 +405,7 @@ Puoi trasferire questo gruppo a **%1$s** solo se hai: Puoi trasferire questo canale a **%1$s** solo se lo hai: La **Verifica in due passaggi** abilitata da più di **7 giorni**. - Connesso questo dispositivo più di **24 ore** fa. + Eseguito l\'accesso su questo dispositivo da più di **24 ore**. Per favore ritorna più tardi. Imposta password Questo trasferirà tutti i **diritti di proprietà** per **%1$s** a **%2$s*. @@ -486,21 +488,31 @@ Seleziona una chat di gruppo per la discussione che sarà mostrata nel tuo canale. Tutto ciò che pubblichi nel canale verrà inoltrato in questo gruppo. A tutti gli iscritti viene mostrato un collegamento a **%1$s** nel pannello inferiore. - Il gruppo è collegato come bacheca di discussione di **%1$s*. + Il gruppo è collegato come chat di discussione di **%1$s*. Tutti i nuovi messaggi pubblicati in questo canale sono inoltrati nel gruppo. Crea un nuovo gruppo Scollega gruppo Scollega canale Scollega COLLEGA GRUPPO - Vuoi rendere **%1$s** la bacheca di discussione di **%2$s**? - Vuoi rendere **%1$s** la bacheca di discussione di **%2$s**?\n\nQualsiasi membro di questo gruppo potrà vedere i messaggi nel canale. - Vuoi rendere **%1$s** la bacheca di discussione di **%2$s**?\n\nChiunque dal canale potrà vedere i messaggi in questo gruppo. + Vuoi rendere **%1$s** la chat di discussione di **%2$s**? + Vuoi rendere **%1$s** la chat di discussione di **%2$s**?\n\nQualsiasi membro di questo gruppo potrà vedere i messaggi nel canale. + Vuoi rendere **%1$s** la chat di discussione di **%2$s**?\n\nChiunque dal canale potrà vedere i messaggi in questo gruppo. La \"Cronologia per i nuovi membri\" sarà resa Visibile. Sei sicuro di voler scollegare **%1$s** da questo gruppo? Sei sicuro di voler scollegare **%1$s** da questo canale? DISCUTI canale + Modalità lenta + Spenta + %1$ds + %1$dm + %1$dh + Scegli quanto tempo ciascun membro deve attendere prima di inviare il messaggio successivo. + I membri potranno inviare solo un messaggio ogni %1$s. + La modalità lenta è attiva. Non puoi inviare più di un messaggio alla volta. + La modalità lenta è attiva. Non puoi selezionare più elementi. + Spiacenti, questo testo è troppo lungo da inviare come singolo messaggio.\n\nLa modalità lenta è attiva. Non puoi inviare più di un messaggio alla volta. Nuovo sondaggio Sondaggio @@ -573,8 +585,8 @@ ha trasferito la proprietà a %1$s un1 ha cambiato il set di sticker del gruppo un1 ha rimosso il set di sticker del gruppo - un1 ha reso un2 il gruppo di discussione per questo canale - un1 ha rimosso il gruppo di discussione un2 + un1 ha reso un2 la chat di discussione per questo canale + un1 ha rimosso la chat di discussione un2 un1 ha collegato questo gruppo a un2 un1 ha scollegato questo gruppo da un2 un1 ha cambiato il link del gruppo: @@ -611,6 +623,8 @@ Aggiungere amministratori Bloccare utenti Aggiungere utenti + Titolo: %1$s + Titolo Fissare messaggi Tutte le azioni Nuove eccezioni @@ -622,6 +636,8 @@ Messaggi modificati Messaggi fissati Membri usciti + un1 ha attivato la modalità lenta con timer %1$s + un1 ha disattivato la modalità lenta Nuova lista broadcast Inserisci il nome della lista @@ -712,7 +728,7 @@ Nessuna traccia sui server Timer di autodistruzione Nessun inoltro - Sei stato rimosso da questo gruppo + sei stato rimosso da questo gruppo Hai lasciato il gruppo Elimina questo gruppo Elimina questa chat @@ -860,6 +876,9 @@ TRUFFA via Il messaggio non esiste + La modalità lenta è attiva. Puoi inviare\nil prossimo messaggio tra %1$s + Tocca per le foto, tieni premuto per i video + Invia senza suono %1$s ha impostato il timer di autodistruzione a %2$s Hai impostato il timer di autodistruzione a %1$s @@ -1075,13 +1094,13 @@ Inizia chat segreta Gruppi in comune Gruppi in comune - Ancora nessun gruppo in comune + Nessun gruppo in comune Si è verificato un errore. Chiave di crittografia Timer di autodistruzione Se imposti un timer, la foto si autodistruggerà dopo essere stata vista. Se imposti un timer, il video si autodistruggerà dopo essere stato visto. - Spento + No L\'immagine e il testo sono derivati dalla chiave di crittografia di questa chat segreta con **%1$s**.\n\nSe sono uguali sul dispositivo di **%2$s**, la crittografia end-to-end è garantita.\n\nUlteriori informazioni su telegram.org https://telegram.org/faq/it#chat-segrete Sconosciuto @@ -1113,6 +1132,7 @@ Si è verificato un errore. Sticker e maschere + Riproduci sticker animati in loop Aggiungi sticker AGGIUNGI %1$s RIMUOVI %1$s @@ -1465,7 +1485,7 @@ Condivisione diretta Mostra le chat recenti nel menù di condivisione Emoji - Disegna una singola emoji grande + Emoji grandi Usa emoji predefinite Telegram per Android %1$s Menù debug @@ -1616,7 +1636,7 @@ Aggiungi contratto di locazione Indirizzo Indirizzo di residenza - Per favore fornisci il tuo indirizzo + Fornisci il tuo indirizzo Carica una prova del tuo indirizzo Indirizzo Via @@ -1700,11 +1720,11 @@ Scansioni Elimina documento Elimina - Sei sicuro di voler eliminare questa scansione? - Sei sicuro di voler eliminare questo selfie? - Sei sicuro di voler eliminare questo documento? + Vuoi eliminare questa scansione? + Vuoi eliminare questo selfie? + Vuoi eliminare questo documento? Sei sicuro di voler eliminare i dettagli personali? - Sei sicuro di voler eliminare i dettagli dell\'indirizzo? + Vuoi eliminare i dettagli dell\'indirizzo? Elimina dettagli personali Elimina dettagli indirizzo Eliminare la scansione? @@ -1713,7 +1733,7 @@ Non puoi caricare più di %1$s. Puoi caricare solamente immagini. Scansiona il tuo passaporto - Scansiona il tuo passaporto o la carta d\'identità con campi leggibili in modo che i dettagli personali vengano inseriti in automatico. + Scansiona il tuo passaporto o la carta d\'identità con campi leggibili in modo che i tuoi dettagli vengano inseriti in automatico. Aggiungi un documento Non hai ancora alcun documento Puoi aggiungere il tuo numero di telefono, indirizzo email, documento d\'identità o indirizzo di residenza. @@ -1779,7 +1799,7 @@ Premi su una sessione per terminarla. Terminare questa sessione? Esce da tutti i dispositivi tranne questo. - Sicuro di voler terminare tutte le altre sessioni? + Sei sicuro di voler terminare tutte le altre sessioni? Termina le altre sessioni app non ufficiale Nessun accesso attivo. @@ -1922,12 +1942,16 @@ Questo video non è ottimizzato per lo streaming. Potresti doverlo scaricare completamente per riprodurlo. L\'app non è in grado di riprodurre questo video. Vuoi provare con un player esterno? Nessuna foto recente + IMMAGINI + GIF Nessuna GIF recente CERCA IMMAGINI RICERCA WEB CERCA GIF Cerca su web Cerca GIF + Premi per permettere l\'accesso alla tua Fotocamera + Premi per permettere l\'accesso alla tua Galleria Ritaglia immagine Migliora Alte luci @@ -1972,6 +1996,8 @@ Quadrato Mostra i media come messaggi separati Mostra i media come messaggio unico + Invia senza raggruppare + Invia senza compressione Verifica in due passaggi Verifica in due passaggi @@ -2192,7 +2218,7 @@ ELIMINA ORA Indietro Iscriviti - Rifiuta e disattiva + Rifiuta ed elimina Avanti Ti sei unito al gruppo tramite link d\'invito @@ -2263,9 +2289,9 @@ Numero di telefono non valido. Per favore controlla il numero e riprova. Per favore accedi al tuo account Telegram per usare Telegram Passport. Questo numero è stato bloccato. - Codice scaduto, effettua di nuovo l\'accesso + Codice scaduto, per favore riprova l\'accesso Troppi tentativi, riprova più tardi - Troppi tentativi, per favore riprova di nuovo tra %1$s + Troppi tentativi, per favore riprova tra %1$s Codice non valido Spiacenti, hai eliminato e ricreato il tuo account troppe volte di recente. Per favore attendi alcuni giorni prima di iscriverti di nuovo. Nome non valido @@ -2310,7 +2336,7 @@ Questo bot vorrebbe sapere la tua posizione ogni volta che invii una richiesta. Questo può essere usato per fornire risultati specifici in base alla posizione. Condividere il tuo numero di telefono? Il bot saprà il tuo numero di telefono. Questo può essere utile per l\'integrazione con altri servizi. - Sicuro di voler condividere il tuo numero %1$s con **%2$s**? + Sei sicuro di voler condividere il tuo numero %1$s con **%2$s**? Sei sicuro di voler condividere il tuo numero? Sei sicuro di voler bloccare **%1$s**? Sei sicuro di voler sbloccare questo contatto? @@ -2346,10 +2372,10 @@ Vuoi attivare le anteprime estese per i link nelle Chat Segrete? Nota che le anteprime dei link sono generate sui server di Telegram. Per favore nota che i bot inline sono forniti da sviluppatori di terze parti. Per far funzionare il bot, i simboli che digiti dopo l\'username del bot sono inviati al rispettivo sviluppatore. Spiacenti, non puoi modificare questo messaggio. - Per favore consenti a Telegram di ricevere SMS così potremo inserire in automatico il codice per te. Per favore consenti a Telegram di ricevere chiamate così potremo inserire in automatico il codice per te. + Per favore permetti a Telegram di ricevere chiamate e leggere il registro delle chiamate in modo da poter inserire il codice per te automaticamente. + Per favore permetti a Telegram di leggere il registro delle chiamate in modo da poter inserire il codice per te automaticamente. Per favore consenti a Telegram di ricevere chiamate, così potremo confermare automaticamente il tuo numero di telefono. - Per favore consenti a Telegram di ricevere chiamate, così potremo confermare automaticamente il tuo numero di telefono. Spiacenti, questa azione non ti è permessa. Spiacenti, non puoi aggiungere questo utente o bot al gruppo perché lo hai bloccato. Per favore sbloccalo per procedere. UNISCITI AL GRUPPO @@ -2410,7 +2436,7 @@ Chiamata Telegram in corso Termina chiamata Altra chiamata in corso - Al momento hai una chiamata in corso con **%1$s**. Vuoi terminare quella chiamata e iniziarne una nuova con **%2$s**? + Al momento hai una chiamata in corso con **%1$s**. Vuoi riagganciare e iniziarne una nuova con **%2$s**? Chiamate vocali Suoneria Puoi personalizzare la suoneria usata quando questo contatto ti chiama su Telegram. @@ -2446,7 +2472,7 @@ Richiama Richiama Default - Sei sicuro di voler eliminare questa voce dal registro delle chiamate? + Vuoi eliminare questa voce dal registro delle chiamate? Chiamata Telegram Auricolare Altoparlante @@ -2459,7 +2485,7 @@ Includi informazioni tecniche Non rivela i contenuti della chat e ci aiuta a risolvere il problema più velocemente. Grazie per aver contribuito a rendere le chiamate di Telegram migliori. - Rispondi come %s + rispondi come %s Rispondi con messaggio Queste risposte rapide sono disponibili quando rispondi ad una chiamata in entrata con un messaggio Telegram. Modificale a tuo piacimento. Non posso parlare ora. Cosa succede? @@ -2815,6 +2841,24 @@ e altri %1$d e altri %1$d e altri %1$d + %1$d foto selezionate + %1$d foto selezionata + %1$d foto selezionate + %1$d foto selezionate + %1$d foto selezionate + %1$d foto selezionate + %1$d video selezionati + %1$d video selezionato + %1$d video selezionati + %1$d video selezionati + %1$d video selezionati + %1$d video selezionati + %1$d media selezionati + %1$d media selezionato + %1$d media selezionati + %1$d media selezionati + %1$d media selezionati + %1$d media selezionati Gruppo Canale diff --git a/TMessagesProj/src/main/res/values-ko/strings.xml b/TMessagesProj/src/main/res/values-ko/strings.xml index 591dee824..60146d531 100644 --- a/TMessagesProj/src/main/res/values-ko/strings.xml +++ b/TMessagesProj/src/main/res/values-ko/strings.xml @@ -23,7 +23,7 @@ 기기에 있는 연락처가 계정에 추가되었습니다. 휴대폰 인증 - **%1$s** 번호로 인증 코드가 담긴 SMS츨 보냈습니다. + **%1$s** 번호로 SMS 인증 코드를 보냈습니다. 회원님의 다른 기기에 설치된 **텔레그램** 앱으로 코드를 보냈습니다. 텔레그램 메시지를 확인하세요 코드를 입력하세요 @@ -49,7 +49,7 @@ Your login code is **%1$s**. Enter it in the Telegram app where you are trying to log in.\n\nDo not give this code to anyone. 성명 - 회원님의 성함을 입력하고 프로필 사진을 업로드해 주세요. + 이름을 입력하고 프로필 사진을 추가하세요. 이름 (필수) 성 (선택) 가입 취소 @@ -202,8 +202,8 @@ 굵게 기울임꼴 고정폭 - Strikethrough - Underline + 취소선 + 밑줄 일반 모든 기기에 걸쳐 친구들과 소통하려면 **텔레그램**의 연락처 접근을 허용해 주세요. 단단히 암호화된 텔레그램 서버로 회원님의 연락처가 지속적으로 동기화될 것입니다. 지금 안 함 @@ -234,8 +234,8 @@ 죄송합니다. 이 사용자는 스스로 그룹에서 나갔기에, 다시 초대하실 수 없습니다. 죄송합니다, 그룹에 너무 많은 관리자가 있습니다. Sorry, the target user has too many public groups or channels already. Please ask them to make one of their existing groups or channels private first. - Sorry, the target user has too many location-based groups already. Please ask them to delete one of their existing ones first. - Sorry, you have too many location-based groups already. Please delete one of your existing ones first. + 죄송합니다. 대상이 되는 사용자가 위치 기반 그룹을 너무 많이 소유하고 있습니다. 먼저 그룹을 하나 삭제하거나 소유권을 넘기도록 요청해 주세요. + 죄송합니다. 위치 기반 그룹을 너무 많이 만드셨습니다. 먼저 하나를 삭제해 주세요. 죄송합니다. 이 그룹에는 봇이 너무 많습니다. un1 님이 \"%1$s\"을(를) 고정했습니다 un1 님이 메시지를 고정했습니다 @@ -271,7 +271,7 @@ 몇 가지 채널 설정을 바꾸셨습니다. 변경 사항을 적용할까요? 공개 채널 공개 그룹 - Location-based Group + 위치 기반 그룹 공개 채널은 검색으로 찾을 수 있으며, 누구나 들어올 수 있습니다. 공개 그룹은 검색으로 찾을 수 있고, 모두에게 대화 내용이 공개되며, 누구나 들어갈 수 있습니다. 비공개 채널 @@ -290,7 +290,7 @@ 조용히 알리기 채널이란 무엇인가요? 채널은 회원님의 메시지를 수많은 사람에게 알리기 위한 도구입니다. - Create Channel + 채널 만들기 죄송합니다. 이미 사용되고 있는 이름입니다. 올바르지 않은 이름입니다. 채널명은 5자 이상이어야 합니다. @@ -331,8 +331,8 @@ 채널 사진이 제거되었습니다 채널명이 un2(으)로 바뀌었습니다 죄송하지만, 공개 사용자명을 너무 많이 가지셨습니다. 다른 그룹이나 채널의 링크를 하나 폐기하거나, 비공개 그룹으로 바꾸세요. - 생성자 - Administrator + 소유자 + 관리자 관리자 음소거 음소거 취소 @@ -388,6 +388,8 @@ 메시지 서명 메시지에 게시한 관리자의 이름을 추가합니다. 관리자 권한 + 맞춤 제목 + 맞춤 제목이 모든 참가자에게 \'%1$s\' 대신 보입니다. 이 관리자가 할 수 있는 일 채널 정보 수정 그룹 정보 수정 @@ -397,19 +399,19 @@ 메시지 삭제 새로운 관리자 추가 관리자 권한 회수 - 그룹 소유권 이전 - 채널 소유권 이전 + 그룹 소유권 넘기기 + 채널 소유권 넘기기 보안 확인 사항 - You can transfer this group to **%1$s** only if you have: - You can transfer this channel to **%1$s** only if you have: - Enabled **2-Step Verification** more than **7 days** ago. - Logged in on this device more than **24 hours** ago. - Please come back later. + 아래 경우에만 이 그룹을 **%1$s** 님에게 넘기실 수 있습니다: + 다음 경우에만 이 채널을 **%1$s** 님에게 넘기실 수 있습니다: + **7일** 전에 **2단계 인증**을 켬 + **24시간** 전에 이 기기에 로그인함 + 나중에 다시 시도하세요. 비밀번호 설정 - This will transfer the **full owner** rights for **%1$s** to **%2$s**. + **총소유자** 권한을 **%1$s** 님에게서 **%2$s** 님에게로 넘깁니다. 소유자 바꾸기 - **%1$s** is now the owner of the group. - **%1$s** is now the owner of the channel. + **%1$s** 님이 이제 그룹의 소유자입니다. + **%1$s** 님이 이제 채널의 소유자입니다. 사용자 차단 사용자 추가 링크로 사용자 초대 @@ -445,7 +447,7 @@ 차단하고 그룹에서 추방 변경 사항을 적용할까요? **%1$s**에서 사용자의 권한을 수정하셨습니다. 변경 사항을 적용할까요? - Custom + 맞춤 그룹 관리 채널 관리 그룹 관리 @@ -468,8 +470,8 @@ 공개 비공개 공개 - Link - Tap to add a permanent link + 링크 + 영구 링크를 추가하려면 누르세요 사진 선택 카메라 갤러리 @@ -486,21 +488,31 @@ 채널 안에 표시될 토론 그룹 대화방을 선택하세요. 채널에 게시하시는 모든 게시물이 이 그룹으로 전달됩니다. **%1$s** 링크는 모든 구독자에게 바닥 패널에서 보입니다. - **%1$s** is linking the group as its discussion board. + **%1$s** 채널은 토론 게시판 그룹을 연결하고 있습니다. 이 채널에 새로 게시되는 대화가 모두 그룹에 전달됩니다. 새로운 그룹 만들기 그룹 연결 해제 채널 연결 해제 연결 해제 그룹 연결 - Do you want to make **%1$s** the discussion board for **%2$s**? - Do you want to make **%1$s** the discussion board for **%2$s**?\n\nAny member of this group will be able to see messages in the channel. - Do you want to make **%1$s** the discussion board for **%2$s**?\n\nAnyone from the channel will be able to see messages in this group. - \"Chat history for new members\" will be switched to Visible. + **%1$s** 그룹을 **%2$s**의 토론 게시판으로 삼으시겠습니까? + **%1$s** 그룹을 **%2$s** 채널의 토론 게시판으로 삼으시겠습니까?\n\n이 그룹에 속한 모든 참가자는 채널의 메시지를 볼 수 있습니다. + **%1$s** 그룹을 **%2$s**의 토론 게시판을 삼으시겠습니까?\n\n\n채널에서 온 누구나 이 그룹의 메시지를 볼 수 있습니다. + \"새로운 참가자에게 대화 기록\"이 보이기로 전환됩니다. **%1$s** 채널과 이 그룹의 연결을 해제하시겠습니가? - Are you sure you want to unlink **%1$s** from this channel? + 정말 이 채널에서 **%1$s** 그룹을 연결 해제하시겠습니까? 토론 채널 + 저속 모드 + 끄기 + %1$d초 + %1$d분 + %1$d시간 + Choose how long each member must wait before sending their next message. + 참가자는 메시지를 %1$s초에 하나씩만 보낼 수 있습니다. + 저속 모드가 켜져 있습니다. 한 번에 메시지를 하나 이상 보내실 수 없습니다. + 저속 모드가 켜져 있습니다. 항목을 더 선택하실 수 없습니다. + 죄송합니다. 이 글은 한 메시지로 치기에 너무 깁니다.\n\n저속 모드가 켜져 있습니다. 한 번에 메시지를 하나 이상 보내실 수 없습니다. 새로운 설문 설문 @@ -569,14 +581,14 @@ un1 님이 설문을 마감했습니다: un1 님이 아래 메시지를 삭제했습니다: un1 님이 그룹 위치를 \"%1$s\"로 바꿨습니다 - un1 removed group location - transferred ownership to %1$s + un1 님이 그룹 위치를 제거했습니다 + %1$s 님에게 소유권을 넘겼습니다 un1 님이 그룹 스티커 묶음을 변경했습니다 un1 님이 그룹 스티커 묶음을 제거했습니다 - un1 made un2 the discussion group for this channel - un1 removed the discussion group un2 - un1 linked this group to un2 - un1 unlinked this group from un2 + un1 님이 un2 그룹을 채널 전용 토론 그룹으로 삼았습니다 + un1 님이 un2 토론 그룹을 제거했습니다 + un1 님이 이 그룹을 un2에 연결했습니다 + un1 님이 이 그룹을 un2에서 연결 해제했습니다 un1 님이 그룹 링크를 바꿨습니다: un1 님이 채널 링크를 바꿨습니다: un1 님이 그룹 링크를 제거했습니다 @@ -611,6 +623,8 @@ 관리자 추가 사용자 차단 사용자 추가 + 제목: %1$s + 제목 메시지 고정 모든 활동 새로운 예외 @@ -622,6 +636,8 @@ 메시지 수정 메시지 고정 나간 참가자 + un1 님이 저속 모드 타이머를 %1$s(으)로 맞췄습니다 + un1 님이 저속 모드를 껐습니다 새 단체 메시지 리스트 리스트 이름을 입력하세요 @@ -702,7 +718,7 @@ 최근 이모지 없음 메시지 메시지 - SHARE MY PHONE NUMBER + 내 전화번호 공유 내 연락처 공유 연락처에 추가 %s 님이 회원님을 비밀 대화에 초대했습니다. @@ -736,23 +752,23 @@ 파일로 보내기 링크 열기 %1$s을(를) 여시겠습니까? - Log in to %1$s as **%2$s** + **%2$s** 님으로 %1$s에 로그인 **%1$s**에서 나에게 메시지를 보내도록 허용합니다 보내기 취소 %1$s이(가) 앞으로 여실 페이지로 회원님의 텔레그램 이름과 아이디(전화번호 아님)를 전달할 수 있도록 허락할까요? - GROUP UNRELATED TO LOCATION? - Report unrelated group - Please let us know if this group is not related to this location:\n\n**%1$s** - Please let us know if this group is not related to this location. + 이 장소와 관련 없는 그룹인가요? + 상관 없는 그룹 신고 + 그룹이 이 장소와 관련 없는 경우 알려 주세요:\n\n**%1$s** + 그룹이 이 장소와 관련 없는 경우 알려 주세요. 스팸 신고 - Report spam - Block %1$s - BLOCK USER + 스팸 신고 + %1$s 님 차단 + 사용자 차단 스팸 신고하고 나가기 연락처에 추가 - ADD %1$s TO CONTACTS + 연락처에 %1$s 님 추가 연락처 보기 - Do you want to block **%1$s** from messaging and calling you on Telegram? + 텔레그램 메시지와 전화 수신에서 **%1$s** 님을 차단하시겠습니까? 정말 이 사용자가 보낸 스팸을 신고하시겠습니까? 이 그룹 메시지를 스팸신고 하시겠습니까? 이 채널을 스팸 신고하시겠습니까? @@ -859,7 +875,10 @@ Google 지도를 설치할까요? 신용 사기 "다음을 통해 보냄: " - Message doesn\'t exist + 메시지가 존재하지 않습니다 + 저속 모드가 켜져 있습니다. %1$s 뒤에 다음 메시지를 보내실 수 있습니다. + 사진은 짧게 누르고, 동영상은 꾹 누르세요 + 소리 없이 보내기 %1$s 님이 자동 삭제 타이머를 %2$s(으)로 맞췄습니다 자동 삭제 타이머를 %1$s(으)로 맞추셨습니다 @@ -995,8 +1014,8 @@ 텔레그램이 아직 동기화되지 않은 여러 연락처를 찾아냈습니다. 연락처를 동기화하시겠습니까? 본인의 기기, SIM 카드와 Google 계정을 사용하는 중이라면 \'확인\'을 누르십시오. 이름순으로 정렬 마지막 접속순으로 정렬 - Add %1$s - Phone number + %1$s 추가 + 전화번호 사람들을 추가하세요... 이 그룹을 마저 만들고 슈퍼그룹으로 변환한 뒤에 사용자를 더 추가하실 수 있습니다. @@ -1046,12 +1065,12 @@ **슈퍼그룹에서는**\n\n• 새로운 참가자가 대화 내용 전체를 볼 수 있습니다\n• 한 사람이 메시지를 삭제하면 모두에게서도 사라집니다\n• 생성자가 그룹에 공개 링크를 둘 수 있습니다 **주의:** 이 작업은 되돌릴 수 없습니다. - 공유 - 추가 + 연락처 공유 + 연락처에 추가 연락처 추가 %1$s 님은 아직 텔레그램에 가입하지 않았습니다. 초대하시겠습니까? 초대 - 차단 + 사용자 차단 사용자 차단 사용자가 차단되었습니다 사용자가 차단 해제되었습니다 @@ -1066,7 +1085,7 @@ 생일 제목 새 연락처 등록 - New Contact + 새로운 연락처 기존 연락처에 추가 자기소개 본인에 대해 몇 마디 적어 보세요 @@ -1086,11 +1105,11 @@ https://telegram.org/faq#secret-chats 알 수 없음 없음 - Mobile hidden - Phone number will be visible once %1$s adds you as a contact. - When you tap **DONE**, your phone number will become visible to %1$s. - Share my phone number with %1$s - %1$s is now in your contact list. + 전화번호 숨김 + 전화번호는 %1$s 님이 회원님을 연락처로 추가하는 즉시 보입니다. + **완료**를 누르시면, 회원님의 전화번호가 %1$s 님에게 보입니다. + %1$s 님과 내 전화번호 공유 + %1$s 님이 연락처 목록에 등록되었습니다. 정보 전화번호 공유하는 콘텐츠 @@ -1113,6 +1132,7 @@ 오류가 발생했습니다. 스티커 및 마스크 + 움직이는 스티커 반복 재생 스티커 추가 %1$s 추가 %1$s 제거 @@ -1431,7 +1451,7 @@ 텔레그램 번호를 여기서 바꾸실 수 있습니다. 회원님의 계정과 함께 메시지와 미디어, 연락처 따위의 모든 클라우드 데이터가 새 번호로 옮겨집니다.\n\n**중요:** 텔레그램 연락 상대 중에서 회원님의 옛 전화번호가 있으며 차단되지 않은 모두에게 회원님의 **새 전화번호**가 등록됩니다. 텔레그램 연락 상대 중에서 회원님의 옛 전화번호가 있으며 차단되지 않은 모두에게 회원님의 새 전화번호가 등록됩니다. 번호 바꾸기 - Change number + 번호 바꾸기 새 번호 회원님의 새 번호로 인증 코드가 담긴 SMS를 보내겠습니다. 그 번호는 이미 텔레그램 계정에 연결되어 있습니다. 새 번호로 이동하기 전에 %1$s 계정에서 탈퇴해 주세요. @@ -1465,7 +1485,7 @@ 바로 공유 공유 메뉴에 최근 대화방 띄우기 이모지 - 큰 이모지 하나 그리기 + 대용량 이모지 시스템 기본 이모지 사용 Android용 텔레그램 %1$s 디버그 메뉴 @@ -1542,7 +1562,7 @@ 대체 옵션 다른 계정 추가 다른 텔레그램 계정을 연결하여 두 계정 간 손쉽게 전환하세요. - 암호 설정 + 암호 설정하기 다른 사람이 열 수 없도록 앱을 암호로 잠그세요. 캐시 비우기 기기의 저장 공간을 확보하세요. 미디어는 클라우드에 보존됩니다. @@ -1558,11 +1578,11 @@ 결과 없음 최근 검색 없음 자주 묻는 질문 - Distance Units - Distance units - Automatic - Kilometers - Miles + 거리 단위 + 거리 단위 + 자동 + 킬로미터 + 마일 로컬 데이터베이스 캐시가 된 문자 메시지를 비울까요? @@ -1616,7 +1636,7 @@ 임차 계약서 추가 주소 거주지 주소 - 회원님의 주소를 입력해 주세요 + 회원님의 주소를 입력하세요 회원님 주소의 증명을 업로드하세요 주소 도로 @@ -1700,20 +1720,20 @@ 스캔 서류 삭제 삭제 - 정말 이 스캔을 삭제하시겠습니까? - 정말 본인 사진을 삭제하시겠습니까? - 정말 이 서류를 삭제하시겠습니까? + 스캔을 삭제하시겠습니까? + 본인 사진을 삭제하시겠습니까? + 서류를 삭제하시겠습니까? 정말 개인 신상 명세를 삭제하시겠습니까? - 정말 주소 세부 정보를 삭제하시겠습니까? + 주소 세부 사항을 삭제하시겠습니까? 개인 신상 명세 삭제 - 주소 세부 정보 삭제 + 주소 세부 사항 삭제 스캔을 삭제할까요? 스캔 업로드 추가 스캔 업로드 파일을 %1$s개 이상 업로드하실 수 없습니다. 이미지 파일만 업로드하실 수 있습니다. 회원님의 여권을 스캔하세요 - 자동으로 개인 신상 명세를 채우려면 기계 판독 가능 구역이 있는 회원님의 여권이나 신분증을 스캔하세요. + 개인 신상 명세를 자동으로 채우려면 회원님의 여권이나 신분증의 기계 판독 가능 구역을 스캔하세요. 서류 추가 아직 서류가 없습니다 회원님의 전화번호나 이메일 주소, 신분 증명서, 거주지 주소를 추가하실 수 있습니다. @@ -1800,7 +1820,7 @@ 암호를 설정하시면, 대화방 화면에 잠금 아이콘이 나타납니다. 이 아이콘을 눌러 텔레그램을 잠그거나 잠금 해제하실 수 있습니다.\n\n주의: 암호를 잊어버리면 앱을 삭제하고 다시 설치하셔야 합니다. 이 경우 모든 비밀 대화가 사라집니다. PIN 암호 - 현재 암호를 임력하세요 + 현재 암호를 입력하세요 암호를 입력하세요 새 암호를 입력하세요 암호를 입력하세요 @@ -1854,10 +1874,10 @@ 지도 위성 혼합 - %1$s m away - %1$s km away - %1$s ft away - %1$s mi away + %1$s m 떨어짐 + %1$s km 떨어짐 + %1$s ft 떨어짐 + %1$s mi 떨어짐 내 현재 위치 보내기 내 실시간 위치 공유... 위치 공유 중단 @@ -1869,7 +1889,7 @@ 위치 장소 반경 %1$s 내로 정확함 - %1$s away + %1$s 떨어짐 아니면 장소 선택 근처 장소를 보려면 쓸어 올리세요 실시간 위치 @@ -1886,23 +1906,23 @@ %1$s 님에게 회원님의 정확한 위치를 얼마 동안 보일지 선택하세요. 이 대화방 사람들에게 회원님의 실시간 위치를 얼마 동안 보일지 선택하세요. GPS가 꺼져 있습니다. 위치 기반 서비스를 사용하려면 GPS를 켜 주세요. - People Nearby - Add People Nearby - Quickly add people nearby who are viewing this section and discover local group chats. \n\nPlease switch on location access to enable this feature. - People nearby - Allow Access - Quickly add people nearby who are also viewing this section and discover local group chats.\n\nPlease turn on location services to enable this feature. - Turn On - Groups nearby - Ask your friend nearby to open this page to exchange phone numbers. - Looking for users around you... + 주변 사람 + 주변 사람 추가 + 손쉽게 이 페이지를 열고 있는 사람들을 추가하고 지역 그룹 대화방을 찾으세요.\n\n이 기능을 켜려면 위치 접근을 켜 주세요. + 주변 사람 + 접근 허용 + 이 페이지를 보고 있는 주변 사람들을 손쉽게 추가하고 지역 그룹 대화방을 발견해 보세요.\n\n이 기능을 사용하려면 위치 서비스를 켜 주세요. + 켜기 + 주변 그룹 + 친구에게 이 페이지를 열자고 말하여 전화번호를 교환하세요. + 주변에 있는 사용자를 찾는 중... 지역 그룹 만들기 그룹하기 - Anyone close to this location (neighbors, co-workers, fellow students, event attendees, visitors of a venue) will be able to see your group in the People Nearby section. - If you start an unrelated group at this location, you may lose the ability to create location-based groups. - Set Location - 이 위치 설정 - People will be able to find your group in the \"People Nearby\" section. + 이 근처에 있는 사람들(이웃이나 직장 동료, 친구, 학생, 행사 참석자, 방문객)이 회원님의 그룹을 \'주변 사람\' 탭에서 볼 수 있습니다. + 이 위치와 관계 없는 그룹을 만든다면, 앞으로 위치 기반 그룹을 못 만드시게 될 수도 있습니다. + 위치 설정 + 이 위치로 설정하기 + 사람들이 회원님의 그룹을 \"주변 사람\" 구역에서 찾을 수 있습니다. 모든 미디어 보기 모든 파일 보기 @@ -1922,12 +1942,16 @@ 이 동영상은 스트리밍에 최적화되어 있지 않습니다. 재생하려면 완전히 다운로드하셔야 합니다. 앱에서 동영상을 재생할 수 없습니다. 외부 플레이어로 재생할까요? 최근 사진 없음 + 이미지 + GIF 최근 GIF 없음 이미지 찾기 웹 검색 GIF 찾기 웹 검색 GIF 검색 + 카메라 접근을 허용하려면 누르기 + 갤러리 접근을 허용하려면 누르기 사진 자르기 향상 하이라이트 @@ -1972,6 +1996,8 @@ 정방형 미디어를 개별 메시지로 보내기 미디어를 하나의 메시지로 묶기 + 묶지 않고 보내기 + 압축 없이 보내기 2단계 인증 2단계 인증 @@ -1998,7 +2024,7 @@ 2단계 인증용 복구 이메일이 이제 작동합니다. 비밀번호 바꾸기 비밀번호 끄기 - 복구 이메일 설정 + 복구 이메일 설정하기 복구 이메일 바꾸기 정말 비밀번호를 사용하지 않도록 하시겠습니까? 정말 2단계 인증 설정을 중단하시겠습니까? @@ -2064,18 +2090,18 @@ 프로필 사진 내 프로필 사진을 볼 수 있는 사람 회원님의 프로필 사진을 볼 수 있는 사람을 세세하게 제한하실 수 있습니다. - 이 설정은 앞선 설정보다 우선합니다. + 앞선 설정을 무시하고 사용자나 그룹 전체를 예외로 추가하실 수 있습니다. 전화번호 내 전화번호를 볼 수 있는 사람 Users who already have your number saved in their contacts will see it on Telegram. - You can add users or entire groups as exceptions that will override the settings above. + 앞선 설정을 무시하고 사용자와 그룹을 예외로 추가하실 수 있습니다. 전달된 메시지 회원님 계정으로 연결합니다 아래 설정이 허용할 시 연결합니다 회원님의 계정으로 연결하지 않습니다 내 메시지를 전달할 때 내 계정으로 연결시킬 수 있는 사람 회원님이 보낸 메시지가 다른 대화방으로 전달되었을 때 회원님의 계정으로 연결되지 않습니다. - 이 설정은 앞선 설정보다 우선합니다. + 앞선 설정을 무시하고 사용자나 그룹 전체를 예외로 추가하실 수 있습니다. 라인하르트, 새 음악도 좀 들어보시지 그래요 🎶? 피어투피어 단대단 통화 @@ -2110,7 +2136,7 @@ 이 기간 안에 한 번이라도 접속하시지 않으면, 모든 그룹, 메시지, 연락처와 더불어 회원님의 계정이 사라집니다. 내 마지막 접속 시간을 볼 수 있는 사람 예외 추가 - Add to exceptions + 예외에 추가 중요: 회원님의 마지막 접속 시간을 공유받지 않는 사람의 마지막 접속 시간은 보실 수 없습니다. 대신 최근, 일주일 이내, 한달 이내와 같이 간략하게 보일 것입니다. 일부 개인 정보 설정을 바꾸셨습니다. 변경 사항을 적용할까요? 항상 공유할 사람 @@ -2129,7 +2155,7 @@ 위 사용자는 앞선 설정과 무관하게 회원님을 그룹과 채널에 추가하지 못합니다. 회원님을 그룹과 채널에 추가할 수 있는 사람을 정하세요. 죄송합니다. 사용자의 개인 정보 보호 설정으로 인해 이 사용자를 그룹에 추가하실 수 없습니다. - 죄송합니다. 이 사용자는 그룹의 참가자가 아니며 회원님에게 초대할 권한이 없기에 관리자에 추가하실 수 없습니다. + 죄송합니다. 사용자의 개인 정보 설정으로 인해 이 사용자를 채널에 추가하실 수 없습니다. 죄송합니다. 이 사용자들의 개인 설정으로 인해 함께 그룹을 만드실 수 없습니다. 단대단을 끄시면, 회원님의 IP 주소를 노출시키지 않도록 모든 전화가 텔레그램 서버를 통해 전달됩니다. 다만 음성 품질이 약간 저하될 수 있습니다. 동기화된 연락처 삭제 @@ -2192,7 +2218,7 @@ 지금 삭제 뒤로 가입 - 거절 및 정지 + 거절 및 삭제 다음 초대 링크를 통해 그룹에 들어오셨습니다 @@ -2232,7 +2258,7 @@ 신분증 공과금 고지서 입출금 내역서 - 임차 계약서 + 임대 계약서 전화번호 이메일 주소 이 메시지는 현재 텔레그램 버전에서 지원되지 않습니다. 메시지를 보시려면 http://telegram.org/update 에서 앱을 업데이트하세요. @@ -2255,7 +2281,7 @@ 회원님이 스크린샷을 찍었습니다! un1 님이 스크린샷을 찍었습니다! - Warning! This will **delete all messages** in this chat for **both** participants. + 잠깐! **참가자 서로에게서** 이 대화방의 **모든 메시지가 삭제**됩니다. 모두 삭제 불러오기를 중단할까요? 텔레그램을 업데이트하세요 @@ -2263,13 +2289,13 @@ 전화번호가 잘못되었습니다. 번호를 확인하여 다시 시도해 주세요. 텔레그램 패스포트를 사용하려면 텔레그램 계정에 로그인해 주세요. 차단된 전화번호입니다. - 코드가 만료되었습니다. 다시 로그인해 주세요. + 코드가 만료되었습니다. 다시 로그인하세요. 너무 많이 시도하셨습니다. 나중에 다시 시도하세요 너무 많이 시도하셨습니다. %1$s초 뒤에 다시 시도하세요. 올바른 코드를 입력해 주세요 죄송합니다. 최근 들어 계정을 너무 많이 삭제한 뒤 재생성하셨습니다. 며칠 기다렸다 다시 가입해 주세요. 올바른 이름을 입력해 주세요 - 올바른 성을 입력해 주세요 + 죄송합니다, 이 성은 사용하실 수 없습니다 불러오는 중... 동영상 재생기가 없습니다. 계속하려면 앱을 설치하세요. 발생한 문제를 자세히 적어 sms@stel.com으로 이메일을 보내 주세요. @@ -2284,7 +2310,7 @@ 정말 %1$s 님을 **%2$s**에 초대하시겠습니까? 정말 %1$s 님을 **%2$s**에 추가하시겠습니까? 새로운 참가자에게 최근 메시지 100개를 보입니다 - Show the last 100 messages to **%1$s** + 최근 메시지 100개를 **%1$s** 님에게 보이기 %1$s 님에게 메시지를 보낼까요? %1$s 님에게 게임을 공유할까요? %1$s 님에게 연락처를 보낼까요? @@ -2346,10 +2372,10 @@ 비밀 대화에서 링크 미리보기를 활성화하시겠습니까? 링크 미리보기는 텔레그램 서버에서 만들어지는 점을 유의하시기 바랍니다. 인라인 봇은 제3 개발자가 제공한다는 점을 유의하시기 바랍니다. 봇이 작동하는 과정에서, 봇의 사용자명 뒤에 입력하신 부호가 각 개발자에게 보내집니다 죄송합니다. 메시지를 수정할 수 없습니다. - 텔레그램이 SMS를 받을 수 있도록 허락해 주셔야 자동으로 코드를 입력해 드릴 수 있습니다. 텔레그램이 전화를 수신 할 수 있도록 설정해주셔야 자동으로 코드 입력이 가능합니다. + Please allow Telegram to receive calls and read the call log so that we can automatically enter your code for you. + Please allow Telegram to read the call log so that we can automatically enter your code for you. 텔레그램이 전화를 받을 수 있도록 허용해 주셔야 회원님의 전화번호를 자동으로 확인할 수 있습니다. - 텔레그램이 전화를 받을 수 있도록 허용해 주시면 전화번호가 자동으로 확인됩니다. 죄송합니다. 이 작업은 진행하실 수 없습니다. 죄송합니다. 차단된 사용자나 봇은 그룹에 추가하실 수 없습니다. 먼저 차단을 해제해 주세요. 그룹 들어가기 @@ -2410,7 +2436,7 @@ 텔레그램으로 통화 중 통화 종료 이미 통화하고 계십니다 - 현재 **%1$s** 님과 전화하고 계십니다. 이 전화를 끊고 **%2$s** 님과 새로 전화하시겠습니까? + 현재 **%1$s** 님과 통화하고 계십니다. 이 전화를 끊고 **%2$s** 님과 새로 통화하시겠습니까? 음성 전화 벨소리 이 연락처에서 전화가 걸려올 때 울리는 벨소리를 맞춤하실 수 있습니다. @@ -2815,6 +2841,24 @@ 및 %1$d 개 및 %1$d 개 및 %1$d 개 + 사진 %1$d장 선택됨 + 사진 %1$d장 선택됨 + 사진 %1$d장 선택됨 + 사진 %1$d장 선택됨 + 사진 %1$d장 선택됨 + 사진 %1$d장 선택됨 + 동영상 %1$d개 선택됨 + 동영상 %1$d개 선택됨 + 동영상 %1$d개 선택됨 + 동영상 %1$d개 선택됨 + 동영상 %1$d개 선택됨 + 동영상 %1$d개 선택됨 + 미디어 %1$d개 선택됨 + 미디어 %1$d개 선택됨 + 미디어 %1$d개 선택됨 + 미디어 %1$d개 선택됨 + 미디어 %1$d개 선택됨 + 미디어 %1$d개 선택됨 그룹 채널 @@ -2889,8 +2933,8 @@ 동영상 품질 종횡비 사진 한 장 더 찍기 - Seen - Not seen + 접속함 + 접속 안 함 미재생 다음 검색 결과 이전 검색 결과 diff --git a/TMessagesProj/src/main/res/values-nl/strings.xml b/TMessagesProj/src/main/res/values-nl/strings.xml index 7c5f0f7d4..1d67d318a 100644 --- a/TMessagesProj/src/main/res/values-nl/strings.xml +++ b/TMessagesProj/src/main/res/values-nl/strings.xml @@ -11,11 +11,11 @@ Je telefoon Bevestig je landnummer en voer je telefoonnummer in. Kies een land - Onjuist landnummer + Ongeldig landnummer Dit account heeft al een actieve sessie in deze app. Wissel Contacten synchroniseren - Hiermee verwijder je je contacten van de Telegram-servers.\nals \'Contacten Synchroniseren\' is ingeschakeld worden je contacten opnieuw gesynchroniseerd. + Hiermee verwijder je je contacten van de Telegram-servers.\nAls \'Contacten Synchroniseren\' is ingeschakeld worden je contacten opnieuw gesynchroniseerd. Contacten van dit apparaat worden aan dit account toegevoegd Contacten van dit apparaat worden niet aan dit account toegevoegd. Contacten van dit apparaat worden aan je account toegevoegd. @@ -23,7 +23,7 @@ Contacten van dit apparaat zijn aan je account toegevoegd. Telefoonverificatie - We hebben een sms-bericht met activatiecode verzonden naar **%1$s**. + Een SMS met activatiecode is verzonden naar **%1$s**. We hebben de code naar je andere **Telegram**-app gestuurd. Controleer je Telegramberichten Code invoeren @@ -49,7 +49,7 @@ Je logincode is **%1$s**. Voer de code in in de Telegram-app waarop je probeert in te loggen.\n\nGeef deze code nooit aan iemand anders. Je naam - Geef je volledige naam in upload je profielfoto + Geef je naam in upload je profielfoto Voornaam (verplicht) Achternaam (optioneel) Registratie annuleren @@ -195,7 +195,7 @@ GIF sturen Bundel bekijken Vastzetten - Je kunt maxmimaal %1$s vastzetten. + Je kunt maxmimaal %1$s vastzetten. Wil je je chats anders organiseren? Probeer wat chats te archiveren, in je archief kun je onbeperkt chats vastzetten. Losmaken Markeer als ongelezen Markeer als gelezen @@ -231,7 +231,7 @@ **%1$s** echt verlaten? Je kunt deze gebruiker niet toevoegen aan groepen. Sorry, deze groep is vol. - Deze gebruiker heeft de groep verlaten. Je kunt hem/haar niet meer uitnodigen. + Deze gebruiker heeft de groep verlaten. Opnieuw toevoegen kan alleen door wederzijdse contactpersonen.\n\nZolang deze gebruiker niet in de lijst met verwijderde gebruikers staat kan hij/zij altijd nog lid worden via de uitnodigingslink van de groep. Maximaal aantal beheerders bereikt. Sorry, de gebruiker heeft al teveel locatiegebonden groepen of kanalen. Vraag of ze er eerst 1 willen overdragen of verwijderen. Sorry, de gebruiker heeft al teveel locatiegebonden groepen. Vraag of ze er eerst 1 willen overdragen of verwijderen. @@ -388,6 +388,8 @@ Ondertekenen Beheerdersnaam bij alle uitgaande berichten. Beheerdersrechten + Aangepaste titel + Een aangepaste titel die zal worden weergegeven aan alle leden i.p.v. \'%1$s\'. Wat mag deze beheerder? Informatie aanpassen Informatie aanpassen @@ -445,7 +447,7 @@ Blokkeer en verwijder uit groep Wijzigingen toepassen? Je hebt de rechten van deze gebruiker in **%1$s** aangepast. Wijzigingen toepassen? - Custom + Aangepast Groep beheren Kanaal beheren Groep beheren @@ -501,6 +503,16 @@ **%1$s** echt ontkoppelen van dit kanaal? Discussiëren kanaal + Tempolimiet + Uit + %1$ds + %1$dm + %1$du + Kies hoe lang leden moeten wachten voordat ze een volgend bericht kunnen sturen. + Leden kunnen maar 1 bericht sturen per %1$s. + Tempolimiet ingeschakeld. Je kunt niet meer dan 1 bericht tegelijkertijd sturen. + Tempolimiet ingeschakeld. Je kunt niet meer dan 1 item selecteren. + Sorry, deze tekst is te lang om als 1 bericht te sturen.\n\nTempolimiet is ingeschakeld, je kunt niet meer dan 1 bericht tegelijkertijd sturen. Nieuwe poll Poll @@ -611,6 +623,8 @@ Beheerders toevoegen Leden blokkeren Leden toevoegen + Titel: %1$s + Titel Berichten vastzetten Alle gebeurtenissen Nieuwe uitzonderingen @@ -622,6 +636,8 @@ Gewijzigde berichten Vastgezette berichten Vertrokken leden + un1 heeft tempolimiet ingesteld op %1$s + un1 heeft tempolimiet uitgeschakeld Nieuwe verzendlijst Naam van lijst @@ -859,7 +875,10 @@ Google Maps installeren? OPLICHTING via - Message doesn\'t exist + Bericht bestaat niet + Tempolimiet is ingeschakeld. Je kunt het\nvolgende bericht sturen over %1$s. + Tik voor foto, hou vast voor video + Stuur zonder geluid %1$s heeft de zelfvernietigingstimer ingesteld op %2$s Je hebt de zelfvernietigingstimer ingesteld op %1$s @@ -1113,6 +1132,7 @@ Er is een fout opgetreden. Stickers en Maskers + Geanimeerde stickers herhalen Stickers toevoegen VOEG %1$s TOE VERWIJDER %1$s @@ -1465,7 +1485,7 @@ Snel delen Recente chats in snel delen weergeven Emoji - Grote emoji gebruiken + Grote emoji Systeem-emoji gebruiken Telegram voor Android %1$s Debug-menu @@ -1558,11 +1578,11 @@ Geen resultaten Geen recente zoekopdrachten Veelgestelde vragen - Distance Units - Distance units - Automatic - Kilometers - Miles + Afstandseenheden + Afstandseenheden + Automatisch + Kilometer + Mijlen Lokale database Gecachet tekstberichten wissen? @@ -1854,10 +1874,10 @@ Kaart Satelliet Hybride - %1$s m away - %1$s km away - %1$s ft away - %1$s mi away + %1$s m afstand + %1$s km afstand + %1$s voet afstand + %1$s mijl afstand Huidige locatie sturen Deel mijn live-locatie Delen van locatie stoppen @@ -1898,7 +1918,7 @@ Zoeken naar gebruikers in de buurt Maak een lokale groep Groep starten - Iedereen die hier dichtbijt is (buren, collega\'s, medestudenten, etc.) zien je groep in de \"Mensen dichtbij\"-sectie. + Iedereen die hier dichtbij is (buren, collega\'s, medestudenten, etc.) zien je groep in de \"Mensen dichtbij\"-sectie. Als je een ongerelateerde groep op deze plek start kun je beperkt worden in het maken van nieuwe lokatie-afhankelijke groepen. Locatie instellen Stel deze locatie in @@ -1922,12 +1942,16 @@ Deze video is niet geoptimaliseerd om te streamen, een volledige download kan nodig zijn om deze af te spelen. De app kon deze video niet afspelen. Afspelen proberen met externe speler? Niets recents + AFBEELDINGEN + GIF\'S Niets recents ONLINE ZOEKEN ZOEK OP HET WEB "GIF\'S ZOEKEN " Online zoeken GIF\'s zoeken + Tik om toegang tot je camera toe te staan + Tik om toegang tot je galerij toe te staan Foto bijsnijden Verbeteren Accent @@ -1972,6 +1996,8 @@ Vierkant Geeft media als aparte berichten weer Geef media als een enkel bericht weer + Stuur zonder groeperen + Stuur zonder compressie Twee-staps-verificatie Twee-staps-verificatie @@ -2263,7 +2289,7 @@ Ongeldig telefoonnummer, controleer het nummer en probeer opnieuw. Log in op Telegram om Telegram Passport te gebruiken. Dit nummer is geblokkeerd. - Code verlopen. Log opnieuw in. + Code verlopen, log opnieuw in. Te veel pogingen. Probeer het later opnieuw. Te veel pogingen, probeer het over %1$s opnieuw Ongeldige code @@ -2346,10 +2372,10 @@ Wil je uitgebreide link-voorbeelden inschakelen voor geheime chats? Let op: deze worden gegenereerd op onze servers. Let op: inline-bots worden aangeboden door externe ontwikkelaars. Voor de werking van de bot worden de karakters die je na de botnaam typt naar deze ontwikkelaar verstuurd. Je mag dit bericht niet wijzigen. - Sta het ontvangen van SMS toe zodat we automatisch je inlogcode kunnen invoeren. Sta het ontvangen van oproepen toe zodat we automatisch je inlogcode kunnen invoeren. + Sta Telegram toe om oproepen te ontvangen en de oproepenlijst te lezen zodat we automatisch de code voor je kunnen ingeven. + Sta Telegram toe om de oproepenlijst te lezen zodat we automatisch de code voor je in kunnen voeren. Sta het ontvangen van oproepen toe zodat we automatisch je telefoonnummer kunnen bevestigen. - Sta het ontvangen van oproepen toe zodat we automatisch je telefoonnummer kunnen bevestigen. Je mag deze actie niet uitvoeren. Je hebt deze gebruiker of bot geblokkeerd, toevoegen aan een groep kan pas na deblokkeren. LID WORDEN @@ -2815,6 +2841,24 @@ en %1$d anderen en %1$d anderen en %1$d anderen + %1$d foto\'s geselecteerd + %1$d foto geselecteerd + %1$d foto\'s geselecteerd + %1$d foto\'s geselecteerd + %1$d foto\'s geselecteerd + %1$d foto\'s geselecteerd + %1$d video\'s geselecteerd + %1$d video geselecteerd + %1$d video\'s geselecteerd + %1$d video\'s geselecteerd + %1$d video\'s geselecteerd + %1$d video\'s geselecteerd + %1$d media geselecteerd + %1$d media geselecteerd + %1$d media geselecteerd + %1$d media geselecteerd + %1$d media geselecteerd + %1$d media geselecteerd Groep Kanaal diff --git a/TMessagesProj/src/main/res/values-pt-rBR/strings.xml b/TMessagesProj/src/main/res/values-pt-rBR/strings.xml index a8ede29e1..e2ff41795 100644 --- a/TMessagesProj/src/main/res/values-pt-rBR/strings.xml +++ b/TMessagesProj/src/main/res/values-pt-rBR/strings.xml @@ -15,7 +15,7 @@ Esta conta já está conectada a partir deste aplicativo. Alternar Sincronizar Contatos - Isso removerá os seus contatos dos servidores do Telegram. Se \"Contatos Sincronizados\" estiver ativa, os contatos serão sincronizados novamente. + Isso removerá os seus contatos dos servidores do Telegram. Se \"Sincronizar Contatos\" estiver ativa, os contatos serão sincronizados novamente. Contatos deste dispositivo serão adicionados à sua conta. Contatos deste dispositivo não serão adicionados à sua conta. Contatos deste dispositivo serão adicionados à sua conta. @@ -23,8 +23,8 @@ Contatos deste dispositivo foram adicionados à sua conta. Verificar Número - Nós te enviamos um SMS com um código de ativação para **%1$s**. - Nós enviamos o código para o app do **Telegram** em seu outro dispositivo. + Enviamos uma SMS com um código de ativação para **%1$s**. + Enviamos o código para o app do **Telegram** em seu outro dispositivo. Confira suas mensagens no Telegram Inserir código Estamos ligando para o seu telefone **%1$s**.\n\nNão atenda, o Telegram processará tudo automaticamente. @@ -40,7 +40,7 @@ Cancelar Exclusão da Conta Alguém com acesso ao seu número de telefone **%1$s** solicitou a exclusão de sua conta do Telegram e a redefinição de sua senha de Verificação em Duas Etapas.\n\nSe não foi você, por favor insira o código que te enviamos via SMS. Apagar conta - Uma vez que a conta **%1$s** está ativa e protegida por senha, nós iremos desativá-la em 1 semana, por questões de segurança.\n\nVocê pode cancelar esse processo a qualquer momento. + Uma vez que a conta **%1$s** está ativa e protegida por senha, iremos desativá-la em 1 semana por questões de segurança.\n\nVocê pode cancelar esse processo a qualquer momento. Você poderá restaurar sua conta em: Suas tentativas recentes de restaurar essa conta foram canceladas pelo usuário ativo. Tente novamente em 7 dias. APAGAR CONTA @@ -49,7 +49,7 @@ Seu código de login é **%1$s**. Digite ele no app do Telegram no qual você está tentando fazer o login.\n\nNão informe esse código para ninguém. Seu nome - Digite seu nome completo e coloque uma foto de perfil. + Digite seu nome e coloque uma foto de perfil. Nome (obrigatório) Sobrenome (opcional) Cancelar registro @@ -59,7 +59,7 @@ Finalizar Métodos de envio Desculpe, não é possível entregar neste endereço. - Dados de envio + Dados de Envio Dados de envio Endereço 1 (Rua) Endereço 2 (Rua) @@ -195,7 +195,7 @@ Enviar GIF Ver Pacote Fixar no topo - Desculpe, você não pode fixar mais que %1$s no topo. + Desculpe, você só pode fixar %1$s na sua lista principal. Se está procurando mais organização, tente arquivar alguns chats – a pasta Chats Arquivados permite o uso de um número ilimitado de chats fixados. Desafixar do topo Marcar como não lido Marcar como lido @@ -231,10 +231,10 @@ Tem certeza de que deseja sair de **%1$s**? Desculpe, você não pode adicionar esse usuário a grupos. Desculpe, este grupo está lotado. - Desculpe, esse usuário decidiu sair deste grupo. Por isso, você não pode convidá-lo de volta. + Desculpe, se uma pessoa não faz mais parte de um grupo, você precisa estar nos contatos do Telegram dela para conseguir adicioná-la de volta ao grupo.\n\nNote que ainda é possível que essa pessoa entre usando um link de convite do grupo desde que não esteja na lista de Usuários Removidos. Desculpe, há muitos administradores neste grupo. - Desculpe, o usuário já tem muitos grupos ou canais públicos. Por favor, peça que ele apague ou transfira um dos grupos ou canais existentes primeiro. - Desculpe, o usuário já tem muitos grupos baseados em localização. Por favor, peça que ele apague um dos grupos existentes primeiro. + Desculpe, o usuário tem muitos grupos ou canais públicos. Por favor, peça que ele mude algum desses para privado primeiro. + Desculpe, o usuário tem muitos grupos baseados em localização. Por favor, peça que ele apague ou transfira um primeiro. Desculpe, você já tem muitos grupos com base em localização. Por favor, apague um dos seus grupos existentes primeiro. Desculpe, há bots demais neste grupo. un1 fixou \"%1$s\" @@ -388,6 +388,8 @@ Assinar Mensagens Adiciona o nome dos admins às mensagens postadas. Permissões de Admin + Título personalizado + Um título personalizado que será mostrado para todos os membros em vez de \'%1$s\'. O que esse admin pode fazer? Alterar Info do Canal Alterar Info do Grupo @@ -501,6 +503,16 @@ Deseja mesmo desvincular **%1$s** deste canal? CONVERSAR canal + Modo Lento + Inativo + %1$ds + %1$dm + %1$dh + Escolha quanto tempo cada membro deverá esperar antes de enviar uma próxima mensagem. + Os membros poderão enviar apenas uma mensagem a cada %1$s. + O Modo Lento está ativado. Você não pode enviar mais de uma mensagem por vez. + O Modo Lento está ativado. Você não pode selecionar mais itens. + Desculpe, este texto é muito longo para ser enviado em uma só mensagem.\n\nO Modo Lento está ativado. Você não pode enviar mais de uma mensagem por vez. Nova Enquete Enquete @@ -611,6 +623,8 @@ Adicionar admins Banir usuários Adicionar usuários + Título: %1$s + Título Fixar mensagens Todas as ações Novas exceções @@ -622,6 +636,8 @@ Mensagens editadas Mensagens fixadas Pessoas que saíram + un1 definiu o timer do modo lento para %1$s + un1 desativou o modo lento Nova Lista de Transmissão Digite o nome da lista @@ -656,7 +672,7 @@ Você pode escolher um pacote de sticker que estará disponível para todos os membros enquanto estiverem no grupo. ESCOLHER PACOTE DE STICKER pacote de sticker - Você pode criar seu próprio pacote de sticker usando o bot @stickers. + Você pode criar seus próprios pacotes de sticker usando o bot @stickers. Nenhum pacote de sticker encontrado Tente novamente ou escolha da lista abaixo @@ -712,7 +728,7 @@ Sem rastros nos servidores Têm timer de autodestruição Encaminhamento desativado - Você foi removido deste grupo + você foi removido deste grupo Você saiu deste grupo Apagar este grupo Apagar este chat @@ -725,7 +741,7 @@ Aplicar arquivo de localização Aplicar tema Anexo não suportado - Definir timer de autodestruição + Timer de autodestruição notificações de serviço Obtendo informações... ABRIR EM... @@ -860,6 +876,9 @@ FRAUDE via A mensagem não existe. + Modo Lento ativado. Poderá enviar\nsua próxima mensagem em %1$s. + Toque para foto, segure para vídeo + Enviar sem som "%1$s alterou o timer de autodestruição para %2$s " Você alterou o timer de autodestruição para %1$s @@ -917,7 +936,7 @@ %1$s removeu você do grupo %2$s %1$s saiu do grupo %2$s %1$s entrou para o Telegram! - %1$s,\nNós detectamos que alguém acessou a sua conta a partir de um novo aparelho em %2$s\n\nAparelho: %3$s\nLocalização: %4$s\n\nSe não foi você, você pode ir em Configurações - Privacidade e Segurança - Sessões, e terminar aquela sessão.\n\nSe você acha que alguém acessou a sua conta contra a sua vontade, você pode habilitar a verificação em duas etapas nas configurações de Privacidade e Segurança.\n\nAtenciosamente,\nEquipe Telegram + %1$s,\nDetectamos que alguém acessou a sua conta a partir de um novo dispositivo em %2$s\n\nDispositivo: %3$s\nLocalização: %4$s\n\nSe não foi você, vá em Configurações > Privacidade e Segurança > Sessões Ativas, e termine essa sessão.\n\nSe você acha que alguém acessou a sua conta sem a sua permissão, você pode habilitar a Verificação em Duas Etapas nas configurações de Privacidade e Segurança.\n\nAtenciosamente,\nEquipe do Telegram. %1$s atualizou a foto do perfil %1$s entrou para o grupo %2$s via link de convite %1$s enviou %3$s ao grupo %2$s @@ -970,7 +989,7 @@ Selecionar Contatos COMPARTILHAR CONTATO Ainda não há contatos - Ei, estou usando o Telegram para conversar. Vem comigo! Baixe aqui: %1$s + Ei, tô usando o Telegram pra conversar. Vem comigo! Baixe aqui: %1$s às ontem às às %1$s @@ -1048,7 +1067,7 @@ Compartilhar contato Adicionar contato - Adicionar contato + Adicionar Contato %1$s ainda não está no Telegram. Gostaria de fazer um convite? Convidar Bloquear usuário @@ -1113,6 +1132,7 @@ Ocorreu um erro. Stickers e Máscaras + Stickers Animados em Loop Adicionar Stickers ADD %1$s REMOVER %1$s @@ -1432,11 +1452,11 @@ Todos os seus contatos do Telegram terão seu novo número adicionado às listas de contatos deles, desde que tenham seu número antigo e você não os tenha bloqueado no Telegram. Alterar Número Alterar número - Novo número + Novo Número Vamos enviar um SMS com um código de confirmação para o seu novo número. O número %1$s já possui uma conta do Telegram. Por favor, exclua esta conta antes de migrar para o novo número. Outro - Desativado + Desativada Ativado Desativado Desativado @@ -1458,14 +1478,14 @@ Frequência do Alerta de Som %1$s em %2$s Prévia de Links - A prévia de links será gerada nos servidores do Telegram. Nós não armazenamos dados sobre os links que você envia. + A prévia de links será gerada nos servidores do Telegram. Não armazenamos dados sobre os links que você envia. Chats secretos Navegador Interno Abre links externos dentro do aplicativo. Compartilhamento Direto Mostra chats recentes no menu compartilhar. Emoji - Desenhe um único emoji grande + Emoji Grande Usar emoji padrão do sistema Telegram para Android %1$s Debug Menu @@ -1616,7 +1636,7 @@ Adicionar Contrato de Aluguel Endereço Endereço Residencial - Por favor, informe o seu endereço + Informe o seu endereço Enviar comprovante de endereço Endereço Rua @@ -1700,11 +1720,11 @@ Scans Apagar Documento Apagar - Deseja mesmo apagar este scan? - Deseja mesmo apagar esta selfie? - Tem certeza de que deseja apagar esse documento? + Deseja apagar este scan? + Deseja apagar esta selfie? + Deseja apagar esse documento? Tem certeza de que deseja apagar seus dados pessoais? - Tem certeza de que deseja apagar os dados de endereço? + Deseja apagar os dados de endereço? Apagar dados pessoais Apagar dados de endereço Apagar digitalização? @@ -1713,7 +1733,7 @@ Você não pode enviar mais do que %1$s arquivos. Você pode enviar apenas arquivos de imagem. Escaneie Seu Passaporte - Escaneie seu passaporte ou carteira de identidade com zona legível por máquina para preencher os dados pessoais automaticamente. + Escaneie a zona legível por máquina do seu passaporte ou carteira de identidade para preencher os seus dados automaticamente. Adicionar um Documento Você ainda não tem documentos Você pode adicionar seu número de telefone, endereço de email, documento de identidade ou endereço residencial. @@ -1774,8 +1794,8 @@ Sessão Atual Nenhuma outra sessão ativa Você pode entrar no Telegram em outros celulares, tablets e computadores usando o mesmo número de telefone. Todos os seus dados serão sincronizados. - Sessões Ativas - Controle suas sessões em outros aparelhos. + Sessões ativas + Controle suas sessões em outros dispositivos. Toque em uma sessão para terminá-la. Encerrar essa sessão? Sai de todos os dispositivos, exceto este. @@ -1840,9 +1860,9 @@ Conteúdo Compartilhado Links Compartilhados Músicas Compartilhadas - Compartilhar fotos e vídeos no chat e acessá-los em qualquer um de seus dispositivos. + Compartilhe fotos e vídeos neste chat e use qualquer um de seus dispositivos para acessá-las. Compartilhe músicas neste chat e acesse-as de qualquer um de seus dispositivos. - Compartilhar arquivos e documentos no chat e acessá-los de qualquer um de seus dispositivos. + Compartilhe arquivos e documentos nessa conversa e acesse-os de qualquer um de seus dispositivos. Compartilhe links neste chat e os acesse de qualquer um de seus dispositivos Compartilhe mensagens de voz nesta conversa e acesse de qualquer um de seus dispositivos. Fotos e vídeos deste chat serão mostrados aqui. @@ -1888,7 +1908,7 @@ Seu GPS parece estar desativado, ative-o para acessar as funções de localização. Pessoas Próximas Adicionar Pessoas Próximas - Adicione rapidamente pessoas próximas que estejam visualizando esta seção e descubra grupos locais.\n\nPor favor, ative o acesso à localização para ativar esse recurso. + Adicione rapidamente pessoas próximas que estejam visualizando esta seção e descubra grupos locais.\n\nPor favor, ative o acesso à localização para ativar este recurso. Pessoas próximas Permitir Acesso Adicione rapidamente pessoas próximas que estejam visualizando esta seção e descubra grupos locais.\n\nPor favor, ative os serviços de localização para ativar este recurso. @@ -1917,17 +1937,21 @@ Todas as mídias Todos os vídeos Ainda não há fotos - Por favor, baixe a mídia primeiro + Por favor, baixe a mídia primeiro. Por favor, aguarde o download completo do vídeo. Este vídeo não está otimizado para streaming. Talvez você precise baixá-lo para assistir. O app não conseguiu reproduzir o vídeo. Deseja abrir em um player externo? Nenhuma foto recente + IMAGENS + GIFS Nenhum GIF recente BUSCAR IMAGENS BUSCA GLOBAL BUSCAR GIFS Buscar na Internet Procurar GIFs + Toque para permitir o acesso à sua Câmera + Toque para permitir o acesso à sua Galeria Recortar imagem Realçar Luzes @@ -1972,11 +1996,13 @@ Quadrado Mostrar mídias em mensagens separadas Mostrar mídias em uma só mensagem + Enviar sem agrupar + Enviar sem compressão Verificação em Duas Etapas Verificação em Duas Etapas Configurar senha adicional - "Você pode configurar uma senha que será requisitada quando você entrar em um novo aparelho, além do código que você receberá por SMS. " + "Você pode configurar uma senha que será requisitada quando você entrar em um novo dispositivo, além do código que você receberá por SMS. " Sua senha Insira sua senha Por favor, digite sua senha para finalizar a transferência. @@ -2009,15 +2035,15 @@ As senhas não são iguais Cancelar a configuração Desistir de config. o email de recuperação - Para completar a Configuração da Verificação em Duas Etapas, verifique o seu email (verifique também a pasta de spam) e digite o código que nós te enviamos. - Para completar a configuração do email de recuperação, verifique %1$s (não se esqueça da pasta de spam) e digite o código que nós te enviamos. + Para completar a Configuração da Verificação em Duas Etapas, verifique o seu email (verifique também a pasta de spam) e digite o código que te enviamos. + Para completar a configuração do email de recuperação, verifique %1$s (não se esqueça da pasta de spam) e digite o código que te enviamos. A dica deve ser diferente da sua senha Endereço de email inválido. Por favor, verifique se você digitou corretamente e tente de novo. Desculpe Como você não indicou um email de recuperação quando configurou a sua senha, as únicas opções restantes são lembrar a senha ou apagar a sua conta. Redefinir Conta O código de recuperação foi enviado para o email fornecido:\n\n%1$s - Por favor, verifique o seu email e digite o código de 6 dígitos que nós enviamos. + Por favor, verifique o seu email e digite o código de 6 dígitos que te enviamos. Está tendo problemas para acessar seu email %1$s? Se você não puder acessar o seu email, as suas únicas opções são lembrar a senha ou apagar a sua conta. APAGAR MINHA CONTA @@ -2033,7 +2059,7 @@ Senha desativada Reenviar código O código de verificação foi enviado para o seu email. - Você ativou a Verificação em Duas Etapas.\nToda vez que você entrar na sua conta em um novo aparelho, será preciso digitar a senha que você configurar aqui. + Você ativou a Verificação em Duas Etapas.\nVocê precisará da senha que configurou aqui para fazer o login em sua conta do Telegram. Dados e Armazenamento Uso de disco e de rede @@ -2192,7 +2218,7 @@ APAGAR AGORA Voltar Inscrever-se - Rejeitar e Desativar + Negar e Apagar Próximo Você entrou no grupo via link de convite @@ -2263,9 +2289,9 @@ Número de telefone inválido. Por favor, verifique o número e tente de novo. Por favor, entre com sua conta do Telegram para usar o Telegram Passport. Este número de telefone está banido. - O código expirou. Por favor, identifique-se novamente. + Código expirado. Por favor, tente entrar novamente. Muitas tentativas. Por favor, tente novamente mais tarde. - Muitas tentativas, por favor tente novamente em %1$s + Muitas tentativas. Por favor, tente novamente em %1$s. Código inválido Desculpe, você apagou e recriou sua conta muitas vezes recentemente. Aguarde alguns dias antes de tentar novamente. Nome inválido @@ -2305,7 +2331,7 @@ Deseja mesmo apagar todos os seus rascunhos da nuvem? Compartilhar sua localização? Isso irá enviar sua localização atual ao bot. - O aplicativo foi impossibilitado de determinar sua localização atual. + O app não conseguiu determinar a sua localização atual. Escolher manualmente Esse bot gostaria de saber sua localização todas as vezes que você enviá-lo uma mensagem. Isso pode ser utilizado para providenciar resultados específicos de localização. Compartilhar seu número de telefone? @@ -2346,15 +2372,15 @@ Você gostaria de ativar a prévia de links estendida em Chats Secretos? Note que a pré-visualização é gerada nos servidores do Telegram. Os bots inline são fornecidos por desenvolvedores terceiros. Para o bot funcionar, os símbolos que você digita depois do nome de usuário do bot são enviados para o respectivo desenvolvedor. Desculpe, você não pode editar essa mensagem. - Por favor, permita que o Telegram receba SMS. Assim podemos inserir o código automaticamente para você. Permita o acesso às ligações ao Telegram, assim podemos automaticamente adicionar o código para você. + Por favor, permita que o Telegram receba chamadas e leia o registro de chamadas para que possamos inserir automaticamente seu código para você. + Por favor, permita que o Telegram leia o registro de chamadas para que possamos inserir automaticamente seu código para você. Por favor, permita que o Telegram receba chamadas. Assim podemos confirmar o seu número de telefone automaticamente. - Por favor, permita que o Telegram receba chamadas. Assim podemos confirmar o seu número de telefone automaticamente. Você não tem permissão para isso. Desculpe, você bloqueou este usuário ou bot e por isso não pode adicioná-lo a grupos. Desbloqueie para prosseguir. ENTRAR NO GRUPO Desculpe, você não pode adicionar o usuário como admin porque ele não está no grupo e você não tem permissão para adicioná-lo. - Você não pode adicionar esse usuário como admin porque ele está na lista de usuários removidos e você não pode desbaní-lo. + Você não pode adicionar esse usuário como admin porque ele está na lista de Usuários Removidos e você não pode desbaní-lo. Você não pode banir esse usuário porque ele é um admin do grupo e você não possui permissão para rebaixá-lo. Desculpe, os admins do grupo te restringiram do envio de stickers. Desculpe, os admins do grupo te restringiram do envio de mídias. @@ -2410,7 +2436,7 @@ Chamada do Telegram em andamento Encerrar chamada Outra chamada em andamento - Você está em uma chamada com **%1$s**. Gostaria de encerrar esta e iniciar uma nova com **%2$s**? + Você está em uma chamada com **%1$s**. Gostaria de desligar e iniciar uma nova com **%2$s**? Chamadas de voz Toque Você pode personalizar o toque usado quando esse contato te chamar no Telegram @@ -2446,7 +2472,7 @@ Ligar de Volta Ligar Novamente Padrão - Tem certeza de que deseja apagar essa entrada do registro de chamadas? + Deseja apagar essa entrada do registro de chamadas? Chamada do Telegram Auricular Alto-falante @@ -2459,7 +2485,7 @@ Incluir informação técnica Não revela o conteúdo do chat e nos ajudará a corrigir o problema mais rápido. Agradecemos por ajudar a tornar as chamadas do Telegram melhores. - Respondendo como %s + respondendo como %s Responder com Texto Essas respostas rápidas estarão disponíveis quando você responder a uma ligação com uma mensagem. Altere-as para dizer o que você quiser. Não posso falar agora. Está tudo bem? @@ -2496,12 +2522,12 @@ "%1$d contatos no Telegram " "%1$d contatos no Telegram " "%1$d contatos no Telegram " - Ei, eu estou usando o Telegram para conversar – assim como %1$d dos nossos contatos. Junte-se a nós! Baixe aqui: %2$s - Ei, eu estou usando o Telegram para conversar – assim como %1$d dos nossos contatos. Junte-se a nós! Baixe aqui: %2$s - Ei, eu estou usando o Telegram para conversar – assim como %1$d dos nossos contatos. Junte-se a nós! Baixe aqui: %2$s - Ei, eu estou usando o Telegram para conversar – assim como %1$d dos nossos contatos. Junte-se a nós! Baixe aqui: %2$s - Ei, eu estou usando o Telegram para conversar – assim como %1$d dos nossos contatos. Junte-se a nós! Baixe aqui: %2$s - Ei, eu estou usando o Telegram para conversar – assim como %1$d dos nossos contatos. Junte-se a nós! Baixe aqui: %2$s + Ei, tô usando o Telegram pra conversar – assim como %1$d dos nossos contatos. Vem com a gente! Baixe aqui: %2$s + Ei, tô usando o Telegram pra conversar – assim como %1$d dos nossos contatos. Vem com a gente! Baixe aqui: %2$s + Ei, tô usando o Telegram pra conversar – assim como %1$d dos nossos contatos. Vem com a gente! Baixe aqui: %2$s + Ei, tô usando o Telegram pra conversar – assim como %1$d dos nossos contatos. Vem com a gente! Baixe aqui: %2$s + Ei, tô usando o Telegram pra conversar – assim como %1$d dos nossos contatos. Vem com a gente! Baixe aqui: %2$s + Ei, tô usando o Telegram pra conversar – assim como %1$d dos nossos contatos. Vem com a gente! Baixe aqui: %2$s %1$d chats %1$d chat %1$d chats @@ -2815,6 +2841,24 @@ e %1$d outros e %1$d outros e %1$d outros + %1$d fotos selecionadas + %1$d foto selecionada + %1$d fotos selecionadas + %1$d fotos selecionadas + %1$d fotos selecionadas + %1$d fotos selecionadas + %1$d vídeos selecionados + %1$d vídeo selecionado + %1$d vídeos selecionados + %1$d vídeos selecionados + %1$d vídeos selecionados + %1$d vídeos selecionados + %1$d mídias selecionadas + %1$d mídia selecionada + %1$d mídias selecionadas + %1$d mídias selecionadas + %1$d mídias selecionadas + %1$d mídias selecionadas Grupo Canal diff --git a/TMessagesProj/src/main/res/values/strings.xml b/TMessagesProj/src/main/res/values/strings.xml index b43e7c4f7..301e64c54 100644 --- a/TMessagesProj/src/main/res/values/strings.xml +++ b/TMessagesProj/src/main/res/values/strings.xml @@ -388,6 +388,8 @@ Sign Messages Add names of the admins to the messages they post. Admin Rights + Custom title + A custom title that will be shown to all members instead of \'%1$s\'. What can this admin do? Change Channel Info Change Group Info @@ -501,6 +503,16 @@ Are you sure you want to unlink **%1$s** from this channel? DISCUSS channel + Slow Mode + Off + %1$ds + %1$dm + %1$dh + Choose how often members can send a message. + Members will be able to send only one message every %1$s. + Slow Mode is enabled. You can\'t send more than one message at once. + Slow Mode is enabled. You can\'t select more items. + Sorry, this text is too long to send as one message.\n\nSlow Mode is enabled. You can\'t send more than one message at once. New Poll Poll @@ -611,6 +623,8 @@ Add admins Ban users Add users + Title: %1$s + Title Pin messages All actions New exceptions @@ -622,6 +636,8 @@ Edited messages Pinned messages Leaving members + un1 set the slow mode timer to %1$s + un1 disabled the slow mode New Broadcast List Enter list name @@ -860,6 +876,9 @@ SCAM via Message doesn\'t exist + Slow Mode is enabled. You can send\nyour next message in %1$s + Tap for photo, hold for video + Send without sound %1$s set the self-destruct timer to %2$s You set the self-destruct timer to %1$s @@ -1113,6 +1132,7 @@ An error occurred. Stickers and Masks + Loop Animated Stickers Add Stickers ADD %1$s REMOVE %1$s @@ -1465,7 +1485,7 @@ Direct Share Show recent chats in Android share menu Emoji - Draw single big emoji + Large Emoji Use system default emoji Telegram for Android %1$s Debug Menu @@ -1922,12 +1942,16 @@ This video is not optimized for streaming. You may need to download it in full to play it. App was unable to play this video. Try to play it with external player? No recent photos + IMAGES + GIFS No recent GIFs FIND IMAGES WEB SEARCH FIND GIFS Search web - Search GIFs + Search Giphy + Tap to allow access to your Camera + Tap to allow access to your Gallery Crop image Enhance Highlights @@ -1972,6 +1996,8 @@ Square Show media as separate messages Group media into one message + Send without grouping + Send without compression Two-Step Verification Two-Step Verification @@ -2346,10 +2372,10 @@ Would you like to enable extended link previews in Secret Chats? Note that link previews are generated on Telegram servers. Please note that inline bots are provided by third-party developers. For the bot to work, the symbols you type after the bot\'s username are sent to the respective developer. Sorry, you can\'t edit this message. - Please allow Telegram to receive SMS so that we can automatically enter your code for you. Please allow Telegram to receive calls so that we can automatically enter your code for you. + Please allow Telegram to receive calls and read the call log so that we can automatically enter your code for you. + Please allow Telegram to read the call log so that we can automatically enter your code for you. Please allow Telegram to receive calls so that we can automatically confirm your phone number. - Please allow Telegram to receive calls so that we can automatically confirm your phone number. Sorry, you are not allowed to do this. Sorry, you can\'t add this user or bot to groups because you\'ve blocked them. Please unblock to proceed. JOIN GROUP @@ -2815,6 +2841,24 @@ and %1$d others and %1$d others and %1$d others + %1$d photos selected + %1$d photo selected + %1$d photos selected + %1$d photos selected + %1$d photos selected + %1$d photos selected + %1$d videos selected + %1$d video selected + %1$d videos selected + %1$d videos selected + %1$d videos selected + %1$d videos selected + %1$d media selected + %1$d media selected + %1$d media selected + %1$d media selected + %1$d media selected + %1$d media selected Group Channel diff --git a/TMessagesProj/src/main/res/values/styles.xml b/TMessagesProj/src/main/res/values/styles.xml index 817261e17..a1f892932 100644 --- a/TMessagesProj/src/main/res/values/styles.xml +++ b/TMessagesProj/src/main/res/values/styles.xml @@ -84,6 +84,11 @@ @anim/popup_context_in + +