mirror of
https://github.com/MGislv/NekoX.git
synced 2024-07-02 10:33:36 +00:00
Update to 3.7.0
This commit is contained in:
parent
6154c891bd
commit
a7513b3ba1
|
@ -1,6 +1,6 @@
|
||||||
## Telegram messenger for Android
|
## Telegram messenger for Android
|
||||||
|
|
||||||
[Telegram](http://telegram.org) is a messaging app with a focus on speed and security. It’s superfast, simple and free.
|
[Telegram](https://telegram.org) is a messaging app with a focus on speed and security. It’s superfast, simple and free.
|
||||||
This repo contains the official source code for [Telegram App for Android](https://play.google.com/store/apps/details?id=org.telegram.messenger).
|
This repo contains the official source code for [Telegram App for Android](https://play.google.com/store/apps/details?id=org.telegram.messenger).
|
||||||
|
|
||||||
##Creating your Telegram Application
|
##Creating your Telegram Application
|
||||||
|
@ -16,9 +16,9 @@ There are several things we require from **all developers** for the moment.
|
||||||
|
|
||||||
### API, Protocol documentation
|
### API, Protocol documentation
|
||||||
|
|
||||||
Telegram API manuals: http://core.telegram.org/api
|
Telegram API manuals: https://core.telegram.org/api
|
||||||
|
|
||||||
MTproto protocol manuals: http://core.telegram.org/mtproto
|
MTproto protocol manuals: https://core.telegram.org/mtproto
|
||||||
|
|
||||||
### Usage
|
### Usage
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@ repositories {
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
compile 'com.android.support:support-v4:23.1.+'
|
compile 'com.android.support:support-v4:23.2.1'
|
||||||
compile "com.google.android.gms:play-services-gcm:8.4.0"
|
compile "com.google.android.gms:play-services-gcm:8.4.0"
|
||||||
compile "com.google.android.gms:play-services-maps:8.4.0"
|
compile "com.google.android.gms:play-services-maps:8.4.0"
|
||||||
compile 'net.hockeyapp.android:HockeySDK:3.6.+'
|
compile 'net.hockeyapp.android:HockeySDK:3.6.+'
|
||||||
|
@ -63,6 +63,8 @@ android {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
defaultConfig.versionCode = 767
|
||||||
|
|
||||||
sourceSets.main {
|
sourceSets.main {
|
||||||
jniLibs.srcDir 'libs'
|
jniLibs.srcDir 'libs'
|
||||||
jni.srcDirs = [] //disable automatic ndk-build call
|
jni.srcDirs = [] //disable automatic ndk-build call
|
||||||
|
@ -80,10 +82,38 @@ android {
|
||||||
manifest.srcFile 'config/foss/AndroidManifest.xml'
|
manifest.srcFile 'config/foss/AndroidManifest.xml'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
productFlavors {
|
||||||
|
x86 {
|
||||||
|
ndk {
|
||||||
|
abiFilter "x86"
|
||||||
|
}
|
||||||
|
versionCode = 2
|
||||||
|
}
|
||||||
|
arm {
|
||||||
|
ndk {
|
||||||
|
abiFilter "armeabi"
|
||||||
|
}
|
||||||
|
versionCode = 0
|
||||||
|
}
|
||||||
|
armv7 {
|
||||||
|
ndk {
|
||||||
|
abiFilter "armeabi-v7a"
|
||||||
|
}
|
||||||
|
versionCode = 1
|
||||||
|
}
|
||||||
|
fat {
|
||||||
|
versionCode = 3
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
applicationVariants.all { variant ->
|
||||||
|
def abiVersion = variant.productFlavors.get(0).versionCode
|
||||||
|
variant.mergedFlavor.versionCode = defaultConfig.versionCode * 10 + abiVersion;
|
||||||
|
}
|
||||||
|
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
minSdkVersion 9
|
minSdkVersion 9
|
||||||
targetSdkVersion 23
|
targetSdkVersion 23
|
||||||
versionCode 755
|
versionName "3.7.0"
|
||||||
versionName "3.6.1"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -235,7 +235,7 @@ include $(BUILD_STATIC_LIBRARY)
|
||||||
include $(CLEAR_VARS)
|
include $(CLEAR_VARS)
|
||||||
LOCAL_PRELINK_MODULE := false
|
LOCAL_PRELINK_MODULE := false
|
||||||
|
|
||||||
LOCAL_MODULE := tmessages.19
|
LOCAL_MODULE := tmessages.20
|
||||||
LOCAL_CFLAGS := -w -std=c11 -Os -DNULL=0 -DSOCKLEN_T=socklen_t -DLOCALE_NOT_USED -D_LARGEFILE_SOURCE=1 -D_FILE_OFFSET_BITS=64
|
LOCAL_CFLAGS := -w -std=c11 -Os -DNULL=0 -DSOCKLEN_T=socklen_t -DLOCALE_NOT_USED -D_LARGEFILE_SOURCE=1 -D_FILE_OFFSET_BITS=64
|
||||||
LOCAL_CFLAGS += -Drestrict='' -D__EMX__ -DOPUS_BUILD -DFIXED_POINT -DUSE_ALLOCA -DHAVE_LRINT -DHAVE_LRINTF -fno-math-errno
|
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_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
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
APP_PLATFORM := android-9
|
APP_PLATFORM := android-9
|
||||||
APP_ABI := armeabi armeabi-v7a x86
|
APP_ABI := armeabi armeabi-v7a x86
|
||||||
NDK_TOOLCHAIN_VERSION := 4.8
|
NDK_TOOLCHAIN_VERSION := 4.9
|
||||||
APP_STL := gnustl_static
|
APP_STL := gnustl_static
|
|
@ -671,8 +671,7 @@ JNIEXPORT int Java_org_telegram_messenger_MediaController_isOpusFile(JNIEnv *env
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void set_bits(uint8_t *bytes, int32_t bitOffset, int32_t numBits, int32_t value) {
|
static inline void set_bits(uint8_t *bytes, int32_t bitOffset, int32_t value) {
|
||||||
numBits = (unsigned int) (2 << (numBits - 1)) - 1;
|
|
||||||
bytes += bitOffset / 8;
|
bytes += bitOffset / 8;
|
||||||
bitOffset %= 8;
|
bitOffset %= 8;
|
||||||
*((int32_t *) bytes) |= (value << bitOffset);
|
*((int32_t *) bytes) |= (value << bitOffset);
|
||||||
|
@ -727,7 +726,7 @@ JNIEXPORT jbyteArray Java_org_telegram_messenger_MediaController_getWaveform2(JN
|
||||||
|
|
||||||
for (int i = 0; i < resultSamples; i++) {
|
for (int i = 0; i < resultSamples; i++) {
|
||||||
int32_t value = min(31, abs((int32_t) samples[i]) * 31 / peak);
|
int32_t value = min(31, abs((int32_t) samples[i]) * 31 / peak);
|
||||||
set_bits(bytes, i * 5, 5, value & 31);
|
set_bits(bytes, i * 5, value & 31);
|
||||||
}
|
}
|
||||||
|
|
||||||
(*env)->ReleaseByteArrayElements(env, result, bytes, JNI_COMMIT);
|
(*env)->ReleaseByteArrayElements(env, result, bytes, JNI_COMMIT);
|
||||||
|
@ -805,7 +804,7 @@ JNIEXPORT jbyteArray Java_org_telegram_messenger_MediaController_getWaveform(JNI
|
||||||
|
|
||||||
for (int i = 0; i < resultSamples; i++) {
|
for (int i = 0; i < resultSamples; i++) {
|
||||||
int32_t value = min(31, abs((int32_t) samples[i]) * 31 / peak);
|
int32_t value = min(31, abs((int32_t) samples[i]) * 31 / peak);
|
||||||
set_bits(bytes, i * 5, 5, value & 31);
|
set_bits(bytes, i * 5, value & 31);
|
||||||
}
|
}
|
||||||
|
|
||||||
(*env)->ReleaseByteArrayElements(env, result, bytes, JNI_COMMIT);
|
(*env)->ReleaseByteArrayElements(env, result, bytes, JNI_COMMIT);
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <openssl/aes.h>
|
#include <openssl/aes.h>
|
||||||
|
#include <unistd.h>
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
#include "sqlite.h"
|
#include "sqlite.h"
|
||||||
#include "image.h"
|
#include "image.h"
|
||||||
|
|
|
@ -8,8 +8,8 @@ jint sqliteOnJNILoad(JavaVM *vm, void *reserved, JNIEnv *env) {
|
||||||
return JNI_VERSION_1_6;
|
return JNI_VERSION_1_6;
|
||||||
}
|
}
|
||||||
|
|
||||||
int Java_org_telegram_SQLite_SQLitePreparedStatement_step(JNIEnv* env, jobject object, int statementHandle) {
|
int Java_org_telegram_SQLite_SQLitePreparedStatement_step(JNIEnv *env, jobject object, int statementHandle) {
|
||||||
sqlite3_stmt *handle = (sqlite3_stmt *)statementHandle;
|
sqlite3_stmt *handle = (sqlite3_stmt *) statementHandle;
|
||||||
|
|
||||||
int errcode = sqlite3_step(handle);
|
int errcode = sqlite3_step(handle);
|
||||||
if (errcode == SQLITE_ROW) {
|
if (errcode == SQLITE_ROW) {
|
||||||
|
@ -23,7 +23,7 @@ int Java_org_telegram_SQLite_SQLitePreparedStatement_step(JNIEnv* env, jobject o
|
||||||
}
|
}
|
||||||
|
|
||||||
int Java_org_telegram_SQLite_SQLitePreparedStatement_prepare(JNIEnv *env, jobject object, int sqliteHandle, jstring sql) {
|
int Java_org_telegram_SQLite_SQLitePreparedStatement_prepare(JNIEnv *env, jobject object, int sqliteHandle, jstring sql) {
|
||||||
sqlite3* handle = (sqlite3 *)sqliteHandle;
|
sqlite3 *handle = (sqlite3 *) sqliteHandle;
|
||||||
|
|
||||||
char const *sqlStr = (*env)->GetStringUTFChars(env, sql, 0);
|
char const *sqlStr = (*env)->GetStringUTFChars(env, sql, 0);
|
||||||
|
|
||||||
|
@ -41,11 +41,11 @@ int Java_org_telegram_SQLite_SQLitePreparedStatement_prepare(JNIEnv *env, jobjec
|
||||||
(*env)->ReleaseStringUTFChars(env, sql, sqlStr);
|
(*env)->ReleaseStringUTFChars(env, sql, sqlStr);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (int)stmt_handle;
|
return (int) stmt_handle;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Java_org_telegram_SQLite_SQLitePreparedStatement_reset(JNIEnv *env, jobject object, int statementHandle) {
|
void Java_org_telegram_SQLite_SQLitePreparedStatement_reset(JNIEnv *env, jobject object, int statementHandle) {
|
||||||
sqlite3_stmt *handle = (sqlite3_stmt *)statementHandle;
|
sqlite3_stmt *handle = (sqlite3_stmt *) statementHandle;
|
||||||
|
|
||||||
int errcode = sqlite3_reset(handle);
|
int errcode = sqlite3_reset(handle);
|
||||||
if (SQLITE_OK != errcode) {
|
if (SQLITE_OK != errcode) {
|
||||||
|
@ -54,16 +54,11 @@ void Java_org_telegram_SQLite_SQLitePreparedStatement_reset(JNIEnv *env, jobject
|
||||||
}
|
}
|
||||||
|
|
||||||
void Java_org_telegram_SQLite_SQLitePreparedStatement_finalize(JNIEnv *env, jobject object, int statementHandle) {
|
void Java_org_telegram_SQLite_SQLitePreparedStatement_finalize(JNIEnv *env, jobject object, int statementHandle) {
|
||||||
sqlite3_stmt *handle = (sqlite3_stmt *)statementHandle;
|
sqlite3_finalize((sqlite3_stmt *) statementHandle);
|
||||||
|
|
||||||
int errcode = sqlite3_finalize (handle);
|
|
||||||
if (SQLITE_OK != errcode) {
|
|
||||||
throw_sqlite3_exception(env, sqlite3_db_handle(handle), errcode);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Java_org_telegram_SQLite_SQLitePreparedStatement_bindByteBuffer(JNIEnv *env, jobject object, int statementHandle, int index, jobject value, int length) {
|
void Java_org_telegram_SQLite_SQLitePreparedStatement_bindByteBuffer(JNIEnv *env, jobject object, int statementHandle, int index, jobject value, int length) {
|
||||||
sqlite3_stmt *handle = (sqlite3_stmt *)statementHandle;
|
sqlite3_stmt *handle = (sqlite3_stmt *) statementHandle;
|
||||||
jbyte *buf = (*env)->GetDirectBufferAddress(env, value);
|
jbyte *buf = (*env)->GetDirectBufferAddress(env, value);
|
||||||
|
|
||||||
int errcode = sqlite3_bind_blob(handle, index, buf, length, SQLITE_STATIC);
|
int errcode = sqlite3_bind_blob(handle, index, buf, length, SQLITE_STATIC);
|
||||||
|
@ -73,7 +68,7 @@ void Java_org_telegram_SQLite_SQLitePreparedStatement_bindByteBuffer(JNIEnv *env
|
||||||
}
|
}
|
||||||
|
|
||||||
void Java_org_telegram_SQLite_SQLitePreparedStatement_bindString(JNIEnv *env, jobject object, int statementHandle, int index, jstring value) {
|
void Java_org_telegram_SQLite_SQLitePreparedStatement_bindString(JNIEnv *env, jobject object, int statementHandle, int index, jstring value) {
|
||||||
sqlite3_stmt *handle = (sqlite3_stmt*)statementHandle;
|
sqlite3_stmt *handle = (sqlite3_stmt *) statementHandle;
|
||||||
|
|
||||||
char const *valueStr = (*env)->GetStringUTFChars(env, value, 0);
|
char const *valueStr = (*env)->GetStringUTFChars(env, value, 0);
|
||||||
|
|
||||||
|
@ -88,7 +83,7 @@ void Java_org_telegram_SQLite_SQLitePreparedStatement_bindString(JNIEnv *env, jo
|
||||||
}
|
}
|
||||||
|
|
||||||
void Java_org_telegram_SQLite_SQLitePreparedStatement_bindInt(JNIEnv *env, jobject object, int statementHandle, int index, int value) {
|
void Java_org_telegram_SQLite_SQLitePreparedStatement_bindInt(JNIEnv *env, jobject object, int statementHandle, int index, int value) {
|
||||||
sqlite3_stmt *handle = (sqlite3_stmt*)statementHandle;
|
sqlite3_stmt *handle = (sqlite3_stmt *) statementHandle;
|
||||||
|
|
||||||
int errcode = sqlite3_bind_int(handle, index, value);
|
int errcode = sqlite3_bind_int(handle, index, value);
|
||||||
if (SQLITE_OK != errcode) {
|
if (SQLITE_OK != errcode) {
|
||||||
|
@ -97,7 +92,7 @@ void Java_org_telegram_SQLite_SQLitePreparedStatement_bindInt(JNIEnv *env, jobje
|
||||||
}
|
}
|
||||||
|
|
||||||
void Java_org_telegram_SQLite_SQLitePreparedStatement_bindLong(JNIEnv *env, jobject object, int statementHandle, int index, long long value) {
|
void Java_org_telegram_SQLite_SQLitePreparedStatement_bindLong(JNIEnv *env, jobject object, int statementHandle, int index, long long value) {
|
||||||
sqlite3_stmt *handle = (sqlite3_stmt*)statementHandle;
|
sqlite3_stmt *handle = (sqlite3_stmt *) statementHandle;
|
||||||
|
|
||||||
int errcode = sqlite3_bind_int64(handle, index, value);
|
int errcode = sqlite3_bind_int64(handle, index, value);
|
||||||
if (SQLITE_OK != errcode) {
|
if (SQLITE_OK != errcode) {
|
||||||
|
@ -105,8 +100,8 @@ void Java_org_telegram_SQLite_SQLitePreparedStatement_bindLong(JNIEnv *env, jobj
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Java_org_telegram_SQLite_SQLitePreparedStatement_bindDouble(JNIEnv* env, jobject object, int statementHandle, int index, double value) {
|
void Java_org_telegram_SQLite_SQLitePreparedStatement_bindDouble(JNIEnv *env, jobject object, int statementHandle, int index, double value) {
|
||||||
sqlite3_stmt *handle = (sqlite3_stmt*)statementHandle;
|
sqlite3_stmt *handle = (sqlite3_stmt *) statementHandle;
|
||||||
|
|
||||||
int errcode = sqlite3_bind_double(handle, index, value);
|
int errcode = sqlite3_bind_double(handle, index, value);
|
||||||
if (SQLITE_OK != errcode) {
|
if (SQLITE_OK != errcode) {
|
||||||
|
@ -114,8 +109,8 @@ void Java_org_telegram_SQLite_SQLitePreparedStatement_bindDouble(JNIEnv* env, jo
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Java_org_telegram_SQLite_SQLitePreparedStatement_bindNull(JNIEnv* env, jobject object, int statementHandle, int index) {
|
void Java_org_telegram_SQLite_SQLitePreparedStatement_bindNull(JNIEnv *env, jobject object, int statementHandle, int index) {
|
||||||
sqlite3_stmt *handle = (sqlite3_stmt*)statementHandle;
|
sqlite3_stmt *handle = (sqlite3_stmt *) statementHandle;
|
||||||
|
|
||||||
int errcode = sqlite3_bind_null(handle, index);
|
int errcode = sqlite3_bind_null(handle, index);
|
||||||
if (SQLITE_OK != errcode) {
|
if (SQLITE_OK != errcode) {
|
||||||
|
|
|
@ -57,7 +57,7 @@ void Connection::suspendConnection() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Connection::onReceivedData(NativeByteBuffer *buffer) {
|
void Connection::onReceivedData(NativeByteBuffer *buffer) {
|
||||||
//AES_ctr128_encrypt(buffer->bytes(), buffer->bytes(), buffer->limit(), &decryptKey, decryptIv, decryptCount, &decryptNum);
|
AES_ctr128_encrypt(buffer->bytes(), buffer->bytes(), buffer->limit(), &decryptKey, decryptIv, decryptCount, &decryptNum);
|
||||||
|
|
||||||
failedConnectionCount = 0;
|
failedConnectionCount = 0;
|
||||||
|
|
||||||
|
@ -323,11 +323,11 @@ void Connection::sendData(NativeByteBuffer *buff, bool reportAck) {
|
||||||
uint32_t val = (bytes[3] << 24) | (bytes[2] << 16) | (bytes[1] << 8) | (bytes[0]);
|
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]);
|
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 && val2 != 0x00000000) {
|
if (bytes[0] != 0xef && val != 0x44414548 && val != 0x54534f50 && val != 0x20544547 && val != 0x4954504f && val != 0xeeeeeeee && val2 != 0x00000000) {
|
||||||
//bytes[56] = bytes[57] = bytes[58] = bytes[59] = 0xef;
|
bytes[56] = bytes[57] = bytes[58] = bytes[59] = 0xef;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/*for (int a = 0; a < 48; a++) {
|
for (int a = 0; a < 48; a++) {
|
||||||
temp[a] = bytes[55 - a];
|
temp[a] = bytes[55 - a];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -348,7 +348,7 @@ void Connection::sendData(NativeByteBuffer *buff, bool reportAck) {
|
||||||
memcpy(decryptIv, temp + 32, 16);
|
memcpy(decryptIv, temp + 32, 16);
|
||||||
|
|
||||||
AES_ctr128_encrypt(bytes, temp, 64, &encryptKey, encryptIv, encryptCount, &encryptNum);
|
AES_ctr128_encrypt(bytes, temp, 64, &encryptKey, encryptIv, encryptCount, &encryptNum);
|
||||||
memcpy(bytes + 56, temp + 56, 8);*/
|
memcpy(bytes + 56, temp + 56, 8);
|
||||||
|
|
||||||
firstPacketSent = true;
|
firstPacketSent = true;
|
||||||
}
|
}
|
||||||
|
@ -358,7 +358,7 @@ void Connection::sendData(NativeByteBuffer *buff, bool reportAck) {
|
||||||
}
|
}
|
||||||
buffer->writeByte((uint8_t) packetLength);
|
buffer->writeByte((uint8_t) packetLength);
|
||||||
bytes += (buffer->limit() - 1);
|
bytes += (buffer->limit() - 1);
|
||||||
//AES_ctr128_encrypt(bytes, bytes, 1, &encryptKey, encryptIv, encryptCount, &encryptNum);
|
AES_ctr128_encrypt(bytes, bytes, 1, &encryptKey, encryptIv, encryptCount, &encryptNum);
|
||||||
} else {
|
} else {
|
||||||
packetLength = (packetLength << 8) + 0x7f;
|
packetLength = (packetLength << 8) + 0x7f;
|
||||||
if (reportAck) {
|
if (reportAck) {
|
||||||
|
@ -366,13 +366,13 @@ void Connection::sendData(NativeByteBuffer *buff, bool reportAck) {
|
||||||
}
|
}
|
||||||
buffer->writeInt32(packetLength);
|
buffer->writeInt32(packetLength);
|
||||||
bytes += (buffer->limit() - 4);
|
bytes += (buffer->limit() - 4);
|
||||||
//AES_ctr128_encrypt(bytes, bytes, 4, &encryptKey, encryptIv, encryptCount, &encryptNum);
|
AES_ctr128_encrypt(bytes, bytes, 4, &encryptKey, encryptIv, encryptCount, &encryptNum);
|
||||||
}
|
}
|
||||||
|
|
||||||
buffer->rewind();
|
buffer->rewind();
|
||||||
writeBuffer(buffer);
|
writeBuffer(buffer);
|
||||||
buff->rewind();
|
buff->rewind();
|
||||||
//AES_ctr128_encrypt(buff->bytes(), buff->bytes(), buff->limit(), &encryptKey, encryptIv, encryptCount, &encryptNum);
|
AES_ctr128_encrypt(buff->bytes(), buff->bytes(), buff->limit(), &encryptKey, encryptIv, encryptCount, &encryptNum);
|
||||||
writeBuffer(buff);
|
writeBuffer(buff);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,7 @@
|
||||||
|
|
||||||
#define USE_DEBUG_SESSION false
|
#define USE_DEBUG_SESSION false
|
||||||
#define READ_BUFFER_SIZE 1024 * 128
|
#define READ_BUFFER_SIZE 1024 * 128
|
||||||
//#define DEBUG_VERSION
|
#define DEBUG_VERSION
|
||||||
#define DEFAULT_DATACENTER_ID INT_MAX
|
#define DEFAULT_DATACENTER_ID INT_MAX
|
||||||
#define DC_UPDATE_TIME 60 * 60
|
#define DC_UPDATE_TIME 60 * 60
|
||||||
#define DOWNLOAD_CONNECTIONS_COUNT 2
|
#define DOWNLOAD_CONNECTIONS_COUNT 2
|
||||||
|
|
|
@ -99,6 +99,8 @@
|
||||||
<category android:name="android.intent.category.BROWSABLE" />
|
<category android:name="android.intent.category.BROWSABLE" />
|
||||||
<data android:host="telegram.me" android:scheme="http" />
|
<data android:host="telegram.me" android:scheme="http" />
|
||||||
<data android:host="telegram.me" android:scheme="https" />
|
<data android:host="telegram.me" android:scheme="https" />
|
||||||
|
<data android:host="telegram.dog" android:scheme="http" />
|
||||||
|
<data android:host="telegram.dog" android:scheme="https" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
<intent-filter android:icon="@drawable/ic_launcher" android:priority="1">
|
<intent-filter android:icon="@drawable/ic_launcher" android:priority="1">
|
||||||
<action android:name="android.intent.action.VIEW" />
|
<action android:name="android.intent.action.VIEW" />
|
||||||
|
|
|
@ -11,6 +11,7 @@ package org.telegram.messenger;
|
||||||
import android.annotation.SuppressLint;
|
import android.annotation.SuppressLint;
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.app.AlertDialog;
|
import android.app.AlertDialog;
|
||||||
|
import android.app.PendingIntent;
|
||||||
import android.content.ContentUris;
|
import android.content.ContentUris;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.DialogInterface;
|
import android.content.DialogInterface;
|
||||||
|
@ -19,6 +20,7 @@ import android.content.pm.ActivityInfo;
|
||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
import android.content.res.Configuration;
|
import android.content.res.Configuration;
|
||||||
import android.database.Cursor;
|
import android.database.Cursor;
|
||||||
|
import android.graphics.BitmapFactory;
|
||||||
import android.graphics.Color;
|
import android.graphics.Color;
|
||||||
import android.graphics.Point;
|
import android.graphics.Point;
|
||||||
import android.graphics.Rect;
|
import android.graphics.Rect;
|
||||||
|
@ -26,6 +28,7 @@ import android.graphics.Typeface;
|
||||||
import android.graphics.drawable.Drawable;
|
import android.graphics.drawable.Drawable;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
|
import android.os.Bundle;
|
||||||
import android.os.Environment;
|
import android.os.Environment;
|
||||||
import android.os.Parcelable;
|
import android.os.Parcelable;
|
||||||
import android.provider.Browser;
|
import android.provider.Browser;
|
||||||
|
@ -84,7 +87,9 @@ public class AndroidUtilities {
|
||||||
private static final Hashtable<String, Typeface> typefaceCache = new Hashtable<>();
|
private static final Hashtable<String, Typeface> typefaceCache = new Hashtable<>();
|
||||||
private static int prevOrientation = -10;
|
private static int prevOrientation = -10;
|
||||||
private static boolean waitingForSms = false;
|
private static boolean waitingForSms = false;
|
||||||
|
private static boolean waitingForCall = false;
|
||||||
private static final Object smsLock = new Object();
|
private static final Object smsLock = new Object();
|
||||||
|
private static final Object callLock = new Object();
|
||||||
|
|
||||||
public static int statusBarHeight = 0;
|
public static int statusBarHeight = 0;
|
||||||
public static float density = 1;
|
public static float density = 1;
|
||||||
|
@ -240,6 +245,20 @@ public class AndroidUtilities {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static boolean isWaitingForCall() {
|
||||||
|
boolean value;
|
||||||
|
synchronized (callLock) {
|
||||||
|
value = waitingForCall;
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void setWaitingForCall(boolean value) {
|
||||||
|
synchronized (callLock) {
|
||||||
|
waitingForCall = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static void showKeyboard(View view) {
|
public static void showKeyboard(View view) {
|
||||||
if (view == null) {
|
if (view == null) {
|
||||||
return;
|
return;
|
||||||
|
@ -422,11 +441,28 @@ public class AndroidUtilities {
|
||||||
if (context == null || uri == null) {
|
if (context == null || uri == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
|
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
|
||||||
intent.putExtra("android.support.customtabs.extra.SESSION", (Parcelable) null);
|
if (MediaController.getInstance().canCustomTabs()) {
|
||||||
intent.putExtra("android.support.customtabs.extra.TOOLBAR_COLOR", 0xff54759e);
|
intent.putExtra("android.support.customtabs.extra.SESSION", (Parcelable) null);
|
||||||
intent.putExtra("android.support.customtabs.extra.TITLE_VISIBILITY", 1);
|
intent.putExtra("android.support.customtabs.extra.TOOLBAR_COLOR", 0xff54759e);
|
||||||
|
intent.putExtra("android.support.customtabs.extra.TITLE_VISIBILITY", 1);
|
||||||
|
|
||||||
|
Intent actionIntent = new Intent(Intent.ACTION_SEND);
|
||||||
|
actionIntent.setType("text/plain");
|
||||||
|
actionIntent.putExtra(Intent.EXTRA_TEXT, uri.toString());
|
||||||
|
actionIntent.putExtra(Intent.EXTRA_SUBJECT, "");
|
||||||
|
PendingIntent pendingIntent = PendingIntent.getActivity(ApplicationLoader.applicationContext, 0, actionIntent, PendingIntent.FLAG_ONE_SHOT);
|
||||||
|
|
||||||
|
Bundle bundle = new Bundle();
|
||||||
|
bundle.putInt("android.support.customtabs.customaction.ID", 0);
|
||||||
|
bundle.putParcelable("android.support.customtabs.customaction.ICON", BitmapFactory.decodeResource(context.getResources(), R.drawable.abc_ic_menu_share_mtrl_alpha));
|
||||||
|
bundle.putString("android.support.customtabs.customaction.DESCRIPTION", LocaleController.getString("ShareFile", R.string.ShareFile));
|
||||||
|
bundle.putParcelable("android.support.customtabs.customaction.PENDING_INTENT", pendingIntent);
|
||||||
|
intent.putExtra("android.support.customtabs.extra.ACTION_BUTTON_BUNDLE", bundle);
|
||||||
|
intent.putExtra("android.support.customtabs.extra.TINT_ACTION_BUTTON", false);
|
||||||
|
}
|
||||||
intent.putExtra(Browser.EXTRA_APPLICATION_ID, context.getPackageName());
|
intent.putExtra(Browser.EXTRA_APPLICATION_ID, context.getPackageName());
|
||||||
context.startActivity(intent);
|
context.startActivity(intent);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
|
@ -917,7 +953,11 @@ public class AndroidUtilities {
|
||||||
cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs, null);
|
cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs, null);
|
||||||
if (cursor != null && cursor.moveToFirst()) {
|
if (cursor != null && cursor.moveToFirst()) {
|
||||||
final int column_index = cursor.getColumnIndexOrThrow(column);
|
final int column_index = cursor.getColumnIndexOrThrow(column);
|
||||||
return cursor.getString(column_index);
|
String value = cursor.getString(column_index);
|
||||||
|
if (value.startsWith("content://") || !value.startsWith("/") && !value.startsWith("file://")) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return value;
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
FileLog.e("tmessages", e);
|
FileLog.e("tmessages", e);
|
||||||
|
|
|
@ -37,6 +37,8 @@ import org.telegram.ui.Components.ForegroundDetector;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.RandomAccessFile;
|
import java.io.RandomAccessFile;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Locale;
|
||||||
|
|
||||||
public class ApplicationLoader extends Application {
|
public class ApplicationLoader extends Application {
|
||||||
|
|
||||||
|
|
|
@ -10,8 +10,8 @@ package org.telegram.messenger;
|
||||||
|
|
||||||
public class BuildVars {
|
public class BuildVars {
|
||||||
public static boolean DEBUG_VERSION = false;
|
public static boolean DEBUG_VERSION = false;
|
||||||
public static int BUILD_VERSION = 753;
|
public static int BUILD_VERSION = 767;
|
||||||
public static String BUILD_VERSION_STRING = "3.6";
|
public static String BUILD_VERSION_STRING = "3.7";
|
||||||
public static int APP_ID = 0; //obtain your own APP_ID at https://core.telegram.org/api/obtaining_api_id
|
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 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";
|
public static String HOCKEY_APP_HASH = "your-hockeyapp-api-key-here";
|
||||||
|
|
|
@ -11,20 +11,24 @@ package org.telegram.messenger;
|
||||||
import android.content.BroadcastReceiver;
|
import android.content.BroadcastReceiver;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
|
import android.telephony.PhoneStateListener;
|
||||||
|
import android.telephony.TelephonyManager;
|
||||||
|
|
||||||
|
import org.telegram.PhoneFormat.PhoneFormat;
|
||||||
|
|
||||||
public class CallReceiver extends BroadcastReceiver {
|
public class CallReceiver extends BroadcastReceiver {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onReceive(final Context context, Intent intent) {
|
public void onReceive(final Context context, Intent intent) {
|
||||||
/*TelephonyManager telephony = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
|
TelephonyManager telephony = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
|
||||||
telephony.listen(new PhoneStateListener() {
|
telephony.listen(new PhoneStateListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onCallStateChanged(int state, String incomingNumber) {
|
public void onCallStateChanged(int state, String incomingNumber) {
|
||||||
super.onCallStateChanged(state, incomingNumber);
|
super.onCallStateChanged(state, incomingNumber);
|
||||||
if (state == 1 && incomingNumber != null && incomingNumber.length() > 0) {
|
if (state == 1 && incomingNumber != null && incomingNumber.length() > 0) {
|
||||||
NotificationCenter.getInstance().postNotificationName(NotificationCenter.didReceiveCall, incomingNumber);
|
NotificationCenter.getInstance().postNotificationName(NotificationCenter.didReceiveCall, PhoneFormat.stripExceptNumbers(incomingNumber));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, PhoneStateListener.LISTEN_CALL_STATE);*/
|
}, PhoneStateListener.LISTEN_CALL_STATE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -265,9 +265,9 @@ public class Emoji {
|
||||||
b = getBounds();
|
b = getBounds();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!canvas.quickReject(b.left, b.top, b.right, b.bottom, Canvas.EdgeType.AA)) {
|
//if (!canvas.quickReject(b.left, b.top, b.right, b.bottom, Canvas.EdgeType.AA)) {
|
||||||
canvas.drawBitmap(emojiBmp[info.page][info.page2], info.rect, b, paint);
|
canvas.drawBitmap(emojiBmp[info.page][info.page2], info.rect, b, paint);
|
||||||
}
|
//}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -550,13 +550,17 @@ public class FileLoader {
|
||||||
return getAttachFileName(sizeFull);
|
return getAttachFileName(sizeFull);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (message.media instanceof TLRPC.TL_messageMediaWebPage && message.media.webpage.photo != null) {
|
} else if (message.media instanceof TLRPC.TL_messageMediaWebPage) {
|
||||||
ArrayList<TLRPC.PhotoSize> sizes = message.media.webpage.photo.sizes;
|
if (message.media.webpage.photo != null) {
|
||||||
if (sizes.size() > 0) {
|
ArrayList<TLRPC.PhotoSize> sizes = message.media.webpage.photo.sizes;
|
||||||
TLRPC.PhotoSize sizeFull = getClosestPhotoSizeWithSize(sizes, AndroidUtilities.getPhotoSize());
|
if (sizes.size() > 0) {
|
||||||
if (sizeFull != null) {
|
TLRPC.PhotoSize sizeFull = getClosestPhotoSizeWithSize(sizes, AndroidUtilities.getPhotoSize());
|
||||||
return getAttachFileName(sizeFull);
|
if (sizeFull != null) {
|
||||||
|
return getAttachFileName(sizeFull);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
} else if (message.media.webpage.document != null) {
|
||||||
|
return getAttachFileName(message.media.webpage.document);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -588,13 +592,17 @@ public class FileLoader {
|
||||||
return getPathToAttach(sizeFull);
|
return getPathToAttach(sizeFull);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (message.media instanceof TLRPC.TL_messageMediaWebPage && message.media.webpage.photo != null) {
|
} else if (message.media instanceof TLRPC.TL_messageMediaWebPage) {
|
||||||
ArrayList<TLRPC.PhotoSize> sizes = message.media.webpage.photo.sizes;
|
if (message.media.webpage.photo != null) {
|
||||||
if (sizes.size() > 0) {
|
ArrayList<TLRPC.PhotoSize> sizes = message.media.webpage.photo.sizes;
|
||||||
TLRPC.PhotoSize sizeFull = getClosestPhotoSizeWithSize(sizes, AndroidUtilities.getPhotoSize());
|
if (sizes.size() > 0) {
|
||||||
if (sizeFull != null) {
|
TLRPC.PhotoSize sizeFull = getClosestPhotoSizeWithSize(sizes, AndroidUtilities.getPhotoSize());
|
||||||
return getPathToAttach(sizeFull);
|
if (sizeFull != null) {
|
||||||
|
return getPathToAttach(sizeFull);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
} else if (message.media.webpage.document != null) {
|
||||||
|
return getPathToAttach(message.media.webpage.document);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -704,6 +712,23 @@ public class FileLoader {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static String getDocumentExtension(TLRPC.Document document) {
|
||||||
|
String fileName = getDocumentFileName(document);
|
||||||
|
int idx = fileName.lastIndexOf(".");
|
||||||
|
String ext = null;
|
||||||
|
if (idx != -1) {
|
||||||
|
ext = fileName.substring(idx + 1);
|
||||||
|
}
|
||||||
|
if (ext == null || ext.length() == 0) {
|
||||||
|
ext = document.mime_type;
|
||||||
|
}
|
||||||
|
if (ext == null) {
|
||||||
|
ext = "";
|
||||||
|
}
|
||||||
|
ext = ext.toUpperCase();
|
||||||
|
return ext;
|
||||||
|
}
|
||||||
|
|
||||||
public static String getAttachFileName(TLObject attach) {
|
public static String getAttachFileName(TLObject attach) {
|
||||||
return getAttachFileName(attach, null);
|
return getAttachFileName(attach, null);
|
||||||
}
|
}
|
||||||
|
|
|
@ -196,14 +196,17 @@ public class FileLog {
|
||||||
File sdCard = ApplicationLoader.applicationContext.getExternalFilesDir(null);
|
File sdCard = ApplicationLoader.applicationContext.getExternalFilesDir(null);
|
||||||
File dir = new File (sdCard.getAbsolutePath() + "/logs");
|
File dir = new File (sdCard.getAbsolutePath() + "/logs");
|
||||||
File[] files = dir.listFiles();
|
File[] files = dir.listFiles();
|
||||||
for (File file : files) {
|
if (files != null) {
|
||||||
if (getInstance().currentFile != null && file.getAbsolutePath().equals(getInstance().currentFile.getAbsolutePath())) {
|
for (int a = 0; a < files.length; a++) {
|
||||||
continue;
|
File file = files[a];
|
||||||
|
if (getInstance().currentFile != null && file.getAbsolutePath().equals(getInstance().currentFile.getAbsolutePath())) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (getInstance().networkFile != null && file.getAbsolutePath().equals(getInstance().networkFile.getAbsolutePath())) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
file.delete();
|
||||||
}
|
}
|
||||||
if (getInstance().networkFile != null && file.getAbsolutePath().equals(getInstance().networkFile.getAbsolutePath())) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
file.delete();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,7 +23,6 @@ import android.net.Uri;
|
||||||
import android.os.AsyncTask;
|
import android.os.AsyncTask;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.os.Environment;
|
import android.os.Environment;
|
||||||
import android.os.ParcelFileDescriptor;
|
|
||||||
import android.provider.MediaStore;
|
import android.provider.MediaStore;
|
||||||
|
|
||||||
import org.telegram.tgnet.ConnectionsManager;
|
import org.telegram.tgnet.ConnectionsManager;
|
||||||
|
@ -33,7 +32,6 @@ import org.telegram.ui.Components.AnimatedFileDrawable;
|
||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileDescriptor;
|
|
||||||
import java.io.FileInputStream;
|
import java.io.FileInputStream;
|
||||||
import java.io.FileOutputStream;
|
import java.io.FileOutputStream;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
@ -2031,8 +2029,7 @@ public class ImageLoader {
|
||||||
public static Bitmap loadBitmap(String path, Uri uri, float maxWidth, float maxHeight, boolean useMaxScale) {
|
public static Bitmap loadBitmap(String path, Uri uri, float maxWidth, float maxHeight, boolean useMaxScale) {
|
||||||
BitmapFactory.Options bmOptions = new BitmapFactory.Options();
|
BitmapFactory.Options bmOptions = new BitmapFactory.Options();
|
||||||
bmOptions.inJustDecodeBounds = true;
|
bmOptions.inJustDecodeBounds = true;
|
||||||
FileDescriptor fileDescriptor = null;
|
InputStream inputStream = null;
|
||||||
ParcelFileDescriptor parcelFD = null;
|
|
||||||
|
|
||||||
if (path == null && uri != null && uri.getScheme() != null) {
|
if (path == null && uri != null && uri.getScheme() != null) {
|
||||||
String imageFilePath = null;
|
String imageFilePath = null;
|
||||||
|
@ -2052,9 +2049,10 @@ public class ImageLoader {
|
||||||
} else if (uri != null) {
|
} else if (uri != null) {
|
||||||
boolean error = false;
|
boolean error = false;
|
||||||
try {
|
try {
|
||||||
parcelFD = ApplicationLoader.applicationContext.getContentResolver().openFileDescriptor(uri, "r");
|
inputStream = ApplicationLoader.applicationContext.getContentResolver().openInputStream(uri);
|
||||||
fileDescriptor = parcelFD.getFileDescriptor();
|
BitmapFactory.decodeStream(inputStream, null, bmOptions);
|
||||||
BitmapFactory.decodeFileDescriptor(fileDescriptor, null, bmOptions);
|
inputStream.close();
|
||||||
|
inputStream = ApplicationLoader.applicationContext.getContentResolver().openInputStream(uri);
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
FileLog.e("tmessages", e);
|
FileLog.e("tmessages", e);
|
||||||
return null;
|
return null;
|
||||||
|
@ -2138,7 +2136,7 @@ public class ImageLoader {
|
||||||
}
|
}
|
||||||
} else if (uri != null) {
|
} else if (uri != null) {
|
||||||
try {
|
try {
|
||||||
b = BitmapFactory.decodeFileDescriptor(fileDescriptor, null, bmOptions);
|
b = BitmapFactory.decodeStream(inputStream, null, bmOptions);
|
||||||
if (b != null) {
|
if (b != null) {
|
||||||
if (bmOptions.inPurgeable) {
|
if (bmOptions.inPurgeable) {
|
||||||
Utilities.pinBitmap(b);
|
Utilities.pinBitmap(b);
|
||||||
|
@ -2153,7 +2151,7 @@ public class ImageLoader {
|
||||||
FileLog.e("tmessages", e);
|
FileLog.e("tmessages", e);
|
||||||
} finally {
|
} finally {
|
||||||
try {
|
try {
|
||||||
parcelFD.close();
|
inputStream.close();
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
FileLog.e("tmessages", e);
|
FileLog.e("tmessages", e);
|
||||||
}
|
}
|
||||||
|
|
|
@ -322,7 +322,7 @@ public class LocaleController {
|
||||||
StringBuilder result = new StringBuilder(11);
|
StringBuilder result = new StringBuilder(11);
|
||||||
result.append(languageCode);
|
result.append(languageCode);
|
||||||
if (countryCode.length() > 0 || variantCode.length() > 0) {
|
if (countryCode.length() > 0 || variantCode.length() > 0) {
|
||||||
result.append('_');
|
result.append('-');
|
||||||
}
|
}
|
||||||
result.append(countryCode);
|
result.append(countryCode);
|
||||||
if (variantCode.length() > 0) {
|
if (variantCode.length() > 0) {
|
||||||
|
@ -664,16 +664,21 @@ public class LocaleController {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String formatDateChat(long date) {
|
public static String formatDateChat(long date) {
|
||||||
Calendar rightNow = Calendar.getInstance();
|
try {
|
||||||
int year = rightNow.get(Calendar.YEAR);
|
Calendar rightNow = Calendar.getInstance();
|
||||||
|
int year = rightNow.get(Calendar.YEAR);
|
||||||
|
|
||||||
rightNow.setTimeInMillis(date * 1000);
|
rightNow.setTimeInMillis(date * 1000);
|
||||||
int dateYear = rightNow.get(Calendar.YEAR);
|
int dateYear = rightNow.get(Calendar.YEAR);
|
||||||
|
|
||||||
if (year == dateYear) {
|
if (year == dateYear) {
|
||||||
return getInstance().chatDate.format(date * 1000);
|
return getInstance().chatDate.format(date * 1000);
|
||||||
|
}
|
||||||
|
return getInstance().chatFullDate.format(date * 1000);
|
||||||
|
} catch (Exception e) {
|
||||||
|
FileLog.e("tmessages", e);
|
||||||
}
|
}
|
||||||
return getInstance().chatFullDate.format(date * 1000);
|
return "LOC_ERR: formatDateChat";
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String formatDate(long date) {
|
public static String formatDate(long date) {
|
||||||
|
@ -697,7 +702,7 @@ public class LocaleController {
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
FileLog.e("tmessages", e);
|
FileLog.e("tmessages", e);
|
||||||
}
|
}
|
||||||
return "LOC_ERR";
|
return "LOC_ERR: formatDate";
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String formatDateAudio(long date) {
|
public static String formatDateAudio(long date) {
|
||||||
|
|
|
@ -42,10 +42,10 @@ import android.net.ConnectivityManager;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.os.Environment;
|
import android.os.Environment;
|
||||||
import android.os.ParcelFileDescriptor;
|
|
||||||
import android.os.PowerManager;
|
import android.os.PowerManager;
|
||||||
import android.os.Vibrator;
|
import android.os.Vibrator;
|
||||||
import android.provider.MediaStore;
|
import android.provider.MediaStore;
|
||||||
|
import android.provider.OpenableColumns;
|
||||||
import android.telephony.PhoneStateListener;
|
import android.telephony.PhoneStateListener;
|
||||||
import android.telephony.TelephonyManager;
|
import android.telephony.TelephonyManager;
|
||||||
|
|
||||||
|
@ -63,6 +63,7 @@ import org.telegram.ui.PhotoViewer;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileInputStream;
|
import java.io.FileInputStream;
|
||||||
import java.io.FileOutputStream;
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.InputStream;
|
||||||
import java.lang.ref.WeakReference;
|
import java.lang.ref.WeakReference;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.nio.ByteOrder;
|
import java.nio.ByteOrder;
|
||||||
|
@ -235,7 +236,7 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener,
|
||||||
private float[] gravityFast = new float[3];
|
private float[] gravityFast = new float[3];
|
||||||
private float[] linearAcceleration = new float[3];
|
private float[] linearAcceleration = new float[3];
|
||||||
|
|
||||||
private boolean hasAudioFoces;
|
private boolean hasAudioFocus;
|
||||||
private boolean callInProgress;
|
private boolean callInProgress;
|
||||||
|
|
||||||
private ArrayList<MessageObject> videoConvertQueue = new ArrayList<>();
|
private ArrayList<MessageObject> videoConvertQueue = new ArrayList<>();
|
||||||
|
@ -269,6 +270,8 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener,
|
||||||
private boolean saveToGallery = true;
|
private boolean saveToGallery = true;
|
||||||
private boolean autoplayGifs = true;
|
private boolean autoplayGifs = true;
|
||||||
private boolean raiseToSpeak = true;
|
private boolean raiseToSpeak = true;
|
||||||
|
private boolean customTabs = true;
|
||||||
|
private boolean directShare = true;
|
||||||
private boolean shuffleMusic;
|
private boolean shuffleMusic;
|
||||||
private int repeatMode;
|
private int repeatMode;
|
||||||
|
|
||||||
|
@ -595,6 +598,8 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener,
|
||||||
saveToGallery = preferences.getBoolean("save_gallery", false);
|
saveToGallery = preferences.getBoolean("save_gallery", false);
|
||||||
autoplayGifs = preferences.getBoolean("autoplay_gif", true) && Build.VERSION.SDK_INT >= 11;
|
autoplayGifs = preferences.getBoolean("autoplay_gif", true) && Build.VERSION.SDK_INT >= 11;
|
||||||
raiseToSpeak = preferences.getBoolean("raise_to_speak", true) && Build.VERSION.SDK_INT >= 11;
|
raiseToSpeak = preferences.getBoolean("raise_to_speak", true) && Build.VERSION.SDK_INT >= 11;
|
||||||
|
customTabs = preferences.getBoolean("custom_tabs", true);
|
||||||
|
directShare = preferences.getBoolean("direct_share", true);
|
||||||
shuffleMusic = preferences.getBoolean("shuffleMusic", false);
|
shuffleMusic = preferences.getBoolean("shuffleMusic", false);
|
||||||
repeatMode = preferences.getInt("repeatMode", 0);
|
repeatMode = preferences.getInt("repeatMode", 0);
|
||||||
|
|
||||||
|
@ -689,7 +694,7 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener,
|
||||||
if (MediaController.getInstance().isPlayingAudio(MediaController.getInstance().getPlayingMessageObject()) && !MediaController.getInstance().isAudioPaused()) {
|
if (MediaController.getInstance().isPlayingAudio(MediaController.getInstance().getPlayingMessageObject()) && !MediaController.getInstance().isAudioPaused()) {
|
||||||
MediaController.getInstance().pauseAudio(MediaController.getInstance().getPlayingMessageObject());
|
MediaController.getInstance().pauseAudio(MediaController.getInstance().getPlayingMessageObject());
|
||||||
}
|
}
|
||||||
hasAudioFoces = false;
|
hasAudioFocus = false;
|
||||||
} else if (focusChange == AudioManager.AUDIOFOCUS_GAIN) {
|
} else if (focusChange == AudioManager.AUDIOFOCUS_GAIN) {
|
||||||
//MediaController.getInstance().playAudio(MediaController.getInstance().getPlayingMessageObject());
|
//MediaController.getInstance().playAudio(MediaController.getInstance().getPlayingMessageObject());
|
||||||
}
|
}
|
||||||
|
@ -1653,14 +1658,24 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener,
|
||||||
if (playingMessageObject == null) {
|
if (playingMessageObject == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
boolean post = audioPlayer != null;
|
||||||
NotificationCenter.getInstance().postNotificationName(NotificationCenter.audioRouteChanged, useFrontSpeaker);
|
NotificationCenter.getInstance().postNotificationName(NotificationCenter.audioRouteChanged, useFrontSpeaker);
|
||||||
MessageObject currentMessageObject = playingMessageObject;
|
final MessageObject currentMessageObject = playingMessageObject;
|
||||||
float progress = playingMessageObject.audioProgress;
|
float progress = playingMessageObject.audioProgress;
|
||||||
cleanupPlayer(false, true);
|
cleanupPlayer(false, true);
|
||||||
currentMessageObject.audioProgress = progress;
|
currentMessageObject.audioProgress = progress;
|
||||||
playAudio(currentMessageObject);
|
playAudio(currentMessageObject);
|
||||||
if (paused) {
|
if (paused) {
|
||||||
pauseAudio(currentMessageObject);
|
if (post) {
|
||||||
|
AndroidUtilities.runOnUIThread(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
pauseAudio(currentMessageObject);
|
||||||
|
}
|
||||||
|
}, 100);
|
||||||
|
} else {
|
||||||
|
pauseAudio(currentMessageObject);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1959,6 +1974,11 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener,
|
||||||
if (byStop && repeatMode == 0) {
|
if (byStop && repeatMode == 0) {
|
||||||
if (audioPlayer != null || audioTrackPlayer != null) {
|
if (audioPlayer != null || audioTrackPlayer != null) {
|
||||||
if (audioPlayer != null) {
|
if (audioPlayer != null) {
|
||||||
|
try {
|
||||||
|
audioPlayer.reset();
|
||||||
|
} catch (Exception e) {
|
||||||
|
FileLog.e("tmessages", e);
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
audioPlayer.stop();
|
audioPlayer.stop();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
|
@ -2058,7 +2078,7 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean playAudio(MessageObject messageObject) {
|
public boolean playAudio(final MessageObject messageObject) {
|
||||||
if (messageObject == null) {
|
if (messageObject == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -2171,7 +2191,7 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener,
|
||||||
if (!playlist.isEmpty() && playlist.size() > 1) {
|
if (!playlist.isEmpty() && playlist.size() > 1) {
|
||||||
playNextMessage(true);
|
playNextMessage(true);
|
||||||
} else {
|
} else {
|
||||||
cleanupPlayer(true, true);
|
cleanupPlayer(true, true, messageObject != null && messageObject.isVoice());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -2201,8 +2221,8 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener,
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!hasAudioFoces) {
|
if (!hasAudioFocus) {
|
||||||
hasAudioFoces = true;
|
hasAudioFocus = true;
|
||||||
NotificationsController.getInstance().audioManager.requestAudioFocus(this, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN);
|
NotificationsController.getInstance().audioManager.requestAudioFocus(this, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2270,6 +2290,11 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener,
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
if (audioPlayer != null) {
|
if (audioPlayer != null) {
|
||||||
|
try {
|
||||||
|
audioPlayer.reset();
|
||||||
|
} catch (Exception e) {
|
||||||
|
FileLog.e("tmessages", e);
|
||||||
|
}
|
||||||
audioPlayer.stop();
|
audioPlayer.stop();
|
||||||
} else if (audioTrackPlayer != null) {
|
} else if (audioTrackPlayer != null) {
|
||||||
audioTrackPlayer.pause();
|
audioTrackPlayer.pause();
|
||||||
|
@ -2378,8 +2403,8 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener,
|
||||||
audioTrackPlayer.play();
|
audioTrackPlayer.play();
|
||||||
checkPlayerQueue();
|
checkPlayerQueue();
|
||||||
}
|
}
|
||||||
if (!hasAudioFoces) {
|
if (!hasAudioFocus) {
|
||||||
hasAudioFoces = true;
|
hasAudioFocus = true;
|
||||||
NotificationsController.getInstance().audioManager.requestAudioFocus(this, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN);
|
NotificationsController.getInstance().audioManager.requestAudioFocus(this, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN);
|
||||||
}
|
}
|
||||||
isPaused = false;
|
isPaused = false;
|
||||||
|
@ -2507,19 +2532,6 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener,
|
||||||
public void generateWaveform(MessageObject messageObject) {
|
public void generateWaveform(MessageObject messageObject) {
|
||||||
final String id = messageObject.getId() + "_" + messageObject.getDialogId();
|
final String id = messageObject.getId() + "_" + messageObject.getDialogId();
|
||||||
final String path = FileLoader.getPathToMessage(messageObject.messageOwner).getAbsolutePath();
|
final String path = FileLoader.getPathToMessage(messageObject.messageOwner).getAbsolutePath();
|
||||||
/*for (int a = 0; a < currentMessageObject.messageOwner.media.document.attributes.size(); a++) { TODO if old attribute
|
|
||||||
TLRPC.DocumentAttribute attribute = currentMessageObject.messageOwner.media.document.attributes.get(a);
|
|
||||||
if (attribute instanceof TLRPC.TL_documentAttributeAudio) {
|
|
||||||
if (attribute.waveform == null || attribute.waveform.length == 0) {
|
|
||||||
attribute.waveform = MediaController.getInstance().getWaveform(path.getAbsolutePath());
|
|
||||||
}
|
|
||||||
if (attribute.waveform != null) {
|
|
||||||
hasWaveform = true;
|
|
||||||
}
|
|
||||||
seekBarWaveform.setWaveform(attribute.waveform);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}*/
|
|
||||||
if (generatingWaveform.containsKey(id)) {
|
if (generatingWaveform.containsKey(id)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -2764,14 +2776,11 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener,
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isWebp(Uri uri) {
|
public static boolean isWebp(Uri uri) {
|
||||||
ParcelFileDescriptor parcelFD = null;
|
InputStream inputStream = null;
|
||||||
FileInputStream input = null;
|
|
||||||
try {
|
try {
|
||||||
parcelFD = ApplicationLoader.applicationContext.getContentResolver().openFileDescriptor(uri, "r");
|
inputStream = ApplicationLoader.applicationContext.getContentResolver().openInputStream(uri);
|
||||||
input = new FileInputStream(parcelFD.getFileDescriptor());
|
byte[] header = new byte[12];
|
||||||
if (input.getChannel().size() > 12) {
|
if (inputStream.read(header, 0, 12) == 12) {
|
||||||
byte[] header = new byte[12];
|
|
||||||
input.read(header, 0, 12);
|
|
||||||
String str = new String(header);
|
String str = new String(header);
|
||||||
if (str != null) {
|
if (str != null) {
|
||||||
str = str.toLowerCase();
|
str = str.toLowerCase();
|
||||||
|
@ -2784,15 +2793,8 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener,
|
||||||
FileLog.e("tmessages", e);
|
FileLog.e("tmessages", e);
|
||||||
} finally {
|
} finally {
|
||||||
try {
|
try {
|
||||||
if (parcelFD != null) {
|
if (inputStream != null) {
|
||||||
parcelFD.close();
|
inputStream.close();
|
||||||
}
|
|
||||||
} catch (Exception e2) {
|
|
||||||
FileLog.e("tmessages", e2);
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
if (input != null) {
|
|
||||||
input.close();
|
|
||||||
}
|
}
|
||||||
} catch (Exception e2) {
|
} catch (Exception e2) {
|
||||||
FileLog.e("tmessages", e2);
|
FileLog.e("tmessages", e2);
|
||||||
|
@ -2802,14 +2804,11 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener,
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isGif(Uri uri) {
|
public static boolean isGif(Uri uri) {
|
||||||
ParcelFileDescriptor parcelFD = null;
|
InputStream inputStream = null;
|
||||||
FileInputStream input = null;
|
|
||||||
try {
|
try {
|
||||||
parcelFD = ApplicationLoader.applicationContext.getContentResolver().openFileDescriptor(uri, "r");
|
inputStream = ApplicationLoader.applicationContext.getContentResolver().openInputStream(uri);
|
||||||
input = new FileInputStream(parcelFD.getFileDescriptor());
|
byte[] header = new byte[3];
|
||||||
if (input.getChannel().size() > 3) {
|
if (inputStream.read(header, 0, 3) == 3) {
|
||||||
byte[] header = new byte[3];
|
|
||||||
input.read(header, 0, 3);
|
|
||||||
String str = new String(header);
|
String str = new String(header);
|
||||||
if (str != null && str.equalsIgnoreCase("gif")) {
|
if (str != null && str.equalsIgnoreCase("gif")) {
|
||||||
return true;
|
return true;
|
||||||
|
@ -2819,15 +2818,8 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener,
|
||||||
FileLog.e("tmessages", e);
|
FileLog.e("tmessages", e);
|
||||||
} finally {
|
} finally {
|
||||||
try {
|
try {
|
||||||
if (parcelFD != null) {
|
if (inputStream != null) {
|
||||||
parcelFD.close();
|
inputStream.close();
|
||||||
}
|
|
||||||
} catch (Exception e2) {
|
|
||||||
FileLog.e("tmessages", e2);
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
if (input != null) {
|
|
||||||
input.close();
|
|
||||||
}
|
}
|
||||||
} catch (Exception e2) {
|
} catch (Exception e2) {
|
||||||
FileLog.e("tmessages", e2);
|
FileLog.e("tmessages", e2);
|
||||||
|
@ -2836,33 +2828,58 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener,
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String copyDocumentToCache(Uri uri, String ext) {
|
public static String getFileName(Uri uri) {
|
||||||
ParcelFileDescriptor parcelFD = null;
|
String result = null;
|
||||||
FileInputStream input = null;
|
if (uri.getScheme().equals("content")) {
|
||||||
|
Cursor cursor = ApplicationLoader.applicationContext.getContentResolver().query(uri, null, null, null, null);
|
||||||
|
try {
|
||||||
|
if (cursor.moveToFirst()) {
|
||||||
|
result = cursor.getString(cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME));
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
FileLog.e("tmessages", e);
|
||||||
|
} finally {
|
||||||
|
if (cursor != null) {
|
||||||
|
cursor.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (result == null) {
|
||||||
|
result = uri.getPath();
|
||||||
|
int cut = result.lastIndexOf('/');
|
||||||
|
if (cut != -1) {
|
||||||
|
result = result.substring(cut + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String copyFileToCache(Uri uri, String ext) {
|
||||||
|
InputStream inputStream = null;
|
||||||
FileOutputStream output = null;
|
FileOutputStream output = null;
|
||||||
try {
|
try {
|
||||||
int id = UserConfig.lastLocalId;
|
String name = getFileName(uri);
|
||||||
UserConfig.lastLocalId--;
|
if (name == null) {
|
||||||
parcelFD = ApplicationLoader.applicationContext.getContentResolver().openFileDescriptor(uri, "r");
|
int id = UserConfig.lastLocalId;
|
||||||
input = new FileInputStream(parcelFD.getFileDescriptor());
|
UserConfig.lastLocalId--;
|
||||||
File f = new File(FileLoader.getInstance().getDirectory(FileLoader.MEDIA_DIR_CACHE), String.format(Locale.US, "%d.%s", id, ext));
|
UserConfig.saveConfig(false);
|
||||||
|
name = String.format(Locale.US, "%d.%s", id, ext);
|
||||||
|
}
|
||||||
|
inputStream = ApplicationLoader.applicationContext.getContentResolver().openInputStream(uri);
|
||||||
|
File f = new File(FileLoader.getInstance().getDirectory(FileLoader.MEDIA_DIR_CACHE), name);
|
||||||
output = new FileOutputStream(f);
|
output = new FileOutputStream(f);
|
||||||
input.getChannel().transferTo(0, input.getChannel().size(), output.getChannel());
|
byte[] buffer = new byte[1024 * 20];
|
||||||
UserConfig.saveConfig(false);
|
int len;
|
||||||
|
while ((len = inputStream.read(buffer)) != -1) {
|
||||||
|
output.write(buffer, 0, len);
|
||||||
|
}
|
||||||
return f.getAbsolutePath();
|
return f.getAbsolutePath();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
FileLog.e("tmessages", e);
|
FileLog.e("tmessages", e);
|
||||||
} finally {
|
} finally {
|
||||||
try {
|
try {
|
||||||
if (parcelFD != null) {
|
if (inputStream != null) {
|
||||||
parcelFD.close();
|
inputStream.close();
|
||||||
}
|
|
||||||
} catch (Exception e2) {
|
|
||||||
FileLog.e("tmessages", e2);
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
if (input != null) {
|
|
||||||
input.close();
|
|
||||||
}
|
}
|
||||||
} catch (Exception e2) {
|
} catch (Exception e2) {
|
||||||
FileLog.e("tmessages", e2);
|
FileLog.e("tmessages", e2);
|
||||||
|
@ -2903,6 +2920,22 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener,
|
||||||
editor.commit();
|
editor.commit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void toggleCustomTabs() {
|
||||||
|
customTabs = !customTabs;
|
||||||
|
SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("mainconfig", Activity.MODE_PRIVATE);
|
||||||
|
SharedPreferences.Editor editor = preferences.edit();
|
||||||
|
editor.putBoolean("custom_tabs", customTabs);
|
||||||
|
editor.commit();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void toggleDirectShare() {
|
||||||
|
directShare = !directShare;
|
||||||
|
SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("mainconfig", Activity.MODE_PRIVATE);
|
||||||
|
SharedPreferences.Editor editor = preferences.edit();
|
||||||
|
editor.putBoolean("direct_share", directShare);
|
||||||
|
editor.commit();
|
||||||
|
}
|
||||||
|
|
||||||
public void checkSaveToGalleryFiles() {
|
public void checkSaveToGalleryFiles() {
|
||||||
try {
|
try {
|
||||||
File telegramPath = new File(Environment.getExternalStorageDirectory(), "Telegram");
|
File telegramPath = new File(Environment.getExternalStorageDirectory(), "Telegram");
|
||||||
|
@ -2943,6 +2976,14 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener,
|
||||||
return raiseToSpeak;
|
return raiseToSpeak;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean canCustomTabs() {
|
||||||
|
return customTabs;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean canDirectShare() {
|
||||||
|
return directShare;
|
||||||
|
}
|
||||||
|
|
||||||
public static void loadGalleryPhotosAlbums(final int guid) {
|
public static void loadGalleryPhotosAlbums(final int guid) {
|
||||||
new Thread(new Runnable() {
|
new Thread(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
|
@ -3246,6 +3287,7 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener,
|
||||||
long startTime = -1;
|
long startTime = -1;
|
||||||
|
|
||||||
checkConversionCanceled();
|
checkConversionCanceled();
|
||||||
|
long lastTimestamp = -100;
|
||||||
|
|
||||||
while (!inputDone) {
|
while (!inputDone) {
|
||||||
checkConversionCanceled();
|
checkConversionCanceled();
|
||||||
|
@ -3254,28 +3296,37 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener,
|
||||||
int index = extractor.getSampleTrackIndex();
|
int index = extractor.getSampleTrackIndex();
|
||||||
if (index == trackIndex) {
|
if (index == trackIndex) {
|
||||||
info.size = extractor.readSampleData(buffer, 0);
|
info.size = extractor.readSampleData(buffer, 0);
|
||||||
|
if (info.size >= 0) {
|
||||||
if (info.size < 0) {
|
info.presentationTimeUs = extractor.getSampleTime();
|
||||||
|
} else {
|
||||||
info.size = 0;
|
info.size = 0;
|
||||||
eof = true;
|
eof = true;
|
||||||
} else {
|
}
|
||||||
info.presentationTimeUs = extractor.getSampleTime();
|
|
||||||
|
if (info.size > 0 && !eof) {
|
||||||
if (start > 0 && startTime == -1) {
|
if (start > 0 && startTime == -1) {
|
||||||
startTime = info.presentationTimeUs;
|
startTime = info.presentationTimeUs;
|
||||||
}
|
}
|
||||||
if (end < 0 || info.presentationTimeUs < end) {
|
if (end < 0 || info.presentationTimeUs < end) {
|
||||||
info.offset = 0;
|
if (info.presentationTimeUs > lastTimestamp) {
|
||||||
info.flags = extractor.getSampleFlags();
|
info.offset = 0;
|
||||||
if (mediaMuxer.writeSampleData(muxerTrackIndex, buffer, info, isAudio)) {
|
info.flags = extractor.getSampleFlags();
|
||||||
didWriteData(messageObject, file, false, false);
|
if (mediaMuxer.writeSampleData(muxerTrackIndex, buffer, info, isAudio)) {
|
||||||
|
didWriteData(messageObject, file, false, false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
extractor.advance();
|
lastTimestamp = info.presentationTimeUs;
|
||||||
} else {
|
} else {
|
||||||
eof = true;
|
eof = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (!eof) {
|
||||||
|
extractor.advance();
|
||||||
|
}
|
||||||
} else if (index == -1) {
|
} else if (index == -1) {
|
||||||
eof = true;
|
eof = true;
|
||||||
|
} else {
|
||||||
|
extractor.advance();
|
||||||
}
|
}
|
||||||
if (eof) {
|
if (eof) {
|
||||||
inputDone = true;
|
inputDone = true;
|
||||||
|
|
|
@ -58,11 +58,10 @@ public class MessageObject {
|
||||||
public VideoEditedInfo videoEditedInfo;
|
public VideoEditedInfo videoEditedInfo;
|
||||||
public boolean viewsReloaded;
|
public boolean viewsReloaded;
|
||||||
|
|
||||||
public static TextPaint textPaint;
|
private static TextPaint textPaint;
|
||||||
public int lastLineWidth;
|
public int lastLineWidth;
|
||||||
public int textWidth;
|
public int textWidth;
|
||||||
public int textHeight;
|
public int textHeight;
|
||||||
public int blockHeight = Integer.MAX_VALUE;
|
|
||||||
|
|
||||||
private boolean layoutCreated;
|
private boolean layoutCreated;
|
||||||
|
|
||||||
|
@ -70,9 +69,10 @@ public class MessageObject {
|
||||||
|
|
||||||
public static class TextLayoutBlock {
|
public static class TextLayoutBlock {
|
||||||
public StaticLayout textLayout;
|
public StaticLayout textLayout;
|
||||||
public float textXOffset = 0;
|
public float textXOffset;
|
||||||
public float textYOffset = 0;
|
public float textYOffset;
|
||||||
public int charactersOffset = 0;
|
public int charactersOffset;
|
||||||
|
public int height;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final int LINES_PER_BLOCK = 10;
|
private static final int LINES_PER_BLOCK = 10;
|
||||||
|
@ -99,7 +99,7 @@ public class MessageObject {
|
||||||
}
|
}
|
||||||
|
|
||||||
TLRPC.User fromUser = null;
|
TLRPC.User fromUser = null;
|
||||||
if (isFromUser()) {
|
if (message.from_id > 0) {
|
||||||
if (users != null) {
|
if (users != null) {
|
||||||
fromUser = users.get(message.from_id);
|
fromUser = users.get(message.from_id);
|
||||||
}
|
}
|
||||||
|
@ -114,22 +114,14 @@ public class MessageObject {
|
||||||
if (isOut()) {
|
if (isOut()) {
|
||||||
messageText = LocaleController.getString("ActionYouCreateGroup", R.string.ActionYouCreateGroup);
|
messageText = LocaleController.getString("ActionYouCreateGroup", R.string.ActionYouCreateGroup);
|
||||||
} else {
|
} else {
|
||||||
if (fromUser != null) {
|
messageText = replaceWithLink(LocaleController.getString("ActionCreateGroup", R.string.ActionCreateGroup), "un1", fromUser);
|
||||||
messageText = replaceWithLink(LocaleController.getString("ActionCreateGroup", R.string.ActionCreateGroup), "un1", fromUser);
|
|
||||||
} else {
|
|
||||||
messageText = LocaleController.getString("ActionCreateGroup", R.string.ActionCreateGroup).replace("un1", "");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else if (message.action instanceof TLRPC.TL_messageActionChatDeleteUser) {
|
} else if (message.action instanceof TLRPC.TL_messageActionChatDeleteUser) {
|
||||||
if (message.action.user_id == message.from_id) {
|
if (message.action.user_id == message.from_id) {
|
||||||
if (isOut()) {
|
if (isOut()) {
|
||||||
messageText = LocaleController.getString("ActionYouLeftUser", R.string.ActionYouLeftUser);
|
messageText = LocaleController.getString("ActionYouLeftUser", R.string.ActionYouLeftUser);
|
||||||
} else {
|
} else {
|
||||||
if (fromUser != null) {
|
messageText = replaceWithLink(LocaleController.getString("ActionLeftUser", R.string.ActionLeftUser), "un1", fromUser);
|
||||||
messageText = replaceWithLink(LocaleController.getString("ActionLeftUser", R.string.ActionLeftUser), "un1", fromUser);
|
|
||||||
} else {
|
|
||||||
messageText = LocaleController.getString("ActionLeftUser", R.string.ActionLeftUser).replace("un1", "");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
TLRPC.User whoUser = null;
|
TLRPC.User whoUser = null;
|
||||||
|
@ -139,17 +131,13 @@ public class MessageObject {
|
||||||
if (whoUser == null) {
|
if (whoUser == null) {
|
||||||
whoUser = MessagesController.getInstance().getUser(message.action.user_id);
|
whoUser = MessagesController.getInstance().getUser(message.action.user_id);
|
||||||
}
|
}
|
||||||
if (whoUser != null && fromUser != null) {
|
if (isOut()) {
|
||||||
if (isOut()) {
|
messageText = replaceWithLink(LocaleController.getString("ActionYouKickUser", R.string.ActionYouKickUser), "un2", whoUser);
|
||||||
messageText = replaceWithLink(LocaleController.getString("ActionYouKickUser", R.string.ActionYouKickUser), "un2", whoUser);
|
} else if (message.action.user_id == UserConfig.getClientUserId()) {
|
||||||
} else if (message.action.user_id == UserConfig.getClientUserId()) {
|
messageText = replaceWithLink(LocaleController.getString("ActionKickUserYou", R.string.ActionKickUserYou), "un1", fromUser);
|
||||||
messageText = replaceWithLink(LocaleController.getString("ActionKickUserYou", R.string.ActionKickUserYou), "un1", fromUser);
|
|
||||||
} else {
|
|
||||||
messageText = replaceWithLink(LocaleController.getString("ActionKickUser", R.string.ActionKickUser), "un2", whoUser);
|
|
||||||
messageText = replaceWithLink(messageText, "un1", fromUser);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
messageText = LocaleController.getString("ActionKickUser", R.string.ActionKickUser).replace("un2", "").replace("un1", "");
|
messageText = replaceWithLink(LocaleController.getString("ActionKickUser", R.string.ActionKickUser), "un2", whoUser);
|
||||||
|
messageText = replaceWithLink(messageText, "un1", fromUser);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (message.action instanceof TLRPC.TL_messageActionChatAddUser) {
|
} else if (message.action instanceof TLRPC.TL_messageActionChatAddUser) {
|
||||||
|
@ -165,36 +153,38 @@ public class MessageObject {
|
||||||
if (whoUser == null) {
|
if (whoUser == null) {
|
||||||
whoUser = MessagesController.getInstance().getUser(singleUserId);
|
whoUser = MessagesController.getInstance().getUser(singleUserId);
|
||||||
}
|
}
|
||||||
if (message.to_id.channel_id != 0 && !isMegagroup()) {
|
if (singleUserId == message.from_id) {
|
||||||
if (whoUser != null && whoUser.id != UserConfig.getClientUserId()) {
|
if (message.to_id.channel_id != 0 && !isMegagroup()) {
|
||||||
if (isMegagroup()) {
|
|
||||||
messageText = replaceWithLink(LocaleController.getString("MegaAddedBy", R.string.MegaAddedBy), "un1", whoUser);
|
|
||||||
} else {
|
|
||||||
messageText = replaceWithLink(LocaleController.getString("ChannelAddedBy", R.string.ChannelAddedBy), "un1", whoUser);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
messageText = LocaleController.getString("ChannelJoined", R.string.ChannelJoined);
|
messageText = LocaleController.getString("ChannelJoined", R.string.ChannelJoined);
|
||||||
|
} else {
|
||||||
|
if (message.to_id.channel_id != 0 && isMegagroup()) {
|
||||||
|
if (singleUserId == UserConfig.getClientUserId()) {
|
||||||
|
messageText = LocaleController.getString("ChannelMegaJoined", R.string.ChannelMegaJoined);
|
||||||
|
} else {
|
||||||
|
messageText = replaceWithLink(LocaleController.getString("ActionAddUserSelfMega", R.string.ActionAddUserSelfMega), "un1", fromUser);
|
||||||
|
}
|
||||||
|
} else if (isOut()) {
|
||||||
|
messageText = LocaleController.getString("ActionAddUserSelfYou", R.string.ActionAddUserSelfYou);
|
||||||
|
} else {
|
||||||
|
messageText = replaceWithLink(LocaleController.getString("ActionAddUserSelf", R.string.ActionAddUserSelf), "un1", fromUser);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (whoUser != null && fromUser != null) {
|
if (isOut()) {
|
||||||
if (whoUser.id == fromUser.id) {
|
messageText = replaceWithLink(LocaleController.getString("ActionYouAddUser", R.string.ActionYouAddUser), "un2", whoUser);
|
||||||
if (isOut()) {
|
} else if (singleUserId == UserConfig.getClientUserId()) {
|
||||||
messageText = LocaleController.getString("ActionAddUserSelfYou", R.string.ActionAddUserSelfYou);
|
if (message.to_id.channel_id != 0) {
|
||||||
|
if (isMegagroup()) {
|
||||||
|
messageText = replaceWithLink(LocaleController.getString("MegaAddedBy", R.string.MegaAddedBy), "un1", fromUser);
|
||||||
} else {
|
} else {
|
||||||
messageText = replaceWithLink(LocaleController.getString("ActionAddUserSelf", R.string.ActionAddUserSelf), "un1", fromUser);
|
messageText = replaceWithLink(LocaleController.getString("ChannelAddedBy", R.string.ChannelAddedBy), "un1", fromUser);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (isOut()) {
|
messageText = replaceWithLink(LocaleController.getString("ActionAddUserYou", R.string.ActionAddUserYou), "un1", fromUser);
|
||||||
messageText = replaceWithLink(LocaleController.getString("ActionYouAddUser", R.string.ActionYouAddUser), "un2", whoUser);
|
|
||||||
} else if (singleUserId == UserConfig.getClientUserId()) {
|
|
||||||
messageText = replaceWithLink(LocaleController.getString("ActionAddUserYou", R.string.ActionAddUserYou), "un1", fromUser);
|
|
||||||
} else {
|
|
||||||
messageText = replaceWithLink(LocaleController.getString("ActionAddUser", R.string.ActionAddUser), "un2", whoUser);
|
|
||||||
messageText = replaceWithLink(messageText, "un1", fromUser);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
messageText = LocaleController.getString("ActionAddUser", R.string.ActionAddUser).replace("un2", "").replace("un1", "");
|
messageText = replaceWithLink(LocaleController.getString("ActionAddUser", R.string.ActionAddUser), "un2", whoUser);
|
||||||
|
messageText = replaceWithLink(messageText, "un1", fromUser);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -206,14 +196,10 @@ public class MessageObject {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (message.action instanceof TLRPC.TL_messageActionChatJoinedByLink) {
|
} else if (message.action instanceof TLRPC.TL_messageActionChatJoinedByLink) {
|
||||||
if (fromUser != null) {
|
if (isOut()) {
|
||||||
if (isOut()) {
|
messageText = LocaleController.getString("ActionInviteYou", R.string.ActionInviteYou);
|
||||||
messageText = LocaleController.getString("ActionInviteYou", R.string.ActionInviteYou);
|
|
||||||
} else {
|
|
||||||
messageText = replaceWithLink(LocaleController.getString("ActionInviteUser", R.string.ActionInviteUser), "un1", fromUser);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
messageText = LocaleController.getString("ActionInviteUser", R.string.ActionInviteUser).replace("un1", "");
|
messageText = replaceWithLink(LocaleController.getString("ActionInviteUser", R.string.ActionInviteUser), "un1", fromUser);
|
||||||
}
|
}
|
||||||
} else if (message.action instanceof TLRPC.TL_messageActionChatEditPhoto) {
|
} else if (message.action instanceof TLRPC.TL_messageActionChatEditPhoto) {
|
||||||
if (message.to_id.channel_id != 0 && !isMegagroup()) {
|
if (message.to_id.channel_id != 0 && !isMegagroup()) {
|
||||||
|
@ -222,11 +208,7 @@ public class MessageObject {
|
||||||
if (isOut()) {
|
if (isOut()) {
|
||||||
messageText = LocaleController.getString("ActionYouChangedPhoto", R.string.ActionYouChangedPhoto);
|
messageText = LocaleController.getString("ActionYouChangedPhoto", R.string.ActionYouChangedPhoto);
|
||||||
} else {
|
} else {
|
||||||
if (fromUser != null) {
|
messageText = replaceWithLink(LocaleController.getString("ActionChangedPhoto", R.string.ActionChangedPhoto), "un1", fromUser);
|
||||||
messageText = replaceWithLink(LocaleController.getString("ActionChangedPhoto", R.string.ActionChangedPhoto), "un1", fromUser);
|
|
||||||
} else {
|
|
||||||
messageText = LocaleController.getString("ActionChangedPhoto", R.string.ActionChangedPhoto).replace("un1", "");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (message.action instanceof TLRPC.TL_messageActionChatEditTitle) {
|
} else if (message.action instanceof TLRPC.TL_messageActionChatEditTitle) {
|
||||||
|
@ -236,11 +218,7 @@ public class MessageObject {
|
||||||
if (isOut()) {
|
if (isOut()) {
|
||||||
messageText = LocaleController.getString("ActionYouChangedTitle", R.string.ActionYouChangedTitle).replace("un2", message.action.title);
|
messageText = LocaleController.getString("ActionYouChangedTitle", R.string.ActionYouChangedTitle).replace("un2", message.action.title);
|
||||||
} else {
|
} else {
|
||||||
if (fromUser != null) {
|
messageText = replaceWithLink(LocaleController.getString("ActionChangedTitle", R.string.ActionChangedTitle).replace("un2", message.action.title), "un1", fromUser);
|
||||||
messageText = replaceWithLink(LocaleController.getString("ActionChangedTitle", R.string.ActionChangedTitle).replace("un2", message.action.title), "un1", fromUser);
|
|
||||||
} else {
|
|
||||||
messageText = LocaleController.getString("ActionChangedTitle", R.string.ActionChangedTitle).replace("un1", "").replace("un2", message.action.title);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (message.action instanceof TLRPC.TL_messageActionChatDeletePhoto) {
|
} else if (message.action instanceof TLRPC.TL_messageActionChatDeletePhoto) {
|
||||||
|
@ -250,11 +228,7 @@ public class MessageObject {
|
||||||
if (isOut()) {
|
if (isOut()) {
|
||||||
messageText = LocaleController.getString("ActionYouRemovedPhoto", R.string.ActionYouRemovedPhoto);
|
messageText = LocaleController.getString("ActionYouRemovedPhoto", R.string.ActionYouRemovedPhoto);
|
||||||
} else {
|
} else {
|
||||||
if (fromUser != null) {
|
messageText = replaceWithLink(LocaleController.getString("ActionRemovedPhoto", R.string.ActionRemovedPhoto), "un1", fromUser);
|
||||||
messageText = replaceWithLink(LocaleController.getString("ActionRemovedPhoto", R.string.ActionRemovedPhoto), "un1", fromUser);
|
|
||||||
} else {
|
|
||||||
messageText = LocaleController.getString("ActionRemovedPhoto", R.string.ActionRemovedPhoto).replace("un1", "");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (message.action instanceof TLRPC.TL_messageActionTTLChange) {
|
} else if (message.action instanceof TLRPC.TL_messageActionTTLChange) {
|
||||||
|
@ -262,21 +236,13 @@ public class MessageObject {
|
||||||
if (isOut()) {
|
if (isOut()) {
|
||||||
messageText = LocaleController.formatString("MessageLifetimeChangedOutgoing", R.string.MessageLifetimeChangedOutgoing, AndroidUtilities.formatTTLString(message.action.ttl));
|
messageText = LocaleController.formatString("MessageLifetimeChangedOutgoing", R.string.MessageLifetimeChangedOutgoing, AndroidUtilities.formatTTLString(message.action.ttl));
|
||||||
} else {
|
} else {
|
||||||
if (fromUser != null) {
|
messageText = LocaleController.formatString("MessageLifetimeChanged", R.string.MessageLifetimeChanged, UserObject.getFirstName(fromUser), AndroidUtilities.formatTTLString(message.action.ttl));
|
||||||
messageText = LocaleController.formatString("MessageLifetimeChanged", R.string.MessageLifetimeChanged, UserObject.getFirstName(fromUser), AndroidUtilities.formatTTLString(message.action.ttl));
|
|
||||||
} else {
|
|
||||||
messageText = LocaleController.formatString("MessageLifetimeChanged", R.string.MessageLifetimeChanged, "", AndroidUtilities.formatTTLString(message.action.ttl));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (isOut()) {
|
if (isOut()) {
|
||||||
messageText = LocaleController.getString("MessageLifetimeYouRemoved", R.string.MessageLifetimeYouRemoved);
|
messageText = LocaleController.getString("MessageLifetimeYouRemoved", R.string.MessageLifetimeYouRemoved);
|
||||||
} else {
|
} else {
|
||||||
if (fromUser != null) {
|
messageText = LocaleController.formatString("MessageLifetimeRemoved", R.string.MessageLifetimeRemoved, UserObject.getFirstName(fromUser));
|
||||||
messageText = LocaleController.formatString("MessageLifetimeRemoved", R.string.MessageLifetimeRemoved, UserObject.getFirstName(fromUser));
|
|
||||||
} else {
|
|
||||||
messageText = LocaleController.formatString("MessageLifetimeRemoved", R.string.MessageLifetimeRemoved, "");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (message.action instanceof TLRPC.TL_messageActionLoginUnknownLocation) {
|
} else if (message.action instanceof TLRPC.TL_messageActionLoginUnknownLocation) {
|
||||||
|
@ -299,27 +265,15 @@ public class MessageObject {
|
||||||
String name = to_user != null ? UserObject.getFirstName(to_user) : "";
|
String name = to_user != null ? UserObject.getFirstName(to_user) : "";
|
||||||
messageText = LocaleController.formatString("NotificationUnrecognizedDevice", R.string.NotificationUnrecognizedDevice, name, date, message.action.title, message.action.address);
|
messageText = LocaleController.formatString("NotificationUnrecognizedDevice", R.string.NotificationUnrecognizedDevice, name, date, message.action.title, message.action.address);
|
||||||
} else if (message.action instanceof TLRPC.TL_messageActionUserJoined) {
|
} else if (message.action instanceof TLRPC.TL_messageActionUserJoined) {
|
||||||
if (fromUser != null) {
|
messageText = LocaleController.formatString("NotificationContactJoined", R.string.NotificationContactJoined, UserObject.getUserName(fromUser));
|
||||||
messageText = LocaleController.formatString("NotificationContactJoined", R.string.NotificationContactJoined, UserObject.getUserName(fromUser));
|
|
||||||
} else {
|
|
||||||
messageText = LocaleController.formatString("NotificationContactJoined", R.string.NotificationContactJoined, "");
|
|
||||||
}
|
|
||||||
} else if (message.action instanceof TLRPC.TL_messageActionUserUpdatedPhoto) {
|
} else if (message.action instanceof TLRPC.TL_messageActionUserUpdatedPhoto) {
|
||||||
if (fromUser != null) {
|
messageText = LocaleController.formatString("NotificationContactNewPhoto", R.string.NotificationContactNewPhoto, UserObject.getUserName(fromUser));
|
||||||
messageText = LocaleController.formatString("NotificationContactNewPhoto", R.string.NotificationContactNewPhoto, UserObject.getUserName(fromUser));
|
|
||||||
} else {
|
|
||||||
messageText = LocaleController.formatString("NotificationContactNewPhoto", R.string.NotificationContactNewPhoto, "");
|
|
||||||
}
|
|
||||||
} else if (message.action instanceof TLRPC.TL_messageEncryptedAction) {
|
} else if (message.action instanceof TLRPC.TL_messageEncryptedAction) {
|
||||||
if (message.action.encryptedAction instanceof TLRPC.TL_decryptedMessageActionScreenshotMessages) {
|
if (message.action.encryptedAction instanceof TLRPC.TL_decryptedMessageActionScreenshotMessages) {
|
||||||
if (isOut()) {
|
if (isOut()) {
|
||||||
messageText = LocaleController.formatString("ActionTakeScreenshootYou", R.string.ActionTakeScreenshootYou);
|
messageText = LocaleController.formatString("ActionTakeScreenshootYou", R.string.ActionTakeScreenshootYou);
|
||||||
} else {
|
} else {
|
||||||
if (fromUser != null) {
|
messageText = replaceWithLink(LocaleController.getString("ActionTakeScreenshoot", R.string.ActionTakeScreenshoot), "un1", fromUser);
|
||||||
messageText = replaceWithLink(LocaleController.getString("ActionTakeScreenshoot", R.string.ActionTakeScreenshoot), "un1", fromUser);
|
|
||||||
} else {
|
|
||||||
messageText = LocaleController.formatString("ActionTakeScreenshoot", R.string.ActionTakeScreenshoot).replace("un1", "");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else if (message.action.encryptedAction instanceof TLRPC.TL_decryptedMessageActionSetMessageTTL) {
|
} else if (message.action.encryptedAction instanceof TLRPC.TL_decryptedMessageActionSetMessageTTL) {
|
||||||
TLRPC.TL_decryptedMessageActionSetMessageTTL action = (TLRPC.TL_decryptedMessageActionSetMessageTTL) message.action.encryptedAction;
|
TLRPC.TL_decryptedMessageActionSetMessageTTL action = (TLRPC.TL_decryptedMessageActionSetMessageTTL) message.action.encryptedAction;
|
||||||
|
@ -327,21 +281,13 @@ public class MessageObject {
|
||||||
if (isOut()) {
|
if (isOut()) {
|
||||||
messageText = LocaleController.formatString("MessageLifetimeChangedOutgoing", R.string.MessageLifetimeChangedOutgoing, AndroidUtilities.formatTTLString(action.ttl_seconds));
|
messageText = LocaleController.formatString("MessageLifetimeChangedOutgoing", R.string.MessageLifetimeChangedOutgoing, AndroidUtilities.formatTTLString(action.ttl_seconds));
|
||||||
} else {
|
} else {
|
||||||
if (fromUser != null) {
|
messageText = LocaleController.formatString("MessageLifetimeChanged", R.string.MessageLifetimeChanged, UserObject.getFirstName(fromUser), AndroidUtilities.formatTTLString(action.ttl_seconds));
|
||||||
messageText = LocaleController.formatString("MessageLifetimeChanged", R.string.MessageLifetimeChanged, UserObject.getFirstName(fromUser), AndroidUtilities.formatTTLString(action.ttl_seconds));
|
|
||||||
} else {
|
|
||||||
messageText = LocaleController.formatString("MessageLifetimeChanged", R.string.MessageLifetimeChanged, "", AndroidUtilities.formatTTLString(action.ttl_seconds));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (isOut()) {
|
if (isOut()) {
|
||||||
messageText = LocaleController.getString("MessageLifetimeYouRemoved", R.string.MessageLifetimeYouRemoved);
|
messageText = LocaleController.getString("MessageLifetimeYouRemoved", R.string.MessageLifetimeYouRemoved);
|
||||||
} else {
|
} else {
|
||||||
if (fromUser != null) {
|
messageText = LocaleController.formatString("MessageLifetimeRemoved", R.string.MessageLifetimeRemoved, UserObject.getFirstName(fromUser));
|
||||||
messageText = LocaleController.formatString("MessageLifetimeRemoved", R.string.MessageLifetimeRemoved, UserObject.getFirstName(fromUser));
|
|
||||||
} else {
|
|
||||||
messageText = LocaleController.formatString("MessageLifetimeRemoved", R.string.MessageLifetimeRemoved, "");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -357,6 +303,8 @@ public class MessageObject {
|
||||||
messageText = LocaleController.getString("ActionMigrateFromGroup", R.string.ActionMigrateFromGroup);
|
messageText = LocaleController.getString("ActionMigrateFromGroup", R.string.ActionMigrateFromGroup);
|
||||||
} else if (message.action instanceof TLRPC.TL_messageActionChannelMigrateFrom) {
|
} else if (message.action instanceof TLRPC.TL_messageActionChannelMigrateFrom) {
|
||||||
messageText = LocaleController.getString("ActionMigrateFromGroup", R.string.ActionMigrateFromGroup);
|
messageText = LocaleController.getString("ActionMigrateFromGroup", R.string.ActionMigrateFromGroup);
|
||||||
|
} else if (message.action instanceof TLRPC.TL_messageActionPinMessage) {
|
||||||
|
generatePinMessageText(fromUser, fromUser == null ? chats.get(message.to_id.channel_id) : null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (!isMediaEmpty()) {
|
} else if (!isMediaEmpty()) {
|
||||||
|
@ -402,27 +350,31 @@ public class MessageObject {
|
||||||
|
|
||||||
if (message instanceof TLRPC.TL_message || message instanceof TLRPC.TL_messageForwarded_old2) {
|
if (message instanceof TLRPC.TL_message || message instanceof TLRPC.TL_messageForwarded_old2) {
|
||||||
if (isMediaEmpty()) {
|
if (isMediaEmpty()) {
|
||||||
contentType = type = 0;
|
contentType = 0;
|
||||||
|
type = 0;
|
||||||
if (messageText == null || messageText.length() == 0) {
|
if (messageText == null || messageText.length() == 0) {
|
||||||
messageText = "Empty message";
|
messageText = "Empty message";
|
||||||
}
|
}
|
||||||
} else if (message.media instanceof TLRPC.TL_messageMediaPhoto) {
|
} else if (message.media instanceof TLRPC.TL_messageMediaPhoto) {
|
||||||
contentType = type = 1;
|
contentType = 0;
|
||||||
|
type = 1;
|
||||||
} else if (message.media instanceof TLRPC.TL_messageMediaGeo || message.media instanceof TLRPC.TL_messageMediaVenue) {
|
} else if (message.media instanceof TLRPC.TL_messageMediaGeo || message.media instanceof TLRPC.TL_messageMediaVenue) {
|
||||||
contentType = 1;
|
contentType = 0;
|
||||||
type = 4;
|
type = 4;
|
||||||
} else if (isVideo()) {
|
} else if (isVideo()) {
|
||||||
contentType = 1;
|
contentType = 0;
|
||||||
type = 3;
|
type = 3;
|
||||||
} else if (isVoice()) {
|
} else if (isVoice()) {
|
||||||
contentType = type = 2;
|
contentType = 2;
|
||||||
|
type = 2;
|
||||||
} else if (message.media instanceof TLRPC.TL_messageMediaContact) {
|
} else if (message.media instanceof TLRPC.TL_messageMediaContact) {
|
||||||
contentType = 3;
|
contentType = 3;
|
||||||
type = 12;
|
type = 12;
|
||||||
} else if (message.media instanceof TLRPC.TL_messageMediaUnsupported) {
|
} else if (message.media instanceof TLRPC.TL_messageMediaUnsupported) {
|
||||||
contentType = type = 0;
|
contentType = 0;
|
||||||
|
type = 0;
|
||||||
} else if (message.media instanceof TLRPC.TL_messageMediaDocument) {
|
} else if (message.media instanceof TLRPC.TL_messageMediaDocument) {
|
||||||
contentType = 1;
|
contentType = 0;
|
||||||
if (message.media.document.mime_type != null) {
|
if (message.media.document.mime_type != null) {
|
||||||
if (isGifDocument(message.media.document)) {
|
if (isGifDocument(message.media.document)) {
|
||||||
type = 8;
|
type = 8;
|
||||||
|
@ -440,7 +392,8 @@ public class MessageObject {
|
||||||
}
|
}
|
||||||
} else if (message instanceof TLRPC.TL_messageService) {
|
} else if (message instanceof TLRPC.TL_messageService) {
|
||||||
if (message.action instanceof TLRPC.TL_messageActionLoginUnknownLocation) {
|
if (message.action instanceof TLRPC.TL_messageActionLoginUnknownLocation) {
|
||||||
contentType = type = 0;
|
contentType = 0;
|
||||||
|
type = 0;
|
||||||
} else if (message.action instanceof TLRPC.TL_messageActionChatEditPhoto || message.action instanceof TLRPC.TL_messageActionUserUpdatedPhoto) {
|
} else if (message.action instanceof TLRPC.TL_messageActionChatEditPhoto || message.action instanceof TLRPC.TL_messageActionUserUpdatedPhoto) {
|
||||||
contentType = 4;
|
contentType = 4;
|
||||||
type = 11;
|
type = 11;
|
||||||
|
@ -464,7 +417,7 @@ public class MessageObject {
|
||||||
int dateYear = rightNow.get(Calendar.YEAR);
|
int dateYear = rightNow.get(Calendar.YEAR);
|
||||||
int dateMonth = rightNow.get(Calendar.MONTH);
|
int dateMonth = rightNow.get(Calendar.MONTH);
|
||||||
dateKey = String.format("%d_%02d_%02d", dateYear, dateMonth, dateDay);
|
dateKey = String.format("%d_%02d_%02d", dateYear, dateMonth, dateDay);
|
||||||
if (contentType == 1 || contentType == 2 || contentType == 0 || contentType == 8) {
|
if (contentType == 2 || contentType == 0 || contentType == 8) {
|
||||||
monthKey = String.format("%d_%02d", dateYear, dateMonth);
|
monthKey = String.format("%d_%02d", dateYear, dateMonth);
|
||||||
} else if (contentType == 9) {
|
} else if (contentType == 9) {
|
||||||
//dateKey = "0_0_0";
|
//dateKey = "0_0_0";
|
||||||
|
@ -484,6 +437,58 @@ public class MessageObject {
|
||||||
generateThumbs(false);
|
generateThumbs(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static TextPaint getTextPaint() {
|
||||||
|
if (textPaint == null) {
|
||||||
|
textPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG);
|
||||||
|
textPaint.setColor(0xff000000);
|
||||||
|
textPaint.linkColor = 0xff316f9f;
|
||||||
|
textPaint.setTextSize(AndroidUtilities.dp(MessagesController.getInstance().fontSize));
|
||||||
|
}
|
||||||
|
return textPaint;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void generatePinMessageText(TLRPC.User fromUser, TLRPC.Chat chat) {
|
||||||
|
if (fromUser == null && chat == null) {
|
||||||
|
if (messageOwner.from_id > 0) {
|
||||||
|
fromUser = MessagesController.getInstance().getUser(messageOwner.from_id);
|
||||||
|
}
|
||||||
|
if (fromUser == null) {
|
||||||
|
chat = MessagesController.getInstance().getChat(messageOwner.to_id.channel_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (replyMessageObject == null) {
|
||||||
|
messageText = replaceWithLink(LocaleController.getString("ActionPinnedNoText", R.string.ActionPinnedNoText), "un1", fromUser != null ? fromUser : chat);
|
||||||
|
} else {
|
||||||
|
if (replyMessageObject.isMusic()) {
|
||||||
|
messageText = replaceWithLink(LocaleController.getString("ActionPinnedMusic", R.string.ActionPinnedMusic), "un1", fromUser != null ? fromUser : chat);
|
||||||
|
} else if (replyMessageObject.isVideo()) {
|
||||||
|
messageText = replaceWithLink(LocaleController.getString("ActionPinnedVideo", R.string.ActionPinnedVideo), "un1", fromUser != null ? fromUser : chat);
|
||||||
|
} else if (replyMessageObject.isGif()) {
|
||||||
|
messageText = replaceWithLink(LocaleController.getString("ActionPinnedGif", R.string.ActionPinnedGif), "un1", fromUser != null ? fromUser : chat);
|
||||||
|
} else if (replyMessageObject.isVoice()) {
|
||||||
|
messageText = replaceWithLink(LocaleController.getString("ActionPinnedVoice", R.string.ActionPinnedVoice), "un1", fromUser != null ? fromUser : chat);
|
||||||
|
} else if (replyMessageObject.isSticker()) {
|
||||||
|
messageText = replaceWithLink(LocaleController.getString("ActionPinnedSticker", R.string.ActionPinnedSticker), "un1", fromUser != null ? fromUser : chat);
|
||||||
|
} else if (replyMessageObject.messageOwner.media instanceof TLRPC.TL_messageMediaDocument) {
|
||||||
|
messageText = replaceWithLink(LocaleController.getString("ActionPinnedFile", R.string.ActionPinnedFile), "un1", fromUser != null ? fromUser : chat);
|
||||||
|
} else if (replyMessageObject.messageOwner.media instanceof TLRPC.TL_messageMediaGeo) {
|
||||||
|
messageText = replaceWithLink(LocaleController.getString("ActionPinnedGeo", R.string.ActionPinnedGeo), "un1", fromUser != null ? fromUser : chat);
|
||||||
|
} else if (replyMessageObject.messageOwner.media instanceof TLRPC.TL_messageMediaContact) {
|
||||||
|
messageText = replaceWithLink(LocaleController.getString("ActionPinnedContact", R.string.ActionPinnedContact), "un1", fromUser != null ? fromUser : chat);
|
||||||
|
} else if (replyMessageObject.messageOwner.media instanceof TLRPC.TL_messageMediaPhoto) {
|
||||||
|
messageText = replaceWithLink(LocaleController.getString("ActionPinnedPhoto", R.string.ActionPinnedPhoto), "un1", fromUser != null ? fromUser : chat);
|
||||||
|
} else if (replyMessageObject.messageText != null && replyMessageObject.messageText.length() > 0) {
|
||||||
|
CharSequence mess = replyMessageObject.messageText;
|
||||||
|
if (mess.length() > 20) {
|
||||||
|
mess = mess.subSequence(0, 20) + "...";
|
||||||
|
}
|
||||||
|
messageText = replaceWithLink(LocaleController.formatString("ActionPinnedText", R.string.ActionPinnedText, mess), "un1", fromUser != null ? fromUser : chat);
|
||||||
|
} else {
|
||||||
|
messageText = replaceWithLink(LocaleController.getString("ActionPinnedNoText", R.string.ActionPinnedNoText), "un1", fromUser != null ? fromUser : chat);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void checkLayout() {
|
public void checkLayout() {
|
||||||
if (!layoutCreated) {
|
if (!layoutCreated) {
|
||||||
layoutCreated = true;
|
layoutCreated = true;
|
||||||
|
@ -662,6 +667,8 @@ public class MessageObject {
|
||||||
return FileLoader.getAttachFileName(sizeFull);
|
return FileLoader.getAttachFileName(sizeFull);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else if (messageOwner.media instanceof TLRPC.TL_messageMediaWebPage) {
|
||||||
|
return FileLoader.getAttachFileName(messageOwner.media.webpage.document);
|
||||||
}
|
}
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
@ -950,7 +957,7 @@ public class MessageObject {
|
||||||
block.textLayout = textLayout;
|
block.textLayout = textLayout;
|
||||||
block.textYOffset = 0;
|
block.textYOffset = 0;
|
||||||
block.charactersOffset = 0;
|
block.charactersOffset = 0;
|
||||||
blockHeight = textHeight;
|
block.height = textHeight;
|
||||||
} else {
|
} else {
|
||||||
int startCharacter = textLayout.getLineStart(linesOffset);
|
int startCharacter = textLayout.getLineStart(linesOffset);
|
||||||
int endCharacter = textLayout.getLineEnd(linesOffset + currentBlockLinesCount - 1);
|
int endCharacter = textLayout.getLineEnd(linesOffset + currentBlockLinesCount - 1);
|
||||||
|
@ -963,16 +970,10 @@ public class MessageObject {
|
||||||
block.textLayout = new StaticLayout(str, textPaint, maxWidth, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false);
|
block.textLayout = new StaticLayout(str, textPaint, maxWidth, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false);
|
||||||
block.textYOffset = textLayout.getLineTop(linesOffset);
|
block.textYOffset = textLayout.getLineTop(linesOffset);
|
||||||
if (a != 0) {
|
if (a != 0) {
|
||||||
blockHeight = Math.min(blockHeight, (int) (block.textYOffset - prevOffset));
|
block.height = (int) (block.textYOffset - prevOffset);
|
||||||
}
|
}
|
||||||
|
block.height = Math.max(block.height, block.textLayout.getLineBottom(block.textLayout.getLineCount() - 1));
|
||||||
prevOffset = block.textYOffset;
|
prevOffset = block.textYOffset;
|
||||||
/*if (a != blocksCount - 1) {
|
|
||||||
int height = block.textLayout.getHeight();
|
|
||||||
blockHeight = Math.min(blockHeight, block.textLayout.getHeight());
|
|
||||||
prevOffset = block.textYOffset;
|
|
||||||
} else {
|
|
||||||
blockHeight = Math.min(blockHeight, (int)(block.textYOffset - prevOffset));
|
|
||||||
}*/
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
FileLog.e("tmessages", e);
|
FileLog.e("tmessages", e);
|
||||||
continue;
|
continue;
|
||||||
|
@ -1067,9 +1068,6 @@ public class MessageObject {
|
||||||
|
|
||||||
linesOffset += currentBlockLinesCount;
|
linesOffset += currentBlockLinesCount;
|
||||||
}
|
}
|
||||||
if (blockHeight == 0) {
|
|
||||||
blockHeight = 1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isOut() {
|
public boolean isOut() {
|
||||||
|
@ -1421,7 +1419,11 @@ public class MessageObject {
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isGif() {
|
public boolean isGif() {
|
||||||
return isGifDocument(messageOwner.media.document);
|
return messageOwner.media instanceof TLRPC.TL_messageMediaDocument && isGifDocument(messageOwner.media.document);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isWebpageDocument() {
|
||||||
|
return messageOwner.media instanceof TLRPC.TL_messageMediaWebPage && messageOwner.media.webpage.document != null && !isGifDocument(messageOwner.media.webpage.document);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isNewGif() {
|
public boolean isNewGif() {
|
||||||
|
@ -1512,16 +1514,16 @@ public class MessageObject {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean canEditMessage(TLRPC.Message message, TLRPC.Chat chat) {
|
public static boolean canEditMessage(TLRPC.Message message, TLRPC.Chat chat) {
|
||||||
if (message.action != null && !(message.action instanceof TLRPC.TL_messageActionEmpty) || isForwardedMessage(message) || message.via_bot_id != 0 || message.id < 0 || Math.abs(message.date - ConnectionsManager.getInstance().getCurrentTime()) > MessagesController.getInstance().maxEditTime) {
|
if (message == null || message.to_id == null || message.to_id.channel_id == 0 || message.action != null && !(message.action instanceof TLRPC.TL_messageActionEmpty) || isForwardedMessage(message) || message.via_bot_id != 0 || message.id < 0 || Math.abs(message.date - ConnectionsManager.getInstance().getCurrentTime()) > MessagesController.getInstance().maxEditTime) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (chat == null && message.to_id.channel_id != 0) {
|
if (chat == null && message.to_id.channel_id != 0) {
|
||||||
chat = MessagesController.getInstance().getChat(message.to_id.channel_id);
|
chat = MessagesController.getInstance().getChat(message.to_id.channel_id);
|
||||||
}
|
}
|
||||||
if (ChatObject.isChannel(chat) && chat.megagroup) {
|
if (chat == null) {
|
||||||
return message.out;
|
return false;
|
||||||
}
|
}
|
||||||
if (ChatObject.isChannel(chat) && !chat.megagroup && (chat.creator || chat.editor && isOut(message)) && isImportant(message)) {
|
if (chat.megagroup && message.out || !chat.megagroup && (chat.creator || chat.editor && isOut(message)) && isImportant(message)) {
|
||||||
if (message.media instanceof TLRPC.TL_messageMediaPhoto ||
|
if (message.media instanceof TLRPC.TL_messageMediaPhoto ||
|
||||||
message.media instanceof TLRPC.TL_messageMediaDocument && (isVideoMessage(message) || isGifDocument(message.media.document)) ||
|
message.media instanceof TLRPC.TL_messageMediaDocument && (isVideoMessage(message) || isGifDocument(message.media.document)) ||
|
||||||
message.media instanceof TLRPC.TL_messageMediaEmpty ||
|
message.media instanceof TLRPC.TL_messageMediaEmpty ||
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -19,6 +19,7 @@ import org.telegram.SQLite.SQLiteCursor;
|
||||||
import org.telegram.SQLite.SQLiteDatabase;
|
import org.telegram.SQLite.SQLiteDatabase;
|
||||||
import org.telegram.SQLite.SQLitePreparedStatement;
|
import org.telegram.SQLite.SQLitePreparedStatement;
|
||||||
import org.telegram.messenger.query.BotQuery;
|
import org.telegram.messenger.query.BotQuery;
|
||||||
|
import org.telegram.messenger.query.MessagesQuery;
|
||||||
import org.telegram.messenger.query.SharedMediaQuery;
|
import org.telegram.messenger.query.SharedMediaQuery;
|
||||||
import org.telegram.tgnet.ConnectionsManager;
|
import org.telegram.tgnet.ConnectionsManager;
|
||||||
import org.telegram.tgnet.NativeByteBuffer;
|
import org.telegram.tgnet.NativeByteBuffer;
|
||||||
|
@ -141,10 +142,16 @@ public class MessagesStorage {
|
||||||
database.executeFast("CREATE TABLE bot_keyboard(uid INTEGER PRIMARY KEY, mid INTEGER, info BLOB)").stepThis().dispose();
|
database.executeFast("CREATE TABLE bot_keyboard(uid INTEGER PRIMARY KEY, mid INTEGER, info BLOB)").stepThis().dispose();
|
||||||
database.executeFast("CREATE INDEX IF NOT EXISTS bot_keyboard_idx_mid ON bot_keyboard(mid);").stepThis().dispose();
|
database.executeFast("CREATE INDEX IF NOT EXISTS bot_keyboard_idx_mid ON bot_keyboard(mid);").stepThis().dispose();
|
||||||
|
|
||||||
|
database.executeFast("CREATE TABLE chat_settings_v2(uid INTEGER PRIMARY KEY, info BLOB, pinned INTEGER)").stepThis().dispose();
|
||||||
|
database.executeFast("CREATE INDEX IF NOT EXISTS chat_settings_pinned_idx ON chat_settings_v2(uid, pinned) WHERE pinned != 0;").stepThis().dispose();
|
||||||
|
|
||||||
|
database.executeFast("CREATE TABLE chat_pinned(uid INTEGER PRIMARY KEY, pinned INTEGER, data BLOB)").stepThis().dispose();
|
||||||
|
database.executeFast("CREATE INDEX IF NOT EXISTS chat_pinned_mid_idx ON chat_pinned(uid, pinned) WHERE pinned != 0;").stepThis().dispose();
|
||||||
|
|
||||||
|
database.executeFast("CREATE TABLE users_data(uid INTEGER PRIMARY KEY, about TEXT)").stepThis().dispose();
|
||||||
database.executeFast("CREATE TABLE users(uid INTEGER PRIMARY KEY, name TEXT, status INTEGER, data BLOB)").stepThis().dispose();
|
database.executeFast("CREATE TABLE users(uid INTEGER PRIMARY KEY, name TEXT, status INTEGER, data BLOB)").stepThis().dispose();
|
||||||
database.executeFast("CREATE TABLE chats(uid INTEGER PRIMARY KEY, name TEXT, data BLOB)").stepThis().dispose();
|
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)").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)").stepThis().dispose();
|
||||||
database.executeFast("CREATE TABLE chat_settings_v2(uid INTEGER PRIMARY KEY, info BLOB)").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_users_v2(did INTEGER, uid INTEGER, date INTEGER, data BLOB, PRIMARY KEY(did, uid))").stepThis().dispose();
|
||||||
database.executeFast("CREATE TABLE contacts(uid INTEGER PRIMARY KEY, mutual INTEGER)").stepThis().dispose();
|
database.executeFast("CREATE TABLE contacts(uid INTEGER PRIMARY KEY, mutual INTEGER)").stepThis().dispose();
|
||||||
database.executeFast("CREATE TABLE pending_read(uid INTEGER PRIMARY KEY, max_id INTEGER)").stepThis().dispose();
|
database.executeFast("CREATE TABLE pending_read(uid INTEGER PRIMARY KEY, max_id INTEGER)").stepThis().dispose();
|
||||||
|
@ -165,7 +172,7 @@ public class MessagesStorage {
|
||||||
database.executeFast("CREATE TABLE bot_info(uid INTEGER PRIMARY KEY, info BLOB)").stepThis().dispose();
|
database.executeFast("CREATE TABLE bot_info(uid INTEGER PRIMARY KEY, info BLOB)").stepThis().dispose();
|
||||||
|
|
||||||
//version
|
//version
|
||||||
database.executeFast("PRAGMA user_version = 30").stepThis().dispose();
|
database.executeFast("PRAGMA user_version = 31").stepThis().dispose();
|
||||||
|
|
||||||
//database.executeFast("CREATE TABLE secret_holes(uid INTEGER, seq_in INTEGER, seq_out INTEGER, data BLOB, PRIMARY KEY (uid, seq_in, seq_out));").stepThis().dispose();
|
//database.executeFast("CREATE TABLE secret_holes(uid INTEGER, seq_in INTEGER, seq_out INTEGER, data BLOB, PRIMARY KEY (uid, seq_in, seq_out));").stepThis().dispose();
|
||||||
//database.executeFast("CREATE TABLE attach_data(uid INTEGER, id INTEGER, data BLOB, PRIMARY KEY (uid, id))").stepThis().dispose();
|
//database.executeFast("CREATE TABLE attach_data(uid INTEGER, id INTEGER, data BLOB, PRIMARY KEY (uid, id))").stepThis().dispose();
|
||||||
|
@ -199,7 +206,7 @@ public class MessagesStorage {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
int version = database.executeInt("PRAGMA user_version");
|
int version = database.executeInt("PRAGMA user_version");
|
||||||
if (version < 30) {
|
if (version < 31) {
|
||||||
updateDbToLastVersion(version);
|
updateDbToLastVersion(version);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -487,7 +494,16 @@ public class MessagesStorage {
|
||||||
database.executeFast("DELETE FROM sent_files_v2 WHERE 1").stepThis().dispose();
|
database.executeFast("DELETE FROM sent_files_v2 WHERE 1").stepThis().dispose();
|
||||||
database.executeFast("DELETE FROM download_queue WHERE 1").stepThis().dispose();
|
database.executeFast("DELETE FROM download_queue WHERE 1").stepThis().dispose();
|
||||||
database.executeFast("PRAGMA user_version = 30").stepThis().dispose();
|
database.executeFast("PRAGMA user_version = 30").stepThis().dispose();
|
||||||
//version = 30;
|
version = 30;
|
||||||
|
}
|
||||||
|
if (version == 30) {
|
||||||
|
database.executeFast("ALTER TABLE chat_settings_v2 ADD COLUMN pinned INTEGER default 0").stepThis().dispose();
|
||||||
|
database.executeFast("CREATE INDEX IF NOT EXISTS chat_settings_pinned_idx ON chat_settings_v2(uid, pinned) WHERE pinned != 0;").stepThis().dispose();
|
||||||
|
database.executeFast("CREATE TABLE IF NOT EXISTS chat_pinned(uid INTEGER PRIMARY KEY, pinned INTEGER, data BLOB)").stepThis().dispose();
|
||||||
|
database.executeFast("CREATE INDEX IF NOT EXISTS chat_pinned_mid_idx ON chat_pinned(uid, pinned) WHERE pinned != 0;").stepThis().dispose();
|
||||||
|
database.executeFast("CREATE TABLE IF NOT EXISTS users_data(uid INTEGER PRIMARY KEY, about TEXT)").stepThis().dispose();
|
||||||
|
database.executeFast("PRAGMA user_version = 31").stepThis().dispose();
|
||||||
|
//version = 31;
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
FileLog.e("tmessages", e);
|
FileLog.e("tmessages", e);
|
||||||
|
@ -1012,22 +1028,22 @@ public class MessagesStorage {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public void deleteDialog(final long did, final int messagesOnly) {
|
public void deleteUserChannelHistory(final int channelId, final int uid) {
|
||||||
storageQueue.postRunnable(new Runnable() {
|
storageQueue.postRunnable(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
try {
|
try {
|
||||||
if ((int) did == 0 || messagesOnly == 2) {
|
long did = -channelId;
|
||||||
SQLiteCursor cursor = database.queryFinalized("SELECT data FROM messages WHERE uid = " + did);
|
final ArrayList<Integer> mids = new ArrayList<>();
|
||||||
ArrayList<File> filesToDelete = new ArrayList<>();
|
SQLiteCursor cursor = database.queryFinalized("SELECT data FROM messages WHERE uid = " + did);
|
||||||
try {
|
ArrayList<File> filesToDelete = new ArrayList<>();
|
||||||
while (cursor.next()) {
|
try {
|
||||||
NativeByteBuffer data = new NativeByteBuffer(cursor.byteArrayLength(0));
|
while (cursor.next()) {
|
||||||
if (data != null && cursor.byteBufferValue(0, data) != 0) {
|
NativeByteBuffer data = new NativeByteBuffer(cursor.byteArrayLength(0));
|
||||||
TLRPC.Message message = TLRPC.Message.TLdeserialize(data, data.readInt32(false), false);
|
if (data != null && cursor.byteBufferValue(0, data) != 0) {
|
||||||
if (message == null || message.media == null) {
|
TLRPC.Message message = TLRPC.Message.TLdeserialize(data, data.readInt32(false), false);
|
||||||
continue;
|
if (message != null && message.from_id == uid && message.id != 1) {
|
||||||
}
|
mids.add(message.id);
|
||||||
if (message.media instanceof TLRPC.TL_messageMediaPhoto) {
|
if (message.media instanceof TLRPC.TL_messageMediaPhoto) {
|
||||||
for (TLRPC.PhotoSize photoSize : message.media.photo.sizes) {
|
for (TLRPC.PhotoSize photoSize : message.media.photo.sizes) {
|
||||||
File file = FileLoader.getPathToAttach(photoSize);
|
File file = FileLoader.getPathToAttach(photoSize);
|
||||||
|
@ -1046,6 +1062,70 @@ public class MessagesStorage {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
data.reuse();
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
FileLog.e("tmessages", e);
|
||||||
|
}
|
||||||
|
cursor.dispose();
|
||||||
|
AndroidUtilities.runOnUIThread(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
MessagesController.getInstance().markChannelDialogMessageAsDeleted(mids, channelId);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
markMessagesAsDeletedInternal(mids, channelId);
|
||||||
|
updateDialogsWithDeletedMessagesInternal(mids, channelId);
|
||||||
|
FileLoader.getInstance().deleteFiles(filesToDelete, 0);
|
||||||
|
if (!mids.isEmpty()) {
|
||||||
|
AndroidUtilities.runOnUIThread(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
NotificationCenter.getInstance().postNotificationName(NotificationCenter.messagesDeleted, mids, channelId);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
FileLog.e("tmessages", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public void deleteDialog(final long did, final int messagesOnly) {
|
||||||
|
storageQueue.postRunnable(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
try {
|
||||||
|
if ((int) did == 0 || messagesOnly == 2) {
|
||||||
|
SQLiteCursor cursor = database.queryFinalized("SELECT data FROM messages WHERE uid = " + did);
|
||||||
|
ArrayList<File> filesToDelete = new ArrayList<>();
|
||||||
|
try {
|
||||||
|
while (cursor.next()) {
|
||||||
|
NativeByteBuffer data = new NativeByteBuffer(cursor.byteArrayLength(0));
|
||||||
|
if (data != null && cursor.byteBufferValue(0, data) != 0) {
|
||||||
|
TLRPC.Message message = TLRPC.Message.TLdeserialize(data, data.readInt32(false), false);
|
||||||
|
if (message != null && message.media != null) {
|
||||||
|
if (message.media instanceof TLRPC.TL_messageMediaPhoto) {
|
||||||
|
for (TLRPC.PhotoSize photoSize : message.media.photo.sizes) {
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
file = FileLoader.getPathToAttach(message.media.document.thumb);
|
||||||
|
if (file != null && file.toString().length() > 0) {
|
||||||
|
filesToDelete.add(file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
data.reuse();
|
data.reuse();
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
|
@ -1058,6 +1138,7 @@ public class MessagesStorage {
|
||||||
if (messagesOnly == 0) {
|
if (messagesOnly == 0) {
|
||||||
database.executeFast("DELETE FROM dialogs WHERE did = " + did).stepThis().dispose();
|
database.executeFast("DELETE FROM dialogs WHERE did = " + did).stepThis().dispose();
|
||||||
database.executeFast("DELETE FROM chat_settings_v2 WHERE uid = " + did).stepThis().dispose();
|
database.executeFast("DELETE FROM chat_settings_v2 WHERE uid = " + did).stepThis().dispose();
|
||||||
|
database.executeFast("DELETE FROM chat_pinned WHERE uid = " + did).stepThis().dispose();
|
||||||
database.executeFast("DELETE FROM channel_users_v2 WHERE did = " + did).stepThis().dispose();
|
database.executeFast("DELETE FROM channel_users_v2 WHERE did = " + did).stepThis().dispose();
|
||||||
database.executeFast("DELETE FROM search_recent WHERE did = " + did).stepThis().dispose();
|
database.executeFast("DELETE FROM search_recent WHERE did = " + did).stepThis().dispose();
|
||||||
int lower_id = (int)did;
|
int lower_id = (int)did;
|
||||||
|
@ -1084,10 +1165,9 @@ public class MessagesStorage {
|
||||||
NativeByteBuffer data = new NativeByteBuffer(cursor2.byteArrayLength(0));
|
NativeByteBuffer data = new NativeByteBuffer(cursor2.byteArrayLength(0));
|
||||||
if (data != null && cursor2.byteBufferValue(0, data) != 0) {
|
if (data != null && cursor2.byteBufferValue(0, data) != 0) {
|
||||||
TLRPC.Message message = TLRPC.Message.TLdeserialize(data, data.readInt32(false), false);
|
TLRPC.Message message = TLRPC.Message.TLdeserialize(data, data.readInt32(false), false);
|
||||||
if (message == null) {
|
if (message != null) {
|
||||||
continue;
|
arrayList.add(message);
|
||||||
}
|
}
|
||||||
arrayList.add(message);
|
|
||||||
}
|
}
|
||||||
data.reuse();
|
data.reuse();
|
||||||
}
|
}
|
||||||
|
@ -1429,13 +1509,14 @@ public class MessagesStorage {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
try {
|
try {
|
||||||
SQLiteCursor cursor = database.queryFinalized("SELECT info FROM chat_settings_v2 WHERE uid = " + participants.chat_id);
|
SQLiteCursor cursor = database.queryFinalized("SELECT info, pinned FROM chat_settings_v2 WHERE uid = " + participants.chat_id);
|
||||||
TLRPC.ChatFull info = null;
|
TLRPC.ChatFull info = null;
|
||||||
ArrayList<TLRPC.User> loadedUsers = new ArrayList<>();
|
ArrayList<TLRPC.User> loadedUsers = new ArrayList<>();
|
||||||
if (cursor.next()) {
|
if (cursor.next()) {
|
||||||
NativeByteBuffer data = new NativeByteBuffer(cursor.byteArrayLength(0));
|
NativeByteBuffer data = new NativeByteBuffer(cursor.byteArrayLength(0));
|
||||||
if (data != null && cursor.byteBufferValue(0, data) != 0) {
|
if (data != null && cursor.byteBufferValue(0, data) != 0) {
|
||||||
info = TLRPC.ChatFull.TLdeserialize(data, data.readInt32(false), false);
|
info = TLRPC.ChatFull.TLdeserialize(data, data.readInt32(false), false);
|
||||||
|
info.pinned_msg_id = cursor.intValue(1);
|
||||||
}
|
}
|
||||||
data.reuse();
|
data.reuse();
|
||||||
}
|
}
|
||||||
|
@ -1446,15 +1527,16 @@ public class MessagesStorage {
|
||||||
AndroidUtilities.runOnUIThread(new Runnable() {
|
AndroidUtilities.runOnUIThread(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
NotificationCenter.getInstance().postNotificationName(NotificationCenter.chatInfoDidLoaded, finalInfo, 0, false);
|
NotificationCenter.getInstance().postNotificationName(NotificationCenter.chatInfoDidLoaded, finalInfo, 0, false, null);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
SQLitePreparedStatement state = database.executeFast("REPLACE INTO chat_settings_v2 VALUES(?, ?)");
|
SQLitePreparedStatement state = database.executeFast("REPLACE INTO chat_settings_v2 VALUES(?, ?, ?)");
|
||||||
NativeByteBuffer data = new NativeByteBuffer(info.getObjectSize());
|
NativeByteBuffer data = new NativeByteBuffer(info.getObjectSize());
|
||||||
info.serializeToStream(data);
|
info.serializeToStream(data);
|
||||||
state.bindInteger(1, info.id);
|
state.bindInteger(1, info.id);
|
||||||
state.bindByteBuffer(2, data);
|
state.bindByteBuffer(2, data);
|
||||||
|
state.bindInteger(3, info.pinned_msg_id);
|
||||||
state.step();
|
state.step();
|
||||||
state.dispose();
|
state.dispose();
|
||||||
data.reuse();
|
data.reuse();
|
||||||
|
@ -1516,11 +1598,12 @@ public class MessagesStorage {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
SQLitePreparedStatement state = database.executeFast("REPLACE INTO chat_settings_v2 VALUES(?, ?)");
|
SQLitePreparedStatement state = database.executeFast("REPLACE INTO chat_settings_v2 VALUES(?, ?, ?)");
|
||||||
NativeByteBuffer data = new NativeByteBuffer(info.getObjectSize());
|
NativeByteBuffer data = new NativeByteBuffer(info.getObjectSize());
|
||||||
info.serializeToStream(data);
|
info.serializeToStream(data);
|
||||||
state.bindInteger(1, info.id);
|
state.bindInteger(1, info.id);
|
||||||
state.bindByteBuffer(2, data);
|
state.bindByteBuffer(2, data);
|
||||||
|
state.bindInteger(3, info.pinned_msg_id);
|
||||||
state.step();
|
state.step();
|
||||||
state.dispose();
|
state.dispose();
|
||||||
data.reuse();
|
data.reuse();
|
||||||
|
@ -1557,18 +1640,65 @@ public class MessagesStorage {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void updateChannelPinnedMessage(final int channelId, final int messageId) {
|
||||||
|
storageQueue.postRunnable(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
try {
|
||||||
|
SQLiteCursor cursor = database.queryFinalized("SELECT info, pinned FROM chat_settings_v2 WHERE uid = " + channelId);
|
||||||
|
TLRPC.ChatFull info = null;
|
||||||
|
ArrayList<TLRPC.User> loadedUsers = new ArrayList<>();
|
||||||
|
if (cursor.next()) {
|
||||||
|
NativeByteBuffer data = new NativeByteBuffer(cursor.byteArrayLength(0));
|
||||||
|
if (cursor.byteBufferValue(0, data) != 0) {
|
||||||
|
info = TLRPC.ChatFull.TLdeserialize(data, data.readInt32(false), false);
|
||||||
|
info.pinned_msg_id = cursor.intValue(1);
|
||||||
|
}
|
||||||
|
data.reuse();
|
||||||
|
}
|
||||||
|
cursor.dispose();
|
||||||
|
if (info instanceof TLRPC.TL_channelFull) {
|
||||||
|
info.pinned_msg_id = messageId;
|
||||||
|
info.flags |= 32;
|
||||||
|
|
||||||
|
final TLRPC.ChatFull finalInfo = info;
|
||||||
|
AndroidUtilities.runOnUIThread(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
NotificationCenter.getInstance().postNotificationName(NotificationCenter.chatInfoDidLoaded, finalInfo, 0, false, null);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
SQLitePreparedStatement state = database.executeFast("REPLACE INTO chat_settings_v2 VALUES(?, ?, ?)");
|
||||||
|
NativeByteBuffer data = new NativeByteBuffer(info.getObjectSize());
|
||||||
|
info.serializeToStream(data);
|
||||||
|
state.bindInteger(1, channelId);
|
||||||
|
state.bindByteBuffer(2, data);
|
||||||
|
state.bindInteger(3, info.pinned_msg_id);
|
||||||
|
state.step();
|
||||||
|
state.dispose();
|
||||||
|
data.reuse();
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
FileLog.e("tmessages", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
public void updateChatInfo(final int chat_id, final int user_id, final int what, final int invited_id, final int version) {
|
public void updateChatInfo(final int chat_id, final int user_id, final int what, final int invited_id, final int version) {
|
||||||
storageQueue.postRunnable(new Runnable() {
|
storageQueue.postRunnable(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
try {
|
try {
|
||||||
SQLiteCursor cursor = database.queryFinalized("SELECT info FROM chat_settings_v2 WHERE uid = " + chat_id);
|
SQLiteCursor cursor = database.queryFinalized("SELECT info, pinned FROM chat_settings_v2 WHERE uid = " + chat_id);
|
||||||
TLRPC.ChatFull info = null;
|
TLRPC.ChatFull info = null;
|
||||||
ArrayList<TLRPC.User> loadedUsers = new ArrayList<>();
|
ArrayList<TLRPC.User> loadedUsers = new ArrayList<>();
|
||||||
if (cursor.next()) {
|
if (cursor.next()) {
|
||||||
NativeByteBuffer data = new NativeByteBuffer(cursor.byteArrayLength(0));
|
NativeByteBuffer data = new NativeByteBuffer(cursor.byteArrayLength(0));
|
||||||
if (data != null && cursor.byteBufferValue(0, data) != 0) {
|
if (data != null && cursor.byteBufferValue(0, data) != 0) {
|
||||||
info = TLRPC.ChatFull.TLdeserialize(data, data.readInt32(false), false);
|
info = TLRPC.ChatFull.TLdeserialize(data, data.readInt32(false), false);
|
||||||
|
info.pinned_msg_id = cursor.intValue(1);
|
||||||
}
|
}
|
||||||
data.reuse();
|
data.reuse();
|
||||||
}
|
}
|
||||||
|
@ -1620,15 +1750,16 @@ public class MessagesStorage {
|
||||||
AndroidUtilities.runOnUIThread(new Runnable() {
|
AndroidUtilities.runOnUIThread(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
NotificationCenter.getInstance().postNotificationName(NotificationCenter.chatInfoDidLoaded, finalInfo, 0, false);
|
NotificationCenter.getInstance().postNotificationName(NotificationCenter.chatInfoDidLoaded, finalInfo, 0, false, null);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
SQLitePreparedStatement state = database.executeFast("REPLACE INTO chat_settings_v2 VALUES(?, ?)");
|
SQLitePreparedStatement state = database.executeFast("REPLACE INTO chat_settings_v2 VALUES(?, ?, ?)");
|
||||||
NativeByteBuffer data = new NativeByteBuffer(info.getObjectSize());
|
NativeByteBuffer data = new NativeByteBuffer(info.getObjectSize());
|
||||||
info.serializeToStream(data);
|
info.serializeToStream(data);
|
||||||
state.bindInteger(1, chat_id);
|
state.bindInteger(1, chat_id);
|
||||||
state.bindByteBuffer(2, data);
|
state.bindByteBuffer(2, data);
|
||||||
|
state.bindInteger(3, info.pinned_msg_id);
|
||||||
state.step();
|
state.step();
|
||||||
state.dispose();
|
state.dispose();
|
||||||
data.reuse();
|
data.reuse();
|
||||||
|
@ -1684,13 +1815,14 @@ public class MessagesStorage {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
try {
|
try {
|
||||||
SQLiteCursor cursor = database.queryFinalized("SELECT info FROM chat_settings_v2 WHERE uid = " + chat_id);
|
SQLiteCursor cursor = database.queryFinalized("SELECT info, pinned FROM chat_settings_v2 WHERE uid = " + chat_id);
|
||||||
TLRPC.ChatFull info = null;
|
TLRPC.ChatFull info = null;
|
||||||
ArrayList<TLRPC.User> loadedUsers = new ArrayList<>();
|
ArrayList<TLRPC.User> loadedUsers = new ArrayList<>();
|
||||||
if (cursor.next()) {
|
if (cursor.next()) {
|
||||||
NativeByteBuffer data = new NativeByteBuffer(cursor.byteArrayLength(0));
|
NativeByteBuffer data = new NativeByteBuffer(cursor.byteArrayLength(0));
|
||||||
if (data != null && cursor.byteBufferValue(0, data) != 0) {
|
if (data != null && cursor.byteBufferValue(0, data) != 0) {
|
||||||
info = TLRPC.ChatFull.TLdeserialize(data, data.readInt32(false), false);
|
info = TLRPC.ChatFull.TLdeserialize(data, data.readInt32(false), false);
|
||||||
|
info.pinned_msg_id = cursor.intValue(1);
|
||||||
}
|
}
|
||||||
data.reuse();
|
data.reuse();
|
||||||
}
|
}
|
||||||
|
@ -1754,7 +1886,12 @@ public class MessagesStorage {
|
||||||
if (semaphore != null) {
|
if (semaphore != null) {
|
||||||
semaphore.release();
|
semaphore.release();
|
||||||
}
|
}
|
||||||
MessagesController.getInstance().processChatInfo(chat_id, info, loadedUsers, true, force, byChannelUsers);
|
MessageObject pinnedMessageObject = null;
|
||||||
|
if (info instanceof TLRPC.TL_channelFull && info.pinned_msg_id != 0) {
|
||||||
|
pinnedMessageObject = MessagesQuery.loadPinnedMessage(chat_id, info.pinned_msg_id, false);
|
||||||
|
}
|
||||||
|
MessagesController.getInstance().processChatInfo(chat_id, info, loadedUsers, true, force, byChannelUsers, pinnedMessageObject);
|
||||||
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
FileLog.e("tmessages", e);
|
FileLog.e("tmessages", e);
|
||||||
} finally {
|
} finally {
|
||||||
|
@ -2281,7 +2418,7 @@ public class MessagesStorage {
|
||||||
holeMessageMinId |= ((long) channelId) << 32;
|
holeMessageMinId |= ((long) channelId) << 32;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/*if (holeMessageMaxId == holeMessageMinId) { TODO ???
|
/*if (holeMessageMaxId == holeMessageMinId) {
|
||||||
holeMessageMaxId = 0;
|
holeMessageMaxId = 0;
|
||||||
holeMessageMinId = 1;
|
holeMessageMinId = 1;
|
||||||
}*/
|
}*/
|
||||||
|
@ -2422,19 +2559,17 @@ public class MessagesStorage {
|
||||||
addUsersAndChatsFromMessage(message, usersToLoad, chatsToLoad);
|
addUsersAndChatsFromMessage(message, usersToLoad, chatsToLoad);
|
||||||
|
|
||||||
if (message.reply_to_msg_id != 0 || message.reply_to_random_id != 0) {
|
if (message.reply_to_msg_id != 0 || message.reply_to_random_id != 0) {
|
||||||
boolean ok = false;
|
|
||||||
if (!cursor.isNull(6)) {
|
if (!cursor.isNull(6)) {
|
||||||
NativeByteBuffer data2 = new NativeByteBuffer(cursor.byteArrayLength(6));
|
NativeByteBuffer data2 = new NativeByteBuffer(cursor.byteArrayLength(6));
|
||||||
if (data2 != null && cursor.byteBufferValue(6, data2) != 0) {
|
if (data2 != null && cursor.byteBufferValue(6, data2) != 0) {
|
||||||
message.replyMessage = TLRPC.Message.TLdeserialize(data2, data2.readInt32(false), false);
|
message.replyMessage = TLRPC.Message.TLdeserialize(data2, data2.readInt32(false), false);
|
||||||
if (message.replyMessage != null) {
|
if (message.replyMessage != null) {
|
||||||
addUsersAndChatsFromMessage(message.replyMessage, usersToLoad, chatsToLoad);
|
addUsersAndChatsFromMessage(message.replyMessage, usersToLoad, chatsToLoad);
|
||||||
ok = true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
data2.reuse();
|
data2.reuse();
|
||||||
}
|
}
|
||||||
if (!ok) {
|
if (message.replyMessage == null) {
|
||||||
if (message.reply_to_msg_id != 0) {
|
if (message.reply_to_msg_id != 0) {
|
||||||
long messageId = message.reply_to_msg_id;
|
long messageId = message.reply_to_msg_id;
|
||||||
if (message.to_id.channel_id != 0) {
|
if (message.to_id.channel_id != 0) {
|
||||||
|
@ -3037,7 +3172,7 @@ public class MessagesStorage {
|
||||||
NativeByteBuffer data = new NativeByteBuffer(cursor.byteArrayLength(0));
|
NativeByteBuffer data = new NativeByteBuffer(cursor.byteArrayLength(0));
|
||||||
if (data != null && cursor.byteBufferValue(0, data) != 0) {
|
if (data != null && cursor.byteBufferValue(0, data) != 0) {
|
||||||
TLRPC.User oldUser = TLRPC.User.TLdeserialize(data, data.readInt32(false), false);
|
TLRPC.User oldUser = TLRPC.User.TLdeserialize(data, data.readInt32(false), false);
|
||||||
if (user != null) {
|
if (oldUser != null) {
|
||||||
if (user.first_name != null) {
|
if (user.first_name != null) {
|
||||||
oldUser.first_name = user.first_name;
|
oldUser.first_name = user.first_name;
|
||||||
oldUser.flags |= 2;
|
oldUser.flags |= 2;
|
||||||
|
@ -3052,6 +3187,13 @@ public class MessagesStorage {
|
||||||
oldUser.last_name = null;
|
oldUser.last_name = null;
|
||||||
oldUser.flags = oldUser.flags &~ 4;
|
oldUser.flags = oldUser.flags &~ 4;
|
||||||
}
|
}
|
||||||
|
if (user.username != null) {
|
||||||
|
oldUser.username = user.username;
|
||||||
|
oldUser.flags |= 8;
|
||||||
|
} else {
|
||||||
|
oldUser.username = null;
|
||||||
|
oldUser.flags = oldUser.flags &~ 8;
|
||||||
|
}
|
||||||
if (user.photo != null) {
|
if (user.photo != null) {
|
||||||
oldUser.photo = user.photo;
|
oldUser.photo = user.photo;
|
||||||
oldUser.flags |= 32;
|
oldUser.flags |= 32;
|
||||||
|
@ -3059,8 +3201,8 @@ public class MessagesStorage {
|
||||||
oldUser.photo = null;
|
oldUser.photo = null;
|
||||||
oldUser.flags = oldUser.flags &~ 32;
|
oldUser.flags = oldUser.flags &~ 32;
|
||||||
}
|
}
|
||||||
|
user = oldUser;
|
||||||
}
|
}
|
||||||
user = oldUser;
|
|
||||||
}
|
}
|
||||||
data.reuse();
|
data.reuse();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
|
@ -3099,6 +3241,36 @@ public class MessagesStorage {
|
||||||
SQLitePreparedStatement state = database.executeFast("REPLACE INTO chats VALUES(?, ?, ?)");
|
SQLitePreparedStatement state = database.executeFast("REPLACE INTO chats VALUES(?, ?, ?)");
|
||||||
for (int a = 0; a < chats.size(); a++) {
|
for (int a = 0; a < chats.size(); a++) {
|
||||||
TLRPC.Chat chat = chats.get(a);
|
TLRPC.Chat chat = chats.get(a);
|
||||||
|
if (chat.min) {
|
||||||
|
SQLiteCursor cursor = database.queryFinalized(String.format(Locale.US, "SELECT data FROM chats WHERE uid = %d", chat.id));
|
||||||
|
if (cursor.next()) {
|
||||||
|
try {
|
||||||
|
NativeByteBuffer data = new NativeByteBuffer(cursor.byteArrayLength(0));
|
||||||
|
if (data != null && cursor.byteBufferValue(0, data) != 0) {
|
||||||
|
TLRPC.Chat oldChat = TLRPC.Chat.TLdeserialize(data, data.readInt32(false), false);
|
||||||
|
if (oldChat != null) {
|
||||||
|
oldChat.title = chat.title;
|
||||||
|
oldChat.photo = chat.photo;
|
||||||
|
oldChat.broadcast = chat.broadcast;
|
||||||
|
oldChat.verified = chat.verified;
|
||||||
|
oldChat.megagroup = chat.megagroup;
|
||||||
|
oldChat.democracy = chat.democracy;
|
||||||
|
if (chat.username != null) {
|
||||||
|
oldChat.username = chat.username;
|
||||||
|
oldChat.flags |= 64;
|
||||||
|
} else {
|
||||||
|
oldChat.username = null;
|
||||||
|
oldChat.flags = oldChat.flags &~ 64;
|
||||||
|
}
|
||||||
|
chat = oldChat;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
data.reuse();
|
||||||
|
} catch (Exception e) {
|
||||||
|
FileLog.e("tmessages", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
state.requery();
|
state.requery();
|
||||||
NativeByteBuffer data = new NativeByteBuffer(chat.getObjectSize());
|
NativeByteBuffer data = new NativeByteBuffer(chat.getObjectSize());
|
||||||
chat.serializeToStream(data);
|
chat.serializeToStream(data);
|
||||||
|
@ -4119,7 +4291,6 @@ public class MessagesStorage {
|
||||||
} catch (Exception e2) {
|
} catch (Exception e2) {
|
||||||
FileLog.e("tmessages", e2);
|
FileLog.e("tmessages", e2);
|
||||||
}
|
}
|
||||||
FileLog.e("tmessages", e);
|
|
||||||
} finally {
|
} finally {
|
||||||
if (state != null) {
|
if (state != null) {
|
||||||
state.dispose();
|
state.dispose();
|
||||||
|
@ -4138,7 +4309,6 @@ public class MessagesStorage {
|
||||||
} catch (Exception e2) {
|
} catch (Exception e2) {
|
||||||
FileLog.e("tmessages", e2);
|
FileLog.e("tmessages", e2);
|
||||||
}
|
}
|
||||||
FileLog.e("tmessages", e);
|
|
||||||
} finally {
|
} finally {
|
||||||
if (state != null) {
|
if (state != null) {
|
||||||
state.dispose();
|
state.dispose();
|
||||||
|
@ -4388,24 +4558,23 @@ public class MessagesStorage {
|
||||||
NativeByteBuffer data = new NativeByteBuffer(cursor.byteArrayLength(1));
|
NativeByteBuffer data = new NativeByteBuffer(cursor.byteArrayLength(1));
|
||||||
if (data != null && cursor.byteBufferValue(1, data) != 0) {
|
if (data != null && cursor.byteBufferValue(1, data) != 0) {
|
||||||
TLRPC.Message message = TLRPC.Message.TLdeserialize(data, data.readInt32(false), false);
|
TLRPC.Message message = TLRPC.Message.TLdeserialize(data, data.readInt32(false), false);
|
||||||
if (message == null || message.media == null) {
|
if (message != null && message.media != null) {
|
||||||
continue;
|
if (message.media instanceof TLRPC.TL_messageMediaPhoto) {
|
||||||
}
|
for (TLRPC.PhotoSize photoSize : message.media.photo.sizes) {
|
||||||
if (message.media instanceof TLRPC.TL_messageMediaPhoto) {
|
File file = FileLoader.getPathToAttach(photoSize);
|
||||||
for (TLRPC.PhotoSize photoSize : message.media.photo.sizes) {
|
if (file != null && file.toString().length() > 0) {
|
||||||
File file = FileLoader.getPathToAttach(photoSize);
|
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);
|
||||||
|
}
|
||||||
|
file = FileLoader.getPathToAttach(message.media.document.thumb);
|
||||||
if (file != null && file.toString().length() > 0) {
|
if (file != null && file.toString().length() > 0) {
|
||||||
filesToDelete.add(file);
|
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);
|
|
||||||
}
|
|
||||||
file = FileLoader.getPathToAttach(message.media.document.thumb);
|
|
||||||
if (file != null && file.toString().length() > 0) {
|
|
||||||
filesToDelete.add(file);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5136,7 +5305,9 @@ public class MessagesStorage {
|
||||||
usersToLoad.add(UserConfig.getClientUserId());
|
usersToLoad.add(UserConfig.getClientUserId());
|
||||||
ArrayList<Integer> chatsToLoad = new ArrayList<>();
|
ArrayList<Integer> chatsToLoad = new ArrayList<>();
|
||||||
ArrayList<Integer> encryptedToLoad = new ArrayList<>();
|
ArrayList<Integer> encryptedToLoad = new ArrayList<>();
|
||||||
SQLiteCursor cursor = database.queryFinalized(String.format(Locale.US, "SELECT d.did, d.last_mid, d.unread_count, d.date, m.data, m.read_state, m.mid, m.send_state, s.flags, m.date, d.last_mid_i, d.unread_count_i, d.pts, d.inbox_max, d.date_i FROM dialogs as d LEFT JOIN messages as m ON d.last_mid = m.mid LEFT JOIN dialog_settings as s ON d.did = s.did ORDER BY d.date DESC LIMIT %d,%d", offset, count));
|
ArrayList<Long> replyMessages = new ArrayList<>();
|
||||||
|
HashMap<Long, TLRPC.Message> replyMessageOwners = new HashMap<>();
|
||||||
|
SQLiteCursor cursor = database.queryFinalized(String.format(Locale.US, "SELECT d.did, d.last_mid, d.unread_count, d.date, m.data, m.read_state, m.mid, m.send_state, s.flags, m.date, d.last_mid_i, d.unread_count_i, d.pts, d.inbox_max, d.date_i, m.replydata FROM dialogs as d LEFT JOIN messages as m ON d.last_mid = m.mid LEFT JOIN dialog_settings as s ON d.did = s.did ORDER BY d.date DESC LIMIT %d,%d", offset, count));
|
||||||
while (cursor.next()) {
|
while (cursor.next()) {
|
||||||
TLRPC.Dialog dialog;
|
TLRPC.Dialog dialog;
|
||||||
int pts = cursor.intValue(12);
|
int pts = cursor.intValue(12);
|
||||||
|
@ -5181,6 +5352,33 @@ public class MessagesStorage {
|
||||||
dialogs.messages.add(message);
|
dialogs.messages.add(message);
|
||||||
|
|
||||||
addUsersAndChatsFromMessage(message, usersToLoad, chatsToLoad);
|
addUsersAndChatsFromMessage(message, usersToLoad, chatsToLoad);
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (message.reply_to_msg_id != 0 && message.action instanceof TLRPC.TL_messageActionPinMessage) {
|
||||||
|
if (!cursor.isNull(15)) {
|
||||||
|
NativeByteBuffer data2 = new NativeByteBuffer(cursor.byteArrayLength(15));
|
||||||
|
if (cursor.byteBufferValue(15, data2) != 0) {
|
||||||
|
message.replyMessage = TLRPC.Message.TLdeserialize(data2, data2.readInt32(false), false);
|
||||||
|
if (message.replyMessage != null) {
|
||||||
|
addUsersAndChatsFromMessage(message.replyMessage, usersToLoad, chatsToLoad);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
data2.reuse();
|
||||||
|
}
|
||||||
|
if (message.replyMessage == null) {
|
||||||
|
long messageId = message.reply_to_msg_id;
|
||||||
|
if (message.to_id.channel_id != 0) {
|
||||||
|
messageId |= ((long) message.to_id.channel_id) << 32;
|
||||||
|
}
|
||||||
|
if (!replyMessages.contains(messageId)) {
|
||||||
|
replyMessages.add(messageId);
|
||||||
|
}
|
||||||
|
replyMessageOwners.put(dialog.id, message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
FileLog.e("tmessages", e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
data.reuse();
|
data.reuse();
|
||||||
|
@ -5211,6 +5409,29 @@ public class MessagesStorage {
|
||||||
}
|
}
|
||||||
cursor.dispose();
|
cursor.dispose();
|
||||||
|
|
||||||
|
if (!replyMessages.isEmpty()) {
|
||||||
|
cursor = database.queryFinalized(String.format(Locale.US, "SELECT data, mid, date, uid FROM messages WHERE mid IN(%s)", TextUtils.join(",", replyMessages)));
|
||||||
|
while (cursor.next()) {
|
||||||
|
NativeByteBuffer data = new NativeByteBuffer(cursor.byteArrayLength(0));
|
||||||
|
if (data != null && cursor.byteBufferValue(0, data) != 0) {
|
||||||
|
TLRPC.Message message = TLRPC.Message.TLdeserialize(data, data.readInt32(false), false);
|
||||||
|
message.id = cursor.intValue(1);
|
||||||
|
message.date = cursor.intValue(2);
|
||||||
|
message.dialog_id = cursor.longValue(3);
|
||||||
|
|
||||||
|
addUsersAndChatsFromMessage(message, usersToLoad, chatsToLoad);
|
||||||
|
|
||||||
|
TLRPC.Message owner = replyMessageOwners.get(message.dialog_id);
|
||||||
|
if (owner != null) {
|
||||||
|
owner.replyMessage = message;
|
||||||
|
message.dialog_id = owner.dialog_id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
data.reuse();
|
||||||
|
}
|
||||||
|
cursor.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
if (!encryptedToLoad.isEmpty()) {
|
if (!encryptedToLoad.isEmpty()) {
|
||||||
getEncryptedChatsInternal(TextUtils.join(",", encryptedToLoad), encryptedChats, usersToLoad);
|
getEncryptedChatsInternal(TextUtils.join(",", encryptedToLoad), encryptedChats, usersToLoad);
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,7 +23,7 @@ import java.util.zip.ZipFile;
|
||||||
|
|
||||||
public class NativeLoader {
|
public class NativeLoader {
|
||||||
|
|
||||||
private final static int LIB_VERSION = 19;
|
private final static int LIB_VERSION = 20;
|
||||||
private final static String LIB_NAME = "tmessages." + LIB_VERSION;
|
private final static String LIB_NAME = "tmessages." + LIB_VERSION;
|
||||||
private final static String LIB_SO_NAME = "lib" + LIB_NAME + ".so";
|
private final static String LIB_SO_NAME = "lib" + LIB_NAME + ".so";
|
||||||
private final static String LOCALE_LIB_SO_NAME = "lib" + LIB_NAME + "loc.so";
|
private final static String LOCALE_LIB_SO_NAME = "lib" + LIB_NAME + "loc.so";
|
||||||
|
|
|
@ -53,6 +53,7 @@ public class NotificationCenter {
|
||||||
public static final int didSetTwoStepPassword = totalEvents++;
|
public static final int didSetTwoStepPassword = totalEvents++;
|
||||||
public static final int screenStateChanged = totalEvents++;
|
public static final int screenStateChanged = totalEvents++;
|
||||||
public static final int didLoadedReplyMessages = totalEvents++;
|
public static final int didLoadedReplyMessages = totalEvents++;
|
||||||
|
public static final int didLoadedPinnedMessage = totalEvents++;
|
||||||
public static final int newSessionReceived = totalEvents++;
|
public static final int newSessionReceived = totalEvents++;
|
||||||
public static final int didReceivedWebpages = totalEvents++;
|
public static final int didReceivedWebpages = totalEvents++;
|
||||||
public static final int didReceivedWebpagesInUpdates = totalEvents++;
|
public static final int didReceivedWebpagesInUpdates = totalEvents++;
|
||||||
|
@ -60,6 +61,7 @@ public class NotificationCenter {
|
||||||
public static final int didReplacedPhotoInMemCache = totalEvents++;
|
public static final int didReplacedPhotoInMemCache = totalEvents++;
|
||||||
public static final int messagesReadContent = totalEvents++;
|
public static final int messagesReadContent = totalEvents++;
|
||||||
public static final int botInfoDidLoaded = totalEvents++;
|
public static final int botInfoDidLoaded = totalEvents++;
|
||||||
|
public static final int userInfoDidLoaded = totalEvents++;
|
||||||
public static final int botKeyboardDidLoaded = totalEvents++;
|
public static final int botKeyboardDidLoaded = totalEvents++;
|
||||||
public static final int chatSearchResultsAvailable = totalEvents++;
|
public static final int chatSearchResultsAvailable = totalEvents++;
|
||||||
public static final int musicDidLoaded = totalEvents++;
|
public static final int musicDidLoaded = totalEvents++;
|
||||||
|
@ -67,6 +69,7 @@ public class NotificationCenter {
|
||||||
public static final int didUpdatedMessagesViews = totalEvents++;
|
public static final int didUpdatedMessagesViews = totalEvents++;
|
||||||
public static final int needReloadRecentDialogsSearch = totalEvents++;
|
public static final int needReloadRecentDialogsSearch = totalEvents++;
|
||||||
public static final int locationPermissionGranted = totalEvents++;
|
public static final int locationPermissionGranted = totalEvents++;
|
||||||
|
public static final int peerSettingsDidLoaded = totalEvents++;
|
||||||
|
|
||||||
public static final int httpFileDidLoaded = totalEvents++;
|
public static final int httpFileDidLoaded = totalEvents++;
|
||||||
public static final int httpFileDidFailedLoad = totalEvents++;
|
public static final int httpFileDidFailedLoad = totalEvents++;
|
||||||
|
|
|
@ -61,7 +61,7 @@ public class NotificationsController {
|
||||||
private int wearNotificationId = 10000;
|
private int wearNotificationId = 10000;
|
||||||
private int autoNotificationId = 20000;
|
private int autoNotificationId = 20000;
|
||||||
public ArrayList<MessageObject> popupMessages = new ArrayList<>();
|
public ArrayList<MessageObject> popupMessages = new ArrayList<>();
|
||||||
private long openned_dialog_id = 0;
|
private long opened_dialog_id = 0;
|
||||||
private int total_unread_count = 0;
|
private int total_unread_count = 0;
|
||||||
private int personal_count = 0;
|
private int personal_count = 0;
|
||||||
private boolean notifyCheck = false;
|
private boolean notifyCheck = false;
|
||||||
|
@ -147,7 +147,7 @@ public class NotificationsController {
|
||||||
notificationsQueue.postRunnable(new Runnable() {
|
notificationsQueue.postRunnable(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
openned_dialog_id = 0;
|
opened_dialog_id = 0;
|
||||||
total_unread_count = 0;
|
total_unread_count = 0;
|
||||||
personal_count = 0;
|
personal_count = 0;
|
||||||
pushMessages.clear();
|
pushMessages.clear();
|
||||||
|
@ -178,11 +178,11 @@ public class NotificationsController {
|
||||||
inChatSoundEnabled = value;
|
inChatSoundEnabled = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setOpennedDialogId(final long dialog_id) {
|
public void setOpenedDialogId(final long dialog_id) {
|
||||||
notificationsQueue.postRunnable(new Runnable() {
|
notificationsQueue.postRunnable(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
openned_dialog_id = dialog_id;
|
opened_dialog_id = dialog_id;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -393,7 +393,7 @@ public class NotificationsController {
|
||||||
}
|
}
|
||||||
long dialog_id = messageObject.getDialogId();
|
long dialog_id = messageObject.getDialogId();
|
||||||
long original_dialog_id = dialog_id;
|
long original_dialog_id = dialog_id;
|
||||||
if (dialog_id == openned_dialog_id && ApplicationLoader.isScreenOn) {
|
if (dialog_id == opened_dialog_id && ApplicationLoader.isScreenOn) {
|
||||||
playInChatSound();
|
playInChatSound();
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -406,7 +406,7 @@ public class NotificationsController {
|
||||||
added = true;
|
added = true;
|
||||||
|
|
||||||
Boolean value = settingsCache.get(dialog_id);
|
Boolean value = settingsCache.get(dialog_id);
|
||||||
boolean isChat = (int)dialog_id < 0;
|
boolean isChat = (int) dialog_id < 0;
|
||||||
popup = (int)dialog_id == 0 ? 0 : preferences.getInt(isChat ? "popupGroup" : "popupAll", 0);
|
popup = (int)dialog_id == 0 ? 0 : preferences.getInt(isChat ? "popupGroup" : "popupAll", 0);
|
||||||
if (value == null) {
|
if (value == null) {
|
||||||
int notifyOverride = getNotifyOverride(preferences, dialog_id);
|
int notifyOverride = getNotifyOverride(preferences, dialog_id);
|
||||||
|
@ -582,7 +582,7 @@ public class NotificationsController {
|
||||||
value = !(notifyOverride == 2 || (!preferences.getBoolean("EnableAll", true) || ((int) dialog_id < 0) && !preferences.getBoolean("EnableGroup", true)) && notifyOverride == 0);
|
value = !(notifyOverride == 2 || (!preferences.getBoolean("EnableAll", true) || ((int) dialog_id < 0) && !preferences.getBoolean("EnableGroup", true)) && notifyOverride == 0);
|
||||||
settingsCache.put(dialog_id, value);
|
settingsCache.put(dialog_id, value);
|
||||||
}
|
}
|
||||||
if (!value || dialog_id == openned_dialog_id && ApplicationLoader.isScreenOn) {
|
if (!value || dialog_id == opened_dialog_id && ApplicationLoader.isScreenOn) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
pushMessagesDict.put(mid, messageObject);
|
pushMessagesDict.put(mid, messageObject);
|
||||||
|
@ -757,6 +757,8 @@ public class NotificationsController {
|
||||||
msg = LocaleController.formatString("NotificationMessageVideo", R.string.NotificationMessageVideo, name);
|
msg = LocaleController.formatString("NotificationMessageVideo", R.string.NotificationMessageVideo, name);
|
||||||
} else if (messageObject.isVoice()) {
|
} else if (messageObject.isVoice()) {
|
||||||
msg = LocaleController.formatString("NotificationMessageAudio", R.string.NotificationMessageAudio, name);
|
msg = LocaleController.formatString("NotificationMessageAudio", R.string.NotificationMessageAudio, name);
|
||||||
|
} else if (messageObject.isMusic()) {
|
||||||
|
msg = LocaleController.formatString("NotificationMessageMusic", R.string.NotificationMessageMusic, name);
|
||||||
} else if (messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaContact) {
|
} else if (messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaContact) {
|
||||||
msg = LocaleController.formatString("NotificationMessageContact", R.string.NotificationMessageContact, name);
|
msg = LocaleController.formatString("NotificationMessageContact", R.string.NotificationMessageContact, name);
|
||||||
} else if (messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaGeo || messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaVenue) {
|
} else if (messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaGeo || messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaVenue) {
|
||||||
|
@ -801,7 +803,11 @@ public class NotificationsController {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
if (from_id == u2.id) {
|
if (from_id == u2.id) {
|
||||||
msg = LocaleController.formatString("NotificationGroupAddSelf", R.string.NotificationGroupAddSelf, name, chat.title);
|
if (messageObject.isMegagroup()) {
|
||||||
|
msg = LocaleController.formatString("NotificationGroupAddSelfMega", R.string.NotificationGroupAddSelfMega, name, chat.title);
|
||||||
|
} else {
|
||||||
|
msg = LocaleController.formatString("NotificationGroupAddSelf", R.string.NotificationGroupAddSelf, name, chat.title);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
msg = LocaleController.formatString("NotificationGroupAddMember", R.string.NotificationGroupAddMember, name, chat.title, UserObject.getUserName(u2));
|
msg = LocaleController.formatString("NotificationGroupAddMember", R.string.NotificationGroupAddMember, name, chat.title, UserObject.getUserName(u2));
|
||||||
}
|
}
|
||||||
|
@ -851,10 +857,91 @@ public class NotificationsController {
|
||||||
msg = LocaleController.formatString("ActionMigrateFromGroupNotify", R.string.ActionMigrateFromGroupNotify, chat.title);
|
msg = LocaleController.formatString("ActionMigrateFromGroupNotify", R.string.ActionMigrateFromGroupNotify, chat.title);
|
||||||
} else if (messageObject.messageOwner.action instanceof TLRPC.TL_messageActionChannelMigrateFrom) {
|
} else if (messageObject.messageOwner.action instanceof TLRPC.TL_messageActionChannelMigrateFrom) {
|
||||||
msg = LocaleController.formatString("ActionMigrateFromGroupNotify", R.string.ActionMigrateFromGroupNotify, messageObject.messageOwner.action.title);
|
msg = LocaleController.formatString("ActionMigrateFromGroupNotify", R.string.ActionMigrateFromGroupNotify, messageObject.messageOwner.action.title);
|
||||||
|
} else if (messageObject.messageOwner.action instanceof TLRPC.TL_messageActionPinMessage) {
|
||||||
|
if (messageObject.replyMessageObject == null) {
|
||||||
|
if (!ChatObject.isChannel(chat) || chat.megagroup) {
|
||||||
|
msg = LocaleController.formatString("NotificationActionPinnedNoText", R.string.NotificationActionPinnedNoText, name, chat.title);
|
||||||
|
} else {
|
||||||
|
msg = LocaleController.formatString("NotificationActionPinnedNoTextChannel", R.string.NotificationActionPinnedNoTextChannel, name, chat.title);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
MessageObject object = messageObject.replyMessageObject;
|
||||||
|
if (object.isMusic()) {
|
||||||
|
if (!ChatObject.isChannel(chat) || chat.megagroup) {
|
||||||
|
msg = LocaleController.formatString("NotificationActionPinnedMusic", R.string.NotificationActionPinnedMusic, name, chat.title);
|
||||||
|
} else {
|
||||||
|
msg = LocaleController.formatString("NotificationActionPinnedMusicChannel", R.string.NotificationActionPinnedMusicChannel, chat.title);
|
||||||
|
}
|
||||||
|
} else if (object.isVideo()) {
|
||||||
|
if (!ChatObject.isChannel(chat) || chat.megagroup) {
|
||||||
|
msg = LocaleController.formatString("NotificationActionPinnedVideo", R.string.NotificationActionPinnedVideo, name, chat.title);
|
||||||
|
} else {
|
||||||
|
msg = LocaleController.formatString("NotificationActionPinnedVideoChannel", R.string.NotificationActionPinnedVideoChannel, chat.title);
|
||||||
|
}
|
||||||
|
} else if (object.isGif()) {
|
||||||
|
if (!ChatObject.isChannel(chat) || chat.megagroup) {
|
||||||
|
msg = LocaleController.formatString("NotificationActionPinnedGif", R.string.NotificationActionPinnedGif, name, chat.title);
|
||||||
|
} else {
|
||||||
|
msg = LocaleController.formatString("NotificationActionPinnedGifChannel", R.string.NotificationActionPinnedGifChannel, chat.title);
|
||||||
|
}
|
||||||
|
} else if (object.isVoice()) {
|
||||||
|
if (!ChatObject.isChannel(chat) || chat.megagroup) {
|
||||||
|
msg = LocaleController.formatString("NotificationActionPinnedVoice", R.string.NotificationActionPinnedVoice, name, chat.title);
|
||||||
|
} else {
|
||||||
|
msg = LocaleController.formatString("NotificationActionPinnedVoiceChannel", R.string.NotificationActionPinnedVoiceChannel, chat.title);
|
||||||
|
}
|
||||||
|
} else if (object.isSticker()) {
|
||||||
|
if (!ChatObject.isChannel(chat) || chat.megagroup) {
|
||||||
|
msg = LocaleController.formatString("NotificationActionPinnedSticker", R.string.NotificationActionPinnedSticker, name, chat.title);
|
||||||
|
} else {
|
||||||
|
msg = LocaleController.formatString("NotificationActionPinnedStickerChannel", R.string.NotificationActionPinnedStickerChannel, chat.title);
|
||||||
|
}
|
||||||
|
} else if (object.messageOwner.media instanceof TLRPC.TL_messageMediaDocument) {
|
||||||
|
if (!ChatObject.isChannel(chat) || chat.megagroup) {
|
||||||
|
msg = LocaleController.formatString("NotificationActionPinnedFile", R.string.NotificationActionPinnedFile, name, chat.title);
|
||||||
|
} else {
|
||||||
|
msg = LocaleController.formatString("NotificationActionPinnedFileChannel", R.string.NotificationActionPinnedFileChannel, chat.title);
|
||||||
|
}
|
||||||
|
} else if (object.messageOwner.media instanceof TLRPC.TL_messageMediaGeo) {
|
||||||
|
if (!ChatObject.isChannel(chat) || chat.megagroup) {
|
||||||
|
msg = LocaleController.formatString("NotificationActionPinnedGeo", R.string.NotificationActionPinnedGeo, name, chat.title);
|
||||||
|
} else {
|
||||||
|
msg = LocaleController.formatString("NotificationActionPinnedGeoChannel", R.string.NotificationActionPinnedGeoChannel, chat.title);
|
||||||
|
}
|
||||||
|
} else if (object.messageOwner.media instanceof TLRPC.TL_messageMediaContact) {
|
||||||
|
if (!ChatObject.isChannel(chat) || chat.megagroup) {
|
||||||
|
msg = LocaleController.formatString("NotificationActionPinnedContact", R.string.NotificationActionPinnedContact, name, chat.title);
|
||||||
|
} else {
|
||||||
|
msg = LocaleController.formatString("NotificationActionPinnedContactChannel", R.string.NotificationActionPinnedContactChannel, chat.title);
|
||||||
|
}
|
||||||
|
} else if (object.messageOwner.media instanceof TLRPC.TL_messageMediaPhoto) {
|
||||||
|
if (!ChatObject.isChannel(chat) || chat.megagroup) {
|
||||||
|
msg = LocaleController.formatString("NotificationActionPinnedPhoto", R.string.NotificationActionPinnedPhoto, name, chat.title);
|
||||||
|
} else {
|
||||||
|
msg = LocaleController.formatString("NotificationActionPinnedPhotoChannel", R.string.NotificationActionPinnedPhotoChannel, chat.title);
|
||||||
|
}
|
||||||
|
} else if (object.messageText != null && object.messageText.length() > 0) {
|
||||||
|
CharSequence message = object.messageText;
|
||||||
|
if (message.length() > 20) {
|
||||||
|
message = message.subSequence(0, 20) + "...";
|
||||||
|
}
|
||||||
|
if (!ChatObject.isChannel(chat) || chat.megagroup) {
|
||||||
|
msg = LocaleController.formatString("NotificationActionPinnedText", R.string.NotificationActionPinnedText, name, message, chat.title);
|
||||||
|
} else {
|
||||||
|
msg = LocaleController.formatString("NotificationActionPinnedTextChannel", R.string.NotificationActionPinnedTextChannel, chat.title, message);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (!ChatObject.isChannel(chat) || chat.megagroup) {
|
||||||
|
msg = LocaleController.formatString("NotificationActionPinnedNoText", R.string.NotificationActionPinnedNoText, name, chat.title);
|
||||||
|
} else {
|
||||||
|
msg = LocaleController.formatString("NotificationActionPinnedNoTextChannel", R.string.NotificationActionPinnedNoTextChannel, chat.title);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (ChatObject.isChannel(chat) && !chat.megagroup) {
|
if (ChatObject.isChannel(chat) && !chat.megagroup) {
|
||||||
if (from_id < 0) {
|
if (messageObject.isImportant()) {
|
||||||
if (messageObject.isMediaEmpty()) {
|
if (messageObject.isMediaEmpty()) {
|
||||||
if (!shortMessage && messageObject.messageOwner.message != null && messageObject.messageOwner.message.length() != 0) {
|
if (!shortMessage && messageObject.messageOwner.message != null && messageObject.messageOwner.message.length() != 0) {
|
||||||
msg = LocaleController.formatString("NotificationMessageGroupText", R.string.NotificationMessageGroupText, name, chat.title, messageObject.messageOwner.message);
|
msg = LocaleController.formatString("NotificationMessageGroupText", R.string.NotificationMessageGroupText, name, chat.title, messageObject.messageOwner.message);
|
||||||
|
@ -867,6 +954,8 @@ public class NotificationsController {
|
||||||
msg = LocaleController.formatString("ChannelMessageVideo", R.string.ChannelMessageVideo, name, chat.title);
|
msg = LocaleController.formatString("ChannelMessageVideo", R.string.ChannelMessageVideo, name, chat.title);
|
||||||
} else if (messageObject.isVoice()) {
|
} else if (messageObject.isVoice()) {
|
||||||
msg = LocaleController.formatString("ChannelMessageAudio", R.string.ChannelMessageAudio, name, chat.title);
|
msg = LocaleController.formatString("ChannelMessageAudio", R.string.ChannelMessageAudio, name, chat.title);
|
||||||
|
} else if (messageObject.isMusic()) {
|
||||||
|
msg = LocaleController.formatString("ChannelMessageMusic", R.string.ChannelMessageMusic, name, chat.title);
|
||||||
} else if (messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaContact) {
|
} else if (messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaContact) {
|
||||||
msg = LocaleController.formatString("ChannelMessageContact", R.string.ChannelMessageContact, name, chat.title);
|
msg = LocaleController.formatString("ChannelMessageContact", R.string.ChannelMessageContact, name, chat.title);
|
||||||
} else if (messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaGeo || messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaVenue) {
|
} else if (messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaGeo || messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaVenue) {
|
||||||
|
@ -893,6 +982,8 @@ public class NotificationsController {
|
||||||
msg = LocaleController.formatString("ChannelMessageGroupVideo", R.string.ChannelMessageGroupVideo, name, chat.title);
|
msg = LocaleController.formatString("ChannelMessageGroupVideo", R.string.ChannelMessageGroupVideo, name, chat.title);
|
||||||
} else if (messageObject.isVoice()) {
|
} else if (messageObject.isVoice()) {
|
||||||
msg = LocaleController.formatString("ChannelMessageGroupAudio", R.string.ChannelMessageGroupAudio, name, chat.title);
|
msg = LocaleController.formatString("ChannelMessageGroupAudio", R.string.ChannelMessageGroupAudio, name, chat.title);
|
||||||
|
} else if (messageObject.isMusic()) {
|
||||||
|
msg = LocaleController.formatString("ChannelMessageGroupMusic", R.string.ChannelMessageGroupMusic, name, chat.title);
|
||||||
} else if (messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaContact) {
|
} else if (messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaContact) {
|
||||||
msg = LocaleController.formatString("ChannelMessageGroupContact", R.string.ChannelMessageGroupContact, name, chat.title);
|
msg = LocaleController.formatString("ChannelMessageGroupContact", R.string.ChannelMessageGroupContact, name, chat.title);
|
||||||
} else if (messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaGeo || messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaVenue) {
|
} else if (messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaGeo || messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaVenue) {
|
||||||
|
@ -920,6 +1011,8 @@ public class NotificationsController {
|
||||||
msg = LocaleController.formatString("NotificationMessageGroupVideo", R.string.NotificationMessageGroupVideo, name, chat.title);
|
msg = LocaleController.formatString("NotificationMessageGroupVideo", R.string.NotificationMessageGroupVideo, name, chat.title);
|
||||||
} else if (messageObject.isVoice()) {
|
} else if (messageObject.isVoice()) {
|
||||||
msg = LocaleController.formatString("NotificationMessageGroupAudio", R.string.NotificationMessageGroupAudio, name, chat.title);
|
msg = LocaleController.formatString("NotificationMessageGroupAudio", R.string.NotificationMessageGroupAudio, name, chat.title);
|
||||||
|
} else if (messageObject.isMusic()) {
|
||||||
|
msg = LocaleController.formatString("NotificationMessageGroupMusic", R.string.NotificationMessageGroupMusic, name, chat.title);
|
||||||
} else if (messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaContact) {
|
} else if (messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaContact) {
|
||||||
msg = LocaleController.formatString("NotificationMessageGroupContact", R.string.NotificationMessageGroupContact, name, chat.title);
|
msg = LocaleController.formatString("NotificationMessageGroupContact", R.string.NotificationMessageGroupContact, name, chat.title);
|
||||||
} else if (messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaGeo || messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaVenue) {
|
} else if (messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaGeo || messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaVenue) {
|
||||||
|
@ -1073,7 +1166,7 @@ public class NotificationsController {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("Notifications", Context.MODE_PRIVATE);
|
SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("Notifications", Context.MODE_PRIVATE);
|
||||||
int notifyOverride = getNotifyOverride(preferences, openned_dialog_id);
|
int notifyOverride = getNotifyOverride(preferences, opened_dialog_id);
|
||||||
if (notifyOverride == 2) {
|
if (notifyOverride == 2) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -1405,12 +1498,6 @@ public class NotificationsController {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (silent == 1) {
|
|
||||||
FileLog.e("tmessages", "don't notify " + lastMessage);
|
|
||||||
} else {
|
|
||||||
FileLog.e("tmessages", "notify" + lastMessage);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!notifyAboutLast || silent == 1) {
|
if (!notifyAboutLast || silent == 1) {
|
||||||
mBuilder.setPriority(NotificationCompat.PRIORITY_LOW);
|
mBuilder.setPriority(NotificationCompat.PRIORITY_LOW);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -820,6 +820,7 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter
|
||||||
req.message = message;
|
req.message = message;
|
||||||
req.id = messageObject.getId();
|
req.id = messageObject.getId();
|
||||||
req.no_webpage = !searchLinks;
|
req.no_webpage = !searchLinks;
|
||||||
|
FileLog.d("tmessages", "try to edit message " + req.id + " in channel " + req.channel.channel_id + " hash " + req.channel.access_hash + " message " + req.message);
|
||||||
final int reqId = ConnectionsManager.getInstance().sendRequest(req, new RequestDelegate() {
|
final int reqId = ConnectionsManager.getInstance().sendRequest(req, new RequestDelegate() {
|
||||||
@Override
|
@Override
|
||||||
public void run(TLObject response, TLRPC.TL_error error) {
|
public void run(TLObject response, TLRPC.TL_error error) {
|
||||||
|
@ -2002,6 +2003,7 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter
|
||||||
|
|
||||||
if (!isSentError) {
|
if (!isSentError) {
|
||||||
newMsgObj.send_state = MessageObject.MESSAGE_SEND_STATE_SENT;
|
newMsgObj.send_state = MessageObject.MESSAGE_SEND_STATE_SENT;
|
||||||
|
NotificationCenter.getInstance().postNotificationName(NotificationCenter.messageReceivedByServer, oldId, (isBroadcast ? oldId : newMsgObj.id), newMsgObj, newMsgObj.dialog_id); //TODO remove later?
|
||||||
MessagesStorage.getInstance().getStorageQueue().postRunnable(new Runnable() {
|
MessagesStorage.getInstance().getStorageQueue().postRunnable(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
|
@ -2274,7 +2276,7 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter
|
||||||
if (extension == null) {
|
if (extension == null) {
|
||||||
extension = "txt";
|
extension = "txt";
|
||||||
}
|
}
|
||||||
path = MediaController.copyDocumentToCache(uri, extension);
|
path = MediaController.copyFileToCache(uri, extension);
|
||||||
if (path == null) {
|
if (path == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -2923,12 +2925,12 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter
|
||||||
if (MediaController.isGif(uri)) {
|
if (MediaController.isGif(uri)) {
|
||||||
isDocument = true;
|
isDocument = true;
|
||||||
originalPath = uri.toString();
|
originalPath = uri.toString();
|
||||||
tempPath = MediaController.copyDocumentToCache(uri, "gif");
|
tempPath = MediaController.copyFileToCache(uri, "gif");
|
||||||
extension = "gif";
|
extension = "gif";
|
||||||
} else if (MediaController.isWebp(uri)) {
|
} else if (MediaController.isWebp(uri)) {
|
||||||
isDocument = true;
|
isDocument = true;
|
||||||
originalPath = uri.toString();
|
originalPath = uri.toString();
|
||||||
tempPath = MediaController.copyDocumentToCache(uri, "webp");
|
tempPath = MediaController.copyFileToCache(uri, "webp");
|
||||||
extension = "webp";
|
extension = "webp";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3009,8 +3011,7 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter
|
||||||
}
|
}
|
||||||
TLRPC.TL_document document = null;
|
TLRPC.TL_document document = null;
|
||||||
if (!isEncrypted) {
|
if (!isEncrypted) {
|
||||||
TLObject object = MessagesStorage.getInstance().getSentFile(originalPath, !isEncrypted ? 2 : 5);
|
//document = (TLRPC.TL_document) MessagesStorage.getInstance().getSentFile(originalPath, !isEncrypted ? 2 : 5);
|
||||||
document = (TLRPC.TL_document) object;
|
|
||||||
}
|
}
|
||||||
if (document == null) {
|
if (document == null) {
|
||||||
Bitmap thumb = ThumbnailUtils.createVideoThumbnail(videoPath, MediaStore.Video.Thumbnails.MINI_KIND);
|
Bitmap thumb = ThumbnailUtils.createVideoThumbnail(videoPath, MediaStore.Video.Thumbnails.MINI_KIND);
|
||||||
|
|
|
@ -9,8 +9,10 @@
|
||||||
package org.telegram.messenger;
|
package org.telegram.messenger;
|
||||||
|
|
||||||
import android.annotation.TargetApi;
|
import android.annotation.TargetApi;
|
||||||
|
import android.app.Activity;
|
||||||
import android.content.ComponentName;
|
import android.content.ComponentName;
|
||||||
import android.content.IntentFilter;
|
import android.content.IntentFilter;
|
||||||
|
import android.content.SharedPreferences;
|
||||||
import android.graphics.Bitmap;
|
import android.graphics.Bitmap;
|
||||||
import android.graphics.BitmapFactory;
|
import android.graphics.BitmapFactory;
|
||||||
import android.graphics.BitmapShader;
|
import android.graphics.BitmapShader;
|
||||||
|
@ -48,6 +50,11 @@ public class TgChooserTargetService extends ChooserTargetService {
|
||||||
if (!UserConfig.isClientActivated()) {
|
if (!UserConfig.isClientActivated()) {
|
||||||
return targets;
|
return targets;
|
||||||
}
|
}
|
||||||
|
SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("mainconfig", Activity.MODE_PRIVATE);
|
||||||
|
if (!preferences.getBoolean("direct_share", true)) {
|
||||||
|
return targets;
|
||||||
|
}
|
||||||
|
|
||||||
ImageLoader imageLoader = ImageLoader.getInstance();
|
ImageLoader imageLoader = ImageLoader.getInstance();
|
||||||
final Semaphore semaphore = new Semaphore(0);
|
final Semaphore semaphore = new Semaphore(0);
|
||||||
final ComponentName componentName = new ComponentName(getPackageName(), LaunchActivity.class.getCanonicalName());
|
final ComponentName componentName = new ComponentName(getPackageName(), LaunchActivity.class.getCanonicalName());
|
||||||
|
|
|
@ -179,7 +179,7 @@ public class BotQuery {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void putBotInfo(final TLRPC.BotInfo botInfo) {
|
public static void putBotInfo(final TLRPC.BotInfo botInfo) {
|
||||||
if (botInfo == null || botInfo instanceof TLRPC.TL_botInfoEmpty) {
|
if (botInfo == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
botInfos.put(botInfo.user_id, botInfo);
|
botInfos.put(botInfo.user_id, botInfo);
|
||||||
|
|
|
@ -29,10 +29,158 @@ import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
|
||||||
public class ReplyMessageQuery {
|
public class MessagesQuery {
|
||||||
|
|
||||||
public static void loadReplyMessagesForMessages(final ArrayList<MessageObject> messages, final long dialog_id) {
|
public static MessageObject loadPinnedMessage(final int channelId, final int mid, boolean useQueue) {
|
||||||
if ((int) dialog_id == 0) {
|
if (useQueue) {
|
||||||
|
MessagesStorage.getInstance().getStorageQueue().postRunnable(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
loadPinnedMessageInternal(channelId, mid, false);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
return loadPinnedMessageInternal(channelId, mid, true);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static MessageObject loadPinnedMessageInternal(final int channelId, final int mid, boolean returnValue) {
|
||||||
|
try {
|
||||||
|
long messageId = ((long) mid) | ((long) channelId) << 32;
|
||||||
|
|
||||||
|
TLRPC.Message result = null;
|
||||||
|
final ArrayList<TLRPC.User> users = new ArrayList<>();
|
||||||
|
final ArrayList<TLRPC.Chat> chats = new ArrayList<>();
|
||||||
|
ArrayList<Integer> usersToLoad = new ArrayList<>();
|
||||||
|
ArrayList<Integer> chatsToLoad = new ArrayList<>();
|
||||||
|
|
||||||
|
SQLiteCursor cursor = MessagesStorage.getInstance().getDatabase().queryFinalized(String.format(Locale.US, "SELECT data, mid, date FROM messages WHERE mid = %d", messageId));
|
||||||
|
if (cursor.next()) {
|
||||||
|
NativeByteBuffer data = new NativeByteBuffer(cursor.byteArrayLength(0));
|
||||||
|
if (data != null && cursor.byteBufferValue(0, data) != 0) {
|
||||||
|
result = TLRPC.Message.TLdeserialize(data, data.readInt32(false), false);
|
||||||
|
result.id = cursor.intValue(1);
|
||||||
|
result.date = cursor.intValue(2);
|
||||||
|
result.dialog_id = -channelId;
|
||||||
|
MessagesStorage.addUsersAndChatsFromMessage(result, usersToLoad, chatsToLoad);
|
||||||
|
}
|
||||||
|
data.reuse();
|
||||||
|
}
|
||||||
|
cursor.dispose();
|
||||||
|
|
||||||
|
if (result == null) {
|
||||||
|
cursor = MessagesStorage.getInstance().getDatabase().queryFinalized(String.format(Locale.US, "SELECT data FROM chat_pinned WHERE uid = %d", channelId));
|
||||||
|
if (cursor.next()) {
|
||||||
|
NativeByteBuffer data = new NativeByteBuffer(cursor.byteArrayLength(0));
|
||||||
|
if (data != null && cursor.byteBufferValue(0, data) != 0) {
|
||||||
|
result = TLRPC.Message.TLdeserialize(data, data.readInt32(false), false);
|
||||||
|
if (result.id != mid) {
|
||||||
|
result = null;
|
||||||
|
} else {
|
||||||
|
result.dialog_id = -channelId;
|
||||||
|
MessagesStorage.addUsersAndChatsFromMessage(result, usersToLoad, chatsToLoad);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
data.reuse();
|
||||||
|
}
|
||||||
|
cursor.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result == null) {
|
||||||
|
final TLRPC.TL_channels_getMessages req = new TLRPC.TL_channels_getMessages();
|
||||||
|
req.channel = MessagesController.getInputChannel(channelId);
|
||||||
|
req.id.add(mid);
|
||||||
|
ConnectionsManager.getInstance().sendRequest(req, new RequestDelegate() {
|
||||||
|
@Override
|
||||||
|
public void run(TLObject response, TLRPC.TL_error error) {
|
||||||
|
boolean ok = false;
|
||||||
|
if (error == null) {
|
||||||
|
TLRPC.messages_Messages messagesRes = (TLRPC.messages_Messages) response;
|
||||||
|
if (!messagesRes.messages.isEmpty()) {
|
||||||
|
ImageLoader.saveMessagesThumbs(messagesRes.messages);
|
||||||
|
broadcastPinnedMessage(messagesRes.messages.get(0), messagesRes.users, messagesRes.chats, false, false);
|
||||||
|
MessagesStorage.getInstance().putUsersAndChats(messagesRes.users, messagesRes.chats, true, true);
|
||||||
|
savePinnedMessage(messagesRes.messages.get(0));
|
||||||
|
ok = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!ok) {
|
||||||
|
MessagesStorage.getInstance().updateChannelPinnedMessage(channelId, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
if (returnValue) {
|
||||||
|
return broadcastPinnedMessage(result, users, chats, true, returnValue);
|
||||||
|
} else {
|
||||||
|
if (!usersToLoad.isEmpty()) {
|
||||||
|
MessagesStorage.getInstance().getUsersInternal(TextUtils.join(",", usersToLoad), users);
|
||||||
|
}
|
||||||
|
if (!chatsToLoad.isEmpty()) {
|
||||||
|
MessagesStorage.getInstance().getChatsInternal(TextUtils.join(",", chatsToLoad), chats);
|
||||||
|
}
|
||||||
|
broadcastPinnedMessage(result, users, chats, true, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
FileLog.e("tmessages", e);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void savePinnedMessage(final TLRPC.Message result) {
|
||||||
|
MessagesStorage.getInstance().getStorageQueue().postRunnable(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
try {
|
||||||
|
MessagesStorage.getInstance().getDatabase().beginTransaction();
|
||||||
|
SQLitePreparedStatement state = MessagesStorage.getInstance().getDatabase().executeFast("REPLACE INTO chat_pinned VALUES(?, ?, ?)");
|
||||||
|
NativeByteBuffer data = new NativeByteBuffer(result.getObjectSize());
|
||||||
|
result.serializeToStream(data);
|
||||||
|
state.requery();
|
||||||
|
state.bindInteger(1, result.to_id.channel_id);
|
||||||
|
state.bindInteger(2, result.id);
|
||||||
|
state.bindByteBuffer(3, data);
|
||||||
|
state.step();
|
||||||
|
data.reuse();
|
||||||
|
state.dispose();
|
||||||
|
MessagesStorage.getInstance().getDatabase().commitTransaction();
|
||||||
|
} catch (Exception e) {
|
||||||
|
FileLog.e("tmessages", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private static MessageObject broadcastPinnedMessage(final TLRPC.Message result, final ArrayList<TLRPC.User> users, final ArrayList<TLRPC.Chat> chats, final boolean isCache, boolean returnValue) {
|
||||||
|
final HashMap<Integer, TLRPC.User> usersDict = new HashMap<>();
|
||||||
|
for (int a = 0; a < users.size(); a++) {
|
||||||
|
TLRPC.User user = users.get(a);
|
||||||
|
usersDict.put(user.id, user);
|
||||||
|
}
|
||||||
|
final HashMap<Integer, TLRPC.Chat> chatsDict = new HashMap<>();
|
||||||
|
for (int a = 0; a < chats.size(); a++) {
|
||||||
|
TLRPC.Chat chat = chats.get(a);
|
||||||
|
chatsDict.put(chat.id, chat);
|
||||||
|
}
|
||||||
|
if (returnValue) {
|
||||||
|
return new MessageObject(result, usersDict, chatsDict, false);
|
||||||
|
} else {
|
||||||
|
AndroidUtilities.runOnUIThread(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
MessagesController.getInstance().putUsers(users, isCache);
|
||||||
|
MessagesController.getInstance().putChats(chats, isCache);
|
||||||
|
NotificationCenter.getInstance().postNotificationName(NotificationCenter.didLoadedPinnedMessage, new MessageObject(result, usersDict, chatsDict, false));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void loadReplyMessagesForMessages(final ArrayList<MessageObject> messages, final long dialogId) {
|
||||||
|
if ((int) dialogId == 0) {
|
||||||
final ArrayList<Long> replyMessages = new ArrayList<>();
|
final ArrayList<Long> replyMessages = new ArrayList<>();
|
||||||
final HashMap<Long, ArrayList<MessageObject>> replyMessageRandomOwners = new HashMap<>();
|
final HashMap<Long, ArrayList<MessageObject>> replyMessageRandomOwners = new HashMap<>();
|
||||||
final StringBuilder stringBuilder = new StringBuilder();
|
final StringBuilder stringBuilder = new StringBuilder();
|
||||||
|
@ -70,7 +218,7 @@ public class ReplyMessageQuery {
|
||||||
TLRPC.Message message = TLRPC.Message.TLdeserialize(data, data.readInt32(false), false);
|
TLRPC.Message message = TLRPC.Message.TLdeserialize(data, data.readInt32(false), false);
|
||||||
message.id = cursor.intValue(1);
|
message.id = cursor.intValue(1);
|
||||||
message.date = cursor.intValue(2);
|
message.date = cursor.intValue(2);
|
||||||
message.dialog_id = dialog_id;
|
message.dialog_id = dialogId;
|
||||||
|
|
||||||
|
|
||||||
ArrayList<MessageObject> arrayList = replyMessageRandomOwners.remove(cursor.longValue(3));
|
ArrayList<MessageObject> arrayList = replyMessageRandomOwners.remove(cursor.longValue(3));
|
||||||
|
@ -97,7 +245,7 @@ public class ReplyMessageQuery {
|
||||||
AndroidUtilities.runOnUIThread(new Runnable() {
|
AndroidUtilities.runOnUIThread(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
NotificationCenter.getInstance().postNotificationName(NotificationCenter.didLoadedReplyMessages, dialog_id);
|
NotificationCenter.getInstance().postNotificationName(NotificationCenter.didLoadedReplyMessages, dialogId);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
|
@ -105,7 +253,6 @@ public class ReplyMessageQuery {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
final ArrayList<Integer> replyMessages = new ArrayList<>();
|
final ArrayList<Integer> replyMessages = new ArrayList<>();
|
||||||
final HashMap<Integer, ArrayList<MessageObject>> replyMessageOwners = new HashMap<>();
|
final HashMap<Integer, ArrayList<MessageObject>> replyMessageOwners = new HashMap<>();
|
||||||
|
@ -157,7 +304,7 @@ public class ReplyMessageQuery {
|
||||||
TLRPC.Message message = TLRPC.Message.TLdeserialize(data, data.readInt32(false), false);
|
TLRPC.Message message = TLRPC.Message.TLdeserialize(data, data.readInt32(false), false);
|
||||||
message.id = cursor.intValue(1);
|
message.id = cursor.intValue(1);
|
||||||
message.date = cursor.intValue(2);
|
message.date = cursor.intValue(2);
|
||||||
message.dialog_id = dialog_id;
|
message.dialog_id = dialogId;
|
||||||
MessagesStorage.addUsersAndChatsFromMessage(message, usersToLoad, chatsToLoad);
|
MessagesStorage.addUsersAndChatsFromMessage(message, usersToLoad, chatsToLoad);
|
||||||
result.add(message);
|
result.add(message);
|
||||||
replyMessages.remove((Integer) message.id);
|
replyMessages.remove((Integer) message.id);
|
||||||
|
@ -172,7 +319,7 @@ public class ReplyMessageQuery {
|
||||||
if (!chatsToLoad.isEmpty()) {
|
if (!chatsToLoad.isEmpty()) {
|
||||||
MessagesStorage.getInstance().getChatsInternal(TextUtils.join(",", chatsToLoad), chats);
|
MessagesStorage.getInstance().getChatsInternal(TextUtils.join(",", chatsToLoad), chats);
|
||||||
}
|
}
|
||||||
broadcastReplyMessages(result, replyMessageOwners, users, chats, dialog_id, true);
|
broadcastReplyMessages(result, replyMessageOwners, users, chats, dialogId, true);
|
||||||
|
|
||||||
if (!replyMessages.isEmpty()) {
|
if (!replyMessages.isEmpty()) {
|
||||||
if (channelIdFinal != 0) {
|
if (channelIdFinal != 0) {
|
||||||
|
@ -185,7 +332,7 @@ public class ReplyMessageQuery {
|
||||||
if (error == null) {
|
if (error == null) {
|
||||||
TLRPC.messages_Messages messagesRes = (TLRPC.messages_Messages) response;
|
TLRPC.messages_Messages messagesRes = (TLRPC.messages_Messages) response;
|
||||||
ImageLoader.saveMessagesThumbs(messagesRes.messages);
|
ImageLoader.saveMessagesThumbs(messagesRes.messages);
|
||||||
broadcastReplyMessages(messagesRes.messages, replyMessageOwners, messagesRes.users, messagesRes.chats, dialog_id, false);
|
broadcastReplyMessages(messagesRes.messages, replyMessageOwners, messagesRes.users, messagesRes.chats, dialogId, false);
|
||||||
MessagesStorage.getInstance().putUsersAndChats(messagesRes.users, messagesRes.chats, true, true);
|
MessagesStorage.getInstance().putUsersAndChats(messagesRes.users, messagesRes.chats, true, true);
|
||||||
saveReplyMessages(replyMessageOwners, messagesRes.messages);
|
saveReplyMessages(replyMessageOwners, messagesRes.messages);
|
||||||
}
|
}
|
||||||
|
@ -200,7 +347,7 @@ public class ReplyMessageQuery {
|
||||||
if (error == null) {
|
if (error == null) {
|
||||||
TLRPC.messages_Messages messagesRes = (TLRPC.messages_Messages) response;
|
TLRPC.messages_Messages messagesRes = (TLRPC.messages_Messages) response;
|
||||||
ImageLoader.saveMessagesThumbs(messagesRes.messages);
|
ImageLoader.saveMessagesThumbs(messagesRes.messages);
|
||||||
broadcastReplyMessages(messagesRes.messages, replyMessageOwners, messagesRes.users, messagesRes.chats, dialog_id, false);
|
broadcastReplyMessages(messagesRes.messages, replyMessageOwners, messagesRes.users, messagesRes.chats, dialogId, false);
|
||||||
MessagesStorage.getInstance().putUsersAndChats(messagesRes.users, messagesRes.chats, true, true);
|
MessagesStorage.getInstance().putUsersAndChats(messagesRes.users, messagesRes.chats, true, true);
|
||||||
saveReplyMessages(replyMessageOwners, messagesRes.messages);
|
saveReplyMessages(replyMessageOwners, messagesRes.messages);
|
||||||
}
|
}
|
||||||
|
@ -223,12 +370,14 @@ public class ReplyMessageQuery {
|
||||||
try {
|
try {
|
||||||
MessagesStorage.getInstance().getDatabase().beginTransaction();
|
MessagesStorage.getInstance().getDatabase().beginTransaction();
|
||||||
SQLitePreparedStatement state = MessagesStorage.getInstance().getDatabase().executeFast("UPDATE messages SET replydata = ? WHERE mid = ?");
|
SQLitePreparedStatement state = MessagesStorage.getInstance().getDatabase().executeFast("UPDATE messages SET replydata = ? WHERE mid = ?");
|
||||||
for (TLRPC.Message message : result) {
|
for (int a = 0; a < result.size(); a++) {
|
||||||
|
TLRPC.Message message = result.get(a);
|
||||||
ArrayList<MessageObject> messageObjects = replyMessageOwners.get(message.id);
|
ArrayList<MessageObject> messageObjects = replyMessageOwners.get(message.id);
|
||||||
if (messageObjects != null) {
|
if (messageObjects != null) {
|
||||||
NativeByteBuffer data = new NativeByteBuffer(message.getObjectSize());
|
NativeByteBuffer data = new NativeByteBuffer(message.getObjectSize());
|
||||||
message.serializeToStream(data);
|
message.serializeToStream(data);
|
||||||
for (MessageObject messageObject : messageObjects) {
|
for (int b = 0; b < messageObjects.size(); b++) {
|
||||||
|
MessageObject messageObject = messageObjects.get(b);
|
||||||
state.requery();
|
state.requery();
|
||||||
long messageId = messageObject.getId();
|
long messageId = messageObject.getId();
|
||||||
if (messageObject.messageOwner.to_id.channel_id != 0) {
|
if (messageObject.messageOwner.to_id.channel_id != 0) {
|
||||||
|
@ -275,6 +424,9 @@ public class ReplyMessageQuery {
|
||||||
for (int b = 0; b < arrayList.size(); b++) {
|
for (int b = 0; b < arrayList.size(); b++) {
|
||||||
MessageObject m = arrayList.get(b);
|
MessageObject m = arrayList.get(b);
|
||||||
m.replyMessageObject = messageObject;
|
m.replyMessageObject = messageObject;
|
||||||
|
if (m.messageOwner.action instanceof TLRPC.TL_messageActionPinMessage) {
|
||||||
|
m.generatePinMessageText(null, null);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
changed = true;
|
changed = true;
|
||||||
}
|
}
|
|
@ -22,9 +22,6 @@ import android.util.Log;
|
||||||
import android.util.SparseBooleanArray;
|
import android.util.SparseBooleanArray;
|
||||||
import android.util.SparseIntArray;
|
import android.util.SparseIntArray;
|
||||||
|
|
||||||
import org.telegram.messenger.support.util.ThreadUtil;
|
|
||||||
import org.telegram.messenger.support.util.TileList;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A utility class that supports asynchronous content loading.
|
* A utility class that supports asynchronous content loading.
|
||||||
* <p>
|
* <p>
|
||||||
|
@ -42,7 +39,7 @@ import org.telegram.messenger.support.util.TileList;
|
||||||
* Note that this class uses a single thread to load the data, so it suitable to load data from
|
* Note that this class uses a single thread to load the data, so it suitable to load data from
|
||||||
* secondary storage such as disk, but not from network.
|
* secondary storage such as disk, but not from network.
|
||||||
* <p>
|
* <p>
|
||||||
* This class is designed to work with {@link org.telegram.messenger.support.widget.RecyclerView}, but it does
|
* This class is designed to work with {@link android.support.v7.widget.RecyclerView}, but it does
|
||||||
* not depend on it and can be used with other list views.
|
* not depend on it and can be used with other list views.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
@ -113,7 +110,7 @@ public class AsyncListUtil<T> {
|
||||||
* <p>
|
* <p>
|
||||||
* Identifies the data items that have not been loaded yet and initiates loading them in the
|
* Identifies the data items that have not been loaded yet and initiates loading them in the
|
||||||
* background. Should be called from the view's scroll listener (such as
|
* background. Should be called from the view's scroll listener (such as
|
||||||
* {@link org.telegram.messenger.support.widget.RecyclerView.OnScrollListener#onScrolled}).
|
* {@link android.support.v7.widget.RecyclerView.OnScrollListener#onScrolled}).
|
||||||
*/
|
*/
|
||||||
public void onRangeChanged() {
|
public void onRangeChanged() {
|
||||||
if (isRefreshPending()) {
|
if (isRefreshPending()) {
|
||||||
|
|
|
@ -18,10 +18,11 @@ package org.telegram.messenger.support.util;
|
||||||
|
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.os.Looper;
|
import android.os.Looper;
|
||||||
|
import android.support.v4.content.ParallelExecutorCompat;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
import java.util.concurrent.Executors;
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
|
||||||
class MessageThreadUtil<T> implements ThreadUtil<T> {
|
class MessageThreadUtil<T> implements ThreadUtil<T> {
|
||||||
|
|
||||||
|
@ -83,7 +84,8 @@ class MessageThreadUtil<T> implements ThreadUtil<T> {
|
||||||
public BackgroundCallback<T> getBackgroundProxy(final BackgroundCallback<T> callback) {
|
public BackgroundCallback<T> getBackgroundProxy(final BackgroundCallback<T> callback) {
|
||||||
return new BackgroundCallback<T>() {
|
return new BackgroundCallback<T>() {
|
||||||
final private MessageQueue mQueue = new MessageQueue();
|
final private MessageQueue mQueue = new MessageQueue();
|
||||||
final private Executor mExecutor = Executors.newSingleThreadExecutor();
|
final private Executor mExecutor = ParallelExecutorCompat.getParallelExecutor();
|
||||||
|
AtomicBoolean mBackgroundRunning = new AtomicBoolean(false);
|
||||||
|
|
||||||
private static final int REFRESH = 1;
|
private static final int REFRESH = 1;
|
||||||
private static final int UPDATE_RANGE = 2;
|
private static final int UPDATE_RANGE = 2;
|
||||||
|
@ -114,42 +116,51 @@ class MessageThreadUtil<T> implements ThreadUtil<T> {
|
||||||
|
|
||||||
private void sendMessage(SyncQueueItem msg) {
|
private void sendMessage(SyncQueueItem msg) {
|
||||||
mQueue.sendMessage(msg);
|
mQueue.sendMessage(msg);
|
||||||
mExecutor.execute(mBackgroundRunnable);
|
maybeExecuteBackgroundRunnable();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void sendMessageAtFrontOfQueue(SyncQueueItem msg) {
|
private void sendMessageAtFrontOfQueue(SyncQueueItem msg) {
|
||||||
mQueue.sendMessageAtFrontOfQueue(msg);
|
mQueue.sendMessageAtFrontOfQueue(msg);
|
||||||
mExecutor.execute(mBackgroundRunnable);
|
maybeExecuteBackgroundRunnable();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void maybeExecuteBackgroundRunnable() {
|
||||||
|
if (mBackgroundRunning.compareAndSet(false, true)) {
|
||||||
|
mExecutor.execute(mBackgroundRunnable);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Runnable mBackgroundRunnable = new Runnable() {
|
private Runnable mBackgroundRunnable = new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
SyncQueueItem msg = mQueue.next();
|
while (true) {
|
||||||
if (msg == null) {
|
SyncQueueItem msg = mQueue.next();
|
||||||
return;
|
if (msg == null) {
|
||||||
}
|
break;
|
||||||
switch (msg.what) {
|
}
|
||||||
case REFRESH:
|
switch (msg.what) {
|
||||||
mQueue.removeMessages(REFRESH);
|
case REFRESH:
|
||||||
callback.refresh(msg.arg1);
|
mQueue.removeMessages(REFRESH);
|
||||||
break;
|
callback.refresh(msg.arg1);
|
||||||
case UPDATE_RANGE:
|
break;
|
||||||
mQueue.removeMessages(UPDATE_RANGE);
|
case UPDATE_RANGE:
|
||||||
mQueue.removeMessages(LOAD_TILE);
|
mQueue.removeMessages(UPDATE_RANGE);
|
||||||
callback.updateRange(
|
mQueue.removeMessages(LOAD_TILE);
|
||||||
msg.arg1, msg.arg2, msg.arg3, msg.arg4, msg.arg5);
|
callback.updateRange(
|
||||||
break;
|
msg.arg1, msg.arg2, msg.arg3, msg.arg4, msg.arg5);
|
||||||
case LOAD_TILE:
|
break;
|
||||||
callback.loadTile(msg.arg1, msg.arg2);
|
case LOAD_TILE:
|
||||||
break;
|
callback.loadTile(msg.arg1, msg.arg2);
|
||||||
case RECYCLE_TILE:
|
break;
|
||||||
//noinspection unchecked
|
case RECYCLE_TILE:
|
||||||
callback.recycleTile((TileList.Tile<T>) msg.data);
|
//noinspection unchecked
|
||||||
break;
|
callback.recycleTile((TileList.Tile<T>) msg.data);
|
||||||
default:
|
break;
|
||||||
Log.e("ThreadUtil", "Unsupported message, what=" + msg.what);
|
default:
|
||||||
|
Log.e("ThreadUtil", "Unsupported message, what=" + msg.what);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
mBackgroundRunning.set(false);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -24,7 +24,7 @@ import java.util.Comparator;
|
||||||
/**
|
/**
|
||||||
* A Sorted list implementation that can keep items in order and also notify for changes in the
|
* A Sorted list implementation that can keep items in order and also notify for changes in the
|
||||||
* list
|
* list
|
||||||
* such that it can be bound to a {@link org.telegram.messenger.support.widget.RecyclerView.Adapter
|
* such that it can be bound to a {@link android.support.v7.widget.RecyclerView.Adapter
|
||||||
* RecyclerView.Adapter}.
|
* RecyclerView.Adapter}.
|
||||||
* <p>
|
* <p>
|
||||||
* It keeps items ordered using the {@link Callback#compare(Object, Object)} method and uses
|
* It keeps items ordered using the {@link Callback#compare(Object, Object)} method and uses
|
||||||
|
@ -737,7 +737,7 @@ public class SortedList<T> {
|
||||||
* so
|
* so
|
||||||
* that you can change its behavior depending on your UI.
|
* that you can change its behavior depending on your UI.
|
||||||
* <p>
|
* <p>
|
||||||
* For example, if you are using SortedList with a {@link org.telegram.messenger.support.widget.RecyclerView.Adapter
|
* For example, if you are using SortedList with a {@link android.support.v7.widget.RecyclerView.Adapter
|
||||||
* RecyclerView.Adapter}, you should
|
* RecyclerView.Adapter}, you should
|
||||||
* return whether the items' visual representations are the same or not.
|
* return whether the items' visual representations are the same or not.
|
||||||
*
|
*
|
||||||
|
|
|
@ -16,8 +16,6 @@
|
||||||
|
|
||||||
package org.telegram.messenger.support.util;
|
package org.telegram.messenger.support.util;
|
||||||
|
|
||||||
import org.telegram.messenger.support.util.TileList;
|
|
||||||
|
|
||||||
interface ThreadUtil<T> {
|
interface ThreadUtil<T> {
|
||||||
|
|
||||||
interface MainThreadCallback<T> {
|
interface MainThreadCallback<T> {
|
||||||
|
|
|
@ -19,9 +19,6 @@ package org.telegram.messenger.support.widget;
|
||||||
import android.support.v4.util.Pools;
|
import android.support.v4.util.Pools;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import org.telegram.messenger.support.widget.OpReorderer;
|
|
||||||
import org.telegram.messenger.support.widget.RecyclerView;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -70,6 +67,8 @@ class AdapterHelper implements OpReorderer.Callback {
|
||||||
|
|
||||||
final OpReorderer mOpReorderer;
|
final OpReorderer mOpReorderer;
|
||||||
|
|
||||||
|
private int mExistingUpdateTypes = 0;
|
||||||
|
|
||||||
AdapterHelper(Callback callback) {
|
AdapterHelper(Callback callback) {
|
||||||
this(callback, false);
|
this(callback, false);
|
||||||
}
|
}
|
||||||
|
@ -88,6 +87,7 @@ class AdapterHelper implements OpReorderer.Callback {
|
||||||
void reset() {
|
void reset() {
|
||||||
recycleUpdateOpsAndClearList(mPendingUpdates);
|
recycleUpdateOpsAndClearList(mPendingUpdates);
|
||||||
recycleUpdateOpsAndClearList(mPostponedList);
|
recycleUpdateOpsAndClearList(mPostponedList);
|
||||||
|
mExistingUpdateTypes = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void preProcess() {
|
void preProcess() {
|
||||||
|
@ -122,6 +122,7 @@ class AdapterHelper implements OpReorderer.Callback {
|
||||||
mCallback.onDispatchSecondPass(mPostponedList.get(i));
|
mCallback.onDispatchSecondPass(mPostponedList.get(i));
|
||||||
}
|
}
|
||||||
recycleUpdateOpsAndClearList(mPostponedList);
|
recycleUpdateOpsAndClearList(mPostponedList);
|
||||||
|
mExistingUpdateTypes = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void applyMove(UpdateOp op) {
|
private void applyMove(UpdateOp op) {
|
||||||
|
@ -460,6 +461,10 @@ class AdapterHelper implements OpReorderer.Callback {
|
||||||
return mPendingUpdates.size() > 0;
|
return mPendingUpdates.size() > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
boolean hasAnyUpdateTypes(int updateTypes) {
|
||||||
|
return (mExistingUpdateTypes & updateTypes) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
int findPositionOffset(int position) {
|
int findPositionOffset(int position) {
|
||||||
return findPositionOffset(position, 0);
|
return findPositionOffset(position, 0);
|
||||||
}
|
}
|
||||||
|
@ -498,6 +503,7 @@ class AdapterHelper implements OpReorderer.Callback {
|
||||||
*/
|
*/
|
||||||
boolean onItemRangeChanged(int positionStart, int itemCount, Object payload) {
|
boolean onItemRangeChanged(int positionStart, int itemCount, Object payload) {
|
||||||
mPendingUpdates.add(obtainUpdateOp(UpdateOp.UPDATE, positionStart, itemCount, payload));
|
mPendingUpdates.add(obtainUpdateOp(UpdateOp.UPDATE, positionStart, itemCount, payload));
|
||||||
|
mExistingUpdateTypes |= UpdateOp.UPDATE;
|
||||||
return mPendingUpdates.size() == 1;
|
return mPendingUpdates.size() == 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -506,6 +512,7 @@ class AdapterHelper implements OpReorderer.Callback {
|
||||||
*/
|
*/
|
||||||
boolean onItemRangeInserted(int positionStart, int itemCount) {
|
boolean onItemRangeInserted(int positionStart, int itemCount) {
|
||||||
mPendingUpdates.add(obtainUpdateOp(UpdateOp.ADD, positionStart, itemCount, null));
|
mPendingUpdates.add(obtainUpdateOp(UpdateOp.ADD, positionStart, itemCount, null));
|
||||||
|
mExistingUpdateTypes |= UpdateOp.ADD;
|
||||||
return mPendingUpdates.size() == 1;
|
return mPendingUpdates.size() == 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -514,6 +521,7 @@ class AdapterHelper implements OpReorderer.Callback {
|
||||||
*/
|
*/
|
||||||
boolean onItemRangeRemoved(int positionStart, int itemCount) {
|
boolean onItemRangeRemoved(int positionStart, int itemCount) {
|
||||||
mPendingUpdates.add(obtainUpdateOp(UpdateOp.REMOVE, positionStart, itemCount, null));
|
mPendingUpdates.add(obtainUpdateOp(UpdateOp.REMOVE, positionStart, itemCount, null));
|
||||||
|
mExistingUpdateTypes |= UpdateOp.REMOVE;
|
||||||
return mPendingUpdates.size() == 1;
|
return mPendingUpdates.size() == 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -522,12 +530,13 @@ class AdapterHelper implements OpReorderer.Callback {
|
||||||
*/
|
*/
|
||||||
boolean onItemRangeMoved(int from, int to, int itemCount) {
|
boolean onItemRangeMoved(int from, int to, int itemCount) {
|
||||||
if (from == to) {
|
if (from == to) {
|
||||||
return false;//no-op
|
return false; // no-op
|
||||||
}
|
}
|
||||||
if (itemCount != 1) {
|
if (itemCount != 1) {
|
||||||
throw new IllegalArgumentException("Moving more than 1 item is not supported yet");
|
throw new IllegalArgumentException("Moving more than 1 item is not supported yet");
|
||||||
}
|
}
|
||||||
mPendingUpdates.add(obtainUpdateOp(UpdateOp.MOVE, from, to, null));
|
mPendingUpdates.add(obtainUpdateOp(UpdateOp.MOVE, from, to, null));
|
||||||
|
mExistingUpdateTypes |= UpdateOp.MOVE;
|
||||||
return mPendingUpdates.size() == 1;
|
return mPendingUpdates.size() == 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -564,6 +573,7 @@ class AdapterHelper implements OpReorderer.Callback {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
recycleUpdateOpsAndClearList(mPendingUpdates);
|
recycleUpdateOpsAndClearList(mPendingUpdates);
|
||||||
|
mExistingUpdateTypes = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int applyPendingUpdatesToPosition(int position) {
|
public int applyPendingUpdatesToPosition(int position) {
|
||||||
|
@ -602,18 +612,22 @@ class AdapterHelper implements OpReorderer.Callback {
|
||||||
return position;
|
return position;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
boolean hasUpdates() {
|
||||||
|
return !mPostponedList.isEmpty() && !mPendingUpdates.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Queued operation to happen when child views are updated.
|
* Queued operation to happen when child views are updated.
|
||||||
*/
|
*/
|
||||||
static class UpdateOp {
|
static class UpdateOp {
|
||||||
|
|
||||||
static final int ADD = 0;
|
static final int ADD = 1;
|
||||||
|
|
||||||
static final int REMOVE = 1;
|
static final int REMOVE = 1 << 1;
|
||||||
|
|
||||||
static final int UPDATE = 2;
|
static final int UPDATE = 1 << 2;
|
||||||
|
|
||||||
static final int MOVE = 3;
|
static final int MOVE = 1 << 3;
|
||||||
|
|
||||||
static final int POOL_SIZE = 30;
|
static final int POOL_SIZE = 30;
|
||||||
|
|
||||||
|
|
|
@ -208,8 +208,8 @@ class ChildHelper {
|
||||||
for (int i = 0; i < count; i++) {
|
for (int i = 0; i < count; i++) {
|
||||||
final View view = mHiddenViews.get(i);
|
final View view = mHiddenViews.get(i);
|
||||||
RecyclerView.ViewHolder holder = mCallback.getChildViewHolder(view);
|
RecyclerView.ViewHolder holder = mCallback.getChildViewHolder(view);
|
||||||
if (holder.getLayoutPosition() == position && !holder.isInvalid() &&
|
if (holder.getLayoutPosition() == position && !holder.isInvalid() && !holder.isRemoved()
|
||||||
(type == RecyclerView.INVALID_TYPE || holder.getItemViewType() == type)) {
|
&& (type == RecyclerView.INVALID_TYPE || holder.getItemViewType() == type)) {
|
||||||
return view;
|
return view;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -339,6 +339,25 @@ class ChildHelper {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Moves a child view from hidden list to regular list.
|
||||||
|
* Calling this method should probably be followed by a detach, otherwise, it will suddenly
|
||||||
|
* show up in LayoutManager's children list.
|
||||||
|
*
|
||||||
|
* @param view The hidden View to unhide
|
||||||
|
*/
|
||||||
|
void unhide(View view) {
|
||||||
|
final int offset = mCallback.indexOfChild(view);
|
||||||
|
if (offset < 0) {
|
||||||
|
throw new IllegalArgumentException("view is not a child, cannot hide " + view);
|
||||||
|
}
|
||||||
|
if (!mBucket.get(offset)) {
|
||||||
|
throw new RuntimeException("trying to unhide a view that was not hidden" + view);
|
||||||
|
}
|
||||||
|
mBucket.clear(offset);
|
||||||
|
unhideViewInternal(view);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return mBucket.toString() + ", hidden list:" + mHiddenViews.size();
|
return mBucket.toString() + ", hidden list:" + mHiddenViews.size();
|
||||||
|
|
|
@ -15,12 +15,11 @@
|
||||||
*/
|
*/
|
||||||
package org.telegram.messenger.support.widget;
|
package org.telegram.messenger.support.widget;
|
||||||
|
|
||||||
|
import android.support.annotation.NonNull;
|
||||||
import android.support.v4.animation.AnimatorCompatHelper;
|
import android.support.v4.animation.AnimatorCompatHelper;
|
||||||
import android.support.v4.view.ViewCompat;
|
import android.support.v4.view.ViewCompat;
|
||||||
import android.support.v4.view.ViewPropertyAnimatorCompat;
|
import android.support.v4.view.ViewPropertyAnimatorCompat;
|
||||||
import android.support.v4.view.ViewPropertyAnimatorListener;
|
import android.support.v4.view.ViewPropertyAnimatorListener;
|
||||||
|
|
||||||
import org.telegram.messenger.support.widget.RecyclerView;
|
|
||||||
import org.telegram.messenger.support.widget.RecyclerView.ViewHolder;
|
import org.telegram.messenger.support.widget.RecyclerView.ViewHolder;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
|
|
||||||
|
@ -34,23 +33,22 @@ import java.util.List;
|
||||||
*
|
*
|
||||||
* @see RecyclerView#setItemAnimator(RecyclerView.ItemAnimator)
|
* @see RecyclerView#setItemAnimator(RecyclerView.ItemAnimator)
|
||||||
*/
|
*/
|
||||||
public class DefaultItemAnimator extends RecyclerView.ItemAnimator {
|
public class DefaultItemAnimator extends SimpleItemAnimator {
|
||||||
private static final boolean DEBUG = false;
|
private static final boolean DEBUG = false;
|
||||||
|
|
||||||
private ArrayList<ViewHolder> mPendingRemovals = new ArrayList<ViewHolder>();
|
private ArrayList<ViewHolder> mPendingRemovals = new ArrayList<>();
|
||||||
private ArrayList<ViewHolder> mPendingAdditions = new ArrayList<ViewHolder>();
|
private ArrayList<ViewHolder> mPendingAdditions = new ArrayList<>();
|
||||||
private ArrayList<MoveInfo> mPendingMoves = new ArrayList<MoveInfo>();
|
private ArrayList<MoveInfo> mPendingMoves = new ArrayList<>();
|
||||||
private ArrayList<ChangeInfo> mPendingChanges = new ArrayList<ChangeInfo>();
|
private ArrayList<ChangeInfo> mPendingChanges = new ArrayList<>();
|
||||||
|
|
||||||
private ArrayList<ArrayList<ViewHolder>> mAdditionsList =
|
private ArrayList<ArrayList<ViewHolder>> mAdditionsList = new ArrayList<>();
|
||||||
new ArrayList<ArrayList<ViewHolder>>();
|
private ArrayList<ArrayList<MoveInfo>> mMovesList = new ArrayList<>();
|
||||||
private ArrayList<ArrayList<MoveInfo>> mMovesList = new ArrayList<ArrayList<MoveInfo>>();
|
private ArrayList<ArrayList<ChangeInfo>> mChangesList = new ArrayList<>();
|
||||||
private ArrayList<ArrayList<ChangeInfo>> mChangesList = new ArrayList<ArrayList<ChangeInfo>>();
|
|
||||||
|
|
||||||
private ArrayList<ViewHolder> mAddAnimations = new ArrayList<ViewHolder>();
|
private ArrayList<ViewHolder> mAddAnimations = new ArrayList<>();
|
||||||
private ArrayList<ViewHolder> mMoveAnimations = new ArrayList<ViewHolder>();
|
private ArrayList<ViewHolder> mMoveAnimations = new ArrayList<>();
|
||||||
private ArrayList<ViewHolder> mRemoveAnimations = new ArrayList<ViewHolder>();
|
private ArrayList<ViewHolder> mRemoveAnimations = new ArrayList<>();
|
||||||
private ArrayList<ViewHolder> mChangeAnimations = new ArrayList<ViewHolder>();
|
private ArrayList<ViewHolder> mChangeAnimations = new ArrayList<>();
|
||||||
|
|
||||||
private static class MoveInfo {
|
private static class MoveInfo {
|
||||||
public ViewHolder holder;
|
public ViewHolder holder;
|
||||||
|
@ -112,7 +110,7 @@ public class DefaultItemAnimator extends RecyclerView.ItemAnimator {
|
||||||
mPendingRemovals.clear();
|
mPendingRemovals.clear();
|
||||||
// Next, move stuff
|
// Next, move stuff
|
||||||
if (movesPending) {
|
if (movesPending) {
|
||||||
final ArrayList<MoveInfo> moves = new ArrayList<MoveInfo>();
|
final ArrayList<MoveInfo> moves = new ArrayList<>();
|
||||||
moves.addAll(mPendingMoves);
|
moves.addAll(mPendingMoves);
|
||||||
mMovesList.add(moves);
|
mMovesList.add(moves);
|
||||||
mPendingMoves.clear();
|
mPendingMoves.clear();
|
||||||
|
@ -136,7 +134,7 @@ public class DefaultItemAnimator extends RecyclerView.ItemAnimator {
|
||||||
}
|
}
|
||||||
// Next, change stuff, to run in parallel with move animations
|
// Next, change stuff, to run in parallel with move animations
|
||||||
if (changesPending) {
|
if (changesPending) {
|
||||||
final ArrayList<ChangeInfo> changes = new ArrayList<ChangeInfo>();
|
final ArrayList<ChangeInfo> changes = new ArrayList<>();
|
||||||
changes.addAll(mPendingChanges);
|
changes.addAll(mPendingChanges);
|
||||||
mChangesList.add(changes);
|
mChangesList.add(changes);
|
||||||
mPendingChanges.clear();
|
mPendingChanges.clear();
|
||||||
|
@ -159,7 +157,7 @@ public class DefaultItemAnimator extends RecyclerView.ItemAnimator {
|
||||||
}
|
}
|
||||||
// Next, add stuff
|
// Next, add stuff
|
||||||
if (additionsPending) {
|
if (additionsPending) {
|
||||||
final ArrayList<ViewHolder> additions = new ArrayList<ViewHolder>();
|
final ArrayList<ViewHolder> additions = new ArrayList<>();
|
||||||
additions.addAll(mPendingAdditions);
|
additions.addAll(mPendingAdditions);
|
||||||
mAdditionsList.add(additions);
|
mAdditionsList.add(additions);
|
||||||
mPendingAdditions.clear();
|
mPendingAdditions.clear();
|
||||||
|
@ -312,6 +310,11 @@ public class DefaultItemAnimator extends RecyclerView.ItemAnimator {
|
||||||
@Override
|
@Override
|
||||||
public boolean animateChange(ViewHolder oldHolder, ViewHolder newHolder,
|
public boolean animateChange(ViewHolder oldHolder, ViewHolder newHolder,
|
||||||
int fromX, int fromY, int toX, int toY) {
|
int fromX, int fromY, int toX, int toY) {
|
||||||
|
if (oldHolder == newHolder) {
|
||||||
|
// Don't know how to run change animations when the same view holder is re-used.
|
||||||
|
// run a move animation to handle position changes.
|
||||||
|
return animateMove(oldHolder, fromX, fromY, toX, toY);
|
||||||
|
}
|
||||||
final float prevTranslationX = ViewCompat.getTranslationX(oldHolder.itemView);
|
final float prevTranslationX = ViewCompat.getTranslationX(oldHolder.itemView);
|
||||||
final float prevTranslationY = ViewCompat.getTranslationY(oldHolder.itemView);
|
final float prevTranslationY = ViewCompat.getTranslationY(oldHolder.itemView);
|
||||||
final float prevAlpha = ViewCompat.getAlpha(oldHolder.itemView);
|
final float prevAlpha = ViewCompat.getAlpha(oldHolder.itemView);
|
||||||
|
@ -322,7 +325,7 @@ public class DefaultItemAnimator extends RecyclerView.ItemAnimator {
|
||||||
ViewCompat.setTranslationX(oldHolder.itemView, prevTranslationX);
|
ViewCompat.setTranslationX(oldHolder.itemView, prevTranslationX);
|
||||||
ViewCompat.setTranslationY(oldHolder.itemView, prevTranslationY);
|
ViewCompat.setTranslationY(oldHolder.itemView, prevTranslationY);
|
||||||
ViewCompat.setAlpha(oldHolder.itemView, prevAlpha);
|
ViewCompat.setAlpha(oldHolder.itemView, prevAlpha);
|
||||||
if (newHolder != null && newHolder.itemView != null) {
|
if (newHolder != null) {
|
||||||
// carry over translation values
|
// carry over translation values
|
||||||
resetAnimation(newHolder);
|
resetAnimation(newHolder);
|
||||||
ViewCompat.setTranslationX(newHolder.itemView, -deltaX);
|
ViewCompat.setTranslationX(newHolder.itemView, -deltaX);
|
||||||
|
@ -481,21 +484,25 @@ public class DefaultItemAnimator extends RecyclerView.ItemAnimator {
|
||||||
}
|
}
|
||||||
|
|
||||||
// animations should be ended by the cancel above.
|
// animations should be ended by the cancel above.
|
||||||
|
//noinspection PointlessBooleanExpression,ConstantConditions
|
||||||
if (mRemoveAnimations.remove(item) && DEBUG) {
|
if (mRemoveAnimations.remove(item) && DEBUG) {
|
||||||
throw new IllegalStateException("after animation is cancelled, item should not be in "
|
throw new IllegalStateException("after animation is cancelled, item should not be in "
|
||||||
+ "mRemoveAnimations list");
|
+ "mRemoveAnimations list");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//noinspection PointlessBooleanExpression,ConstantConditions
|
||||||
if (mAddAnimations.remove(item) && DEBUG) {
|
if (mAddAnimations.remove(item) && DEBUG) {
|
||||||
throw new IllegalStateException("after animation is cancelled, item should not be in "
|
throw new IllegalStateException("after animation is cancelled, item should not be in "
|
||||||
+ "mAddAnimations list");
|
+ "mAddAnimations list");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//noinspection PointlessBooleanExpression,ConstantConditions
|
||||||
if (mChangeAnimations.remove(item) && DEBUG) {
|
if (mChangeAnimations.remove(item) && DEBUG) {
|
||||||
throw new IllegalStateException("after animation is cancelled, item should not be in "
|
throw new IllegalStateException("after animation is cancelled, item should not be in "
|
||||||
+ "mChangeAnimations list");
|
+ "mChangeAnimations list");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//noinspection PointlessBooleanExpression,ConstantConditions
|
||||||
if (mMoveAnimations.remove(item) && DEBUG) {
|
if (mMoveAnimations.remove(item) && DEBUG) {
|
||||||
throw new IllegalStateException("after animation is cancelled, item should not be in "
|
throw new IllegalStateException("after animation is cancelled, item should not be in "
|
||||||
+ "mMoveAnimations list");
|
+ "mMoveAnimations list");
|
||||||
|
@ -626,6 +633,28 @@ public class DefaultItemAnimator extends RecyclerView.ItemAnimator {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
* <p>
|
||||||
|
* If the payload list is not empty, DefaultItemAnimator returns <code>true</code>.
|
||||||
|
* When this is the case:
|
||||||
|
* <ul>
|
||||||
|
* <li>If you override {@link #animateChange(ViewHolder, ViewHolder, int, int, int, int)}, both
|
||||||
|
* ViewHolder arguments will be the same instance.
|
||||||
|
* </li>
|
||||||
|
* <li>
|
||||||
|
* If you are not overriding {@link #animateChange(ViewHolder, ViewHolder, int, int, int, int)},
|
||||||
|
* then DefaultItemAnimator will call {@link #animateMove(ViewHolder, int, int, int, int)} and
|
||||||
|
* run a move animation instead.
|
||||||
|
* </li>
|
||||||
|
* </ul>
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean canReuseUpdatedViewHolder(@NonNull ViewHolder viewHolder,
|
||||||
|
@NonNull List<Object> payloads) {
|
||||||
|
return !payloads.isEmpty() || super.canReuseUpdatedViewHolder(viewHolder, payloads);
|
||||||
|
}
|
||||||
|
|
||||||
private static class VpaListenerAdapter implements ViewPropertyAnimatorListener {
|
private static class VpaListenerAdapter implements ViewPropertyAnimatorListener {
|
||||||
@Override
|
@Override
|
||||||
public void onAnimationStart(View view) {}
|
public void onAnimationStart(View view) {}
|
||||||
|
@ -635,5 +664,5 @@ public class DefaultItemAnimator extends RecyclerView.ItemAnimator {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onAnimationCancel(View view) {}
|
public void onAnimationCancel(View view) {}
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,11 +37,6 @@ public class GridLayoutManager extends LinearLayoutManager {
|
||||||
private static final boolean DEBUG = false;
|
private static final boolean DEBUG = false;
|
||||||
private static final String TAG = "GridLayoutManager";
|
private static final String TAG = "GridLayoutManager";
|
||||||
public static final int DEFAULT_SPAN_COUNT = -1;
|
public static final int DEFAULT_SPAN_COUNT = -1;
|
||||||
/**
|
|
||||||
* The measure spec for the scroll direction.
|
|
||||||
*/
|
|
||||||
static final int MAIN_DIR_SPEC =
|
|
||||||
View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
|
|
||||||
/**
|
/**
|
||||||
* Span size have been changed but we've not done a new layout calculation.
|
* Span size have been changed but we've not done a new layout calculation.
|
||||||
*/
|
*/
|
||||||
|
@ -63,6 +58,21 @@ public class GridLayoutManager extends LinearLayoutManager {
|
||||||
// re-used variable to acquire decor insets from RecyclerView
|
// re-used variable to acquire decor insets from RecyclerView
|
||||||
final Rect mDecorInsets = new Rect();
|
final Rect mDecorInsets = new Rect();
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor used when layout manager is set in XML by RecyclerView attribute
|
||||||
|
* "layoutManager". If spanCount is not specified in the XML, it defaults to a
|
||||||
|
* single column.
|
||||||
|
*
|
||||||
|
* @attr ref android.support.v7.recyclerview.R.styleable#RecyclerView_spanCount
|
||||||
|
*/
|
||||||
|
public GridLayoutManager(Context context, AttributeSet attrs, int defStyleAttr,
|
||||||
|
int defStyleRes) {
|
||||||
|
super(context, attrs, defStyleAttr, defStyleRes);
|
||||||
|
Properties properties = getProperties(context, attrs, defStyleAttr, defStyleRes);
|
||||||
|
setSpanCount(properties.spanCount);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a vertical GridLayoutManager
|
* Creates a vertical GridLayoutManager
|
||||||
*
|
*
|
||||||
|
@ -110,7 +120,9 @@ public class GridLayoutManager extends LinearLayoutManager {
|
||||||
if (state.getItemCount() < 1) {
|
if (state.getItemCount() < 1) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return getSpanGroupIndex(recycler, state, state.getItemCount() - 1);
|
|
||||||
|
// Row count is one more than the last item's row index.
|
||||||
|
return getSpanGroupIndex(recycler, state, state.getItemCount() - 1) + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -122,7 +134,9 @@ public class GridLayoutManager extends LinearLayoutManager {
|
||||||
if (state.getItemCount() < 1) {
|
if (state.getItemCount() < 1) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return getSpanGroupIndex(recycler, state, state.getItemCount() - 1);
|
|
||||||
|
// Column count is one more than the last item's column index.
|
||||||
|
return getSpanGroupIndex(recycler, state, state.getItemCount() - 1) + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -206,8 +220,13 @@ public class GridLayoutManager extends LinearLayoutManager {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public RecyclerView.LayoutParams generateDefaultLayoutParams() {
|
public RecyclerView.LayoutParams generateDefaultLayoutParams() {
|
||||||
return new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
|
if (mOrientation == HORIZONTAL) {
|
||||||
ViewGroup.LayoutParams.WRAP_CONTENT);
|
return new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
|
||||||
|
ViewGroup.LayoutParams.FILL_PARENT);
|
||||||
|
} else {
|
||||||
|
return new LayoutParams(ViewGroup.LayoutParams.FILL_PARENT,
|
||||||
|
ViewGroup.LayoutParams.WRAP_CONTENT);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -258,47 +277,124 @@ public class GridLayoutManager extends LinearLayoutManager {
|
||||||
calculateItemBorders(totalSpace);
|
calculateItemBorders(totalSpace);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void calculateItemBorders(int totalSpace) {
|
@Override
|
||||||
if (mCachedBorders == null || mCachedBorders.length != mSpanCount + 1
|
public void setMeasuredDimension(Rect childrenBounds, int wSpec, int hSpec) {
|
||||||
|| mCachedBorders[mCachedBorders.length - 1] != totalSpace) {
|
if (mCachedBorders == null) {
|
||||||
mCachedBorders = new int[mSpanCount + 1];
|
super.setMeasuredDimension(childrenBounds, wSpec, hSpec);
|
||||||
}
|
}
|
||||||
mCachedBorders[0] = 0;
|
final int width, height;
|
||||||
int sizePerSpan = totalSpace / mSpanCount;
|
final int horizontalPadding = getPaddingLeft() + getPaddingRight();
|
||||||
int sizePerSpanRemainder = totalSpace % mSpanCount;
|
final int verticalPadding = getPaddingTop() + getPaddingBottom();
|
||||||
|
if (mOrientation == VERTICAL) {
|
||||||
|
final int usedHeight = childrenBounds.height() + verticalPadding;
|
||||||
|
height = chooseSize(hSpec, usedHeight, getMinimumHeight());
|
||||||
|
width = chooseSize(wSpec, mCachedBorders[mCachedBorders.length - 1] + horizontalPadding,
|
||||||
|
getMinimumWidth());
|
||||||
|
} else {
|
||||||
|
final int usedWidth = childrenBounds.width() + horizontalPadding;
|
||||||
|
width = chooseSize(wSpec, usedWidth, getMinimumWidth());
|
||||||
|
height = chooseSize(hSpec, mCachedBorders[mCachedBorders.length - 1] + verticalPadding,
|
||||||
|
getMinimumHeight());
|
||||||
|
}
|
||||||
|
setMeasuredDimension(width, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param totalSpace Total available space after padding is removed
|
||||||
|
*/
|
||||||
|
private void calculateItemBorders(int totalSpace) {
|
||||||
|
mCachedBorders = calculateItemBorders(mCachedBorders, mSpanCount, totalSpace);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param cachedBorders The out array
|
||||||
|
* @param spanCount number of spans
|
||||||
|
* @param totalSpace total available space after padding is removed
|
||||||
|
* @return The updated array. Might be the same instance as the provided array if its size
|
||||||
|
* has not changed.
|
||||||
|
*/
|
||||||
|
static int[] calculateItemBorders(int[] cachedBorders, int spanCount, int totalSpace) {
|
||||||
|
if (cachedBorders == null || cachedBorders.length != spanCount + 1
|
||||||
|
|| cachedBorders[cachedBorders.length - 1] != totalSpace) {
|
||||||
|
cachedBorders = new int[spanCount + 1];
|
||||||
|
}
|
||||||
|
cachedBorders[0] = 0;
|
||||||
|
int sizePerSpan = totalSpace / spanCount;
|
||||||
|
int sizePerSpanRemainder = totalSpace % spanCount;
|
||||||
int consumedPixels = 0;
|
int consumedPixels = 0;
|
||||||
int additionalSize = 0;
|
int additionalSize = 0;
|
||||||
for (int i = 1; i <= mSpanCount; i++) {
|
for (int i = 1; i <= spanCount; i++) {
|
||||||
int itemSize = sizePerSpan;
|
int itemSize = sizePerSpan;
|
||||||
additionalSize += sizePerSpanRemainder;
|
additionalSize += sizePerSpanRemainder;
|
||||||
if (additionalSize > 0 && (mSpanCount - additionalSize) < sizePerSpanRemainder) {
|
if (additionalSize > 0 && (spanCount - additionalSize) < sizePerSpanRemainder) {
|
||||||
itemSize += 1;
|
itemSize += 1;
|
||||||
additionalSize -= mSpanCount;
|
additionalSize -= spanCount;
|
||||||
}
|
}
|
||||||
consumedPixels += itemSize;
|
consumedPixels += itemSize;
|
||||||
mCachedBorders[i] = consumedPixels;
|
cachedBorders[i] = consumedPixels;
|
||||||
}
|
}
|
||||||
|
return cachedBorders;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
void onAnchorReady(RecyclerView.Recycler recycler, RecyclerView.State state,
|
void onAnchorReady(RecyclerView.Recycler recycler, RecyclerView.State state,
|
||||||
AnchorInfo anchorInfo) {
|
AnchorInfo anchorInfo, int itemDirection) {
|
||||||
super.onAnchorReady(recycler, state, anchorInfo);
|
super.onAnchorReady(recycler, state, anchorInfo, itemDirection);
|
||||||
updateMeasurements();
|
updateMeasurements();
|
||||||
if (state.getItemCount() > 0 && !state.isPreLayout()) {
|
if (state.getItemCount() > 0 && !state.isPreLayout()) {
|
||||||
ensureAnchorIsInFirstSpan(recycler, state, anchorInfo);
|
ensureAnchorIsInCorrectSpan(recycler, state, anchorInfo, itemDirection);
|
||||||
}
|
}
|
||||||
|
ensureViewSet();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ensureViewSet() {
|
||||||
if (mSet == null || mSet.length != mSpanCount) {
|
if (mSet == null || mSet.length != mSpanCount) {
|
||||||
mSet = new View[mSpanCount];
|
mSet = new View[mSpanCount];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ensureAnchorIsInFirstSpan(RecyclerView.Recycler recycler, RecyclerView.State state,
|
@Override
|
||||||
AnchorInfo anchorInfo) {
|
public int scrollHorizontallyBy(int dx, RecyclerView.Recycler recycler,
|
||||||
|
RecyclerView.State state) {
|
||||||
|
updateMeasurements();
|
||||||
|
ensureViewSet();
|
||||||
|
return super.scrollHorizontallyBy(dx, recycler, state);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler,
|
||||||
|
RecyclerView.State state) {
|
||||||
|
updateMeasurements();
|
||||||
|
ensureViewSet();
|
||||||
|
return super.scrollVerticallyBy(dy, recycler, state);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ensureAnchorIsInCorrectSpan(RecyclerView.Recycler recycler,
|
||||||
|
RecyclerView.State state, AnchorInfo anchorInfo, int itemDirection) {
|
||||||
|
final boolean layingOutInPrimaryDirection =
|
||||||
|
itemDirection == LayoutState.ITEM_DIRECTION_TAIL;
|
||||||
int span = getSpanIndex(recycler, state, anchorInfo.mPosition);
|
int span = getSpanIndex(recycler, state, anchorInfo.mPosition);
|
||||||
while (span > 0 && anchorInfo.mPosition > 0) {
|
if (layingOutInPrimaryDirection) {
|
||||||
anchorInfo.mPosition--;
|
// choose span 0
|
||||||
span = getSpanIndex(recycler, state, anchorInfo.mPosition);
|
while (span > 0 && anchorInfo.mPosition > 0) {
|
||||||
|
anchorInfo.mPosition--;
|
||||||
|
span = getSpanIndex(recycler, state, anchorInfo.mPosition);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// choose the max span we can get. hopefully last one
|
||||||
|
final int indexLimit = state.getItemCount() - 1;
|
||||||
|
int pos = anchorInfo.mPosition;
|
||||||
|
int bestSpan = span;
|
||||||
|
while (pos < indexLimit) {
|
||||||
|
int next = getSpanIndex(recycler, state, pos + 1);
|
||||||
|
if (next > bestSpan) {
|
||||||
|
pos += 1;
|
||||||
|
bestSpan = next;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
anchorInfo.mPosition = pos;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -398,6 +494,15 @@ public class GridLayoutManager extends LinearLayoutManager {
|
||||||
@Override
|
@Override
|
||||||
void layoutChunk(RecyclerView.Recycler recycler, RecyclerView.State state,
|
void layoutChunk(RecyclerView.Recycler recycler, RecyclerView.State state,
|
||||||
LayoutState layoutState, LayoutChunkResult result) {
|
LayoutState layoutState, LayoutChunkResult result) {
|
||||||
|
final int otherDirSpecMode = mOrientationHelper.getModeInOther();
|
||||||
|
final boolean flexibleInOtherDir = otherDirSpecMode != View.MeasureSpec.EXACTLY;
|
||||||
|
final int currentOtherDirSize = getChildCount() > 0 ? mCachedBorders[mSpanCount] : 0;
|
||||||
|
// if grid layout's dimensions are not specified, let the new row change the measurements
|
||||||
|
// This is not perfect since we not covering all rows but still solves an important case
|
||||||
|
// where they may have a header row which should be laid out according to children.
|
||||||
|
if (flexibleInOtherDir) {
|
||||||
|
updateMeasurements(); // reset measurements
|
||||||
|
}
|
||||||
final boolean layingOutInPrimaryDirection =
|
final boolean layingOutInPrimaryDirection =
|
||||||
layoutState.mItemDirection == LayoutState.ITEM_DIRECTION_TAIL;
|
layoutState.mItemDirection == LayoutState.ITEM_DIRECTION_TAIL;
|
||||||
int count = 0;
|
int count = 0;
|
||||||
|
@ -435,6 +540,7 @@ public class GridLayoutManager extends LinearLayoutManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
int maxSize = 0;
|
int maxSize = 0;
|
||||||
|
float maxSizeInOther = 0; // use a float to get size per span
|
||||||
|
|
||||||
// we should assign spans before item decor offsets are calculated
|
// we should assign spans before item decor offsets are calculated
|
||||||
assignSpans(recycler, state, count, consumedSpanCount, layingOutInPrimaryDirection);
|
assignSpans(recycler, state, count, consumedSpanCount, layingOutInPrimaryDirection);
|
||||||
|
@ -455,35 +561,73 @@ public class GridLayoutManager extends LinearLayoutManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
final LayoutParams lp = (LayoutParams) view.getLayoutParams();
|
final LayoutParams lp = (LayoutParams) view.getLayoutParams();
|
||||||
final int spec = View.MeasureSpec.makeMeasureSpec(
|
final int spec = getChildMeasureSpec(mCachedBorders[lp.mSpanIndex + lp.mSpanSize] -
|
||||||
mCachedBorders[lp.mSpanIndex + lp.mSpanSize] -
|
mCachedBorders[lp.mSpanIndex], otherDirSpecMode, 0,
|
||||||
mCachedBorders[lp.mSpanIndex],
|
mOrientation == HORIZONTAL ? lp.height : lp.width,
|
||||||
View.MeasureSpec.EXACTLY);
|
false);
|
||||||
|
final int mainSpec = getChildMeasureSpec(mOrientationHelper.getTotalSpace(),
|
||||||
|
mOrientationHelper.getMode(), 0,
|
||||||
|
mOrientation == VERTICAL ? lp.height : lp.width, true);
|
||||||
|
// Unless the child has MATCH_PARENT, measure it from its specs before adding insets.
|
||||||
if (mOrientation == VERTICAL) {
|
if (mOrientation == VERTICAL) {
|
||||||
measureChildWithDecorationsAndMargin(view, spec, getMainDirSpec(lp.height), false);
|
@SuppressWarnings("deprecation")
|
||||||
|
final boolean applyInsets = lp.height == ViewGroup.LayoutParams.FILL_PARENT;
|
||||||
|
measureChildWithDecorationsAndMargin(view, spec, mainSpec, applyInsets, false);
|
||||||
} else {
|
} else {
|
||||||
measureChildWithDecorationsAndMargin(view, getMainDirSpec(lp.width), spec, false);
|
//noinspection deprecation
|
||||||
|
final boolean applyInsets = lp.width == ViewGroup.LayoutParams.FILL_PARENT;
|
||||||
|
measureChildWithDecorationsAndMargin(view, mainSpec, spec, applyInsets, false);
|
||||||
}
|
}
|
||||||
final int size = mOrientationHelper.getDecoratedMeasurement(view);
|
final int size = mOrientationHelper.getDecoratedMeasurement(view);
|
||||||
if (size > maxSize) {
|
if (size > maxSize) {
|
||||||
maxSize = size;
|
maxSize = size;
|
||||||
}
|
}
|
||||||
|
final float otherSize = 1f * mOrientationHelper.getDecoratedMeasurementInOther(view) /
|
||||||
|
lp.mSpanSize;
|
||||||
|
if (otherSize > maxSizeInOther) {
|
||||||
|
maxSizeInOther = otherSize;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
if (flexibleInOtherDir) {
|
||||||
// views that did not measure the maxSize has to be re-measured
|
// re-distribute columns
|
||||||
final int maxMeasureSpec = getMainDirSpec(maxSize);
|
guessMeasurement(maxSizeInOther, currentOtherDirSize);
|
||||||
|
// now we should re-measure any item that was match parent.
|
||||||
|
maxSize = 0;
|
||||||
|
for (int i = 0; i < count; i++) {
|
||||||
|
View view = mSet[i];
|
||||||
|
final LayoutParams lp = (LayoutParams) view.getLayoutParams();
|
||||||
|
final int spec = getChildMeasureSpec(mCachedBorders[lp.mSpanIndex + lp.mSpanSize] -
|
||||||
|
mCachedBorders[lp.mSpanIndex], View.MeasureSpec.EXACTLY, 0,
|
||||||
|
mOrientation == HORIZONTAL ? lp.height : lp.width, false);
|
||||||
|
final int mainSpec = getChildMeasureSpec(mOrientationHelper.getTotalSpace(),
|
||||||
|
mOrientationHelper.getMode(), 0,
|
||||||
|
mOrientation == VERTICAL ? lp.height : lp.width, true);
|
||||||
|
if (mOrientation == VERTICAL) {
|
||||||
|
measureChildWithDecorationsAndMargin(view, spec, mainSpec, false, true);
|
||||||
|
} else {
|
||||||
|
measureChildWithDecorationsAndMargin(view, mainSpec, spec, false, true);
|
||||||
|
}
|
||||||
|
final int size = mOrientationHelper.getDecoratedMeasurement(view);
|
||||||
|
if (size > maxSize) {
|
||||||
|
maxSize = size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Views that did not measure the maxSize has to be re-measured
|
||||||
|
// We will stop doing this once we introduce Gravity in the GLM layout params
|
||||||
|
final int maxMeasureSpec = View.MeasureSpec.makeMeasureSpec(maxSize,
|
||||||
|
View.MeasureSpec.EXACTLY);
|
||||||
for (int i = 0; i < count; i ++) {
|
for (int i = 0; i < count; i ++) {
|
||||||
final View view = mSet[i];
|
final View view = mSet[i];
|
||||||
if (mOrientationHelper.getDecoratedMeasurement(view) != maxSize) {
|
if (mOrientationHelper.getDecoratedMeasurement(view) != maxSize) {
|
||||||
final LayoutParams lp = (LayoutParams) view.getLayoutParams();
|
final LayoutParams lp = (LayoutParams) view.getLayoutParams();
|
||||||
final int spec = View.MeasureSpec.makeMeasureSpec(
|
final int spec = getChildMeasureSpec(mCachedBorders[lp.mSpanIndex + lp.mSpanSize]
|
||||||
mCachedBorders[lp.mSpanIndex + lp.mSpanSize] -
|
- mCachedBorders[lp.mSpanIndex], View.MeasureSpec.EXACTLY, 0,
|
||||||
mCachedBorders[lp.mSpanIndex],
|
mOrientation == HORIZONTAL ? lp.height : lp.width, false);
|
||||||
View.MeasureSpec.EXACTLY);
|
|
||||||
if (mOrientation == VERTICAL) {
|
if (mOrientation == VERTICAL) {
|
||||||
measureChildWithDecorationsAndMargin(view, spec, maxMeasureSpec, true);
|
measureChildWithDecorationsAndMargin(view, spec, maxMeasureSpec, true, true);
|
||||||
} else {
|
} else {
|
||||||
measureChildWithDecorationsAndMargin(view, maxMeasureSpec, spec, true);
|
measureChildWithDecorationsAndMargin(view, maxMeasureSpec, spec, true, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -512,8 +656,13 @@ public class GridLayoutManager extends LinearLayoutManager {
|
||||||
View view = mSet[i];
|
View view = mSet[i];
|
||||||
LayoutParams params = (LayoutParams) view.getLayoutParams();
|
LayoutParams params = (LayoutParams) view.getLayoutParams();
|
||||||
if (mOrientation == VERTICAL) {
|
if (mOrientation == VERTICAL) {
|
||||||
left = getPaddingLeft() + mCachedBorders[params.mSpanIndex];
|
if (isLayoutRTL()) {
|
||||||
right = left + mOrientationHelper.getDecoratedMeasurementInOther(view);
|
right = getPaddingLeft() + mCachedBorders[params.mSpanIndex + params.mSpanSize];
|
||||||
|
left = right - mOrientationHelper.getDecoratedMeasurementInOther(view);
|
||||||
|
} else {
|
||||||
|
left = getPaddingLeft() + mCachedBorders[params.mSpanIndex];
|
||||||
|
right = left + mOrientationHelper.getDecoratedMeasurementInOther(view);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
top = getPaddingTop() + mCachedBorders[params.mSpanIndex];
|
top = getPaddingTop() + mCachedBorders[params.mSpanIndex];
|
||||||
bottom = top + mOrientationHelper.getDecoratedMeasurementInOther(view);
|
bottom = top + mOrientationHelper.getDecoratedMeasurementInOther(view);
|
||||||
|
@ -537,16 +686,24 @@ public class GridLayoutManager extends LinearLayoutManager {
|
||||||
Arrays.fill(mSet, null);
|
Arrays.fill(mSet, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
private int getMainDirSpec(int dim) {
|
/**
|
||||||
if (dim < 0) {
|
* This is called after laying out a row (if vertical) or a column (if horizontal) when the
|
||||||
return MAIN_DIR_SPEC;
|
* RecyclerView does not have exact measurement specs.
|
||||||
} else {
|
* <p>
|
||||||
return View.MeasureSpec.makeMeasureSpec(dim, View.MeasureSpec.EXACTLY);
|
* Here we try to assign a best guess width or height and re-do the layout to update other
|
||||||
}
|
* views that wanted to FILL_PARENT in the non-scroll orientation.
|
||||||
|
*
|
||||||
|
* @param maxSizeInOther The maximum size per span ratio from the measurement of the children.
|
||||||
|
* @param currentOtherDirSize The size before this layout chunk. There is no reason to go below.
|
||||||
|
*/
|
||||||
|
private void guessMeasurement(float maxSizeInOther, int currentOtherDirSize) {
|
||||||
|
final int contentSize = Math.round(maxSizeInOther * mSpanCount);
|
||||||
|
// always re-calculate because borders were stretched during the fill
|
||||||
|
calculateItemBorders(Math.max(contentSize, currentOtherDirSize));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void measureChildWithDecorationsAndMargin(View child, int widthSpec, int heightSpec,
|
private void measureChildWithDecorationsAndMargin(View child, int widthSpec, int heightSpec,
|
||||||
boolean capBothSpecs) {
|
boolean capBothSpecs, boolean alreadyMeasured) {
|
||||||
calculateItemDecorationsForChild(child, mDecorInsets);
|
calculateItemDecorationsForChild(child, mDecorInsets);
|
||||||
RecyclerView.LayoutParams lp = (RecyclerView.LayoutParams) child.getLayoutParams();
|
RecyclerView.LayoutParams lp = (RecyclerView.LayoutParams) child.getLayoutParams();
|
||||||
if (capBothSpecs || mOrientation == VERTICAL) {
|
if (capBothSpecs || mOrientation == VERTICAL) {
|
||||||
|
@ -557,7 +714,16 @@ public class GridLayoutManager extends LinearLayoutManager {
|
||||||
heightSpec = updateSpecWithExtra(heightSpec, lp.topMargin + mDecorInsets.top,
|
heightSpec = updateSpecWithExtra(heightSpec, lp.topMargin + mDecorInsets.top,
|
||||||
lp.bottomMargin + mDecorInsets.bottom);
|
lp.bottomMargin + mDecorInsets.bottom);
|
||||||
}
|
}
|
||||||
child.measure(widthSpec, heightSpec);
|
final boolean measure;
|
||||||
|
if (alreadyMeasured) {
|
||||||
|
measure = shouldReMeasureChild(child, widthSpec, heightSpec, lp);
|
||||||
|
} else {
|
||||||
|
measure = shouldMeasureChild(child, widthSpec, heightSpec, lp);
|
||||||
|
}
|
||||||
|
if (measure) {
|
||||||
|
child.measure(widthSpec, heightSpec);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private int updateSpecWithExtra(int spec, int startInset, int endInset) {
|
private int updateSpecWithExtra(int spec, int startInset, int endInset) {
|
||||||
|
@ -567,7 +733,7 @@ public class GridLayoutManager extends LinearLayoutManager {
|
||||||
final int mode = View.MeasureSpec.getMode(spec);
|
final int mode = View.MeasureSpec.getMode(spec);
|
||||||
if (mode == View.MeasureSpec.AT_MOST || mode == View.MeasureSpec.EXACTLY) {
|
if (mode == View.MeasureSpec.AT_MOST || mode == View.MeasureSpec.EXACTLY) {
|
||||||
return View.MeasureSpec.makeMeasureSpec(
|
return View.MeasureSpec.makeMeasureSpec(
|
||||||
View.MeasureSpec.getSize(spec) - startInset - endInset, mode);
|
Math.max(0, View.MeasureSpec.getSize(spec) - startInset - endInset), mode);
|
||||||
}
|
}
|
||||||
return spec;
|
return spec;
|
||||||
}
|
}
|
||||||
|
@ -806,6 +972,78 @@ public class GridLayoutManager extends LinearLayoutManager {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public View onFocusSearchFailed(View focused, int focusDirection,
|
||||||
|
RecyclerView.Recycler recycler, RecyclerView.State state) {
|
||||||
|
View prevFocusedChild = findContainingItemView(focused);
|
||||||
|
if (prevFocusedChild == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
LayoutParams lp = (LayoutParams) prevFocusedChild.getLayoutParams();
|
||||||
|
final int prevSpanStart = lp.mSpanIndex;
|
||||||
|
final int prevSpanEnd = lp.mSpanIndex + lp.mSpanSize;
|
||||||
|
View view = super.onFocusSearchFailed(focused, focusDirection, recycler, state);
|
||||||
|
if (view == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
// LinearLayoutManager finds the last child. What we want is the child which has the same
|
||||||
|
// spanIndex.
|
||||||
|
final int layoutDir = convertFocusDirectionToLayoutDirection(focusDirection);
|
||||||
|
final boolean ascend = (layoutDir == LayoutState.LAYOUT_END) != mShouldReverseLayout;
|
||||||
|
final int start, inc, limit;
|
||||||
|
if (ascend) {
|
||||||
|
start = getChildCount() - 1;
|
||||||
|
inc = -1;
|
||||||
|
limit = -1;
|
||||||
|
} else {
|
||||||
|
start = 0;
|
||||||
|
inc = 1;
|
||||||
|
limit = getChildCount();
|
||||||
|
}
|
||||||
|
final boolean preferLastSpan = mOrientation == VERTICAL && isLayoutRTL();
|
||||||
|
View weakCandidate = null; // somewhat matches but not strong
|
||||||
|
int weakCandidateSpanIndex = -1;
|
||||||
|
int weakCandidateOverlap = 0; // how many spans overlap
|
||||||
|
|
||||||
|
for (int i = start; i != limit; i += inc) {
|
||||||
|
View candidate = getChildAt(i);
|
||||||
|
if (candidate == prevFocusedChild) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (!candidate.isFocusable()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
final LayoutParams candidateLp = (LayoutParams) candidate.getLayoutParams();
|
||||||
|
final int candidateStart = candidateLp.mSpanIndex;
|
||||||
|
final int candidateEnd = candidateLp.mSpanIndex + candidateLp.mSpanSize;
|
||||||
|
if (candidateStart == prevSpanStart && candidateEnd == prevSpanEnd) {
|
||||||
|
return candidate; // perfect match
|
||||||
|
}
|
||||||
|
boolean assignAsWeek = false;
|
||||||
|
if (weakCandidate == null) {
|
||||||
|
assignAsWeek = true;
|
||||||
|
} else {
|
||||||
|
int maxStart = Math.max(candidateStart, prevSpanStart);
|
||||||
|
int minEnd = Math.min(candidateEnd, prevSpanEnd);
|
||||||
|
int overlap = minEnd - maxStart;
|
||||||
|
if (overlap > weakCandidateOverlap) {
|
||||||
|
assignAsWeek = true;
|
||||||
|
} else if (overlap == weakCandidateOverlap &&
|
||||||
|
preferLastSpan == (candidateStart > weakCandidateSpanIndex)) {
|
||||||
|
assignAsWeek = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (assignAsWeek) {
|
||||||
|
weakCandidate = candidate;
|
||||||
|
weakCandidateSpanIndex = candidateLp.mSpanIndex;
|
||||||
|
weakCandidateOverlap = Math.min(candidateEnd, prevSpanEnd) -
|
||||||
|
Math.max(candidateStart, prevSpanStart);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return weakCandidate;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean supportsPredictiveItemAnimations() {
|
public boolean supportsPredictiveItemAnimations() {
|
||||||
return mPendingSavedState == null && !mPendingSpanCountChange;
|
return mPendingSavedState == null && !mPendingSpanCountChange;
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.telegram.messenger.support.widget;
|
package org.telegram.messenger.support.widget;
|
||||||
|
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -35,8 +36,11 @@ class LayoutState {
|
||||||
|
|
||||||
final static int ITEM_DIRECTION_TAIL = 1;
|
final static int ITEM_DIRECTION_TAIL = 1;
|
||||||
|
|
||||||
final static int SCOLLING_OFFSET_NaN = Integer.MIN_VALUE;
|
/**
|
||||||
|
* We may not want to recycle children in some cases (e.g. layout)
|
||||||
|
*/
|
||||||
|
boolean mRecycle = true;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Number of pixels that we should fill, in the layout direction.
|
* Number of pixels that we should fill, in the layout direction.
|
||||||
*/
|
*/
|
||||||
|
@ -69,6 +73,16 @@ class LayoutState {
|
||||||
*/
|
*/
|
||||||
int mEndLine = 0;
|
int mEndLine = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If true, layout should stop if a focusable view is added
|
||||||
|
*/
|
||||||
|
boolean mStopInFocusable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If the content is not wrapped with any value
|
||||||
|
*/
|
||||||
|
boolean mInfinite;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return true if there are more items in the data adapter
|
* @return true if there are more items in the data adapter
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -16,6 +16,8 @@
|
||||||
|
|
||||||
package org.telegram.messenger.support.widget;
|
package org.telegram.messenger.support.widget;
|
||||||
|
|
||||||
|
import static org.telegram.messenger.support.widget.RecyclerView.NO_POSITION;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.graphics.PointF;
|
import android.graphics.PointF;
|
||||||
import android.os.Parcel;
|
import android.os.Parcel;
|
||||||
|
@ -23,20 +25,18 @@ import android.os.Parcelable;
|
||||||
import android.support.v4.view.ViewCompat;
|
import android.support.v4.view.ViewCompat;
|
||||||
import android.support.v4.view.accessibility.AccessibilityEventCompat;
|
import android.support.v4.view.accessibility.AccessibilityEventCompat;
|
||||||
import android.support.v4.view.accessibility.AccessibilityRecordCompat;
|
import android.support.v4.view.accessibility.AccessibilityRecordCompat;
|
||||||
|
import org.telegram.messenger.support.widget.RecyclerView.LayoutParams;
|
||||||
import org.telegram.messenger.support.widget.helper.ItemTouchHelper;
|
import org.telegram.messenger.support.widget.helper.ItemTouchHelper;
|
||||||
|
import android.util.AttributeSet;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.view.accessibility.AccessibilityEvent;
|
import android.view.accessibility.AccessibilityEvent;
|
||||||
import org.telegram.messenger.support.widget.RecyclerView.LayoutParams;
|
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import static org.telegram.messenger.support.widget.RecyclerView.NO_POSITION;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A {@link RecyclerView.LayoutManager} implementation which provides
|
* A {@link android.support.v7.widget.RecyclerView.LayoutManager} implementation which provides
|
||||||
* similar functionality to {@link android.widget.ListView}.
|
* similar functionality to {@link android.widget.ListView}.
|
||||||
*/
|
*/
|
||||||
public class LinearLayoutManager extends RecyclerView.LayoutManager implements
|
public class LinearLayoutManager extends RecyclerView.LayoutManager implements
|
||||||
|
@ -58,7 +58,7 @@ public class LinearLayoutManager extends RecyclerView.LayoutManager implements
|
||||||
* than this factor times the total space of the list. If layout is vertical, total space is the
|
* than this factor times the total space of the list. If layout is vertical, total space is the
|
||||||
* height minus padding, if layout is horizontal, total space is the width minus padding.
|
* height minus padding, if layout is horizontal, total space is the width minus padding.
|
||||||
*/
|
*/
|
||||||
private static final float MAX_SCROLL_FACTOR = 0.33f;
|
private static final float MAX_SCROLL_FACTOR = 1 / 3f;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -154,6 +154,24 @@ public class LinearLayoutManager extends RecyclerView.LayoutManager implements
|
||||||
public LinearLayoutManager(Context context, int orientation, boolean reverseLayout) {
|
public LinearLayoutManager(Context context, int orientation, boolean reverseLayout) {
|
||||||
setOrientation(orientation);
|
setOrientation(orientation);
|
||||||
setReverseLayout(reverseLayout);
|
setReverseLayout(reverseLayout);
|
||||||
|
setAutoMeasureEnabled(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor used when layout manager is set in XML by RecyclerView attribute
|
||||||
|
* "layoutManager". Defaults to vertical orientation.
|
||||||
|
*
|
||||||
|
* @attr ref android.support.v7.recyclerview.R.styleable#RecyclerView_android_orientation
|
||||||
|
* @attr ref android.support.v7.recyclerview.R.styleable#RecyclerView_reverseLayout
|
||||||
|
* @attr ref android.support.v7.recyclerview.R.styleable#RecyclerView_stackFromEnd
|
||||||
|
*/
|
||||||
|
public LinearLayoutManager(Context context, AttributeSet attrs, int defStyleAttr,
|
||||||
|
int defStyleRes) {
|
||||||
|
Properties properties = getProperties(context, attrs, defStyleAttr, defStyleRes);
|
||||||
|
setOrientation(properties.orientation);
|
||||||
|
setReverseLayout(properties.reverseLayout);
|
||||||
|
setStackFromEnd(properties.stackFromEnd);
|
||||||
|
setAutoMeasureEnabled(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -288,8 +306,7 @@ public class LinearLayoutManager extends RecyclerView.LayoutManager implements
|
||||||
/**
|
/**
|
||||||
* Returns the current orientaion of the layout.
|
* Returns the current orientaion of the layout.
|
||||||
*
|
*
|
||||||
* @return Current orientation.
|
* @return Current orientation, either {@link #HORIZONTAL} or {@link #VERTICAL}
|
||||||
* @see #mOrientation
|
|
||||||
* @see #setOrientation(int)
|
* @see #setOrientation(int)
|
||||||
*/
|
*/
|
||||||
public int getOrientation() {
|
public int getOrientation() {
|
||||||
|
@ -297,7 +314,7 @@ public class LinearLayoutManager extends RecyclerView.LayoutManager implements
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the orientation of the layout. {@link org.telegram.messenger.support.widget.LinearLayoutManager}
|
* Sets the orientation of the layout. {@link android.support.v7.widget.LinearLayoutManager}
|
||||||
* will do its best to keep scroll position.
|
* will do its best to keep scroll position.
|
||||||
*
|
*
|
||||||
* @param orientation {@link #HORIZONTAL} or {@link #VERTICAL}
|
* @param orientation {@link #HORIZONTAL} or {@link #VERTICAL}
|
||||||
|
@ -333,7 +350,7 @@ public class LinearLayoutManager extends RecyclerView.LayoutManager implements
|
||||||
* Returns if views are laid out from the opposite direction of the layout.
|
* Returns if views are laid out from the opposite direction of the layout.
|
||||||
*
|
*
|
||||||
* @return If layout is reversed or not.
|
* @return If layout is reversed or not.
|
||||||
* @see {@link #setReverseLayout(boolean)}
|
* @see #setReverseLayout(boolean)
|
||||||
*/
|
*/
|
||||||
public boolean getReverseLayout() {
|
public boolean getReverseLayout() {
|
||||||
return mReverseLayout;
|
return mReverseLayout;
|
||||||
|
@ -345,8 +362,8 @@ public class LinearLayoutManager extends RecyclerView.LayoutManager implements
|
||||||
* laid out at the end of the UI, second item is laid out before it etc.
|
* laid out at the end of the UI, second item is laid out before it etc.
|
||||||
*
|
*
|
||||||
* For horizontal layouts, it depends on the layout direction.
|
* For horizontal layouts, it depends on the layout direction.
|
||||||
* When set to true, If {@link RecyclerView} is LTR, than it will
|
* When set to true, If {@link android.support.v7.widget.RecyclerView} is LTR, than it will
|
||||||
* layout from RTL, if {@link RecyclerView}} is RTL, it will layout
|
* layout from RTL, if {@link android.support.v7.widget.RecyclerView}} is RTL, it will layout
|
||||||
* from LTR.
|
* from LTR.
|
||||||
*
|
*
|
||||||
* If you are looking for the exact same behavior of
|
* If you are looking for the exact same behavior of
|
||||||
|
@ -385,7 +402,7 @@ public class LinearLayoutManager extends RecyclerView.LayoutManager implements
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>Returns the amount of extra space that should be laid out by LayoutManager.
|
* <p>Returns the amount of extra space that should be laid out by LayoutManager.
|
||||||
* By default, {@link org.telegram.messenger.support.widget.LinearLayoutManager} lays out 1 extra page of
|
* By default, {@link android.support.v7.widget.LinearLayoutManager} lays out 1 extra page of
|
||||||
* items while smooth scrolling and 0 otherwise. You can override this method to implement your
|
* items while smooth scrolling and 0 otherwise. You can override this method to implement your
|
||||||
* custom layout pre-cache logic.</p>
|
* custom layout pre-cache logic.</p>
|
||||||
* <p>Laying out invisible elements will eventually come with performance cost. On the other
|
* <p>Laying out invisible elements will eventually come with performance cost. On the other
|
||||||
|
@ -512,8 +529,18 @@ public class LinearLayoutManager extends RecyclerView.LayoutManager implements
|
||||||
}
|
}
|
||||||
int startOffset;
|
int startOffset;
|
||||||
int endOffset;
|
int endOffset;
|
||||||
onAnchorReady(recycler, state, mAnchorInfo);
|
final int firstLayoutDirection;
|
||||||
|
if (mAnchorInfo.mLayoutFromEnd) {
|
||||||
|
firstLayoutDirection = mShouldReverseLayout ? LayoutState.ITEM_DIRECTION_TAIL :
|
||||||
|
LayoutState.ITEM_DIRECTION_HEAD;
|
||||||
|
} else {
|
||||||
|
firstLayoutDirection = mShouldReverseLayout ? LayoutState.ITEM_DIRECTION_HEAD :
|
||||||
|
LayoutState.ITEM_DIRECTION_TAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
onAnchorReady(recycler, state, mAnchorInfo, firstLayoutDirection);
|
||||||
detachAndScrapAttachedViews(recycler);
|
detachAndScrapAttachedViews(recycler);
|
||||||
|
mLayoutState.mInfinite = mOrientationHelper.getMode() == View.MeasureSpec.UNSPECIFIED;
|
||||||
mLayoutState.mIsPreLayout = state.isPreLayout();
|
mLayoutState.mIsPreLayout = state.isPreLayout();
|
||||||
if (mAnchorInfo.mLayoutFromEnd) {
|
if (mAnchorInfo.mLayoutFromEnd) {
|
||||||
// fill towards start
|
// fill towards start
|
||||||
|
@ -606,13 +633,14 @@ public class LinearLayoutManager extends RecyclerView.LayoutManager implements
|
||||||
/**
|
/**
|
||||||
* Method called when Anchor position is decided. Extending class can setup accordingly or
|
* Method called when Anchor position is decided. Extending class can setup accordingly or
|
||||||
* even update anchor info if necessary.
|
* even update anchor info if necessary.
|
||||||
*
|
* @param recycler The recycler for the layout
|
||||||
* @param recycler
|
* @param state The layout state
|
||||||
* @param state
|
* @param anchorInfo The mutable POJO that keeps the position and offset.
|
||||||
* @param anchorInfo Simple data structure to keep anchor point information for the next layout
|
* @param firstLayoutItemDirection The direction of the first layout filling in terms of adapter
|
||||||
|
* indices.
|
||||||
*/
|
*/
|
||||||
void onAnchorReady(RecyclerView.Recycler recycler, RecyclerView.State state,
|
void onAnchorReady(RecyclerView.Recycler recycler, RecyclerView.State state,
|
||||||
AnchorInfo anchorInfo) {
|
AnchorInfo anchorInfo, int firstLayoutItemDirection) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1100,9 +1128,10 @@ public class LinearLayoutManager extends RecyclerView.LayoutManager implements
|
||||||
|
|
||||||
private void updateLayoutState(int layoutDirection, int requiredSpace,
|
private void updateLayoutState(int layoutDirection, int requiredSpace,
|
||||||
boolean canUseExistingSpace, RecyclerView.State state) {
|
boolean canUseExistingSpace, RecyclerView.State state) {
|
||||||
|
mLayoutState.mInfinite = mOrientationHelper.getMode() == View.MeasureSpec.UNSPECIFIED;
|
||||||
mLayoutState.mExtra = getExtraLayoutSpace(state);
|
mLayoutState.mExtra = getExtraLayoutSpace(state);
|
||||||
mLayoutState.mLayoutDirection = layoutDirection;
|
mLayoutState.mLayoutDirection = layoutDirection;
|
||||||
int fastScrollSpace;
|
int scrollingOffset;
|
||||||
if (layoutDirection == LayoutState.LAYOUT_END) {
|
if (layoutDirection == LayoutState.LAYOUT_END) {
|
||||||
mLayoutState.mExtra += mOrientationHelper.getEndPadding();
|
mLayoutState.mExtra += mOrientationHelper.getEndPadding();
|
||||||
// get the first child in the direction we are going
|
// get the first child in the direction we are going
|
||||||
|
@ -1113,7 +1142,7 @@ public class LinearLayoutManager extends RecyclerView.LayoutManager implements
|
||||||
mLayoutState.mCurrentPosition = getPosition(child) + mLayoutState.mItemDirection;
|
mLayoutState.mCurrentPosition = getPosition(child) + mLayoutState.mItemDirection;
|
||||||
mLayoutState.mOffset = mOrientationHelper.getDecoratedEnd(child);
|
mLayoutState.mOffset = mOrientationHelper.getDecoratedEnd(child);
|
||||||
// calculate how much we can scroll without adding new children (independent of layout)
|
// calculate how much we can scroll without adding new children (independent of layout)
|
||||||
fastScrollSpace = mOrientationHelper.getDecoratedEnd(child)
|
scrollingOffset = mOrientationHelper.getDecoratedEnd(child)
|
||||||
- mOrientationHelper.getEndAfterPadding();
|
- mOrientationHelper.getEndAfterPadding();
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
@ -1123,14 +1152,14 @@ public class LinearLayoutManager extends RecyclerView.LayoutManager implements
|
||||||
: LayoutState.ITEM_DIRECTION_HEAD;
|
: LayoutState.ITEM_DIRECTION_HEAD;
|
||||||
mLayoutState.mCurrentPosition = getPosition(child) + mLayoutState.mItemDirection;
|
mLayoutState.mCurrentPosition = getPosition(child) + mLayoutState.mItemDirection;
|
||||||
mLayoutState.mOffset = mOrientationHelper.getDecoratedStart(child);
|
mLayoutState.mOffset = mOrientationHelper.getDecoratedStart(child);
|
||||||
fastScrollSpace = -mOrientationHelper.getDecoratedStart(child)
|
scrollingOffset = -mOrientationHelper.getDecoratedStart(child)
|
||||||
+ mOrientationHelper.getStartAfterPadding();
|
+ mOrientationHelper.getStartAfterPadding();
|
||||||
}
|
}
|
||||||
mLayoutState.mAvailable = requiredSpace;
|
mLayoutState.mAvailable = requiredSpace;
|
||||||
if (canUseExistingSpace) {
|
if (canUseExistingSpace) {
|
||||||
mLayoutState.mAvailable -= fastScrollSpace;
|
mLayoutState.mAvailable -= scrollingOffset;
|
||||||
}
|
}
|
||||||
mLayoutState.mScrollingOffset = fastScrollSpace;
|
mLayoutState.mScrollingOffset = scrollingOffset;
|
||||||
}
|
}
|
||||||
|
|
||||||
int scrollBy(int dy, RecyclerView.Recycler recycler, RecyclerView.State state) {
|
int scrollBy(int dy, RecyclerView.Recycler recycler, RecyclerView.State state) {
|
||||||
|
@ -1142,8 +1171,8 @@ public class LinearLayoutManager extends RecyclerView.LayoutManager implements
|
||||||
final int layoutDirection = dy > 0 ? LayoutState.LAYOUT_END : LayoutState.LAYOUT_START;
|
final int layoutDirection = dy > 0 ? LayoutState.LAYOUT_END : LayoutState.LAYOUT_START;
|
||||||
final int absDy = Math.abs(dy);
|
final int absDy = Math.abs(dy);
|
||||||
updateLayoutState(layoutDirection, absDy, true, state);
|
updateLayoutState(layoutDirection, absDy, true, state);
|
||||||
final int freeScroll = mLayoutState.mScrollingOffset;
|
final int consumed = mLayoutState.mScrollingOffset
|
||||||
final int consumed = freeScroll + fill(recycler, mLayoutState, state, false);
|
+ fill(recycler, mLayoutState, state, false);
|
||||||
if (consumed < 0) {
|
if (consumed < 0) {
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
Log.d(TAG, "Don't have any more elements to scroll");
|
Log.d(TAG, "Don't have any more elements to scroll");
|
||||||
|
@ -1193,7 +1222,7 @@ public class LinearLayoutManager extends RecyclerView.LayoutManager implements
|
||||||
/**
|
/**
|
||||||
* Recycles views that went out of bounds after scrolling towards the end of the layout.
|
* Recycles views that went out of bounds after scrolling towards the end of the layout.
|
||||||
*
|
*
|
||||||
* @param recycler Recycler instance of {@link RecyclerView}
|
* @param recycler Recycler instance of {@link android.support.v7.widget.RecyclerView}
|
||||||
* @param dt This can be used to add additional padding to the visible area. This is used
|
* @param dt This can be used to add additional padding to the visible area. This is used
|
||||||
* to detect children that will go out of bounds after scrolling, without
|
* to detect children that will go out of bounds after scrolling, without
|
||||||
* actually moving them.
|
* actually moving them.
|
||||||
|
@ -1232,7 +1261,7 @@ public class LinearLayoutManager extends RecyclerView.LayoutManager implements
|
||||||
/**
|
/**
|
||||||
* Recycles views that went out of bounds after scrolling towards the start of the layout.
|
* Recycles views that went out of bounds after scrolling towards the start of the layout.
|
||||||
*
|
*
|
||||||
* @param recycler Recycler instance of {@link RecyclerView}
|
* @param recycler Recycler instance of {@link android.support.v7.widget.RecyclerView}
|
||||||
* @param dt This can be used to add additional padding to the visible area. This is used
|
* @param dt This can be used to add additional padding to the visible area. This is used
|
||||||
* to detect children that will go out of bounds after scrolling, without
|
* to detect children that will go out of bounds after scrolling, without
|
||||||
* actually moving them.
|
* actually moving them.
|
||||||
|
@ -1274,12 +1303,12 @@ public class LinearLayoutManager extends RecyclerView.LayoutManager implements
|
||||||
* @param layoutState Current layout state. Right now, this object does not change but
|
* @param layoutState Current layout state. Right now, this object does not change but
|
||||||
* we may consider moving it out of this view so passing around as a
|
* we may consider moving it out of this view so passing around as a
|
||||||
* parameter for now, rather than accessing {@link #mLayoutState}
|
* parameter for now, rather than accessing {@link #mLayoutState}
|
||||||
* @see #recycleViewsFromStart(RecyclerView.Recycler, int)
|
* @see #recycleViewsFromStart(android.support.v7.widget.RecyclerView.Recycler, int)
|
||||||
* @see #recycleViewsFromEnd(RecyclerView.Recycler, int)
|
* @see #recycleViewsFromEnd(android.support.v7.widget.RecyclerView.Recycler, int)
|
||||||
* @see org.telegram.messenger.support.widget.LinearLayoutManager.LayoutState#mLayoutDirection
|
* @see android.support.v7.widget.LinearLayoutManager.LayoutState#mLayoutDirection
|
||||||
*/
|
*/
|
||||||
private void recycleByLayoutState(RecyclerView.Recycler recycler, LayoutState layoutState) {
|
private void recycleByLayoutState(RecyclerView.Recycler recycler, LayoutState layoutState) {
|
||||||
if (!layoutState.mRecycle) {
|
if (!layoutState.mRecycle || layoutState.mInfinite) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (layoutState.mLayoutDirection == LayoutState.LAYOUT_START) {
|
if (layoutState.mLayoutDirection == LayoutState.LAYOUT_START) {
|
||||||
|
@ -1291,7 +1320,7 @@ public class LinearLayoutManager extends RecyclerView.LayoutManager implements
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The magic functions :). Fills the given layout, defined by the layoutState. This is fairly
|
* The magic functions :). Fills the given layout, defined by the layoutState. This is fairly
|
||||||
* independent from the rest of the {@link org.telegram.messenger.support.widget.LinearLayoutManager}
|
* independent from the rest of the {@link android.support.v7.widget.LinearLayoutManager}
|
||||||
* and with little change, can be made publicly available as a helper class.
|
* and with little change, can be made publicly available as a helper class.
|
||||||
*
|
*
|
||||||
* @param recycler Current recycler that is attached to RecyclerView
|
* @param recycler Current recycler that is attached to RecyclerView
|
||||||
|
@ -1313,7 +1342,7 @@ public class LinearLayoutManager extends RecyclerView.LayoutManager implements
|
||||||
}
|
}
|
||||||
int remainingSpace = layoutState.mAvailable + layoutState.mExtra;
|
int remainingSpace = layoutState.mAvailable + layoutState.mExtra;
|
||||||
LayoutChunkResult layoutChunkResult = new LayoutChunkResult();
|
LayoutChunkResult layoutChunkResult = new LayoutChunkResult();
|
||||||
while (remainingSpace > 0 && layoutState.hasMore(state)) {
|
while ((layoutState.mInfinite || remainingSpace > 0) && layoutState.hasMore(state)) {
|
||||||
layoutChunkResult.resetInternal();
|
layoutChunkResult.resetInternal();
|
||||||
layoutChunk(recycler, state, layoutState, layoutChunkResult);
|
layoutChunk(recycler, state, layoutState, layoutChunkResult);
|
||||||
if (layoutChunkResult.mFinished) {
|
if (layoutChunkResult.mFinished) {
|
||||||
|
@ -1424,6 +1453,13 @@ public class LinearLayoutManager extends RecyclerView.LayoutManager implements
|
||||||
result.mFocusable = view.isFocusable();
|
result.mFocusable = view.isFocusable();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
boolean shouldMeasureTwice() {
|
||||||
|
return getHeightMode() != View.MeasureSpec.EXACTLY
|
||||||
|
&& getWidthMode() != View.MeasureSpec.EXACTLY
|
||||||
|
&& hasFlexibleChildInBothOrientations();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Converts a focusDirection to orientation.
|
* Converts a focusDirection to orientation.
|
||||||
*
|
*
|
||||||
|
@ -1434,7 +1470,7 @@ public class LinearLayoutManager extends RecyclerView.LayoutManager implements
|
||||||
* @return {@link LayoutState#LAYOUT_START} or {@link LayoutState#LAYOUT_END} if focus direction
|
* @return {@link LayoutState#LAYOUT_START} or {@link LayoutState#LAYOUT_END} if focus direction
|
||||||
* is applicable to current state, {@link LayoutState#INVALID_LAYOUT} otherwise.
|
* is applicable to current state, {@link LayoutState#INVALID_LAYOUT} otherwise.
|
||||||
*/
|
*/
|
||||||
private int convertFocusDirectionToLayoutDirection(int focusDirection) {
|
int convertFocusDirectionToLayoutDirection(int focusDirection) {
|
||||||
switch (focusDirection) {
|
switch (focusDirection) {
|
||||||
case View.FOCUS_BACKWARD:
|
case View.FOCUS_BACKWARD:
|
||||||
return LayoutState.LAYOUT_START;
|
return LayoutState.LAYOUT_START;
|
||||||
|
@ -1916,7 +1952,8 @@ public class LinearLayoutManager extends RecyclerView.LayoutManager implements
|
||||||
boolean mIsPreLayout = false;
|
boolean mIsPreLayout = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The most recent {@link #scrollBy(int, RecyclerView.Recycler, RecyclerView.State)} amount.
|
* The most recent {@link #scrollBy(int, RecyclerView.Recycler, RecyclerView.State)}
|
||||||
|
* amount.
|
||||||
*/
|
*/
|
||||||
int mLastScrollDelta;
|
int mLastScrollDelta;
|
||||||
|
|
||||||
|
@ -1926,6 +1963,11 @@ public class LinearLayoutManager extends RecyclerView.LayoutManager implements
|
||||||
*/
|
*/
|
||||||
List<RecyclerView.ViewHolder> mScrapList = null;
|
List<RecyclerView.ViewHolder> mScrapList = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used when there is no limit in how many views can be laid out.
|
||||||
|
*/
|
||||||
|
boolean mInfinite;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return true if there are more items in the data adapter
|
* @return true if there are more items in the data adapter
|
||||||
*/
|
*/
|
||||||
|
@ -2020,7 +2062,10 @@ public class LinearLayoutManager extends RecyclerView.LayoutManager implements
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static class SavedState implements Parcelable {
|
/**
|
||||||
|
* @hide
|
||||||
|
*/
|
||||||
|
public static class SavedState implements Parcelable {
|
||||||
|
|
||||||
int mAnchorPosition;
|
int mAnchorPosition;
|
||||||
|
|
||||||
|
|
|
@ -24,8 +24,6 @@ import android.view.View;
|
||||||
import android.view.animation.DecelerateInterpolator;
|
import android.view.animation.DecelerateInterpolator;
|
||||||
import android.view.animation.LinearInterpolator;
|
import android.view.animation.LinearInterpolator;
|
||||||
|
|
||||||
import org.telegram.messenger.support.widget.RecyclerView;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@link RecyclerView.SmoothScroller} implementation which uses
|
* {@link RecyclerView.SmoothScroller} implementation which uses
|
||||||
* {@link android.view.animation.LinearInterpolator} until the target position becames a child of
|
* {@link android.view.animation.LinearInterpolator} until the target position becames a child of
|
||||||
|
@ -124,6 +122,7 @@ abstract public class LinearSmoothScroller extends RecyclerView.SmoothScroller {
|
||||||
stop();
|
stop();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
//noinspection PointlessBooleanExpression
|
||||||
if (DEBUG && mTargetVector != null
|
if (DEBUG && mTargetVector != null
|
||||||
&& ((mTargetVector.x * dx < 0 || mTargetVector.y * dy < 0))) {
|
&& ((mTargetVector.x * dx < 0 || mTargetVector.y * dy < 0))) {
|
||||||
throw new IllegalStateException("Scroll happened in the opposite direction"
|
throw new IllegalStateException("Scroll happened in the opposite direction"
|
||||||
|
@ -293,13 +292,13 @@ abstract public class LinearSmoothScroller extends RecyclerView.SmoothScroller {
|
||||||
* @param view The view which we want to make fully visible
|
* @param view The view which we want to make fully visible
|
||||||
* @param snapPreference The edge which the view should snap to when entering the visible
|
* @param snapPreference The edge which the view should snap to when entering the visible
|
||||||
* area. One of {@link #SNAP_TO_START}, {@link #SNAP_TO_END} or
|
* area. One of {@link #SNAP_TO_START}, {@link #SNAP_TO_END} or
|
||||||
* {@link #SNAP_TO_END}.
|
* {@link #SNAP_TO_ANY}.
|
||||||
* @return The vertical scroll amount necessary to make the view visible with the given
|
* @return The vertical scroll amount necessary to make the view visible with the given
|
||||||
* snap preference.
|
* snap preference.
|
||||||
*/
|
*/
|
||||||
public int calculateDyToMakeVisible(View view, int snapPreference) {
|
public int calculateDyToMakeVisible(View view, int snapPreference) {
|
||||||
final RecyclerView.LayoutManager layoutManager = getLayoutManager();
|
final RecyclerView.LayoutManager layoutManager = getLayoutManager();
|
||||||
if (!layoutManager.canScrollVertically()) {
|
if (layoutManager == null || !layoutManager.canScrollVertically()) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams)
|
final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams)
|
||||||
|
@ -324,7 +323,7 @@ abstract public class LinearSmoothScroller extends RecyclerView.SmoothScroller {
|
||||||
*/
|
*/
|
||||||
public int calculateDxToMakeVisible(View view, int snapPreference) {
|
public int calculateDxToMakeVisible(View view, int snapPreference) {
|
||||||
final RecyclerView.LayoutManager layoutManager = getLayoutManager();
|
final RecyclerView.LayoutManager layoutManager = getLayoutManager();
|
||||||
if (!layoutManager.canScrollHorizontally()) {
|
if (layoutManager == null || !layoutManager.canScrollHorizontally()) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams)
|
final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams)
|
||||||
|
|
|
@ -19,8 +19,6 @@ package org.telegram.messenger.support.widget;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.widget.LinearLayout;
|
import android.widget.LinearLayout;
|
||||||
|
|
||||||
import org.telegram.messenger.support.widget.RecyclerView;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper class for LayoutManagers to abstract measurements depending on the View's orientation.
|
* Helper class for LayoutManagers to abstract measurements depending on the View's orientation.
|
||||||
* <p>
|
* <p>
|
||||||
|
@ -167,6 +165,28 @@ public abstract class OrientationHelper {
|
||||||
*/
|
*/
|
||||||
public abstract int getEndPadding();
|
public abstract int getEndPadding();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the MeasureSpec mode for the current orientation from the LayoutManager.
|
||||||
|
*
|
||||||
|
* @return The current measure spec mode.
|
||||||
|
*
|
||||||
|
* @see View.MeasureSpec
|
||||||
|
* @see RecyclerView.LayoutManager#getWidthMode()
|
||||||
|
* @see RecyclerView.LayoutManager#getHeightMode()
|
||||||
|
*/
|
||||||
|
public abstract int getMode();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the MeasureSpec mode for the perpendicular orientation from the LayoutManager.
|
||||||
|
*
|
||||||
|
* @return The current measure spec mode.
|
||||||
|
*
|
||||||
|
* @see View.MeasureSpec
|
||||||
|
* @see RecyclerView.LayoutManager#getWidthMode()
|
||||||
|
* @see RecyclerView.LayoutManager#getHeightMode()
|
||||||
|
*/
|
||||||
|
public abstract int getModeInOther();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates an OrientationHelper for the given LayoutManager and orientation.
|
* Creates an OrientationHelper for the given LayoutManager and orientation.
|
||||||
*
|
*
|
||||||
|
@ -259,6 +279,16 @@ public abstract class OrientationHelper {
|
||||||
public int getEndPadding() {
|
public int getEndPadding() {
|
||||||
return mLayoutManager.getPaddingRight();
|
return mLayoutManager.getPaddingRight();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getMode() {
|
||||||
|
return mLayoutManager.getWidthMode();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getModeInOther() {
|
||||||
|
return mLayoutManager.getHeightMode();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -335,6 +365,16 @@ public abstract class OrientationHelper {
|
||||||
public int getEndPadding() {
|
public int getEndPadding() {
|
||||||
return mLayoutManager.getPaddingBottom();
|
return mLayoutManager.getPaddingBottom();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getMode() {
|
||||||
|
return mLayoutManager.getHeightMode();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getModeInOther() {
|
||||||
|
return mLayoutManager.getWidthMode();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
File diff suppressed because it is too large
Load Diff
|
@ -22,8 +22,6 @@ import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.accessibility.AccessibilityEvent;
|
import android.view.accessibility.AccessibilityEvent;
|
||||||
|
|
||||||
import org.telegram.messenger.support.widget.RecyclerView;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The AccessibilityDelegate used by RecyclerView.
|
* The AccessibilityDelegate used by RecyclerView.
|
||||||
* <p>
|
* <p>
|
||||||
|
|
|
@ -17,8 +17,6 @@ package org.telegram.messenger.support.widget;
|
||||||
|
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
|
|
||||||
import org.telegram.messenger.support.widget.RecyclerView;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A helper class to do scroll offset calculations.
|
* A helper class to do scroll offset calculations.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -0,0 +1,442 @@
|
||||||
|
package org.telegram.messenger.support.widget;
|
||||||
|
|
||||||
|
import android.support.annotation.NonNull;
|
||||||
|
import android.support.annotation.Nullable;
|
||||||
|
import org.telegram.messenger.support.widget.RecyclerView.Adapter;
|
||||||
|
import org.telegram.messenger.support.widget.RecyclerView.ViewHolder;
|
||||||
|
import org.telegram.messenger.support.widget.RecyclerView.ItemAnimator.ItemHolderInfo;
|
||||||
|
import android.util.Log;
|
||||||
|
import android.view.View;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A wrapper class for ItemAnimator that records View bounds and decides whether it should run
|
||||||
|
* move, change, add or remove animations. This class also replicates the original ItemAnimator
|
||||||
|
* API.
|
||||||
|
* <p>
|
||||||
|
* It uses {@link ItemHolderInfo} to track the bounds information of the Views. If you would like
|
||||||
|
* to
|
||||||
|
* extend this class, you can override {@link #obtainHolderInfo()} method to provide your own info
|
||||||
|
* class that extends {@link ItemHolderInfo}.
|
||||||
|
*/
|
||||||
|
abstract public class SimpleItemAnimator extends RecyclerView.ItemAnimator {
|
||||||
|
|
||||||
|
private static final boolean DEBUG = false;
|
||||||
|
|
||||||
|
private static final String TAG = "SimpleItemAnimator";
|
||||||
|
|
||||||
|
boolean mSupportsChangeAnimations = true;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether this ItemAnimator supports animations of change events.
|
||||||
|
*
|
||||||
|
* @return true if change animations are supported, false otherwise
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
public boolean getSupportsChangeAnimations() {
|
||||||
|
return mSupportsChangeAnimations;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets whether this ItemAnimator supports animations of item change events.
|
||||||
|
* If you set this property to false, actions on the data set which change the
|
||||||
|
* contents of items will not be animated. What those animations do is left
|
||||||
|
* up to the discretion of the ItemAnimator subclass, in its
|
||||||
|
* {@link #animateChange(ViewHolder, ViewHolder, int, int, int, int)} implementation.
|
||||||
|
* The value of this property is true by default.
|
||||||
|
*
|
||||||
|
* @param supportsChangeAnimations true if change animations are supported by
|
||||||
|
* this ItemAnimator, false otherwise. If the property is false,
|
||||||
|
* the ItemAnimator
|
||||||
|
* will not receive a call to
|
||||||
|
* {@link #animateChange(ViewHolder, ViewHolder, int, int, int,
|
||||||
|
* int)} when changes occur.
|
||||||
|
* @see Adapter#notifyItemChanged(int)
|
||||||
|
* @see Adapter#notifyItemRangeChanged(int, int)
|
||||||
|
*/
|
||||||
|
public void setSupportsChangeAnimations(boolean supportsChangeAnimations) {
|
||||||
|
mSupportsChangeAnimations = supportsChangeAnimations;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*
|
||||||
|
* @return True if change animations are not supported or the ViewHolder is invalid,
|
||||||
|
* false otherwise.
|
||||||
|
*
|
||||||
|
* @see #setSupportsChangeAnimations(boolean)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean canReuseUpdatedViewHolder(@NonNull RecyclerView.ViewHolder viewHolder) {
|
||||||
|
return !mSupportsChangeAnimations || viewHolder.isInvalid();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean animateDisappearance(@NonNull ViewHolder viewHolder,
|
||||||
|
@NonNull ItemHolderInfo preLayoutInfo, @Nullable ItemHolderInfo postLayoutInfo) {
|
||||||
|
int oldLeft = preLayoutInfo.left;
|
||||||
|
int oldTop = preLayoutInfo.top;
|
||||||
|
View disappearingItemView = viewHolder.itemView;
|
||||||
|
int newLeft = postLayoutInfo == null ? disappearingItemView.getLeft() : postLayoutInfo.left;
|
||||||
|
int newTop = postLayoutInfo == null ? disappearingItemView.getTop() : postLayoutInfo.top;
|
||||||
|
if (!viewHolder.isRemoved() && (oldLeft != newLeft || oldTop != newTop)) {
|
||||||
|
disappearingItemView.layout(newLeft, newTop,
|
||||||
|
newLeft + disappearingItemView.getWidth(),
|
||||||
|
newTop + disappearingItemView.getHeight());
|
||||||
|
if (DEBUG) {
|
||||||
|
Log.d(TAG, "DISAPPEARING: " + viewHolder + " with view " + disappearingItemView);
|
||||||
|
}
|
||||||
|
return animateMove(viewHolder, oldLeft, oldTop, newLeft, newTop);
|
||||||
|
} else {
|
||||||
|
if (DEBUG) {
|
||||||
|
Log.d(TAG, "REMOVED: " + viewHolder + " with view " + disappearingItemView);
|
||||||
|
}
|
||||||
|
return animateRemove(viewHolder);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean animateAppearance(@NonNull ViewHolder viewHolder,
|
||||||
|
@Nullable ItemHolderInfo preLayoutInfo, @NonNull ItemHolderInfo postLayoutInfo) {
|
||||||
|
if (preLayoutInfo != null && (preLayoutInfo.left != postLayoutInfo.left
|
||||||
|
|| preLayoutInfo.top != postLayoutInfo.top)) {
|
||||||
|
// slide items in if before/after locations differ
|
||||||
|
if (DEBUG) {
|
||||||
|
Log.d(TAG, "APPEARING: " + viewHolder + " with view " + viewHolder);
|
||||||
|
}
|
||||||
|
return animateMove(viewHolder, preLayoutInfo.left, preLayoutInfo.top,
|
||||||
|
postLayoutInfo.left, postLayoutInfo.top);
|
||||||
|
} else {
|
||||||
|
if (DEBUG) {
|
||||||
|
Log.d(TAG, "ADDED: " + viewHolder + " with view " + viewHolder);
|
||||||
|
}
|
||||||
|
return animateAdd(viewHolder);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean animatePersistence(@NonNull ViewHolder viewHolder,
|
||||||
|
@NonNull ItemHolderInfo preInfo, @NonNull ItemHolderInfo postInfo) {
|
||||||
|
if (preInfo.left != postInfo.left || preInfo.top != postInfo.top) {
|
||||||
|
if (DEBUG) {
|
||||||
|
Log.d(TAG, "PERSISTENT: " + viewHolder +
|
||||||
|
" with view " + viewHolder.itemView);
|
||||||
|
}
|
||||||
|
return animateMove(viewHolder,
|
||||||
|
preInfo.left, preInfo.top, postInfo.left, postInfo.top);
|
||||||
|
}
|
||||||
|
dispatchMoveFinished(viewHolder);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean animateChange(@NonNull ViewHolder oldHolder, @NonNull ViewHolder newHolder,
|
||||||
|
@NonNull ItemHolderInfo preInfo, @NonNull ItemHolderInfo postInfo) {
|
||||||
|
if (DEBUG) {
|
||||||
|
Log.d(TAG, "CHANGED: " + oldHolder + " with view " + oldHolder.itemView);
|
||||||
|
}
|
||||||
|
final int fromLeft = preInfo.left;
|
||||||
|
final int fromTop = preInfo.top;
|
||||||
|
final int toLeft, toTop;
|
||||||
|
if (newHolder.shouldIgnore()) {
|
||||||
|
toLeft = preInfo.left;
|
||||||
|
toTop = preInfo.top;
|
||||||
|
} else {
|
||||||
|
toLeft = postInfo.left;
|
||||||
|
toTop = postInfo.top;
|
||||||
|
}
|
||||||
|
return animateChange(oldHolder, newHolder, fromLeft, fromTop, toLeft, toTop);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when an item is removed from the RecyclerView. Implementors can choose
|
||||||
|
* whether and how to animate that change, but must always call
|
||||||
|
* {@link #dispatchRemoveFinished(ViewHolder)} when done, either
|
||||||
|
* immediately (if no animation will occur) or after the animation actually finishes.
|
||||||
|
* The return value indicates whether an animation has been set up and whether the
|
||||||
|
* ItemAnimator's {@link #runPendingAnimations()} method should be called at the
|
||||||
|
* next opportunity. This mechanism allows ItemAnimator to set up individual animations
|
||||||
|
* as separate calls to {@link #animateAdd(ViewHolder) animateAdd()},
|
||||||
|
* {@link #animateMove(ViewHolder, int, int, int, int) animateMove()},
|
||||||
|
* {@link #animateRemove(ViewHolder) animateRemove()}, and
|
||||||
|
* {@link #animateChange(ViewHolder, ViewHolder, int, int, int, int)} come in one by one,
|
||||||
|
* then start the animations together in the later call to {@link #runPendingAnimations()}.
|
||||||
|
*
|
||||||
|
* <p>This method may also be called for disappearing items which continue to exist in the
|
||||||
|
* RecyclerView, but for which the system does not have enough information to animate
|
||||||
|
* them out of view. In that case, the default animation for removing items is run
|
||||||
|
* on those items as well.</p>
|
||||||
|
*
|
||||||
|
* @param holder The item that is being removed.
|
||||||
|
* @return true if a later call to {@link #runPendingAnimations()} is requested,
|
||||||
|
* false otherwise.
|
||||||
|
*/
|
||||||
|
abstract public boolean animateRemove(ViewHolder holder);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when an item is added to the RecyclerView. Implementors can choose
|
||||||
|
* whether and how to animate that change, but must always call
|
||||||
|
* {@link #dispatchAddFinished(ViewHolder)} when done, either
|
||||||
|
* immediately (if no animation will occur) or after the animation actually finishes.
|
||||||
|
* The return value indicates whether an animation has been set up and whether the
|
||||||
|
* ItemAnimator's {@link #runPendingAnimations()} method should be called at the
|
||||||
|
* next opportunity. This mechanism allows ItemAnimator to set up individual animations
|
||||||
|
* as separate calls to {@link #animateAdd(ViewHolder) animateAdd()},
|
||||||
|
* {@link #animateMove(ViewHolder, int, int, int, int) animateMove()},
|
||||||
|
* {@link #animateRemove(ViewHolder) animateRemove()}, and
|
||||||
|
* {@link #animateChange(ViewHolder, ViewHolder, int, int, int, int)} come in one by one,
|
||||||
|
* then start the animations together in the later call to {@link #runPendingAnimations()}.
|
||||||
|
*
|
||||||
|
* <p>This method may also be called for appearing items which were already in the
|
||||||
|
* RecyclerView, but for which the system does not have enough information to animate
|
||||||
|
* them into view. In that case, the default animation for adding items is run
|
||||||
|
* on those items as well.</p>
|
||||||
|
*
|
||||||
|
* @param holder The item that is being added.
|
||||||
|
* @return true if a later call to {@link #runPendingAnimations()} is requested,
|
||||||
|
* false otherwise.
|
||||||
|
*/
|
||||||
|
abstract public boolean animateAdd(ViewHolder holder);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when an item is moved in the RecyclerView. Implementors can choose
|
||||||
|
* whether and how to animate that change, but must always call
|
||||||
|
* {@link #dispatchMoveFinished(ViewHolder)} when done, either
|
||||||
|
* immediately (if no animation will occur) or after the animation actually finishes.
|
||||||
|
* The return value indicates whether an animation has been set up and whether the
|
||||||
|
* ItemAnimator's {@link #runPendingAnimations()} method should be called at the
|
||||||
|
* next opportunity. This mechanism allows ItemAnimator to set up individual animations
|
||||||
|
* as separate calls to {@link #animateAdd(ViewHolder) animateAdd()},
|
||||||
|
* {@link #animateMove(ViewHolder, int, int, int, int) animateMove()},
|
||||||
|
* {@link #animateRemove(ViewHolder) animateRemove()}, and
|
||||||
|
* {@link #animateChange(ViewHolder, ViewHolder, int, int, int, int)} come in one by one,
|
||||||
|
* then start the animations together in the later call to {@link #runPendingAnimations()}.
|
||||||
|
*
|
||||||
|
* @param holder The item that is being moved.
|
||||||
|
* @return true if a later call to {@link #runPendingAnimations()} is requested,
|
||||||
|
* false otherwise.
|
||||||
|
*/
|
||||||
|
abstract public boolean animateMove(ViewHolder holder, int fromX, int fromY,
|
||||||
|
int toX, int toY);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when an item is changed in the RecyclerView, as indicated by a call to
|
||||||
|
* {@link Adapter#notifyItemChanged(int)} or
|
||||||
|
* {@link Adapter#notifyItemRangeChanged(int, int)}.
|
||||||
|
* <p>
|
||||||
|
* Implementers can choose whether and how to animate changes, but must always call
|
||||||
|
* {@link #dispatchChangeFinished(ViewHolder, boolean)} for each non-null distinct ViewHolder,
|
||||||
|
* either immediately (if no animation will occur) or after the animation actually finishes.
|
||||||
|
* If the {@code oldHolder} is the same ViewHolder as the {@code newHolder}, you must call
|
||||||
|
* {@link #dispatchChangeFinished(ViewHolder, boolean)} once and only once. In that case, the
|
||||||
|
* second parameter of {@code dispatchChangeFinished} is ignored.
|
||||||
|
* <p>
|
||||||
|
* The return value indicates whether an animation has been set up and whether the
|
||||||
|
* ItemAnimator's {@link #runPendingAnimations()} method should be called at the
|
||||||
|
* next opportunity. This mechanism allows ItemAnimator to set up individual animations
|
||||||
|
* as separate calls to {@link #animateAdd(ViewHolder) animateAdd()},
|
||||||
|
* {@link #animateMove(ViewHolder, int, int, int, int) animateMove()},
|
||||||
|
* {@link #animateRemove(ViewHolder) animateRemove()}, and
|
||||||
|
* {@link #animateChange(ViewHolder, ViewHolder, int, int, int, int)} come in one by one,
|
||||||
|
* then start the animations together in the later call to {@link #runPendingAnimations()}.
|
||||||
|
*
|
||||||
|
* @param oldHolder The original item that changed.
|
||||||
|
* @param newHolder The new item that was created with the changed content. Might be null
|
||||||
|
* @param fromLeft Left of the old view holder
|
||||||
|
* @param fromTop Top of the old view holder
|
||||||
|
* @param toLeft Left of the new view holder
|
||||||
|
* @param toTop Top of the new view holder
|
||||||
|
* @return true if a later call to {@link #runPendingAnimations()} is requested,
|
||||||
|
* false otherwise.
|
||||||
|
*/
|
||||||
|
abstract public boolean animateChange(ViewHolder oldHolder,
|
||||||
|
ViewHolder newHolder, int fromLeft, int fromTop, int toLeft, int toTop);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method to be called by subclasses when a remove animation is done.
|
||||||
|
*
|
||||||
|
* @param item The item which has been removed
|
||||||
|
* @see RecyclerView.ItemAnimator#animateDisappearance(ViewHolder, ItemHolderInfo,
|
||||||
|
* ItemHolderInfo)
|
||||||
|
*/
|
||||||
|
public final void dispatchRemoveFinished(ViewHolder item) {
|
||||||
|
onRemoveFinished(item);
|
||||||
|
dispatchAnimationFinished(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method to be called by subclasses when a move animation is done.
|
||||||
|
*
|
||||||
|
* @param item The item which has been moved
|
||||||
|
* @see RecyclerView.ItemAnimator#animateDisappearance(ViewHolder, ItemHolderInfo,
|
||||||
|
* ItemHolderInfo)
|
||||||
|
* @see RecyclerView.ItemAnimator#animatePersistence(ViewHolder, ItemHolderInfo, ItemHolderInfo)
|
||||||
|
* @see RecyclerView.ItemAnimator#animateAppearance(ViewHolder, ItemHolderInfo, ItemHolderInfo)
|
||||||
|
*/
|
||||||
|
public final void dispatchMoveFinished(ViewHolder item) {
|
||||||
|
onMoveFinished(item);
|
||||||
|
dispatchAnimationFinished(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method to be called by subclasses when an add animation is done.
|
||||||
|
*
|
||||||
|
* @param item The item which has been added
|
||||||
|
*/
|
||||||
|
public final void dispatchAddFinished(ViewHolder item) {
|
||||||
|
onAddFinished(item);
|
||||||
|
dispatchAnimationFinished(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method to be called by subclasses when a change animation is done.
|
||||||
|
*
|
||||||
|
* @param item The item which has been changed (this method must be called for
|
||||||
|
* each non-null ViewHolder passed into
|
||||||
|
* {@link #animateChange(ViewHolder, ViewHolder, int, int, int, int)}).
|
||||||
|
* @param oldItem true if this is the old item that was changed, false if
|
||||||
|
* it is the new item that replaced the old item.
|
||||||
|
* @see #animateChange(ViewHolder, ViewHolder, int, int, int, int)
|
||||||
|
*/
|
||||||
|
public final void dispatchChangeFinished(ViewHolder item, boolean oldItem) {
|
||||||
|
onChangeFinished(item, oldItem);
|
||||||
|
dispatchAnimationFinished(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method to be called by subclasses when a remove animation is being started.
|
||||||
|
*
|
||||||
|
* @param item The item being removed
|
||||||
|
*/
|
||||||
|
public final void dispatchRemoveStarting(ViewHolder item) {
|
||||||
|
onRemoveStarting(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method to be called by subclasses when a move animation is being started.
|
||||||
|
*
|
||||||
|
* @param item The item being moved
|
||||||
|
*/
|
||||||
|
public final void dispatchMoveStarting(ViewHolder item) {
|
||||||
|
onMoveStarting(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method to be called by subclasses when an add animation is being started.
|
||||||
|
*
|
||||||
|
* @param item The item being added
|
||||||
|
*/
|
||||||
|
public final void dispatchAddStarting(ViewHolder item) {
|
||||||
|
onAddStarting(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method to be called by subclasses when a change animation is being started.
|
||||||
|
*
|
||||||
|
* @param item The item which has been changed (this method must be called for
|
||||||
|
* each non-null ViewHolder passed into
|
||||||
|
* {@link #animateChange(ViewHolder, ViewHolder, int, int, int, int)}).
|
||||||
|
* @param oldItem true if this is the old item that was changed, false if
|
||||||
|
* it is the new item that replaced the old item.
|
||||||
|
*/
|
||||||
|
public final void dispatchChangeStarting(ViewHolder item, boolean oldItem) {
|
||||||
|
onChangeStarting(item, oldItem);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when a remove animation is being started on the given ViewHolder.
|
||||||
|
* The default implementation does nothing. Subclasses may wish to override
|
||||||
|
* this method to handle any ViewHolder-specific operations linked to animation
|
||||||
|
* lifecycles.
|
||||||
|
*
|
||||||
|
* @param item The ViewHolder being animated.
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("UnusedParameters")
|
||||||
|
public void onRemoveStarting(ViewHolder item) {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when a remove animation has ended on the given ViewHolder.
|
||||||
|
* The default implementation does nothing. Subclasses may wish to override
|
||||||
|
* this method to handle any ViewHolder-specific operations linked to animation
|
||||||
|
* lifecycles.
|
||||||
|
*
|
||||||
|
* @param item The ViewHolder being animated.
|
||||||
|
*/
|
||||||
|
public void onRemoveFinished(ViewHolder item) {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when an add animation is being started on the given ViewHolder.
|
||||||
|
* The default implementation does nothing. Subclasses may wish to override
|
||||||
|
* this method to handle any ViewHolder-specific operations linked to animation
|
||||||
|
* lifecycles.
|
||||||
|
*
|
||||||
|
* @param item The ViewHolder being animated.
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("UnusedParameters")
|
||||||
|
public void onAddStarting(ViewHolder item) {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when an add animation has ended on the given ViewHolder.
|
||||||
|
* The default implementation does nothing. Subclasses may wish to override
|
||||||
|
* this method to handle any ViewHolder-specific operations linked to animation
|
||||||
|
* lifecycles.
|
||||||
|
*
|
||||||
|
* @param item The ViewHolder being animated.
|
||||||
|
*/
|
||||||
|
public void onAddFinished(ViewHolder item) {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when a move animation is being started on the given ViewHolder.
|
||||||
|
* The default implementation does nothing. Subclasses may wish to override
|
||||||
|
* this method to handle any ViewHolder-specific operations linked to animation
|
||||||
|
* lifecycles.
|
||||||
|
*
|
||||||
|
* @param item The ViewHolder being animated.
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("UnusedParameters")
|
||||||
|
public void onMoveStarting(ViewHolder item) {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when a move animation has ended on the given ViewHolder.
|
||||||
|
* The default implementation does nothing. Subclasses may wish to override
|
||||||
|
* this method to handle any ViewHolder-specific operations linked to animation
|
||||||
|
* lifecycles.
|
||||||
|
*
|
||||||
|
* @param item The ViewHolder being animated.
|
||||||
|
*/
|
||||||
|
public void onMoveFinished(ViewHolder item) {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when a change animation is being started on the given ViewHolder.
|
||||||
|
* The default implementation does nothing. Subclasses may wish to override
|
||||||
|
* this method to handle any ViewHolder-specific operations linked to animation
|
||||||
|
* lifecycles.
|
||||||
|
*
|
||||||
|
* @param item The ViewHolder being animated.
|
||||||
|
* @param oldItem true if this is the old item that was changed, false if
|
||||||
|
* it is the new item that replaced the old item.
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("UnusedParameters")
|
||||||
|
public void onChangeStarting(ViewHolder item, boolean oldItem) {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when a change animation has ended on the given ViewHolder.
|
||||||
|
* The default implementation does nothing. Subclasses may wish to override
|
||||||
|
* this method to handle any ViewHolder-specific operations linked to animation
|
||||||
|
* lifecycles.
|
||||||
|
*
|
||||||
|
* @param item The ViewHolder being animated.
|
||||||
|
* @param oldItem true if this is the old item that was changed, false if
|
||||||
|
* it is the new item that replaced the old item.
|
||||||
|
*/
|
||||||
|
public void onChangeFinished(ViewHolder item, boolean oldItem) {
|
||||||
|
}
|
||||||
|
}
|
|
@ -16,11 +16,18 @@
|
||||||
|
|
||||||
package org.telegram.messenger.support.widget;
|
package org.telegram.messenger.support.widget;
|
||||||
|
|
||||||
|
import static org.telegram.messenger.support.widget.LayoutState.ITEM_DIRECTION_HEAD;
|
||||||
|
import static org.telegram.messenger.support.widget.LayoutState.ITEM_DIRECTION_TAIL;
|
||||||
|
import static org.telegram.messenger.support.widget.LayoutState.LAYOUT_END;
|
||||||
|
import static org.telegram.messenger.support.widget.LayoutState.LAYOUT_START;
|
||||||
|
import static org.telegram.messenger.support.widget.RecyclerView.NO_POSITION;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.graphics.PointF;
|
import android.graphics.PointF;
|
||||||
import android.graphics.Rect;
|
import android.graphics.Rect;
|
||||||
import android.os.Parcel;
|
import android.os.Parcel;
|
||||||
import android.os.Parcelable;
|
import android.os.Parcelable;
|
||||||
|
import android.support.annotation.Nullable;
|
||||||
import android.support.v4.view.ViewCompat;
|
import android.support.v4.view.ViewCompat;
|
||||||
import android.support.v4.view.accessibility.AccessibilityEventCompat;
|
import android.support.v4.view.accessibility.AccessibilityEventCompat;
|
||||||
import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat;
|
import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat;
|
||||||
|
@ -31,24 +38,11 @@ import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.view.accessibility.AccessibilityEvent;
|
import android.view.accessibility.AccessibilityEvent;
|
||||||
|
|
||||||
import org.telegram.messenger.support.widget.AdapterHelper;
|
|
||||||
import org.telegram.messenger.support.widget.LayoutState;
|
|
||||||
import org.telegram.messenger.support.widget.LinearSmoothScroller;
|
|
||||||
import org.telegram.messenger.support.widget.OrientationHelper;
|
|
||||||
import org.telegram.messenger.support.widget.RecyclerView;
|
|
||||||
import org.telegram.messenger.support.widget.ScrollbarHelper;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.BitSet;
|
import java.util.BitSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import static org.telegram.messenger.support.widget.LayoutState.LAYOUT_START;
|
|
||||||
import static org.telegram.messenger.support.widget.LayoutState.LAYOUT_END;
|
|
||||||
import static org.telegram.messenger.support.widget.LayoutState.ITEM_DIRECTION_HEAD;
|
|
||||||
import static org.telegram.messenger.support.widget.LayoutState.ITEM_DIRECTION_TAIL;
|
|
||||||
import static org.telegram.messenger.support.widget.RecyclerView.NO_POSITION;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A LayoutManager that lays out children in a staggered grid formation.
|
* A LayoutManager that lays out children in a staggered grid formation.
|
||||||
* It supports horizontal & vertical layout as well as an ability to layout children in reverse.
|
* It supports horizontal & vertical layout as well as an ability to layout children in reverse.
|
||||||
|
@ -72,6 +66,7 @@ public class StaggeredGridLayoutManager extends RecyclerView.LayoutManager {
|
||||||
*/
|
*/
|
||||||
public static final int GAP_HANDLING_NONE = 0;
|
public static final int GAP_HANDLING_NONE = 0;
|
||||||
|
|
||||||
|
@SuppressWarnings("unused")
|
||||||
@Deprecated
|
@Deprecated
|
||||||
public static final int GAP_HANDLING_LAZY = 1;
|
public static final int GAP_HANDLING_LAZY = 1;
|
||||||
|
|
||||||
|
@ -97,6 +92,12 @@ public class StaggeredGridLayoutManager extends RecyclerView.LayoutManager {
|
||||||
public static final int GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS = 2;
|
public static final int GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS = 2;
|
||||||
|
|
||||||
private static final int INVALID_OFFSET = Integer.MIN_VALUE;
|
private static final int INVALID_OFFSET = Integer.MIN_VALUE;
|
||||||
|
/**
|
||||||
|
* While trying to find next view to focus, LayoutManager will not try to scroll more
|
||||||
|
* than this factor times the total space of the list. If layout is vertical, total space is the
|
||||||
|
* height minus padding, if layout is horizontal, total space is the width minus padding.
|
||||||
|
*/
|
||||||
|
private static final float MAX_SCROLL_FACTOR = 1 / 3f;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Number of spans
|
* Number of spans
|
||||||
|
@ -175,7 +176,7 @@ public class StaggeredGridLayoutManager extends RecyclerView.LayoutManager {
|
||||||
/**
|
/**
|
||||||
* Re-used measurement specs. updated by onLayout.
|
* Re-used measurement specs. updated by onLayout.
|
||||||
*/
|
*/
|
||||||
private int mFullSizeSpec, mWidthSpec, mHeightSpec;
|
private int mFullSizeSpec;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Re-used rectangle to get child decor offsets.
|
* Re-used rectangle to get child decor offsets.
|
||||||
|
@ -208,6 +209,20 @@ public class StaggeredGridLayoutManager extends RecyclerView.LayoutManager {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor used when layout manager is set in XML by RecyclerView attribute
|
||||||
|
* "layoutManager". Defaults to single column and vertical.
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
public StaggeredGridLayoutManager(Context context, AttributeSet attrs, int defStyleAttr,
|
||||||
|
int defStyleRes) {
|
||||||
|
Properties properties = getProperties(context, attrs, defStyleAttr, defStyleRes);
|
||||||
|
setOrientation(properties.orientation);
|
||||||
|
setSpanCount(properties.spanCount);
|
||||||
|
setReverseLayout(properties.reverseLayout);
|
||||||
|
setAutoMeasureEnabled(mGapStrategy != GAP_HANDLING_NONE);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a StaggeredGridLayoutManager with given parameters.
|
* Creates a StaggeredGridLayoutManager with given parameters.
|
||||||
*
|
*
|
||||||
|
@ -218,6 +233,7 @@ public class StaggeredGridLayoutManager extends RecyclerView.LayoutManager {
|
||||||
public StaggeredGridLayoutManager(int spanCount, int orientation) {
|
public StaggeredGridLayoutManager(int spanCount, int orientation) {
|
||||||
mOrientation = orientation;
|
mOrientation = orientation;
|
||||||
setSpanCount(spanCount);
|
setSpanCount(spanCount);
|
||||||
|
setAutoMeasureEnabled(mGapStrategy != GAP_HANDLING_NONE);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -358,10 +374,16 @@ public class StaggeredGridLayoutManager extends RecyclerView.LayoutManager {
|
||||||
private boolean checkSpanForGap(Span span) {
|
private boolean checkSpanForGap(Span span) {
|
||||||
if (mShouldReverseLayout) {
|
if (mShouldReverseLayout) {
|
||||||
if (span.getEndLine() < mPrimaryOrientation.getEndAfterPadding()) {
|
if (span.getEndLine() < mPrimaryOrientation.getEndAfterPadding()) {
|
||||||
return true;
|
// if it is full span, it is OK
|
||||||
|
final View endView = span.mViews.get(span.mViews.size() - 1);
|
||||||
|
final LayoutParams lp = span.getLayoutParams(endView);
|
||||||
|
return !lp.mFullSpan;
|
||||||
}
|
}
|
||||||
} else if (span.getStartLine() > mPrimaryOrientation.getStartAfterPadding()) {
|
} else if (span.getStartLine() > mPrimaryOrientation.getStartAfterPadding()) {
|
||||||
return true;
|
// if it is full span, it is OK
|
||||||
|
final View startView = span.mViews.get(0);
|
||||||
|
final LayoutParams lp = span.getLayoutParams(startView);
|
||||||
|
return !lp.mFullSpan;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -473,6 +495,7 @@ public class StaggeredGridLayoutManager extends RecyclerView.LayoutManager {
|
||||||
+ "or GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS");
|
+ "or GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS");
|
||||||
}
|
}
|
||||||
mGapStrategy = gapStrategy;
|
mGapStrategy = gapStrategy;
|
||||||
|
setAutoMeasureEnabled(mGapStrategy != GAP_HANDLING_NONE);
|
||||||
requestLayout();
|
requestLayout();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -541,8 +564,35 @@ public class StaggeredGridLayoutManager extends RecyclerView.LayoutManager {
|
||||||
public boolean getReverseLayout() {
|
public boolean getReverseLayout() {
|
||||||
return mReverseLayout;
|
return mReverseLayout;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setMeasuredDimension(Rect childrenBounds, int wSpec, int hSpec) {
|
||||||
|
// we don't like it to wrap content in our non-scroll direction.
|
||||||
|
final int width, height;
|
||||||
|
final int horizontalPadding = getPaddingLeft() + getPaddingRight();
|
||||||
|
final int verticalPadding = getPaddingTop() + getPaddingBottom();
|
||||||
|
if (mOrientation == VERTICAL) {
|
||||||
|
final int usedHeight = childrenBounds.height() + verticalPadding;
|
||||||
|
height = chooseSize(hSpec, usedHeight, getMinimumHeight());
|
||||||
|
width = chooseSize(wSpec, mSizePerSpan * mSpanCount + horizontalPadding,
|
||||||
|
getMinimumWidth());
|
||||||
|
} else {
|
||||||
|
final int usedWidth = childrenBounds.width() + horizontalPadding;
|
||||||
|
width = chooseSize(wSpec, usedWidth, getMinimumWidth());
|
||||||
|
height = chooseSize(hSpec, mSizePerSpan * mSpanCount + verticalPadding,
|
||||||
|
getMinimumHeight());
|
||||||
|
}
|
||||||
|
setMeasuredDimension(width, height);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
|
public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
|
||||||
|
onLayoutChildren(recycler, state, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state,
|
||||||
|
boolean shouldCheckForGaps) {
|
||||||
ensureOrientationHelper();
|
ensureOrientationHelper();
|
||||||
final AnchorInfo anchorInfo = mAnchorInfo;
|
final AnchorInfo anchorInfo = mAnchorInfo;
|
||||||
anchorInfo.reset();
|
anchorInfo.reset();
|
||||||
|
@ -588,8 +638,9 @@ public class StaggeredGridLayoutManager extends RecyclerView.LayoutManager {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
detachAndScrapAttachedViews(recycler);
|
detachAndScrapAttachedViews(recycler);
|
||||||
|
mLayoutState.mRecycle = false;
|
||||||
mLaidOutInvalidFullSpan = false;
|
mLaidOutInvalidFullSpan = false;
|
||||||
updateMeasureSpecs();
|
updateMeasureSpecs(mSecondaryOrientation.getTotalSpace());
|
||||||
updateLayoutState(anchorInfo.mPosition, state);
|
updateLayoutState(anchorInfo.mPosition, state);
|
||||||
if (anchorInfo.mLayoutFromEnd) {
|
if (anchorInfo.mLayoutFromEnd) {
|
||||||
// Layout start.
|
// Layout start.
|
||||||
|
@ -609,6 +660,8 @@ public class StaggeredGridLayoutManager extends RecyclerView.LayoutManager {
|
||||||
fill(recycler, mLayoutState, state);
|
fill(recycler, mLayoutState, state);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
repositionToWrapContentIfNecessary();
|
||||||
|
|
||||||
if (getChildCount() > 0) {
|
if (getChildCount() > 0) {
|
||||||
if (mShouldReverseLayout) {
|
if (mShouldReverseLayout) {
|
||||||
fixEndGap(recycler, state, true);
|
fixEndGap(recycler, state, true);
|
||||||
|
@ -618,14 +671,16 @@ public class StaggeredGridLayoutManager extends RecyclerView.LayoutManager {
|
||||||
fixEndGap(recycler, state, false);
|
fixEndGap(recycler, state, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
boolean hasGaps = false;
|
||||||
if (!state.isPreLayout()) {
|
if (shouldCheckForGaps && !state.isPreLayout()) {
|
||||||
final boolean needToCheckForGaps = mGapStrategy != GAP_HANDLING_NONE
|
final boolean needToCheckForGaps = mGapStrategy != GAP_HANDLING_NONE
|
||||||
&& getChildCount() > 0
|
&& getChildCount() > 0
|
||||||
&& (mLaidOutInvalidFullSpan || hasGapsToFix() != null);
|
&& (mLaidOutInvalidFullSpan || hasGapsToFix() != null);
|
||||||
if (needToCheckForGaps) {
|
if (needToCheckForGaps) {
|
||||||
removeCallbacks(mCheckForGapsRunnable);
|
removeCallbacks(mCheckForGapsRunnable);
|
||||||
postOnAnimation(mCheckForGapsRunnable);
|
if (checkForGaps()) {
|
||||||
|
hasGaps = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
mPendingScrollPosition = NO_POSITION;
|
mPendingScrollPosition = NO_POSITION;
|
||||||
mPendingScrollPositionOffset = INVALID_OFFSET;
|
mPendingScrollPositionOffset = INVALID_OFFSET;
|
||||||
|
@ -633,6 +688,58 @@ public class StaggeredGridLayoutManager extends RecyclerView.LayoutManager {
|
||||||
mLastLayoutFromEnd = anchorInfo.mLayoutFromEnd;
|
mLastLayoutFromEnd = anchorInfo.mLayoutFromEnd;
|
||||||
mLastLayoutRTL = isLayoutRTL();
|
mLastLayoutRTL = isLayoutRTL();
|
||||||
mPendingSavedState = null; // we don't need this anymore
|
mPendingSavedState = null; // we don't need this anymore
|
||||||
|
if (hasGaps) {
|
||||||
|
onLayoutChildren(recycler, state, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void repositionToWrapContentIfNecessary() {
|
||||||
|
if (mSecondaryOrientation.getMode() == View.MeasureSpec.EXACTLY) {
|
||||||
|
return; // nothing to do
|
||||||
|
}
|
||||||
|
float maxSize = 0;
|
||||||
|
final int childCount = getChildCount();
|
||||||
|
for (int i = 0; i < childCount; i ++) {
|
||||||
|
View child = getChildAt(i);
|
||||||
|
float size = mSecondaryOrientation.getDecoratedMeasurement(child);
|
||||||
|
if (size < maxSize) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
LayoutParams layoutParams = (LayoutParams) child.getLayoutParams();
|
||||||
|
if (layoutParams.isFullSpan()) {
|
||||||
|
size = 1f * size / mSpanCount;
|
||||||
|
}
|
||||||
|
maxSize = Math.max(maxSize, size);
|
||||||
|
}
|
||||||
|
int before = mSizePerSpan;
|
||||||
|
int desired = Math.round(maxSize * mSpanCount);
|
||||||
|
if (mSecondaryOrientation.getMode() == View.MeasureSpec.AT_MOST) {
|
||||||
|
desired = Math.min(desired, mSecondaryOrientation.getTotalSpace());
|
||||||
|
}
|
||||||
|
updateMeasureSpecs(desired);
|
||||||
|
if (mSizePerSpan == before) {
|
||||||
|
return; // nothing has changed
|
||||||
|
}
|
||||||
|
for (int i = 0; i < childCount; i ++) {
|
||||||
|
View child = getChildAt(i);
|
||||||
|
final LayoutParams lp = (LayoutParams) child.getLayoutParams();
|
||||||
|
if (lp.mFullSpan) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (isLayoutRTL() && mOrientation == VERTICAL) {
|
||||||
|
int newOffset = -(mSpanCount - 1 - lp.mSpan.mIndex) * mSizePerSpan;
|
||||||
|
int prevOffset = -(mSpanCount - 1 - lp.mSpan.mIndex) * before;
|
||||||
|
child.offsetLeftAndRight(newOffset - prevOffset);
|
||||||
|
} else {
|
||||||
|
int newOffset = lp.mSpan.mIndex * mSizePerSpan;
|
||||||
|
int prevOffset = lp.mSpan.mIndex * before;
|
||||||
|
if (mOrientation == VERTICAL) {
|
||||||
|
child.offsetLeftAndRight(newOffset - prevOffset);
|
||||||
|
} else {
|
||||||
|
child.offsetTopAndBottom(newOffset - prevOffset);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void applyPendingSavedState(AnchorInfo anchorInfo) {
|
private void applyPendingSavedState(AnchorInfo anchorInfo) {
|
||||||
|
@ -780,17 +887,11 @@ public class StaggeredGridLayoutManager extends RecyclerView.LayoutManager {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void updateMeasureSpecs() {
|
void updateMeasureSpecs(int totalSpace) {
|
||||||
mSizePerSpan = mSecondaryOrientation.getTotalSpace() / mSpanCount;
|
mSizePerSpan = totalSpace / mSpanCount;
|
||||||
|
//noinspection ResourceType
|
||||||
mFullSizeSpec = View.MeasureSpec.makeMeasureSpec(
|
mFullSizeSpec = View.MeasureSpec.makeMeasureSpec(
|
||||||
mSecondaryOrientation.getTotalSpace(), View.MeasureSpec.EXACTLY);
|
totalSpace, mSecondaryOrientation.getMode());
|
||||||
if (mOrientation == VERTICAL) {
|
|
||||||
mWidthSpec = View.MeasureSpec.makeMeasureSpec(mSizePerSpan, View.MeasureSpec.EXACTLY);
|
|
||||||
mHeightSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
|
|
||||||
} else {
|
|
||||||
mHeightSpec = View.MeasureSpec.makeMeasureSpec(mSizePerSpan, View.MeasureSpec.EXACTLY);
|
|
||||||
mWidthSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -989,43 +1090,48 @@ public class StaggeredGridLayoutManager extends RecyclerView.LayoutManager {
|
||||||
return computeScrollRange(state);
|
return computeScrollRange(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void measureChildWithDecorationsAndMargin(View child, LayoutParams lp) {
|
private void measureChildWithDecorationsAndMargin(View child, LayoutParams lp,
|
||||||
|
boolean alreadyMeasured) {
|
||||||
if (lp.mFullSpan) {
|
if (lp.mFullSpan) {
|
||||||
if (mOrientation == VERTICAL) {
|
if (mOrientation == VERTICAL) {
|
||||||
measureChildWithDecorationsAndMargin(child, mFullSizeSpec,
|
measureChildWithDecorationsAndMargin(child, mFullSizeSpec,
|
||||||
getSpecForDimension(lp.height, mHeightSpec));
|
getChildMeasureSpec(getHeight(), getHeightMode(), 0, lp.height, true),
|
||||||
|
alreadyMeasured);
|
||||||
} else {
|
} else {
|
||||||
measureChildWithDecorationsAndMargin(child,
|
measureChildWithDecorationsAndMargin(child,
|
||||||
getSpecForDimension(lp.width, mWidthSpec), mFullSizeSpec);
|
getChildMeasureSpec(getWidth(), getWidthMode(), 0, lp.width, true),
|
||||||
|
mFullSizeSpec, alreadyMeasured);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (mOrientation == VERTICAL) {
|
if (mOrientation == VERTICAL) {
|
||||||
measureChildWithDecorationsAndMargin(child, mWidthSpec,
|
measureChildWithDecorationsAndMargin(child,
|
||||||
getSpecForDimension(lp.height, mHeightSpec));
|
getChildMeasureSpec(mSizePerSpan, getWidthMode(), 0, lp.width, false),
|
||||||
|
getChildMeasureSpec(getHeight(), getHeightMode(), 0, lp.height, true),
|
||||||
|
alreadyMeasured);
|
||||||
} else {
|
} else {
|
||||||
measureChildWithDecorationsAndMargin(child,
|
measureChildWithDecorationsAndMargin(child,
|
||||||
getSpecForDimension(lp.width, mWidthSpec), mHeightSpec);
|
getChildMeasureSpec(getWidth(), getWidthMode(), 0, lp.width, true),
|
||||||
|
getChildMeasureSpec(mSizePerSpan, getHeightMode(), 0, lp.height, false),
|
||||||
|
alreadyMeasured);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private int getSpecForDimension(int dim, int defaultSpec) {
|
|
||||||
if (dim < 0) {
|
|
||||||
return defaultSpec;
|
|
||||||
} else {
|
|
||||||
return View.MeasureSpec.makeMeasureSpec(dim, View.MeasureSpec.EXACTLY);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void measureChildWithDecorationsAndMargin(View child, int widthSpec,
|
private void measureChildWithDecorationsAndMargin(View child, int widthSpec,
|
||||||
int heightSpec) {
|
int heightSpec, boolean alreadyMeasured) {
|
||||||
calculateItemDecorationsForChild(child, mTmpRect);
|
calculateItemDecorationsForChild(child, mTmpRect);
|
||||||
LayoutParams lp = (LayoutParams) child.getLayoutParams();
|
LayoutParams lp = (LayoutParams) child.getLayoutParams();
|
||||||
widthSpec = updateSpecWithExtra(widthSpec, lp.leftMargin + mTmpRect.left,
|
widthSpec = updateSpecWithExtra(widthSpec, lp.leftMargin + mTmpRect.left,
|
||||||
lp.rightMargin + mTmpRect.right);
|
lp.rightMargin + mTmpRect.right);
|
||||||
heightSpec = updateSpecWithExtra(heightSpec, lp.topMargin + mTmpRect.top,
|
heightSpec = updateSpecWithExtra(heightSpec, lp.topMargin + mTmpRect.top,
|
||||||
lp.bottomMargin + mTmpRect.bottom);
|
lp.bottomMargin + mTmpRect.bottom);
|
||||||
child.measure(widthSpec, heightSpec);
|
final boolean measure = alreadyMeasured
|
||||||
|
? shouldReMeasureChild(child, widthSpec, heightSpec, lp)
|
||||||
|
: shouldMeasureChild(child, widthSpec, heightSpec, lp);
|
||||||
|
if (measure) {
|
||||||
|
child.measure(widthSpec, heightSpec);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private int updateSpecWithExtra(int spec, int startInset, int endInset) {
|
private int updateSpecWithExtra(int spec, int startInset, int endInset) {
|
||||||
|
@ -1035,7 +1141,7 @@ public class StaggeredGridLayoutManager extends RecyclerView.LayoutManager {
|
||||||
final int mode = View.MeasureSpec.getMode(spec);
|
final int mode = View.MeasureSpec.getMode(spec);
|
||||||
if (mode == View.MeasureSpec.AT_MOST || mode == View.MeasureSpec.EXACTLY) {
|
if (mode == View.MeasureSpec.AT_MOST || mode == View.MeasureSpec.EXACTLY) {
|
||||||
return View.MeasureSpec.makeMeasureSpec(
|
return View.MeasureSpec.makeMeasureSpec(
|
||||||
View.MeasureSpec.getSize(spec) - startInset - endInset, mode);
|
Math.max(0, View.MeasureSpec.getSize(spec) - startInset - endInset), mode);
|
||||||
}
|
}
|
||||||
return spec;
|
return spec;
|
||||||
}
|
}
|
||||||
|
@ -1238,7 +1344,10 @@ public class StaggeredGridLayoutManager extends RecyclerView.LayoutManager {
|
||||||
|
|
||||||
private void fixEndGap(RecyclerView.Recycler recycler, RecyclerView.State state,
|
private void fixEndGap(RecyclerView.Recycler recycler, RecyclerView.State state,
|
||||||
boolean canOffsetChildren) {
|
boolean canOffsetChildren) {
|
||||||
final int maxEndLine = getMaxEnd(mPrimaryOrientation.getEndAfterPadding());
|
final int maxEndLine = getMaxEnd(Integer.MIN_VALUE);
|
||||||
|
if (maxEndLine == Integer.MIN_VALUE) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
int gap = mPrimaryOrientation.getEndAfterPadding() - maxEndLine;
|
int gap = mPrimaryOrientation.getEndAfterPadding() - maxEndLine;
|
||||||
int fixOffset;
|
int fixOffset;
|
||||||
if (gap > 0) {
|
if (gap > 0) {
|
||||||
|
@ -1254,7 +1363,10 @@ public class StaggeredGridLayoutManager extends RecyclerView.LayoutManager {
|
||||||
|
|
||||||
private void fixStartGap(RecyclerView.Recycler recycler, RecyclerView.State state,
|
private void fixStartGap(RecyclerView.Recycler recycler, RecyclerView.State state,
|
||||||
boolean canOffsetChildren) {
|
boolean canOffsetChildren) {
|
||||||
final int minStartLine = getMinStart(mPrimaryOrientation.getStartAfterPadding());
|
final int minStartLine = getMinStart(Integer.MAX_VALUE);
|
||||||
|
if (minStartLine == Integer.MAX_VALUE) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
int gap = minStartLine - mPrimaryOrientation.getStartAfterPadding();
|
int gap = minStartLine - mPrimaryOrientation.getStartAfterPadding();
|
||||||
int fixOffset;
|
int fixOffset;
|
||||||
if (gap > 0) {
|
if (gap > 0) {
|
||||||
|
@ -1293,6 +1405,9 @@ public class StaggeredGridLayoutManager extends RecyclerView.LayoutManager {
|
||||||
mLayoutState.mEndLine = mPrimaryOrientation.getEnd() + endExtra;
|
mLayoutState.mEndLine = mPrimaryOrientation.getEnd() + endExtra;
|
||||||
mLayoutState.mStartLine = -startExtra;
|
mLayoutState.mStartLine = -startExtra;
|
||||||
}
|
}
|
||||||
|
mLayoutState.mStopInFocusable = false;
|
||||||
|
mLayoutState.mRecycle = true;
|
||||||
|
mLayoutState.mInfinite = mPrimaryOrientation.getMode() == View.MeasureSpec.UNSPECIFIED;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setLayoutStateDirection(int direction) {
|
private void setLayoutStateDirection(int direction) {
|
||||||
|
@ -1397,10 +1512,18 @@ public class StaggeredGridLayoutManager extends RecyclerView.LayoutManager {
|
||||||
final int targetLine;
|
final int targetLine;
|
||||||
|
|
||||||
// Line of the furthest row.
|
// Line of the furthest row.
|
||||||
if (layoutState.mLayoutDirection == LAYOUT_END) {
|
if (mLayoutState.mInfinite) {
|
||||||
targetLine = layoutState.mEndLine + layoutState.mAvailable;
|
if (layoutState.mLayoutDirection == LAYOUT_END) {
|
||||||
} else { // LAYOUT_START
|
targetLine = Integer.MAX_VALUE;
|
||||||
targetLine = layoutState.mStartLine - layoutState.mAvailable;
|
} else { // LAYOUT_START
|
||||||
|
targetLine = Integer.MIN_VALUE;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (layoutState.mLayoutDirection == LAYOUT_END) {
|
||||||
|
targetLine = layoutState.mEndLine + layoutState.mAvailable;
|
||||||
|
} else { // LAYOUT_START
|
||||||
|
targetLine = layoutState.mStartLine - layoutState.mAvailable;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
updateAllRemainingSpans(layoutState.mLayoutDirection, targetLine);
|
updateAllRemainingSpans(layoutState.mLayoutDirection, targetLine);
|
||||||
|
@ -1414,7 +1537,8 @@ public class StaggeredGridLayoutManager extends RecyclerView.LayoutManager {
|
||||||
? mPrimaryOrientation.getEndAfterPadding()
|
? mPrimaryOrientation.getEndAfterPadding()
|
||||||
: mPrimaryOrientation.getStartAfterPadding();
|
: mPrimaryOrientation.getStartAfterPadding();
|
||||||
boolean added = false;
|
boolean added = false;
|
||||||
while (layoutState.hasMore(state) && !mRemainingSpans.isEmpty()) {
|
while (layoutState.hasMore(state)
|
||||||
|
&& (mLayoutState.mInfinite || !mRemainingSpans.isEmpty())) {
|
||||||
View view = layoutState.next(recycler);
|
View view = layoutState.next(recycler);
|
||||||
LayoutParams lp = ((LayoutParams) view.getLayoutParams());
|
LayoutParams lp = ((LayoutParams) view.getLayoutParams());
|
||||||
final int position = lp.getViewLayoutPosition();
|
final int position = lp.getViewLayoutPosition();
|
||||||
|
@ -1440,7 +1564,7 @@ public class StaggeredGridLayoutManager extends RecyclerView.LayoutManager {
|
||||||
} else {
|
} else {
|
||||||
addView(view, 0);
|
addView(view, 0);
|
||||||
}
|
}
|
||||||
measureChildWithDecorationsAndMargin(view, lp);
|
measureChildWithDecorationsAndMargin(view, lp, false);
|
||||||
|
|
||||||
final int start;
|
final int start;
|
||||||
final int end;
|
final int end;
|
||||||
|
@ -1488,13 +1612,22 @@ public class StaggeredGridLayoutManager extends RecyclerView.LayoutManager {
|
||||||
mLaidOutInvalidFullSpan = true;
|
mLaidOutInvalidFullSpan = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
attachViewToSpans(view, lp, layoutState);
|
attachViewToSpans(view, lp, layoutState);
|
||||||
final int otherStart = lp.mFullSpan ? mSecondaryOrientation.getStartAfterPadding()
|
final int otherStart;
|
||||||
: currentSpan.mIndex * mSizePerSpan +
|
final int otherEnd;
|
||||||
mSecondaryOrientation.getStartAfterPadding();
|
if (isLayoutRTL() && mOrientation == VERTICAL) {
|
||||||
final int otherEnd = otherStart + mSecondaryOrientation.getDecoratedMeasurement(view);
|
otherEnd = lp.mFullSpan ? mSecondaryOrientation.getEndAfterPadding() :
|
||||||
|
mSecondaryOrientation.getEndAfterPadding()
|
||||||
|
- (mSpanCount - 1 - currentSpan.mIndex) * mSizePerSpan;
|
||||||
|
otherStart = otherEnd - mSecondaryOrientation.getDecoratedMeasurement(view);
|
||||||
|
} else {
|
||||||
|
otherStart = lp.mFullSpan ? mSecondaryOrientation.getStartAfterPadding()
|
||||||
|
: currentSpan.mIndex * mSizePerSpan +
|
||||||
|
mSecondaryOrientation.getStartAfterPadding();
|
||||||
|
otherEnd = otherStart + mSecondaryOrientation.getDecoratedMeasurement(view);
|
||||||
|
}
|
||||||
|
|
||||||
if (mOrientation == VERTICAL) {
|
if (mOrientation == VERTICAL) {
|
||||||
layoutDecoratedWithMargins(view, otherStart, start, otherEnd, end);
|
layoutDecoratedWithMargins(view, otherStart, start, otherEnd, end);
|
||||||
} else {
|
} else {
|
||||||
|
@ -1507,6 +1640,13 @@ public class StaggeredGridLayoutManager extends RecyclerView.LayoutManager {
|
||||||
updateRemainingSpans(currentSpan, mLayoutState.mLayoutDirection, targetLine);
|
updateRemainingSpans(currentSpan, mLayoutState.mLayoutDirection, targetLine);
|
||||||
}
|
}
|
||||||
recycle(recycler, mLayoutState);
|
recycle(recycler, mLayoutState);
|
||||||
|
if (mLayoutState.mStopInFocusable && view.isFocusable()) {
|
||||||
|
if (lp.mFullSpan) {
|
||||||
|
mRemainingSpans.clear();
|
||||||
|
} else {
|
||||||
|
mRemainingSpans.set(currentSpan.mIndex, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
added = true;
|
added = true;
|
||||||
}
|
}
|
||||||
if (!added) {
|
if (!added) {
|
||||||
|
@ -1558,6 +1698,9 @@ public class StaggeredGridLayoutManager extends RecyclerView.LayoutManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void recycle(RecyclerView.Recycler recycler, LayoutState layoutState) {
|
private void recycle(RecyclerView.Recycler recycler, LayoutState layoutState) {
|
||||||
|
if (!layoutState.mRecycle || layoutState.mInfinite) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (layoutState.mAvailable == 0) {
|
if (layoutState.mAvailable == 0) {
|
||||||
// easy, recycle line is still valid
|
// easy, recycle line is still valid
|
||||||
if (layoutState.mLayoutDirection == LAYOUT_START) {
|
if (layoutState.mLayoutDirection == LAYOUT_START) {
|
||||||
|
@ -1913,6 +2056,7 @@ public class StaggeredGridLayoutManager extends RecyclerView.LayoutManager {
|
||||||
layoutDir = LAYOUT_START;
|
layoutDir = LAYOUT_START;
|
||||||
referenceChildPosition = getFirstChildPosition();
|
referenceChildPosition = getFirstChildPosition();
|
||||||
}
|
}
|
||||||
|
mLayoutState.mRecycle = true;
|
||||||
updateLayoutState(referenceChildPosition, state);
|
updateLayoutState(referenceChildPosition, state);
|
||||||
setLayoutStateDirection(layoutDir);
|
setLayoutStateDirection(layoutDir);
|
||||||
mLayoutState.mCurrentPosition = referenceChildPosition + mLayoutState.mItemDirection;
|
mLayoutState.mCurrentPosition = referenceChildPosition + mLayoutState.mItemDirection;
|
||||||
|
@ -1982,8 +2126,13 @@ public class StaggeredGridLayoutManager extends RecyclerView.LayoutManager {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public RecyclerView.LayoutParams generateDefaultLayoutParams() {
|
public RecyclerView.LayoutParams generateDefaultLayoutParams() {
|
||||||
return new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
|
if (mOrientation == HORIZONTAL) {
|
||||||
ViewGroup.LayoutParams.WRAP_CONTENT);
|
return new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
|
||||||
|
ViewGroup.LayoutParams.FILL_PARENT);
|
||||||
|
} else {
|
||||||
|
return new LayoutParams(ViewGroup.LayoutParams.FILL_PARENT,
|
||||||
|
ViewGroup.LayoutParams.WRAP_CONTENT);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -2009,6 +2158,105 @@ public class StaggeredGridLayoutManager extends RecyclerView.LayoutManager {
|
||||||
return mOrientation;
|
return mOrientation;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public View onFocusSearchFailed(View focused, int direction, RecyclerView.Recycler recycler,
|
||||||
|
RecyclerView.State state) {
|
||||||
|
if (getChildCount() == 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
final View directChild = findContainingItemView(focused);
|
||||||
|
if (directChild == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
ensureOrientationHelper();
|
||||||
|
resolveShouldLayoutReverse();
|
||||||
|
final int layoutDir = convertFocusDirectionToLayoutDirection(direction);
|
||||||
|
if (layoutDir == LayoutState.INVALID_LAYOUT) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
LayoutParams prevFocusLayoutParams = (LayoutParams) directChild.getLayoutParams();
|
||||||
|
boolean prevFocusFullSpan = prevFocusLayoutParams.mFullSpan;
|
||||||
|
final Span prevFocusSpan = prevFocusLayoutParams.mSpan;
|
||||||
|
final int referenceChildPosition;
|
||||||
|
if (layoutDir == LAYOUT_END) { // layout towards end
|
||||||
|
referenceChildPosition = getLastChildPosition();
|
||||||
|
} else {
|
||||||
|
referenceChildPosition = getFirstChildPosition();
|
||||||
|
}
|
||||||
|
updateLayoutState(referenceChildPosition, state);
|
||||||
|
setLayoutStateDirection(layoutDir);
|
||||||
|
|
||||||
|
mLayoutState.mCurrentPosition = referenceChildPosition + mLayoutState.mItemDirection;
|
||||||
|
mLayoutState.mAvailable = (int) (MAX_SCROLL_FACTOR * mPrimaryOrientation.getTotalSpace());
|
||||||
|
mLayoutState.mStopInFocusable = true;
|
||||||
|
mLayoutState.mRecycle = false;
|
||||||
|
fill(recycler, mLayoutState, state);
|
||||||
|
mLastLayoutFromEnd = mShouldReverseLayout;
|
||||||
|
if (!prevFocusFullSpan) {
|
||||||
|
View view = prevFocusSpan.getFocusableViewAfter(referenceChildPosition, layoutDir);
|
||||||
|
if (view != null && view != directChild) {
|
||||||
|
return view;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// either could not find from the desired span or prev view is full span.
|
||||||
|
// traverse all spans
|
||||||
|
if (preferLastSpan(layoutDir)) {
|
||||||
|
for (int i = mSpanCount - 1; i >= 0; i --) {
|
||||||
|
View view = mSpans[i].getFocusableViewAfter(referenceChildPosition, layoutDir);
|
||||||
|
if (view != null && view != directChild) {
|
||||||
|
return view;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (int i = 0; i < mSpanCount; i ++) {
|
||||||
|
View view = mSpans[i].getFocusableViewAfter(referenceChildPosition, layoutDir);
|
||||||
|
if (view != null && view != directChild) {
|
||||||
|
return view;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts a focusDirection to orientation.
|
||||||
|
*
|
||||||
|
* @param focusDirection One of {@link View#FOCUS_UP}, {@link View#FOCUS_DOWN},
|
||||||
|
* {@link View#FOCUS_LEFT}, {@link View#FOCUS_RIGHT},
|
||||||
|
* {@link View#FOCUS_BACKWARD}, {@link View#FOCUS_FORWARD}
|
||||||
|
* or 0 for not applicable
|
||||||
|
* @return {@link LayoutState#LAYOUT_START} or {@link LayoutState#LAYOUT_END} if focus direction
|
||||||
|
* is applicable to current state, {@link LayoutState#INVALID_LAYOUT} otherwise.
|
||||||
|
*/
|
||||||
|
private int convertFocusDirectionToLayoutDirection(int focusDirection) {
|
||||||
|
switch (focusDirection) {
|
||||||
|
case View.FOCUS_BACKWARD:
|
||||||
|
return LayoutState.LAYOUT_START;
|
||||||
|
case View.FOCUS_FORWARD:
|
||||||
|
return LayoutState.LAYOUT_END;
|
||||||
|
case View.FOCUS_UP:
|
||||||
|
return mOrientation == VERTICAL ? LayoutState.LAYOUT_START
|
||||||
|
: LayoutState.INVALID_LAYOUT;
|
||||||
|
case View.FOCUS_DOWN:
|
||||||
|
return mOrientation == VERTICAL ? LayoutState.LAYOUT_END
|
||||||
|
: LayoutState.INVALID_LAYOUT;
|
||||||
|
case View.FOCUS_LEFT:
|
||||||
|
return mOrientation == HORIZONTAL ? LayoutState.LAYOUT_START
|
||||||
|
: LayoutState.INVALID_LAYOUT;
|
||||||
|
case View.FOCUS_RIGHT:
|
||||||
|
return mOrientation == HORIZONTAL ? LayoutState.LAYOUT_END
|
||||||
|
: LayoutState.INVALID_LAYOUT;
|
||||||
|
default:
|
||||||
|
if (DEBUG) {
|
||||||
|
Log.d(TAG, "Unknown focus request:" + focusDirection);
|
||||||
|
}
|
||||||
|
return LayoutState.INVALID_LAYOUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* LayoutParams used by StaggeredGridLayoutManager.
|
* LayoutParams used by StaggeredGridLayoutManager.
|
||||||
|
@ -2089,7 +2337,7 @@ public class StaggeredGridLayoutManager extends RecyclerView.LayoutManager {
|
||||||
class Span {
|
class Span {
|
||||||
|
|
||||||
static final int INVALID_LINE = Integer.MIN_VALUE;
|
static final int INVALID_LINE = Integer.MIN_VALUE;
|
||||||
private ArrayList<View> mViews = new ArrayList<View>();
|
private ArrayList<View> mViews = new ArrayList<>();
|
||||||
int mCachedStart = INVALID_LINE;
|
int mCachedStart = INVALID_LINE;
|
||||||
int mCachedEnd = INVALID_LINE;
|
int mCachedEnd = INVALID_LINE;
|
||||||
int mDeletedSize = 0;
|
int mDeletedSize = 0;
|
||||||
|
@ -2273,45 +2521,6 @@ public class StaggeredGridLayoutManager extends RecyclerView.LayoutManager {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// normalized offset is how much this span can scroll
|
|
||||||
int getNormalizedOffset(int dt, int targetStart, int targetEnd) {
|
|
||||||
if (mViews.size() == 0) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if (dt < 0) {
|
|
||||||
final int endSpace = getEndLine() - targetEnd;
|
|
||||||
if (endSpace <= 0) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
return -dt > endSpace ? -endSpace : dt;
|
|
||||||
} else {
|
|
||||||
final int startSpace = targetStart - getStartLine();
|
|
||||||
if (startSpace <= 0) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
return startSpace < dt ? startSpace : dt;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns if there is no child between start-end lines
|
|
||||||
*
|
|
||||||
* @param start The start line
|
|
||||||
* @param end The end line
|
|
||||||
* @return true if a new child can be added between start and end
|
|
||||||
*/
|
|
||||||
boolean isEmpty(int start, int end) {
|
|
||||||
final int count = mViews.size();
|
|
||||||
for (int i = 0; i < count; i++) {
|
|
||||||
final View view = mViews.get(i);
|
|
||||||
if (mPrimaryOrientation.getDecoratedStart(view) < end &&
|
|
||||||
mPrimaryOrientation.getDecoratedEnd(view) > start) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int findFirstVisibleItemPosition() {
|
public int findFirstVisibleItemPosition() {
|
||||||
return mReverseLayout
|
return mReverseLayout
|
||||||
? findOneVisibleChild(mViews.size() - 1, -1, false)
|
? findOneVisibleChild(mViews.size() - 1, -1, false)
|
||||||
|
@ -2356,6 +2565,36 @@ public class StaggeredGridLayoutManager extends RecyclerView.LayoutManager {
|
||||||
}
|
}
|
||||||
return NO_POSITION;
|
return NO_POSITION;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Depending on the layout direction, returns the View that is after the given position.
|
||||||
|
*/
|
||||||
|
public View getFocusableViewAfter(int referenceChildPosition, int layoutDir) {
|
||||||
|
View candidate = null;
|
||||||
|
if (layoutDir == LAYOUT_START) {
|
||||||
|
final int limit = mViews.size();
|
||||||
|
for (int i = 0; i < limit; i++) {
|
||||||
|
final View view = mViews.get(i);
|
||||||
|
if (view.isFocusable() &&
|
||||||
|
(getPosition(view) > referenceChildPosition == mReverseLayout) ) {
|
||||||
|
candidate = view;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (int i = mViews.size() - 1; i >= 0; i--) {
|
||||||
|
final View view = mViews.get(i);
|
||||||
|
if (view.isFocusable() &&
|
||||||
|
(getPosition(view) > referenceChildPosition == !mReverseLayout)) {
|
||||||
|
candidate = view;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return candidate;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -2532,7 +2771,7 @@ public class StaggeredGridLayoutManager extends RecyclerView.LayoutManager {
|
||||||
|
|
||||||
public void addFullSpanItem(FullSpanItem fullSpanItem) {
|
public void addFullSpanItem(FullSpanItem fullSpanItem) {
|
||||||
if (mFullSpanItems == null) {
|
if (mFullSpanItems == null) {
|
||||||
mFullSpanItems = new ArrayList<FullSpanItem>();
|
mFullSpanItems = new ArrayList<>();
|
||||||
}
|
}
|
||||||
final int size = mFullSpanItems.size();
|
final int size = mFullSpanItems.size();
|
||||||
for (int i = 0; i < size; i++) {
|
for (int i = 0; i < size; i++) {
|
||||||
|
@ -2624,10 +2863,6 @@ public class StaggeredGridLayoutManager extends RecyclerView.LayoutManager {
|
||||||
return mGapPerSpan == null ? 0 : mGapPerSpan[spanIndex];
|
return mGapPerSpan == null ? 0 : mGapPerSpan[spanIndex];
|
||||||
}
|
}
|
||||||
|
|
||||||
public void invalidateSpanGaps() {
|
|
||||||
mGapPerSpan = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int describeContents() {
|
public int describeContents() {
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -2671,7 +2906,10 @@ public class StaggeredGridLayoutManager extends RecyclerView.LayoutManager {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static class SavedState implements Parcelable {
|
/**
|
||||||
|
* @hide
|
||||||
|
*/
|
||||||
|
public static class SavedState implements Parcelable {
|
||||||
|
|
||||||
int mAnchorPosition;
|
int mAnchorPosition;
|
||||||
int mVisibleAnchorPosition; // Replacement for span info when spans are invalidated
|
int mVisibleAnchorPosition; // Replacement for span info when spans are invalidated
|
||||||
|
@ -2704,6 +2942,7 @@ public class StaggeredGridLayoutManager extends RecyclerView.LayoutManager {
|
||||||
mReverseLayout = in.readInt() == 1;
|
mReverseLayout = in.readInt() == 1;
|
||||||
mAnchorLayoutFromEnd = in.readInt() == 1;
|
mAnchorLayoutFromEnd = in.readInt() == 1;
|
||||||
mLastLayoutRTL = in.readInt() == 1;
|
mLastLayoutRTL = in.readInt() == 1;
|
||||||
|
//noinspection unchecked
|
||||||
mFullSpanItems = in.readArrayList(
|
mFullSpanItems = in.readArrayList(
|
||||||
LazySpanLookup.FullSpanItem.class.getClassLoader());
|
LazySpanLookup.FullSpanItem.class.getClassLoader());
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,326 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2015 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.telegram.messenger.support.widget;
|
||||||
|
|
||||||
|
import android.support.annotation.NonNull;
|
||||||
|
import android.support.annotation.Nullable;
|
||||||
|
import android.support.annotation.VisibleForTesting;
|
||||||
|
import android.support.v4.util.ArrayMap;
|
||||||
|
import android.support.v4.util.LongSparseArray;
|
||||||
|
import android.support.v4.util.Pools;
|
||||||
|
|
||||||
|
import static org.telegram.messenger.support.widget.RecyclerView.ViewHolder;
|
||||||
|
import static org.telegram.messenger.support.widget.RecyclerView.ItemAnimator.ItemHolderInfo;
|
||||||
|
|
||||||
|
import static org.telegram.messenger.support.widget.ViewInfoStore.InfoRecord.FLAG_APPEAR_PRE_AND_POST;
|
||||||
|
import static org.telegram.messenger.support.widget.ViewInfoStore.InfoRecord.FLAG_APPEAR_AND_DISAPPEAR;
|
||||||
|
import static org.telegram.messenger.support.widget.ViewInfoStore.InfoRecord.FLAG_PRE_AND_POST;
|
||||||
|
import static org.telegram.messenger.support.widget.ViewInfoStore.InfoRecord.FLAG_DISAPPEARED;
|
||||||
|
import static org.telegram.messenger.support.widget.ViewInfoStore.InfoRecord.FLAG_APPEAR;
|
||||||
|
import static org.telegram.messenger.support.widget.ViewInfoStore.InfoRecord.FLAG_PRE;
|
||||||
|
import static org.telegram.messenger.support.widget.ViewInfoStore.InfoRecord.FLAG_POST;
|
||||||
|
|
||||||
|
class ViewInfoStore {
|
||||||
|
|
||||||
|
private static final boolean DEBUG = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* View data records for pre-layout
|
||||||
|
*/
|
||||||
|
@VisibleForTesting
|
||||||
|
final ArrayMap<ViewHolder, InfoRecord> mLayoutHolderMap = new ArrayMap<>();
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
final LongSparseArray<ViewHolder> mOldChangedHolders = new LongSparseArray<>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clears the state and all existing tracking data
|
||||||
|
*/
|
||||||
|
void clear() {
|
||||||
|
mLayoutHolderMap.clear();
|
||||||
|
mOldChangedHolders.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds the item information to the prelayout tracking
|
||||||
|
* @param holder The ViewHolder whose information is being saved
|
||||||
|
* @param info The information to save
|
||||||
|
*/
|
||||||
|
void addToPreLayout(ViewHolder holder, ItemHolderInfo info) {
|
||||||
|
InfoRecord record = mLayoutHolderMap.get(holder);
|
||||||
|
if (record == null) {
|
||||||
|
record = InfoRecord.obtain();
|
||||||
|
mLayoutHolderMap.put(holder, record);
|
||||||
|
}
|
||||||
|
record.preInfo = info;
|
||||||
|
record.flags |= FLAG_PRE;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean isDisappearing(ViewHolder holder) {
|
||||||
|
final InfoRecord record = mLayoutHolderMap.get(holder);
|
||||||
|
return record != null && ((record.flags & FLAG_DISAPPEARED) != 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finds the ItemHolderInfo for the given ViewHolder in preLayout list and removes it.
|
||||||
|
*
|
||||||
|
* @param vh The ViewHolder whose information is being queried
|
||||||
|
* @return The ItemHolderInfo for the given ViewHolder or null if it does not exist
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
ItemHolderInfo popFromPreLayout(ViewHolder vh) {
|
||||||
|
return popFromLayoutStep(vh, FLAG_PRE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finds the ItemHolderInfo for the given ViewHolder in postLayout list and removes it.
|
||||||
|
*
|
||||||
|
* @param vh The ViewHolder whose information is being queried
|
||||||
|
* @return The ItemHolderInfo for the given ViewHolder or null if it does not exist
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
ItemHolderInfo popFromPostLayout(ViewHolder vh) {
|
||||||
|
return popFromLayoutStep(vh, FLAG_POST);
|
||||||
|
}
|
||||||
|
|
||||||
|
private ItemHolderInfo popFromLayoutStep(ViewHolder vh, int flag) {
|
||||||
|
int index = mLayoutHolderMap.indexOfKey(vh);
|
||||||
|
if (index < 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
final InfoRecord record = mLayoutHolderMap.valueAt(index);
|
||||||
|
if (record != null && (record.flags & flag) != 0) {
|
||||||
|
record.flags &= ~flag;
|
||||||
|
final ItemHolderInfo info;
|
||||||
|
if (flag == FLAG_PRE) {
|
||||||
|
info = record.preInfo;
|
||||||
|
} else if (flag == FLAG_POST) {
|
||||||
|
info = record.postInfo;
|
||||||
|
} else {
|
||||||
|
throw new IllegalArgumentException("Must provide flag PRE or POST");
|
||||||
|
}
|
||||||
|
// if not pre-post flag is left, clear.
|
||||||
|
if ((record.flags & (FLAG_PRE | FLAG_POST)) == 0) {
|
||||||
|
mLayoutHolderMap.removeAt(index);
|
||||||
|
InfoRecord.recycle(record);
|
||||||
|
}
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds the given ViewHolder to the oldChangeHolders list
|
||||||
|
* @param key The key to identify the ViewHolder.
|
||||||
|
* @param holder The ViewHolder to store
|
||||||
|
*/
|
||||||
|
void addToOldChangeHolders(long key, ViewHolder holder) {
|
||||||
|
mOldChangedHolders.put(key, holder);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds the given ViewHolder to the appeared in pre layout list. These are Views added by the
|
||||||
|
* LayoutManager during a pre-layout pass. We distinguish them from other views that were
|
||||||
|
* already in the pre-layout so that ItemAnimator can choose to run a different animation for
|
||||||
|
* them.
|
||||||
|
*
|
||||||
|
* @param holder The ViewHolder to store
|
||||||
|
* @param info The information to save
|
||||||
|
*/
|
||||||
|
void addToAppearedInPreLayoutHolders(ViewHolder holder, ItemHolderInfo info) {
|
||||||
|
InfoRecord record = mLayoutHolderMap.get(holder);
|
||||||
|
if (record == null) {
|
||||||
|
record = InfoRecord.obtain();
|
||||||
|
mLayoutHolderMap.put(holder, record);
|
||||||
|
}
|
||||||
|
record.flags |= FLAG_APPEAR;
|
||||||
|
record.preInfo = info;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks whether the given ViewHolder is in preLayout list
|
||||||
|
* @param viewHolder The ViewHolder to query
|
||||||
|
*
|
||||||
|
* @return True if the ViewHolder is present in preLayout, false otherwise
|
||||||
|
*/
|
||||||
|
boolean isInPreLayout(ViewHolder viewHolder) {
|
||||||
|
final InfoRecord record = mLayoutHolderMap.get(viewHolder);
|
||||||
|
return record != null && (record.flags & FLAG_PRE) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Queries the oldChangeHolder list for the given key. If they are not tracked, simply returns
|
||||||
|
* null.
|
||||||
|
* @param key The key to be used to find the ViewHolder.
|
||||||
|
*
|
||||||
|
* @return A ViewHolder if exists or null if it does not exist.
|
||||||
|
*/
|
||||||
|
ViewHolder getFromOldChangeHolders(long key) {
|
||||||
|
return mOldChangedHolders.get(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds the item information to the post layout list
|
||||||
|
* @param holder The ViewHolder whose information is being saved
|
||||||
|
* @param info The information to save
|
||||||
|
*/
|
||||||
|
void addToPostLayout(ViewHolder holder, ItemHolderInfo info) {
|
||||||
|
InfoRecord record = mLayoutHolderMap.get(holder);
|
||||||
|
if (record == null) {
|
||||||
|
record = InfoRecord.obtain();
|
||||||
|
mLayoutHolderMap.put(holder, record);
|
||||||
|
}
|
||||||
|
record.postInfo = info;
|
||||||
|
record.flags |= FLAG_POST;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A ViewHolder might be added by the LayoutManager just to animate its disappearance.
|
||||||
|
* This list holds such items so that we can animate / recycle these ViewHolders properly.
|
||||||
|
*
|
||||||
|
* @param holder The ViewHolder which disappeared during a layout.
|
||||||
|
*/
|
||||||
|
void addToDisappearedInLayout(ViewHolder holder) {
|
||||||
|
InfoRecord record = mLayoutHolderMap.get(holder);
|
||||||
|
if (record == null) {
|
||||||
|
record = InfoRecord.obtain();
|
||||||
|
mLayoutHolderMap.put(holder, record);
|
||||||
|
}
|
||||||
|
record.flags |= FLAG_DISAPPEARED;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes a ViewHolder from disappearing list.
|
||||||
|
* @param holder The ViewHolder to be removed from the disappearing list.
|
||||||
|
*/
|
||||||
|
void removeFromDisappearedInLayout(ViewHolder holder) {
|
||||||
|
InfoRecord record = mLayoutHolderMap.get(holder);
|
||||||
|
if (record == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
record.flags &= ~FLAG_DISAPPEARED;
|
||||||
|
}
|
||||||
|
|
||||||
|
void process(ProcessCallback callback) {
|
||||||
|
for (int index = mLayoutHolderMap.size() - 1; index >= 0; index --) {
|
||||||
|
final ViewHolder viewHolder = mLayoutHolderMap.keyAt(index);
|
||||||
|
final InfoRecord record = mLayoutHolderMap.removeAt(index);
|
||||||
|
if ((record.flags & FLAG_APPEAR_AND_DISAPPEAR) == FLAG_APPEAR_AND_DISAPPEAR) {
|
||||||
|
// Appeared then disappeared. Not useful for animations.
|
||||||
|
callback.unused(viewHolder);
|
||||||
|
} else if ((record.flags & FLAG_DISAPPEARED) != 0) {
|
||||||
|
// Set as "disappeared" by the LayoutManager (addDisappearingView)
|
||||||
|
if (record.preInfo == null) {
|
||||||
|
// similar to appear disappear but happened between different layout passes.
|
||||||
|
// this can happen when the layout manager is using auto-measure
|
||||||
|
callback.unused(viewHolder);
|
||||||
|
} else {
|
||||||
|
callback.processDisappeared(viewHolder, record.preInfo, record.postInfo);
|
||||||
|
}
|
||||||
|
} else if ((record.flags & FLAG_APPEAR_PRE_AND_POST) == FLAG_APPEAR_PRE_AND_POST) {
|
||||||
|
// Appeared in the layout but not in the adapter (e.g. entered the viewport)
|
||||||
|
callback.processAppeared(viewHolder, record.preInfo, record.postInfo);
|
||||||
|
} else if ((record.flags & FLAG_PRE_AND_POST) == FLAG_PRE_AND_POST) {
|
||||||
|
// Persistent in both passes. Animate persistence
|
||||||
|
callback.processPersistent(viewHolder, record.preInfo, record.postInfo);
|
||||||
|
} else if ((record.flags & FLAG_PRE) != 0) {
|
||||||
|
// Was in pre-layout, never been added to post layout
|
||||||
|
callback.processDisappeared(viewHolder, record.preInfo, null);
|
||||||
|
} else if ((record.flags & FLAG_POST) != 0) {
|
||||||
|
// Was not in pre-layout, been added to post layout
|
||||||
|
callback.processAppeared(viewHolder, record.preInfo, record.postInfo);
|
||||||
|
} else if ((record.flags & FLAG_APPEAR) != 0) {
|
||||||
|
// Scrap view. RecyclerView will handle removing/recycling this.
|
||||||
|
} else if (DEBUG) {
|
||||||
|
throw new IllegalStateException("record without any reasonable flag combination:/");
|
||||||
|
}
|
||||||
|
InfoRecord.recycle(record);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes the ViewHolder from all list
|
||||||
|
* @param holder The ViewHolder which we should stop tracking
|
||||||
|
*/
|
||||||
|
void removeViewHolder(ViewHolder holder) {
|
||||||
|
for (int i = mOldChangedHolders.size() - 1; i >= 0; i--) {
|
||||||
|
if (holder == mOldChangedHolders.valueAt(i)) {
|
||||||
|
mOldChangedHolders.removeAt(i);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
final InfoRecord info = mLayoutHolderMap.remove(holder);
|
||||||
|
if (info != null) {
|
||||||
|
InfoRecord.recycle(info);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void onDetach() {
|
||||||
|
InfoRecord.drainCache();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onViewDetached(ViewHolder viewHolder) {
|
||||||
|
removeFromDisappearedInLayout(viewHolder);
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ProcessCallback {
|
||||||
|
void processDisappeared(ViewHolder viewHolder, @NonNull ItemHolderInfo preInfo,
|
||||||
|
@Nullable ItemHolderInfo postInfo);
|
||||||
|
void processAppeared(ViewHolder viewHolder, @Nullable ItemHolderInfo preInfo,
|
||||||
|
ItemHolderInfo postInfo);
|
||||||
|
void processPersistent(ViewHolder viewHolder, @NonNull ItemHolderInfo preInfo,
|
||||||
|
@NonNull ItemHolderInfo postInfo);
|
||||||
|
void unused(ViewHolder holder);
|
||||||
|
}
|
||||||
|
|
||||||
|
static class InfoRecord {
|
||||||
|
// disappearing list
|
||||||
|
static final int FLAG_DISAPPEARED = 1;
|
||||||
|
// appear in pre layout list
|
||||||
|
static final int FLAG_APPEAR = 1 << 1;
|
||||||
|
// pre layout, this is necessary to distinguish null item info
|
||||||
|
static final int FLAG_PRE = 1 << 2;
|
||||||
|
// post layout, this is necessary to distinguish null item info
|
||||||
|
static final int FLAG_POST = 1 << 3;
|
||||||
|
static final int FLAG_APPEAR_AND_DISAPPEAR = FLAG_APPEAR | FLAG_DISAPPEARED;
|
||||||
|
static final int FLAG_PRE_AND_POST = FLAG_PRE | FLAG_POST;
|
||||||
|
static final int FLAG_APPEAR_PRE_AND_POST = FLAG_APPEAR | FLAG_PRE | FLAG_POST;
|
||||||
|
int flags;
|
||||||
|
@Nullable ItemHolderInfo preInfo;
|
||||||
|
@Nullable ItemHolderInfo postInfo;
|
||||||
|
static Pools.Pool<InfoRecord> sPool = new Pools.SimplePool<>(20);
|
||||||
|
|
||||||
|
private InfoRecord() {
|
||||||
|
}
|
||||||
|
|
||||||
|
static InfoRecord obtain() {
|
||||||
|
InfoRecord record = sPool.acquire();
|
||||||
|
return record == null ? new InfoRecord() : record;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void recycle(InfoRecord record) {
|
||||||
|
record.flags = 0;
|
||||||
|
record.preInfo = null;
|
||||||
|
record.postInfo = null;
|
||||||
|
sPool.release(record);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void drainCache() {
|
||||||
|
//noinspection StatementWithEmptyBody
|
||||||
|
while (sPool.acquire() != null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -16,13 +16,15 @@
|
||||||
|
|
||||||
package org.telegram.messenger.support.widget.helper;
|
package org.telegram.messenger.support.widget.helper;
|
||||||
|
|
||||||
|
import android.content.res.Resources;
|
||||||
import android.graphics.Canvas;
|
import android.graphics.Canvas;
|
||||||
import android.graphics.Rect;
|
import android.graphics.Rect;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.support.v4.animation.ValueAnimatorCompat;
|
import android.support.annotation.Nullable;
|
||||||
import android.support.v4.animation.AnimatorCompatHelper;
|
import android.support.v4.animation.AnimatorCompatHelper;
|
||||||
import android.support.v4.animation.AnimatorListenerCompat;
|
import android.support.v4.animation.AnimatorListenerCompat;
|
||||||
import android.support.v4.animation.AnimatorUpdateListenerCompat;
|
import android.support.v4.animation.AnimatorUpdateListenerCompat;
|
||||||
|
import android.support.v4.animation.ValueAnimatorCompat;
|
||||||
import android.support.v4.view.GestureDetectorCompat;
|
import android.support.v4.view.GestureDetectorCompat;
|
||||||
import android.support.v4.view.MotionEventCompat;
|
import android.support.v4.view.MotionEventCompat;
|
||||||
import android.support.v4.view.VelocityTrackerCompat;
|
import android.support.v4.view.VelocityTrackerCompat;
|
||||||
|
@ -31,6 +33,8 @@ import android.support.v4.view.ViewCompat;
|
||||||
import org.telegram.messenger.AndroidUtilities;
|
import org.telegram.messenger.AndroidUtilities;
|
||||||
import org.telegram.messenger.support.widget.LinearLayoutManager;
|
import org.telegram.messenger.support.widget.LinearLayoutManager;
|
||||||
import org.telegram.messenger.support.widget.RecyclerView;
|
import org.telegram.messenger.support.widget.RecyclerView;
|
||||||
|
import org.telegram.messenger.support.widget.RecyclerView.OnItemTouchListener;
|
||||||
|
import org.telegram.messenger.support.widget.RecyclerView.ViewHolder;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.view.GestureDetector;
|
import android.view.GestureDetector;
|
||||||
import android.view.HapticFeedbackConstants;
|
import android.view.HapticFeedbackConstants;
|
||||||
|
@ -39,14 +43,11 @@ import android.view.VelocityTracker;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewConfiguration;
|
import android.view.ViewConfiguration;
|
||||||
import android.view.ViewParent;
|
import android.view.ViewParent;
|
||||||
|
import android.view.animation.Interpolator;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.telegram.messenger.support.widget.RecyclerView.OnItemTouchListener;
|
|
||||||
import org.telegram.messenger.support.widget.RecyclerView.ViewHolder;
|
|
||||||
import android.view.animation.Interpolator;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This is a utility class to add swipe to dismiss and drag & drop support to RecyclerView.
|
* This is a utility class to add swipe to dismiss and drag & drop support to RecyclerView.
|
||||||
* <p>
|
* <p>
|
||||||
|
@ -156,6 +157,11 @@ public class ItemTouchHelper extends RecyclerView.ItemDecoration
|
||||||
|
|
||||||
private static final int ACTION_MODE_DRAG_MASK = ACTION_MODE_SWIPE_MASK << DIRECTION_FLAG_COUNT;
|
private static final int ACTION_MODE_DRAG_MASK = ACTION_MODE_SWIPE_MASK << DIRECTION_FLAG_COUNT;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The unit we are using to track velocity
|
||||||
|
*/
|
||||||
|
private static final int PIXELS_PER_SECOND = 1000;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Views, whose state should be cleared after they are detached from RecyclerView.
|
* Views, whose state should be cleared after they are detached from RecyclerView.
|
||||||
* This is necessary after swipe dismissing an item. We wait until animator finishes its job
|
* This is necessary after swipe dismissing an item. We wait until animator finishes its job
|
||||||
|
@ -181,6 +187,16 @@ public class ItemTouchHelper extends RecyclerView.ItemDecoration
|
||||||
|
|
||||||
float mInitialTouchY;
|
float mInitialTouchY;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set when ItemTouchHelper is assigned to a RecyclerView.
|
||||||
|
*/
|
||||||
|
float mSwipeEscapeVelocity;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set when ItemTouchHelper is assigned to a RecyclerView.
|
||||||
|
*/
|
||||||
|
float mMaxSwipeVelocity;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The diff between the last event and initial touch.
|
* The diff between the last event and initial touch.
|
||||||
*/
|
*/
|
||||||
|
@ -367,11 +383,11 @@ public class ItemTouchHelper extends RecyclerView.ItemDecoration
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case MotionEvent.ACTION_CANCEL:
|
case MotionEvent.ACTION_CANCEL:
|
||||||
case MotionEvent.ACTION_UP:
|
|
||||||
if (mVelocityTracker != null) {
|
if (mVelocityTracker != null) {
|
||||||
mVelocityTracker
|
mVelocityTracker.clear();
|
||||||
.computeCurrentVelocity(1000, mRecyclerView.getMaxFlingVelocity());
|
|
||||||
}
|
}
|
||||||
|
// fall through
|
||||||
|
case MotionEvent.ACTION_UP:
|
||||||
select(null, ACTION_STATE_IDLE);
|
select(null, ACTION_STATE_IDLE);
|
||||||
mActivePointerId = ACTIVE_POINTER_ID_NONE;
|
mActivePointerId = ACTIVE_POINTER_ID_NONE;
|
||||||
break;
|
break;
|
||||||
|
@ -379,11 +395,6 @@ public class ItemTouchHelper extends RecyclerView.ItemDecoration
|
||||||
final int pointerIndex = MotionEventCompat.getActionIndex(event);
|
final int pointerIndex = MotionEventCompat.getActionIndex(event);
|
||||||
final int pointerId = MotionEventCompat.getPointerId(event, pointerIndex);
|
final int pointerId = MotionEventCompat.getPointerId(event, pointerIndex);
|
||||||
if (pointerId == mActivePointerId) {
|
if (pointerId == mActivePointerId) {
|
||||||
if (mVelocityTracker != null) {
|
|
||||||
mVelocityTracker
|
|
||||||
.computeCurrentVelocity(1000,
|
|
||||||
mRecyclerView.getMaxFlingVelocity());
|
|
||||||
}
|
|
||||||
// This was our active pointer going up. Choose a new
|
// This was our active pointer going up. Choose a new
|
||||||
// active pointer and adjust accordingly.
|
// active pointer and adjust accordingly.
|
||||||
final int newPointerIndex = pointerIndex == 0 ? 1 : 0;
|
final int newPointerIndex = pointerIndex == 0 ? 1 : 0;
|
||||||
|
@ -436,12 +447,14 @@ public class ItemTouchHelper extends RecyclerView.ItemDecoration
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Attaches the ItemTouchHelper to the provided RecyclerView. If TouchHelper is already
|
* Attaches the ItemTouchHelper to the provided RecyclerView. If TouchHelper is already
|
||||||
* attached
|
* attached to a RecyclerView, it will first detach from the previous one. You can call this
|
||||||
* to a RecyclerView, it will first detach from the previous one.
|
* method with {@code null} to detach it from the current RecyclerView.
|
||||||
*
|
*
|
||||||
* @param recyclerView The RecyclerView instance to which you want to add this helper.
|
* @param recyclerView The RecyclerView instance to which you want to add this helper or
|
||||||
|
* {@code null} if you want to remove ItemTouchHelper from the current
|
||||||
|
* RecyclerView.
|
||||||
*/
|
*/
|
||||||
public void attachToRecyclerView(RecyclerView recyclerView) {
|
public void attachToRecyclerView(@Nullable RecyclerView recyclerView) {
|
||||||
if (mRecyclerView == recyclerView) {
|
if (mRecyclerView == recyclerView) {
|
||||||
return; // nothing to do
|
return; // nothing to do
|
||||||
}
|
}
|
||||||
|
@ -450,6 +463,9 @@ public class ItemTouchHelper extends RecyclerView.ItemDecoration
|
||||||
}
|
}
|
||||||
mRecyclerView = recyclerView;
|
mRecyclerView = recyclerView;
|
||||||
if (mRecyclerView != null) {
|
if (mRecyclerView != null) {
|
||||||
|
final Resources resources = recyclerView.getResources();
|
||||||
|
mSwipeEscapeVelocity = AndroidUtilities.dp(120);
|
||||||
|
mMaxSwipeVelocity = AndroidUtilities.dp(800);
|
||||||
setupCallbacks();
|
setupCallbacks();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -874,7 +890,6 @@ public class ItemTouchHelper extends RecyclerView.ItemDecoration
|
||||||
anim.cancel();
|
anim.cancel();
|
||||||
}
|
}
|
||||||
mRecoverAnimations.remove(i);
|
mRecoverAnimations.remove(i);
|
||||||
anim.mViewHolder.setIsRecyclable(true);
|
|
||||||
return anim.mAnimationType;
|
return anim.mAnimationType;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1010,7 +1025,7 @@ public class ItemTouchHelper extends RecyclerView.ItemDecoration
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Starts dragging the provided ViewHolder. By default, ItemTouchHelper starts a drag when a
|
* Starts dragging the provided ViewHolder. By default, ItemTouchHelper starts a drag when a
|
||||||
* View is long pressed. You can disable that behavior via
|
* View is long pressed. You can disable that behavior by overriding
|
||||||
* {@link ItemTouchHelper.Callback#isLongPressDragEnabled()}.
|
* {@link ItemTouchHelper.Callback#isLongPressDragEnabled()}.
|
||||||
* <p>
|
* <p>
|
||||||
* For this method to work:
|
* For this method to work:
|
||||||
|
@ -1189,11 +1204,17 @@ public class ItemTouchHelper extends RecyclerView.ItemDecoration
|
||||||
if ((flags & (LEFT | RIGHT)) != 0) {
|
if ((flags & (LEFT | RIGHT)) != 0) {
|
||||||
final int dirFlag = mDx > 0 ? RIGHT : LEFT;
|
final int dirFlag = mDx > 0 ? RIGHT : LEFT;
|
||||||
if (mVelocityTracker != null && mActivePointerId > -1) {
|
if (mVelocityTracker != null && mActivePointerId > -1) {
|
||||||
|
mVelocityTracker.computeCurrentVelocity(PIXELS_PER_SECOND,
|
||||||
|
mCallback.getSwipeVelocityThreshold(mMaxSwipeVelocity));
|
||||||
final float xVelocity = VelocityTrackerCompat
|
final float xVelocity = VelocityTrackerCompat
|
||||||
.getXVelocity(mVelocityTracker, mActivePointerId);
|
.getXVelocity(mVelocityTracker, mActivePointerId);
|
||||||
|
final float yVelocity = VelocityTrackerCompat
|
||||||
|
.getYVelocity(mVelocityTracker, mActivePointerId);
|
||||||
final int velDirFlag = xVelocity > 0f ? RIGHT : LEFT;
|
final int velDirFlag = xVelocity > 0f ? RIGHT : LEFT;
|
||||||
|
final float absXVelocity = Math.abs(xVelocity);
|
||||||
if ((velDirFlag & flags) != 0 && dirFlag == velDirFlag &&
|
if ((velDirFlag & flags) != 0 && dirFlag == velDirFlag &&
|
||||||
Math.abs(xVelocity) >= mRecyclerView.getMinFlingVelocity()) {
|
absXVelocity >= mCallback.getSwipeEscapeVelocity(mSwipeEscapeVelocity) &&
|
||||||
|
absXVelocity > Math.abs(yVelocity)) {
|
||||||
return velDirFlag;
|
return velDirFlag;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1212,11 +1233,17 @@ public class ItemTouchHelper extends RecyclerView.ItemDecoration
|
||||||
if ((flags & (UP | DOWN)) != 0) {
|
if ((flags & (UP | DOWN)) != 0) {
|
||||||
final int dirFlag = mDy > 0 ? DOWN : UP;
|
final int dirFlag = mDy > 0 ? DOWN : UP;
|
||||||
if (mVelocityTracker != null && mActivePointerId > -1) {
|
if (mVelocityTracker != null && mActivePointerId > -1) {
|
||||||
|
mVelocityTracker.computeCurrentVelocity(PIXELS_PER_SECOND,
|
||||||
|
mCallback.getSwipeVelocityThreshold(mMaxSwipeVelocity));
|
||||||
|
final float xVelocity = VelocityTrackerCompat
|
||||||
|
.getXVelocity(mVelocityTracker, mActivePointerId);
|
||||||
final float yVelocity = VelocityTrackerCompat
|
final float yVelocity = VelocityTrackerCompat
|
||||||
.getYVelocity(mVelocityTracker, mActivePointerId);
|
.getYVelocity(mVelocityTracker, mActivePointerId);
|
||||||
final int velDirFlag = yVelocity > 0f ? DOWN : UP;
|
final int velDirFlag = yVelocity > 0f ? DOWN : UP;
|
||||||
|
final float absYVelocity = Math.abs(yVelocity);
|
||||||
if ((velDirFlag & flags) != 0 && velDirFlag == dirFlag &&
|
if ((velDirFlag & flags) != 0 && velDirFlag == dirFlag &&
|
||||||
Math.abs(yVelocity) >= mRecyclerView.getMinFlingVelocity()) {
|
absYVelocity >= mCallback.getSwipeEscapeVelocity(mSwipeEscapeVelocity) &&
|
||||||
|
absYVelocity > Math.abs(xVelocity)) {
|
||||||
return velDirFlag;
|
return velDirFlag;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1357,7 +1384,7 @@ public class ItemTouchHelper extends RecyclerView.ItemDecoration
|
||||||
/**
|
/**
|
||||||
* Drag scroll speed keeps accelerating until this many milliseconds before being capped.
|
* Drag scroll speed keeps accelerating until this many milliseconds before being capped.
|
||||||
*/
|
*/
|
||||||
private static final long DRAG_SCROLL_ACCELERATION_LIMIT_TIME_MS = 500;
|
private static final long DRAG_SCROLL_ACCELERATION_LIMIT_TIME_MS = 2000;
|
||||||
|
|
||||||
private int mCachedMaxScrollSpeed = -1;
|
private int mCachedMaxScrollSpeed = -1;
|
||||||
|
|
||||||
|
@ -1372,7 +1399,8 @@ public class ItemTouchHelper extends RecyclerView.ItemDecoration
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the {@link ItemTouchUIUtil} that is used by the {@link Callback} class for visual
|
* Returns the {@link ItemTouchUIUtil} that is used by the {@link Callback} class for
|
||||||
|
* visual
|
||||||
* changes on Views in response to user interactions. {@link ItemTouchUIUtil} has different
|
* changes on Views in response to user interactions. {@link ItemTouchUIUtil} has different
|
||||||
* implementations for different platform versions.
|
* implementations for different platform versions.
|
||||||
* <p>
|
* <p>
|
||||||
|
@ -1661,6 +1689,54 @@ public class ItemTouchHelper extends RecyclerView.ItemDecoration
|
||||||
return .5f;
|
return .5f;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defines the minimum velocity which will be considered as a swipe action by the user.
|
||||||
|
* <p>
|
||||||
|
* You can increase this value to make it harder to swipe or decrease it to make it easier.
|
||||||
|
* Keep in mind that ItemTouchHelper also checks the perpendicular velocity and makes sure
|
||||||
|
* current direction velocity is larger then the perpendicular one. Otherwise, user's
|
||||||
|
* movement is ambiguous. You can change the threshold by overriding
|
||||||
|
* {@link #getSwipeVelocityThreshold(float)}.
|
||||||
|
* <p>
|
||||||
|
* The velocity is calculated in pixels per second.
|
||||||
|
* <p>
|
||||||
|
* The default framework value is passed as a parameter so that you can modify it with a
|
||||||
|
* multiplier.
|
||||||
|
*
|
||||||
|
* @param defaultValue The default value (in pixels per second) used by the
|
||||||
|
* ItemTouchHelper.
|
||||||
|
* @return The minimum swipe velocity. The default implementation returns the
|
||||||
|
* <code>defaultValue</code> parameter.
|
||||||
|
* @see #getSwipeVelocityThreshold(float)
|
||||||
|
* @see #getSwipeThreshold(ViewHolder)
|
||||||
|
*/
|
||||||
|
public float getSwipeEscapeVelocity(float defaultValue) {
|
||||||
|
return defaultValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defines the maximum velocity ItemTouchHelper will ever calculate for pointer movements.
|
||||||
|
* <p>
|
||||||
|
* To consider a movement as swipe, ItemTouchHelper requires it to be larger than the
|
||||||
|
* perpendicular movement. If both directions reach to the max threshold, none of them will
|
||||||
|
* be considered as a swipe because it is usually an indication that user rather tried to
|
||||||
|
* scroll then swipe.
|
||||||
|
* <p>
|
||||||
|
* The velocity is calculated in pixels per second.
|
||||||
|
* <p>
|
||||||
|
* You can customize this behavior by changing this method. If you increase the value, it
|
||||||
|
* will be easier for the user to swipe diagonally and if you decrease the value, user will
|
||||||
|
* need to make a rather straight finger movement to trigger a swipe.
|
||||||
|
*
|
||||||
|
* @param defaultValue The default value(in pixels per second) used by the ItemTouchHelper.
|
||||||
|
* @return The velocity cap for pointer movements. The default implementation returns the
|
||||||
|
* <code>defaultValue</code> parameter.
|
||||||
|
* @see #getSwipeEscapeVelocity(float)
|
||||||
|
*/
|
||||||
|
public float getSwipeVelocityThreshold(float defaultValue) {
|
||||||
|
return defaultValue;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called by ItemTouchHelper to select a drop target from the list of ViewHolders that
|
* Called by ItemTouchHelper to select a drop target from the list of ViewHolders that
|
||||||
* are under the dragged View.
|
* are under the dragged View.
|
||||||
|
@ -1779,7 +1855,6 @@ public class ItemTouchHelper extends RecyclerView.ItemDecoration
|
||||||
* @param actionState One of {@link ItemTouchHelper#ACTION_STATE_IDLE},
|
* @param actionState One of {@link ItemTouchHelper#ACTION_STATE_IDLE},
|
||||||
* {@link ItemTouchHelper#ACTION_STATE_SWIPE} or
|
* {@link ItemTouchHelper#ACTION_STATE_SWIPE} or
|
||||||
* {@link ItemTouchHelper#ACTION_STATE_DRAG}.
|
* {@link ItemTouchHelper#ACTION_STATE_DRAG}.
|
||||||
*
|
|
||||||
* @see #clearView(RecyclerView, RecyclerView.ViewHolder)
|
* @see #clearView(RecyclerView, RecyclerView.ViewHolder)
|
||||||
*/
|
*/
|
||||||
public void onSelectedChanged(ViewHolder viewHolder, int actionState) {
|
public void onSelectedChanged(ViewHolder viewHolder, int actionState) {
|
||||||
|
@ -1902,7 +1977,6 @@ public class ItemTouchHelper extends RecyclerView.ItemDecoration
|
||||||
final RecoverAnimation anim = recoverAnimationList.get(i);
|
final RecoverAnimation anim = recoverAnimationList.get(i);
|
||||||
if (anim.mEnded && !anim.mIsPendingCleanup) {
|
if (anim.mEnded && !anim.mIsPendingCleanup) {
|
||||||
recoverAnimationList.remove(i);
|
recoverAnimationList.remove(i);
|
||||||
anim.mViewHolder.setIsRecyclable(true);
|
|
||||||
} else if (!anim.mEnded) {
|
} else if (!anim.mEnded) {
|
||||||
hasRunningAnimation = true;
|
hasRunningAnimation = true;
|
||||||
}
|
}
|
||||||
|
@ -2038,15 +2112,14 @@ public class ItemTouchHelper extends RecyclerView.ItemDecoration
|
||||||
* the faster the list will scroll. Similarly, the larger portion of the View is out of
|
* the faster the list will scroll. Similarly, the larger portion of the View is out of
|
||||||
* bounds, the faster the RecyclerView will scroll.
|
* bounds, the faster the RecyclerView will scroll.
|
||||||
*
|
*
|
||||||
* @param recyclerView The RecyclerView instance to which ItemTouchHelper is attached
|
* @param recyclerView The RecyclerView instance to which ItemTouchHelper is
|
||||||
* to.
|
* attached to.
|
||||||
* @param viewSize The total size of the View in scroll direction, excluding
|
* @param viewSize The total size of the View in scroll direction, excluding
|
||||||
* item decorations.
|
* item decorations.
|
||||||
* @param viewSizeOutOfBounds The total size of the View that is out of bounds. This value
|
* @param viewSizeOutOfBounds The total size of the View that is out of bounds. This value
|
||||||
* is negative if the View is dragged towards left or top edge.
|
* is negative if the View is dragged towards left or top edge.
|
||||||
* @param totalSize The total size of RecyclerView in the scroll direction.
|
* @param totalSize The total size of RecyclerView in the scroll direction.
|
||||||
* @param msSinceStartScroll The time passed since View is kept out of bounds.
|
* @param msSinceStartScroll The time passed since View is kept out of bounds.
|
||||||
*
|
|
||||||
* @return The amount that RecyclerView should scroll. Keep in mind that this value will
|
* @return The amount that RecyclerView should scroll. Keep in mind that this value will
|
||||||
* be passed to {@link RecyclerView#scrollBy(int, int)} method.
|
* be passed to {@link RecyclerView#scrollBy(int, int)} method.
|
||||||
*/
|
*/
|
||||||
|
@ -2314,6 +2387,9 @@ public class ItemTouchHelper extends RecyclerView.ItemDecoration
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onAnimationEnd(ValueAnimatorCompat animation) {
|
public void onAnimationEnd(ValueAnimatorCompat animation) {
|
||||||
|
if (!mEnded) {
|
||||||
|
mViewHolder.setIsRecyclable(true);
|
||||||
|
}
|
||||||
mEnded = true;
|
mEnded = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,16 +21,16 @@ import android.support.v4.view.ViewCompat;
|
||||||
import org.telegram.messenger.support.widget.RecyclerView;
|
import org.telegram.messenger.support.widget.RecyclerView;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Package private class to keep implementations. Putting them inside ItemTouchUIUtil makes them
|
* Package private class to keep implementations. Putting them inside ItemTouchUIUtil makes them
|
||||||
* public API, which is not desired in this case.
|
* public API, which is not desired in this case.
|
||||||
*/
|
*/
|
||||||
class ItemTouchUIUtilImpl {
|
class ItemTouchUIUtilImpl {
|
||||||
|
|
||||||
static class Lollipop extends Honeycomb {
|
static class Lollipop extends Honeycomb {
|
||||||
@Override
|
@Override
|
||||||
public void onDraw(Canvas c, RecyclerView recyclerView, View view,
|
public void onDraw(Canvas c, RecyclerView recyclerView, View view,
|
||||||
float dX, float dY, int actionState, boolean isCurrentlyActive) {
|
float dX, float dY, int actionState, boolean isCurrentlyActive) {
|
||||||
if (isCurrentlyActive) {
|
if (isCurrentlyActive) {
|
||||||
Object originalElevation = view.getTag();
|
Object originalElevation = view.getTag();
|
||||||
if (originalElevation == null) {
|
if (originalElevation == null) {
|
||||||
|
@ -85,14 +85,14 @@ class ItemTouchUIUtilImpl {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDraw(Canvas c, RecyclerView recyclerView, View view,
|
public void onDraw(Canvas c, RecyclerView recyclerView, View view,
|
||||||
float dX, float dY, int actionState, boolean isCurrentlyActive) {
|
float dX, float dY, int actionState, boolean isCurrentlyActive) {
|
||||||
ViewCompat.setTranslationX(view, dX);
|
ViewCompat.setTranslationX(view, dX);
|
||||||
ViewCompat.setTranslationY(view, dY);
|
ViewCompat.setTranslationY(view, dY);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDrawOver(Canvas c, RecyclerView recyclerView,
|
public void onDrawOver(Canvas c, RecyclerView recyclerView,
|
||||||
View view, float dX, float dY, int actionState, boolean isCurrentlyActive) {
|
View view, float dX, float dY, int actionState, boolean isCurrentlyActive) {
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -100,7 +100,7 @@ class ItemTouchUIUtilImpl {
|
||||||
static class Gingerbread implements ItemTouchUIUtil {
|
static class Gingerbread implements ItemTouchUIUtil {
|
||||||
|
|
||||||
private void draw(Canvas c, RecyclerView parent, View view,
|
private void draw(Canvas c, RecyclerView parent, View view,
|
||||||
float dX, float dY) {
|
float dX, float dY) {
|
||||||
c.save();
|
c.save();
|
||||||
c.translate(dX, dY);
|
c.translate(dX, dY);
|
||||||
parent.drawChild(c, view, 0);
|
parent.drawChild(c, view, 0);
|
||||||
|
@ -119,7 +119,7 @@ class ItemTouchUIUtilImpl {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDraw(Canvas c, RecyclerView recyclerView, View view,
|
public void onDraw(Canvas c, RecyclerView recyclerView, View view,
|
||||||
float dX, float dY, int actionState, boolean isCurrentlyActive) {
|
float dX, float dY, int actionState, boolean isCurrentlyActive) {
|
||||||
if (actionState != ItemTouchHelper.ACTION_STATE_DRAG) {
|
if (actionState != ItemTouchHelper.ACTION_STATE_DRAG) {
|
||||||
draw(c, recyclerView, view, dX, dY);
|
draw(c, recyclerView, view, dX, dY);
|
||||||
}
|
}
|
||||||
|
@ -127,8 +127,8 @@ class ItemTouchUIUtilImpl {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDrawOver(Canvas c, RecyclerView recyclerView,
|
public void onDrawOver(Canvas c, RecyclerView recyclerView,
|
||||||
View view, float dX, float dY,
|
View view, float dX, float dY,
|
||||||
int actionState, boolean isCurrentlyActive) {
|
int actionState, boolean isCurrentlyActive) {
|
||||||
if (actionState == ItemTouchHelper.ACTION_STATE_DRAG) {
|
if (actionState == ItemTouchHelper.ACTION_STATE_DRAG) {
|
||||||
draw(c, recyclerView, view, dX, dY);
|
draw(c, recyclerView, view, dX, dY);
|
||||||
}
|
}
|
||||||
|
|
|
@ -67,8 +67,9 @@ public class Track {
|
||||||
samplingFrequencyIndexMap.put(8000, 0xb);
|
samplingFrequencyIndexMap.put(8000, 0xb);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Track(int id, MediaFormat format, boolean isAudio) throws Exception {
|
public Track(int id, MediaFormat format, boolean audio) throws Exception {
|
||||||
trackId = id;
|
trackId = id;
|
||||||
|
isAudio = audio;
|
||||||
if (!isAudio) {
|
if (!isAudio) {
|
||||||
sampleDurations.add((long) 3015);
|
sampleDurations.add((long) 3015);
|
||||||
duration = 3015;
|
duration = 3015;
|
||||||
|
@ -136,7 +137,6 @@ public class Track {
|
||||||
} else {
|
} else {
|
||||||
sampleDurations.add((long) 1024);
|
sampleDurations.add((long) 1024);
|
||||||
duration = 1024;
|
duration = 1024;
|
||||||
isAudio = true;
|
|
||||||
volume = 1;
|
volume = 1;
|
||||||
timeScale = format.getInteger(MediaFormat.KEY_SAMPLE_RATE);
|
timeScale = format.getInteger(MediaFormat.KEY_SAMPLE_RATE);
|
||||||
handler = "soun";
|
handler = "soun";
|
||||||
|
@ -184,15 +184,18 @@ public class Track {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addSample(long offset, MediaCodec.BufferInfo bufferInfo) {
|
public void addSample(long offset, MediaCodec.BufferInfo bufferInfo) {
|
||||||
|
long delta = bufferInfo.presentationTimeUs - lastPresentationTimeUs;
|
||||||
|
if (delta < 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
boolean isSyncFrame = !isAudio && (bufferInfo.flags & MediaCodec.BUFFER_FLAG_SYNC_FRAME) != 0;
|
boolean isSyncFrame = !isAudio && (bufferInfo.flags & MediaCodec.BUFFER_FLAG_SYNC_FRAME) != 0;
|
||||||
samples.add(new Sample(offset, bufferInfo.size));
|
samples.add(new Sample(offset, bufferInfo.size));
|
||||||
if (syncSamples != null && isSyncFrame) {
|
if (syncSamples != null && isSyncFrame) {
|
||||||
syncSamples.add(samples.size());
|
syncSamples.add(samples.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
long delta = bufferInfo.presentationTimeUs - lastPresentationTimeUs;
|
|
||||||
lastPresentationTimeUs = bufferInfo.presentationTimeUs;
|
|
||||||
delta = (delta * timeScale + 500000L) / 1000000L;
|
delta = (delta * timeScale + 500000L) / 1000000L;
|
||||||
|
lastPresentationTimeUs = bufferInfo.presentationTimeUs;
|
||||||
if (!first) {
|
if (!first) {
|
||||||
sampleDurations.add(sampleDurations.size() - 1, delta);
|
sampleDurations.add(sampleDurations.size() - 1, delta);
|
||||||
duration += delta;
|
duration += delta;
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -443,11 +443,6 @@ public class ActionBarLayout extends FrameLayout {
|
||||||
public void onAnimationEnd(Object animator) {
|
public void onAnimationEnd(Object animator) {
|
||||||
onSlideAnimationEnd(backAnimation);
|
onSlideAnimationEnd(backAnimation);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onAnimationCancel(Object animator) {
|
|
||||||
onSlideAnimationEnd(backAnimation);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
animatorSet.start();
|
animatorSet.start();
|
||||||
animationInProgress = true;
|
animationInProgress = true;
|
||||||
|
@ -693,11 +688,6 @@ public class ActionBarLayout extends FrameLayout {
|
||||||
public void onAnimationEnd(Object animation) {
|
public void onAnimationEnd(Object animation) {
|
||||||
onAnimationEndCheck(false);
|
onAnimationEndCheck(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onAnimationCancel(Object animation) {
|
|
||||||
onAnimationEndCheck(false);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
currentAnimation.start();
|
currentAnimation.start();
|
||||||
} else {
|
} else {
|
||||||
|
@ -927,11 +917,6 @@ public class ActionBarLayout extends FrameLayout {
|
||||||
public void onAnimationEnd(Object animation) {
|
public void onAnimationEnd(Object animation) {
|
||||||
onAnimationEndCheck(false);
|
onAnimationEndCheck(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onAnimationCancel(Object animation) {
|
|
||||||
onAnimationEndCheck(false);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
currentAnimation.start();
|
currentAnimation.start();
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -610,11 +610,6 @@ public class BottomSheet extends Dialog {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onAnimationCancel(Animator animation) {
|
|
||||||
onAnimationEnd(animation);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
animatorSet.start();
|
animatorSet.start();
|
||||||
}
|
}
|
||||||
|
@ -706,11 +701,6 @@ public class BottomSheet extends Dialog {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onAnimationCancel(Object animation) {
|
|
||||||
onAnimationEnd(animation);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
animatorSetProxy.start();
|
animatorSetProxy.start();
|
||||||
}
|
}
|
||||||
|
@ -745,11 +735,6 @@ public class BottomSheet extends Dialog {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onAnimationCancel(Object animation) {
|
|
||||||
onAnimationEnd(animation);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
animatorSetProxy.start();
|
animatorSetProxy.start();
|
||||||
}
|
}
|
||||||
|
|
|
@ -187,11 +187,6 @@ public class DrawerLayoutContainer extends FrameLayout {
|
||||||
public void onAnimationEnd(Object animator) {
|
public void onAnimationEnd(Object animator) {
|
||||||
onDrawerAnimationEnd(true);
|
onDrawerAnimationEnd(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onAnimationCancel(Object animator) {
|
|
||||||
onDrawerAnimationEnd(true);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
animatorSet.start();
|
animatorSet.start();
|
||||||
currentAnimation = animatorSet;
|
currentAnimation = animatorSet;
|
||||||
|
@ -214,11 +209,6 @@ public class DrawerLayoutContainer extends FrameLayout {
|
||||||
public void onAnimationEnd(Object animator) {
|
public void onAnimationEnd(Object animator) {
|
||||||
onDrawerAnimationEnd(false);
|
onDrawerAnimationEnd(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onAnimationCancel(Object animator) {
|
|
||||||
onDrawerAnimationEnd(false);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
animatorSet.start();
|
animatorSet.start();
|
||||||
}
|
}
|
||||||
|
|
|
@ -238,7 +238,7 @@ public class ContactsAdapter extends BaseSectionsAdapter {
|
||||||
}
|
}
|
||||||
} else if (type == 0) {
|
} else if (type == 0) {
|
||||||
if (convertView == null) {
|
if (convertView == null) {
|
||||||
convertView = new UserCell(mContext, 58, 1);
|
convertView = new UserCell(mContext, 58, 1, false);
|
||||||
((UserCell) convertView).setStatusColors(0xffa8a8a8, 0xff3b84c0);
|
((UserCell) convertView).setStatusColors(0xffa8a8a8, 0xff3b84c0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -94,6 +94,7 @@ public class DialogsAdapter extends RecyclerView.Adapter {
|
||||||
} else if (viewType == 1) {
|
} else if (viewType == 1) {
|
||||||
view = new LoadingCell(mContext);
|
view = new LoadingCell(mContext);
|
||||||
}
|
}
|
||||||
|
view.setLayoutParams(new RecyclerView.LayoutParams(RecyclerView.LayoutParams.MATCH_PARENT, RecyclerView.LayoutParams.WRAP_CONTENT));
|
||||||
return new Holder(view);
|
return new Holder(view);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -885,6 +885,7 @@ public class DialogsSearchAdapter extends BaseSearchAdapterRecycler {
|
||||||
view = new HashtagSearchCell(mContext);
|
view = new HashtagSearchCell(mContext);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
view.setLayoutParams(new RecyclerView.LayoutParams(RecyclerView.LayoutParams.MATCH_PARENT, RecyclerView.LayoutParams.WRAP_CONTENT));
|
||||||
return new Holder(view);
|
return new Holder(view);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -419,6 +419,7 @@ public class MentionsAdapter extends BaseSearchAdapterRecycler {
|
||||||
boolean added = false;
|
boolean added = false;
|
||||||
if (searchResultBotContext == null || offset.length() == 0) {
|
if (searchResultBotContext == null || offset.length() == 0) {
|
||||||
searchResultBotContext = res.results;
|
searchResultBotContext = res.results;
|
||||||
|
contextMedia = res.gallery;
|
||||||
} else {
|
} else {
|
||||||
added = true;
|
added = true;
|
||||||
searchResultBotContext.addAll(res.results);
|
searchResultBotContext.addAll(res.results);
|
||||||
|
@ -426,7 +427,6 @@ public class MentionsAdapter extends BaseSearchAdapterRecycler {
|
||||||
nextQueryOffset = "";
|
nextQueryOffset = "";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
contextMedia = res.gallery;
|
|
||||||
searchResultHashtags = null;
|
searchResultHashtags = null;
|
||||||
searchResultUsernames = null;
|
searchResultUsernames = null;
|
||||||
searchResultCommands = null;
|
searchResultCommands = null;
|
||||||
|
|
|
@ -238,7 +238,7 @@ public class SearchAdapter extends BaseSearchAdapter {
|
||||||
} else {
|
} else {
|
||||||
if (view == null) {
|
if (view == null) {
|
||||||
if (useUserCell) {
|
if (useUserCell) {
|
||||||
view = new UserCell(mContext, 1, 1);
|
view = new UserCell(mContext, 1, 1, false);
|
||||||
if (checkedMap != null) {
|
if (checkedMap != null) {
|
||||||
((UserCell) view).setChecked(false, false);
|
((UserCell) view).setChecked(false, false);
|
||||||
}
|
}
|
||||||
|
|
|
@ -263,11 +263,19 @@ public class BlockedUsersActivity extends BaseFragment implements NotificationCe
|
||||||
int type = getItemViewType(i);
|
int type = getItemViewType(i);
|
||||||
if (type == 0) {
|
if (type == 0) {
|
||||||
if (view == null) {
|
if (view == null) {
|
||||||
view = new UserCell(mContext, 1, 0);
|
view = new UserCell(mContext, 1, 0, false);
|
||||||
}
|
}
|
||||||
TLRPC.User user = MessagesController.getInstance().getUser(MessagesController.getInstance().blockedUsers.get(i));
|
TLRPC.User user = MessagesController.getInstance().getUser(MessagesController.getInstance().blockedUsers.get(i));
|
||||||
if (user != null) {
|
if (user != null) {
|
||||||
((UserCell) view).setData(user, null, user.phone != null && user.phone.length() != 0 ? PhoneFormat.getInstance().format("+" + user.phone) : LocaleController.getString("NumberUnknown", R.string.NumberUnknown), 0);
|
String number;
|
||||||
|
if (user.bot) {
|
||||||
|
number = LocaleController.getString("Bot", R.string.Bot).substring(0, 1).toUpperCase() + LocaleController.getString("Bot", R.string.Bot).substring(1);
|
||||||
|
} else if (user.phone != null && user.phone.length() != 0) {
|
||||||
|
number = PhoneFormat.getInstance().format("+" + user.phone);
|
||||||
|
} else {
|
||||||
|
number = LocaleController.getString("NumberUnknown", R.string.NumberUnknown);
|
||||||
|
}
|
||||||
|
((UserCell) view).setData(user, null, number, 0);
|
||||||
}
|
}
|
||||||
} else if (type == 1) {
|
} else if (type == 1) {
|
||||||
if (view == null) {
|
if (view == null) {
|
||||||
|
|
|
@ -413,10 +413,9 @@ public class CacheControlActivity extends BaseFragment {
|
||||||
NativeByteBuffer data = new NativeByteBuffer(cursor2.byteArrayLength(0));
|
NativeByteBuffer data = new NativeByteBuffer(cursor2.byteArrayLength(0));
|
||||||
if (data != null && cursor2.byteBufferValue(0, data) != 0) {
|
if (data != null && cursor2.byteBufferValue(0, data) != 0) {
|
||||||
TLRPC.Message message = TLRPC.Message.TLdeserialize(data, data.readInt32(false), false);
|
TLRPC.Message message = TLRPC.Message.TLdeserialize(data, data.readInt32(false), false);
|
||||||
if (message == null) {
|
if (message != null) {
|
||||||
continue;
|
arrayList.add(message);
|
||||||
}
|
}
|
||||||
arrayList.add(message);
|
|
||||||
}
|
}
|
||||||
data.reuse();
|
data.reuse();
|
||||||
}
|
}
|
||||||
|
|
|
@ -100,12 +100,16 @@ public class BotHelpCell extends View {
|
||||||
MessageObject.addLinks(stringBuilder);
|
MessageObject.addLinks(stringBuilder);
|
||||||
stringBuilder.setSpan(new TypefaceSpan(AndroidUtilities.getTypeface("fonts/rmedium.ttf")), 0, help.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
|
stringBuilder.setSpan(new TypefaceSpan(AndroidUtilities.getTypeface("fonts/rmedium.ttf")), 0, help.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||||
Emoji.replaceEmoji(stringBuilder, textPaint.getFontMetricsInt(), AndroidUtilities.dp(20), false);
|
Emoji.replaceEmoji(stringBuilder, textPaint.getFontMetricsInt(), AndroidUtilities.dp(20), false);
|
||||||
textLayout = new StaticLayout(stringBuilder, textPaint, width, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false);
|
try {
|
||||||
width = 0;
|
textLayout = new StaticLayout(stringBuilder, textPaint, width, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false);
|
||||||
height = textLayout.getHeight() + AndroidUtilities.dp(4 + 18);
|
width = 0;
|
||||||
int count = textLayout.getLineCount();
|
height = textLayout.getHeight() + AndroidUtilities.dp(4 + 18);
|
||||||
for (int a = 0; a < count; a++) {
|
int count = textLayout.getLineCount();
|
||||||
width = (int) Math.ceil(Math.max(width, textLayout.getLineWidth(a) + textLayout.getLineLeft(a)));
|
for (int a = 0; a < count; a++) {
|
||||||
|
width = (int) Math.ceil(Math.max(width, textLayout.getLineWidth(a) + textLayout.getLineLeft(a)));
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
FileLog.e("tmessage", e);
|
||||||
}
|
}
|
||||||
width += AndroidUtilities.dp(4 + 18);
|
width += AndroidUtilities.dp(4 + 18);
|
||||||
}
|
}
|
||||||
|
|
|
@ -57,6 +57,8 @@ public class ChatActionCell extends BaseCell {
|
||||||
private int previousWidth = 0;
|
private int previousWidth = 0;
|
||||||
private boolean imagePressed = false;
|
private boolean imagePressed = false;
|
||||||
|
|
||||||
|
private boolean hasReplyMessage;
|
||||||
|
|
||||||
private MessageObject currentMessageObject;
|
private MessageObject currentMessageObject;
|
||||||
|
|
||||||
private ChatActionCellDelegate delegate;
|
private ChatActionCellDelegate delegate;
|
||||||
|
@ -79,10 +81,11 @@ public class ChatActionCell extends BaseCell {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setMessageObject(MessageObject messageObject) {
|
public void setMessageObject(MessageObject messageObject) {
|
||||||
if (currentMessageObject == messageObject) {
|
if (currentMessageObject == messageObject && (hasReplyMessage || messageObject.replyMessageObject == null)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
currentMessageObject = messageObject;
|
currentMessageObject = messageObject;
|
||||||
|
hasReplyMessage = messageObject.replyMessageObject != null;
|
||||||
previousWidth = 0;
|
previousWidth = 0;
|
||||||
if (currentMessageObject.type == 11) {
|
if (currentMessageObject.type == 11) {
|
||||||
int id = 0;
|
int id = 0;
|
||||||
|
@ -220,8 +223,8 @@ public class ChatActionCell extends BaseCell {
|
||||||
int width = Math.max(AndroidUtilities.dp(30), MeasureSpec.getSize(widthMeasureSpec));
|
int width = Math.max(AndroidUtilities.dp(30), MeasureSpec.getSize(widthMeasureSpec));
|
||||||
if (width != previousWidth) {
|
if (width != previousWidth) {
|
||||||
previousWidth = width;
|
previousWidth = width;
|
||||||
|
int maxWidth = width - AndroidUtilities.dp(30);
|
||||||
textLayout = new StaticLayout(currentMessageObject.messageText, textPaint, width - AndroidUtilities.dp(30), Layout.Alignment.ALIGN_CENTER, 1.0f, 0.0f, false);
|
textLayout = new StaticLayout(currentMessageObject.messageText, textPaint, maxWidth, Layout.Alignment.ALIGN_CENTER, 1.0f, 0.0f, false);
|
||||||
textHeight = 0;
|
textHeight = 0;
|
||||||
textWidth = 0;
|
textWidth = 0;
|
||||||
try {
|
try {
|
||||||
|
@ -230,6 +233,9 @@ public class ChatActionCell extends BaseCell {
|
||||||
float lineWidth;
|
float lineWidth;
|
||||||
try {
|
try {
|
||||||
lineWidth = textLayout.getLineWidth(a);
|
lineWidth = textLayout.getLineWidth(a);
|
||||||
|
if (lineWidth > maxWidth) {
|
||||||
|
lineWidth = maxWidth;
|
||||||
|
}
|
||||||
textHeight = (int)Math.max(textHeight, Math.ceil(textLayout.getLineBottom(a)));
|
textHeight = (int)Math.max(textHeight, Math.ceil(textLayout.getLineBottom(a)));
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
FileLog.e("tmessages", e);
|
FileLog.e("tmessages", e);
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* This is the source code of Telegram for Android v. 1.3.x.
|
* This is the source code of Telegram for Android v. 3.x.x.
|
||||||
* It is licensed under GNU GPL v. 2 or later.
|
* It is licensed under GNU GPL v. 2 or later.
|
||||||
* You should have received a copy of the license in this archive (see LICENSE).
|
* You should have received a copy of the license in this archive (see LICENSE).
|
||||||
*
|
*
|
||||||
|
@ -39,7 +39,6 @@ import org.telegram.messenger.R;
|
||||||
import org.telegram.messenger.MessageObject;
|
import org.telegram.messenger.MessageObject;
|
||||||
import org.telegram.messenger.ImageReceiver;
|
import org.telegram.messenger.ImageReceiver;
|
||||||
import org.telegram.ui.Components.AvatarDrawable;
|
import org.telegram.ui.Components.AvatarDrawable;
|
||||||
import org.telegram.ui.Components.LinkPath;
|
|
||||||
import org.telegram.ui.Components.ResourceLoader;
|
import org.telegram.ui.Components.ResourceLoader;
|
||||||
import org.telegram.ui.Components.StaticLayoutEx;
|
import org.telegram.ui.Components.StaticLayoutEx;
|
||||||
import org.telegram.ui.Components.TypefaceSpan;
|
import org.telegram.ui.Components.TypefaceSpan;
|
||||||
|
@ -52,25 +51,22 @@ public class ChatBaseCell extends BaseCell implements MediaController.FileDownlo
|
||||||
void didPressedChannelAvatar(ChatBaseCell cell, TLRPC.Chat chat, int postId);
|
void didPressedChannelAvatar(ChatBaseCell cell, TLRPC.Chat chat, int postId);
|
||||||
void didPressedCancelSendButton(ChatBaseCell cell);
|
void didPressedCancelSendButton(ChatBaseCell cell);
|
||||||
void didLongPressed(ChatBaseCell cell);
|
void didLongPressed(ChatBaseCell cell);
|
||||||
void didPressReplyMessage(ChatBaseCell cell, int id);
|
void didPressedReplyMessage(ChatBaseCell cell, int id);
|
||||||
void didPressUrl(MessageObject messageObject, ClickableSpan url, boolean longPress);
|
void didPressedUrl(MessageObject messageObject, ClickableSpan url, boolean longPress);
|
||||||
void needOpenWebView(String url, String title, String originalUrl, int w, int h);
|
void needOpenWebView(String url, String title, String originalUrl, int w, int h);
|
||||||
void didClickedImage(ChatBaseCell cell);
|
void didPressedImage(ChatBaseCell cell);
|
||||||
void didPressShare(ChatBaseCell cell);
|
void didPressedShare(ChatBaseCell cell);
|
||||||
|
void didPressedOther(ChatBaseCell cell);
|
||||||
boolean canPerformActions();
|
boolean canPerformActions();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected ClickableSpan pressedLink;
|
|
||||||
protected boolean linkPreviewPressed;
|
|
||||||
protected LinkPath urlPath = new LinkPath();
|
|
||||||
protected static Paint urlPaint;
|
|
||||||
private int TAG;
|
private int TAG;
|
||||||
|
|
||||||
public boolean isChat;
|
public boolean isChat;
|
||||||
protected boolean isPressed;
|
protected boolean isPressed;
|
||||||
protected boolean forwardName;
|
protected boolean forwardName;
|
||||||
protected boolean isHighlighted;
|
protected boolean isHighlighted;
|
||||||
protected boolean media;
|
protected boolean mediaBackground;
|
||||||
protected boolean isCheckPressed = true;
|
protected boolean isCheckPressed = true;
|
||||||
private boolean wasLayout;
|
private boolean wasLayout;
|
||||||
protected boolean isAvatarVisible;
|
protected boolean isAvatarVisible;
|
||||||
|
@ -180,9 +176,6 @@ public class ChatBaseCell extends BaseCell implements MediaController.FileDownlo
|
||||||
replyTextPaint.linkColor = 0xff316f9f;
|
replyTextPaint.linkColor = 0xff316f9f;
|
||||||
|
|
||||||
replyLinePaint = new Paint();
|
replyLinePaint = new Paint();
|
||||||
|
|
||||||
urlPaint = new Paint();
|
|
||||||
urlPaint.setColor(0x33316f9f);
|
|
||||||
}
|
}
|
||||||
avatarImage = new ImageReceiver(this);
|
avatarImage = new ImageReceiver(this);
|
||||||
avatarImage.setRoundRadius(AndroidUtilities.dp(21));
|
avatarImage.setRoundRadius(AndroidUtilities.dp(21));
|
||||||
|
@ -211,14 +204,6 @@ public class ChatBaseCell extends BaseCell implements MediaController.FileDownlo
|
||||||
invalidate();
|
invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void resetPressedLink() {
|
|
||||||
if (pressedLink != null) {
|
|
||||||
pressedLink = null;
|
|
||||||
}
|
|
||||||
linkPreviewPressed = false;
|
|
||||||
invalidate();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setDelegate(ChatBaseCellDelegate delegate) {
|
public void setDelegate(ChatBaseCellDelegate delegate) {
|
||||||
this.delegate = delegate;
|
this.delegate = delegate;
|
||||||
}
|
}
|
||||||
|
@ -487,7 +472,7 @@ public class ChatBaseCell extends BaseCell implements MediaController.FileDownlo
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
nameLayout = new StaticLayout(nameStringFinal, namePaint, nameWidth, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false);
|
nameLayout = new StaticLayout(nameStringFinal, namePaint, nameWidth + AndroidUtilities.dp(2), Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false);
|
||||||
if (nameLayout != null && nameLayout.getLineCount() > 0) {
|
if (nameLayout != null && nameLayout.getLineCount() > 0) {
|
||||||
nameWidth = (int)Math.ceil(nameLayout.getLineWidth(0));
|
nameWidth = (int)Math.ceil(nameLayout.getLineWidth(0));
|
||||||
namesOffset += AndroidUtilities.dp(19);
|
namesOffset += AndroidUtilities.dp(19);
|
||||||
|
@ -557,7 +542,7 @@ public class ChatBaseCell extends BaseCell implements MediaController.FileDownlo
|
||||||
namesOffset += AndroidUtilities.dp(42);
|
namesOffset += AndroidUtilities.dp(42);
|
||||||
if (messageObject.contentType == 2 || messageObject.contentType == 3) {
|
if (messageObject.contentType == 2 || messageObject.contentType == 3) {
|
||||||
namesOffset += AndroidUtilities.dp(4);
|
namesOffset += AndroidUtilities.dp(4);
|
||||||
} else if (messageObject.contentType == 1) {
|
} else if (messageObject.type != 0) {
|
||||||
if (messageObject.type == 13) {
|
if (messageObject.type == 13) {
|
||||||
namesOffset -= AndroidUtilities.dp(42);
|
namesOffset -= AndroidUtilities.dp(42);
|
||||||
} else {
|
} else {
|
||||||
|
@ -590,7 +575,7 @@ public class ChatBaseCell extends BaseCell implements MediaController.FileDownlo
|
||||||
} else {
|
} else {
|
||||||
maxWidth = getMaxNameWidth() - AndroidUtilities.dp(22);
|
maxWidth = getMaxNameWidth() - AndroidUtilities.dp(22);
|
||||||
}
|
}
|
||||||
if (!media && messageObject.contentType != 0) {
|
if (!mediaBackground) {
|
||||||
maxWidth -= AndroidUtilities.dp(8);
|
maxWidth -= AndroidUtilities.dp(8);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -772,7 +757,7 @@ public class ChatBaseCell extends BaseCell implements MediaController.FileDownlo
|
||||||
replyPressed = false;
|
replyPressed = false;
|
||||||
playSoundEffect(SoundEffectConstants.CLICK);
|
playSoundEffect(SoundEffectConstants.CLICK);
|
||||||
if (delegate != null) {
|
if (delegate != null) {
|
||||||
delegate.didPressReplyMessage(this, currentMessageObject.messageOwner.reply_to_msg_id);
|
delegate.didPressedReplyMessage(this, currentMessageObject.messageOwner.reply_to_msg_id);
|
||||||
}
|
}
|
||||||
} else if (event.getAction() == MotionEvent.ACTION_CANCEL) {
|
} else if (event.getAction() == MotionEvent.ACTION_CANCEL) {
|
||||||
replyPressed = false;
|
replyPressed = false;
|
||||||
|
@ -786,7 +771,7 @@ public class ChatBaseCell extends BaseCell implements MediaController.FileDownlo
|
||||||
sharePressed = false;
|
sharePressed = false;
|
||||||
playSoundEffect(SoundEffectConstants.CLICK);
|
playSoundEffect(SoundEffectConstants.CLICK);
|
||||||
if (delegate != null) {
|
if (delegate != null) {
|
||||||
delegate.didPressShare(this);
|
delegate.didPressedShare(this);
|
||||||
}
|
}
|
||||||
} else if (event.getAction() == MotionEvent.ACTION_CANCEL) {
|
} else if (event.getAction() == MotionEvent.ACTION_CANCEL) {
|
||||||
sharePressed = false;
|
sharePressed = false;
|
||||||
|
@ -812,9 +797,11 @@ public class ChatBaseCell extends BaseCell implements MediaController.FileDownlo
|
||||||
if (changed || !wasLayout) {
|
if (changed || !wasLayout) {
|
||||||
layoutWidth = getMeasuredWidth();
|
layoutWidth = getMeasuredWidth();
|
||||||
layoutHeight = getMeasuredHeight();
|
layoutHeight = getMeasuredHeight();
|
||||||
|
if (timeTextWidth < 0) {
|
||||||
|
timeTextWidth = AndroidUtilities.dp(10);
|
||||||
|
}
|
||||||
timeLayout = new StaticLayout(currentTimeString, timePaint, timeTextWidth, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false);
|
timeLayout = new StaticLayout(currentTimeString, timePaint, timeTextWidth, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false);
|
||||||
if (!media) {
|
if (!mediaBackground) {
|
||||||
if (!currentMessageObject.isOutOwner()) {
|
if (!currentMessageObject.isOutOwner()) {
|
||||||
timeX = backgroundWidth - AndroidUtilities.dp(9) - timeWidth + (isChat && currentMessageObject.isFromUser() ? AndroidUtilities.dp(52) : 0);
|
timeX = backgroundWidth - AndroidUtilities.dp(9) - timeWidth + (isChat && currentMessageObject.isFromUser() ? AndroidUtilities.dp(52) : 0);
|
||||||
} else {
|
} else {
|
||||||
|
@ -876,7 +863,7 @@ public class ChatBaseCell extends BaseCell implements MediaController.FileDownlo
|
||||||
avatarImage.draw(canvas);
|
avatarImage.draw(canvas);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (media) {
|
if (mediaBackground) {
|
||||||
timePaint.setColor(0xffffffff);
|
timePaint.setColor(0xffffffff);
|
||||||
} else {
|
} else {
|
||||||
if (currentMessageObject.isOutOwner()) {
|
if (currentMessageObject.isOutOwner()) {
|
||||||
|
@ -889,37 +876,37 @@ public class ChatBaseCell extends BaseCell implements MediaController.FileDownlo
|
||||||
Drawable currentBackgroundDrawable;
|
Drawable currentBackgroundDrawable;
|
||||||
if (currentMessageObject.isOutOwner()) {
|
if (currentMessageObject.isOutOwner()) {
|
||||||
if (isDrawSelectedBackground()) {
|
if (isDrawSelectedBackground()) {
|
||||||
if (!media) {
|
if (!mediaBackground) {
|
||||||
currentBackgroundDrawable = ResourceLoader.backgroundDrawableOutSelected;
|
currentBackgroundDrawable = ResourceLoader.backgroundDrawableOutSelected;
|
||||||
} else {
|
} else {
|
||||||
currentBackgroundDrawable = ResourceLoader.backgroundMediaDrawableOutSelected;
|
currentBackgroundDrawable = ResourceLoader.backgroundMediaDrawableOutSelected;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (!media) {
|
if (!mediaBackground) {
|
||||||
currentBackgroundDrawable = ResourceLoader.backgroundDrawableOut;
|
currentBackgroundDrawable = ResourceLoader.backgroundDrawableOut;
|
||||||
} else {
|
} else {
|
||||||
currentBackgroundDrawable = ResourceLoader.backgroundMediaDrawableOut;
|
currentBackgroundDrawable = ResourceLoader.backgroundMediaDrawableOut;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
setDrawableBounds(currentBackgroundDrawable, layoutWidth - backgroundWidth - (!media ? 0 : AndroidUtilities.dp(9)), AndroidUtilities.dp(1), backgroundWidth, layoutHeight - AndroidUtilities.dp(2));
|
setDrawableBounds(currentBackgroundDrawable, layoutWidth - backgroundWidth - (!mediaBackground ? 0 : AndroidUtilities.dp(9)), AndroidUtilities.dp(1), backgroundWidth, layoutHeight - AndroidUtilities.dp(2));
|
||||||
} else {
|
} else {
|
||||||
if (isDrawSelectedBackground()) {
|
if (isDrawSelectedBackground()) {
|
||||||
if (!media) {
|
if (!mediaBackground) {
|
||||||
currentBackgroundDrawable = ResourceLoader.backgroundDrawableInSelected;
|
currentBackgroundDrawable = ResourceLoader.backgroundDrawableInSelected;
|
||||||
} else {
|
} else {
|
||||||
currentBackgroundDrawable = ResourceLoader.backgroundMediaDrawableInSelected;
|
currentBackgroundDrawable = ResourceLoader.backgroundMediaDrawableInSelected;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (!media) {
|
if (!mediaBackground) {
|
||||||
currentBackgroundDrawable = ResourceLoader.backgroundDrawableIn;
|
currentBackgroundDrawable = ResourceLoader.backgroundDrawableIn;
|
||||||
} else {
|
} else {
|
||||||
currentBackgroundDrawable = ResourceLoader.backgroundMediaDrawableIn;
|
currentBackgroundDrawable = ResourceLoader.backgroundMediaDrawableIn;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (isChat && currentMessageObject.isFromUser()) {
|
if (isChat && currentMessageObject.isFromUser()) {
|
||||||
setDrawableBounds(currentBackgroundDrawable, AndroidUtilities.dp(52 + (!media ? 0 : 9)), AndroidUtilities.dp(1), backgroundWidth, layoutHeight - AndroidUtilities.dp(2));
|
setDrawableBounds(currentBackgroundDrawable, AndroidUtilities.dp(52 + (!mediaBackground ? 0 : 9)), AndroidUtilities.dp(1), backgroundWidth, layoutHeight - AndroidUtilities.dp(2));
|
||||||
} else {
|
} else {
|
||||||
setDrawableBounds(currentBackgroundDrawable, (!media ? 0 : AndroidUtilities.dp(9)), AndroidUtilities.dp(1), backgroundWidth, layoutHeight - AndroidUtilities.dp(2));
|
setDrawableBounds(currentBackgroundDrawable, (!mediaBackground ? 0 : AndroidUtilities.dp(9)), AndroidUtilities.dp(1), backgroundWidth, layoutHeight - AndroidUtilities.dp(2));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (drawBackground && currentBackgroundDrawable != null) {
|
if (drawBackground && currentBackgroundDrawable != null) {
|
||||||
|
@ -935,7 +922,7 @@ public class ChatBaseCell extends BaseCell implements MediaController.FileDownlo
|
||||||
|
|
||||||
if (drawName && nameLayout != null) {
|
if (drawName && nameLayout != null) {
|
||||||
canvas.save();
|
canvas.save();
|
||||||
if (media || currentMessageObject.isOutOwner()) {
|
if (mediaBackground || currentMessageObject.isOutOwner()) {
|
||||||
canvas.translate(nameX = currentBackgroundDrawable.getBounds().left + AndroidUtilities.dp(10) - nameOffsetX, AndroidUtilities.dp(10));
|
canvas.translate(nameX = currentBackgroundDrawable.getBounds().left + AndroidUtilities.dp(10) - nameOffsetX, AndroidUtilities.dp(10));
|
||||||
} else {
|
} else {
|
||||||
canvas.translate(nameX = currentBackgroundDrawable.getBounds().left + AndroidUtilities.dp(19) - nameOffsetX, AndroidUtilities.dp(10));
|
canvas.translate(nameX = currentBackgroundDrawable.getBounds().left + AndroidUtilities.dp(19) - nameOffsetX, AndroidUtilities.dp(10));
|
||||||
|
@ -962,7 +949,7 @@ public class ChatBaseCell extends BaseCell implements MediaController.FileDownlo
|
||||||
forwardNameX = currentBackgroundDrawable.getBounds().left + AndroidUtilities.dp(10);
|
forwardNameX = currentBackgroundDrawable.getBounds().left + AndroidUtilities.dp(10);
|
||||||
} else {
|
} else {
|
||||||
forwardNamePaint.setColor(0xff006fc8);
|
forwardNamePaint.setColor(0xff006fc8);
|
||||||
if (media) {
|
if (mediaBackground) {
|
||||||
forwardNameX = currentBackgroundDrawable.getBounds().left + AndroidUtilities.dp(10);
|
forwardNameX = currentBackgroundDrawable.getBounds().left + AndroidUtilities.dp(10);
|
||||||
} else {
|
} else {
|
||||||
forwardNameX = currentBackgroundDrawable.getBounds().left + AndroidUtilities.dp(19);
|
forwardNameX = currentBackgroundDrawable.getBounds().left + AndroidUtilities.dp(19);
|
||||||
|
@ -972,10 +959,6 @@ public class ChatBaseCell extends BaseCell implements MediaController.FileDownlo
|
||||||
canvas.translate(forwardNameX - forwardNameOffsetX, forwardNameY);
|
canvas.translate(forwardNameX - forwardNameOffsetX, forwardNameY);
|
||||||
forwardedNameLayout.draw(canvas);
|
forwardedNameLayout.draw(canvas);
|
||||||
canvas.restore();
|
canvas.restore();
|
||||||
|
|
||||||
/*if (viaWidth != 0) {
|
|
||||||
canvas.drawRect(forwardNameX + viaNameWidth, forwardNameY, forwardNameX + viaNameWidth + viaWidth, forwardNameY + AndroidUtilities.dp(32), namePaint);
|
|
||||||
}*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (currentMessageObject.isReply()) {
|
if (currentMessageObject.isReply()) {
|
||||||
|
@ -1018,7 +1001,7 @@ public class ChatBaseCell extends BaseCell implements MediaController.FileDownlo
|
||||||
} else {
|
} else {
|
||||||
replyTextPaint.setColor(0xff999999);
|
replyTextPaint.setColor(0xff999999);
|
||||||
}
|
}
|
||||||
if (currentMessageObject.contentType == 1 && media) {
|
if (mediaBackground) {
|
||||||
replyStartX = currentBackgroundDrawable.getBounds().left + AndroidUtilities.dp(11);
|
replyStartX = currentBackgroundDrawable.getBounds().left + AndroidUtilities.dp(11);
|
||||||
} else {
|
} else {
|
||||||
replyStartX = currentBackgroundDrawable.getBounds().left + AndroidUtilities.dp(20);
|
replyStartX = currentBackgroundDrawable.getBounds().left + AndroidUtilities.dp(20);
|
||||||
|
@ -1045,8 +1028,8 @@ public class ChatBaseCell extends BaseCell implements MediaController.FileDownlo
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (drawTime || !media) {
|
if (drawTime || !mediaBackground) {
|
||||||
if (media) {
|
if (mediaBackground) {
|
||||||
setDrawableBounds(ResourceLoader.mediaBackgroundDrawable, timeX - AndroidUtilities.dp(3), layoutHeight - AndroidUtilities.dp(27.5f), timeWidth + AndroidUtilities.dp(6 + (currentMessageObject.isOutOwner() ? 20 : 0)), AndroidUtilities.dp(16.5f));
|
setDrawableBounds(ResourceLoader.mediaBackgroundDrawable, timeX - AndroidUtilities.dp(3), layoutHeight - AndroidUtilities.dp(27.5f), timeWidth + AndroidUtilities.dp(6 + (currentMessageObject.isOutOwner() ? 20 : 0)), AndroidUtilities.dp(16.5f));
|
||||||
ResourceLoader.mediaBackgroundDrawable.draw(canvas);
|
ResourceLoader.mediaBackgroundDrawable.draw(canvas);
|
||||||
|
|
||||||
|
@ -1152,7 +1135,7 @@ public class ChatBaseCell extends BaseCell implements MediaController.FileDownlo
|
||||||
}
|
}
|
||||||
|
|
||||||
if (drawClock) {
|
if (drawClock) {
|
||||||
if (!media) {
|
if (!mediaBackground) {
|
||||||
setDrawableBounds(ResourceLoader.clockDrawable, layoutWidth - AndroidUtilities.dp(18.5f) - ResourceLoader.clockDrawable.getIntrinsicWidth(), layoutHeight - AndroidUtilities.dp(8.5f) - ResourceLoader.clockDrawable.getIntrinsicHeight());
|
setDrawableBounds(ResourceLoader.clockDrawable, layoutWidth - AndroidUtilities.dp(18.5f) - ResourceLoader.clockDrawable.getIntrinsicWidth(), layoutHeight - AndroidUtilities.dp(8.5f) - ResourceLoader.clockDrawable.getIntrinsicHeight());
|
||||||
ResourceLoader.clockDrawable.draw(canvas);
|
ResourceLoader.clockDrawable.draw(canvas);
|
||||||
} else {
|
} else {
|
||||||
|
@ -1162,7 +1145,7 @@ public class ChatBaseCell extends BaseCell implements MediaController.FileDownlo
|
||||||
}
|
}
|
||||||
if (isBroadcast) {
|
if (isBroadcast) {
|
||||||
if (drawCheck1 || drawCheck2) {
|
if (drawCheck1 || drawCheck2) {
|
||||||
if (!media) {
|
if (!mediaBackground) {
|
||||||
setDrawableBounds(ResourceLoader.broadcastDrawable, layoutWidth - AndroidUtilities.dp(20.5f) - ResourceLoader.broadcastDrawable.getIntrinsicWidth(), layoutHeight - AndroidUtilities.dp(8.0f) - ResourceLoader.broadcastDrawable.getIntrinsicHeight());
|
setDrawableBounds(ResourceLoader.broadcastDrawable, layoutWidth - AndroidUtilities.dp(20.5f) - ResourceLoader.broadcastDrawable.getIntrinsicWidth(), layoutHeight - AndroidUtilities.dp(8.0f) - ResourceLoader.broadcastDrawable.getIntrinsicHeight());
|
||||||
ResourceLoader.broadcastDrawable.draw(canvas);
|
ResourceLoader.broadcastDrawable.draw(canvas);
|
||||||
} else {
|
} else {
|
||||||
|
@ -1172,7 +1155,7 @@ public class ChatBaseCell extends BaseCell implements MediaController.FileDownlo
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (drawCheck2) {
|
if (drawCheck2) {
|
||||||
if (!media) {
|
if (!mediaBackground) {
|
||||||
if (drawCheck1) {
|
if (drawCheck1) {
|
||||||
setDrawableBounds(ResourceLoader.checkDrawable, layoutWidth - AndroidUtilities.dp(22.5f) - ResourceLoader.checkDrawable.getIntrinsicWidth(), layoutHeight - AndroidUtilities.dp(8.0f) - ResourceLoader.checkDrawable.getIntrinsicHeight());
|
setDrawableBounds(ResourceLoader.checkDrawable, layoutWidth - AndroidUtilities.dp(22.5f) - ResourceLoader.checkDrawable.getIntrinsicWidth(), layoutHeight - AndroidUtilities.dp(8.0f) - ResourceLoader.checkDrawable.getIntrinsicHeight());
|
||||||
} else {
|
} else {
|
||||||
|
@ -1189,7 +1172,7 @@ public class ChatBaseCell extends BaseCell implements MediaController.FileDownlo
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (drawCheck1) {
|
if (drawCheck1) {
|
||||||
if (!media) {
|
if (!mediaBackground) {
|
||||||
setDrawableBounds(ResourceLoader.halfCheckDrawable, layoutWidth - AndroidUtilities.dp(18) - ResourceLoader.halfCheckDrawable.getIntrinsicWidth(), layoutHeight - AndroidUtilities.dp(8.0f) - ResourceLoader.halfCheckDrawable.getIntrinsicHeight());
|
setDrawableBounds(ResourceLoader.halfCheckDrawable, layoutWidth - AndroidUtilities.dp(18) - ResourceLoader.halfCheckDrawable.getIntrinsicWidth(), layoutHeight - AndroidUtilities.dp(8.0f) - ResourceLoader.halfCheckDrawable.getIntrinsicHeight());
|
||||||
ResourceLoader.halfCheckDrawable.draw(canvas);
|
ResourceLoader.halfCheckDrawable.draw(canvas);
|
||||||
} else {
|
} else {
|
||||||
|
@ -1199,7 +1182,7 @@ public class ChatBaseCell extends BaseCell implements MediaController.FileDownlo
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (drawError) {
|
if (drawError) {
|
||||||
if (!media) {
|
if (!mediaBackground) {
|
||||||
setDrawableBounds(ResourceLoader.errorDrawable, layoutWidth - AndroidUtilities.dp(18) - ResourceLoader.errorDrawable.getIntrinsicWidth(), layoutHeight - AndroidUtilities.dp(6.5f) - ResourceLoader.errorDrawable.getIntrinsicHeight());
|
setDrawableBounds(ResourceLoader.errorDrawable, layoutWidth - AndroidUtilities.dp(18) - ResourceLoader.errorDrawable.getIntrinsicWidth(), layoutHeight - AndroidUtilities.dp(6.5f) - ResourceLoader.errorDrawable.getIntrinsicHeight());
|
||||||
ResourceLoader.errorDrawable.draw(canvas);
|
ResourceLoader.errorDrawable.draw(canvas);
|
||||||
} else {
|
} else {
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -17,6 +17,7 @@ import android.graphics.drawable.BitmapDrawable;
|
||||||
import android.graphics.drawable.ColorDrawable;
|
import android.graphics.drawable.ColorDrawable;
|
||||||
import android.graphics.drawable.Drawable;
|
import android.graphics.drawable.Drawable;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
|
import android.text.TextUtils;
|
||||||
import android.util.TypedValue;
|
import android.util.TypedValue;
|
||||||
import android.view.Gravity;
|
import android.view.Gravity;
|
||||||
import android.widget.FrameLayout;
|
import android.widget.FrameLayout;
|
||||||
|
@ -66,6 +67,7 @@ public class DrawerProfileCell extends FrameLayout {
|
||||||
nameTextView.setMaxLines(1);
|
nameTextView.setMaxLines(1);
|
||||||
nameTextView.setSingleLine(true);
|
nameTextView.setSingleLine(true);
|
||||||
nameTextView.setGravity(Gravity.LEFT);
|
nameTextView.setGravity(Gravity.LEFT);
|
||||||
|
nameTextView.setEllipsize(TextUtils.TruncateAt.END);
|
||||||
addView(nameTextView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.LEFT | Gravity.BOTTOM, 16, 0, 16, 28));
|
addView(nameTextView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.LEFT | Gravity.BOTTOM, 16, 0, 16, 28));
|
||||||
|
|
||||||
phoneTextView = new TextView(context);
|
phoneTextView = new TextView(context);
|
||||||
|
|
|
@ -16,13 +16,19 @@ import org.telegram.messenger.R;
|
||||||
|
|
||||||
public class ShadowSectionCell extends View {
|
public class ShadowSectionCell extends View {
|
||||||
|
|
||||||
|
private int size = 12;
|
||||||
|
|
||||||
public ShadowSectionCell(Context context) {
|
public ShadowSectionCell(Context context) {
|
||||||
super(context);
|
super(context);
|
||||||
setBackgroundResource(R.drawable.greydivider);
|
setBackgroundResource(R.drawable.greydivider);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setSize(int value) {
|
||||||
|
size = value;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
||||||
super.onMeasure(MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(12), MeasureSpec.EXACTLY));
|
super.onMeasure(MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(size), MeasureSpec.EXACTLY));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,7 +38,7 @@ public class TextBlockCell extends FrameLayoutFixed {
|
||||||
textView.setTextColor(0xff212121);
|
textView.setTextColor(0xff212121);
|
||||||
textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16);
|
textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16);
|
||||||
textView.setGravity((LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.CENTER_VERTICAL);
|
textView.setGravity((LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.CENTER_VERTICAL);
|
||||||
addView(textView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.TOP, 17, 8, 17, 8));
|
addView(textView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.TOP, 17, 10, 17, 10));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setTextColor(int color) {
|
public void setTextColor(int color) {
|
||||||
|
|
|
@ -25,6 +25,7 @@ import org.telegram.ui.Components.Switch;
|
||||||
public class TextCheckCell extends FrameLayoutFixed {
|
public class TextCheckCell extends FrameLayoutFixed {
|
||||||
|
|
||||||
private TextView textView;
|
private TextView textView;
|
||||||
|
private TextView valueTextView;
|
||||||
private Switch checkBox;
|
private Switch checkBox;
|
||||||
private static Paint paint;
|
private static Paint paint;
|
||||||
private boolean needDivider;
|
private boolean needDivider;
|
||||||
|
@ -47,6 +48,16 @@ public class TextCheckCell extends FrameLayoutFixed {
|
||||||
textView.setGravity((LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.CENTER_VERTICAL);
|
textView.setGravity((LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.CENTER_VERTICAL);
|
||||||
addView(textView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.TOP, 17, 0, 17, 0));
|
addView(textView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.TOP, 17, 0, 17, 0));
|
||||||
|
|
||||||
|
valueTextView = new TextView(context);
|
||||||
|
valueTextView.setTextColor(0xff8a8a8a);
|
||||||
|
valueTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 13);
|
||||||
|
valueTextView.setGravity(LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT);
|
||||||
|
valueTextView.setLines(1);
|
||||||
|
valueTextView.setMaxLines(1);
|
||||||
|
valueTextView.setSingleLine(true);
|
||||||
|
valueTextView.setPadding(0, 0, 0, 0);
|
||||||
|
addView(valueTextView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.TOP, 17, 35, 17, 0));
|
||||||
|
|
||||||
checkBox = new Switch(context);
|
checkBox = new Switch(context);
|
||||||
checkBox.setDuplicateParentStateEnabled(false);
|
checkBox.setDuplicateParentStateEnabled(false);
|
||||||
checkBox.setFocusable(false);
|
checkBox.setFocusable(false);
|
||||||
|
@ -57,7 +68,7 @@ public class TextCheckCell extends FrameLayoutFixed {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
||||||
super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(48) + (needDivider ? 1 : 0), MeasureSpec.EXACTLY));
|
super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(valueTextView.getVisibility() == VISIBLE ? 64 : 48) + (needDivider ? 1 : 0), MeasureSpec.EXACTLY));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setTextAndCheck(String text, boolean checked, boolean divider) {
|
public void setTextAndCheck(String text, boolean checked, boolean divider) {
|
||||||
|
@ -68,6 +79,28 @@ public class TextCheckCell extends FrameLayoutFixed {
|
||||||
}
|
}
|
||||||
checkBox.setChecked(checked);
|
checkBox.setChecked(checked);
|
||||||
needDivider = divider;
|
needDivider = divider;
|
||||||
|
valueTextView.setVisibility(GONE);
|
||||||
|
LayoutParams layoutParams = (LayoutParams) textView.getLayoutParams();
|
||||||
|
layoutParams.height = LayoutParams.MATCH_PARENT;
|
||||||
|
layoutParams.topMargin = 0;
|
||||||
|
textView.setLayoutParams(layoutParams);
|
||||||
|
setWillNotDraw(!divider);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTextAndValueAndCheck(String text, String value, boolean checked, boolean divider) {
|
||||||
|
textView.setText(text);
|
||||||
|
valueTextView.setText(value);
|
||||||
|
if (Build.VERSION.SDK_INT < 11) {
|
||||||
|
checkBox.resetLayout();
|
||||||
|
checkBox.requestLayout();
|
||||||
|
}
|
||||||
|
checkBox.setChecked(checked);
|
||||||
|
needDivider = divider;
|
||||||
|
valueTextView.setVisibility(VISIBLE);
|
||||||
|
LayoutParams layoutParams = (LayoutParams) textView.getLayoutParams();
|
||||||
|
layoutParams.height = LayoutParams.WRAP_CONTENT;
|
||||||
|
layoutParams.topMargin = AndroidUtilities.dp(10);
|
||||||
|
textView.setLayoutParams(layoutParams);
|
||||||
setWillNotDraw(!divider);
|
setWillNotDraw(!divider);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -87,6 +87,10 @@ public class TextSettingsCell extends FrameLayout {
|
||||||
textView.setTextColor(color);
|
textView.setTextColor(color);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setTextValueColor(int color) {
|
||||||
|
valueTextView.setTextColor(color);
|
||||||
|
}
|
||||||
|
|
||||||
public void setText(String text, boolean divider) {
|
public void setText(String text, boolean divider) {
|
||||||
textView.setText(text);
|
textView.setText(text);
|
||||||
valueTextView.setVisibility(INVISIBLE);
|
valueTextView.setVisibility(INVISIBLE);
|
||||||
|
|
|
@ -37,6 +37,7 @@ public class UserCell extends FrameLayout {
|
||||||
private ImageView imageView;
|
private ImageView imageView;
|
||||||
private CheckBox checkBox;
|
private CheckBox checkBox;
|
||||||
private CheckBoxSquare checkBoxBig;
|
private CheckBoxSquare checkBoxBig;
|
||||||
|
private ImageView adminImage;
|
||||||
|
|
||||||
private AvatarDrawable avatarDrawable;
|
private AvatarDrawable avatarDrawable;
|
||||||
private TLObject currentObject = null;
|
private TLObject currentObject = null;
|
||||||
|
@ -52,7 +53,7 @@ public class UserCell extends FrameLayout {
|
||||||
private int statusColor = 0xffa8a8a8;
|
private int statusColor = 0xffa8a8a8;
|
||||||
private int statusOnlineColor = 0xff3b84c0;
|
private int statusOnlineColor = 0xff3b84c0;
|
||||||
|
|
||||||
public UserCell(Context context, int padding, int checkbox) {
|
public UserCell(Context context, int padding, int checkbox, boolean admin) {
|
||||||
super(context);
|
super(context);
|
||||||
|
|
||||||
avatarDrawable = new AvatarDrawable();
|
avatarDrawable = new AvatarDrawable();
|
||||||
|
@ -65,7 +66,7 @@ public class UserCell extends FrameLayout {
|
||||||
nameTextView.setTextColor(0xff212121);
|
nameTextView.setTextColor(0xff212121);
|
||||||
nameTextView.setTextSize(17);
|
nameTextView.setTextSize(17);
|
||||||
nameTextView.setGravity((LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.TOP);
|
nameTextView.setGravity((LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.TOP);
|
||||||
addView(nameTextView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 20, (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.TOP, LocaleController.isRTL ? 28 : (68 + padding), 11.5f, LocaleController.isRTL ? (68 + padding) : 28, 0));
|
addView(nameTextView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 20, (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.TOP, LocaleController.isRTL ? 28 + (checkbox == 2 ? 18 : 0) : (68 + padding), 11.5f, LocaleController.isRTL ? (68 + padding) : 28 + (checkbox == 2 ? 18 : 0), 0));
|
||||||
|
|
||||||
statusTextView = new SimpleTextView(context);
|
statusTextView = new SimpleTextView(context);
|
||||||
statusTextView.setTextSize(14);
|
statusTextView.setTextSize(14);
|
||||||
|
@ -85,6 +86,20 @@ public class UserCell extends FrameLayout {
|
||||||
checkBox.setVisibility(INVISIBLE);
|
checkBox.setVisibility(INVISIBLE);
|
||||||
addView(checkBox, LayoutHelper.createFrame(22, 22, (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.TOP, LocaleController.isRTL ? 0 : 37 + padding, 38, LocaleController.isRTL ? 37 + padding : 0, 0));
|
addView(checkBox, LayoutHelper.createFrame(22, 22, (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.TOP, LocaleController.isRTL ? 0 : 37 + padding, 38, LocaleController.isRTL ? 37 + padding : 0, 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (admin) {
|
||||||
|
adminImage = new ImageView(context);
|
||||||
|
adminImage.setImageResource(R.drawable.admin_star);
|
||||||
|
addView(adminImage, LayoutHelper.createFrame(16, 16, (LocaleController.isRTL ? Gravity.LEFT : Gravity.RIGHT) | Gravity.TOP, LocaleController.isRTL ? 24 : 0, 13.5f, LocaleController.isRTL ? 0 : 24, 0));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setIsAdmin(boolean value) {
|
||||||
|
if (adminImage == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
adminImage.setVisibility(value ? VISIBLE : GONE);
|
||||||
|
nameTextView.setPadding(LocaleController.isRTL && value ? AndroidUtilities.dp(16) : 0, 0, !LocaleController.isRTL && value ? AndroidUtilities.dp(16) : 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setData(TLObject user, CharSequence name, CharSequence status, int resId) {
|
public void setData(TLObject user, CharSequence name, CharSequence status, int resId) {
|
||||||
|
|
|
@ -166,6 +166,7 @@ public class ChangeNameActivity extends BaseFragment {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
TLRPC.TL_account_updateProfile req = new TLRPC.TL_account_updateProfile();
|
TLRPC.TL_account_updateProfile req = new TLRPC.TL_account_updateProfile();
|
||||||
|
req.flags = 3;
|
||||||
currentUser.first_name = req.first_name = newFirst;
|
currentUser.first_name = req.first_name = newFirst;
|
||||||
currentUser.last_name = req.last_name = newLast;
|
currentUser.last_name = req.last_name = newLast;
|
||||||
TLRPC.User user = MessagesController.getInstance().getUser(UserConfig.getClientUserId());
|
TLRPC.User user = MessagesController.getInstance().getUser(UserConfig.getClientUserId());
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* This is the source code of Telegram for Android v. 2.0.x.
|
* This is the source code of Telegram for Android v. 3.x.x.
|
||||||
* It is licensed under GNU GPL v. 2 or later.
|
* It is licensed under GNU GPL v. 2 or later.
|
||||||
* You should have received a copy of the license in this archive (see LICENSE).
|
* You should have received a copy of the license in this archive (see LICENSE).
|
||||||
*
|
*
|
||||||
|
@ -8,17 +8,25 @@
|
||||||
|
|
||||||
package org.telegram.ui;
|
package org.telegram.ui;
|
||||||
|
|
||||||
|
import android.Manifest;
|
||||||
import android.annotation.SuppressLint;
|
import android.annotation.SuppressLint;
|
||||||
|
import android.app.Activity;
|
||||||
import android.app.AlertDialog;
|
import android.app.AlertDialog;
|
||||||
|
import android.app.Dialog;
|
||||||
import android.app.ProgressDialog;
|
import android.app.ProgressDialog;
|
||||||
import android.content.Context;
|
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.Canvas;
|
||||||
|
import android.graphics.Paint;
|
||||||
|
import android.os.Build;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.telephony.TelephonyManager;
|
import android.telephony.TelephonyManager;
|
||||||
import android.text.Editable;
|
import android.text.Editable;
|
||||||
import android.text.InputFilter;
|
import android.text.InputFilter;
|
||||||
import android.text.InputType;
|
import android.text.InputType;
|
||||||
import android.text.SpannableStringBuilder;
|
|
||||||
import android.text.Spanned;
|
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.text.TextWatcher;
|
import android.text.TextWatcher;
|
||||||
import android.util.TypedValue;
|
import android.util.TypedValue;
|
||||||
|
@ -30,6 +38,7 @@ import android.view.inputmethod.EditorInfo;
|
||||||
import android.widget.AdapterView;
|
import android.widget.AdapterView;
|
||||||
import android.widget.EditText;
|
import android.widget.EditText;
|
||||||
import android.widget.FrameLayout;
|
import android.widget.FrameLayout;
|
||||||
|
import android.widget.ImageView;
|
||||||
import android.widget.LinearLayout;
|
import android.widget.LinearLayout;
|
||||||
import android.widget.ScrollView;
|
import android.widget.ScrollView;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
@ -59,7 +68,6 @@ import org.telegram.messenger.AnimationCompat.ViewProxy;
|
||||||
import org.telegram.ui.Components.HintEditText;
|
import org.telegram.ui.Components.HintEditText;
|
||||||
import org.telegram.ui.Components.LayoutHelper;
|
import org.telegram.ui.Components.LayoutHelper;
|
||||||
import org.telegram.ui.Components.SlideView;
|
import org.telegram.ui.Components.SlideView;
|
||||||
import org.telegram.ui.Components.TypefaceSpan;
|
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
import java.io.BufferedReader;
|
||||||
import java.io.InputStreamReader;
|
import java.io.InputStreamReader;
|
||||||
|
@ -74,17 +82,21 @@ import java.util.TimerTask;
|
||||||
public class ChangePhoneActivity extends BaseFragment {
|
public class ChangePhoneActivity extends BaseFragment {
|
||||||
|
|
||||||
private int currentViewNum = 0;
|
private int currentViewNum = 0;
|
||||||
private SlideView[] views = new SlideView[2];
|
private SlideView[] views = new SlideView[5];
|
||||||
private ProgressDialog progressDialog;
|
private ProgressDialog progressDialog;
|
||||||
|
private Dialog permissionsDialog;
|
||||||
|
private ArrayList<String> permissionsItems = new ArrayList<>();
|
||||||
|
private boolean checkPermissions = true;
|
||||||
|
private View doneButton;
|
||||||
|
|
||||||
private final static int done_button = 1;
|
private final static int done_button = 1;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onFragmentDestroy() {
|
public void onFragmentDestroy() {
|
||||||
super.onFragmentDestroy();
|
super.onFragmentDestroy();
|
||||||
for (SlideView v : views) {
|
for (int a = 0; a < views.length; a++) {
|
||||||
if (v != null) {
|
if (views[a] != null) {
|
||||||
v.onDestroyActivity();
|
views[a].onDestroyActivity();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (progressDialog != null) {
|
if (progressDialog != null) {
|
||||||
|
@ -114,39 +126,25 @@ public class ChangePhoneActivity extends BaseFragment {
|
||||||
});
|
});
|
||||||
|
|
||||||
ActionBarMenu menu = actionBar.createMenu();
|
ActionBarMenu menu = actionBar.createMenu();
|
||||||
menu.addItemWithWidth(done_button, R.drawable.ic_done, AndroidUtilities.dp(56));
|
doneButton = menu.addItemWithWidth(done_button, R.drawable.ic_done, AndroidUtilities.dp(56));
|
||||||
|
|
||||||
fragmentView = new ScrollView(context);
|
fragmentView = new ScrollView(context);
|
||||||
ScrollView scrollView = (ScrollView) fragmentView;
|
ScrollView scrollView = (ScrollView) fragmentView;
|
||||||
scrollView.setFillViewport(true);
|
scrollView.setFillViewport(true);
|
||||||
|
|
||||||
FrameLayout frameLayout = new FrameLayout(context);
|
FrameLayout frameLayout = new FrameLayout(context);
|
||||||
scrollView.addView(frameLayout);
|
scrollView.addView(frameLayout, LayoutHelper.createScroll(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.TOP | Gravity.LEFT));
|
||||||
ScrollView.LayoutParams layoutParams = (ScrollView.LayoutParams) frameLayout.getLayoutParams();
|
|
||||||
layoutParams.width = ScrollView.LayoutParams.MATCH_PARENT;
|
|
||||||
layoutParams.height = ScrollView.LayoutParams.WRAP_CONTENT;
|
|
||||||
layoutParams.gravity = Gravity.TOP | Gravity.LEFT;
|
|
||||||
frameLayout.setLayoutParams(layoutParams);
|
|
||||||
|
|
||||||
views[0] = new PhoneView(context);
|
views[0] = new PhoneView(context);
|
||||||
views[0].setVisibility(View.VISIBLE);
|
views[1] = new LoginActivitySmsView(context, 1);
|
||||||
frameLayout.addView(views[0], LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.TOP | Gravity.LEFT, 16, 30, 16, 0));
|
views[2] = new LoginActivitySmsView(context, 2);
|
||||||
|
views[3] = new LoginActivitySmsView(context, 3);
|
||||||
|
views[4] = new LoginActivitySmsView(context, 4);
|
||||||
|
|
||||||
views[1] = new LoginActivitySmsView(context);
|
for (int a = 0; a < views.length; a++) {
|
||||||
views[1].setVisibility(View.GONE);
|
views[a].setVisibility(a == 0 ? View.VISIBLE : View.GONE);
|
||||||
frameLayout.addView(views[1], LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.TOP | Gravity.LEFT, 16, 30, 16, 0));
|
frameLayout.addView(views[a], LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, a == 0 ? LayoutHelper.WRAP_CONTENT : LayoutHelper.MATCH_PARENT, Gravity.TOP | Gravity.LEFT, AndroidUtilities.isTablet() ? 26 : 18, 30, AndroidUtilities.isTablet() ? 26 : 18, 0));
|
||||||
|
//LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.TOP | Gravity.LEFT, 16, 30, 16, 0)
|
||||||
try {
|
|
||||||
if (views[0] == null || views[1] == null) {
|
|
||||||
FrameLayout parent = (FrameLayout) ((ScrollView) fragmentView).getChildAt(0);
|
|
||||||
for (int a = 0; a < views.length; a++) {
|
|
||||||
if (views[a] == null) {
|
|
||||||
views[a] = (SlideView) parent.getChildAt(a);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
FileLog.e("tmessages", e);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
actionBar.setTitle(views[0].getHeaderName());
|
actionBar.setTitle(views[0].getHeaderName());
|
||||||
|
@ -160,16 +158,34 @@ public class ChangePhoneActivity extends BaseFragment {
|
||||||
AndroidUtilities.requestAdjustResize(getParentActivity(), classGuid);
|
AndroidUtilities.requestAdjustResize(getParentActivity(), classGuid);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onRequestPermissionsResultFragment(int requestCode, String[] permissions, int[] grantResults) {
|
||||||
|
if (requestCode == 6) {
|
||||||
|
checkPermissions = false;
|
||||||
|
if (currentViewNum == 0) {
|
||||||
|
views[currentViewNum].onNextPressed();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onBackPressed() {
|
public boolean onBackPressed() {
|
||||||
if (currentViewNum == 0) {
|
if (currentViewNum == 0) {
|
||||||
for (SlideView v : views) {
|
for (int a = 0; a < views.length; a++) {
|
||||||
if (v != null) {
|
if (views[a] != null) {
|
||||||
v.onDestroyActivity();
|
views[a].onDestroyActivity();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
} else if (currentViewNum == 1) {
|
} else {
|
||||||
|
views[currentViewNum].onBackPressed();
|
||||||
setPage(0, true, null, true);
|
setPage(0, true, null, true);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
@ -217,6 +233,14 @@ public class ChangePhoneActivity extends BaseFragment {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setPage(int page, boolean animated, Bundle params, boolean back) {
|
public void setPage(int page, boolean animated, Bundle params, boolean back) {
|
||||||
|
if (page == 3) {
|
||||||
|
doneButton.setVisibility(View.GONE);
|
||||||
|
} else {
|
||||||
|
if (page == 0) {
|
||||||
|
checkPermissions = true;
|
||||||
|
}
|
||||||
|
doneButton.setVisibility(View.VISIBLE);
|
||||||
|
}
|
||||||
if(android.os.Build.VERSION.SDK_INT > 10) {
|
if(android.os.Build.VERSION.SDK_INT > 10) {
|
||||||
final SlideView outView = views[currentViewNum];
|
final SlideView outView = views[currentViewNum];
|
||||||
final SlideView newView = views[page];
|
final SlideView newView = views[page];
|
||||||
|
@ -257,6 +281,40 @@ public class ChangePhoneActivity extends BaseFragment {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void fillNextCodeParams(Bundle params, TLRPC.TL_auth_sentCode res) {
|
||||||
|
params.putString("phoneHash", res.phone_code_hash);
|
||||||
|
if (res.next_type instanceof TLRPC.TL_auth_codeTypeCall) {
|
||||||
|
params.putInt("nextType", 4);
|
||||||
|
} else if (res.next_type instanceof TLRPC.TL_auth_codeTypeFlashCall) {
|
||||||
|
params.putInt("nextType", 3);
|
||||||
|
} else if (res.next_type instanceof TLRPC.TL_auth_codeTypeSms) {
|
||||||
|
params.putInt("nextType", 2);
|
||||||
|
}
|
||||||
|
if (res.type instanceof TLRPC.TL_auth_sentCodeTypeApp) {
|
||||||
|
params.putInt("type", 1);
|
||||||
|
params.putInt("length", res.type.length);
|
||||||
|
setPage(1, true, params, false);
|
||||||
|
} else {
|
||||||
|
if (res.timeout == 0) {
|
||||||
|
res.timeout = 60;
|
||||||
|
}
|
||||||
|
params.putInt("timeout", res.timeout * 1000);
|
||||||
|
if (res.type instanceof TLRPC.TL_auth_sentCodeTypeCall) {
|
||||||
|
params.putInt("type", 4);
|
||||||
|
params.putInt("length", res.type.length);
|
||||||
|
setPage(4, true, params, false);
|
||||||
|
} else if (res.type instanceof TLRPC.TL_auth_sentCodeTypeFlashCall) {
|
||||||
|
params.putInt("type", 3);
|
||||||
|
params.putString("pattern", res.type.pattern);
|
||||||
|
setPage(3, true, params, false);
|
||||||
|
} else if (res.type instanceof TLRPC.TL_auth_sentCodeTypeSms) {
|
||||||
|
params.putInt("type", 2);
|
||||||
|
params.putInt("length", res.type.length);
|
||||||
|
setPage(2, true, params, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public class PhoneView extends SlideView implements AdapterView.OnItemSelectedListener {
|
public class PhoneView extends SlideView implements AdapterView.OnItemSelectedListener {
|
||||||
|
|
||||||
private EditText codeField;
|
private EditText codeField;
|
||||||
|
@ -287,9 +345,9 @@ public class ChangePhoneActivity extends BaseFragment {
|
||||||
countryButton.setMaxLines(1);
|
countryButton.setMaxLines(1);
|
||||||
countryButton.setSingleLine(true);
|
countryButton.setSingleLine(true);
|
||||||
countryButton.setEllipsize(TextUtils.TruncateAt.END);
|
countryButton.setEllipsize(TextUtils.TruncateAt.END);
|
||||||
countryButton.setGravity(Gravity.LEFT | Gravity.CENTER_HORIZONTAL);
|
countryButton.setGravity((LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.CENTER_HORIZONTAL);
|
||||||
countryButton.setBackgroundResource(R.drawable.spinner_states);
|
countryButton.setBackgroundResource(R.drawable.spinner_states);
|
||||||
addView(countryButton, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 36, 20, 0, 20, 14));
|
addView(countryButton, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 36, 0, 0, 0, 14));
|
||||||
countryButton.setOnClickListener(new OnClickListener() {
|
countryButton.setOnClickListener(new OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onClick(View view) {
|
public void onClick(View view) {
|
||||||
|
@ -315,7 +373,7 @@ public class ChangePhoneActivity extends BaseFragment {
|
||||||
View view = new View(context);
|
View view = new View(context);
|
||||||
view.setPadding(AndroidUtilities.dp(12), 0, AndroidUtilities.dp(12), 0);
|
view.setPadding(AndroidUtilities.dp(12), 0, AndroidUtilities.dp(12), 0);
|
||||||
view.setBackgroundColor(0xffdbdbdb);
|
view.setBackgroundColor(0xffdbdbdb);
|
||||||
addView(view, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 1, 24, -17.5f, 24, 0));
|
addView(view, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 1, 4, -17.5f, 4, 0));
|
||||||
|
|
||||||
LinearLayout linearLayout = new LinearLayout(context);
|
LinearLayout linearLayout = new LinearLayout(context);
|
||||||
linearLayout.setOrientation(HORIZONTAL);
|
linearLayout.setOrientation(HORIZONTAL);
|
||||||
|
@ -325,7 +383,7 @@ public class ChangePhoneActivity extends BaseFragment {
|
||||||
textView.setText("+");
|
textView.setText("+");
|
||||||
textView.setTextColor(0xff212121);
|
textView.setTextColor(0xff212121);
|
||||||
textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 18);
|
textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 18);
|
||||||
linearLayout.addView(textView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, 24, 0, 0, 0));
|
linearLayout.addView(textView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT));
|
||||||
|
|
||||||
codeField = new EditText(context);
|
codeField = new EditText(context);
|
||||||
codeField.setInputType(InputType.TYPE_CLASS_PHONE);
|
codeField.setInputType(InputType.TYPE_CLASS_PHONE);
|
||||||
|
@ -354,7 +412,6 @@ public class ChangePhoneActivity extends BaseFragment {
|
||||||
@Override
|
@Override
|
||||||
public void afterTextChanged(Editable editable) {
|
public void afterTextChanged(Editable editable) {
|
||||||
if (ignoreOnTextChange) {
|
if (ignoreOnTextChange) {
|
||||||
ignoreOnTextChange = false;
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
ignoreOnTextChange = true;
|
ignoreOnTextChange = true;
|
||||||
|
@ -414,6 +471,7 @@ public class ChangePhoneActivity extends BaseFragment {
|
||||||
phoneField.setSelection(phoneField.length());
|
phoneField.setSelection(phoneField.length());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
ignoreOnTextChange = false;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
codeField.setOnEditorActionListener(new TextView.OnEditorActionListener() {
|
codeField.setOnEditorActionListener(new TextView.OnEditorActionListener() {
|
||||||
|
@ -438,7 +496,7 @@ public class ChangePhoneActivity extends BaseFragment {
|
||||||
phoneField.setMaxLines(1);
|
phoneField.setMaxLines(1);
|
||||||
phoneField.setGravity(Gravity.LEFT | Gravity.CENTER_VERTICAL);
|
phoneField.setGravity(Gravity.LEFT | Gravity.CENTER_VERTICAL);
|
||||||
phoneField.setImeOptions(EditorInfo.IME_ACTION_NEXT | EditorInfo.IME_FLAG_NO_EXTRACT_UI);
|
phoneField.setImeOptions(EditorInfo.IME_ACTION_NEXT | EditorInfo.IME_FLAG_NO_EXTRACT_UI);
|
||||||
linearLayout.addView(phoneField, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 36, 0, 0, 24, 0));
|
linearLayout.addView(phoneField, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 36));
|
||||||
phoneField.addTextChangedListener(new TextWatcher() {
|
phoneField.addTextChangedListener(new TextWatcher() {
|
||||||
|
|
||||||
private int characterAction = -1;
|
private int characterAction = -1;
|
||||||
|
@ -528,9 +586,9 @@ public class ChangePhoneActivity extends BaseFragment {
|
||||||
textView.setText(LocaleController.getString("ChangePhoneHelp", R.string.ChangePhoneHelp));
|
textView.setText(LocaleController.getString("ChangePhoneHelp", R.string.ChangePhoneHelp));
|
||||||
textView.setTextColor(0xff757575);
|
textView.setTextColor(0xff757575);
|
||||||
textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14);
|
textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14);
|
||||||
textView.setGravity(Gravity.LEFT);
|
textView.setGravity(LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT);
|
||||||
textView.setLineSpacing(AndroidUtilities.dp(2), 1.0f);
|
textView.setLineSpacing(AndroidUtilities.dp(2), 1.0f);
|
||||||
addView(textView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.LEFT, 24, 28, 24, 10));
|
addView(textView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT, 0, 28, 0, 10));
|
||||||
|
|
||||||
HashMap<String, String> languageMap = new HashMap<>();
|
HashMap<String, String> languageMap = new HashMap<>();
|
||||||
try {
|
try {
|
||||||
|
@ -561,7 +619,7 @@ public class ChangePhoneActivity extends BaseFragment {
|
||||||
String country = null;
|
String country = null;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
TelephonyManager telephonyManager = (TelephonyManager)ApplicationLoader.applicationContext.getSystemService(Context.TELEPHONY_SERVICE);
|
TelephonyManager telephonyManager = (TelephonyManager) ApplicationLoader.applicationContext.getSystemService(Context.TELEPHONY_SERVICE);
|
||||||
if (telephonyManager != null) {
|
if (telephonyManager != null) {
|
||||||
country = telephonyManager.getSimCountryIso().toUpperCase();
|
country = telephonyManager.getSimCountryIso().toUpperCase();
|
||||||
}
|
}
|
||||||
|
@ -605,6 +663,7 @@ public class ChangePhoneActivity extends BaseFragment {
|
||||||
String hint = phoneFormatMap.get(code);
|
String hint = phoneFormatMap.get(code);
|
||||||
phoneField.setHintText(hint != null ? hint.replace('X', '–') : null);
|
phoneField.setHintText(hint != null ? hint.replace('X', '–') : null);
|
||||||
countryState = 0;
|
countryState = 0;
|
||||||
|
ignoreOnTextChange = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -617,6 +676,7 @@ public class ChangePhoneActivity extends BaseFragment {
|
||||||
ignoreOnTextChange = true;
|
ignoreOnTextChange = true;
|
||||||
String str = countriesArray.get(i);
|
String str = countriesArray.get(i);
|
||||||
codeField.setText(countriesMap.get(str));
|
codeField.setText(countriesMap.get(str));
|
||||||
|
ignoreOnTextChange = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -626,9 +686,46 @@ public class ChangePhoneActivity extends BaseFragment {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onNextPressed() {
|
public void onNextPressed() {
|
||||||
if (nextPressed) {
|
if (getParentActivity() == null || nextPressed) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
TelephonyManager tm = (TelephonyManager) ApplicationLoader.applicationContext.getSystemService(Context.TELEPHONY_SERVICE);
|
||||||
|
boolean simcardAvailable = tm.getSimState() != TelephonyManager.SIM_STATE_ABSENT && tm.getPhoneType() != TelephonyManager.PHONE_TYPE_NONE;
|
||||||
|
boolean allowCall = true;
|
||||||
|
if (Build.VERSION.SDK_INT >= 23 && simcardAvailable) {
|
||||||
|
allowCall = getParentActivity().checkSelfPermission(Manifest.permission.READ_PHONE_STATE) == PackageManager.PERMISSION_GRANTED;
|
||||||
|
boolean allowSms = getParentActivity().checkSelfPermission(Manifest.permission.RECEIVE_SMS) == PackageManager.PERMISSION_GRANTED;
|
||||||
|
if (checkPermissions) {
|
||||||
|
permissionsItems.clear();
|
||||||
|
if (!allowCall) {
|
||||||
|
permissionsItems.add(Manifest.permission.READ_PHONE_STATE);
|
||||||
|
}
|
||||||
|
if (!allowSms) {
|
||||||
|
permissionsItems.add(Manifest.permission.RECEIVE_SMS);
|
||||||
|
}
|
||||||
|
if (!permissionsItems.isEmpty()) {
|
||||||
|
SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("mainconfig", Activity.MODE_PRIVATE);
|
||||||
|
if (preferences.getBoolean("firstlogin", true) || getParentActivity().shouldShowRequestPermissionRationale(Manifest.permission.READ_PHONE_STATE) || getParentActivity().shouldShowRequestPermissionRationale(Manifest.permission.RECEIVE_SMS)) {
|
||||||
|
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);
|
||||||
|
if (permissionsItems.size() == 2) {
|
||||||
|
builder.setMessage(LocaleController.getString("AllowReadCallAndSms", R.string.AllowReadCallAndSms));
|
||||||
|
} else if (!allowSms) {
|
||||||
|
builder.setMessage(LocaleController.getString("AllowReadSms", R.string.AllowReadSms));
|
||||||
|
} else {
|
||||||
|
builder.setMessage(LocaleController.getString("AllowReadCall", R.string.AllowReadCall));
|
||||||
|
}
|
||||||
|
permissionsDialog = showDialog(builder.create());
|
||||||
|
} else {
|
||||||
|
getParentActivity().requestPermissions(permissionsItems.toArray(new String[permissionsItems.size()]), 6);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (countryState == 1) {
|
if (countryState == 1) {
|
||||||
needShowAlert(LocaleController.getString("ChooseCountry", R.string.ChooseCountry));
|
needShowAlert(LocaleController.getString("ChooseCountry", R.string.ChooseCountry));
|
||||||
return;
|
return;
|
||||||
|
@ -643,10 +740,20 @@ public class ChangePhoneActivity extends BaseFragment {
|
||||||
TLRPC.TL_account_sendChangePhoneCode req = new TLRPC.TL_account_sendChangePhoneCode();
|
TLRPC.TL_account_sendChangePhoneCode req = new TLRPC.TL_account_sendChangePhoneCode();
|
||||||
String phone = PhoneFormat.stripExceptNumbers("" + codeField.getText() + phoneField.getText());
|
String phone = PhoneFormat.stripExceptNumbers("" + codeField.getText() + phoneField.getText());
|
||||||
req.phone_number = phone;
|
req.phone_number = phone;
|
||||||
final String phone2 = "+" + codeField.getText() + " " + phoneField.getText();
|
req.allow_flashcall = simcardAvailable && allowCall;
|
||||||
|
if (req.allow_flashcall) {
|
||||||
|
String number = tm.getLine1Number();
|
||||||
|
req.current_number = number != null && number.length() != 0 && (phone.contains(number) || number.contains(phone));
|
||||||
|
}
|
||||||
|
|
||||||
final Bundle params = new Bundle();
|
final Bundle params = new Bundle();
|
||||||
params.putString("phone", phone2);
|
params.putString("phone", "+" + codeField.getText() + phoneField.getText());
|
||||||
|
try {
|
||||||
|
params.putString("ephone", "+" + PhoneFormat.stripExceptNumbers(codeField.getText().toString()) + " " + PhoneFormat.stripExceptNumbers(phoneField.getText().toString()));
|
||||||
|
} catch (Exception e) {
|
||||||
|
FileLog.e("tmessages", e);
|
||||||
|
params.putString("ephone", "+" + phone);
|
||||||
|
}
|
||||||
params.putString("phoneFormated", phone);
|
params.putString("phoneFormated", phone);
|
||||||
nextPressed = true;
|
nextPressed = true;
|
||||||
needShowProgress();
|
needShowProgress();
|
||||||
|
@ -658,10 +765,7 @@ public class ChangePhoneActivity extends BaseFragment {
|
||||||
public void run() {
|
public void run() {
|
||||||
nextPressed = false;
|
nextPressed = false;
|
||||||
if (error == null) {
|
if (error == null) {
|
||||||
TLRPC.TL_account_sentChangePhoneCode res = (TLRPC.TL_account_sentChangePhoneCode)response;
|
fillNextCodeParams(params, (TLRPC.TL_auth_sentCode) response);
|
||||||
params.putString("phoneHash", res.phone_code_hash);
|
|
||||||
params.putInt("calltime", res.send_call_timeout * 1000);
|
|
||||||
setPage(1, true, params, false);
|
|
||||||
} else {
|
} else {
|
||||||
if (error.text != null) {
|
if (error.text != null) {
|
||||||
if (error.text.contains("PHONE_NUMBER_INVALID")) {
|
if (error.text.contains("PHONE_NUMBER_INVALID")) {
|
||||||
|
@ -673,7 +777,7 @@ public class ChangePhoneActivity extends BaseFragment {
|
||||||
} else if (error.text.startsWith("FLOOD_WAIT")) {
|
} else if (error.text.startsWith("FLOOD_WAIT")) {
|
||||||
needShowAlert(LocaleController.getString("FloodWait", R.string.FloodWait));
|
needShowAlert(LocaleController.getString("FloodWait", R.string.FloodWait));
|
||||||
} else if (error.text.startsWith("PHONE_NUMBER_OCCUPIED")) {
|
} else if (error.text.startsWith("PHONE_NUMBER_OCCUPIED")) {
|
||||||
needShowAlert(LocaleController.formatString("ChangePhoneNumberOccupied", R.string.ChangePhoneNumberOccupied, phone2));
|
needShowAlert(LocaleController.formatString("ChangePhoneNumberOccupied", R.string.ChangePhoneNumberOccupied, params.getString("phone")));
|
||||||
} else {
|
} else {
|
||||||
needShowAlert(LocaleController.getString("ErrorOccurred", R.string.ErrorOccurred));
|
needShowAlert(LocaleController.getString("ErrorOccurred", R.string.ErrorOccurred));
|
||||||
}
|
}
|
||||||
|
@ -709,43 +813,88 @@ public class ChangePhoneActivity extends BaseFragment {
|
||||||
|
|
||||||
public class LoginActivitySmsView extends SlideView implements NotificationCenter.NotificationCenterDelegate {
|
public class LoginActivitySmsView extends SlideView implements NotificationCenter.NotificationCenterDelegate {
|
||||||
|
|
||||||
|
private class ProgressView extends View {
|
||||||
|
|
||||||
|
private Paint paint = new Paint();
|
||||||
|
private Paint paint2 = new Paint();
|
||||||
|
private float progress;
|
||||||
|
|
||||||
|
public ProgressView(Context context) {
|
||||||
|
super(context);
|
||||||
|
paint.setColor(0xffe1eaf2);
|
||||||
|
paint2.setColor(0xff62a0d0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setProgress(float value) {
|
||||||
|
progress = value;
|
||||||
|
invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onDraw(Canvas canvas) {
|
||||||
|
int start = (int) (getMeasuredWidth() * progress);
|
||||||
|
canvas.drawRect(0, 0, start, getMeasuredHeight(), paint2);
|
||||||
|
canvas.drawRect(start, 0, getMeasuredWidth(), getMeasuredHeight(), paint);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String phone;
|
||||||
private String phoneHash;
|
private String phoneHash;
|
||||||
private String requestPhone;
|
private String requestPhone;
|
||||||
|
private String emailPhone;
|
||||||
private EditText codeField;
|
private EditText codeField;
|
||||||
private TextView confirmTextView;
|
private TextView confirmTextView;
|
||||||
private TextView timeText;
|
private TextView timeText;
|
||||||
|
private TextView problemText;
|
||||||
private Bundle currentParams;
|
private Bundle currentParams;
|
||||||
|
private ProgressView progressView;
|
||||||
|
|
||||||
private Timer timeTimer;
|
private Timer timeTimer;
|
||||||
private Timer codeTimer;
|
private Timer codeTimer;
|
||||||
|
private int openTime;
|
||||||
private final Object timerSync = new Object();
|
private final Object timerSync = new Object();
|
||||||
private volatile int time = 60000;
|
private volatile int time = 60000;
|
||||||
private volatile int codeTime = 15000;
|
private volatile int codeTime = 15000;
|
||||||
private double lastCurrentTime;
|
private double lastCurrentTime;
|
||||||
private double lastCodeTime;
|
private double lastCodeTime;
|
||||||
private boolean ignoreOnTextChange;
|
private boolean ignoreOnTextChange;
|
||||||
private boolean waitingForSms = false;
|
private boolean waitingForEvent;
|
||||||
private boolean nextPressed = false;
|
private boolean nextPressed;
|
||||||
private String lastError = "";
|
private String lastError = "";
|
||||||
|
private int currentType;
|
||||||
|
private int nextType;
|
||||||
|
private String pattern = "*";
|
||||||
|
private int length;
|
||||||
|
private int timeout;
|
||||||
|
|
||||||
public LoginActivitySmsView(Context context) {
|
public LoginActivitySmsView(Context context, final int type) {
|
||||||
super(context);
|
super(context);
|
||||||
|
|
||||||
|
currentType = type;
|
||||||
setOrientation(VERTICAL);
|
setOrientation(VERTICAL);
|
||||||
|
|
||||||
confirmTextView = new TextView(context);
|
confirmTextView = new TextView(context);
|
||||||
confirmTextView.setTextColor(0xff757575);
|
confirmTextView.setTextColor(0xff757575);
|
||||||
confirmTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14);
|
confirmTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14);
|
||||||
confirmTextView.setGravity(Gravity.LEFT);
|
confirmTextView.setGravity(LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT);
|
||||||
confirmTextView.setLineSpacing(AndroidUtilities.dp(2), 1.0f);
|
confirmTextView.setLineSpacing(AndroidUtilities.dp(2), 1.0f);
|
||||||
addView(confirmTextView);
|
|
||||||
LayoutParams layoutParams = (LayoutParams) confirmTextView.getLayoutParams();
|
if (currentType == 3) {
|
||||||
layoutParams.width = LayoutHelper.WRAP_CONTENT;
|
FrameLayout frameLayout = new FrameLayout(context);
|
||||||
layoutParams.height = LayoutHelper.WRAP_CONTENT;
|
|
||||||
layoutParams.gravity = Gravity.LEFT;
|
ImageView imageView = new ImageView(context);
|
||||||
layoutParams.leftMargin = AndroidUtilities.dp(24);
|
imageView.setImageResource(R.drawable.phone_activate);
|
||||||
layoutParams.rightMargin = AndroidUtilities.dp(24);
|
if (LocaleController.isRTL) {
|
||||||
confirmTextView.setLayoutParams(layoutParams);
|
frameLayout.addView(imageView, LayoutHelper.createFrame(64, 76, Gravity.LEFT | Gravity.CENTER_VERTICAL, 2, 2, 0, 0));
|
||||||
|
frameLayout.addView(confirmTextView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT, 64 + 18, 0, 0, 0));
|
||||||
|
} else {
|
||||||
|
frameLayout.addView(confirmTextView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT, 0, 0, 64 + 18, 0));
|
||||||
|
frameLayout.addView(imageView, LayoutHelper.createFrame(64, 76, Gravity.RIGHT | Gravity.CENTER_VERTICAL, 0, 2, 0, 2));
|
||||||
|
}
|
||||||
|
addView(frameLayout, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT));
|
||||||
|
} else {
|
||||||
|
addView(confirmTextView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT));
|
||||||
|
}
|
||||||
|
|
||||||
codeField = new EditText(context);
|
codeField = new EditText(context);
|
||||||
codeField.setTextColor(0xff212121);
|
codeField.setTextColor(0xff212121);
|
||||||
|
@ -757,15 +906,7 @@ public class ChangePhoneActivity extends BaseFragment {
|
||||||
codeField.setInputType(InputType.TYPE_CLASS_PHONE);
|
codeField.setInputType(InputType.TYPE_CLASS_PHONE);
|
||||||
codeField.setMaxLines(1);
|
codeField.setMaxLines(1);
|
||||||
codeField.setPadding(0, 0, 0, 0);
|
codeField.setPadding(0, 0, 0, 0);
|
||||||
addView(codeField);
|
addView(codeField, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 36, Gravity.CENTER_HORIZONTAL, 0, 20, 0, 0));
|
||||||
layoutParams = (LayoutParams) codeField.getLayoutParams();
|
|
||||||
layoutParams.width = LayoutHelper.MATCH_PARENT;
|
|
||||||
layoutParams.height = AndroidUtilities.dp(36);
|
|
||||||
layoutParams.gravity = Gravity.CENTER_HORIZONTAL;
|
|
||||||
layoutParams.topMargin = AndroidUtilities.dp(20);
|
|
||||||
layoutParams.leftMargin = AndroidUtilities.dp(24);
|
|
||||||
layoutParams.rightMargin = AndroidUtilities.dp(24);
|
|
||||||
codeField.setLayoutParams(layoutParams);
|
|
||||||
codeField.addTextChangedListener(new TextWatcher() {
|
codeField.addTextChangedListener(new TextWatcher() {
|
||||||
@Override
|
@Override
|
||||||
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
|
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
|
||||||
|
@ -782,7 +923,7 @@ public class ChangePhoneActivity extends BaseFragment {
|
||||||
if (ignoreOnTextChange) {
|
if (ignoreOnTextChange) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (codeField.length() == 5) {
|
if (length != 0 && codeField.length() == length) {
|
||||||
onNextPressed();
|
onNextPressed();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -797,55 +938,133 @@ public class ChangePhoneActivity extends BaseFragment {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
if (currentType == 3) {
|
||||||
|
codeField.setEnabled(false);
|
||||||
|
codeField.setInputType(InputType.TYPE_NULL);
|
||||||
|
codeField.setVisibility(GONE);
|
||||||
|
}
|
||||||
|
|
||||||
timeText = new TextView(context);
|
timeText = new TextView(context);
|
||||||
timeText.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14);
|
timeText.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14);
|
||||||
timeText.setTextColor(0xff757575);
|
timeText.setTextColor(0xff757575);
|
||||||
timeText.setLineSpacing(AndroidUtilities.dp(2), 1.0f);
|
timeText.setLineSpacing(AndroidUtilities.dp(2), 1.0f);
|
||||||
timeText.setGravity(Gravity.LEFT);
|
timeText.setGravity(LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT);
|
||||||
addView(timeText);
|
addView(timeText, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT, 0, 30, 0, 0));
|
||||||
layoutParams = (LayoutParams) timeText.getLayoutParams();
|
|
||||||
layoutParams.width = LayoutHelper.WRAP_CONTENT;
|
if (currentType == 3) {
|
||||||
layoutParams.height = LayoutHelper.WRAP_CONTENT;
|
progressView = new ProgressView(context);
|
||||||
layoutParams.gravity = Gravity.LEFT;
|
addView(progressView, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 3, 0, 12, 0, 0));
|
||||||
layoutParams.topMargin = AndroidUtilities.dp(30);
|
}
|
||||||
layoutParams.leftMargin = AndroidUtilities.dp(24);
|
|
||||||
layoutParams.rightMargin = AndroidUtilities.dp(24);
|
problemText = new TextView(context);
|
||||||
timeText.setLayoutParams(layoutParams);
|
problemText.setText(LocaleController.getString("DidNotGetTheCode", R.string.DidNotGetTheCode));
|
||||||
|
problemText.setGravity(LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT);
|
||||||
|
problemText.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14);
|
||||||
|
problemText.setTextColor(0xff4d83b3);
|
||||||
|
problemText.setLineSpacing(AndroidUtilities.dp(2), 1.0f);
|
||||||
|
problemText.setPadding(0, AndroidUtilities.dp(2), 0, AndroidUtilities.dp(12));
|
||||||
|
addView(problemText, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT, 0, 20, 0, 0));
|
||||||
|
problemText.setOnClickListener(new OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
if (nextPressed) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (nextType != 0 && nextType != 4) {
|
||||||
|
resendCode();
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
PackageInfo pInfo = ApplicationLoader.applicationContext.getPackageManager().getPackageInfo(ApplicationLoader.applicationContext.getPackageName(), 0);
|
||||||
|
String version = String.format(Locale.US, "%s (%d)", pInfo.versionName, pInfo.versionCode);
|
||||||
|
|
||||||
|
Intent mailer = new Intent(Intent.ACTION_SEND);
|
||||||
|
mailer.setType("message/rfc822");
|
||||||
|
mailer.putExtra(Intent.EXTRA_EMAIL, new String[]{"sms@stel.com"});
|
||||||
|
mailer.putExtra(Intent.EXTRA_SUBJECT, "Android registration/login issue " + version + " " + emailPhone);
|
||||||
|
mailer.putExtra(Intent.EXTRA_TEXT, "Phone: " + requestPhone + "\nApp version: " + version + "\nOS version: SDK " + Build.VERSION.SDK_INT + "\nDevice Name: " + Build.MANUFACTURER + Build.MODEL + "\nLocale: " + Locale.getDefault() + "\nError: " + lastError);
|
||||||
|
getContext().startActivity(Intent.createChooser(mailer, "Send email..."));
|
||||||
|
} catch (Exception e) {
|
||||||
|
needShowAlert(LocaleController.getString("NoMailInstalled", R.string.NoMailInstalled));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
LinearLayout linearLayout = new LinearLayout(context);
|
LinearLayout linearLayout = new LinearLayout(context);
|
||||||
linearLayout.setGravity(Gravity.BOTTOM | Gravity.CENTER_VERTICAL);
|
linearLayout.setGravity((LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.CENTER_VERTICAL);
|
||||||
addView(linearLayout);
|
addView(linearLayout, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT));
|
||||||
layoutParams = (LayoutParams) linearLayout.getLayoutParams();
|
|
||||||
layoutParams.width = LayoutHelper.MATCH_PARENT;
|
|
||||||
layoutParams.height = LayoutHelper.MATCH_PARENT;
|
|
||||||
linearLayout.setLayoutParams(layoutParams);
|
|
||||||
|
|
||||||
TextView wrongNumber = new TextView(context);
|
TextView wrongNumber = new TextView(context);
|
||||||
wrongNumber.setGravity(Gravity.LEFT | Gravity.CENTER_HORIZONTAL);
|
wrongNumber.setGravity((LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.CENTER_HORIZONTAL);
|
||||||
wrongNumber.setTextColor(0xff4d83b3);
|
wrongNumber.setTextColor(0xff4d83b3);
|
||||||
wrongNumber.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14);
|
wrongNumber.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14);
|
||||||
wrongNumber.setLineSpacing(AndroidUtilities.dp(2), 1.0f);
|
wrongNumber.setLineSpacing(AndroidUtilities.dp(2), 1.0f);
|
||||||
wrongNumber.setPadding(0, AndroidUtilities.dp(24), 0, 0);
|
wrongNumber.setPadding(0, AndroidUtilities.dp(24), 0, 0);
|
||||||
linearLayout.addView(wrongNumber);
|
linearLayout.addView(wrongNumber, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.BOTTOM | (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT), 0, 0, 0, 10));
|
||||||
layoutParams = (LayoutParams) wrongNumber.getLayoutParams();
|
|
||||||
layoutParams.width = LayoutHelper.WRAP_CONTENT;
|
|
||||||
layoutParams.height = LayoutHelper.WRAP_CONTENT;
|
|
||||||
layoutParams.gravity = Gravity.BOTTOM | Gravity.LEFT;
|
|
||||||
layoutParams.bottomMargin = AndroidUtilities.dp(10);
|
|
||||||
layoutParams.leftMargin = AndroidUtilities.dp(24);
|
|
||||||
layoutParams.rightMargin = AndroidUtilities.dp(24);
|
|
||||||
wrongNumber.setLayoutParams(layoutParams);
|
|
||||||
wrongNumber.setText(LocaleController.getString("WrongNumber", R.string.WrongNumber));
|
wrongNumber.setText(LocaleController.getString("WrongNumber", R.string.WrongNumber));
|
||||||
wrongNumber.setOnClickListener(new OnClickListener() {
|
wrongNumber.setOnClickListener(new OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onClick(View view) {
|
public void onClick(View view) {
|
||||||
|
TLRPC.TL_auth_cancelCode req = new TLRPC.TL_auth_cancelCode();
|
||||||
|
req.phone_number = requestPhone;
|
||||||
|
req.phone_code_hash = phoneHash;
|
||||||
|
ConnectionsManager.getInstance().sendRequest(req, new RequestDelegate() {
|
||||||
|
@Override
|
||||||
|
public void run(TLObject response, TLRPC.TL_error error) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}, ConnectionsManager.RequestFlagFailOnServerErrors);
|
||||||
onBackPressed();
|
onBackPressed();
|
||||||
setPage(0, true, null, true);
|
setPage(0, true, null, true);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void resendCode() {
|
||||||
|
final Bundle params = new Bundle();
|
||||||
|
params.putString("phone", phone);
|
||||||
|
params.putString("ephone", emailPhone);
|
||||||
|
params.putString("phoneFormated", requestPhone);
|
||||||
|
|
||||||
|
nextPressed = true;
|
||||||
|
needShowProgress();
|
||||||
|
|
||||||
|
TLRPC.TL_auth_resendCode req = new TLRPC.TL_auth_resendCode();
|
||||||
|
req.phone_number = requestPhone;
|
||||||
|
req.phone_code_hash = phoneHash;
|
||||||
|
ConnectionsManager.getInstance().sendRequest(req, new RequestDelegate() {
|
||||||
|
@Override
|
||||||
|
public void run(final TLObject response, final TLRPC.TL_error error) {
|
||||||
|
AndroidUtilities.runOnUIThread(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
nextPressed = false;
|
||||||
|
if (error == null) {
|
||||||
|
fillNextCodeParams(params, (TLRPC.TL_auth_sentCode) response);
|
||||||
|
} else {
|
||||||
|
if (error.text != null) {
|
||||||
|
if (error.text.contains("PHONE_NUMBER_INVALID")) {
|
||||||
|
needShowAlert(LocaleController.getString("InvalidPhoneNumber", R.string.InvalidPhoneNumber));
|
||||||
|
} else if (error.text.contains("PHONE_CODE_EMPTY") || error.text.contains("PHONE_CODE_INVALID")) {
|
||||||
|
needShowAlert(LocaleController.getString("InvalidCode", R.string.InvalidCode));
|
||||||
|
} else if (error.text.contains("PHONE_CODE_EXPIRED")) {
|
||||||
|
onBackPressed();
|
||||||
|
setPage(0, true, null, true);
|
||||||
|
needShowAlert(LocaleController.getString("CodeExpired", R.string.CodeExpired));
|
||||||
|
} else if (error.text.startsWith("FLOOD_WAIT")) {
|
||||||
|
needShowAlert(LocaleController.getString("FloodWait", R.string.FloodWait));
|
||||||
|
} else if (error.code != -1000) {
|
||||||
|
needShowAlert(LocaleController.getString("ErrorOccurred", R.string.ErrorOccurred) + "\n" + error.text);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
needHideProgress();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, ConnectionsManager.RequestFlagFailOnServerErrors);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getHeaderName() {
|
public String getHeaderName() {
|
||||||
return LocaleController.getString("YourCode", R.string.YourCode);
|
return LocaleController.getString("YourCode", R.string.YourCode);
|
||||||
|
@ -857,41 +1076,87 @@ public class ChangePhoneActivity extends BaseFragment {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
codeField.setText("");
|
codeField.setText("");
|
||||||
AndroidUtilities.setWaitingForSms(true);
|
waitingForEvent = true;
|
||||||
NotificationCenter.getInstance().addObserver(this, NotificationCenter.didReceiveSmsCode);
|
if (currentType == 2) {
|
||||||
|
AndroidUtilities.setWaitingForSms(true);
|
||||||
|
NotificationCenter.getInstance().addObserver(this, NotificationCenter.didReceiveSmsCode);
|
||||||
|
} else if (currentType == 3) {
|
||||||
|
AndroidUtilities.setWaitingForCall(true);
|
||||||
|
NotificationCenter.getInstance().addObserver(this, NotificationCenter.didReceiveCall);
|
||||||
|
}
|
||||||
|
|
||||||
currentParams = params;
|
currentParams = params;
|
||||||
waitingForSms = true;
|
phone = params.getString("phone");
|
||||||
String phone = params.getString("phone");
|
emailPhone = params.getString("ephone");
|
||||||
requestPhone = params.getString("phoneFormated");
|
requestPhone = params.getString("phoneFormated");
|
||||||
phoneHash = params.getString("phoneHash");
|
phoneHash = params.getString("phoneHash");
|
||||||
time = params.getInt("calltime");
|
timeout = time = params.getInt("timeout");
|
||||||
|
openTime = (int) (System.currentTimeMillis() / 1000);
|
||||||
|
nextType = params.getInt("nextType");
|
||||||
|
pattern = params.getString("pattern");
|
||||||
|
length = params.getInt("length");
|
||||||
|
|
||||||
|
if (length != 0) {
|
||||||
|
InputFilter[] inputFilters = new InputFilter[1];
|
||||||
|
inputFilters[0] = new InputFilter.LengthFilter(length);
|
||||||
|
codeField.setFilters(inputFilters);
|
||||||
|
} else {
|
||||||
|
codeField.setFilters(new InputFilter[0]);
|
||||||
|
}
|
||||||
|
if (progressView != null) {
|
||||||
|
progressView.setVisibility(nextType != 0 ? VISIBLE : GONE);
|
||||||
|
}
|
||||||
|
|
||||||
if (phone == null) {
|
if (phone == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
String number = PhoneFormat.getInstance().format(phone);
|
String number = PhoneFormat.getInstance().format(phone);
|
||||||
String str = String.format(Locale.US, LocaleController.getString("SentSmsCode", R.string.SentSmsCode) + " %s", number);
|
CharSequence str = "";
|
||||||
try {
|
if (currentType == 1) {
|
||||||
SpannableStringBuilder stringBuilder = new SpannableStringBuilder(str);
|
str = AndroidUtilities.replaceTags(LocaleController.getString("SentAppCode", R.string.SentAppCode));
|
||||||
TypefaceSpan span = new TypefaceSpan(AndroidUtilities.getTypeface("fonts/rmedium.ttf"));
|
} else if (currentType == 2) {
|
||||||
int idx = str.indexOf(number);
|
str = AndroidUtilities.replaceTags(LocaleController.formatString("SentSmsCode", R.string.SentSmsCode, number));
|
||||||
stringBuilder.setSpan(span, idx, idx + number.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
|
} else if (currentType == 3) {
|
||||||
confirmTextView.setText(stringBuilder);
|
str = AndroidUtilities.replaceTags(LocaleController.formatString("SentCallCode", R.string.SentCallCode, number));
|
||||||
} catch (Exception e) {
|
} else if (currentType == 4) {
|
||||||
FileLog.e("tmessages", e);
|
str = AndroidUtilities.replaceTags(LocaleController.formatString("SentCallOnly", R.string.SentCallOnly, number));
|
||||||
confirmTextView.setText(str);
|
|
||||||
}
|
}
|
||||||
|
confirmTextView.setText(str);
|
||||||
|
|
||||||
AndroidUtilities.showKeyboard(codeField);
|
if (currentType != 3) {
|
||||||
codeField.requestFocus();
|
AndroidUtilities.showKeyboard(codeField);
|
||||||
|
codeField.requestFocus();
|
||||||
|
} else {
|
||||||
|
AndroidUtilities.hideKeyboard(codeField);
|
||||||
|
}
|
||||||
|
|
||||||
destroyTimer();
|
destroyTimer();
|
||||||
destroyCodeTimer();
|
destroyCodeTimer();
|
||||||
timeText.setText(LocaleController.formatString("CallText", R.string.CallText, 1, 0));
|
|
||||||
lastCurrentTime = System.currentTimeMillis();
|
|
||||||
|
|
||||||
createTimer();
|
lastCurrentTime = System.currentTimeMillis();
|
||||||
|
if (currentType == 1) {
|
||||||
|
problemText.setVisibility(VISIBLE);
|
||||||
|
timeText.setVisibility(GONE);
|
||||||
|
} else if (currentType == 3 && (nextType == 4 || nextType == 2)) {
|
||||||
|
problemText.setVisibility(GONE);
|
||||||
|
timeText.setVisibility(VISIBLE);
|
||||||
|
if (nextType == 4) {
|
||||||
|
timeText.setText(LocaleController.formatString("CallText", R.string.CallText, 1, 0));
|
||||||
|
} else if (nextType == 2) {
|
||||||
|
timeText.setText(LocaleController.formatString("SmsText", R.string.SmsText, 1, 0));
|
||||||
|
}
|
||||||
|
createTimer();
|
||||||
|
} else if (currentType == 2 && nextType == 4) {
|
||||||
|
timeText.setVisibility(VISIBLE);
|
||||||
|
timeText.setText(LocaleController.formatString("CallText", R.string.CallText, 2, 0));
|
||||||
|
problemText.setVisibility(time < 1000 ? VISIBLE : GONE);
|
||||||
|
createTimer();
|
||||||
|
} else {
|
||||||
|
timeText.setVisibility(GONE);
|
||||||
|
problemText.setVisibility(GONE);
|
||||||
|
createCodeTimer();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void createCodeTimer() {
|
private void createCodeTimer() {
|
||||||
|
@ -912,6 +1177,7 @@ public class ChangePhoneActivity extends BaseFragment {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
if (codeTime <= 1000) {
|
if (codeTime <= 1000) {
|
||||||
|
problemText.setVisibility(VISIBLE);
|
||||||
destroyCodeTimer();
|
destroyCodeTimer();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -922,7 +1188,7 @@ public class ChangePhoneActivity extends BaseFragment {
|
||||||
|
|
||||||
private void destroyCodeTimer() {
|
private void destroyCodeTimer() {
|
||||||
try {
|
try {
|
||||||
synchronized(timerSync) {
|
synchronized (timerSync) {
|
||||||
if (codeTimer != null) {
|
if (codeTimer != null) {
|
||||||
codeTimer.cancel();
|
codeTimer.cancel();
|
||||||
codeTimer = null;
|
codeTimer = null;
|
||||||
|
@ -941,7 +1207,10 @@ public class ChangePhoneActivity extends BaseFragment {
|
||||||
timeTimer.schedule(new TimerTask() {
|
timeTimer.schedule(new TimerTask() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
double currentTime = System.currentTimeMillis();
|
if (timeTimer == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
final double currentTime = System.currentTimeMillis();
|
||||||
double diff = currentTime - lastCurrentTime;
|
double diff = currentTime - lastCurrentTime;
|
||||||
time -= diff;
|
time -= diff;
|
||||||
lastCurrentTime = currentTime;
|
lastCurrentTime = currentTime;
|
||||||
|
@ -951,27 +1220,45 @@ public class ChangePhoneActivity extends BaseFragment {
|
||||||
if (time >= 1000) {
|
if (time >= 1000) {
|
||||||
int minutes = time / 1000 / 60;
|
int minutes = time / 1000 / 60;
|
||||||
int seconds = time / 1000 - minutes * 60;
|
int seconds = time / 1000 - minutes * 60;
|
||||||
timeText.setText(LocaleController.formatString("CallText", R.string.CallText, minutes, seconds));
|
if (nextType == 4) {
|
||||||
|
timeText.setText(LocaleController.formatString("CallText", R.string.CallText, minutes, seconds));
|
||||||
|
} else if (nextType == 2) {
|
||||||
|
timeText.setText(LocaleController.formatString("SmsText", R.string.SmsText, minutes, seconds));
|
||||||
|
}
|
||||||
|
if (progressView != null) {
|
||||||
|
progressView.setProgress(1.0f - (float) time / (float) timeout);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
timeText.setText(LocaleController.getString("Calling", R.string.Calling));
|
if (progressView != null) {
|
||||||
|
progressView.setProgress(1.0f);
|
||||||
|
}
|
||||||
destroyTimer();
|
destroyTimer();
|
||||||
createCodeTimer();
|
if (currentType == 3) {
|
||||||
TLRPC.TL_auth_sendCall req = new TLRPC.TL_auth_sendCall();
|
AndroidUtilities.setWaitingForCall(false);
|
||||||
req.phone_number = requestPhone;
|
NotificationCenter.getInstance().removeObserver(this, NotificationCenter.didReceiveCall);
|
||||||
req.phone_code_hash = phoneHash;
|
waitingForEvent = false;
|
||||||
ConnectionsManager.getInstance().sendRequest(req, new RequestDelegate() {
|
destroyCodeTimer();
|
||||||
@Override
|
resendCode();
|
||||||
public void run(TLObject response, final TLRPC.TL_error error) {
|
} else {
|
||||||
if (error != null && error.text != null) {
|
timeText.setText(LocaleController.getString("Calling", R.string.Calling));
|
||||||
AndroidUtilities.runOnUIThread(new Runnable() {
|
createCodeTimer();
|
||||||
@Override
|
TLRPC.TL_auth_resendCode req = new TLRPC.TL_auth_resendCode();
|
||||||
public void run() {
|
req.phone_number = requestPhone;
|
||||||
lastError = error.text;
|
req.phone_code_hash = phoneHash;
|
||||||
}
|
ConnectionsManager.getInstance().sendRequest(req, new RequestDelegate() {
|
||||||
});
|
@Override
|
||||||
|
public void run(TLObject response, final TLRPC.TL_error error) {
|
||||||
|
if (error != null && error.text != null) {
|
||||||
|
AndroidUtilities.runOnUIThread(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
lastError = error.text;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}, ConnectionsManager.RequestFlagFailOnServerErrors);
|
||||||
}, ConnectionsManager.RequestFlagFailOnServerErrors);
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -981,7 +1268,7 @@ public class ChangePhoneActivity extends BaseFragment {
|
||||||
|
|
||||||
private void destroyTimer() {
|
private void destroyTimer() {
|
||||||
try {
|
try {
|
||||||
synchronized(timerSync) {
|
synchronized (timerSync) {
|
||||||
if (timeTimer != null) {
|
if (timeTimer != null) {
|
||||||
timeTimer.cancel();
|
timeTimer.cancel();
|
||||||
timeTimer = null;
|
timeTimer = null;
|
||||||
|
@ -998,9 +1285,14 @@ public class ChangePhoneActivity extends BaseFragment {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
nextPressed = true;
|
nextPressed = true;
|
||||||
waitingForSms = false;
|
if (currentType == 2) {
|
||||||
AndroidUtilities.setWaitingForSms(false);
|
AndroidUtilities.setWaitingForSms(false);
|
||||||
NotificationCenter.getInstance().removeObserver(this, NotificationCenter.didReceiveSmsCode);
|
NotificationCenter.getInstance().removeObserver(this, NotificationCenter.didReceiveSmsCode);
|
||||||
|
} else if (currentType == 3) {
|
||||||
|
AndroidUtilities.setWaitingForCall(false);
|
||||||
|
NotificationCenter.getInstance().removeObserver(this, NotificationCenter.didReceiveCall);
|
||||||
|
}
|
||||||
|
waitingForEvent = false;
|
||||||
final TLRPC.TL_account_changePhone req = new TLRPC.TL_account_changePhone();
|
final TLRPC.TL_account_changePhone req = new TLRPC.TL_account_changePhone();
|
||||||
req.phone_number = requestPhone;
|
req.phone_number = requestPhone;
|
||||||
req.phone_code = codeField.getText().toString();
|
req.phone_code = codeField.getText().toString();
|
||||||
|
@ -1028,17 +1320,29 @@ public class ChangePhoneActivity extends BaseFragment {
|
||||||
finishFragment();
|
finishFragment();
|
||||||
} else {
|
} else {
|
||||||
lastError = error.text;
|
lastError = error.text;
|
||||||
createTimer();
|
if (currentType == 3 && (nextType == 4 || nextType == 2) || currentType == 2 && nextType == 4) {
|
||||||
if (error.text.contains("PHONE_NUMBER_INVALID")) {
|
createTimer();
|
||||||
needShowAlert(LocaleController.getString("InvalidPhoneNumber", R.string.InvalidPhoneNumber));
|
}
|
||||||
} else if (error.text.contains("PHONE_CODE_EMPTY") || error.text.contains("PHONE_CODE_INVALID")) {
|
if (currentType == 2) {
|
||||||
needShowAlert(LocaleController.getString("InvalidCode", R.string.InvalidCode));
|
AndroidUtilities.setWaitingForSms(true);
|
||||||
} else if (error.text.contains("PHONE_CODE_EXPIRED")) {
|
NotificationCenter.getInstance().addObserver(LoginActivitySmsView.this, NotificationCenter.didReceiveSmsCode);
|
||||||
needShowAlert(LocaleController.getString("CodeExpired", R.string.CodeExpired));
|
} else if (currentType == 3) {
|
||||||
} else if (error.text.startsWith("FLOOD_WAIT")) {
|
AndroidUtilities.setWaitingForCall(true);
|
||||||
needShowAlert(LocaleController.getString("FloodWait", R.string.FloodWait));
|
NotificationCenter.getInstance().addObserver(LoginActivitySmsView.this, NotificationCenter.didReceiveCall);
|
||||||
} else {
|
}
|
||||||
needShowAlert(error.text);
|
waitingForEvent = true;
|
||||||
|
if (currentType != 3) {
|
||||||
|
if (error.text.contains("PHONE_NUMBER_INVALID")) {
|
||||||
|
needShowAlert(LocaleController.getString("InvalidPhoneNumber", R.string.InvalidPhoneNumber));
|
||||||
|
} else if (error.text.contains("PHONE_CODE_EMPTY") || error.text.contains("PHONE_CODE_INVALID")) {
|
||||||
|
needShowAlert(LocaleController.getString("InvalidCode", R.string.InvalidCode));
|
||||||
|
} else if (error.text.contains("PHONE_CODE_EXPIRED")) {
|
||||||
|
needShowAlert(LocaleController.getString("CodeExpired", R.string.CodeExpired));
|
||||||
|
} else if (error.text.startsWith("FLOOD_WAIT")) {
|
||||||
|
needShowAlert(LocaleController.getString("FloodWait", R.string.FloodWait));
|
||||||
|
} else {
|
||||||
|
needShowAlert(error.text);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1052,19 +1356,29 @@ public class ChangePhoneActivity extends BaseFragment {
|
||||||
destroyTimer();
|
destroyTimer();
|
||||||
destroyCodeTimer();
|
destroyCodeTimer();
|
||||||
currentParams = null;
|
currentParams = null;
|
||||||
AndroidUtilities.setWaitingForSms(false);
|
if (currentType == 2) {
|
||||||
NotificationCenter.getInstance().removeObserver(this, NotificationCenter.didReceiveSmsCode);
|
AndroidUtilities.setWaitingForSms(false);
|
||||||
waitingForSms = false;
|
NotificationCenter.getInstance().removeObserver(this, NotificationCenter.didReceiveSmsCode);
|
||||||
|
} else if (currentType == 3) {
|
||||||
|
AndroidUtilities.setWaitingForCall(false);
|
||||||
|
NotificationCenter.getInstance().removeObserver(this, NotificationCenter.didReceiveCall);
|
||||||
|
}
|
||||||
|
waitingForEvent = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDestroyActivity() {
|
public void onDestroyActivity() {
|
||||||
super.onDestroyActivity();
|
super.onDestroyActivity();
|
||||||
AndroidUtilities.setWaitingForSms(false);
|
if (currentType == 2) {
|
||||||
NotificationCenter.getInstance().removeObserver(this, NotificationCenter.didReceiveSmsCode);
|
AndroidUtilities.setWaitingForSms(false);
|
||||||
|
NotificationCenter.getInstance().removeObserver(this, NotificationCenter.didReceiveSmsCode);
|
||||||
|
} else if (currentType == 3) {
|
||||||
|
AndroidUtilities.setWaitingForCall(false);
|
||||||
|
NotificationCenter.getInstance().removeObserver(this, NotificationCenter.didReceiveCall);
|
||||||
|
}
|
||||||
|
waitingForEvent = false;
|
||||||
destroyTimer();
|
destroyTimer();
|
||||||
destroyCodeTimer();
|
destroyCodeTimer();
|
||||||
waitingForSms = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -1078,15 +1392,26 @@ public class ChangePhoneActivity extends BaseFragment {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void didReceivedNotification(int id, final Object... args) {
|
public void didReceivedNotification(int id, final Object... args) {
|
||||||
|
if (!waitingForEvent || codeField == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (id == NotificationCenter.didReceiveSmsCode) {
|
if (id == NotificationCenter.didReceiveSmsCode) {
|
||||||
if (!waitingForSms) {
|
ignoreOnTextChange = true;
|
||||||
return;
|
codeField.setText("" + args[0]);
|
||||||
}
|
ignoreOnTextChange = false;
|
||||||
if (codeField != null) {
|
onNextPressed();
|
||||||
ignoreOnTextChange = true;
|
} else if (id == NotificationCenter.didReceiveCall) {
|
||||||
codeField.setText("" + args[0]);
|
String num = "" + args[0];
|
||||||
onNextPressed();
|
if (!pattern.equals("*")) {
|
||||||
|
String patternNumbers = pattern.replace("*", "");
|
||||||
|
if (!num.contains(patternNumbers)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
ignoreOnTextChange = true;
|
||||||
|
codeField.setText(num);
|
||||||
|
ignoreOnTextChange = false;
|
||||||
|
onNextPressed();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,9 +39,6 @@ import org.telegram.messenger.MessagesStorage;
|
||||||
import org.telegram.messenger.NotificationCenter;
|
import org.telegram.messenger.NotificationCenter;
|
||||||
import org.telegram.messenger.R;
|
import org.telegram.messenger.R;
|
||||||
import org.telegram.messenger.UserConfig;
|
import org.telegram.messenger.UserConfig;
|
||||||
import org.telegram.tgnet.ConnectionsManager;
|
|
||||||
import org.telegram.tgnet.RequestDelegate;
|
|
||||||
import org.telegram.tgnet.TLObject;
|
|
||||||
import org.telegram.tgnet.TLRPC;
|
import org.telegram.tgnet.TLRPC;
|
||||||
import org.telegram.ui.ActionBar.ActionBar;
|
import org.telegram.ui.ActionBar.ActionBar;
|
||||||
import org.telegram.ui.ActionBar.ActionBarMenu;
|
import org.telegram.ui.ActionBar.ActionBarMenu;
|
||||||
|
@ -63,25 +60,19 @@ public class ChannelEditActivity extends BaseFragment implements AvatarUpdater.A
|
||||||
private View doneButton;
|
private View doneButton;
|
||||||
private EditText nameTextView;
|
private EditText nameTextView;
|
||||||
private EditText descriptionTextView;
|
private EditText descriptionTextView;
|
||||||
private EditText userNameTextView;
|
|
||||||
private BackupImageView avatarImage;
|
private BackupImageView avatarImage;
|
||||||
private AvatarDrawable avatarDrawable;
|
private AvatarDrawable avatarDrawable;
|
||||||
private AvatarUpdater avatarUpdater;
|
private AvatarUpdater avatarUpdater;
|
||||||
private TextView checkTextView;
|
private ProgressDialog progressDialog;
|
||||||
private ProgressDialog progressDialog = null;
|
private TextSettingsCell typeCell;
|
||||||
|
private TextSettingsCell adminCell;
|
||||||
|
|
||||||
private TLRPC.FileLocation avatar;
|
private TLRPC.FileLocation avatar;
|
||||||
private int checkReqId = 0;
|
|
||||||
private String lastCheckName = null;
|
|
||||||
private Runnable checkRunnable = null;
|
|
||||||
private boolean lastNameAvailable = false;
|
|
||||||
private TLRPC.Chat currentChat;
|
private TLRPC.Chat currentChat;
|
||||||
private TLRPC.ChatFull info;
|
private TLRPC.ChatFull info;
|
||||||
private int chatId;
|
private int chatId;
|
||||||
private boolean allowComments = true;
|
private boolean allowComments = true;
|
||||||
private TLRPC.InputFile uploadedAvatar;
|
private TLRPC.InputFile uploadedAvatar;
|
||||||
private boolean wasPrivate;
|
|
||||||
private boolean privateAlertShown;
|
|
||||||
private boolean signMessages;
|
private boolean signMessages;
|
||||||
|
|
||||||
private boolean createAfterUpload;
|
private boolean createAfterUpload;
|
||||||
|
@ -131,24 +122,23 @@ public class ChannelEditActivity extends BaseFragment implements AvatarUpdater.A
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
wasPrivate = currentChat.username == null || currentChat.username.length() == 0;
|
|
||||||
avatarUpdater.parentFragment = this;
|
avatarUpdater.parentFragment = this;
|
||||||
avatarUpdater.delegate = this;
|
avatarUpdater.delegate = this;
|
||||||
allowComments = !currentChat.broadcast;
|
allowComments = !currentChat.broadcast;
|
||||||
signMessages = currentChat.signatures;
|
signMessages = currentChat.signatures;
|
||||||
|
NotificationCenter.getInstance().addObserver(this, NotificationCenter.chatInfoDidLoaded);
|
||||||
|
NotificationCenter.getInstance().addObserver(this, NotificationCenter.updateInterfaces);
|
||||||
return super.onFragmentCreate();
|
return super.onFragmentCreate();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setInfo(TLRPC.ChatFull chatFull) {
|
|
||||||
info = chatFull;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onFragmentDestroy() {
|
public void onFragmentDestroy() {
|
||||||
super.onFragmentDestroy();
|
super.onFragmentDestroy();
|
||||||
if (avatarUpdater != null) {
|
if (avatarUpdater != null) {
|
||||||
avatarUpdater.clear();
|
avatarUpdater.clear();
|
||||||
}
|
}
|
||||||
|
NotificationCenter.getInstance().removeObserver(this, NotificationCenter.chatInfoDidLoaded);
|
||||||
|
NotificationCenter.getInstance().removeObserver(this, NotificationCenter.updateInterfaces);
|
||||||
AndroidUtilities.removeAdjustResize(getParentActivity(), classGuid);
|
AndroidUtilities.removeAdjustResize(getParentActivity(), classGuid);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -172,7 +162,6 @@ public class ChannelEditActivity extends BaseFragment implements AvatarUpdater.A
|
||||||
if (donePressed) {
|
if (donePressed) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
donePressed = true;
|
|
||||||
if (nameTextView.length() == 0) {
|
if (nameTextView.length() == 0) {
|
||||||
Vibrator v = (Vibrator) getParentActivity().getSystemService(Context.VIBRATOR_SERVICE);
|
Vibrator v = (Vibrator) getParentActivity().getSystemService(Context.VIBRATOR_SERVICE);
|
||||||
if (v != null) {
|
if (v != null) {
|
||||||
|
@ -181,18 +170,7 @@ public class ChannelEditActivity extends BaseFragment implements AvatarUpdater.A
|
||||||
AndroidUtilities.shakeView(nameTextView, 2, 0);
|
AndroidUtilities.shakeView(nameTextView, 2, 0);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (userNameTextView != null) {
|
donePressed = true;
|
||||||
if ((currentChat.username == null && userNameTextView.length() != 0) || (currentChat.username != null && !currentChat.username.equalsIgnoreCase(userNameTextView.getText().toString()))) {
|
|
||||||
if (userNameTextView.length() != 0 && !lastNameAvailable) {
|
|
||||||
Vibrator v = (Vibrator) getParentActivity().getSystemService(Context.VIBRATOR_SERVICE);
|
|
||||||
if (v != null) {
|
|
||||||
v.vibrate(200);
|
|
||||||
}
|
|
||||||
AndroidUtilities.shakeView(checkTextView, 2, 0);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (avatarUpdater.uploadingAvatar != null) {
|
if (avatarUpdater.uploadingAvatar != null) {
|
||||||
createAfterUpload = true;
|
createAfterUpload = true;
|
||||||
|
@ -226,12 +204,6 @@ public class ChannelEditActivity extends BaseFragment implements AvatarUpdater.A
|
||||||
if (info != null && !info.about.equals(descriptionTextView.getText().toString())) {
|
if (info != null && !info.about.equals(descriptionTextView.getText().toString())) {
|
||||||
MessagesController.getInstance().updateChannelAbout(chatId, descriptionTextView.getText().toString(), info);
|
MessagesController.getInstance().updateChannelAbout(chatId, descriptionTextView.getText().toString(), info);
|
||||||
}
|
}
|
||||||
if (userNameTextView != null) {
|
|
||||||
String oldUserName = currentChat.username != null ? currentChat.username : "";
|
|
||||||
if (!oldUserName.equals(userNameTextView.getText().toString())) {
|
|
||||||
MessagesController.getInstance().updateChannelUserName(chatId, userNameTextView.getText().toString());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (signMessages != currentChat.signatures) {
|
if (signMessages != currentChat.signatures) {
|
||||||
currentChat.signatures = true;
|
currentChat.signatures = true;
|
||||||
MessagesController.getInstance().toogleChannelSignatures(chatId, signMessages);
|
MessagesController.getInstance().toogleChannelSignatures(chatId, signMessages);
|
||||||
|
@ -346,8 +318,9 @@ public class ChannelEditActivity extends BaseFragment implements AvatarUpdater.A
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
ShadowSectionCell sectionCell = new ShadowSectionCell(context);
|
View lineView = new View(context);
|
||||||
linearLayout.addView(sectionCell, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT));
|
lineView.setBackgroundColor(0xffcfcfcf);
|
||||||
|
linearLayout.addView(lineView, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 1));
|
||||||
|
|
||||||
linearLayout2 = new LinearLayout(context);
|
linearLayout2 = new LinearLayout(context);
|
||||||
linearLayout2.setOrientation(LinearLayout.VERTICAL);
|
linearLayout2.setOrientation(LinearLayout.VERTICAL);
|
||||||
|
@ -355,7 +328,7 @@ public class ChannelEditActivity extends BaseFragment implements AvatarUpdater.A
|
||||||
linearLayout.addView(linearLayout2, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT));
|
linearLayout.addView(linearLayout2, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT));
|
||||||
|
|
||||||
descriptionTextView = new EditText(context);
|
descriptionTextView = new EditText(context);
|
||||||
descriptionTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 18);
|
descriptionTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16);
|
||||||
descriptionTextView.setHintTextColor(0xff979797);
|
descriptionTextView.setHintTextColor(0xff979797);
|
||||||
descriptionTextView.setTextColor(0xff212121);
|
descriptionTextView.setTextColor(0xff212121);
|
||||||
descriptionTextView.setPadding(0, 0, 0, AndroidUtilities.dp(6));
|
descriptionTextView.setPadding(0, 0, 0, AndroidUtilities.dp(6));
|
||||||
|
@ -364,9 +337,9 @@ public class ChannelEditActivity extends BaseFragment implements AvatarUpdater.A
|
||||||
descriptionTextView.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_FLAG_CAP_SENTENCES | InputType.TYPE_TEXT_FLAG_MULTI_LINE | InputType.TYPE_TEXT_FLAG_AUTO_CORRECT);
|
descriptionTextView.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_FLAG_CAP_SENTENCES | InputType.TYPE_TEXT_FLAG_MULTI_LINE | InputType.TYPE_TEXT_FLAG_AUTO_CORRECT);
|
||||||
descriptionTextView.setImeOptions(EditorInfo.IME_ACTION_DONE);
|
descriptionTextView.setImeOptions(EditorInfo.IME_ACTION_DONE);
|
||||||
inputFilters = new InputFilter[1];
|
inputFilters = new InputFilter[1];
|
||||||
inputFilters[0] = new InputFilter.LengthFilter(120);
|
inputFilters[0] = new InputFilter.LengthFilter(255);
|
||||||
descriptionTextView.setFilters(inputFilters);
|
descriptionTextView.setFilters(inputFilters);
|
||||||
descriptionTextView.setHint(LocaleController.getString("DescriptionPlaceholder", R.string.DescriptionPlaceholder));
|
descriptionTextView.setHint(LocaleController.getString("DescriptionOptionalPlaceholder", R.string.DescriptionOptionalPlaceholder));
|
||||||
AndroidUtilities.clearCursorDrawable(descriptionTextView);
|
AndroidUtilities.clearCursorDrawable(descriptionTextView);
|
||||||
linearLayout2.addView(descriptionTextView, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, 17, 12, 17, 6));
|
linearLayout2.addView(descriptionTextView, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, 17, 12, 17, 6));
|
||||||
descriptionTextView.setOnEditorActionListener(new TextView.OnEditorActionListener() {
|
descriptionTextView.setOnEditorActionListener(new TextView.OnEditorActionListener() {
|
||||||
|
@ -396,148 +369,68 @@ public class ChannelEditActivity extends BaseFragment implements AvatarUpdater.A
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
TextInfoPrivacyCell infoCell = new TextInfoPrivacyCell(context);
|
ShadowSectionCell sectionCell = new ShadowSectionCell(context);
|
||||||
if (currentChat.megagroup) {
|
sectionCell.setSize(20);
|
||||||
infoCell.setText(LocaleController.getString("DescriptionInfoMega", R.string.DescriptionInfoMega));
|
linearLayout.addView(sectionCell, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT));
|
||||||
infoCell.setBackgroundResource(currentChat.creator ? R.drawable.greydivider : R.drawable.greydivider_bottom);
|
|
||||||
} else {
|
|
||||||
infoCell.setText(LocaleController.getString("DescriptionInfo", R.string.DescriptionInfo));
|
|
||||||
infoCell.setBackgroundResource(R.drawable.greydivider);
|
|
||||||
}
|
|
||||||
linearLayout.addView(infoCell, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT));
|
|
||||||
|
|
||||||
if (/*BuildVars.DEBUG_VERSION && currentChat.megagroup && currentChat.creator || */!currentChat.megagroup) {
|
if (currentChat.megagroup || !currentChat.megagroup) {
|
||||||
linearLayout2 = new LinearLayout(context);
|
|
||||||
linearLayout2.setOrientation(LinearLayout.VERTICAL);
|
|
||||||
linearLayout2.setBackgroundColor(0xffffffff);
|
|
||||||
linearLayout2.setPadding(0, 0, 0, AndroidUtilities.dp(7));
|
|
||||||
linearLayout.addView(linearLayout2, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT));
|
|
||||||
|
|
||||||
LinearLayout publicContainer = new LinearLayout(context);
|
|
||||||
publicContainer.setOrientation(LinearLayout.HORIZONTAL);
|
|
||||||
linearLayout2.addView(publicContainer, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 36, 17, 7, 17, 0));
|
|
||||||
|
|
||||||
EditText editText = new EditText(context);
|
|
||||||
editText.setText("telegram.me/");
|
|
||||||
editText.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 18);
|
|
||||||
editText.setHintTextColor(0xff979797);
|
|
||||||
editText.setTextColor(0xff212121);
|
|
||||||
editText.setMaxLines(1);
|
|
||||||
editText.setLines(1);
|
|
||||||
editText.setEnabled(false);
|
|
||||||
editText.setBackgroundDrawable(null);
|
|
||||||
editText.setPadding(0, 0, 0, 0);
|
|
||||||
editText.setSingleLine(true);
|
|
||||||
editText.setInputType(InputType.TYPE_TEXT_FLAG_MULTI_LINE | InputType.TYPE_TEXT_FLAG_AUTO_CORRECT);
|
|
||||||
editText.setImeOptions(EditorInfo.IME_ACTION_DONE);
|
|
||||||
publicContainer.addView(editText, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, 36));
|
|
||||||
|
|
||||||
userNameTextView = new EditText(context);
|
|
||||||
userNameTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 18);
|
|
||||||
userNameTextView.setHintTextColor(0xff979797);
|
|
||||||
userNameTextView.setTextColor(0xff212121);
|
|
||||||
userNameTextView.setMaxLines(1);
|
|
||||||
userNameTextView.setLines(1);
|
|
||||||
userNameTextView.setBackgroundDrawable(null);
|
|
||||||
userNameTextView.setPadding(0, 0, 0, 0);
|
|
||||||
userNameTextView.setSingleLine(true);
|
|
||||||
userNameTextView.setText(currentChat.username);
|
|
||||||
userNameTextView.setInputType(InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS | InputType.TYPE_TEXT_FLAG_MULTI_LINE | InputType.TYPE_TEXT_FLAG_AUTO_CORRECT);
|
|
||||||
userNameTextView.setImeOptions(EditorInfo.IME_ACTION_DONE);
|
|
||||||
userNameTextView.setHint(LocaleController.getString("ChannelUsernamePlaceholder", R.string.ChannelUsernamePlaceholder));
|
|
||||||
userNameTextView.setOnFocusChangeListener(new View.OnFocusChangeListener() {
|
|
||||||
@Override
|
|
||||||
public void onFocusChange(View v, boolean hasFocus) {
|
|
||||||
if (wasPrivate && hasFocus && !privateAlertShown) {
|
|
||||||
AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity());
|
|
||||||
builder.setTitle(LocaleController.getString("AppName", R.string.AppName));
|
|
||||||
if (currentChat.megagroup) {
|
|
||||||
//builder.setMessage(LocaleController.getString("MegaWasPrivateAlert", R.string.MegaWasPrivateAlert));
|
|
||||||
} else {
|
|
||||||
builder.setMessage(LocaleController.getString("ChannelWasPrivateAlert", R.string.ChannelWasPrivateAlert));
|
|
||||||
}
|
|
||||||
builder.setPositiveButton(LocaleController.getString("Close", R.string.Close), null);
|
|
||||||
showDialog(builder.create());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
AndroidUtilities.clearCursorDrawable(userNameTextView);
|
|
||||||
publicContainer.addView(userNameTextView, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 36));
|
|
||||||
userNameTextView.addTextChangedListener(new TextWatcher() {
|
|
||||||
@Override
|
|
||||||
public void beforeTextChanged(CharSequence charSequence, int i, int i2, int i3) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onTextChanged(CharSequence charSequence, int i, int i2, int i3) {
|
|
||||||
checkUserName(userNameTextView.getText().toString(), false);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void afterTextChanged(Editable editable) {
|
|
||||||
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
checkTextView = new TextView(context);
|
|
||||||
checkTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 15);
|
|
||||||
checkTextView.setGravity(LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT);
|
|
||||||
checkTextView.setVisibility(View.GONE);
|
|
||||||
linearLayout2.addView(checkTextView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT, 17, 3, 17, 7));
|
|
||||||
|
|
||||||
infoCell = new TextInfoPrivacyCell(context);
|
|
||||||
infoCell.setBackgroundResource(R.drawable.greydivider);
|
|
||||||
if (currentChat.megagroup) {
|
|
||||||
//infoCell.setText(LocaleController.getString("MegaUsernameHelp", R.string.MegaUsernameHelp));
|
|
||||||
} else {
|
|
||||||
infoCell.setText(LocaleController.getString("ChannelUsernameHelp", R.string.ChannelUsernameHelp));
|
|
||||||
}
|
|
||||||
linearLayout.addView(infoCell, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT));
|
|
||||||
}
|
|
||||||
|
|
||||||
/*frameLayout = new FrameLayoutFixed(context);
|
|
||||||
frameLayout.setBackgroundColor(0xffffffff);
|
|
||||||
linearLayout.addView(frameLayout, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT));
|
|
||||||
|
|
||||||
TextCheckCell commentsCell = new TextCheckCell(context);
|
|
||||||
commentsCell.setTextAndCheck(LocaleController.getString("Comments", R.string.Comments), allowComments, false);
|
|
||||||
commentsCell.setBackgroundResource(R.drawable.list_selector);
|
|
||||||
frameLayout.addView(commentsCell, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT));
|
|
||||||
commentsCell.setOnClickListener(new View.OnClickListener() {
|
|
||||||
@Override
|
|
||||||
public void onClick(View v) {
|
|
||||||
allowComments = !allowComments;
|
|
||||||
((TextCheckCell) v).setChecked(allowComments);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
infoCell = new TextInfoPrivacyCell(context);
|
|
||||||
infoCell.setText(LocaleController.getString("CommentsInfo", R.string.CommentsInfo));
|
|
||||||
infoCell.setBackgroundResource(R.drawable.greydivider);
|
|
||||||
linearLayout.addView(infoCell, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT));*/
|
|
||||||
|
|
||||||
if (!currentChat.megagroup && currentChat.creator) {
|
|
||||||
frameLayout = new FrameLayoutFixed(context);
|
frameLayout = new FrameLayoutFixed(context);
|
||||||
frameLayout.setBackgroundColor(0xffffffff);
|
frameLayout.setBackgroundColor(0xffffffff);
|
||||||
linearLayout.addView(frameLayout, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT));
|
linearLayout.addView(frameLayout, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT));
|
||||||
|
|
||||||
TextCheckCell textCell = new TextCheckCell(context);
|
typeCell = new TextSettingsCell(context);
|
||||||
textCell.setBackgroundResource(R.drawable.list_selector);
|
updateTypeCell();
|
||||||
textCell.setTextAndCheck(LocaleController.getString("ChannelSignMessages", R.string.ChannelSignMessages), signMessages, false);
|
typeCell.setBackgroundResource(R.drawable.list_selector);
|
||||||
frameLayout.addView(textCell, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT));
|
frameLayout.addView(typeCell, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT));
|
||||||
textCell.setOnClickListener(new View.OnClickListener() {
|
//TODO
|
||||||
@Override
|
|
||||||
public void onClick(View v) {
|
|
||||||
signMessages = !signMessages;
|
|
||||||
((TextCheckCell) v).setChecked(signMessages);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
infoCell = new TextInfoPrivacyCell(context);
|
lineView = new View(context);
|
||||||
infoCell.setBackgroundResource(R.drawable.greydivider);
|
lineView.setBackgroundColor(0xffcfcfcf);
|
||||||
infoCell.setText(LocaleController.getString("ChannelSignMessagesInfo", R.string.ChannelSignMessagesInfo));
|
linearLayout.addView(lineView, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 1));
|
||||||
linearLayout.addView(infoCell, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT));
|
|
||||||
|
frameLayout = new FrameLayoutFixed(context);
|
||||||
|
frameLayout.setBackgroundColor(0xffffffff);
|
||||||
|
linearLayout.addView(frameLayout, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT));
|
||||||
|
|
||||||
|
if (!currentChat.megagroup) {
|
||||||
|
TextCheckCell textCheckCell = new TextCheckCell(context);
|
||||||
|
textCheckCell.setBackgroundResource(R.drawable.list_selector);
|
||||||
|
textCheckCell.setTextAndCheck(LocaleController.getString("ChannelSignMessages", R.string.ChannelSignMessages), signMessages, false);
|
||||||
|
frameLayout.addView(textCheckCell, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT));
|
||||||
|
textCheckCell.setOnClickListener(new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
signMessages = !signMessages;
|
||||||
|
((TextCheckCell) v).setChecked(signMessages);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
TextInfoPrivacyCell infoCell = new TextInfoPrivacyCell(context);
|
||||||
|
infoCell.setBackgroundResource(R.drawable.greydivider);
|
||||||
|
infoCell.setText(LocaleController.getString("ChannelSignMessagesInfo", R.string.ChannelSignMessagesInfo));
|
||||||
|
linearLayout.addView(infoCell, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT));
|
||||||
|
} else {
|
||||||
|
adminCell = new TextSettingsCell(context);
|
||||||
|
updateAdminCell();
|
||||||
|
adminCell.setBackgroundResource(R.drawable.list_selector);
|
||||||
|
frameLayout.addView(adminCell, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT));
|
||||||
|
adminCell.setOnClickListener(new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
Bundle args = new Bundle();
|
||||||
|
args.putInt("chat_id", chatId);
|
||||||
|
args.putInt("type", 1);
|
||||||
|
presentFragment(new ChannelUsersActivity(args));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
sectionCell = new ShadowSectionCell(context);
|
||||||
|
sectionCell.setSize(20);
|
||||||
|
linearLayout.addView(sectionCell, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT));
|
||||||
|
if (!currentChat.creator) {
|
||||||
|
sectionCell.setBackgroundResource(R.drawable.greydivider_bottom);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (currentChat.creator) {
|
if (currentChat.creator) {
|
||||||
|
@ -582,7 +475,7 @@ public class ChannelEditActivity extends BaseFragment implements AvatarUpdater.A
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
infoCell = new TextInfoPrivacyCell(context);
|
TextInfoPrivacyCell infoCell = new TextInfoPrivacyCell(context);
|
||||||
infoCell.setBackgroundResource(R.drawable.greydivider_bottom);
|
infoCell.setBackgroundResource(R.drawable.greydivider_bottom);
|
||||||
if (currentChat.megagroup) {
|
if (currentChat.megagroup) {
|
||||||
infoCell.setText(LocaleController.getString("MegaDeleteInfo", R.string.MegaDeleteInfo));
|
infoCell.setText(LocaleController.getString("MegaDeleteInfo", R.string.MegaDeleteInfo));
|
||||||
|
@ -592,6 +485,27 @@ public class ChannelEditActivity extends BaseFragment implements AvatarUpdater.A
|
||||||
linearLayout.addView(infoCell, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT));
|
linearLayout.addView(infoCell, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*frameLayout = new FrameLayoutFixed(context);
|
||||||
|
frameLayout.setBackgroundColor(0xffffffff);
|
||||||
|
linearLayout.addView(frameLayout, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT));
|
||||||
|
|
||||||
|
TextCheckCell commentsCell = new TextCheckCell(context);
|
||||||
|
commentsCell.setTextAndCheck(LocaleController.getString("Comments", R.string.Comments), allowComments, false);
|
||||||
|
commentsCell.setBackgroundResource(R.drawable.list_selector);
|
||||||
|
frameLayout.addView(commentsCell, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT));
|
||||||
|
commentsCell.setOnClickListener(new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
allowComments = !allowComments;
|
||||||
|
((TextCheckCell) v).setChecked(allowComments);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
infoCell = new TextInfoPrivacyCell(context);
|
||||||
|
infoCell.setText(LocaleController.getString("CommentsInfo", R.string.CommentsInfo));
|
||||||
|
infoCell.setBackgroundResource(R.drawable.greydivider);
|
||||||
|
linearLayout.addView(infoCell, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT));*/
|
||||||
|
|
||||||
nameTextView.setText(currentChat.title);
|
nameTextView.setText(currentChat.title);
|
||||||
nameTextView.setSelection(nameTextView.length());
|
nameTextView.setSelection(nameTextView.length());
|
||||||
if (info != null) {
|
if (info != null) {
|
||||||
|
@ -616,6 +530,13 @@ public class ChannelEditActivity extends BaseFragment implements AvatarUpdater.A
|
||||||
descriptionTextView.setText(chatFull.about);
|
descriptionTextView.setText(chatFull.about);
|
||||||
}
|
}
|
||||||
info = chatFull;
|
info = chatFull;
|
||||||
|
updateAdminCell();
|
||||||
|
updateTypeCell();
|
||||||
|
}
|
||||||
|
} else if (id == NotificationCenter.updateInterfaces) {
|
||||||
|
int updateMask = (Integer) args[0];
|
||||||
|
if ((updateMask & MessagesController.UPDATE_MASK_CHANNEL) != 0) {
|
||||||
|
updateTypeCell();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -668,153 +589,46 @@ public class ChannelEditActivity extends BaseFragment implements AvatarUpdater.A
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean checkUserName(final String name, boolean alert) {
|
public void setInfo(TLRPC.ChatFull chatFull) {
|
||||||
if (name != null && name.length() > 0) {
|
info = chatFull;
|
||||||
checkTextView.setVisibility(View.VISIBLE);
|
|
||||||
} else {
|
|
||||||
checkTextView.setVisibility(View.GONE);
|
|
||||||
}
|
|
||||||
if (alert && name.length() == 0) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (checkRunnable != null) {
|
|
||||||
AndroidUtilities.cancelRunOnUIThread(checkRunnable);
|
|
||||||
checkRunnable = null;
|
|
||||||
lastCheckName = null;
|
|
||||||
if (checkReqId != 0) {
|
|
||||||
ConnectionsManager.getInstance().cancelRequest(checkReqId, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
lastNameAvailable = false;
|
|
||||||
if (name != null) {
|
|
||||||
if (name.startsWith("_") || name.endsWith("_")) {
|
|
||||||
checkTextView.setText(LocaleController.getString("LinkInvalid", R.string.LinkInvalid));
|
|
||||||
checkTextView.setTextColor(0xffcf3030);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
for (int a = 0; a < name.length(); a++) {
|
|
||||||
char ch = name.charAt(a);
|
|
||||||
if (a == 0 && ch >= '0' && ch <= '9') {
|
|
||||||
if (currentChat.megagroup) {
|
|
||||||
if (alert) {
|
|
||||||
//showErrorAlert(LocaleController.getString("LinkInvalidStartNumberMega", R.string.LinkInvalidStartNumberMega));
|
|
||||||
} else {
|
|
||||||
//checkTextView.setText(LocaleController.getString("LinkInvalidStartNumberMega", R.string.LinkInvalidStartNumberMega));
|
|
||||||
checkTextView.setTextColor(0xffcf3030);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (alert) {
|
|
||||||
showErrorAlert(LocaleController.getString("LinkInvalidStartNumber", R.string.LinkInvalidStartNumber));
|
|
||||||
} else {
|
|
||||||
checkTextView.setText(LocaleController.getString("LinkInvalidStartNumber", R.string.LinkInvalidStartNumber));
|
|
||||||
checkTextView.setTextColor(0xffcf3030);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (!(ch >= '0' && ch <= '9' || ch >= 'a' && ch <= 'z' || ch >= 'A' && ch <= 'Z' || ch == '_')) {
|
|
||||||
if (alert) {
|
|
||||||
showErrorAlert(LocaleController.getString("LinkInvalid", R.string.LinkInvalid));
|
|
||||||
} else {
|
|
||||||
checkTextView.setText(LocaleController.getString("LinkInvalid", R.string.LinkInvalid));
|
|
||||||
checkTextView.setTextColor(0xffcf3030);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (name == null || name.length() < 5) {
|
|
||||||
if (currentChat.megagroup) {
|
|
||||||
if (alert) {
|
|
||||||
//showErrorAlert(LocaleController.getString("LinkInvalidShortMega", R.string.LinkInvalidShortMega));
|
|
||||||
} else {
|
|
||||||
//checkTextView.setText(LocaleController.getString("LinkInvalidShortMega", R.string.LinkInvalidShortMega));
|
|
||||||
checkTextView.setTextColor(0xffcf3030);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (alert) {
|
|
||||||
showErrorAlert(LocaleController.getString("LinkInvalidShort", R.string.LinkInvalidShort));
|
|
||||||
} else {
|
|
||||||
checkTextView.setText(LocaleController.getString("LinkInvalidShort", R.string.LinkInvalidShort));
|
|
||||||
checkTextView.setTextColor(0xffcf3030);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (name.length() > 32) {
|
|
||||||
if (alert) {
|
|
||||||
showErrorAlert(LocaleController.getString("LinkInvalidLong", R.string.LinkInvalidLong));
|
|
||||||
} else {
|
|
||||||
checkTextView.setText(LocaleController.getString("LinkInvalidLong", R.string.LinkInvalidLong));
|
|
||||||
checkTextView.setTextColor(0xffcf3030);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!alert) {
|
|
||||||
checkTextView.setText(LocaleController.getString("LinkChecking", R.string.LinkChecking));
|
|
||||||
checkTextView.setTextColor(0xff6d6d72);
|
|
||||||
lastCheckName = name;
|
|
||||||
checkRunnable = new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
TLRPC.TL_channels_checkUsername req = new TLRPC.TL_channels_checkUsername();
|
|
||||||
req.username = name;
|
|
||||||
req.channel = MessagesController.getInputChannel(chatId);
|
|
||||||
checkReqId = ConnectionsManager.getInstance().sendRequest(req, new RequestDelegate() {
|
|
||||||
@Override
|
|
||||||
public void run(final TLObject response, final TLRPC.TL_error error) {
|
|
||||||
AndroidUtilities.runOnUIThread(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
checkReqId = 0;
|
|
||||||
if (lastCheckName != null && lastCheckName.equals(name)) {
|
|
||||||
if (error == null && response instanceof TLRPC.TL_boolTrue) {
|
|
||||||
checkTextView.setText(LocaleController.formatString("LinkAvailable", R.string.LinkAvailable, name));
|
|
||||||
checkTextView.setTextColor(0xff26972c);
|
|
||||||
lastNameAvailable = true;
|
|
||||||
} else {
|
|
||||||
if (error != null && error.text.equals("CHANNELS_ADMIN_PUBLIC_TOO_MUCH")) {
|
|
||||||
checkTextView.setText(LocaleController.getString("ChannelPublicLimitReached", R.string.ChannelPublicLimitReached));
|
|
||||||
} else {
|
|
||||||
checkTextView.setText(LocaleController.getString("LinkInUse", R.string.LinkInUse));
|
|
||||||
}
|
|
||||||
checkTextView.setTextColor(0xffcf3030);
|
|
||||||
lastNameAvailable = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}, ConnectionsManager.RequestFlagFailOnServerErrors);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
AndroidUtilities.runOnUIThread(checkRunnable, 300);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void showErrorAlert(String error) {
|
private void updateTypeCell() {
|
||||||
if (getParentActivity() == null) {
|
String type = currentChat.username == null || currentChat.username.length() == 0 ? LocaleController.getString("ChannelTypePrivate", R.string.ChannelTypePrivate) : LocaleController.getString("ChannelTypePublic", R.string.ChannelTypePublic);
|
||||||
|
if (currentChat.megagroup) {
|
||||||
|
typeCell.setTextAndValue(LocaleController.getString("GroupType", R.string.GroupType), type, false);
|
||||||
|
} else {
|
||||||
|
typeCell.setTextAndValue(LocaleController.getString("ChannelType", R.string.ChannelType), type, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (currentChat.creator && (info == null || info.can_set_username)) {
|
||||||
|
typeCell.setOnClickListener(new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
Bundle args = new Bundle();
|
||||||
|
args.putInt("chat_id", chatId);
|
||||||
|
ChannelEditTypeActivity fragment = new ChannelEditTypeActivity(args);
|
||||||
|
fragment.setInfo(info);
|
||||||
|
presentFragment(fragment);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
typeCell.setTextColor(0xff212121);
|
||||||
|
typeCell.setTextValueColor(0xff2f8cc9);
|
||||||
|
} else {
|
||||||
|
typeCell.setOnClickListener(null);
|
||||||
|
typeCell.setTextColor(0xffa8a8a8);
|
||||||
|
typeCell.setTextValueColor(0xffa8a8a8);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateAdminCell() {
|
||||||
|
if (adminCell == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity());
|
if (info != null) {
|
||||||
builder.setTitle(LocaleController.getString("AppName", R.string.AppName));
|
adminCell.setTextAndValue(LocaleController.getString("ChannelAdministrators", R.string.ChannelAdministrators), String.format("%d", info.admins_count), false);
|
||||||
switch (error) {
|
} else {
|
||||||
case "USERNAME_INVALID":
|
adminCell.setText(LocaleController.getString("ChannelAdministrators", R.string.ChannelAdministrators), false);
|
||||||
builder.setMessage(LocaleController.getString("LinkInvalid", R.string.LinkInvalid));
|
|
||||||
break;
|
|
||||||
case "USERNAME_OCCUPIED":
|
|
||||||
builder.setMessage(LocaleController.getString("LinkInUse", R.string.LinkInUse));
|
|
||||||
break;
|
|
||||||
case "USERNAMES_UNAVAILABLE":
|
|
||||||
builder.setMessage(LocaleController.getString("FeatureUnavailable", R.string.FeatureUnavailable));
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
builder.setMessage(LocaleController.getString("ErrorOccurred", R.string.ErrorOccurred));
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), null);
|
|
||||||
showDialog(builder.create());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,544 @@
|
||||||
|
/*
|
||||||
|
* This is the source code of Telegram for Android v. 3.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-2016.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.telegram.ui;
|
||||||
|
|
||||||
|
import android.app.AlertDialog;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.os.Build;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.os.Vibrator;
|
||||||
|
import android.text.Editable;
|
||||||
|
import android.text.InputType;
|
||||||
|
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.EditText;
|
||||||
|
import android.widget.LinearLayout;
|
||||||
|
import android.widget.ScrollView;
|
||||||
|
import android.widget.TextView;
|
||||||
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
import org.telegram.messenger.AndroidUtilities;
|
||||||
|
import org.telegram.messenger.ApplicationLoader;
|
||||||
|
import org.telegram.messenger.FileLog;
|
||||||
|
import org.telegram.messenger.LocaleController;
|
||||||
|
import org.telegram.messenger.MessagesController;
|
||||||
|
import org.telegram.messenger.MessagesStorage;
|
||||||
|
import org.telegram.messenger.NotificationCenter;
|
||||||
|
import org.telegram.messenger.R;
|
||||||
|
import org.telegram.tgnet.ConnectionsManager;
|
||||||
|
import org.telegram.tgnet.RequestDelegate;
|
||||||
|
import org.telegram.tgnet.TLObject;
|
||||||
|
import org.telegram.tgnet.TLRPC;
|
||||||
|
import org.telegram.ui.ActionBar.ActionBar;
|
||||||
|
import org.telegram.ui.ActionBar.ActionBarMenu;
|
||||||
|
import org.telegram.ui.ActionBar.BaseFragment;
|
||||||
|
import org.telegram.ui.Cells.HeaderCell;
|
||||||
|
import org.telegram.ui.Cells.RadioButtonCell;
|
||||||
|
import org.telegram.ui.Cells.ShadowSectionCell;
|
||||||
|
import org.telegram.ui.Cells.TextBlockCell;
|
||||||
|
import org.telegram.ui.Cells.TextInfoPrivacyCell;
|
||||||
|
import org.telegram.ui.Components.LayoutHelper;
|
||||||
|
|
||||||
|
import java.util.concurrent.Semaphore;
|
||||||
|
|
||||||
|
public class ChannelEditTypeActivity extends BaseFragment implements NotificationCenter.NotificationCenterDelegate {
|
||||||
|
|
||||||
|
private LinearLayout linkContainer;
|
||||||
|
private LinearLayout publicContainer;
|
||||||
|
private TextBlockCell privateContainer;
|
||||||
|
private RadioButtonCell radioButtonCell1;
|
||||||
|
private RadioButtonCell radioButtonCell2;
|
||||||
|
private TextInfoPrivacyCell typeInfoCell;
|
||||||
|
private TextView checkTextView;
|
||||||
|
private HeaderCell headerCell;
|
||||||
|
private EditText nameTextView;
|
||||||
|
private boolean isPrivate = false;
|
||||||
|
private boolean loadingInvite;
|
||||||
|
private TLRPC.ExportedChatInvite invite;
|
||||||
|
|
||||||
|
private int checkReqId = 0;
|
||||||
|
private String lastCheckName = null;
|
||||||
|
private Runnable checkRunnable = null;
|
||||||
|
private boolean lastNameAvailable = false;
|
||||||
|
private TLRPC.Chat currentChat;
|
||||||
|
private int chatId;
|
||||||
|
|
||||||
|
private boolean donePressed;
|
||||||
|
|
||||||
|
private final static int done_button = 1;
|
||||||
|
|
||||||
|
public ChannelEditTypeActivity(Bundle args) {
|
||||||
|
super(args);
|
||||||
|
chatId = args.getInt("chat_id", 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
@Override
|
||||||
|
public boolean onFragmentCreate() {
|
||||||
|
currentChat = MessagesController.getInstance().getChat(chatId);
|
||||||
|
if (currentChat == null) {
|
||||||
|
final Semaphore semaphore = new Semaphore(0);
|
||||||
|
MessagesStorage.getInstance().getStorageQueue().postRunnable(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
currentChat = MessagesStorage.getInstance().getChat(chatId);
|
||||||
|
semaphore.release();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
try {
|
||||||
|
semaphore.acquire();
|
||||||
|
} catch (Exception e) {
|
||||||
|
FileLog.e("tmessages", e);
|
||||||
|
}
|
||||||
|
if (currentChat != null) {
|
||||||
|
MessagesController.getInstance().putChat(currentChat, true);
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
isPrivate = currentChat.username == null || currentChat.username.length() == 0;
|
||||||
|
NotificationCenter.getInstance().addObserver(this, NotificationCenter.chatInfoDidLoaded);
|
||||||
|
return super.onFragmentCreate();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onFragmentDestroy() {
|
||||||
|
super.onFragmentDestroy();
|
||||||
|
NotificationCenter.getInstance().removeObserver(this, NotificationCenter.chatInfoDidLoaded);
|
||||||
|
AndroidUtilities.removeAdjustResize(getParentActivity(), classGuid);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onResume() {
|
||||||
|
super.onResume();
|
||||||
|
AndroidUtilities.requestAdjustResize(getParentActivity(), classGuid);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public View createView(Context context) {
|
||||||
|
actionBar.setBackButtonImage(R.drawable.ic_ab_back);
|
||||||
|
actionBar.setAllowOverlayTitle(true);
|
||||||
|
|
||||||
|
actionBar.setActionBarMenuOnItemClick(new ActionBar.ActionBarMenuOnItemClick() {
|
||||||
|
@Override
|
||||||
|
public void onItemClick(int id) {
|
||||||
|
if (id == -1) {
|
||||||
|
finishFragment();
|
||||||
|
} else if (id == done_button) {
|
||||||
|
if (donePressed) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isPrivate && ((currentChat.username == null && nameTextView.length() != 0) || (currentChat.username != null && !currentChat.username.equalsIgnoreCase(nameTextView.getText().toString())))) {
|
||||||
|
if (nameTextView.length() != 0 && !lastNameAvailable) {
|
||||||
|
Vibrator v = (Vibrator) getParentActivity().getSystemService(Context.VIBRATOR_SERVICE);
|
||||||
|
if (v != null) {
|
||||||
|
v.vibrate(200);
|
||||||
|
}
|
||||||
|
AndroidUtilities.shakeView(checkTextView, 2, 0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
donePressed = true;
|
||||||
|
|
||||||
|
String oldUserName = currentChat.username != null ? currentChat.username : "";
|
||||||
|
String newUserName = isPrivate ? "" : nameTextView.getText().toString();
|
||||||
|
if (!oldUserName.equals(newUserName)) {
|
||||||
|
MessagesController.getInstance().updateChannelUserName(chatId, newUserName);
|
||||||
|
}
|
||||||
|
finishFragment();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
ActionBarMenu menu = actionBar.createMenu();
|
||||||
|
menu.addItemWithWidth(done_button, R.drawable.ic_done, AndroidUtilities.dp(56));
|
||||||
|
|
||||||
|
LinearLayout linearLayout;
|
||||||
|
|
||||||
|
fragmentView = new ScrollView(context);
|
||||||
|
fragmentView.setBackgroundColor(0xfff0f0f0);
|
||||||
|
ScrollView scrollView = (ScrollView) fragmentView;
|
||||||
|
scrollView.setFillViewport(true);
|
||||||
|
linearLayout = new LinearLayout(context);
|
||||||
|
scrollView.addView(linearLayout, new ScrollView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
|
||||||
|
|
||||||
|
linearLayout.setOrientation(LinearLayout.VERTICAL);
|
||||||
|
|
||||||
|
if (currentChat.megagroup) {
|
||||||
|
actionBar.setTitle(LocaleController.getString("GroupType", R.string.GroupType));
|
||||||
|
} else {
|
||||||
|
actionBar.setTitle(LocaleController.getString("ChannelType", R.string.ChannelType));
|
||||||
|
}
|
||||||
|
|
||||||
|
LinearLayout linearLayout2 = new LinearLayout(context);
|
||||||
|
linearLayout2.setOrientation(LinearLayout.VERTICAL);
|
||||||
|
linearLayout2.setBackgroundColor(0xffffffff);
|
||||||
|
linearLayout.addView(linearLayout2, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT));
|
||||||
|
|
||||||
|
radioButtonCell1 = new RadioButtonCell(context);
|
||||||
|
radioButtonCell1.setBackgroundResource(R.drawable.list_selector);
|
||||||
|
if (currentChat.megagroup) {
|
||||||
|
radioButtonCell1.setTextAndValue(LocaleController.getString("MegaPublic", R.string.MegaPublic), LocaleController.getString("MegaPublicInfo", R.string.MegaPublicInfo), !isPrivate, false);
|
||||||
|
} else {
|
||||||
|
radioButtonCell1.setTextAndValue(LocaleController.getString("ChannelPublic", R.string.ChannelPublic), LocaleController.getString("ChannelPublicInfo", R.string.ChannelPublicInfo), !isPrivate, false);
|
||||||
|
}
|
||||||
|
linearLayout2.addView(radioButtonCell1, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT));
|
||||||
|
radioButtonCell1.setOnClickListener(new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
if (!isPrivate) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
isPrivate = false;
|
||||||
|
updatePrivatePublic();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
radioButtonCell2 = new RadioButtonCell(context);
|
||||||
|
radioButtonCell2.setBackgroundResource(R.drawable.list_selector);
|
||||||
|
if (currentChat.megagroup) {
|
||||||
|
radioButtonCell2.setTextAndValue(LocaleController.getString("MegaPrivate", R.string.MegaPrivate), LocaleController.getString("MegaPrivateInfo", R.string.MegaPrivateInfo), isPrivate, false);
|
||||||
|
} else {
|
||||||
|
radioButtonCell2.setTextAndValue(LocaleController.getString("ChannelPrivate", R.string.ChannelPrivate), LocaleController.getString("ChannelPrivateInfo", R.string.ChannelPrivateInfo), isPrivate, false);
|
||||||
|
}
|
||||||
|
linearLayout2.addView(radioButtonCell2, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT));
|
||||||
|
radioButtonCell2.setOnClickListener(new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
if (isPrivate) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
isPrivate = true;
|
||||||
|
updatePrivatePublic();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
ShadowSectionCell sectionCell = new ShadowSectionCell(context);
|
||||||
|
linearLayout.addView(sectionCell, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT));
|
||||||
|
|
||||||
|
linkContainer = new LinearLayout(context);
|
||||||
|
linkContainer.setOrientation(LinearLayout.VERTICAL);
|
||||||
|
linkContainer.setBackgroundColor(0xffffffff);
|
||||||
|
linearLayout.addView(linkContainer, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT));
|
||||||
|
|
||||||
|
headerCell = new HeaderCell(context);
|
||||||
|
linkContainer.addView(headerCell);
|
||||||
|
|
||||||
|
publicContainer = new LinearLayout(context);
|
||||||
|
publicContainer.setOrientation(LinearLayout.HORIZONTAL);
|
||||||
|
linkContainer.addView(publicContainer, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 36, 17, 7, 17, 0));
|
||||||
|
|
||||||
|
EditText editText = new EditText(context);
|
||||||
|
editText.setText("telegram.me/");
|
||||||
|
editText.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 18);
|
||||||
|
editText.setHintTextColor(0xff979797);
|
||||||
|
editText.setTextColor(0xff212121);
|
||||||
|
editText.setMaxLines(1);
|
||||||
|
editText.setLines(1);
|
||||||
|
editText.setEnabled(false);
|
||||||
|
editText.setBackgroundDrawable(null);
|
||||||
|
editText.setPadding(0, 0, 0, 0);
|
||||||
|
editText.setSingleLine(true);
|
||||||
|
editText.setInputType(InputType.TYPE_TEXT_FLAG_MULTI_LINE | InputType.TYPE_TEXT_FLAG_AUTO_CORRECT);
|
||||||
|
editText.setImeOptions(EditorInfo.IME_ACTION_DONE);
|
||||||
|
publicContainer.addView(editText, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, 36));
|
||||||
|
|
||||||
|
nameTextView = new EditText(context);
|
||||||
|
nameTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 18);
|
||||||
|
if (!isPrivate) {
|
||||||
|
nameTextView.setText(currentChat.username);
|
||||||
|
}
|
||||||
|
nameTextView.setHintTextColor(0xff979797);
|
||||||
|
nameTextView.setTextColor(0xff212121);
|
||||||
|
nameTextView.setMaxLines(1);
|
||||||
|
nameTextView.setLines(1);
|
||||||
|
nameTextView.setBackgroundDrawable(null);
|
||||||
|
nameTextView.setPadding(0, 0, 0, 0);
|
||||||
|
nameTextView.setSingleLine(true);
|
||||||
|
nameTextView.setInputType(InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS | InputType.TYPE_TEXT_FLAG_MULTI_LINE | InputType.TYPE_TEXT_FLAG_AUTO_CORRECT);
|
||||||
|
nameTextView.setImeOptions(EditorInfo.IME_ACTION_DONE);
|
||||||
|
nameTextView.setHint(LocaleController.getString("ChannelUsernamePlaceholder", R.string.ChannelUsernamePlaceholder));
|
||||||
|
AndroidUtilities.clearCursorDrawable(nameTextView);
|
||||||
|
publicContainer.addView(nameTextView, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 36));
|
||||||
|
nameTextView.addTextChangedListener(new TextWatcher() {
|
||||||
|
@Override
|
||||||
|
public void beforeTextChanged(CharSequence charSequence, int i, int i2, int i3) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onTextChanged(CharSequence charSequence, int i, int i2, int i3) {
|
||||||
|
checkUserName(nameTextView.getText().toString(), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void afterTextChanged(Editable editable) {
|
||||||
|
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
privateContainer = new TextBlockCell(context);
|
||||||
|
privateContainer.setBackgroundResource(R.drawable.list_selector);
|
||||||
|
linkContainer.addView(privateContainer);
|
||||||
|
privateContainer.setOnClickListener(new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
if (invite == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
if (Build.VERSION.SDK_INT < 11) {
|
||||||
|
android.text.ClipboardManager clipboard = (android.text.ClipboardManager) ApplicationLoader.applicationContext.getSystemService(Context.CLIPBOARD_SERVICE);
|
||||||
|
clipboard.setText(invite.link);
|
||||||
|
} else {
|
||||||
|
android.content.ClipboardManager clipboard = (android.content.ClipboardManager) ApplicationLoader.applicationContext.getSystemService(Context.CLIPBOARD_SERVICE);
|
||||||
|
android.content.ClipData clip = android.content.ClipData.newPlainText("label", invite.link);
|
||||||
|
clipboard.setPrimaryClip(clip);
|
||||||
|
}
|
||||||
|
Toast.makeText(getParentActivity(), LocaleController.getString("LinkCopied", R.string.LinkCopied), Toast.LENGTH_SHORT).show();
|
||||||
|
} catch (Exception e) {
|
||||||
|
FileLog.e("tmessages", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
checkTextView = new TextView(context);
|
||||||
|
checkTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 15);
|
||||||
|
checkTextView.setGravity(LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT);
|
||||||
|
checkTextView.setVisibility(View.GONE);
|
||||||
|
linkContainer.addView(checkTextView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT, 17, 3, 17, 7));
|
||||||
|
|
||||||
|
typeInfoCell = new TextInfoPrivacyCell(context);
|
||||||
|
typeInfoCell.setBackgroundResource(R.drawable.greydivider_bottom);
|
||||||
|
linearLayout.addView(typeInfoCell, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT));
|
||||||
|
|
||||||
|
updatePrivatePublic();
|
||||||
|
|
||||||
|
return fragmentView;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void didReceivedNotification(int id, Object... args) {
|
||||||
|
if (id == NotificationCenter.chatInfoDidLoaded) {
|
||||||
|
TLRPC.ChatFull chatFull = (TLRPC.ChatFull) args[0];
|
||||||
|
if (chatFull.id == chatId) {
|
||||||
|
invite = chatFull.exported_invite;
|
||||||
|
updatePrivatePublic();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setInfo(TLRPC.ChatFull chatFull) {
|
||||||
|
if (chatFull != null) {
|
||||||
|
if (chatFull.exported_invite instanceof TLRPC.TL_chatInviteExported) {
|
||||||
|
invite = chatFull.exported_invite;
|
||||||
|
} else {
|
||||||
|
generateLink();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updatePrivatePublic() {
|
||||||
|
radioButtonCell1.setChecked(!isPrivate, true);
|
||||||
|
radioButtonCell2.setChecked(isPrivate, true);
|
||||||
|
if (currentChat.megagroup) {
|
||||||
|
typeInfoCell.setText(isPrivate ? LocaleController.getString("MegaPrivateLinkHelp", R.string.MegaPrivateLinkHelp) : LocaleController.getString("MegaUsernameHelp", R.string.MegaUsernameHelp));
|
||||||
|
headerCell.setText(isPrivate ? LocaleController.getString("ChannelInviteLinkTitle", R.string.ChannelInviteLinkTitle) : LocaleController.getString("ChannelLinkTitle", R.string.ChannelLinkTitle));
|
||||||
|
} else {
|
||||||
|
typeInfoCell.setText(isPrivate ? LocaleController.getString("ChannelPrivateLinkHelp", R.string.ChannelPrivateLinkHelp) : LocaleController.getString("ChannelUsernameHelp", R.string.ChannelUsernameHelp));
|
||||||
|
headerCell.setText(isPrivate ? LocaleController.getString("ChannelInviteLinkTitle", R.string.ChannelInviteLinkTitle) : LocaleController.getString("ChannelLinkTitle", R.string.ChannelLinkTitle));
|
||||||
|
}
|
||||||
|
publicContainer.setVisibility(isPrivate ? View.GONE : View.VISIBLE);
|
||||||
|
privateContainer.setVisibility(isPrivate ? View.VISIBLE : View.GONE);
|
||||||
|
linkContainer.setPadding(0, 0, 0, isPrivate ? 0 : AndroidUtilities.dp(7));
|
||||||
|
privateContainer.setText(invite != null ? invite.link : LocaleController.getString("Loading", R.string.Loading), false);
|
||||||
|
nameTextView.clearFocus();
|
||||||
|
checkTextView.setVisibility(!isPrivate && checkTextView.length() != 0 ? View.VISIBLE : View.GONE);
|
||||||
|
AndroidUtilities.hideKeyboard(nameTextView);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean checkUserName(final String name, boolean alert) {
|
||||||
|
if (name != null && name.length() > 0) {
|
||||||
|
checkTextView.setVisibility(View.VISIBLE);
|
||||||
|
} else {
|
||||||
|
checkTextView.setVisibility(View.GONE);
|
||||||
|
}
|
||||||
|
if (alert && name.length() == 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (checkRunnable != null) {
|
||||||
|
AndroidUtilities.cancelRunOnUIThread(checkRunnable);
|
||||||
|
checkRunnable = null;
|
||||||
|
lastCheckName = null;
|
||||||
|
if (checkReqId != 0) {
|
||||||
|
ConnectionsManager.getInstance().cancelRequest(checkReqId, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
lastNameAvailable = false;
|
||||||
|
if (name != null) {
|
||||||
|
if (name.startsWith("_") || name.endsWith("_")) {
|
||||||
|
checkTextView.setText(LocaleController.getString("LinkInvalid", R.string.LinkInvalid));
|
||||||
|
checkTextView.setTextColor(0xffcf3030);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
for (int a = 0; a < name.length(); a++) {
|
||||||
|
char ch = name.charAt(a);
|
||||||
|
if (a == 0 && ch >= '0' && ch <= '9') {
|
||||||
|
if (currentChat.megagroup) {
|
||||||
|
if (alert) {
|
||||||
|
showErrorAlert(LocaleController.getString("LinkInvalidStartNumberMega", R.string.LinkInvalidStartNumberMega));
|
||||||
|
} else {
|
||||||
|
checkTextView.setText(LocaleController.getString("LinkInvalidStartNumberMega", R.string.LinkInvalidStartNumberMega));
|
||||||
|
checkTextView.setTextColor(0xffcf3030);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (alert) {
|
||||||
|
showErrorAlert(LocaleController.getString("LinkInvalidStartNumber", R.string.LinkInvalidStartNumber));
|
||||||
|
} else {
|
||||||
|
checkTextView.setText(LocaleController.getString("LinkInvalidStartNumber", R.string.LinkInvalidStartNumber));
|
||||||
|
checkTextView.setTextColor(0xffcf3030);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!(ch >= '0' && ch <= '9' || ch >= 'a' && ch <= 'z' || ch >= 'A' && ch <= 'Z' || ch == '_')) {
|
||||||
|
if (alert) {
|
||||||
|
showErrorAlert(LocaleController.getString("LinkInvalid", R.string.LinkInvalid));
|
||||||
|
} else {
|
||||||
|
checkTextView.setText(LocaleController.getString("LinkInvalid", R.string.LinkInvalid));
|
||||||
|
checkTextView.setTextColor(0xffcf3030);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (name == null || name.length() < 5) {
|
||||||
|
if (currentChat.megagroup) {
|
||||||
|
if (alert) {
|
||||||
|
showErrorAlert(LocaleController.getString("LinkInvalidShortMega", R.string.LinkInvalidShortMega));
|
||||||
|
} else {
|
||||||
|
checkTextView.setText(LocaleController.getString("LinkInvalidShortMega", R.string.LinkInvalidShortMega));
|
||||||
|
checkTextView.setTextColor(0xffcf3030);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (alert) {
|
||||||
|
showErrorAlert(LocaleController.getString("LinkInvalidShort", R.string.LinkInvalidShort));
|
||||||
|
} else {
|
||||||
|
checkTextView.setText(LocaleController.getString("LinkInvalidShort", R.string.LinkInvalidShort));
|
||||||
|
checkTextView.setTextColor(0xffcf3030);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (name.length() > 32) {
|
||||||
|
if (alert) {
|
||||||
|
showErrorAlert(LocaleController.getString("LinkInvalidLong", R.string.LinkInvalidLong));
|
||||||
|
} else {
|
||||||
|
checkTextView.setText(LocaleController.getString("LinkInvalidLong", R.string.LinkInvalidLong));
|
||||||
|
checkTextView.setTextColor(0xffcf3030);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!alert) {
|
||||||
|
checkTextView.setText(LocaleController.getString("LinkChecking", R.string.LinkChecking));
|
||||||
|
checkTextView.setTextColor(0xff6d6d72);
|
||||||
|
lastCheckName = name;
|
||||||
|
checkRunnable = new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
TLRPC.TL_channels_checkUsername req = new TLRPC.TL_channels_checkUsername();
|
||||||
|
req.username = name;
|
||||||
|
req.channel = MessagesController.getInputChannel(chatId);
|
||||||
|
checkReqId = ConnectionsManager.getInstance().sendRequest(req, new RequestDelegate() {
|
||||||
|
@Override
|
||||||
|
public void run(final TLObject response, final TLRPC.TL_error error) {
|
||||||
|
AndroidUtilities.runOnUIThread(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
checkReqId = 0;
|
||||||
|
if (lastCheckName != null && lastCheckName.equals(name)) {
|
||||||
|
if (error == null && response instanceof TLRPC.TL_boolTrue) {
|
||||||
|
checkTextView.setText(LocaleController.formatString("LinkAvailable", R.string.LinkAvailable, name));
|
||||||
|
checkTextView.setTextColor(0xff26972c);
|
||||||
|
lastNameAvailable = true;
|
||||||
|
} else {
|
||||||
|
if (error != null && error.text.equals("CHANNELS_ADMIN_PUBLIC_TOO_MUCH")) {
|
||||||
|
checkTextView.setText(LocaleController.getString("ChangePublicLimitReached", R.string.ChangePublicLimitReached));
|
||||||
|
} else {
|
||||||
|
checkTextView.setText(LocaleController.getString("LinkInUse", R.string.LinkInUse));
|
||||||
|
}
|
||||||
|
checkTextView.setTextColor(0xffcf3030);
|
||||||
|
lastNameAvailable = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, ConnectionsManager.RequestFlagFailOnServerErrors);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
AndroidUtilities.runOnUIThread(checkRunnable, 300);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void generateLink() {
|
||||||
|
if (loadingInvite || invite != null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
loadingInvite = true;
|
||||||
|
TLRPC.TL_channels_exportInvite req = new TLRPC.TL_channels_exportInvite();
|
||||||
|
req.channel = MessagesController.getInputChannel(chatId);
|
||||||
|
ConnectionsManager.getInstance().sendRequest(req, new RequestDelegate() {
|
||||||
|
@Override
|
||||||
|
public void run(final TLObject response, final TLRPC.TL_error error) {
|
||||||
|
AndroidUtilities.runOnUIThread(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
if (error == null) {
|
||||||
|
invite = (TLRPC.ExportedChatInvite) response;
|
||||||
|
}
|
||||||
|
loadingInvite = false;
|
||||||
|
privateContainer.setText(invite != null ? invite.link : LocaleController.getString("Loading", R.string.Loading), false);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void showErrorAlert(String error) {
|
||||||
|
if (getParentActivity() == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity());
|
||||||
|
builder.setTitle(LocaleController.getString("AppName", R.string.AppName));
|
||||||
|
switch (error) {
|
||||||
|
case "USERNAME_INVALID":
|
||||||
|
builder.setMessage(LocaleController.getString("LinkInvalid", R.string.LinkInvalid));
|
||||||
|
break;
|
||||||
|
case "USERNAME_OCCUPIED":
|
||||||
|
builder.setMessage(LocaleController.getString("LinkInUse", R.string.LinkInUse));
|
||||||
|
break;
|
||||||
|
case "USERNAMES_UNAVAILABLE":
|
||||||
|
builder.setMessage(LocaleController.getString("FeatureUnavailable", R.string.FeatureUnavailable));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
builder.setMessage(LocaleController.getString("ErrorOccurred", R.string.ErrorOccurred));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), null);
|
||||||
|
showDialog(builder.create());
|
||||||
|
}
|
||||||
|
}
|
|
@ -560,7 +560,7 @@ public class ChannelUsersActivity extends BaseFragment implements NotificationCe
|
||||||
int viewType = getItemViewType(i);
|
int viewType = getItemViewType(i);
|
||||||
if (viewType == 0) {
|
if (viewType == 0) {
|
||||||
if (view == null) {
|
if (view == null) {
|
||||||
view = new UserCell(mContext, 1, 0);
|
view = new UserCell(mContext, 1, 0, false);
|
||||||
view.setBackgroundColor(0xffffffff);
|
view.setBackgroundColor(0xffffffff);
|
||||||
}
|
}
|
||||||
UserCell userCell = (UserCell) view;
|
UserCell userCell = (UserCell) view;
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -14,6 +14,7 @@ import android.app.Dialog;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.DialogInterface;
|
import android.content.DialogInterface;
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
|
import android.os.Bundle;
|
||||||
|
|
||||||
import org.telegram.messenger.AndroidUtilities;
|
import org.telegram.messenger.AndroidUtilities;
|
||||||
import org.telegram.messenger.LocaleController;
|
import org.telegram.messenger.LocaleController;
|
||||||
|
@ -22,10 +23,14 @@ import org.telegram.messenger.MessagesStorage;
|
||||||
import org.telegram.messenger.NotificationsController;
|
import org.telegram.messenger.NotificationsController;
|
||||||
import org.telegram.messenger.ApplicationLoader;
|
import org.telegram.messenger.ApplicationLoader;
|
||||||
import org.telegram.messenger.R;
|
import org.telegram.messenger.R;
|
||||||
|
import org.telegram.messenger.Utilities;
|
||||||
import org.telegram.tgnet.ConnectionsManager;
|
import org.telegram.tgnet.ConnectionsManager;
|
||||||
|
import org.telegram.tgnet.RequestDelegate;
|
||||||
|
import org.telegram.tgnet.TLObject;
|
||||||
import org.telegram.tgnet.TLRPC;
|
import org.telegram.tgnet.TLRPC;
|
||||||
import org.telegram.ui.ActionBar.BaseFragment;
|
import org.telegram.ui.ActionBar.BaseFragment;
|
||||||
import org.telegram.ui.ActionBar.BottomSheet;
|
import org.telegram.ui.ActionBar.BottomSheet;
|
||||||
|
import org.telegram.ui.ReportOtherActivity;
|
||||||
|
|
||||||
public class AlertsCreator {
|
public class AlertsCreator {
|
||||||
|
|
||||||
|
@ -82,6 +87,68 @@ public class AlertsCreator {
|
||||||
return builder.create();
|
return builder.create();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Dialog createReportAlert(Context context, final long dialog_id, final BaseFragment parentFragment) {
|
||||||
|
if (context == null || parentFragment == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
BottomSheet.Builder builder = new BottomSheet.Builder(context);
|
||||||
|
builder.setTitle(LocaleController.getString("ReportChat", R.string.ReportChat));
|
||||||
|
CharSequence[] items = new CharSequence[]{
|
||||||
|
LocaleController.getString("ReportChatSpam", R.string.ReportChatSpam),
|
||||||
|
LocaleController.getString("ReportChatViolence", R.string.ReportChatViolence),
|
||||||
|
LocaleController.getString("ReportChatPornography", R.string.ReportChatPornography),
|
||||||
|
LocaleController.getString("ReportChatOther", R.string.ReportChatOther)
|
||||||
|
};
|
||||||
|
builder.setItems(items, new DialogInterface.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(DialogInterface dialogInterface, int i) {
|
||||||
|
if (i == 3) {
|
||||||
|
Bundle args = new Bundle();
|
||||||
|
args.putLong("dialog_id", dialog_id);
|
||||||
|
parentFragment.presentFragment(new ReportOtherActivity(args));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
TLRPC.TL_account_reportPeer req = new TLRPC.TL_account_reportPeer();
|
||||||
|
req.peer = MessagesController.getInputPeer((int) dialog_id);
|
||||||
|
if (i == 0) {
|
||||||
|
req.reason = new TLRPC.TL_inputReportReasonSpam();
|
||||||
|
} else if (i == 1) {
|
||||||
|
req.reason = new TLRPC.TL_inputReportReasonViolence();
|
||||||
|
} else if (i == 2) {
|
||||||
|
req.reason = new TLRPC.TL_inputReportReasonPornography();
|
||||||
|
}
|
||||||
|
ConnectionsManager.getInstance().sendRequest(req, new RequestDelegate() {
|
||||||
|
@Override
|
||||||
|
public void run(TLObject response, TLRPC.TL_error error) {
|
||||||
|
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
return builder.create();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void showFloodWaitAlert(String error, final BaseFragment fragment) {
|
||||||
|
if (error == null || !error.startsWith("FLOOD_WAIT") || fragment == null || fragment.getParentActivity() == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
int time = Utilities.parseInt(error);
|
||||||
|
String timeString;
|
||||||
|
if (time < 60) {
|
||||||
|
timeString = LocaleController.formatPluralString("Seconds", time);
|
||||||
|
} else {
|
||||||
|
timeString = LocaleController.formatPluralString("Minutes", time / 60);
|
||||||
|
}
|
||||||
|
|
||||||
|
AlertDialog.Builder builder = new AlertDialog.Builder(fragment.getParentActivity());
|
||||||
|
builder.setTitle(LocaleController.getString("AppName", R.string.AppName));
|
||||||
|
builder.setMessage(LocaleController.formatString("FloodWaitTime", R.string.FloodWaitTime, timeString));
|
||||||
|
builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), null);
|
||||||
|
fragment.showDialog(builder.create(), true);
|
||||||
|
}
|
||||||
|
|
||||||
public static void showAddUserAlert(String error, final BaseFragment fragment, boolean isChannel) {
|
public static void showAddUserAlert(String error, final BaseFragment fragment, boolean isChannel) {
|
||||||
if (error == null || fragment == null || fragment.getParentActivity() == null) {
|
if (error == null || fragment == null || fragment.getParentActivity() == null) {
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -11,7 +11,9 @@ package org.telegram.ui.Components;
|
||||||
import android.Manifest;
|
import android.Manifest;
|
||||||
import android.annotation.SuppressLint;
|
import android.annotation.SuppressLint;
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
|
import android.app.AlertDialog;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.content.DialogInterface;
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
import android.graphics.Canvas;
|
import android.graphics.Canvas;
|
||||||
|
@ -482,8 +484,13 @@ public class ChatActivityEnterView extends FrameLayoutFixed implements Notificat
|
||||||
emojiButton = new ImageView(context);
|
emojiButton = new ImageView(context);
|
||||||
emojiButton.setImageResource(R.drawable.ic_msg_panel_smiles);
|
emojiButton.setImageResource(R.drawable.ic_msg_panel_smiles);
|
||||||
emojiButton.setScaleType(ImageView.ScaleType.CENTER_INSIDE);
|
emojiButton.setScaleType(ImageView.ScaleType.CENTER_INSIDE);
|
||||||
emojiButton.setPadding(AndroidUtilities.dp(4), AndroidUtilities.dp(1), 0, 0);
|
emojiButton.setPadding(0, AndroidUtilities.dp(1), 0, 0);
|
||||||
frameLayout.addView(emojiButton, LayoutHelper.createFrame(48, 48, Gravity.BOTTOM));
|
if (Build.VERSION.SDK_INT >= 21) {
|
||||||
|
emojiButton.setBackgroundResource(R.drawable.circle_selector);
|
||||||
|
frameLayout.addView(emojiButton, LayoutHelper.createFrame(44, 44, Gravity.BOTTOM | Gravity.LEFT, 4, 0, 0, 2));
|
||||||
|
} else {
|
||||||
|
frameLayout.addView(emojiButton, LayoutHelper.createFrame(48, 48, Gravity.BOTTOM | Gravity.LEFT, 3, 0, 0, 0));
|
||||||
|
}
|
||||||
emojiButton.setOnClickListener(new View.OnClickListener() {
|
emojiButton.setOnClickListener(new View.OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onClick(View view) {
|
public void onClick(View view) {
|
||||||
|
@ -583,7 +590,7 @@ public class ChatActivityEnterView extends FrameLayoutFixed implements Notificat
|
||||||
if (innerTextChange != 2 && before != count && (count - before) > 1) {
|
if (innerTextChange != 2 && before != count && (count - before) > 1) {
|
||||||
processChange = true;
|
processChange = true;
|
||||||
}
|
}
|
||||||
if (!isAsAdmin && message.length() != 0 && lastTypingTimeSend < System.currentTimeMillis() - 5000 && !ignoreTextChange) {
|
if (editingMessageObject == null && !isAsAdmin && message.length() != 0 && lastTypingTimeSend < System.currentTimeMillis() - 5000 && !ignoreTextChange) {
|
||||||
int currentTime = ConnectionsManager.getInstance().getCurrentTime();
|
int currentTime = ConnectionsManager.getInstance().getCurrentTime();
|
||||||
TLRPC.User currentUser = null;
|
TLRPC.User currentUser = null;
|
||||||
if ((int) dialog_id > 0) {
|
if ((int) dialog_id > 0) {
|
||||||
|
@ -633,7 +640,12 @@ public class ChatActivityEnterView extends FrameLayoutFixed implements Notificat
|
||||||
botButton.setImageResource(R.drawable.bot_keyboard2);
|
botButton.setImageResource(R.drawable.bot_keyboard2);
|
||||||
botButton.setScaleType(ImageView.ScaleType.CENTER);
|
botButton.setScaleType(ImageView.ScaleType.CENTER);
|
||||||
botButton.setVisibility(GONE);
|
botButton.setVisibility(GONE);
|
||||||
attachButton.addView(botButton, LayoutHelper.createLinear(48, 48));
|
if (Build.VERSION.SDK_INT >= 21) {
|
||||||
|
botButton.setBackgroundResource(R.drawable.circle_selector);
|
||||||
|
attachButton.addView(botButton, LayoutHelper.createLinear(44, 44, Gravity.CENTER_VERTICAL, 2, 0, 2, 0));
|
||||||
|
} else {
|
||||||
|
attachButton.addView(botButton, LayoutHelper.createLinear(48, 48));
|
||||||
|
}
|
||||||
botButton.setOnClickListener(new OnClickListener() {
|
botButton.setOnClickListener(new OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onClick(View v) {
|
public void onClick(View v) {
|
||||||
|
@ -660,7 +672,12 @@ public class ChatActivityEnterView extends FrameLayoutFixed implements Notificat
|
||||||
asAdminButton.setImageResource(isAsAdmin ? R.drawable.publish_active : R.drawable.publish);
|
asAdminButton.setImageResource(isAsAdmin ? R.drawable.publish_active : R.drawable.publish);
|
||||||
asAdminButton.setScaleType(ImageView.ScaleType.CENTER);
|
asAdminButton.setScaleType(ImageView.ScaleType.CENTER);
|
||||||
asAdminButton.setVisibility(adminModeAvailable ? VISIBLE : GONE);
|
asAdminButton.setVisibility(adminModeAvailable ? VISIBLE : GONE);
|
||||||
attachButton.addView(asAdminButton, LayoutHelper.createLinear(48, 48));
|
if (Build.VERSION.SDK_INT >= 21) {
|
||||||
|
asAdminButton.setBackgroundResource(R.drawable.circle_selector);
|
||||||
|
attachButton.addView(asAdminButton, LayoutHelper.createLinear(44, 44, Gravity.CENTER_VERTICAL, 2, 0, 2, 0));
|
||||||
|
} else {
|
||||||
|
attachButton.addView(asAdminButton, LayoutHelper.createLinear(48, 48));
|
||||||
|
}
|
||||||
asAdminButton.setOnClickListener(new OnClickListener() {
|
asAdminButton.setOnClickListener(new OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onClick(View v) {
|
public void onClick(View v) {
|
||||||
|
@ -676,7 +693,12 @@ public class ChatActivityEnterView extends FrameLayoutFixed implements Notificat
|
||||||
notifyButton.setImageResource(silent ? R.drawable.notify_members_off : R.drawable.notify_members_on);
|
notifyButton.setImageResource(silent ? R.drawable.notify_members_off : R.drawable.notify_members_on);
|
||||||
notifyButton.setScaleType(ImageView.ScaleType.CENTER);
|
notifyButton.setScaleType(ImageView.ScaleType.CENTER);
|
||||||
notifyButton.setVisibility(canWriteToChannel ? VISIBLE : GONE);
|
notifyButton.setVisibility(canWriteToChannel ? VISIBLE : GONE);
|
||||||
attachButton.addView(notifyButton, LayoutHelper.createLinear(48, 48));
|
if (Build.VERSION.SDK_INT >= 21) {
|
||||||
|
notifyButton.setBackgroundResource(R.drawable.circle_selector);
|
||||||
|
attachButton.addView(notifyButton, LayoutHelper.createLinear(44, 44, Gravity.CENTER_VERTICAL, 2, 0, 2, 0));
|
||||||
|
} else {
|
||||||
|
attachButton.addView(notifyButton, LayoutHelper.createLinear(48, 48));
|
||||||
|
}
|
||||||
notifyButton.setOnClickListener(new OnClickListener() {
|
notifyButton.setOnClickListener(new OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onClick(View v) {
|
public void onClick(View v) {
|
||||||
|
@ -689,6 +711,7 @@ public class ChatActivityEnterView extends FrameLayoutFixed implements Notificat
|
||||||
} else {
|
} else {
|
||||||
Toast.makeText(parentActivity, LocaleController.getString("ChannelNotifyMembersInfoOn", R.string.ChannelNotifyMembersInfoOn), Toast.LENGTH_SHORT).show();
|
Toast.makeText(parentActivity, LocaleController.getString("ChannelNotifyMembersInfoOn", R.string.ChannelNotifyMembersInfoOn), Toast.LENGTH_SHORT).show();
|
||||||
}
|
}
|
||||||
|
updateFieldHint();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -802,11 +825,9 @@ public class ChatActivityEnterView extends FrameLayoutFixed implements Notificat
|
||||||
public boolean onTouch(View view, MotionEvent motionEvent) {
|
public boolean onTouch(View view, MotionEvent motionEvent) {
|
||||||
if (motionEvent.getAction() == MotionEvent.ACTION_DOWN) {
|
if (motionEvent.getAction() == MotionEvent.ACTION_DOWN) {
|
||||||
if (parentFragment != null) {
|
if (parentFragment != null) {
|
||||||
if (Build.VERSION.SDK_INT >= 23) {
|
if (Build.VERSION.SDK_INT >= 23 && parentActivity.checkSelfPermission(Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED) {
|
||||||
if (parentActivity.checkSelfPermission(Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED) {
|
parentActivity.requestPermissions(new String[]{Manifest.permission.RECORD_AUDIO}, 3);
|
||||||
parentActivity.requestPermissions(new String[]{Manifest.permission.RECORD_AUDIO}, 3);
|
return false;
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
String action;
|
String action;
|
||||||
|
@ -1171,7 +1192,15 @@ public class ChatActivityEnterView extends FrameLayoutFixed implements Notificat
|
||||||
if (editingMessageObject != null) {
|
if (editingMessageObject != null) {
|
||||||
messageEditText.setHint(editingCaption ? LocaleController.getString("Caption", R.string.Caption) : LocaleController.getString("TypeMessage", R.string.TypeMessage));
|
messageEditText.setHint(editingCaption ? LocaleController.getString("Caption", R.string.Caption) : LocaleController.getString("TypeMessage", R.string.TypeMessage));
|
||||||
} else {
|
} else {
|
||||||
messageEditText.setHint(isAsAdmin ? LocaleController.getString("ChannelBroadcast", R.string.ChannelBroadcast) : LocaleController.getString("ChannelComment", R.string.ChannelComment));
|
if (isAsAdmin) {
|
||||||
|
if (silent) {
|
||||||
|
messageEditText.setHint(LocaleController.getString("ChannelSilentBroadcast", R.string.ChannelSilentBroadcast));
|
||||||
|
} else {
|
||||||
|
messageEditText.setHint(LocaleController.getString("ChannelBroadcast", R.string.ChannelBroadcast));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
messageEditText.setHint(LocaleController.getString("ChannelComment", R.string.ChannelComment));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
messageEditText.setHint(LocaleController.getString("TypeMessage", R.string.TypeMessage));
|
messageEditText.setHint(LocaleController.getString("TypeMessage", R.string.TypeMessage));
|
||||||
|
@ -1764,7 +1793,12 @@ public class ChatActivityEnterView extends FrameLayoutFixed implements Notificat
|
||||||
ViewGroup viewGroup = (ViewGroup) view.getParent();
|
ViewGroup viewGroup = (ViewGroup) view.getParent();
|
||||||
viewGroup.removeView(view);
|
viewGroup.removeView(view);
|
||||||
}
|
}
|
||||||
attachButton.addView(view, LayoutHelper.createLinear(48, 48));
|
if (Build.VERSION.SDK_INT >= 21) {
|
||||||
|
view.setBackgroundResource(R.drawable.circle_selector);
|
||||||
|
attachButton.addView(view, LayoutHelper.createLinear(44, 44, Gravity.CENTER_VERTICAL, 2, 0, 2, 0));
|
||||||
|
} else {
|
||||||
|
attachButton.addView(view, LayoutHelper.createLinear(48, 48));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateBotButton() {
|
private void updateBotButton() {
|
||||||
|
@ -1920,7 +1954,10 @@ public class ChatActivityEnterView extends FrameLayoutFixed implements Notificat
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onGifSelected(TLRPC.Document gif) {
|
public void onGifSelected(TLRPC.Document gif) {
|
||||||
SendMessagesHelper.getInstance().sendMessage((TLRPC.TL_document) gif, null, null, dialog_id, replyingMessageObject, asAdmin(), null);
|
SendMessagesHelper.getInstance().sendSticker(gif, dialog_id, replyingMessageObject, asAdmin());
|
||||||
|
if ((int) dialog_id == 0) {
|
||||||
|
MessagesController.getInstance().saveGif(gif);
|
||||||
|
}
|
||||||
if (delegate != null) {
|
if (delegate != null) {
|
||||||
delegate.onMessageSend(null);
|
delegate.onMessageSend(null);
|
||||||
}
|
}
|
||||||
|
@ -1944,6 +1981,24 @@ public class ChatActivityEnterView extends FrameLayoutFixed implements Notificat
|
||||||
public void onStickersTab(boolean opened) {
|
public void onStickersTab(boolean opened) {
|
||||||
delegate.onStickersTab(opened);
|
delegate.onStickersTab(opened);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onClearEmojiRecent() {
|
||||||
|
if (parentFragment == null || parentActivity == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
AlertDialog.Builder builder = new AlertDialog.Builder(parentActivity);
|
||||||
|
builder.setTitle(LocaleController.getString("AppName", R.string.AppName));
|
||||||
|
builder.setMessage(LocaleController.getString("ClearRecentEmoji", R.string.ClearRecentEmoji));
|
||||||
|
builder.setPositiveButton(LocaleController.getString("ClearButton", R.string.ClearButton).toUpperCase(), new DialogInterface.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(DialogInterface dialogInterface, int i) {
|
||||||
|
emojiView.clearRecentEmoji();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null);
|
||||||
|
parentFragment.showDialog(builder.create());
|
||||||
|
}
|
||||||
});
|
});
|
||||||
emojiView.setVisibility(GONE);
|
emojiView.setVisibility(GONE);
|
||||||
sizeNotifierLayout.addView(emojiView);
|
sizeNotifierLayout.addView(emojiView);
|
||||||
|
@ -2066,6 +2121,10 @@ public class ChatActivityEnterView extends FrameLayoutFixed implements Notificat
|
||||||
return editingCaption;
|
return editingCaption;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean hasAudioToSend() {
|
||||||
|
return audioToSendMessageObject != null;
|
||||||
|
}
|
||||||
|
|
||||||
public void openKeyboard() {
|
public void openKeyboard() {
|
||||||
AndroidUtilities.showKeyboard(messageEditText);
|
AndroidUtilities.showKeyboard(messageEditText);
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,6 +48,7 @@ import org.telegram.messenger.LocaleController;
|
||||||
import org.telegram.messenger.MediaController;
|
import org.telegram.messenger.MediaController;
|
||||||
import org.telegram.messenger.MessagesStorage;
|
import org.telegram.messenger.MessagesStorage;
|
||||||
import org.telegram.messenger.NotificationCenter;
|
import org.telegram.messenger.NotificationCenter;
|
||||||
|
import org.telegram.messenger.Utilities;
|
||||||
import org.telegram.messenger.query.StickersQuery;
|
import org.telegram.messenger.query.StickersQuery;
|
||||||
import org.telegram.messenger.FileLog;
|
import org.telegram.messenger.FileLog;
|
||||||
import org.telegram.messenger.R;
|
import org.telegram.messenger.R;
|
||||||
|
@ -77,6 +78,7 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific
|
||||||
void onGifSelected(TLRPC.Document gif);
|
void onGifSelected(TLRPC.Document gif);
|
||||||
void onGifTab(boolean opened);
|
void onGifTab(boolean opened);
|
||||||
void onStickersTab(boolean opened);
|
void onStickersTab(boolean opened);
|
||||||
|
void onClearEmojiRecent();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final Field superListenerField;
|
private static final Field superListenerField;
|
||||||
|
@ -160,6 +162,8 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific
|
||||||
pickerViewPopup.showAsDropDown(view, xOffset, -view.getMeasuredHeight() - popupHeight + (view.getMeasuredHeight() - emojiSize) / 2 - yOffset);
|
pickerViewPopup.showAsDropDown(view, xOffset, -view.getMeasuredHeight() - popupHeight + (view.getMeasuredHeight() - emojiSize) / 2 - yOffset);
|
||||||
view.getParent().requestDisallowInterceptTouchEvent(true);
|
view.getParent().requestDisallowInterceptTouchEvent(true);
|
||||||
return true;
|
return true;
|
||||||
|
} else if (pager.getCurrentItem() == 0) {
|
||||||
|
listener.onClearEmojiRecent();
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -519,7 +523,6 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific
|
||||||
private GifsAdapter gifsAdapter;
|
private GifsAdapter gifsAdapter;
|
||||||
private AdapterView.OnItemClickListener stickersOnItemClickListener;
|
private AdapterView.OnItemClickListener stickersOnItemClickListener;
|
||||||
|
|
||||||
|
|
||||||
private EmojiColorPickerView pickerView;
|
private EmojiColorPickerView pickerView;
|
||||||
private EmojiPopupWindow pickerViewPopup;
|
private EmojiPopupWindow pickerViewPopup;
|
||||||
private int popupWidth;
|
private int popupWidth;
|
||||||
|
@ -531,8 +534,6 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific
|
||||||
private int gifTabBum = -2;
|
private int gifTabBum = -2;
|
||||||
private boolean switchToGifTab;
|
private boolean switchToGifTab;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private int oldWidth;
|
private int oldWidth;
|
||||||
private int lastNotifyWidth;
|
private int lastNotifyWidth;
|
||||||
|
|
||||||
|
@ -667,7 +668,7 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
TLRPC.Document document = recentImages.get(position).document;
|
TLRPC.Document document = recentImages.get(position).document;
|
||||||
listener.onStickerSelected(document);
|
listener.onGifSelected(document);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
gifsGridView.setOnItemLongClickListener(new RecyclerListView.OnItemLongClickListener() {
|
gifsGridView.setOnItemLongClickListener(new RecyclerListView.OnItemLongClickListener() {
|
||||||
|
@ -966,6 +967,15 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific
|
||||||
loadRecents();
|
loadRecents();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void clearRecentEmoji() {
|
||||||
|
SharedPreferences preferences = getContext().getSharedPreferences("emoji", Activity.MODE_PRIVATE);
|
||||||
|
preferences.edit().putBoolean("filled_default", true).commit();
|
||||||
|
emojiUseHistory.clear();
|
||||||
|
recentEmoji.clear();
|
||||||
|
saveRecentEmoji();
|
||||||
|
adapters.get(0).notifyDataSetChanged();
|
||||||
|
}
|
||||||
|
|
||||||
private void showGifTab() {
|
private void showGifTab() {
|
||||||
gifsGridView.setVisibility(VISIBLE);
|
gifsGridView.setVisibility(VISIBLE);
|
||||||
stickersGridView.setVisibility(GONE);
|
stickersGridView.setVisibility(GONE);
|
||||||
|
@ -1268,7 +1278,7 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific
|
||||||
String[] args = str.split(",");
|
String[] args = str.split(",");
|
||||||
for (String arg : args) {
|
for (String arg : args) {
|
||||||
String[] args2 = arg.split("=");
|
String[] args2 = arg.split("=");
|
||||||
long value = Long.parseLong(args2[0]);
|
long value = Utilities.parseLong(args2[0]);
|
||||||
String string = "";
|
String string = "";
|
||||||
for (int a = 0; a < 4; a++) {
|
for (int a = 0; a < 4; a++) {
|
||||||
char ch = (char) value;
|
char ch = (char) value;
|
||||||
|
@ -1279,7 +1289,7 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (string.length() > 0) {
|
if (string.length() > 0) {
|
||||||
emojiUseHistory.put(string, Integer.parseInt(args2[1]));
|
emojiUseHistory.put(string, Utilities.parseInt(args2[1]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1291,22 +1301,25 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific
|
||||||
String[] args = str.split(",");
|
String[] args = str.split(",");
|
||||||
for (String arg : args) {
|
for (String arg : args) {
|
||||||
String[] args2 = arg.split("=");
|
String[] args2 = arg.split("=");
|
||||||
emojiUseHistory.put(args2[0], Integer.parseInt(args2[1]));
|
emojiUseHistory.put(args2[0], Utilities.parseInt(args2[1]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (emojiUseHistory.isEmpty()) {
|
if (emojiUseHistory.isEmpty()) {
|
||||||
String[] newRecent = new String[]{
|
if (!preferences.getBoolean("filled_default", false)) {
|
||||||
"\uD83D\uDE02", "\uD83D\uDE18", "\u2764", "\uD83D\uDE0D", "\uD83D\uDE0A", "\uD83D\uDE01",
|
String[] newRecent = new String[]{
|
||||||
"\uD83D\uDC4D", "\u263A", "\uD83D\uDE14", "\uD83D\uDE04", "\uD83D\uDE2D", "\uD83D\uDC8B",
|
"\uD83D\uDE02", "\uD83D\uDE18", "\u2764", "\uD83D\uDE0D", "\uD83D\uDE0A", "\uD83D\uDE01",
|
||||||
"\uD83D\uDE12", "\uD83D\uDE33", "\uD83D\uDE1C", "\uD83D\uDE48", "\uD83D\uDE09", "\uD83D\uDE03",
|
"\uD83D\uDC4D", "\u263A", "\uD83D\uDE14", "\uD83D\uDE04", "\uD83D\uDE2D", "\uD83D\uDC8B",
|
||||||
"\uD83D\uDE22", "\uD83D\uDE1D", "\uD83D\uDE31", "\uD83D\uDE21", "\uD83D\uDE0F", "\uD83D\uDE1E",
|
"\uD83D\uDE12", "\uD83D\uDE33", "\uD83D\uDE1C", "\uD83D\uDE48", "\uD83D\uDE09", "\uD83D\uDE03",
|
||||||
"\uD83D\uDE05", "\uD83D\uDE1A", "\uD83D\uDE4A", "\uD83D\uDE0C", "\uD83D\uDE00", "\uD83D\uDE0B",
|
"\uD83D\uDE22", "\uD83D\uDE1D", "\uD83D\uDE31", "\uD83D\uDE21", "\uD83D\uDE0F", "\uD83D\uDE1E",
|
||||||
"\uD83D\uDE06", "\uD83D\uDC4C", "\uD83D\uDE10", "\uD83D\uDE15"};
|
"\uD83D\uDE05", "\uD83D\uDE1A", "\uD83D\uDE4A", "\uD83D\uDE0C", "\uD83D\uDE00", "\uD83D\uDE0B",
|
||||||
for (int i = 0; i < newRecent.length; i++) {
|
"\uD83D\uDE06", "\uD83D\uDC4C", "\uD83D\uDE10", "\uD83D\uDE15"};
|
||||||
emojiUseHistory.put(newRecent[i], newRecent.length - i);
|
for (int i = 0; i < newRecent.length; i++) {
|
||||||
|
emojiUseHistory.put(newRecent[i], newRecent.length - i);
|
||||||
|
}
|
||||||
|
preferences.edit().putBoolean("filled_default", true).commit();
|
||||||
|
saveRecentEmoji();
|
||||||
}
|
}
|
||||||
saveRecentEmoji();
|
|
||||||
}
|
}
|
||||||
sortEmoji();
|
sortEmoji();
|
||||||
adapters.get(0).notifyDataSetChanged();
|
adapters.get(0).notifyDataSetChanged();
|
||||||
|
@ -1338,8 +1351,8 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific
|
||||||
for (int a = 0; a < args.length; a++) {
|
for (int a = 0; a < args.length; a++) {
|
||||||
String arg = args[a];
|
String arg = args[a];
|
||||||
String[] args2 = arg.split("=");
|
String[] args2 = arg.split("=");
|
||||||
Long key = Long.parseLong(args2[0]);
|
Long key = Utilities.parseLong(args2[0]);
|
||||||
stickersUseHistory.put(key, Integer.parseInt(args2[1]));
|
stickersUseHistory.put(key, Utilities.parseInt(args2[1]));
|
||||||
newRecentStickers.add(key);
|
newRecentStickers.add(key);
|
||||||
}
|
}
|
||||||
Collections.sort(newRecentStickers, new Comparator<Long>() {
|
Collections.sort(newRecentStickers, new Comparator<Long>() {
|
||||||
|
@ -1367,7 +1380,13 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific
|
||||||
str = preferences.getString("stickers2", "");
|
str = preferences.getString("stickers2", "");
|
||||||
String[] args = str.split(",");
|
String[] args = str.split(",");
|
||||||
for (int a = 0; a < args.length; a++) {
|
for (int a = 0; a < args.length; a++) {
|
||||||
newRecentStickers.add(Long.parseLong(args[a]));
|
if (args[a].length() == 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
long id = Utilities.parseLong(args[a]);
|
||||||
|
if (id != 0) {
|
||||||
|
newRecentStickers.add(id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
sortStickers();
|
sortStickers();
|
||||||
|
|
|
@ -14,6 +14,7 @@ import android.util.AttributeSet;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.widget.FrameLayout;
|
import android.widget.FrameLayout;
|
||||||
|
|
||||||
|
import org.telegram.messenger.AndroidUtilities;
|
||||||
import org.telegram.messenger.FileLog;
|
import org.telegram.messenger.FileLog;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
@ -155,6 +156,7 @@ public class FrameLayoutFixed extends FrameLayout {
|
||||||
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
|
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
|
||||||
} catch (Exception e2) {
|
} catch (Exception e2) {
|
||||||
FileLog.e("tmessages", e2);
|
FileLog.e("tmessages", e2);
|
||||||
|
setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(10), MeasureSpec.EXACTLY));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,6 +24,7 @@ public class PhotoCropView extends FrameLayout {
|
||||||
|
|
||||||
public interface PhotoCropViewDelegate {
|
public interface PhotoCropViewDelegate {
|
||||||
void needMoveImageTo(float x, float y, float s, boolean animated);
|
void needMoveImageTo(float x, float y, float s, boolean animated);
|
||||||
|
Bitmap getBitmap();
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean freeformCrop = true;
|
private boolean freeformCrop = true;
|
||||||
|
@ -38,11 +39,11 @@ public class PhotoCropView extends FrameLayout {
|
||||||
private float oldX = 0, oldY = 0;
|
private float oldX = 0, oldY = 0;
|
||||||
private int bitmapWidth = 1, bitmapHeight = 1, bitmapX, bitmapY;
|
private int bitmapWidth = 1, bitmapHeight = 1, bitmapX, bitmapY;
|
||||||
private float rectX = -1, rectY = -1;
|
private float rectX = -1, rectY = -1;
|
||||||
private Bitmap bitmapToEdit;
|
|
||||||
private float bitmapGlobalScale = 1;
|
private float bitmapGlobalScale = 1;
|
||||||
private float bitmapGlobalX = 0;
|
private float bitmapGlobalX = 0;
|
||||||
private float bitmapGlobalY = 0;
|
private float bitmapGlobalY = 0;
|
||||||
private PhotoCropViewDelegate delegate;
|
private PhotoCropViewDelegate delegate;
|
||||||
|
private Bitmap bitmapToEdit;
|
||||||
|
|
||||||
private RectF animationStartValues;
|
private RectF animationStartValues;
|
||||||
private RectF animationEndValues;
|
private RectF animationEndValues;
|
||||||
|
@ -472,6 +473,11 @@ public class PhotoCropView extends FrameLayout {
|
||||||
}
|
}
|
||||||
|
|
||||||
private Bitmap createBitmap(int x, int y, int w, int h) {
|
private Bitmap createBitmap(int x, int y, int w, int h) {
|
||||||
|
Bitmap newBimap = delegate.getBitmap();
|
||||||
|
if (newBimap != null) {
|
||||||
|
bitmapToEdit = newBimap;
|
||||||
|
}
|
||||||
|
|
||||||
Bitmap bitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
|
Bitmap bitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
|
||||||
Canvas canvas = new Canvas(bitmap);
|
Canvas canvas = new Canvas(bitmap);
|
||||||
Paint paint = new Paint(Paint.FILTER_BITMAP_FLAG | Paint.DITHER_FLAG);
|
Paint paint = new Paint(Paint.FILTER_BITMAP_FLAG | Paint.DITHER_FLAG);
|
||||||
|
@ -495,6 +501,11 @@ public class PhotoCropView extends FrameLayout {
|
||||||
}
|
}
|
||||||
|
|
||||||
public Bitmap getBitmap() {
|
public Bitmap getBitmap() {
|
||||||
|
Bitmap newBimap = delegate.getBitmap();
|
||||||
|
if (newBimap != null) {
|
||||||
|
bitmapToEdit = newBimap;
|
||||||
|
}
|
||||||
|
|
||||||
float bitmapScaledWidth = bitmapWidth * bitmapGlobalScale;
|
float bitmapScaledWidth = bitmapWidth * bitmapGlobalScale;
|
||||||
float bitmapScaledHeight = bitmapHeight * bitmapGlobalScale;
|
float bitmapScaledHeight = bitmapHeight * bitmapGlobalScale;
|
||||||
float bitmapStartX = (getWidth() - AndroidUtilities.dp(28) - bitmapScaledWidth) / 2 + bitmapGlobalX + AndroidUtilities.dp(14);
|
float bitmapStartX = (getWidth() - AndroidUtilities.dp(28) - bitmapScaledWidth) / 2 + bitmapGlobalX + AndroidUtilities.dp(14);
|
||||||
|
@ -658,6 +669,11 @@ public class PhotoCropView extends FrameLayout {
|
||||||
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
|
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
|
||||||
super.onLayout(changed, left, top, right, bottom);
|
super.onLayout(changed, left, top, right, bottom);
|
||||||
|
|
||||||
|
Bitmap newBimap = delegate.getBitmap();
|
||||||
|
if (newBimap != null) {
|
||||||
|
bitmapToEdit = newBimap;
|
||||||
|
}
|
||||||
|
|
||||||
if (bitmapToEdit == null) {
|
if (bitmapToEdit == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -2006,7 +2006,9 @@ public class PhotoFilterView extends FrameLayout {
|
||||||
eglThread.postRunnable(new Runnable() {
|
eglThread.postRunnable(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
eglThread.requestRender(false);
|
if (eglThread != null) {
|
||||||
|
eglThread.requestRender(false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -343,6 +343,11 @@ public class PhotoViewerCaptionEnterView extends FrameLayoutFixed implements Not
|
||||||
public void onStickersTab(boolean opened) {
|
public void onStickersTab(boolean opened) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onClearEmojiRecent() {
|
||||||
|
|
||||||
|
}
|
||||||
});
|
});
|
||||||
sizeNotifierLayout.addView(emojiView);
|
sizeNotifierLayout.addView(emojiView);
|
||||||
}
|
}
|
||||||
|
|
|
@ -84,6 +84,7 @@ public class SimpleTextView extends View {
|
||||||
} else {
|
} else {
|
||||||
offsetX = 0;
|
offsetX = 0;
|
||||||
}
|
}
|
||||||
|
offsetX += getPaddingLeft();
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
//ignore
|
//ignore
|
||||||
|
@ -94,7 +95,7 @@ public class SimpleTextView extends View {
|
||||||
@Override
|
@Override
|
||||||
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
|
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
|
||||||
if (changed) {
|
if (changed) {
|
||||||
createLayout(right - left);
|
createLayout(right - left - getPaddingLeft() - getPaddingRight());
|
||||||
invalidate();
|
invalidate();
|
||||||
wasLayout = true;
|
wasLayout = true;
|
||||||
}
|
}
|
||||||
|
@ -103,7 +104,7 @@ public class SimpleTextView extends View {
|
||||||
public void setText(CharSequence value) {
|
public void setText(CharSequence value) {
|
||||||
text = value;
|
text = value;
|
||||||
if (wasLayout) {
|
if (wasLayout) {
|
||||||
createLayout(getMeasuredWidth());
|
createLayout(getMeasuredWidth() - getPaddingLeft() - getPaddingRight());
|
||||||
invalidate();
|
invalidate();
|
||||||
} else {
|
} else {
|
||||||
requestLayout();
|
requestLayout();
|
||||||
|
|
|
@ -391,6 +391,7 @@ public class Switch extends CompoundButton {
|
||||||
protected void onAttachedToWindow() {
|
protected void onAttachedToWindow() {
|
||||||
super.onAttachedToWindow();
|
super.onAttachedToWindow();
|
||||||
attachedToWindow = true;
|
attachedToWindow = true;
|
||||||
|
requestLayout();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -40,6 +40,7 @@ import org.telegram.messenger.ApplicationLoader;
|
||||||
import org.telegram.messenger.LocaleController;
|
import org.telegram.messenger.LocaleController;
|
||||||
import org.telegram.messenger.MessagesStorage;
|
import org.telegram.messenger.MessagesStorage;
|
||||||
import org.telegram.messenger.SecretChatHelper;
|
import org.telegram.messenger.SecretChatHelper;
|
||||||
|
import org.telegram.messenger.UserConfig;
|
||||||
import org.telegram.messenger.UserObject;
|
import org.telegram.messenger.UserObject;
|
||||||
import org.telegram.tgnet.TLRPC;
|
import org.telegram.tgnet.TLRPC;
|
||||||
import org.telegram.messenger.ContactsController;
|
import org.telegram.messenger.ContactsController;
|
||||||
|
@ -289,12 +290,17 @@ public class ContactsActivity extends BaseFragment implements NotificationCenter
|
||||||
didSelectResult(user, true, null);
|
didSelectResult(user, true, null);
|
||||||
} else {
|
} else {
|
||||||
if (createSecretChat) {
|
if (createSecretChat) {
|
||||||
|
if (user.id == UserConfig.getClientUserId()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
creatingChat = true;
|
creatingChat = true;
|
||||||
SecretChatHelper.getInstance().startSecretChat(getParentActivity(), user);
|
SecretChatHelper.getInstance().startSecretChat(getParentActivity(), user);
|
||||||
} else {
|
} else {
|
||||||
Bundle args = new Bundle();
|
Bundle args = new Bundle();
|
||||||
args.putInt("user_id", user.id);
|
args.putInt("user_id", user.id);
|
||||||
presentFragment(new ChatActivity(args), true);
|
if (MessagesController.checkCanOpenChat(args, ContactsActivity.this)) {
|
||||||
|
presentFragment(new ChatActivity(args), true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -330,6 +336,7 @@ public class ContactsActivity extends BaseFragment implements NotificationCenter
|
||||||
args.putBoolean("onlyUsers", true);
|
args.putBoolean("onlyUsers", true);
|
||||||
args.putBoolean("destroyAfterSelect", true);
|
args.putBoolean("destroyAfterSelect", true);
|
||||||
args.putBoolean("createSecretChat", true);
|
args.putBoolean("createSecretChat", true);
|
||||||
|
args.putBoolean("allowBots", false);
|
||||||
presentFragment(new ContactsActivity(args), false);
|
presentFragment(new ContactsActivity(args), false);
|
||||||
} else if (row == 2) {
|
} else if (row == 2) {
|
||||||
if (!MessagesController.isFeatureEnabled("broadcast_create", ContactsActivity.this)) {
|
if (!MessagesController.isFeatureEnabled("broadcast_create", ContactsActivity.this)) {
|
||||||
|
@ -363,7 +370,9 @@ public class ContactsActivity extends BaseFragment implements NotificationCenter
|
||||||
} else {
|
} else {
|
||||||
Bundle args = new Bundle();
|
Bundle args = new Bundle();
|
||||||
args.putInt("user_id", user.id);
|
args.putInt("user_id", user.id);
|
||||||
presentFragment(new ChatActivity(args), true);
|
if (MessagesController.checkCanOpenChat(args, ContactsActivity.this)) {
|
||||||
|
presentFragment(new ChatActivity(args), true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (item instanceof ContactsController.Contact) {
|
} else if (item instanceof ContactsController.Contact) {
|
||||||
|
|
|
@ -0,0 +1,216 @@
|
||||||
|
/*
|
||||||
|
* This is the source code of Telegram for Android v. 3.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-2016.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.telegram.ui;
|
||||||
|
|
||||||
|
import android.app.AlertDialog;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.DialogInterface;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import android.widget.AdapterView;
|
||||||
|
import android.widget.FrameLayout;
|
||||||
|
import android.widget.ListView;
|
||||||
|
|
||||||
|
import org.telegram.messenger.AndroidUtilities;
|
||||||
|
import org.telegram.messenger.LocaleController;
|
||||||
|
import org.telegram.messenger.MessagesController;
|
||||||
|
import org.telegram.messenger.NotificationCenter;
|
||||||
|
import org.telegram.messenger.R;
|
||||||
|
import org.telegram.ui.ActionBar.ActionBar;
|
||||||
|
import org.telegram.ui.ActionBar.BaseFragment;
|
||||||
|
import org.telegram.ui.Adapters.BaseFragmentAdapter;
|
||||||
|
import org.telegram.ui.Cells.TextInfoPrivacyCell;
|
||||||
|
import org.telegram.ui.Cells.TextSettingsCell;
|
||||||
|
import org.telegram.ui.Components.LayoutHelper;
|
||||||
|
|
||||||
|
public class ConvertGroupActivity extends BaseFragment implements NotificationCenter.NotificationCenterDelegate {
|
||||||
|
|
||||||
|
private ListAdapter listAdapter;
|
||||||
|
|
||||||
|
private int convertInfoRow;
|
||||||
|
private int convertRow;
|
||||||
|
private int convertDetailRow;
|
||||||
|
private int rowCount;
|
||||||
|
|
||||||
|
private int chat_id;
|
||||||
|
|
||||||
|
public ConvertGroupActivity(Bundle args) {
|
||||||
|
super(args);
|
||||||
|
chat_id = args.getInt("chat_id");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onFragmentCreate() {
|
||||||
|
super.onFragmentCreate();
|
||||||
|
|
||||||
|
convertInfoRow = rowCount++;
|
||||||
|
convertRow = rowCount++;
|
||||||
|
convertDetailRow = rowCount++;
|
||||||
|
|
||||||
|
NotificationCenter.getInstance().addObserver(this, NotificationCenter.closeChats);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onFragmentDestroy() {
|
||||||
|
super.onFragmentDestroy();
|
||||||
|
NotificationCenter.getInstance().removeObserver(this, NotificationCenter.closeChats);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public View createView(Context context) {
|
||||||
|
actionBar.setBackButtonImage(R.drawable.ic_ab_back);
|
||||||
|
actionBar.setAllowOverlayTitle(true);
|
||||||
|
actionBar.setTitle(LocaleController.getString("ConvertGroup", R.string.ConvertGroup));
|
||||||
|
actionBar.setActionBarMenuOnItemClick(new ActionBar.ActionBarMenuOnItemClick() {
|
||||||
|
@Override
|
||||||
|
public void onItemClick(int id) {
|
||||||
|
if (id == -1) {
|
||||||
|
finishFragment();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
listAdapter = new ListAdapter(context);
|
||||||
|
|
||||||
|
fragmentView = new FrameLayout(context);
|
||||||
|
FrameLayout frameLayout = (FrameLayout) fragmentView;
|
||||||
|
frameLayout.setBackgroundColor(0xfff0f0f0);
|
||||||
|
|
||||||
|
ListView listView = new ListView(context);
|
||||||
|
listView.setDivider(null);
|
||||||
|
listView.setDividerHeight(0);
|
||||||
|
listView.setVerticalScrollBarEnabled(false);
|
||||||
|
listView.setDrawSelectorOnTop(true);
|
||||||
|
frameLayout.addView(listView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT));
|
||||||
|
listView.setAdapter(listAdapter);
|
||||||
|
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onItemClick(final AdapterView<?> adapterView, View view, final int i, long l) {
|
||||||
|
if (i == convertRow) {
|
||||||
|
AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity());
|
||||||
|
builder.setMessage(LocaleController.getString("ConvertGroupAlert", R.string.ConvertGroupAlert));
|
||||||
|
builder.setTitle(LocaleController.getString("ConvertGroupAlertWarning", R.string.ConvertGroupAlertWarning));
|
||||||
|
builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), new DialogInterface.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(DialogInterface dialogInterface, int i) {
|
||||||
|
MessagesController.getInstance().convertToMegaGroup(getParentActivity(), chat_id);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null);
|
||||||
|
showDialog(builder.create());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return fragmentView;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onResume() {
|
||||||
|
super.onResume();
|
||||||
|
if (listAdapter != null) {
|
||||||
|
listAdapter.notifyDataSetChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void didReceivedNotification(int id, Object... args) {
|
||||||
|
if (id == NotificationCenter.closeChats) {
|
||||||
|
removeSelfFromStack();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class ListAdapter extends BaseFragmentAdapter {
|
||||||
|
private Context mContext;
|
||||||
|
|
||||||
|
public ListAdapter(Context context) {
|
||||||
|
mContext = context;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean areAllItemsEnabled() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isEnabled(int i) {
|
||||||
|
return i == convertRow;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getCount() {
|
||||||
|
return rowCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object getItem(int i) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getItemId(int i) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasStableIds() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public View getView(int i, View view, ViewGroup viewGroup) {
|
||||||
|
int type = getItemViewType(i);
|
||||||
|
if (type == 0) {
|
||||||
|
if (view == null) {
|
||||||
|
view = new TextSettingsCell(mContext);
|
||||||
|
view.setBackgroundColor(0xffffffff);
|
||||||
|
}
|
||||||
|
TextSettingsCell textCell = (TextSettingsCell) view;
|
||||||
|
if (i == convertRow) {
|
||||||
|
textCell.setText(LocaleController.getString("ConvertGroup", R.string.ConvertGroup), false);
|
||||||
|
}
|
||||||
|
} else if (type == 1) {
|
||||||
|
if (view == null) {
|
||||||
|
view = new TextInfoPrivacyCell(mContext);
|
||||||
|
}
|
||||||
|
if (i == convertInfoRow) {
|
||||||
|
((TextInfoPrivacyCell) view).setText(AndroidUtilities.replaceTags(LocaleController.getString("ConvertGroupInfo2", R.string.ConvertGroupInfo2)));
|
||||||
|
view.setBackgroundResource(R.drawable.greydivider);
|
||||||
|
} else if (i == convertDetailRow) {
|
||||||
|
((TextInfoPrivacyCell) view).setText(AndroidUtilities.replaceTags(LocaleController.getString("ConvertGroupInfo3", R.string.ConvertGroupInfo3)));
|
||||||
|
view.setBackgroundResource(R.drawable.greydivider_bottom);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return view;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getItemViewType(int i) {
|
||||||
|
if (i == convertRow) {
|
||||||
|
return 0;
|
||||||
|
} else if (i == convertInfoRow || i == convertDetailRow) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getViewTypeCount() {
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isEmpty() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -147,6 +147,7 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter.
|
||||||
NotificationCenter.getInstance().addObserver(this, NotificationCenter.messageSendError);
|
NotificationCenter.getInstance().addObserver(this, NotificationCenter.messageSendError);
|
||||||
NotificationCenter.getInstance().addObserver(this, NotificationCenter.didSetPasscode);
|
NotificationCenter.getInstance().addObserver(this, NotificationCenter.didSetPasscode);
|
||||||
NotificationCenter.getInstance().addObserver(this, NotificationCenter.needReloadRecentDialogsSearch);
|
NotificationCenter.getInstance().addObserver(this, NotificationCenter.needReloadRecentDialogsSearch);
|
||||||
|
NotificationCenter.getInstance().addObserver(this, NotificationCenter.didLoadedReplyMessages);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -175,6 +176,7 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter.
|
||||||
NotificationCenter.getInstance().removeObserver(this, NotificationCenter.messageSendError);
|
NotificationCenter.getInstance().removeObserver(this, NotificationCenter.messageSendError);
|
||||||
NotificationCenter.getInstance().removeObserver(this, NotificationCenter.didSetPasscode);
|
NotificationCenter.getInstance().removeObserver(this, NotificationCenter.didSetPasscode);
|
||||||
NotificationCenter.getInstance().removeObserver(this, NotificationCenter.needReloadRecentDialogsSearch);
|
NotificationCenter.getInstance().removeObserver(this, NotificationCenter.needReloadRecentDialogsSearch);
|
||||||
|
NotificationCenter.getInstance().removeObserver(this, NotificationCenter.didLoadedReplyMessages);
|
||||||
}
|
}
|
||||||
delegate = null;
|
delegate = null;
|
||||||
}
|
}
|
||||||
|
@ -429,10 +431,14 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (searchString != null) {
|
if (searchString != null) {
|
||||||
NotificationCenter.getInstance().postNotificationName(NotificationCenter.closeChats);
|
if (MessagesController.checkCanOpenChat(args, DialogsActivity.this)) {
|
||||||
presentFragment(new ChatActivity(args));
|
NotificationCenter.getInstance().postNotificationName(NotificationCenter.closeChats);
|
||||||
|
presentFragment(new ChatActivity(args));
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
presentFragment(new ChatActivity(args));
|
if (MessagesController.checkCanOpenChat(args, DialogsActivity.this)) {
|
||||||
|
presentFragment(new ChatActivity(args));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -896,9 +902,7 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (id == NotificationCenter.emojiDidLoaded) {
|
} else if (id == NotificationCenter.emojiDidLoaded) {
|
||||||
if (listView != null) {
|
updateVisibleRows(0);
|
||||||
updateVisibleRows(0);
|
|
||||||
}
|
|
||||||
} else if (id == NotificationCenter.updateInterfaces) {
|
} else if (id == NotificationCenter.updateInterfaces) {
|
||||||
updateVisibleRows((Integer) args[0]);
|
updateVisibleRows((Integer) args[0]);
|
||||||
} else if (id == NotificationCenter.appDidLogout) {
|
} else if (id == NotificationCenter.appDidLogout) {
|
||||||
|
@ -933,6 +937,8 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter.
|
||||||
if (dialogsSearchAdapter != null) {
|
if (dialogsSearchAdapter != null) {
|
||||||
dialogsSearchAdapter.loadRecentSearch();
|
dialogsSearchAdapter.loadRecentSearch();
|
||||||
}
|
}
|
||||||
|
} else if (id == NotificationCenter.didLoadedReplyMessages) {
|
||||||
|
updateVisibleRows(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -78,7 +78,7 @@ public class GroupCreateActivity extends BaseFragment implements NotificationCen
|
||||||
private int beforeChangeIndex;
|
private int beforeChangeIndex;
|
||||||
private boolean ignoreChange;
|
private boolean ignoreChange;
|
||||||
private CharSequence changeString;
|
private CharSequence changeString;
|
||||||
private int maxCount = 1000;
|
private int maxCount = 5000;
|
||||||
private int chatType = ChatObject.CHAT_TYPE_CHAT;
|
private int chatType = ChatObject.CHAT_TYPE_CHAT;
|
||||||
private boolean isAlwaysShare;
|
private boolean isAlwaysShare;
|
||||||
private boolean isNeverShare;
|
private boolean isNeverShare;
|
||||||
|
|
|
@ -450,7 +450,7 @@ public class GroupCreateFinalActivity extends BaseFragment implements Notificati
|
||||||
@Override
|
@Override
|
||||||
public View getView(int i, View view, ViewGroup viewGroup) {
|
public View getView(int i, View view, ViewGroup viewGroup) {
|
||||||
if (view == null) {
|
if (view == null) {
|
||||||
view = new UserCell(mContext, 1, 0);
|
view = new UserCell(mContext, 1, 0, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
TLRPC.User user = MessagesController.getInstance().getUser(selectedContacts.get(i));
|
TLRPC.User user = MessagesController.getInstance().getUser(selectedContacts.get(i));
|
||||||
|
|
|
@ -127,7 +127,7 @@ public class LaunchActivity extends Activity implements ActionBarLayout.ActionBa
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (intent != null && !intent.getBooleanExtra("fromIntro", false)) {
|
if (intent != null && !intent.getBooleanExtra("fromIntro", false)) {
|
||||||
SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("logininfo", MODE_PRIVATE);
|
SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("logininfo2", MODE_PRIVATE);
|
||||||
Map<String, ?> state = preferences.getAll();
|
Map<String, ?> state = preferences.getAll();
|
||||||
if (state.isEmpty()) {
|
if (state.isEmpty()) {
|
||||||
Intent intent2 = new Intent(this, IntroActivity.class);
|
Intent intent2 = new Intent(this, IntroActivity.class);
|
||||||
|
@ -295,6 +295,7 @@ public class LaunchActivity extends Activity implements ActionBarLayout.ActionBa
|
||||||
args.putBoolean("onlyUsers", true);
|
args.putBoolean("onlyUsers", true);
|
||||||
args.putBoolean("destroyAfterSelect", true);
|
args.putBoolean("destroyAfterSelect", true);
|
||||||
args.putBoolean("createSecretChat", true);
|
args.putBoolean("createSecretChat", true);
|
||||||
|
args.putBoolean("allowBots", false);
|
||||||
presentFragment(new ContactsActivity(args));
|
presentFragment(new ContactsActivity(args));
|
||||||
drawerLayoutContainer.closeDrawer(false);
|
drawerLayoutContainer.closeDrawer(false);
|
||||||
} else if (position == 4) {
|
} else if (position == 4) {
|
||||||
|
@ -768,7 +769,7 @@ public class LaunchActivity extends Activity implements ActionBarLayout.ActionBa
|
||||||
if (scheme != null) {
|
if (scheme != null) {
|
||||||
if ((scheme.equals("http") || scheme.equals("https"))) {
|
if ((scheme.equals("http") || scheme.equals("https"))) {
|
||||||
String host = data.getHost().toLowerCase();
|
String host = data.getHost().toLowerCase();
|
||||||
if (host.equals("telegram.me")) {
|
if (host.equals("telegram.me") || host.equals("telegram.dog")) {
|
||||||
String path = data.getPath();
|
String path = data.getPath();
|
||||||
if (path != null && path.length() > 1) {
|
if (path != null && path.length() > 1) {
|
||||||
path = path.substring(1);
|
path = path.substring(1);
|
||||||
|
@ -882,16 +883,20 @@ public class LaunchActivity extends Activity implements ActionBarLayout.ActionBa
|
||||||
if (push_user_id != 0) {
|
if (push_user_id != 0) {
|
||||||
Bundle args = new Bundle();
|
Bundle args = new Bundle();
|
||||||
args.putInt("user_id", push_user_id);
|
args.putInt("user_id", push_user_id);
|
||||||
ChatActivity fragment = new ChatActivity(args);
|
if (mainFragmentsStack.isEmpty() || MessagesController.checkCanOpenChat(args, mainFragmentsStack.get(mainFragmentsStack.size() - 1))) {
|
||||||
if (actionBarLayout.presentFragment(fragment, false, true, true)) {
|
ChatActivity fragment = new ChatActivity(args);
|
||||||
pushOpened = true;
|
if (actionBarLayout.presentFragment(fragment, false, true, true)) {
|
||||||
|
pushOpened = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else if (push_chat_id != 0) {
|
} else if (push_chat_id != 0) {
|
||||||
Bundle args = new Bundle();
|
Bundle args = new Bundle();
|
||||||
args.putInt("chat_id", push_chat_id);
|
args.putInt("chat_id", push_chat_id);
|
||||||
ChatActivity fragment = new ChatActivity(args);
|
if (mainFragmentsStack.isEmpty() || MessagesController.checkCanOpenChat(args, mainFragmentsStack.get(mainFragmentsStack.size() - 1))) {
|
||||||
if (actionBarLayout.presentFragment(fragment, false, true, true)) {
|
ChatActivity fragment = new ChatActivity(args);
|
||||||
pushOpened = true;
|
if (actionBarLayout.presentFragment(fragment, false, true, true)) {
|
||||||
|
pushOpened = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else if (push_enc_id != 0) {
|
} else if (push_enc_id != 0) {
|
||||||
Bundle args = new Bundle();
|
Bundle args = new Bundle();
|
||||||
|
@ -1071,12 +1076,14 @@ public class LaunchActivity extends Activity implements ActionBarLayout.ActionBa
|
||||||
fragment.setDelegate(new DialogsActivity.MessagesActivityDelegate() {
|
fragment.setDelegate(new DialogsActivity.MessagesActivityDelegate() {
|
||||||
@Override
|
@Override
|
||||||
public void didSelectDialog(DialogsActivity fragment, long did, boolean param) {
|
public void didSelectDialog(DialogsActivity fragment, long did, boolean param) {
|
||||||
NotificationCenter.getInstance().postNotificationName(NotificationCenter.closeChats);
|
|
||||||
MessagesController.getInstance().addUserToChat(-(int) did, user, null, 0, botChat, null);
|
|
||||||
Bundle args = new Bundle();
|
Bundle args = new Bundle();
|
||||||
args.putBoolean("scrollToTopOnResume", true);
|
args.putBoolean("scrollToTopOnResume", true);
|
||||||
args.putInt("chat_id", -(int) did);
|
args.putInt("chat_id", -(int) did);
|
||||||
actionBarLayout.presentFragment(new ChatActivity(args), true, false, true);
|
if (mainFragmentsStack.isEmpty() || MessagesController.checkCanOpenChat(args, mainFragmentsStack.get(mainFragmentsStack.size() - 1))) {
|
||||||
|
NotificationCenter.getInstance().postNotificationName(NotificationCenter.closeChats);
|
||||||
|
MessagesController.getInstance().addUserToChat(-(int) did, user, null, 0, botChat, null);
|
||||||
|
actionBarLayout.presentFragment(new ChatActivity(args), true, false, true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
presentFragment(fragment);
|
presentFragment(fragment);
|
||||||
|
@ -1093,9 +1100,11 @@ public class LaunchActivity extends Activity implements ActionBarLayout.ActionBa
|
||||||
if (messageId != null) {
|
if (messageId != null) {
|
||||||
args.putInt("message_id", messageId);
|
args.putInt("message_id", messageId);
|
||||||
}
|
}
|
||||||
ChatActivity fragment = new ChatActivity(args);
|
if (mainFragmentsStack.isEmpty() || MessagesController.checkCanOpenChat(args, mainFragmentsStack.get(mainFragmentsStack.size() - 1))) {
|
||||||
NotificationCenter.getInstance().postNotificationName(NotificationCenter.closeChats);
|
ChatActivity fragment = new ChatActivity(args);
|
||||||
actionBarLayout.presentFragment(fragment, false, true, true);
|
NotificationCenter.getInstance().postNotificationName(NotificationCenter.closeChats);
|
||||||
|
actionBarLayout.presentFragment(fragment, false, true, true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
try {
|
try {
|
||||||
|
@ -1134,9 +1143,11 @@ public class LaunchActivity extends Activity implements ActionBarLayout.ActionBa
|
||||||
MessagesStorage.getInstance().putUsersAndChats(null, chats, false, true);
|
MessagesStorage.getInstance().putUsersAndChats(null, chats, false, true);
|
||||||
Bundle args = new Bundle();
|
Bundle args = new Bundle();
|
||||||
args.putInt("chat_id", invite.chat.id);
|
args.putInt("chat_id", invite.chat.id);
|
||||||
ChatActivity fragment = new ChatActivity(args);
|
if (mainFragmentsStack.isEmpty() || MessagesController.checkCanOpenChat(args, mainFragmentsStack.get(mainFragmentsStack.size() - 1))) {
|
||||||
NotificationCenter.getInstance().postNotificationName(NotificationCenter.closeChats);
|
ChatActivity fragment = new ChatActivity(args);
|
||||||
actionBarLayout.presentFragment(fragment, false, true, true);
|
NotificationCenter.getInstance().postNotificationName(NotificationCenter.closeChats);
|
||||||
|
actionBarLayout.presentFragment(fragment, false, true, true);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
AlertDialog.Builder builder = new AlertDialog.Builder(LaunchActivity.this);
|
AlertDialog.Builder builder = new AlertDialog.Builder(LaunchActivity.this);
|
||||||
builder.setTitle(LocaleController.getString("AppName", R.string.AppName));
|
builder.setTitle(LocaleController.getString("AppName", R.string.AppName));
|
||||||
|
@ -1200,9 +1211,11 @@ public class LaunchActivity extends Activity implements ActionBarLayout.ActionBa
|
||||||
MessagesController.getInstance().putChats(updates.chats, false);
|
MessagesController.getInstance().putChats(updates.chats, false);
|
||||||
Bundle args = new Bundle();
|
Bundle args = new Bundle();
|
||||||
args.putInt("chat_id", chat.id);
|
args.putInt("chat_id", chat.id);
|
||||||
ChatActivity fragment = new ChatActivity(args);
|
if (mainFragmentsStack.isEmpty() || MessagesController.checkCanOpenChat(args, mainFragmentsStack.get(mainFragmentsStack.size() - 1))) {
|
||||||
NotificationCenter.getInstance().postNotificationName(NotificationCenter.closeChats);
|
ChatActivity fragment = new ChatActivity(args);
|
||||||
actionBarLayout.presentFragment(fragment, false, true, true);
|
NotificationCenter.getInstance().postNotificationName(NotificationCenter.closeChats);
|
||||||
|
actionBarLayout.presentFragment(fragment, false, true, true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -1238,11 +1251,6 @@ public class LaunchActivity extends Activity implements ActionBarLayout.ActionBa
|
||||||
fragment.setDelegate(new DialogsActivity.MessagesActivityDelegate() {
|
fragment.setDelegate(new DialogsActivity.MessagesActivityDelegate() {
|
||||||
@Override
|
@Override
|
||||||
public void didSelectDialog(DialogsActivity fragment, long did, boolean param) {
|
public void didSelectDialog(DialogsActivity fragment, long did, boolean param) {
|
||||||
NotificationCenter.getInstance().postNotificationName(NotificationCenter.closeChats);
|
|
||||||
SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("mainconfig", Activity.MODE_PRIVATE);
|
|
||||||
SharedPreferences.Editor editor = preferences.edit();
|
|
||||||
editor.putString("dialog_" + did, message);
|
|
||||||
editor.commit();
|
|
||||||
Bundle args = new Bundle();
|
Bundle args = new Bundle();
|
||||||
args.putBoolean("scrollToTopOnResume", true);
|
args.putBoolean("scrollToTopOnResume", true);
|
||||||
args.putBoolean("hasUrl", hasUrl);
|
args.putBoolean("hasUrl", hasUrl);
|
||||||
|
@ -1261,7 +1269,14 @@ public class LaunchActivity extends Activity implements ActionBarLayout.ActionBa
|
||||||
} else {
|
} else {
|
||||||
args.putInt("enc_id", high_id);
|
args.putInt("enc_id", high_id);
|
||||||
}
|
}
|
||||||
actionBarLayout.presentFragment(new ChatActivity(args), true, false, true);
|
if (MessagesController.checkCanOpenChat(args, fragment)) {
|
||||||
|
NotificationCenter.getInstance().postNotificationName(NotificationCenter.closeChats);
|
||||||
|
SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("mainconfig", Activity.MODE_PRIVATE);
|
||||||
|
SharedPreferences.Editor editor = preferences.edit();
|
||||||
|
editor.putString("dialog_" + did, message);
|
||||||
|
editor.commit();
|
||||||
|
actionBarLayout.presentFragment(new ChatActivity(args), true, false, true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
presentFragment(fragment, false, true);
|
presentFragment(fragment, false, true);
|
||||||
|
@ -1339,6 +1354,9 @@ public class LaunchActivity extends Activity implements ActionBarLayout.ActionBa
|
||||||
} else {
|
} else {
|
||||||
args.putInt("enc_id", high_id);
|
args.putInt("enc_id", high_id);
|
||||||
}
|
}
|
||||||
|
if (!MessagesController.checkCanOpenChat(args, dialogsFragment)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
ChatActivity fragment = new ChatActivity(args);
|
ChatActivity fragment = new ChatActivity(args);
|
||||||
|
|
||||||
if (videoPath != null) {
|
if (videoPath != null) {
|
||||||
|
@ -1495,7 +1513,12 @@ public class LaunchActivity extends Activity implements ActionBarLayout.ActionBa
|
||||||
actionBarLayout.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
|
actionBarLayout.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onGlobalLayout() {
|
public void onGlobalLayout() {
|
||||||
needLayout();
|
AndroidUtilities.runOnUIThread(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
needLayout();
|
||||||
|
}
|
||||||
|
});
|
||||||
if (actionBarLayout != null) {
|
if (actionBarLayout != null) {
|
||||||
if (Build.VERSION.SDK_INT < 16) {
|
if (Build.VERSION.SDK_INT < 16) {
|
||||||
actionBarLayout.getViewTreeObserver().removeGlobalOnLayoutListener(this);
|
actionBarLayout.getViewTreeObserver().removeGlobalOnLayoutListener(this);
|
||||||
|
|
|
@ -929,7 +929,11 @@ public class LocationActivity extends BaseFragment implements NotificationCenter
|
||||||
super.onResume();
|
super.onResume();
|
||||||
AndroidUtilities.removeAdjustResize(getParentActivity(), classGuid);
|
AndroidUtilities.removeAdjustResize(getParentActivity(), classGuid);
|
||||||
if (mapView != null) {
|
if (mapView != null) {
|
||||||
mapView.onResume();
|
try {
|
||||||
|
mapView.onResume();
|
||||||
|
} catch (Throwable e) {
|
||||||
|
FileLog.e("tmessages", e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
updateUserData();
|
updateUserData();
|
||||||
fixLayoutInternal(true);
|
fixLayoutInternal(true);
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -348,6 +348,9 @@ public class MediaActivity extends BaseFragment implements NotificationCenter.No
|
||||||
} else if (lower_part < 0) {
|
} else if (lower_part < 0) {
|
||||||
args.putInt("chat_id", -lower_part);
|
args.putInt("chat_id", -lower_part);
|
||||||
}
|
}
|
||||||
|
if (!MessagesController.checkCanOpenChat(args, fragment)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
ArrayList<MessageObject> fmessages = new ArrayList<>();
|
ArrayList<MessageObject> fmessages = new ArrayList<>();
|
||||||
for (int a = 1; a >= 0; a--) {
|
for (int a = 1; a >= 0; a--) {
|
||||||
|
@ -364,6 +367,7 @@ public class MediaActivity extends BaseFragment implements NotificationCenter.No
|
||||||
actionBar.hideActionMode();
|
actionBar.hideActionMode();
|
||||||
|
|
||||||
NotificationCenter.getInstance().postNotificationName(NotificationCenter.closeChats);
|
NotificationCenter.getInstance().postNotificationName(NotificationCenter.closeChats);
|
||||||
|
|
||||||
ChatActivity chatActivity = new ChatActivity(args);
|
ChatActivity chatActivity = new ChatActivity(args);
|
||||||
presentFragment(chatActivity, true);
|
presentFragment(chatActivity, true);
|
||||||
chatActivity.showReplyPanel(true, null, fmessages, null, false, false);
|
chatActivity.showReplyPanel(true, null, fmessages, null, false, false);
|
||||||
|
@ -901,7 +905,11 @@ public class MediaActivity extends BaseFragment implements NotificationCenter.No
|
||||||
listView.setAdapter(photoVideoAdapter);
|
listView.setAdapter(photoVideoAdapter);
|
||||||
dropDown.setText(LocaleController.getString("SharedMediaTitle", R.string.SharedMediaTitle));
|
dropDown.setText(LocaleController.getString("SharedMediaTitle", R.string.SharedMediaTitle));
|
||||||
emptyImageView.setImageResource(R.drawable.tip1);
|
emptyImageView.setImageResource(R.drawable.tip1);
|
||||||
emptyTextView.setText(LocaleController.getString("NoMedia", R.string.NoMedia));
|
if ((int) dialog_id == 0) {
|
||||||
|
emptyTextView.setText(LocaleController.getString("NoMediaSecret", R.string.NoMediaSecret));
|
||||||
|
} else {
|
||||||
|
emptyTextView.setText(LocaleController.getString("NoMedia", R.string.NoMedia));
|
||||||
|
}
|
||||||
searchItem.setVisibility(View.GONE);
|
searchItem.setVisibility(View.GONE);
|
||||||
if (sharedMediaData[selectedMode].loading && sharedMediaData[selectedMode].messages.isEmpty()) {
|
if (sharedMediaData[selectedMode].loading && sharedMediaData[selectedMode].messages.isEmpty()) {
|
||||||
progressView.setVisibility(View.VISIBLE);
|
progressView.setVisibility(View.VISIBLE);
|
||||||
|
@ -918,12 +926,20 @@ public class MediaActivity extends BaseFragment implements NotificationCenter.No
|
||||||
listView.setAdapter(documentsAdapter);
|
listView.setAdapter(documentsAdapter);
|
||||||
dropDown.setText(LocaleController.getString("DocumentsTitle", R.string.DocumentsTitle));
|
dropDown.setText(LocaleController.getString("DocumentsTitle", R.string.DocumentsTitle));
|
||||||
emptyImageView.setImageResource(R.drawable.tip2);
|
emptyImageView.setImageResource(R.drawable.tip2);
|
||||||
emptyTextView.setText(LocaleController.getString("NoSharedFiles", R.string.NoSharedFiles));
|
if ((int) dialog_id == 0) {
|
||||||
|
emptyTextView.setText(LocaleController.getString("NoSharedFilesSecret", R.string.NoSharedFilesSecret));
|
||||||
|
} else {
|
||||||
|
emptyTextView.setText(LocaleController.getString("NoSharedFiles", R.string.NoSharedFiles));
|
||||||
|
}
|
||||||
} else if (selectedMode == 4) {
|
} else if (selectedMode == 4) {
|
||||||
listView.setAdapter(audioAdapter);
|
listView.setAdapter(audioAdapter);
|
||||||
dropDown.setText(LocaleController.getString("AudioTitle", R.string.AudioTitle));
|
dropDown.setText(LocaleController.getString("AudioTitle", R.string.AudioTitle));
|
||||||
emptyImageView.setImageResource(R.drawable.tip4);
|
emptyImageView.setImageResource(R.drawable.tip4);
|
||||||
emptyTextView.setText(LocaleController.getString("NoSharedAudio", R.string.NoSharedAudio));
|
if ((int) dialog_id == 0) {
|
||||||
|
emptyTextView.setText(LocaleController.getString("NoSharedAudioSecret", R.string.NoSharedAudioSecret));
|
||||||
|
} else {
|
||||||
|
emptyTextView.setText(LocaleController.getString("NoSharedAudio", R.string.NoSharedAudio));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
searchItem.setVisibility(!sharedMediaData[selectedMode].messages.isEmpty() ? View.VISIBLE : View.GONE);
|
searchItem.setVisibility(!sharedMediaData[selectedMode].messages.isEmpty() ? View.VISIBLE : View.GONE);
|
||||||
if (!sharedMediaData[selectedMode].loading && !sharedMediaData[selectedMode].endReached[0] && sharedMediaData[selectedMode].messages.isEmpty()) {
|
if (!sharedMediaData[selectedMode].loading && !sharedMediaData[selectedMode].endReached[0] && sharedMediaData[selectedMode].messages.isEmpty()) {
|
||||||
|
@ -944,7 +960,11 @@ public class MediaActivity extends BaseFragment implements NotificationCenter.No
|
||||||
listView.setAdapter(linksAdapter);
|
listView.setAdapter(linksAdapter);
|
||||||
dropDown.setText(LocaleController.getString("LinksTitle", R.string.LinksTitle));
|
dropDown.setText(LocaleController.getString("LinksTitle", R.string.LinksTitle));
|
||||||
emptyImageView.setImageResource(R.drawable.tip3);
|
emptyImageView.setImageResource(R.drawable.tip3);
|
||||||
emptyTextView.setText(LocaleController.getString("NoSharedLinks", R.string.NoSharedLinks));
|
if ((int) dialog_id == 0) {
|
||||||
|
emptyTextView.setText(LocaleController.getString("NoSharedLinksSecret", R.string.NoSharedLinksSecret));
|
||||||
|
} else {
|
||||||
|
emptyTextView.setText(LocaleController.getString("NoSharedLinks", R.string.NoSharedLinks));
|
||||||
|
}
|
||||||
searchItem.setVisibility(!sharedMediaData[3].messages.isEmpty() ? View.VISIBLE : View.GONE);
|
searchItem.setVisibility(!sharedMediaData[3].messages.isEmpty() ? View.VISIBLE : View.GONE);
|
||||||
if (!sharedMediaData[selectedMode].loading && !sharedMediaData[selectedMode].endReached[0] && sharedMediaData[selectedMode].messages.isEmpty()) {
|
if (!sharedMediaData[selectedMode].loading && !sharedMediaData[selectedMode].endReached[0] && sharedMediaData[selectedMode].messages.isEmpty()) {
|
||||||
sharedMediaData[selectedMode].loading = true;
|
sharedMediaData[selectedMode].loading = true;
|
||||||
|
|
|
@ -15,7 +15,6 @@ import android.graphics.Paint;
|
||||||
import android.graphics.drawable.BitmapDrawable;
|
import android.graphics.drawable.BitmapDrawable;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.util.AttributeSet;
|
|
||||||
import android.view.MotionEvent;
|
import android.view.MotionEvent;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.widget.FrameLayout;
|
import android.widget.FrameLayout;
|
||||||
|
@ -58,16 +57,6 @@ public class PhotoCropActivity extends BaseFragment {
|
||||||
init();
|
init();
|
||||||
}
|
}
|
||||||
|
|
||||||
public PhotoCropView(Context context, AttributeSet attrs) {
|
|
||||||
super(context, attrs);
|
|
||||||
init();
|
|
||||||
}
|
|
||||||
|
|
||||||
public PhotoCropView(Context context, AttributeSet attrs, int defStyle) {
|
|
||||||
super(context, attrs, defStyle);
|
|
||||||
init();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void init() {
|
private void init() {
|
||||||
rectPaint = new Paint();
|
rectPaint = new Paint();
|
||||||
rectPaint.setColor(0x3ffafafa);
|
rectPaint.setColor(0x3ffafafa);
|
||||||
|
|
|
@ -914,6 +914,9 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat
|
||||||
};
|
};
|
||||||
windowView.setBackgroundDrawable(backgroundDrawable);
|
windowView.setBackgroundDrawable(backgroundDrawable);
|
||||||
windowView.setFocusable(false);
|
windowView.setFocusable(false);
|
||||||
|
if (Build.VERSION.SDK_INT >= 23) {
|
||||||
|
windowView.setFitsSystemWindows(true); //TODO ?
|
||||||
|
}
|
||||||
|
|
||||||
animatingImageView = new ClippingImageView(activity);
|
animatingImageView = new ClippingImageView(activity);
|
||||||
animatingImageView.setAnimationValues(animationValues);
|
animatingImageView.setAnimationValues(animationValues);
|
||||||
|
@ -1206,10 +1209,10 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat
|
||||||
|
|
||||||
if (currentMessageObject != null) {
|
if (currentMessageObject != null) {
|
||||||
isVideo = currentMessageObject.isVideo();
|
isVideo = currentMessageObject.isVideo();
|
||||||
if (currentMessageObject.messageOwner.media instanceof TLRPC.TL_messageMediaWebPage) {
|
/*if (currentMessageObject.messageOwner.media instanceof TLRPC.TL_messageMediaWebPage) {
|
||||||
AndroidUtilities.openUrl(parentActivity, currentMessageObject.messageOwner.media.webpage.url);
|
AndroidUtilities.openUrl(parentActivity, currentMessageObject.messageOwner.media.webpage.url);
|
||||||
return;
|
return;
|
||||||
}
|
}*/
|
||||||
f = FileLoader.getPathToMessage(currentMessageObject.messageOwner);
|
f = FileLoader.getPathToMessage(currentMessageObject.messageOwner);
|
||||||
} else if (currentFileLocation != null) {
|
} else if (currentFileLocation != null) {
|
||||||
f = FileLoader.getPathToAttach(currentFileLocation, avatarsUserId != 0);
|
f = FileLoader.getPathToAttach(currentFileLocation, avatarsUserId != 0);
|
||||||
|
@ -1800,6 +1803,11 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat
|
||||||
containerView.invalidate();
|
containerView.invalidate();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Bitmap getBitmap() {
|
||||||
|
return centerImage.getBitmap();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2579,7 +2587,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat
|
||||||
captionTextViewNew = captionTextView;
|
captionTextViewNew = captionTextView;
|
||||||
|
|
||||||
captionItem.setIcon(R.drawable.photo_text2);
|
captionItem.setIcon(R.drawable.photo_text2);
|
||||||
CharSequence str = Emoji.replaceEmoji(new SpannableStringBuilder(caption.toString()), MessageObject.textPaint.getFontMetricsInt(), AndroidUtilities.dp(20), false);
|
CharSequence str = Emoji.replaceEmoji(new SpannableStringBuilder(caption.toString()), MessageObject.getTextPaint().getFontMetricsInt(), AndroidUtilities.dp(20), false);
|
||||||
captionTextView.setTag(str);
|
captionTextView.setTag(str);
|
||||||
captionTextView.setText(str);
|
captionTextView.setText(str);
|
||||||
ViewProxy.setAlpha(captionTextView, bottomLayout.getVisibility() == View.VISIBLE || pickerView.getVisibility() == View.VISIBLE ? 1.0f : 0.0f);
|
ViewProxy.setAlpha(captionTextView, bottomLayout.getVisibility() == View.VISIBLE || pickerView.getVisibility() == View.VISIBLE ? 1.0f : 0.0f);
|
||||||
|
@ -2973,11 +2981,6 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onAnimationCancel(Object animation) {
|
|
||||||
onAnimationEnd(animation);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
transitionAnimationStartTime = System.currentTimeMillis();
|
transitionAnimationStartTime = System.currentTimeMillis();
|
||||||
AndroidUtilities.runOnUIThread(new Runnable() {
|
AndroidUtilities.runOnUIThread(new Runnable() {
|
||||||
|
@ -3178,11 +3181,6 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onAnimationCancel(Object animation) {
|
|
||||||
onAnimationEnd(animation);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
transitionAnimationStartTime = System.currentTimeMillis();
|
transitionAnimationStartTime = System.currentTimeMillis();
|
||||||
if (Build.VERSION.SDK_INT >= 18) {
|
if (Build.VERSION.SDK_INT >= 18) {
|
||||||
|
|
|
@ -285,7 +285,7 @@ public class PrivacyUsersActivity extends BaseFragment implements NotificationCe
|
||||||
int type = getItemViewType(i);
|
int type = getItemViewType(i);
|
||||||
if (type == 0) {
|
if (type == 0) {
|
||||||
if (view == null) {
|
if (view == null) {
|
||||||
view = new UserCell(mContext, 1, 0);
|
view = new UserCell(mContext, 1, 0, false);
|
||||||
}
|
}
|
||||||
TLRPC.User user = MessagesController.getInstance().getUser(uidArray.get(i));
|
TLRPC.User user = MessagesController.getInstance().getUser(uidArray.get(i));
|
||||||
((UserCell)view).setData(user, null, user.phone != null && user.phone.length() != 0 ? PhoneFormat.getInstance().format("+" + user.phone) : LocaleController.getString("NumberUnknown", R.string.NumberUnknown), 0);
|
((UserCell)view).setData(user, null, user.phone != null && user.phone.length() != 0 ? PhoneFormat.getInstance().format("+" + user.phone) : LocaleController.getString("NumberUnknown", R.string.NumberUnknown), 0);
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user