mirror of https://github.com/NekoX-Dev/NekoX.git
Update to 3.7.0
This commit is contained in:
parent
6154c891bd
commit
a7513b3ba1
|
@ -1,6 +1,6 @@
|
|||
## 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).
|
||||
|
||||
##Creating your Telegram Application
|
||||
|
@ -16,9 +16,9 @@ There are several things we require from **all developers** for the moment.
|
|||
|
||||
### 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
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@ repositories {
|
|||
}
|
||||
|
||||
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-maps:8.4.0"
|
||||
compile 'net.hockeyapp.android:HockeySDK:3.6.+'
|
||||
|
@ -63,6 +63,8 @@ android {
|
|||
}
|
||||
}
|
||||
|
||||
defaultConfig.versionCode = 767
|
||||
|
||||
sourceSets.main {
|
||||
jniLibs.srcDir 'libs'
|
||||
jni.srcDirs = [] //disable automatic ndk-build call
|
||||
|
@ -80,10 +82,38 @@ android {
|
|||
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 {
|
||||
minSdkVersion 9
|
||||
targetSdkVersion 23
|
||||
versionCode 755
|
||||
versionName "3.6.1"
|
||||
versionName "3.7.0"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -235,7 +235,7 @@ include $(BUILD_STATIC_LIBRARY)
|
|||
include $(CLEAR_VARS)
|
||||
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 += -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
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
APP_PLATFORM := android-9
|
||||
APP_ABI := armeabi armeabi-v7a x86
|
||||
NDK_TOOLCHAIN_VERSION := 4.8
|
||||
NDK_TOOLCHAIN_VERSION := 4.9
|
||||
APP_STL := gnustl_static
|
|
@ -671,8 +671,7 @@ JNIEXPORT int Java_org_telegram_messenger_MediaController_isOpusFile(JNIEnv *env
|
|||
return result;
|
||||
}
|
||||
|
||||
static inline void set_bits(uint8_t *bytes, int32_t bitOffset, int32_t numBits, int32_t value) {
|
||||
numBits = (unsigned int) (2 << (numBits - 1)) - 1;
|
||||
static inline void set_bits(uint8_t *bytes, int32_t bitOffset, int32_t value) {
|
||||
bytes += bitOffset / 8;
|
||||
bitOffset %= 8;
|
||||
*((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++) {
|
||||
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);
|
||||
|
@ -805,7 +804,7 @@ JNIEXPORT jbyteArray Java_org_telegram_messenger_MediaController_getWaveform(JNI
|
|||
|
||||
for (int i = 0; i < resultSamples; i++) {
|
||||
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);
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#include <inttypes.h>
|
||||
#include <stdlib.h>
|
||||
#include <openssl/aes.h>
|
||||
#include <unistd.h>
|
||||
#include "utils.h"
|
||||
#include "sqlite.h"
|
||||
#include "image.h"
|
||||
|
|
|
@ -8,8 +8,8 @@ jint sqliteOnJNILoad(JavaVM *vm, void *reserved, JNIEnv *env) {
|
|||
return JNI_VERSION_1_6;
|
||||
}
|
||||
|
||||
int Java_org_telegram_SQLite_SQLitePreparedStatement_step(JNIEnv* env, jobject object, int statementHandle) {
|
||||
sqlite3_stmt *handle = (sqlite3_stmt *)statementHandle;
|
||||
int Java_org_telegram_SQLite_SQLitePreparedStatement_step(JNIEnv *env, jobject object, int statementHandle) {
|
||||
sqlite3_stmt *handle = (sqlite3_stmt *) statementHandle;
|
||||
|
||||
int errcode = sqlite3_step(handle);
|
||||
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) {
|
||||
sqlite3* handle = (sqlite3 *)sqliteHandle;
|
||||
sqlite3 *handle = (sqlite3 *) sqliteHandle;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
return (int)stmt_handle;
|
||||
return (int) stmt_handle;
|
||||
}
|
||||
|
||||
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);
|
||||
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) {
|
||||
sqlite3_stmt *handle = (sqlite3_stmt *)statementHandle;
|
||||
|
||||
int errcode = sqlite3_finalize (handle);
|
||||
if (SQLITE_OK != errcode) {
|
||||
throw_sqlite3_exception(env, sqlite3_db_handle(handle), errcode);
|
||||
}
|
||||
sqlite3_finalize((sqlite3_stmt *) statementHandle);
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
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) {
|
||||
sqlite3_stmt *handle = (sqlite3_stmt*)statementHandle;
|
||||
sqlite3_stmt *handle = (sqlite3_stmt *) statementHandle;
|
||||
|
||||
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) {
|
||||
sqlite3_stmt *handle = (sqlite3_stmt*)statementHandle;
|
||||
sqlite3_stmt *handle = (sqlite3_stmt *) statementHandle;
|
||||
|
||||
int errcode = sqlite3_bind_int(handle, index, value);
|
||||
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) {
|
||||
sqlite3_stmt *handle = (sqlite3_stmt*)statementHandle;
|
||||
sqlite3_stmt *handle = (sqlite3_stmt *) statementHandle;
|
||||
|
||||
int errcode = sqlite3_bind_int64(handle, index, value);
|
||||
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) {
|
||||
sqlite3_stmt *handle = (sqlite3_stmt*)statementHandle;
|
||||
void Java_org_telegram_SQLite_SQLitePreparedStatement_bindDouble(JNIEnv *env, jobject object, int statementHandle, int index, double value) {
|
||||
sqlite3_stmt *handle = (sqlite3_stmt *) statementHandle;
|
||||
|
||||
int errcode = sqlite3_bind_double(handle, index, value);
|
||||
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) {
|
||||
sqlite3_stmt *handle = (sqlite3_stmt*)statementHandle;
|
||||
void Java_org_telegram_SQLite_SQLitePreparedStatement_bindNull(JNIEnv *env, jobject object, int statementHandle, int index) {
|
||||
sqlite3_stmt *handle = (sqlite3_stmt *) statementHandle;
|
||||
|
||||
int errcode = sqlite3_bind_null(handle, index);
|
||||
if (SQLITE_OK != errcode) {
|
||||
|
|
|
@ -57,7 +57,7 @@ void Connection::suspendConnection() {
|
|||
}
|
||||
|
||||
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;
|
||||
|
||||
|
@ -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 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) {
|
||||
//bytes[56] = bytes[57] = bytes[58] = bytes[59] = 0xef;
|
||||
bytes[56] = bytes[57] = bytes[58] = bytes[59] = 0xef;
|
||||
break;
|
||||
}
|
||||
}
|
||||
/*for (int a = 0; a < 48; a++) {
|
||||
for (int a = 0; a < 48; a++) {
|
||||
temp[a] = bytes[55 - a];
|
||||
}
|
||||
|
||||
|
@ -348,7 +348,7 @@ void Connection::sendData(NativeByteBuffer *buff, bool reportAck) {
|
|||
memcpy(decryptIv, temp + 32, 16);
|
||||
|
||||
AES_ctr128_encrypt(bytes, temp, 64, &encryptKey, encryptIv, encryptCount, &encryptNum);
|
||||
memcpy(bytes + 56, temp + 56, 8);*/
|
||||
memcpy(bytes + 56, temp + 56, 8);
|
||||
|
||||
firstPacketSent = true;
|
||||
}
|
||||
|
@ -358,7 +358,7 @@ void Connection::sendData(NativeByteBuffer *buff, bool reportAck) {
|
|||
}
|
||||
buffer->writeByte((uint8_t) packetLength);
|
||||
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 {
|
||||
packetLength = (packetLength << 8) + 0x7f;
|
||||
if (reportAck) {
|
||||
|
@ -366,13 +366,13 @@ void Connection::sendData(NativeByteBuffer *buff, bool reportAck) {
|
|||
}
|
||||
buffer->writeInt32(packetLength);
|
||||
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();
|
||||
writeBuffer(buffer);
|
||||
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);
|
||||
}
|
||||
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
|
||||
#define USE_DEBUG_SESSION false
|
||||
#define READ_BUFFER_SIZE 1024 * 128
|
||||
//#define DEBUG_VERSION
|
||||
#define DEBUG_VERSION
|
||||
#define DEFAULT_DATACENTER_ID INT_MAX
|
||||
#define DC_UPDATE_TIME 60 * 60
|
||||
#define DOWNLOAD_CONNECTIONS_COUNT 2
|
||||
|
|
|
@ -99,6 +99,8 @@
|
|||
<category android:name="android.intent.category.BROWSABLE" />
|
||||
<data android:host="telegram.me" android:scheme="http" />
|
||||
<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 android:icon="@drawable/ic_launcher" android:priority="1">
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
|
|
|
@ -11,6 +11,7 @@ package org.telegram.messenger;
|
|||
import android.annotation.SuppressLint;
|
||||
import android.app.Activity;
|
||||
import android.app.AlertDialog;
|
||||
import android.app.PendingIntent;
|
||||
import android.content.ContentUris;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
|
@ -19,6 +20,7 @@ import android.content.pm.ActivityInfo;
|
|||
import android.content.pm.PackageManager;
|
||||
import android.content.res.Configuration;
|
||||
import android.database.Cursor;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Point;
|
||||
import android.graphics.Rect;
|
||||
|
@ -26,6 +28,7 @@ import android.graphics.Typeface;
|
|||
import android.graphics.drawable.Drawable;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.Environment;
|
||||
import android.os.Parcelable;
|
||||
import android.provider.Browser;
|
||||
|
@ -84,7 +87,9 @@ public class AndroidUtilities {
|
|||
private static final Hashtable<String, Typeface> typefaceCache = new Hashtable<>();
|
||||
private static int prevOrientation = -10;
|
||||
private static boolean waitingForSms = false;
|
||||
private static boolean waitingForCall = false;
|
||||
private static final Object smsLock = new Object();
|
||||
private static final Object callLock = new Object();
|
||||
|
||||
public static int statusBarHeight = 0;
|
||||
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) {
|
||||
if (view == null) {
|
||||
return;
|
||||
|
@ -422,11 +441,28 @@ public class AndroidUtilities {
|
|||
if (context == null || uri == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
|
||||
intent.putExtra("android.support.customtabs.extra.SESSION", (Parcelable) null);
|
||||
intent.putExtra("android.support.customtabs.extra.TOOLBAR_COLOR", 0xff54759e);
|
||||
intent.putExtra("android.support.customtabs.extra.TITLE_VISIBILITY", 1);
|
||||
if (MediaController.getInstance().canCustomTabs()) {
|
||||
intent.putExtra("android.support.customtabs.extra.SESSION", (Parcelable) null);
|
||||
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());
|
||||
context.startActivity(intent);
|
||||
} catch (Exception e) {
|
||||
|
@ -917,7 +953,11 @@ public class AndroidUtilities {
|
|||
cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs, null);
|
||||
if (cursor != null && cursor.moveToFirst()) {
|
||||
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) {
|
||||
FileLog.e("tmessages", e);
|
||||
|
|
|
@ -37,6 +37,8 @@ import org.telegram.ui.Components.ForegroundDetector;
|
|||
|
||||
import java.io.File;
|
||||
import java.io.RandomAccessFile;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Locale;
|
||||
|
||||
public class ApplicationLoader extends Application {
|
||||
|
||||
|
|
|
@ -10,8 +10,8 @@ package org.telegram.messenger;
|
|||
|
||||
public class BuildVars {
|
||||
public static boolean DEBUG_VERSION = false;
|
||||
public static int BUILD_VERSION = 753;
|
||||
public static String BUILD_VERSION_STRING = "3.6";
|
||||
public static int BUILD_VERSION = 767;
|
||||
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 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";
|
||||
|
|
|
@ -11,20 +11,24 @@ package org.telegram.messenger;
|
|||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.telephony.PhoneStateListener;
|
||||
import android.telephony.TelephonyManager;
|
||||
|
||||
import org.telegram.PhoneFormat.PhoneFormat;
|
||||
|
||||
public class CallReceiver extends BroadcastReceiver {
|
||||
|
||||
@Override
|
||||
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() {
|
||||
@Override
|
||||
public void onCallStateChanged(int state, String incomingNumber) {
|
||||
super.onCallStateChanged(state, incomingNumber);
|
||||
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();
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
//}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -550,13 +550,17 @@ public class FileLoader {
|
|||
return getAttachFileName(sizeFull);
|
||||
}
|
||||
}
|
||||
} else if (message.media instanceof TLRPC.TL_messageMediaWebPage && message.media.webpage.photo != null) {
|
||||
ArrayList<TLRPC.PhotoSize> sizes = message.media.webpage.photo.sizes;
|
||||
if (sizes.size() > 0) {
|
||||
TLRPC.PhotoSize sizeFull = getClosestPhotoSizeWithSize(sizes, AndroidUtilities.getPhotoSize());
|
||||
if (sizeFull != null) {
|
||||
return getAttachFileName(sizeFull);
|
||||
} else if (message.media instanceof TLRPC.TL_messageMediaWebPage) {
|
||||
if (message.media.webpage.photo != null) {
|
||||
ArrayList<TLRPC.PhotoSize> sizes = message.media.webpage.photo.sizes;
|
||||
if (sizes.size() > 0) {
|
||||
TLRPC.PhotoSize sizeFull = getClosestPhotoSizeWithSize(sizes, AndroidUtilities.getPhotoSize());
|
||||
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);
|
||||
}
|
||||
}
|
||||
} else if (message.media instanceof TLRPC.TL_messageMediaWebPage && message.media.webpage.photo != null) {
|
||||
ArrayList<TLRPC.PhotoSize> sizes = message.media.webpage.photo.sizes;
|
||||
if (sizes.size() > 0) {
|
||||
TLRPC.PhotoSize sizeFull = getClosestPhotoSizeWithSize(sizes, AndroidUtilities.getPhotoSize());
|
||||
if (sizeFull != null) {
|
||||
return getPathToAttach(sizeFull);
|
||||
} else if (message.media instanceof TLRPC.TL_messageMediaWebPage) {
|
||||
if (message.media.webpage.photo != null) {
|
||||
ArrayList<TLRPC.PhotoSize> sizes = message.media.webpage.photo.sizes;
|
||||
if (sizes.size() > 0) {
|
||||
TLRPC.PhotoSize sizeFull = getClosestPhotoSizeWithSize(sizes, AndroidUtilities.getPhotoSize());
|
||||
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 "";
|
||||
}
|
||||
|
||||
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) {
|
||||
return getAttachFileName(attach, null);
|
||||
}
|
||||
|
|
|
@ -196,14 +196,17 @@ public class FileLog {
|
|||
File sdCard = ApplicationLoader.applicationContext.getExternalFilesDir(null);
|
||||
File dir = new File (sdCard.getAbsolutePath() + "/logs");
|
||||
File[] files = dir.listFiles();
|
||||
for (File file : files) {
|
||||
if (getInstance().currentFile != null && file.getAbsolutePath().equals(getInstance().currentFile.getAbsolutePath())) {
|
||||
continue;
|
||||
if (files != null) {
|
||||
for (int a = 0; a < files.length; a++) {
|
||||
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.Build;
|
||||
import android.os.Environment;
|
||||
import android.os.ParcelFileDescriptor;
|
||||
import android.provider.MediaStore;
|
||||
|
||||
import org.telegram.tgnet.ConnectionsManager;
|
||||
|
@ -33,7 +32,6 @@ import org.telegram.ui.Components.AnimatedFileDrawable;
|
|||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
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) {
|
||||
BitmapFactory.Options bmOptions = new BitmapFactory.Options();
|
||||
bmOptions.inJustDecodeBounds = true;
|
||||
FileDescriptor fileDescriptor = null;
|
||||
ParcelFileDescriptor parcelFD = null;
|
||||
InputStream inputStream = null;
|
||||
|
||||
if (path == null && uri != null && uri.getScheme() != null) {
|
||||
String imageFilePath = null;
|
||||
|
@ -2052,9 +2049,10 @@ public class ImageLoader {
|
|||
} else if (uri != null) {
|
||||
boolean error = false;
|
||||
try {
|
||||
parcelFD = ApplicationLoader.applicationContext.getContentResolver().openFileDescriptor(uri, "r");
|
||||
fileDescriptor = parcelFD.getFileDescriptor();
|
||||
BitmapFactory.decodeFileDescriptor(fileDescriptor, null, bmOptions);
|
||||
inputStream = ApplicationLoader.applicationContext.getContentResolver().openInputStream(uri);
|
||||
BitmapFactory.decodeStream(inputStream, null, bmOptions);
|
||||
inputStream.close();
|
||||
inputStream = ApplicationLoader.applicationContext.getContentResolver().openInputStream(uri);
|
||||
} catch (Throwable e) {
|
||||
FileLog.e("tmessages", e);
|
||||
return null;
|
||||
|
@ -2138,7 +2136,7 @@ public class ImageLoader {
|
|||
}
|
||||
} else if (uri != null) {
|
||||
try {
|
||||
b = BitmapFactory.decodeFileDescriptor(fileDescriptor, null, bmOptions);
|
||||
b = BitmapFactory.decodeStream(inputStream, null, bmOptions);
|
||||
if (b != null) {
|
||||
if (bmOptions.inPurgeable) {
|
||||
Utilities.pinBitmap(b);
|
||||
|
@ -2153,7 +2151,7 @@ public class ImageLoader {
|
|||
FileLog.e("tmessages", e);
|
||||
} finally {
|
||||
try {
|
||||
parcelFD.close();
|
||||
inputStream.close();
|
||||
} catch (Throwable e) {
|
||||
FileLog.e("tmessages", e);
|
||||
}
|
||||
|
|
|
@ -322,7 +322,7 @@ public class LocaleController {
|
|||
StringBuilder result = new StringBuilder(11);
|
||||
result.append(languageCode);
|
||||
if (countryCode.length() > 0 || variantCode.length() > 0) {
|
||||
result.append('_');
|
||||
result.append('-');
|
||||
}
|
||||
result.append(countryCode);
|
||||
if (variantCode.length() > 0) {
|
||||
|
@ -664,16 +664,21 @@ public class LocaleController {
|
|||
}
|
||||
|
||||
public static String formatDateChat(long date) {
|
||||
Calendar rightNow = Calendar.getInstance();
|
||||
int year = rightNow.get(Calendar.YEAR);
|
||||
try {
|
||||
Calendar rightNow = Calendar.getInstance();
|
||||
int year = rightNow.get(Calendar.YEAR);
|
||||
|
||||
rightNow.setTimeInMillis(date * 1000);
|
||||
int dateYear = rightNow.get(Calendar.YEAR);
|
||||
rightNow.setTimeInMillis(date * 1000);
|
||||
int dateYear = rightNow.get(Calendar.YEAR);
|
||||
|
||||
if (year == dateYear) {
|
||||
return getInstance().chatDate.format(date * 1000);
|
||||
if (year == dateYear) {
|
||||
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) {
|
||||
|
@ -697,7 +702,7 @@ public class LocaleController {
|
|||
} catch (Exception e) {
|
||||
FileLog.e("tmessages", e);
|
||||
}
|
||||
return "LOC_ERR";
|
||||
return "LOC_ERR: formatDate";
|
||||
}
|
||||
|
||||
public static String formatDateAudio(long date) {
|
||||
|
|
|
@ -42,10 +42,10 @@ import android.net.ConnectivityManager;
|
|||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.Environment;
|
||||
import android.os.ParcelFileDescriptor;
|
||||
import android.os.PowerManager;
|
||||
import android.os.Vibrator;
|
||||
import android.provider.MediaStore;
|
||||
import android.provider.OpenableColumns;
|
||||
import android.telephony.PhoneStateListener;
|
||||
import android.telephony.TelephonyManager;
|
||||
|
||||
|
@ -63,6 +63,7 @@ import org.telegram.ui.PhotoViewer;
|
|||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.InputStream;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
|
@ -235,7 +236,7 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener,
|
|||
private float[] gravityFast = new float[3];
|
||||
private float[] linearAcceleration = new float[3];
|
||||
|
||||
private boolean hasAudioFoces;
|
||||
private boolean hasAudioFocus;
|
||||
private boolean callInProgress;
|
||||
|
||||
private ArrayList<MessageObject> videoConvertQueue = new ArrayList<>();
|
||||
|
@ -269,6 +270,8 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener,
|
|||
private boolean saveToGallery = true;
|
||||
private boolean autoplayGifs = true;
|
||||
private boolean raiseToSpeak = true;
|
||||
private boolean customTabs = true;
|
||||
private boolean directShare = true;
|
||||
private boolean shuffleMusic;
|
||||
private int repeatMode;
|
||||
|
||||
|
@ -595,6 +598,8 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener,
|
|||
saveToGallery = preferences.getBoolean("save_gallery", false);
|
||||
autoplayGifs = preferences.getBoolean("autoplay_gif", 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);
|
||||
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()) {
|
||||
MediaController.getInstance().pauseAudio(MediaController.getInstance().getPlayingMessageObject());
|
||||
}
|
||||
hasAudioFoces = false;
|
||||
hasAudioFocus = false;
|
||||
} else if (focusChange == AudioManager.AUDIOFOCUS_GAIN) {
|
||||
//MediaController.getInstance().playAudio(MediaController.getInstance().getPlayingMessageObject());
|
||||
}
|
||||
|
@ -1653,14 +1658,24 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener,
|
|||
if (playingMessageObject == null) {
|
||||
return;
|
||||
}
|
||||
boolean post = audioPlayer != null;
|
||||
NotificationCenter.getInstance().postNotificationName(NotificationCenter.audioRouteChanged, useFrontSpeaker);
|
||||
MessageObject currentMessageObject = playingMessageObject;
|
||||
final MessageObject currentMessageObject = playingMessageObject;
|
||||
float progress = playingMessageObject.audioProgress;
|
||||
cleanupPlayer(false, true);
|
||||
currentMessageObject.audioProgress = progress;
|
||||
playAudio(currentMessageObject);
|
||||
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 (audioPlayer != null || audioTrackPlayer != null) {
|
||||
if (audioPlayer != null) {
|
||||
try {
|
||||
audioPlayer.reset();
|
||||
} catch (Exception e) {
|
||||
FileLog.e("tmessages", e);
|
||||
}
|
||||
try {
|
||||
audioPlayer.stop();
|
||||
} 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) {
|
||||
return false;
|
||||
}
|
||||
|
@ -2171,7 +2191,7 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener,
|
|||
if (!playlist.isEmpty() && playlist.size() > 1) {
|
||||
playNextMessage(true);
|
||||
} else {
|
||||
cleanupPlayer(true, true);
|
||||
cleanupPlayer(true, true, messageObject != null && messageObject.isVoice());
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -2201,8 +2221,8 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener,
|
|||
return false;
|
||||
}
|
||||
}
|
||||
if (!hasAudioFoces) {
|
||||
hasAudioFoces = true;
|
||||
if (!hasAudioFocus) {
|
||||
hasAudioFocus = true;
|
||||
NotificationsController.getInstance().audioManager.requestAudioFocus(this, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN);
|
||||
}
|
||||
|
||||
|
@ -2270,6 +2290,11 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener,
|
|||
}
|
||||
try {
|
||||
if (audioPlayer != null) {
|
||||
try {
|
||||
audioPlayer.reset();
|
||||
} catch (Exception e) {
|
||||
FileLog.e("tmessages", e);
|
||||
}
|
||||
audioPlayer.stop();
|
||||
} else if (audioTrackPlayer != null) {
|
||||
audioTrackPlayer.pause();
|
||||
|
@ -2378,8 +2403,8 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener,
|
|||
audioTrackPlayer.play();
|
||||
checkPlayerQueue();
|
||||
}
|
||||
if (!hasAudioFoces) {
|
||||
hasAudioFoces = true;
|
||||
if (!hasAudioFocus) {
|
||||
hasAudioFocus = true;
|
||||
NotificationsController.getInstance().audioManager.requestAudioFocus(this, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN);
|
||||
}
|
||||
isPaused = false;
|
||||
|
@ -2507,19 +2532,6 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener,
|
|||
public void generateWaveform(MessageObject messageObject) {
|
||||
final String id = messageObject.getId() + "_" + messageObject.getDialogId();
|
||||
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)) {
|
||||
return;
|
||||
}
|
||||
|
@ -2764,14 +2776,11 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener,
|
|||
}
|
||||
|
||||
public static boolean isWebp(Uri uri) {
|
||||
ParcelFileDescriptor parcelFD = null;
|
||||
FileInputStream input = null;
|
||||
InputStream inputStream = null;
|
||||
try {
|
||||
parcelFD = ApplicationLoader.applicationContext.getContentResolver().openFileDescriptor(uri, "r");
|
||||
input = new FileInputStream(parcelFD.getFileDescriptor());
|
||||
if (input.getChannel().size() > 12) {
|
||||
byte[] header = new byte[12];
|
||||
input.read(header, 0, 12);
|
||||
inputStream = ApplicationLoader.applicationContext.getContentResolver().openInputStream(uri);
|
||||
byte[] header = new byte[12];
|
||||
if (inputStream.read(header, 0, 12) == 12) {
|
||||
String str = new String(header);
|
||||
if (str != null) {
|
||||
str = str.toLowerCase();
|
||||
|
@ -2784,15 +2793,8 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener,
|
|||
FileLog.e("tmessages", e);
|
||||
} finally {
|
||||
try {
|
||||
if (parcelFD != null) {
|
||||
parcelFD.close();
|
||||
}
|
||||
} catch (Exception e2) {
|
||||
FileLog.e("tmessages", e2);
|
||||
}
|
||||
try {
|
||||
if (input != null) {
|
||||
input.close();
|
||||
if (inputStream != null) {
|
||||
inputStream.close();
|
||||
}
|
||||
} catch (Exception e2) {
|
||||
FileLog.e("tmessages", e2);
|
||||
|
@ -2802,14 +2804,11 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener,
|
|||
}
|
||||
|
||||
public static boolean isGif(Uri uri) {
|
||||
ParcelFileDescriptor parcelFD = null;
|
||||
FileInputStream input = null;
|
||||
InputStream inputStream = null;
|
||||
try {
|
||||
parcelFD = ApplicationLoader.applicationContext.getContentResolver().openFileDescriptor(uri, "r");
|
||||
input = new FileInputStream(parcelFD.getFileDescriptor());
|
||||
if (input.getChannel().size() > 3) {
|
||||
byte[] header = new byte[3];
|
||||
input.read(header, 0, 3);
|
||||
inputStream = ApplicationLoader.applicationContext.getContentResolver().openInputStream(uri);
|
||||
byte[] header = new byte[3];
|
||||
if (inputStream.read(header, 0, 3) == 3) {
|
||||
String str = new String(header);
|
||||
if (str != null && str.equalsIgnoreCase("gif")) {
|
||||
return true;
|
||||
|
@ -2819,15 +2818,8 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener,
|
|||
FileLog.e("tmessages", e);
|
||||
} finally {
|
||||
try {
|
||||
if (parcelFD != null) {
|
||||
parcelFD.close();
|
||||
}
|
||||
} catch (Exception e2) {
|
||||
FileLog.e("tmessages", e2);
|
||||
}
|
||||
try {
|
||||
if (input != null) {
|
||||
input.close();
|
||||
if (inputStream != null) {
|
||||
inputStream.close();
|
||||
}
|
||||
} catch (Exception e2) {
|
||||
FileLog.e("tmessages", e2);
|
||||
|
@ -2836,33 +2828,58 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener,
|
|||
return false;
|
||||
}
|
||||
|
||||
public static String copyDocumentToCache(Uri uri, String ext) {
|
||||
ParcelFileDescriptor parcelFD = null;
|
||||
FileInputStream input = null;
|
||||
public static String getFileName(Uri uri) {
|
||||
String result = 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;
|
||||
try {
|
||||
int id = UserConfig.lastLocalId;
|
||||
UserConfig.lastLocalId--;
|
||||
parcelFD = ApplicationLoader.applicationContext.getContentResolver().openFileDescriptor(uri, "r");
|
||||
input = new FileInputStream(parcelFD.getFileDescriptor());
|
||||
File f = new File(FileLoader.getInstance().getDirectory(FileLoader.MEDIA_DIR_CACHE), String.format(Locale.US, "%d.%s", id, ext));
|
||||
String name = getFileName(uri);
|
||||
if (name == null) {
|
||||
int id = UserConfig.lastLocalId;
|
||||
UserConfig.lastLocalId--;
|
||||
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);
|
||||
input.getChannel().transferTo(0, input.getChannel().size(), output.getChannel());
|
||||
UserConfig.saveConfig(false);
|
||||
byte[] buffer = new byte[1024 * 20];
|
||||
int len;
|
||||
while ((len = inputStream.read(buffer)) != -1) {
|
||||
output.write(buffer, 0, len);
|
||||
}
|
||||
return f.getAbsolutePath();
|
||||
} catch (Exception e) {
|
||||
FileLog.e("tmessages", e);
|
||||
} finally {
|
||||
try {
|
||||
if (parcelFD != null) {
|
||||
parcelFD.close();
|
||||
}
|
||||
} catch (Exception e2) {
|
||||
FileLog.e("tmessages", e2);
|
||||
}
|
||||
try {
|
||||
if (input != null) {
|
||||
input.close();
|
||||
if (inputStream != null) {
|
||||
inputStream.close();
|
||||
}
|
||||
} catch (Exception e2) {
|
||||
FileLog.e("tmessages", e2);
|
||||
|
@ -2903,6 +2920,22 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener,
|
|||
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() {
|
||||
try {
|
||||
File telegramPath = new File(Environment.getExternalStorageDirectory(), "Telegram");
|
||||
|
@ -2943,6 +2976,14 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener,
|
|||
return raiseToSpeak;
|
||||
}
|
||||
|
||||
public boolean canCustomTabs() {
|
||||
return customTabs;
|
||||
}
|
||||
|
||||
public boolean canDirectShare() {
|
||||
return directShare;
|
||||
}
|
||||
|
||||
public static void loadGalleryPhotosAlbums(final int guid) {
|
||||
new Thread(new Runnable() {
|
||||
@Override
|
||||
|
@ -3246,6 +3287,7 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener,
|
|||
long startTime = -1;
|
||||
|
||||
checkConversionCanceled();
|
||||
long lastTimestamp = -100;
|
||||
|
||||
while (!inputDone) {
|
||||
checkConversionCanceled();
|
||||
|
@ -3254,28 +3296,37 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener,
|
|||
int index = extractor.getSampleTrackIndex();
|
||||
if (index == trackIndex) {
|
||||
info.size = extractor.readSampleData(buffer, 0);
|
||||
|
||||
if (info.size < 0) {
|
||||
if (info.size >= 0) {
|
||||
info.presentationTimeUs = extractor.getSampleTime();
|
||||
} else {
|
||||
info.size = 0;
|
||||
eof = true;
|
||||
} else {
|
||||
info.presentationTimeUs = extractor.getSampleTime();
|
||||
}
|
||||
|
||||
if (info.size > 0 && !eof) {
|
||||
if (start > 0 && startTime == -1) {
|
||||
startTime = info.presentationTimeUs;
|
||||
}
|
||||
if (end < 0 || info.presentationTimeUs < end) {
|
||||
info.offset = 0;
|
||||
info.flags = extractor.getSampleFlags();
|
||||
if (mediaMuxer.writeSampleData(muxerTrackIndex, buffer, info, isAudio)) {
|
||||
didWriteData(messageObject, file, false, false);
|
||||
if (info.presentationTimeUs > lastTimestamp) {
|
||||
info.offset = 0;
|
||||
info.flags = extractor.getSampleFlags();
|
||||
if (mediaMuxer.writeSampleData(muxerTrackIndex, buffer, info, isAudio)) {
|
||||
didWriteData(messageObject, file, false, false);
|
||||
}
|
||||
}
|
||||
extractor.advance();
|
||||
lastTimestamp = info.presentationTimeUs;
|
||||
} else {
|
||||
eof = true;
|
||||
}
|
||||
}
|
||||
if (!eof) {
|
||||
extractor.advance();
|
||||
}
|
||||
} else if (index == -1) {
|
||||
eof = true;
|
||||
} else {
|
||||
extractor.advance();
|
||||
}
|
||||
if (eof) {
|
||||
inputDone = true;
|
||||
|
|
|
@ -58,11 +58,10 @@ public class MessageObject {
|
|||
public VideoEditedInfo videoEditedInfo;
|
||||
public boolean viewsReloaded;
|
||||
|
||||
public static TextPaint textPaint;
|
||||
private static TextPaint textPaint;
|
||||
public int lastLineWidth;
|
||||
public int textWidth;
|
||||
public int textHeight;
|
||||
public int blockHeight = Integer.MAX_VALUE;
|
||||
|
||||
private boolean layoutCreated;
|
||||
|
||||
|
@ -70,9 +69,10 @@ public class MessageObject {
|
|||
|
||||
public static class TextLayoutBlock {
|
||||
public StaticLayout textLayout;
|
||||
public float textXOffset = 0;
|
||||
public float textYOffset = 0;
|
||||
public int charactersOffset = 0;
|
||||
public float textXOffset;
|
||||
public float textYOffset;
|
||||
public int charactersOffset;
|
||||
public int height;
|
||||
}
|
||||
|
||||
private static final int LINES_PER_BLOCK = 10;
|
||||
|
@ -99,7 +99,7 @@ public class MessageObject {
|
|||
}
|
||||
|
||||
TLRPC.User fromUser = null;
|
||||
if (isFromUser()) {
|
||||
if (message.from_id > 0) {
|
||||
if (users != null) {
|
||||
fromUser = users.get(message.from_id);
|
||||
}
|
||||
|
@ -114,22 +114,14 @@ public class MessageObject {
|
|||
if (isOut()) {
|
||||
messageText = LocaleController.getString("ActionYouCreateGroup", R.string.ActionYouCreateGroup);
|
||||
} else {
|
||||
if (fromUser != null) {
|
||||
messageText = replaceWithLink(LocaleController.getString("ActionCreateGroup", R.string.ActionCreateGroup), "un1", fromUser);
|
||||
} else {
|
||||
messageText = LocaleController.getString("ActionCreateGroup", R.string.ActionCreateGroup).replace("un1", "");
|
||||
}
|
||||
messageText = replaceWithLink(LocaleController.getString("ActionCreateGroup", R.string.ActionCreateGroup), "un1", fromUser);
|
||||
}
|
||||
} else if (message.action instanceof TLRPC.TL_messageActionChatDeleteUser) {
|
||||
if (message.action.user_id == message.from_id) {
|
||||
if (isOut()) {
|
||||
messageText = LocaleController.getString("ActionYouLeftUser", R.string.ActionYouLeftUser);
|
||||
} else {
|
||||
if (fromUser != null) {
|
||||
messageText = replaceWithLink(LocaleController.getString("ActionLeftUser", R.string.ActionLeftUser), "un1", fromUser);
|
||||
} else {
|
||||
messageText = LocaleController.getString("ActionLeftUser", R.string.ActionLeftUser).replace("un1", "");
|
||||
}
|
||||
messageText = replaceWithLink(LocaleController.getString("ActionLeftUser", R.string.ActionLeftUser), "un1", fromUser);
|
||||
}
|
||||
} else {
|
||||
TLRPC.User whoUser = null;
|
||||
|
@ -139,17 +131,13 @@ public class MessageObject {
|
|||
if (whoUser == null) {
|
||||
whoUser = MessagesController.getInstance().getUser(message.action.user_id);
|
||||
}
|
||||
if (whoUser != null && fromUser != null) {
|
||||
if (isOut()) {
|
||||
messageText = replaceWithLink(LocaleController.getString("ActionYouKickUser", R.string.ActionYouKickUser), "un2", whoUser);
|
||||
} else if (message.action.user_id == UserConfig.getClientUserId()) {
|
||||
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);
|
||||
}
|
||||
if (isOut()) {
|
||||
messageText = replaceWithLink(LocaleController.getString("ActionYouKickUser", R.string.ActionYouKickUser), "un2", whoUser);
|
||||
} else if (message.action.user_id == UserConfig.getClientUserId()) {
|
||||
messageText = replaceWithLink(LocaleController.getString("ActionKickUserYou", R.string.ActionKickUserYou), "un1", fromUser);
|
||||
} 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) {
|
||||
|
@ -165,36 +153,38 @@ public class MessageObject {
|
|||
if (whoUser == null) {
|
||||
whoUser = MessagesController.getInstance().getUser(singleUserId);
|
||||
}
|
||||
if (message.to_id.channel_id != 0 && !isMegagroup()) {
|
||||
if (whoUser != null && whoUser.id != UserConfig.getClientUserId()) {
|
||||
if (isMegagroup()) {
|
||||
messageText = replaceWithLink(LocaleController.getString("MegaAddedBy", R.string.MegaAddedBy), "un1", whoUser);
|
||||
} else {
|
||||
messageText = replaceWithLink(LocaleController.getString("ChannelAddedBy", R.string.ChannelAddedBy), "un1", whoUser);
|
||||
}
|
||||
} else {
|
||||
if (singleUserId == message.from_id) {
|
||||
if (message.to_id.channel_id != 0 && !isMegagroup()) {
|
||||
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 {
|
||||
if (whoUser != null && fromUser != null) {
|
||||
if (whoUser.id == fromUser.id) {
|
||||
if (isOut()) {
|
||||
messageText = LocaleController.getString("ActionAddUserSelfYou", R.string.ActionAddUserSelfYou);
|
||||
if (isOut()) {
|
||||
messageText = replaceWithLink(LocaleController.getString("ActionYouAddUser", R.string.ActionYouAddUser), "un2", whoUser);
|
||||
} else if (singleUserId == UserConfig.getClientUserId()) {
|
||||
if (message.to_id.channel_id != 0) {
|
||||
if (isMegagroup()) {
|
||||
messageText = replaceWithLink(LocaleController.getString("MegaAddedBy", R.string.MegaAddedBy), "un1", fromUser);
|
||||
} else {
|
||||
messageText = replaceWithLink(LocaleController.getString("ActionAddUserSelf", R.string.ActionAddUserSelf), "un1", fromUser);
|
||||
messageText = replaceWithLink(LocaleController.getString("ChannelAddedBy", R.string.ChannelAddedBy), "un1", fromUser);
|
||||
}
|
||||
} else {
|
||||
if (isOut()) {
|
||||
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);
|
||||
}
|
||||
messageText = replaceWithLink(LocaleController.getString("ActionAddUserYou", R.string.ActionAddUserYou), "un1", fromUser);
|
||||
}
|
||||
} 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 {
|
||||
|
@ -206,14 +196,10 @@ public class MessageObject {
|
|||
}
|
||||
}
|
||||
} else if (message.action instanceof TLRPC.TL_messageActionChatJoinedByLink) {
|
||||
if (fromUser != null) {
|
||||
if (isOut()) {
|
||||
messageText = LocaleController.getString("ActionInviteYou", R.string.ActionInviteYou);
|
||||
} else {
|
||||
messageText = replaceWithLink(LocaleController.getString("ActionInviteUser", R.string.ActionInviteUser), "un1", fromUser);
|
||||
}
|
||||
if (isOut()) {
|
||||
messageText = LocaleController.getString("ActionInviteYou", R.string.ActionInviteYou);
|
||||
} 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) {
|
||||
if (message.to_id.channel_id != 0 && !isMegagroup()) {
|
||||
|
@ -222,11 +208,7 @@ public class MessageObject {
|
|||
if (isOut()) {
|
||||
messageText = LocaleController.getString("ActionYouChangedPhoto", R.string.ActionYouChangedPhoto);
|
||||
} else {
|
||||
if (fromUser != null) {
|
||||
messageText = replaceWithLink(LocaleController.getString("ActionChangedPhoto", R.string.ActionChangedPhoto), "un1", fromUser);
|
||||
} else {
|
||||
messageText = LocaleController.getString("ActionChangedPhoto", R.string.ActionChangedPhoto).replace("un1", "");
|
||||
}
|
||||
messageText = replaceWithLink(LocaleController.getString("ActionChangedPhoto", R.string.ActionChangedPhoto), "un1", fromUser);
|
||||
}
|
||||
}
|
||||
} else if (message.action instanceof TLRPC.TL_messageActionChatEditTitle) {
|
||||
|
@ -236,11 +218,7 @@ public class MessageObject {
|
|||
if (isOut()) {
|
||||
messageText = LocaleController.getString("ActionYouChangedTitle", R.string.ActionYouChangedTitle).replace("un2", message.action.title);
|
||||
} else {
|
||||
if (fromUser != null) {
|
||||
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);
|
||||
}
|
||||
messageText = replaceWithLink(LocaleController.getString("ActionChangedTitle", R.string.ActionChangedTitle).replace("un2", message.action.title), "un1", fromUser);
|
||||
}
|
||||
}
|
||||
} else if (message.action instanceof TLRPC.TL_messageActionChatDeletePhoto) {
|
||||
|
@ -250,11 +228,7 @@ public class MessageObject {
|
|||
if (isOut()) {
|
||||
messageText = LocaleController.getString("ActionYouRemovedPhoto", R.string.ActionYouRemovedPhoto);
|
||||
} else {
|
||||
if (fromUser != null) {
|
||||
messageText = replaceWithLink(LocaleController.getString("ActionRemovedPhoto", R.string.ActionRemovedPhoto), "un1", fromUser);
|
||||
} else {
|
||||
messageText = LocaleController.getString("ActionRemovedPhoto", R.string.ActionRemovedPhoto).replace("un1", "");
|
||||
}
|
||||
messageText = replaceWithLink(LocaleController.getString("ActionRemovedPhoto", R.string.ActionRemovedPhoto), "un1", fromUser);
|
||||
}
|
||||
}
|
||||
} else if (message.action instanceof TLRPC.TL_messageActionTTLChange) {
|
||||
|
@ -262,21 +236,13 @@ public class MessageObject {
|
|||
if (isOut()) {
|
||||
messageText = LocaleController.formatString("MessageLifetimeChangedOutgoing", R.string.MessageLifetimeChangedOutgoing, AndroidUtilities.formatTTLString(message.action.ttl));
|
||||
} else {
|
||||
if (fromUser != null) {
|
||||
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));
|
||||
}
|
||||
messageText = LocaleController.formatString("MessageLifetimeChanged", R.string.MessageLifetimeChanged, UserObject.getFirstName(fromUser), AndroidUtilities.formatTTLString(message.action.ttl));
|
||||
}
|
||||
} else {
|
||||
if (isOut()) {
|
||||
messageText = LocaleController.getString("MessageLifetimeYouRemoved", R.string.MessageLifetimeYouRemoved);
|
||||
} else {
|
||||
if (fromUser != null) {
|
||||
messageText = LocaleController.formatString("MessageLifetimeRemoved", R.string.MessageLifetimeRemoved, UserObject.getFirstName(fromUser));
|
||||
} else {
|
||||
messageText = LocaleController.formatString("MessageLifetimeRemoved", R.string.MessageLifetimeRemoved, "");
|
||||
}
|
||||
messageText = LocaleController.formatString("MessageLifetimeRemoved", R.string.MessageLifetimeRemoved, UserObject.getFirstName(fromUser));
|
||||
}
|
||||
}
|
||||
} else if (message.action instanceof TLRPC.TL_messageActionLoginUnknownLocation) {
|
||||
|
@ -299,27 +265,15 @@ public class MessageObject {
|
|||
String name = to_user != null ? UserObject.getFirstName(to_user) : "";
|
||||
messageText = LocaleController.formatString("NotificationUnrecognizedDevice", R.string.NotificationUnrecognizedDevice, name, date, message.action.title, message.action.address);
|
||||
} else if (message.action instanceof TLRPC.TL_messageActionUserJoined) {
|
||||
if (fromUser != null) {
|
||||
messageText = LocaleController.formatString("NotificationContactJoined", R.string.NotificationContactJoined, UserObject.getUserName(fromUser));
|
||||
} else {
|
||||
messageText = LocaleController.formatString("NotificationContactJoined", R.string.NotificationContactJoined, "");
|
||||
}
|
||||
messageText = LocaleController.formatString("NotificationContactJoined", R.string.NotificationContactJoined, UserObject.getUserName(fromUser));
|
||||
} else if (message.action instanceof TLRPC.TL_messageActionUserUpdatedPhoto) {
|
||||
if (fromUser != null) {
|
||||
messageText = LocaleController.formatString("NotificationContactNewPhoto", R.string.NotificationContactNewPhoto, UserObject.getUserName(fromUser));
|
||||
} else {
|
||||
messageText = LocaleController.formatString("NotificationContactNewPhoto", R.string.NotificationContactNewPhoto, "");
|
||||
}
|
||||
messageText = LocaleController.formatString("NotificationContactNewPhoto", R.string.NotificationContactNewPhoto, UserObject.getUserName(fromUser));
|
||||
} else if (message.action instanceof TLRPC.TL_messageEncryptedAction) {
|
||||
if (message.action.encryptedAction instanceof TLRPC.TL_decryptedMessageActionScreenshotMessages) {
|
||||
if (isOut()) {
|
||||
messageText = LocaleController.formatString("ActionTakeScreenshootYou", R.string.ActionTakeScreenshootYou);
|
||||
} else {
|
||||
if (fromUser != null) {
|
||||
messageText = replaceWithLink(LocaleController.getString("ActionTakeScreenshoot", R.string.ActionTakeScreenshoot), "un1", fromUser);
|
||||
} else {
|
||||
messageText = LocaleController.formatString("ActionTakeScreenshoot", R.string.ActionTakeScreenshoot).replace("un1", "");
|
||||
}
|
||||
messageText = replaceWithLink(LocaleController.getString("ActionTakeScreenshoot", R.string.ActionTakeScreenshoot), "un1", fromUser);
|
||||
}
|
||||
} else if (message.action.encryptedAction instanceof TLRPC.TL_decryptedMessageActionSetMessageTTL) {
|
||||
TLRPC.TL_decryptedMessageActionSetMessageTTL action = (TLRPC.TL_decryptedMessageActionSetMessageTTL) message.action.encryptedAction;
|
||||
|
@ -327,21 +281,13 @@ public class MessageObject {
|
|||
if (isOut()) {
|
||||
messageText = LocaleController.formatString("MessageLifetimeChangedOutgoing", R.string.MessageLifetimeChangedOutgoing, AndroidUtilities.formatTTLString(action.ttl_seconds));
|
||||
} else {
|
||||
if (fromUser != null) {
|
||||
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));
|
||||
}
|
||||
messageText = LocaleController.formatString("MessageLifetimeChanged", R.string.MessageLifetimeChanged, UserObject.getFirstName(fromUser), AndroidUtilities.formatTTLString(action.ttl_seconds));
|
||||
}
|
||||
} else {
|
||||
if (isOut()) {
|
||||
messageText = LocaleController.getString("MessageLifetimeYouRemoved", R.string.MessageLifetimeYouRemoved);
|
||||
} else {
|
||||
if (fromUser != null) {
|
||||
messageText = LocaleController.formatString("MessageLifetimeRemoved", R.string.MessageLifetimeRemoved, UserObject.getFirstName(fromUser));
|
||||
} else {
|
||||
messageText = LocaleController.formatString("MessageLifetimeRemoved", R.string.MessageLifetimeRemoved, "");
|
||||
}
|
||||
messageText = LocaleController.formatString("MessageLifetimeRemoved", R.string.MessageLifetimeRemoved, UserObject.getFirstName(fromUser));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -357,6 +303,8 @@ public class MessageObject {
|
|||
messageText = LocaleController.getString("ActionMigrateFromGroup", R.string.ActionMigrateFromGroup);
|
||||
} else if (message.action instanceof TLRPC.TL_messageActionChannelMigrateFrom) {
|
||||
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()) {
|
||||
|
@ -402,27 +350,31 @@ public class MessageObject {
|
|||
|
||||
if (message instanceof TLRPC.TL_message || message instanceof TLRPC.TL_messageForwarded_old2) {
|
||||
if (isMediaEmpty()) {
|
||||
contentType = type = 0;
|
||||
contentType = 0;
|
||||
type = 0;
|
||||
if (messageText == null || messageText.length() == 0) {
|
||||
messageText = "Empty message";
|
||||
}
|
||||
} 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) {
|
||||
contentType = 1;
|
||||
contentType = 0;
|
||||
type = 4;
|
||||
} else if (isVideo()) {
|
||||
contentType = 1;
|
||||
contentType = 0;
|
||||
type = 3;
|
||||
} else if (isVoice()) {
|
||||
contentType = type = 2;
|
||||
contentType = 2;
|
||||
type = 2;
|
||||
} else if (message.media instanceof TLRPC.TL_messageMediaContact) {
|
||||
contentType = 3;
|
||||
type = 12;
|
||||
} else if (message.media instanceof TLRPC.TL_messageMediaUnsupported) {
|
||||
contentType = type = 0;
|
||||
contentType = 0;
|
||||
type = 0;
|
||||
} else if (message.media instanceof TLRPC.TL_messageMediaDocument) {
|
||||
contentType = 1;
|
||||
contentType = 0;
|
||||
if (message.media.document.mime_type != null) {
|
||||
if (isGifDocument(message.media.document)) {
|
||||
type = 8;
|
||||
|
@ -440,7 +392,8 @@ public class MessageObject {
|
|||
}
|
||||
} else if (message instanceof TLRPC.TL_messageService) {
|
||||
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) {
|
||||
contentType = 4;
|
||||
type = 11;
|
||||
|
@ -464,7 +417,7 @@ public class MessageObject {
|
|||
int dateYear = rightNow.get(Calendar.YEAR);
|
||||
int dateMonth = rightNow.get(Calendar.MONTH);
|
||||
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);
|
||||
} else if (contentType == 9) {
|
||||
//dateKey = "0_0_0";
|
||||
|
@ -484,6 +437,58 @@ public class MessageObject {
|
|||
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() {
|
||||
if (!layoutCreated) {
|
||||
layoutCreated = true;
|
||||
|
@ -662,6 +667,8 @@ public class MessageObject {
|
|||
return FileLoader.getAttachFileName(sizeFull);
|
||||
}
|
||||
}
|
||||
} else if (messageOwner.media instanceof TLRPC.TL_messageMediaWebPage) {
|
||||
return FileLoader.getAttachFileName(messageOwner.media.webpage.document);
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
@ -950,7 +957,7 @@ public class MessageObject {
|
|||
block.textLayout = textLayout;
|
||||
block.textYOffset = 0;
|
||||
block.charactersOffset = 0;
|
||||
blockHeight = textHeight;
|
||||
block.height = textHeight;
|
||||
} else {
|
||||
int startCharacter = textLayout.getLineStart(linesOffset);
|
||||
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.textYOffset = textLayout.getLineTop(linesOffset);
|
||||
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;
|
||||
/*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) {
|
||||
FileLog.e("tmessages", e);
|
||||
continue;
|
||||
|
@ -1067,9 +1068,6 @@ public class MessageObject {
|
|||
|
||||
linesOffset += currentBlockLinesCount;
|
||||
}
|
||||
if (blockHeight == 0) {
|
||||
blockHeight = 1;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isOut() {
|
||||
|
@ -1421,7 +1419,11 @@ public class MessageObject {
|
|||
}
|
||||
|
||||
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() {
|
||||
|
@ -1512,16 +1514,16 @@ public class MessageObject {
|
|||
}
|
||||
|
||||
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;
|
||||
}
|
||||
if (chat == null && message.to_id.channel_id != 0) {
|
||||
chat = MessagesController.getInstance().getChat(message.to_id.channel_id);
|
||||
}
|
||||
if (ChatObject.isChannel(chat) && chat.megagroup) {
|
||||
return message.out;
|
||||
if (chat == null) {
|
||||
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 ||
|
||||
message.media instanceof TLRPC.TL_messageMediaDocument && (isVideoMessage(message) || isGifDocument(message.media.document)) ||
|
||||
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.SQLitePreparedStatement;
|
||||
import org.telegram.messenger.query.BotQuery;
|
||||
import org.telegram.messenger.query.MessagesQuery;
|
||||
import org.telegram.messenger.query.SharedMediaQuery;
|
||||
import org.telegram.tgnet.ConnectionsManager;
|
||||
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 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 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 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 contacts(uid INTEGER PRIMARY KEY, mutual 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();
|
||||
|
||||
//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 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");
|
||||
if (version < 30) {
|
||||
if (version < 31) {
|
||||
updateDbToLastVersion(version);
|
||||
}
|
||||
}
|
||||
|
@ -487,7 +494,16 @@ public class MessagesStorage {
|
|||
database.executeFast("DELETE FROM sent_files_v2 WHERE 1").stepThis().dispose();
|
||||
database.executeFast("DELETE FROM download_queue WHERE 1").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) {
|
||||
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() {
|
||||
@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) {
|
||||
continue;
|
||||
}
|
||||
long did = -channelId;
|
||||
final ArrayList<Integer> mids = new ArrayList<>();
|
||||
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.from_id == uid && message.id != 1) {
|
||||
mids.add(message.id);
|
||||
if (message.media instanceof TLRPC.TL_messageMediaPhoto) {
|
||||
for (TLRPC.PhotoSize photoSize : message.media.photo.sizes) {
|
||||
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();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
|
@ -1058,6 +1138,7 @@ public class MessagesStorage {
|
|||
if (messagesOnly == 0) {
|
||||
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_pinned WHERE uid = " + 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();
|
||||
int lower_id = (int)did;
|
||||
|
@ -1084,10 +1165,9 @@ public class MessagesStorage {
|
|||
NativeByteBuffer data = new NativeByteBuffer(cursor2.byteArrayLength(0));
|
||||
if (data != null && cursor2.byteBufferValue(0, data) != 0) {
|
||||
TLRPC.Message message = TLRPC.Message.TLdeserialize(data, data.readInt32(false), false);
|
||||
if (message == null) {
|
||||
continue;
|
||||
if (message != null) {
|
||||
arrayList.add(message);
|
||||
}
|
||||
arrayList.add(message);
|
||||
}
|
||||
data.reuse();
|
||||
}
|
||||
|
@ -1429,13 +1509,14 @@ public class MessagesStorage {
|
|||
@Override
|
||||
public void run() {
|
||||
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;
|
||||
ArrayList<TLRPC.User> loadedUsers = new ArrayList<>();
|
||||
if (cursor.next()) {
|
||||
NativeByteBuffer data = new NativeByteBuffer(cursor.byteArrayLength(0));
|
||||
if (data != null && cursor.byteBufferValue(0, data) != 0) {
|
||||
info = TLRPC.ChatFull.TLdeserialize(data, data.readInt32(false), false);
|
||||
info.pinned_msg_id = cursor.intValue(1);
|
||||
}
|
||||
data.reuse();
|
||||
}
|
||||
|
@ -1446,15 +1527,16 @@ public class MessagesStorage {
|
|||
AndroidUtilities.runOnUIThread(new Runnable() {
|
||||
@Override
|
||||
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());
|
||||
info.serializeToStream(data);
|
||||
state.bindInteger(1, info.id);
|
||||
state.bindByteBuffer(2, data);
|
||||
state.bindInteger(3, info.pinned_msg_id);
|
||||
state.step();
|
||||
state.dispose();
|
||||
data.reuse();
|
||||
|
@ -1516,11 +1598,12 @@ public class MessagesStorage {
|
|||
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());
|
||||
info.serializeToStream(data);
|
||||
state.bindInteger(1, info.id);
|
||||
state.bindByteBuffer(2, data);
|
||||
state.bindInteger(3, info.pinned_msg_id);
|
||||
state.step();
|
||||
state.dispose();
|
||||
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) {
|
||||
storageQueue.postRunnable(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
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;
|
||||
ArrayList<TLRPC.User> loadedUsers = new ArrayList<>();
|
||||
if (cursor.next()) {
|
||||
NativeByteBuffer data = new NativeByteBuffer(cursor.byteArrayLength(0));
|
||||
if (data != null && cursor.byteBufferValue(0, data) != 0) {
|
||||
info = TLRPC.ChatFull.TLdeserialize(data, data.readInt32(false), false);
|
||||
info.pinned_msg_id = cursor.intValue(1);
|
||||
}
|
||||
data.reuse();
|
||||
}
|
||||
|
@ -1620,15 +1750,16 @@ public class MessagesStorage {
|
|||
AndroidUtilities.runOnUIThread(new Runnable() {
|
||||
@Override
|
||||
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());
|
||||
info.serializeToStream(data);
|
||||
state.bindInteger(1, chat_id);
|
||||
state.bindByteBuffer(2, data);
|
||||
state.bindInteger(3, info.pinned_msg_id);
|
||||
state.step();
|
||||
state.dispose();
|
||||
data.reuse();
|
||||
|
@ -1684,13 +1815,14 @@ public class MessagesStorage {
|
|||
@Override
|
||||
public void run() {
|
||||
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;
|
||||
ArrayList<TLRPC.User> loadedUsers = new ArrayList<>();
|
||||
if (cursor.next()) {
|
||||
NativeByteBuffer data = new NativeByteBuffer(cursor.byteArrayLength(0));
|
||||
if (data != null && cursor.byteBufferValue(0, data) != 0) {
|
||||
info = TLRPC.ChatFull.TLdeserialize(data, data.readInt32(false), false);
|
||||
info.pinned_msg_id = cursor.intValue(1);
|
||||
}
|
||||
data.reuse();
|
||||
}
|
||||
|
@ -1754,7 +1886,12 @@ public class MessagesStorage {
|
|||
if (semaphore != null) {
|
||||
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) {
|
||||
FileLog.e("tmessages", e);
|
||||
} finally {
|
||||
|
@ -2281,7 +2418,7 @@ public class MessagesStorage {
|
|||
holeMessageMinId |= ((long) channelId) << 32;
|
||||
}
|
||||
}
|
||||
/*if (holeMessageMaxId == holeMessageMinId) { TODO ???
|
||||
/*if (holeMessageMaxId == holeMessageMinId) {
|
||||
holeMessageMaxId = 0;
|
||||
holeMessageMinId = 1;
|
||||
}*/
|
||||
|
@ -2422,19 +2559,17 @@ public class MessagesStorage {
|
|||
addUsersAndChatsFromMessage(message, usersToLoad, chatsToLoad);
|
||||
|
||||
if (message.reply_to_msg_id != 0 || message.reply_to_random_id != 0) {
|
||||
boolean ok = false;
|
||||
if (!cursor.isNull(6)) {
|
||||
NativeByteBuffer data2 = new NativeByteBuffer(cursor.byteArrayLength(6));
|
||||
if (data2 != null && cursor.byteBufferValue(6, data2) != 0) {
|
||||
message.replyMessage = TLRPC.Message.TLdeserialize(data2, data2.readInt32(false), false);
|
||||
if (message.replyMessage != null) {
|
||||
addUsersAndChatsFromMessage(message.replyMessage, usersToLoad, chatsToLoad);
|
||||
ok = true;
|
||||
}
|
||||
}
|
||||
data2.reuse();
|
||||
}
|
||||
if (!ok) {
|
||||
if (message.replyMessage == null) {
|
||||
if (message.reply_to_msg_id != 0) {
|
||||
long messageId = message.reply_to_msg_id;
|
||||
if (message.to_id.channel_id != 0) {
|
||||
|
@ -3037,7 +3172,7 @@ public class MessagesStorage {
|
|||
NativeByteBuffer data = new NativeByteBuffer(cursor.byteArrayLength(0));
|
||||
if (data != null && cursor.byteBufferValue(0, data) != 0) {
|
||||
TLRPC.User oldUser = TLRPC.User.TLdeserialize(data, data.readInt32(false), false);
|
||||
if (user != null) {
|
||||
if (oldUser != null) {
|
||||
if (user.first_name != null) {
|
||||
oldUser.first_name = user.first_name;
|
||||
oldUser.flags |= 2;
|
||||
|
@ -3052,6 +3187,13 @@ public class MessagesStorage {
|
|||
oldUser.last_name = null;
|
||||
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) {
|
||||
oldUser.photo = user.photo;
|
||||
oldUser.flags |= 32;
|
||||
|
@ -3059,8 +3201,8 @@ public class MessagesStorage {
|
|||
oldUser.photo = null;
|
||||
oldUser.flags = oldUser.flags &~ 32;
|
||||
}
|
||||
user = oldUser;
|
||||
}
|
||||
user = oldUser;
|
||||
}
|
||||
data.reuse();
|
||||
} catch (Exception e) {
|
||||
|
@ -3099,6 +3241,36 @@ public class MessagesStorage {
|
|||
SQLitePreparedStatement state = database.executeFast("REPLACE INTO chats VALUES(?, ?, ?)");
|
||||
for (int a = 0; a < chats.size(); 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();
|
||||
NativeByteBuffer data = new NativeByteBuffer(chat.getObjectSize());
|
||||
chat.serializeToStream(data);
|
||||
|
@ -4119,7 +4291,6 @@ public class MessagesStorage {
|
|||
} catch (Exception e2) {
|
||||
FileLog.e("tmessages", e2);
|
||||
}
|
||||
FileLog.e("tmessages", e);
|
||||
} finally {
|
||||
if (state != null) {
|
||||
state.dispose();
|
||||
|
@ -4138,7 +4309,6 @@ public class MessagesStorage {
|
|||
} catch (Exception e2) {
|
||||
FileLog.e("tmessages", e2);
|
||||
}
|
||||
FileLog.e("tmessages", e);
|
||||
} finally {
|
||||
if (state != null) {
|
||||
state.dispose();
|
||||
|
@ -4388,24 +4558,23 @@ public class MessagesStorage {
|
|||
NativeByteBuffer data = new NativeByteBuffer(cursor.byteArrayLength(1));
|
||||
if (data != null && cursor.byteBufferValue(1, data) != 0) {
|
||||
TLRPC.Message message = TLRPC.Message.TLdeserialize(data, data.readInt32(false), false);
|
||||
if (message == null || message.media == null) {
|
||||
continue;
|
||||
}
|
||||
if (message.media instanceof TLRPC.TL_messageMediaPhoto) {
|
||||
for (TLRPC.PhotoSize photoSize : message.media.photo.sizes) {
|
||||
File file = FileLoader.getPathToAttach(photoSize);
|
||||
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);
|
||||
}
|
||||
}
|
||||
} 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());
|
||||
ArrayList<Integer> chatsToLoad = 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()) {
|
||||
TLRPC.Dialog dialog;
|
||||
int pts = cursor.intValue(12);
|
||||
|
@ -5181,6 +5352,33 @@ public class MessagesStorage {
|
|||
dialogs.messages.add(message);
|
||||
|
||||
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();
|
||||
|
@ -5211,6 +5409,29 @@ public class MessagesStorage {
|
|||
}
|
||||
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()) {
|
||||
getEncryptedChatsInternal(TextUtils.join(",", encryptedToLoad), encryptedChats, usersToLoad);
|
||||
}
|
||||
|
|
|
@ -23,7 +23,7 @@ import java.util.zip.ZipFile;
|
|||
|
||||
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_SO_NAME = "lib" + LIB_NAME + ".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 screenStateChanged = totalEvents++;
|
||||
public static final int didLoadedReplyMessages = totalEvents++;
|
||||
public static final int didLoadedPinnedMessage = totalEvents++;
|
||||
public static final int newSessionReceived = totalEvents++;
|
||||
public static final int didReceivedWebpages = totalEvents++;
|
||||
public static final int didReceivedWebpagesInUpdates = totalEvents++;
|
||||
|
@ -60,6 +61,7 @@ public class NotificationCenter {
|
|||
public static final int didReplacedPhotoInMemCache = totalEvents++;
|
||||
public static final int messagesReadContent = totalEvents++;
|
||||
public static final int botInfoDidLoaded = totalEvents++;
|
||||
public static final int userInfoDidLoaded = totalEvents++;
|
||||
public static final int botKeyboardDidLoaded = totalEvents++;
|
||||
public static final int chatSearchResultsAvailable = totalEvents++;
|
||||
public static final int musicDidLoaded = totalEvents++;
|
||||
|
@ -67,6 +69,7 @@ public class NotificationCenter {
|
|||
public static final int didUpdatedMessagesViews = totalEvents++;
|
||||
public static final int needReloadRecentDialogsSearch = totalEvents++;
|
||||
public static final int locationPermissionGranted = totalEvents++;
|
||||
public static final int peerSettingsDidLoaded = totalEvents++;
|
||||
|
||||
public static final int httpFileDidLoaded = totalEvents++;
|
||||
public static final int httpFileDidFailedLoad = totalEvents++;
|
||||
|
|
|
@ -61,7 +61,7 @@ public class NotificationsController {
|
|||
private int wearNotificationId = 10000;
|
||||
private int autoNotificationId = 20000;
|
||||
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 personal_count = 0;
|
||||
private boolean notifyCheck = false;
|
||||
|
@ -147,7 +147,7 @@ public class NotificationsController {
|
|||
notificationsQueue.postRunnable(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
openned_dialog_id = 0;
|
||||
opened_dialog_id = 0;
|
||||
total_unread_count = 0;
|
||||
personal_count = 0;
|
||||
pushMessages.clear();
|
||||
|
@ -178,11 +178,11 @@ public class NotificationsController {
|
|||
inChatSoundEnabled = value;
|
||||
}
|
||||
|
||||
public void setOpennedDialogId(final long dialog_id) {
|
||||
public void setOpenedDialogId(final long dialog_id) {
|
||||
notificationsQueue.postRunnable(new Runnable() {
|
||||
@Override
|
||||
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 original_dialog_id = dialog_id;
|
||||
if (dialog_id == openned_dialog_id && ApplicationLoader.isScreenOn) {
|
||||
if (dialog_id == opened_dialog_id && ApplicationLoader.isScreenOn) {
|
||||
playInChatSound();
|
||||
continue;
|
||||
}
|
||||
|
@ -406,7 +406,7 @@ public class NotificationsController {
|
|||
added = true;
|
||||
|
||||
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);
|
||||
if (value == null) {
|
||||
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);
|
||||
settingsCache.put(dialog_id, value);
|
||||
}
|
||||
if (!value || dialog_id == openned_dialog_id && ApplicationLoader.isScreenOn) {
|
||||
if (!value || dialog_id == opened_dialog_id && ApplicationLoader.isScreenOn) {
|
||||
continue;
|
||||
}
|
||||
pushMessagesDict.put(mid, messageObject);
|
||||
|
@ -757,6 +757,8 @@ public class NotificationsController {
|
|||
msg = LocaleController.formatString("NotificationMessageVideo", R.string.NotificationMessageVideo, name);
|
||||
} else if (messageObject.isVoice()) {
|
||||
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) {
|
||||
msg = LocaleController.formatString("NotificationMessageContact", R.string.NotificationMessageContact, name);
|
||||
} 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;
|
||||
}
|
||||
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 {
|
||||
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);
|
||||
} else if (messageObject.messageOwner.action instanceof TLRPC.TL_messageActionChannelMigrateFrom) {
|
||||
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 {
|
||||
if (ChatObject.isChannel(chat) && !chat.megagroup) {
|
||||
if (from_id < 0) {
|
||||
if (messageObject.isImportant()) {
|
||||
if (messageObject.isMediaEmpty()) {
|
||||
if (!shortMessage && messageObject.messageOwner.message != null && messageObject.messageOwner.message.length() != 0) {
|
||||
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);
|
||||
} else if (messageObject.isVoice()) {
|
||||
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) {
|
||||
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) {
|
||||
|
@ -893,6 +982,8 @@ public class NotificationsController {
|
|||
msg = LocaleController.formatString("ChannelMessageGroupVideo", R.string.ChannelMessageGroupVideo, name, chat.title);
|
||||
} else if (messageObject.isVoice()) {
|
||||
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) {
|
||||
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) {
|
||||
|
@ -920,6 +1011,8 @@ public class NotificationsController {
|
|||
msg = LocaleController.formatString("NotificationMessageGroupVideo", R.string.NotificationMessageGroupVideo, name, chat.title);
|
||||
} else if (messageObject.isVoice()) {
|
||||
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) {
|
||||
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) {
|
||||
|
@ -1073,7 +1166,7 @@ public class NotificationsController {
|
|||
|
||||
try {
|
||||
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) {
|
||||
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) {
|
||||
mBuilder.setPriority(NotificationCompat.PRIORITY_LOW);
|
||||
} else {
|
||||
|
|
|
@ -820,6 +820,7 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter
|
|||
req.message = message;
|
||||
req.id = messageObject.getId();
|
||||
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() {
|
||||
@Override
|
||||
public void run(TLObject response, TLRPC.TL_error error) {
|
||||
|
@ -2002,6 +2003,7 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter
|
|||
|
||||
if (!isSentError) {
|
||||
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() {
|
||||
@Override
|
||||
public void run() {
|
||||
|
@ -2274,7 +2276,7 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter
|
|||
if (extension == null) {
|
||||
extension = "txt";
|
||||
}
|
||||
path = MediaController.copyDocumentToCache(uri, extension);
|
||||
path = MediaController.copyFileToCache(uri, extension);
|
||||
if (path == null) {
|
||||
return false;
|
||||
}
|
||||
|
@ -2923,12 +2925,12 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter
|
|||
if (MediaController.isGif(uri)) {
|
||||
isDocument = true;
|
||||
originalPath = uri.toString();
|
||||
tempPath = MediaController.copyDocumentToCache(uri, "gif");
|
||||
tempPath = MediaController.copyFileToCache(uri, "gif");
|
||||
extension = "gif";
|
||||
} else if (MediaController.isWebp(uri)) {
|
||||
isDocument = true;
|
||||
originalPath = uri.toString();
|
||||
tempPath = MediaController.copyDocumentToCache(uri, "webp");
|
||||
tempPath = MediaController.copyFileToCache(uri, "webp");
|
||||
extension = "webp";
|
||||
}
|
||||
}
|
||||
|
@ -3009,8 +3011,7 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter
|
|||
}
|
||||
TLRPC.TL_document document = null;
|
||||
if (!isEncrypted) {
|
||||
TLObject object = MessagesStorage.getInstance().getSentFile(originalPath, !isEncrypted ? 2 : 5);
|
||||
document = (TLRPC.TL_document) object;
|
||||
//document = (TLRPC.TL_document) MessagesStorage.getInstance().getSentFile(originalPath, !isEncrypted ? 2 : 5);
|
||||
}
|
||||
if (document == null) {
|
||||
Bitmap thumb = ThumbnailUtils.createVideoThumbnail(videoPath, MediaStore.Video.Thumbnails.MINI_KIND);
|
||||
|
|
|
@ -9,8 +9,10 @@
|
|||
package org.telegram.messenger;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.app.Activity;
|
||||
import android.content.ComponentName;
|
||||
import android.content.IntentFilter;
|
||||
import android.content.SharedPreferences;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.graphics.BitmapShader;
|
||||
|
@ -48,6 +50,11 @@ public class TgChooserTargetService extends ChooserTargetService {
|
|||
if (!UserConfig.isClientActivated()) {
|
||||
return targets;
|
||||
}
|
||||
SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("mainconfig", Activity.MODE_PRIVATE);
|
||||
if (!preferences.getBoolean("direct_share", true)) {
|
||||
return targets;
|
||||
}
|
||||
|
||||
ImageLoader imageLoader = ImageLoader.getInstance();
|
||||
final Semaphore semaphore = new Semaphore(0);
|
||||
final ComponentName componentName = new ComponentName(getPackageName(), LaunchActivity.class.getCanonicalName());
|
||||
|
|
|
@ -179,7 +179,7 @@ public class BotQuery {
|
|||
}
|
||||
|
||||
public static void putBotInfo(final TLRPC.BotInfo botInfo) {
|
||||
if (botInfo == null || botInfo instanceof TLRPC.TL_botInfoEmpty) {
|
||||
if (botInfo == null) {
|
||||
return;
|
||||
}
|
||||
botInfos.put(botInfo.user_id, botInfo);
|
||||
|
|
|
@ -29,10 +29,158 @@ import java.util.ArrayList;
|
|||
import java.util.HashMap;
|
||||
import java.util.Locale;
|
||||
|
||||
public class ReplyMessageQuery {
|
||||
public class MessagesQuery {
|
||||
|
||||
public static void loadReplyMessagesForMessages(final ArrayList<MessageObject> messages, final long dialog_id) {
|
||||
if ((int) dialog_id == 0) {
|
||||
public static MessageObject loadPinnedMessage(final int channelId, final int mid, boolean useQueue) {
|
||||
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 HashMap<Long, ArrayList<MessageObject>> replyMessageRandomOwners = new HashMap<>();
|
||||
final StringBuilder stringBuilder = new StringBuilder();
|
||||
|
@ -70,7 +218,7 @@ public class ReplyMessageQuery {
|
|||
TLRPC.Message message = TLRPC.Message.TLdeserialize(data, data.readInt32(false), false);
|
||||
message.id = cursor.intValue(1);
|
||||
message.date = cursor.intValue(2);
|
||||
message.dialog_id = dialog_id;
|
||||
message.dialog_id = dialogId;
|
||||
|
||||
|
||||
ArrayList<MessageObject> arrayList = replyMessageRandomOwners.remove(cursor.longValue(3));
|
||||
|
@ -97,7 +245,7 @@ public class ReplyMessageQuery {
|
|||
AndroidUtilities.runOnUIThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
NotificationCenter.getInstance().postNotificationName(NotificationCenter.didLoadedReplyMessages, dialog_id);
|
||||
NotificationCenter.getInstance().postNotificationName(NotificationCenter.didLoadedReplyMessages, dialogId);
|
||||
}
|
||||
});
|
||||
} catch (Exception e) {
|
||||
|
@ -105,7 +253,6 @@ public class ReplyMessageQuery {
|
|||
}
|
||||
}
|
||||
});
|
||||
|
||||
} else {
|
||||
final ArrayList<Integer> replyMessages = new ArrayList<>();
|
||||
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);
|
||||
message.id = cursor.intValue(1);
|
||||
message.date = cursor.intValue(2);
|
||||
message.dialog_id = dialog_id;
|
||||
message.dialog_id = dialogId;
|
||||
MessagesStorage.addUsersAndChatsFromMessage(message, usersToLoad, chatsToLoad);
|
||||
result.add(message);
|
||||
replyMessages.remove((Integer) message.id);
|
||||
|
@ -172,7 +319,7 @@ public class ReplyMessageQuery {
|
|||
if (!chatsToLoad.isEmpty()) {
|
||||
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 (channelIdFinal != 0) {
|
||||
|
@ -185,7 +332,7 @@ public class ReplyMessageQuery {
|
|||
if (error == null) {
|
||||
TLRPC.messages_Messages messagesRes = (TLRPC.messages_Messages) response;
|
||||
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);
|
||||
saveReplyMessages(replyMessageOwners, messagesRes.messages);
|
||||
}
|
||||
|
@ -200,7 +347,7 @@ public class ReplyMessageQuery {
|
|||
if (error == null) {
|
||||
TLRPC.messages_Messages messagesRes = (TLRPC.messages_Messages) response;
|
||||
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);
|
||||
saveReplyMessages(replyMessageOwners, messagesRes.messages);
|
||||
}
|
||||
|
@ -223,12 +370,14 @@ public class ReplyMessageQuery {
|
|||
try {
|
||||
MessagesStorage.getInstance().getDatabase().beginTransaction();
|
||||
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);
|
||||
if (messageObjects != null) {
|
||||
NativeByteBuffer data = new NativeByteBuffer(message.getObjectSize());
|
||||
message.serializeToStream(data);
|
||||
for (MessageObject messageObject : messageObjects) {
|
||||
for (int b = 0; b < messageObjects.size(); b++) {
|
||||
MessageObject messageObject = messageObjects.get(b);
|
||||
state.requery();
|
||||
long messageId = messageObject.getId();
|
||||
if (messageObject.messageOwner.to_id.channel_id != 0) {
|
||||
|
@ -275,6 +424,9 @@ public class ReplyMessageQuery {
|
|||
for (int b = 0; b < arrayList.size(); b++) {
|
||||
MessageObject m = arrayList.get(b);
|
||||
m.replyMessageObject = messageObject;
|
||||
if (m.messageOwner.action instanceof TLRPC.TL_messageActionPinMessage) {
|
||||
m.generatePinMessageText(null, null);
|
||||
}
|
||||
}
|
||||
changed = true;
|
||||
}
|
|
@ -22,9 +22,6 @@ import android.util.Log;
|
|||
import android.util.SparseBooleanArray;
|
||||
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.
|
||||
* <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
|
||||
* secondary storage such as disk, but not from network.
|
||||
* <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.
|
||||
*
|
||||
*/
|
||||
|
@ -113,7 +110,7 @@ public class AsyncListUtil<T> {
|
|||
* <p>
|
||||
* 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
|
||||
* {@link org.telegram.messenger.support.widget.RecyclerView.OnScrollListener#onScrolled}).
|
||||
* {@link android.support.v7.widget.RecyclerView.OnScrollListener#onScrolled}).
|
||||
*/
|
||||
public void onRangeChanged() {
|
||||
if (isRefreshPending()) {
|
||||
|
|
|
@ -18,10 +18,11 @@ package org.telegram.messenger.support.util;
|
|||
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.support.v4.content.ParallelExecutorCompat;
|
||||
import android.util.Log;
|
||||
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
class MessageThreadUtil<T> implements ThreadUtil<T> {
|
||||
|
||||
|
@ -83,7 +84,8 @@ class MessageThreadUtil<T> implements ThreadUtil<T> {
|
|||
public BackgroundCallback<T> getBackgroundProxy(final BackgroundCallback<T> callback) {
|
||||
return new BackgroundCallback<T>() {
|
||||
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 UPDATE_RANGE = 2;
|
||||
|
@ -114,42 +116,51 @@ class MessageThreadUtil<T> implements ThreadUtil<T> {
|
|||
|
||||
private void sendMessage(SyncQueueItem msg) {
|
||||
mQueue.sendMessage(msg);
|
||||
mExecutor.execute(mBackgroundRunnable);
|
||||
maybeExecuteBackgroundRunnable();
|
||||
}
|
||||
|
||||
private void sendMessageAtFrontOfQueue(SyncQueueItem msg) {
|
||||
mQueue.sendMessageAtFrontOfQueue(msg);
|
||||
mExecutor.execute(mBackgroundRunnable);
|
||||
maybeExecuteBackgroundRunnable();
|
||||
}
|
||||
|
||||
private void maybeExecuteBackgroundRunnable() {
|
||||
if (mBackgroundRunning.compareAndSet(false, true)) {
|
||||
mExecutor.execute(mBackgroundRunnable);
|
||||
}
|
||||
}
|
||||
|
||||
private Runnable mBackgroundRunnable = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
SyncQueueItem msg = mQueue.next();
|
||||
if (msg == null) {
|
||||
return;
|
||||
}
|
||||
switch (msg.what) {
|
||||
case REFRESH:
|
||||
mQueue.removeMessages(REFRESH);
|
||||
callback.refresh(msg.arg1);
|
||||
break;
|
||||
case UPDATE_RANGE:
|
||||
mQueue.removeMessages(UPDATE_RANGE);
|
||||
mQueue.removeMessages(LOAD_TILE);
|
||||
callback.updateRange(
|
||||
msg.arg1, msg.arg2, msg.arg3, msg.arg4, msg.arg5);
|
||||
break;
|
||||
case LOAD_TILE:
|
||||
callback.loadTile(msg.arg1, msg.arg2);
|
||||
break;
|
||||
case RECYCLE_TILE:
|
||||
//noinspection unchecked
|
||||
callback.recycleTile((TileList.Tile<T>) msg.data);
|
||||
break;
|
||||
default:
|
||||
Log.e("ThreadUtil", "Unsupported message, what=" + msg.what);
|
||||
while (true) {
|
||||
SyncQueueItem msg = mQueue.next();
|
||||
if (msg == null) {
|
||||
break;
|
||||
}
|
||||
switch (msg.what) {
|
||||
case REFRESH:
|
||||
mQueue.removeMessages(REFRESH);
|
||||
callback.refresh(msg.arg1);
|
||||
break;
|
||||
case UPDATE_RANGE:
|
||||
mQueue.removeMessages(UPDATE_RANGE);
|
||||
mQueue.removeMessages(LOAD_TILE);
|
||||
callback.updateRange(
|
||||
msg.arg1, msg.arg2, msg.arg3, msg.arg4, msg.arg5);
|
||||
break;
|
||||
case LOAD_TILE:
|
||||
callback.loadTile(msg.arg1, msg.arg2);
|
||||
break;
|
||||
case RECYCLE_TILE:
|
||||
//noinspection unchecked
|
||||
callback.recycleTile((TileList.Tile<T>) msg.data);
|
||||
break;
|
||||
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
|
||||
* 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}.
|
||||
* <p>
|
||||
* It keeps items ordered using the {@link Callback#compare(Object, Object)} method and uses
|
||||
|
@ -737,7 +737,7 @@ public class SortedList<T> {
|
|||
* so
|
||||
* that you can change its behavior depending on your UI.
|
||||
* <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
|
||||
* return whether the items' visual representations are the same or not.
|
||||
*
|
||||
|
|
|
@ -16,8 +16,6 @@
|
|||
|
||||
package org.telegram.messenger.support.util;
|
||||
|
||||
import org.telegram.messenger.support.util.TileList;
|
||||
|
||||
interface ThreadUtil<T> {
|
||||
|
||||
interface MainThreadCallback<T> {
|
||||
|
|
|
@ -19,9 +19,6 @@ package org.telegram.messenger.support.widget;
|
|||
import android.support.v4.util.Pools;
|
||||
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.Collections;
|
||||
import java.util.List;
|
||||
|
@ -70,6 +67,8 @@ class AdapterHelper implements OpReorderer.Callback {
|
|||
|
||||
final OpReorderer mOpReorderer;
|
||||
|
||||
private int mExistingUpdateTypes = 0;
|
||||
|
||||
AdapterHelper(Callback callback) {
|
||||
this(callback, false);
|
||||
}
|
||||
|
@ -88,6 +87,7 @@ class AdapterHelper implements OpReorderer.Callback {
|
|||
void reset() {
|
||||
recycleUpdateOpsAndClearList(mPendingUpdates);
|
||||
recycleUpdateOpsAndClearList(mPostponedList);
|
||||
mExistingUpdateTypes = 0;
|
||||
}
|
||||
|
||||
void preProcess() {
|
||||
|
@ -122,6 +122,7 @@ class AdapterHelper implements OpReorderer.Callback {
|
|||
mCallback.onDispatchSecondPass(mPostponedList.get(i));
|
||||
}
|
||||
recycleUpdateOpsAndClearList(mPostponedList);
|
||||
mExistingUpdateTypes = 0;
|
||||
}
|
||||
|
||||
private void applyMove(UpdateOp op) {
|
||||
|
@ -460,6 +461,10 @@ class AdapterHelper implements OpReorderer.Callback {
|
|||
return mPendingUpdates.size() > 0;
|
||||
}
|
||||
|
||||
boolean hasAnyUpdateTypes(int updateTypes) {
|
||||
return (mExistingUpdateTypes & updateTypes) != 0;
|
||||
}
|
||||
|
||||
int findPositionOffset(int position) {
|
||||
return findPositionOffset(position, 0);
|
||||
}
|
||||
|
@ -498,6 +503,7 @@ class AdapterHelper implements OpReorderer.Callback {
|
|||
*/
|
||||
boolean onItemRangeChanged(int positionStart, int itemCount, Object payload) {
|
||||
mPendingUpdates.add(obtainUpdateOp(UpdateOp.UPDATE, positionStart, itemCount, payload));
|
||||
mExistingUpdateTypes |= UpdateOp.UPDATE;
|
||||
return mPendingUpdates.size() == 1;
|
||||
}
|
||||
|
||||
|
@ -506,6 +512,7 @@ class AdapterHelper implements OpReorderer.Callback {
|
|||
*/
|
||||
boolean onItemRangeInserted(int positionStart, int itemCount) {
|
||||
mPendingUpdates.add(obtainUpdateOp(UpdateOp.ADD, positionStart, itemCount, null));
|
||||
mExistingUpdateTypes |= UpdateOp.ADD;
|
||||
return mPendingUpdates.size() == 1;
|
||||
}
|
||||
|
||||
|
@ -514,6 +521,7 @@ class AdapterHelper implements OpReorderer.Callback {
|
|||
*/
|
||||
boolean onItemRangeRemoved(int positionStart, int itemCount) {
|
||||
mPendingUpdates.add(obtainUpdateOp(UpdateOp.REMOVE, positionStart, itemCount, null));
|
||||
mExistingUpdateTypes |= UpdateOp.REMOVE;
|
||||
return mPendingUpdates.size() == 1;
|
||||
}
|
||||
|
||||
|
@ -522,12 +530,13 @@ class AdapterHelper implements OpReorderer.Callback {
|
|||
*/
|
||||
boolean onItemRangeMoved(int from, int to, int itemCount) {
|
||||
if (from == to) {
|
||||
return false;//no-op
|
||||
return false; // no-op
|
||||
}
|
||||
if (itemCount != 1) {
|
||||
throw new IllegalArgumentException("Moving more than 1 item is not supported yet");
|
||||
}
|
||||
mPendingUpdates.add(obtainUpdateOp(UpdateOp.MOVE, from, to, null));
|
||||
mExistingUpdateTypes |= UpdateOp.MOVE;
|
||||
return mPendingUpdates.size() == 1;
|
||||
}
|
||||
|
||||
|
@ -564,6 +573,7 @@ class AdapterHelper implements OpReorderer.Callback {
|
|||
}
|
||||
}
|
||||
recycleUpdateOpsAndClearList(mPendingUpdates);
|
||||
mExistingUpdateTypes = 0;
|
||||
}
|
||||
|
||||
public int applyPendingUpdatesToPosition(int position) {
|
||||
|
@ -602,18 +612,22 @@ class AdapterHelper implements OpReorderer.Callback {
|
|||
return position;
|
||||
}
|
||||
|
||||
boolean hasUpdates() {
|
||||
return !mPostponedList.isEmpty() && !mPendingUpdates.isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Queued operation to happen when child views are updated.
|
||||
*/
|
||||
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;
|
||||
|
||||
|
|
|
@ -208,8 +208,8 @@ class ChildHelper {
|
|||
for (int i = 0; i < count; i++) {
|
||||
final View view = mHiddenViews.get(i);
|
||||
RecyclerView.ViewHolder holder = mCallback.getChildViewHolder(view);
|
||||
if (holder.getLayoutPosition() == position && !holder.isInvalid() &&
|
||||
(type == RecyclerView.INVALID_TYPE || holder.getItemViewType() == type)) {
|
||||
if (holder.getLayoutPosition() == position && !holder.isInvalid() && !holder.isRemoved()
|
||||
&& (type == RecyclerView.INVALID_TYPE || holder.getItemViewType() == type)) {
|
||||
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
|
||||
public String toString() {
|
||||
return mBucket.toString() + ", hidden list:" + mHiddenViews.size();
|
||||
|
|
|
@ -15,12 +15,11 @@
|
|||
*/
|
||||
package org.telegram.messenger.support.widget;
|
||||
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.v4.animation.AnimatorCompatHelper;
|
||||
import android.support.v4.view.ViewCompat;
|
||||
import android.support.v4.view.ViewPropertyAnimatorCompat;
|
||||
import android.support.v4.view.ViewPropertyAnimatorListener;
|
||||
|
||||
import org.telegram.messenger.support.widget.RecyclerView;
|
||||
import org.telegram.messenger.support.widget.RecyclerView.ViewHolder;
|
||||
import android.view.View;
|
||||
|
||||
|
@ -34,23 +33,22 @@ import java.util.List;
|
|||
*
|
||||
* @see RecyclerView#setItemAnimator(RecyclerView.ItemAnimator)
|
||||
*/
|
||||
public class DefaultItemAnimator extends RecyclerView.ItemAnimator {
|
||||
public class DefaultItemAnimator extends SimpleItemAnimator {
|
||||
private static final boolean DEBUG = false;
|
||||
|
||||
private ArrayList<ViewHolder> mPendingRemovals = new ArrayList<ViewHolder>();
|
||||
private ArrayList<ViewHolder> mPendingAdditions = new ArrayList<ViewHolder>();
|
||||
private ArrayList<MoveInfo> mPendingMoves = new ArrayList<MoveInfo>();
|
||||
private ArrayList<ChangeInfo> mPendingChanges = new ArrayList<ChangeInfo>();
|
||||
private ArrayList<ViewHolder> mPendingRemovals = new ArrayList<>();
|
||||
private ArrayList<ViewHolder> mPendingAdditions = new ArrayList<>();
|
||||
private ArrayList<MoveInfo> mPendingMoves = new ArrayList<>();
|
||||
private ArrayList<ChangeInfo> mPendingChanges = new ArrayList<>();
|
||||
|
||||
private ArrayList<ArrayList<ViewHolder>> mAdditionsList =
|
||||
new ArrayList<ArrayList<ViewHolder>>();
|
||||
private ArrayList<ArrayList<MoveInfo>> mMovesList = new ArrayList<ArrayList<MoveInfo>>();
|
||||
private ArrayList<ArrayList<ChangeInfo>> mChangesList = new ArrayList<ArrayList<ChangeInfo>>();
|
||||
private ArrayList<ArrayList<ViewHolder>> mAdditionsList = new ArrayList<>();
|
||||
private ArrayList<ArrayList<MoveInfo>> mMovesList = new ArrayList<>();
|
||||
private ArrayList<ArrayList<ChangeInfo>> mChangesList = new ArrayList<>();
|
||||
|
||||
private ArrayList<ViewHolder> mAddAnimations = new ArrayList<ViewHolder>();
|
||||
private ArrayList<ViewHolder> mMoveAnimations = new ArrayList<ViewHolder>();
|
||||
private ArrayList<ViewHolder> mRemoveAnimations = new ArrayList<ViewHolder>();
|
||||
private ArrayList<ViewHolder> mChangeAnimations = new ArrayList<ViewHolder>();
|
||||
private ArrayList<ViewHolder> mAddAnimations = new ArrayList<>();
|
||||
private ArrayList<ViewHolder> mMoveAnimations = new ArrayList<>();
|
||||
private ArrayList<ViewHolder> mRemoveAnimations = new ArrayList<>();
|
||||
private ArrayList<ViewHolder> mChangeAnimations = new ArrayList<>();
|
||||
|
||||
private static class MoveInfo {
|
||||
public ViewHolder holder;
|
||||
|
@ -112,7 +110,7 @@ public class DefaultItemAnimator extends RecyclerView.ItemAnimator {
|
|||
mPendingRemovals.clear();
|
||||
// Next, move stuff
|
||||
if (movesPending) {
|
||||
final ArrayList<MoveInfo> moves = new ArrayList<MoveInfo>();
|
||||
final ArrayList<MoveInfo> moves = new ArrayList<>();
|
||||
moves.addAll(mPendingMoves);
|
||||
mMovesList.add(moves);
|
||||
mPendingMoves.clear();
|
||||
|
@ -136,7 +134,7 @@ public class DefaultItemAnimator extends RecyclerView.ItemAnimator {
|
|||
}
|
||||
// Next, change stuff, to run in parallel with move animations
|
||||
if (changesPending) {
|
||||
final ArrayList<ChangeInfo> changes = new ArrayList<ChangeInfo>();
|
||||
final ArrayList<ChangeInfo> changes = new ArrayList<>();
|
||||
changes.addAll(mPendingChanges);
|
||||
mChangesList.add(changes);
|
||||
mPendingChanges.clear();
|
||||
|
@ -159,7 +157,7 @@ public class DefaultItemAnimator extends RecyclerView.ItemAnimator {
|
|||
}
|
||||
// Next, add stuff
|
||||
if (additionsPending) {
|
||||
final ArrayList<ViewHolder> additions = new ArrayList<ViewHolder>();
|
||||
final ArrayList<ViewHolder> additions = new ArrayList<>();
|
||||
additions.addAll(mPendingAdditions);
|
||||
mAdditionsList.add(additions);
|
||||
mPendingAdditions.clear();
|
||||
|
@ -312,6 +310,11 @@ public class DefaultItemAnimator extends RecyclerView.ItemAnimator {
|
|||
@Override
|
||||
public boolean animateChange(ViewHolder oldHolder, ViewHolder newHolder,
|
||||
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 prevTranslationY = ViewCompat.getTranslationY(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.setTranslationY(oldHolder.itemView, prevTranslationY);
|
||||
ViewCompat.setAlpha(oldHolder.itemView, prevAlpha);
|
||||
if (newHolder != null && newHolder.itemView != null) {
|
||||
if (newHolder != null) {
|
||||
// carry over translation values
|
||||
resetAnimation(newHolder);
|
||||
ViewCompat.setTranslationX(newHolder.itemView, -deltaX);
|
||||
|
@ -481,21 +484,25 @@ public class DefaultItemAnimator extends RecyclerView.ItemAnimator {
|
|||
}
|
||||
|
||||
// animations should be ended by the cancel above.
|
||||
//noinspection PointlessBooleanExpression,ConstantConditions
|
||||
if (mRemoveAnimations.remove(item) && DEBUG) {
|
||||
throw new IllegalStateException("after animation is cancelled, item should not be in "
|
||||
+ "mRemoveAnimations list");
|
||||
}
|
||||
|
||||
//noinspection PointlessBooleanExpression,ConstantConditions
|
||||
if (mAddAnimations.remove(item) && DEBUG) {
|
||||
throw new IllegalStateException("after animation is cancelled, item should not be in "
|
||||
+ "mAddAnimations list");
|
||||
}
|
||||
|
||||
//noinspection PointlessBooleanExpression,ConstantConditions
|
||||
if (mChangeAnimations.remove(item) && DEBUG) {
|
||||
throw new IllegalStateException("after animation is cancelled, item should not be in "
|
||||
+ "mChangeAnimations list");
|
||||
}
|
||||
|
||||
//noinspection PointlessBooleanExpression,ConstantConditions
|
||||
if (mMoveAnimations.remove(item) && DEBUG) {
|
||||
throw new IllegalStateException("after animation is cancelled, item should not be in "
|
||||
+ "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 {
|
||||
@Override
|
||||
public void onAnimationStart(View view) {}
|
||||
|
@ -635,5 +664,5 @@ public class DefaultItemAnimator extends RecyclerView.ItemAnimator {
|
|||
|
||||
@Override
|
||||
public void onAnimationCancel(View view) {}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -37,11 +37,6 @@ public class GridLayoutManager extends LinearLayoutManager {
|
|||
private static final boolean DEBUG = false;
|
||||
private static final String TAG = "GridLayoutManager";
|
||||
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.
|
||||
*/
|
||||
|
@ -63,6 +58,21 @@ public class GridLayoutManager extends LinearLayoutManager {
|
|||
// re-used variable to acquire decor insets from RecyclerView
|
||||
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
|
||||
*
|
||||
|
@ -110,7 +120,9 @@ public class GridLayoutManager extends LinearLayoutManager {
|
|||
if (state.getItemCount() < 1) {
|
||||
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
|
||||
|
@ -122,7 +134,9 @@ public class GridLayoutManager extends LinearLayoutManager {
|
|||
if (state.getItemCount() < 1) {
|
||||
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
|
||||
|
@ -206,8 +220,13 @@ public class GridLayoutManager extends LinearLayoutManager {
|
|||
|
||||
@Override
|
||||
public RecyclerView.LayoutParams generateDefaultLayoutParams() {
|
||||
return new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT);
|
||||
if (mOrientation == HORIZONTAL) {
|
||||
return new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
|
||||
ViewGroup.LayoutParams.FILL_PARENT);
|
||||
} else {
|
||||
return new LayoutParams(ViewGroup.LayoutParams.FILL_PARENT,
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -258,47 +277,124 @@ public class GridLayoutManager extends LinearLayoutManager {
|
|||
calculateItemBorders(totalSpace);
|
||||
}
|
||||
|
||||
private void calculateItemBorders(int totalSpace) {
|
||||
if (mCachedBorders == null || mCachedBorders.length != mSpanCount + 1
|
||||
|| mCachedBorders[mCachedBorders.length - 1] != totalSpace) {
|
||||
mCachedBorders = new int[mSpanCount + 1];
|
||||
@Override
|
||||
public void setMeasuredDimension(Rect childrenBounds, int wSpec, int hSpec) {
|
||||
if (mCachedBorders == null) {
|
||||
super.setMeasuredDimension(childrenBounds, wSpec, hSpec);
|
||||
}
|
||||
mCachedBorders[0] = 0;
|
||||
int sizePerSpan = totalSpace / mSpanCount;
|
||||
int sizePerSpanRemainder = totalSpace % mSpanCount;
|
||||
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, 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 additionalSize = 0;
|
||||
for (int i = 1; i <= mSpanCount; i++) {
|
||||
for (int i = 1; i <= spanCount; i++) {
|
||||
int itemSize = sizePerSpan;
|
||||
additionalSize += sizePerSpanRemainder;
|
||||
if (additionalSize > 0 && (mSpanCount - additionalSize) < sizePerSpanRemainder) {
|
||||
if (additionalSize > 0 && (spanCount - additionalSize) < sizePerSpanRemainder) {
|
||||
itemSize += 1;
|
||||
additionalSize -= mSpanCount;
|
||||
additionalSize -= spanCount;
|
||||
}
|
||||
consumedPixels += itemSize;
|
||||
mCachedBorders[i] = consumedPixels;
|
||||
cachedBorders[i] = consumedPixels;
|
||||
}
|
||||
return cachedBorders;
|
||||
}
|
||||
|
||||
@Override
|
||||
void onAnchorReady(RecyclerView.Recycler recycler, RecyclerView.State state,
|
||||
AnchorInfo anchorInfo) {
|
||||
super.onAnchorReady(recycler, state, anchorInfo);
|
||||
AnchorInfo anchorInfo, int itemDirection) {
|
||||
super.onAnchorReady(recycler, state, anchorInfo, itemDirection);
|
||||
updateMeasurements();
|
||||
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) {
|
||||
mSet = new View[mSpanCount];
|
||||
}
|
||||
}
|
||||
|
||||
private void ensureAnchorIsInFirstSpan(RecyclerView.Recycler recycler, RecyclerView.State state,
|
||||
AnchorInfo anchorInfo) {
|
||||
@Override
|
||||
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);
|
||||
while (span > 0 && anchorInfo.mPosition > 0) {
|
||||
anchorInfo.mPosition--;
|
||||
span = getSpanIndex(recycler, state, anchorInfo.mPosition);
|
||||
if (layingOutInPrimaryDirection) {
|
||||
// choose span 0
|
||||
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
|
||||
void layoutChunk(RecyclerView.Recycler recycler, RecyclerView.State state,
|
||||
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 =
|
||||
layoutState.mItemDirection == LayoutState.ITEM_DIRECTION_TAIL;
|
||||
int count = 0;
|
||||
|
@ -435,6 +540,7 @@ public class GridLayoutManager extends LinearLayoutManager {
|
|||
}
|
||||
|
||||
int maxSize = 0;
|
||||
float maxSizeInOther = 0; // use a float to get size per span
|
||||
|
||||
// we should assign spans before item decor offsets are calculated
|
||||
assignSpans(recycler, state, count, consumedSpanCount, layingOutInPrimaryDirection);
|
||||
|
@ -455,35 +561,73 @@ public class GridLayoutManager extends LinearLayoutManager {
|
|||
}
|
||||
|
||||
final LayoutParams lp = (LayoutParams) view.getLayoutParams();
|
||||
final int spec = View.MeasureSpec.makeMeasureSpec(
|
||||
mCachedBorders[lp.mSpanIndex + lp.mSpanSize] -
|
||||
mCachedBorders[lp.mSpanIndex],
|
||||
View.MeasureSpec.EXACTLY);
|
||||
final int spec = getChildMeasureSpec(mCachedBorders[lp.mSpanIndex + lp.mSpanSize] -
|
||||
mCachedBorders[lp.mSpanIndex], otherDirSpecMode, 0,
|
||||
mOrientation == HORIZONTAL ? lp.height : lp.width,
|
||||
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) {
|
||||
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 {
|
||||
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);
|
||||
if (size > maxSize) {
|
||||
maxSize = size;
|
||||
}
|
||||
final float otherSize = 1f * mOrientationHelper.getDecoratedMeasurementInOther(view) /
|
||||
lp.mSpanSize;
|
||||
if (otherSize > maxSizeInOther) {
|
||||
maxSizeInOther = otherSize;
|
||||
}
|
||||
}
|
||||
|
||||
// views that did not measure the maxSize has to be re-measured
|
||||
final int maxMeasureSpec = getMainDirSpec(maxSize);
|
||||
if (flexibleInOtherDir) {
|
||||
// re-distribute columns
|
||||
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 ++) {
|
||||
final View view = mSet[i];
|
||||
if (mOrientationHelper.getDecoratedMeasurement(view) != maxSize) {
|
||||
final LayoutParams lp = (LayoutParams) view.getLayoutParams();
|
||||
final int spec = View.MeasureSpec.makeMeasureSpec(
|
||||
mCachedBorders[lp.mSpanIndex + lp.mSpanSize] -
|
||||
mCachedBorders[lp.mSpanIndex],
|
||||
View.MeasureSpec.EXACTLY);
|
||||
final int spec = getChildMeasureSpec(mCachedBorders[lp.mSpanIndex + lp.mSpanSize]
|
||||
- mCachedBorders[lp.mSpanIndex], View.MeasureSpec.EXACTLY, 0,
|
||||
mOrientation == HORIZONTAL ? lp.height : lp.width, false);
|
||||
if (mOrientation == VERTICAL) {
|
||||
measureChildWithDecorationsAndMargin(view, spec, maxMeasureSpec, true);
|
||||
measureChildWithDecorationsAndMargin(view, spec, maxMeasureSpec, true, true);
|
||||
} 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];
|
||||
LayoutParams params = (LayoutParams) view.getLayoutParams();
|
||||
if (mOrientation == VERTICAL) {
|
||||
left = getPaddingLeft() + mCachedBorders[params.mSpanIndex];
|
||||
right = left + mOrientationHelper.getDecoratedMeasurementInOther(view);
|
||||
if (isLayoutRTL()) {
|
||||
right = getPaddingLeft() + mCachedBorders[params.mSpanIndex + params.mSpanSize];
|
||||
left = right - mOrientationHelper.getDecoratedMeasurementInOther(view);
|
||||
} else {
|
||||
left = getPaddingLeft() + mCachedBorders[params.mSpanIndex];
|
||||
right = left + mOrientationHelper.getDecoratedMeasurementInOther(view);
|
||||
}
|
||||
} else {
|
||||
top = getPaddingTop() + mCachedBorders[params.mSpanIndex];
|
||||
bottom = top + mOrientationHelper.getDecoratedMeasurementInOther(view);
|
||||
|
@ -537,16 +686,24 @@ public class GridLayoutManager extends LinearLayoutManager {
|
|||
Arrays.fill(mSet, null);
|
||||
}
|
||||
|
||||
private int getMainDirSpec(int dim) {
|
||||
if (dim < 0) {
|
||||
return MAIN_DIR_SPEC;
|
||||
} else {
|
||||
return View.MeasureSpec.makeMeasureSpec(dim, View.MeasureSpec.EXACTLY);
|
||||
}
|
||||
/**
|
||||
* This is called after laying out a row (if vertical) or a column (if horizontal) when the
|
||||
* RecyclerView does not have exact measurement specs.
|
||||
* <p>
|
||||
* 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,
|
||||
boolean capBothSpecs) {
|
||||
boolean capBothSpecs, boolean alreadyMeasured) {
|
||||
calculateItemDecorationsForChild(child, mDecorInsets);
|
||||
RecyclerView.LayoutParams lp = (RecyclerView.LayoutParams) child.getLayoutParams();
|
||||
if (capBothSpecs || mOrientation == VERTICAL) {
|
||||
|
@ -557,7 +714,16 @@ public class GridLayoutManager extends LinearLayoutManager {
|
|||
heightSpec = updateSpecWithExtra(heightSpec, lp.topMargin + mDecorInsets.top,
|
||||
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) {
|
||||
|
@ -567,7 +733,7 @@ public class GridLayoutManager extends LinearLayoutManager {
|
|||
final int mode = View.MeasureSpec.getMode(spec);
|
||||
if (mode == View.MeasureSpec.AT_MOST || mode == View.MeasureSpec.EXACTLY) {
|
||||
return View.MeasureSpec.makeMeasureSpec(
|
||||
View.MeasureSpec.getSize(spec) - startInset - endInset, mode);
|
||||
Math.max(0, View.MeasureSpec.getSize(spec) - startInset - endInset), mode);
|
||||
}
|
||||
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
|
||||
public boolean supportsPredictiveItemAnimations() {
|
||||
return mPendingSavedState == null && !mPendingSpanCountChange;
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
*/
|
||||
|
||||
package org.telegram.messenger.support.widget;
|
||||
|
||||
import android.view.View;
|
||||
|
||||
/**
|
||||
|
@ -35,8 +36,11 @@ class LayoutState {
|
|||
|
||||
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.
|
||||
*/
|
||||
|
@ -69,6 +73,16 @@ class LayoutState {
|
|||
*/
|
||||
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
|
||||
*/
|
||||
|
|
|
@ -16,6 +16,8 @@
|
|||
|
||||
package org.telegram.messenger.support.widget;
|
||||
|
||||
import static org.telegram.messenger.support.widget.RecyclerView.NO_POSITION;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.PointF;
|
||||
import android.os.Parcel;
|
||||
|
@ -23,20 +25,18 @@ import android.os.Parcelable;
|
|||
import android.support.v4.view.ViewCompat;
|
||||
import android.support.v4.view.accessibility.AccessibilityEventCompat;
|
||||
import android.support.v4.view.accessibility.AccessibilityRecordCompat;
|
||||
|
||||
import org.telegram.messenger.support.widget.RecyclerView.LayoutParams;
|
||||
import org.telegram.messenger.support.widget.helper.ItemTouchHelper;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.accessibility.AccessibilityEvent;
|
||||
import org.telegram.messenger.support.widget.RecyclerView.LayoutParams;
|
||||
|
||||
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}.
|
||||
*/
|
||||
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
|
||||
* 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) {
|
||||
setOrientation(orientation);
|
||||
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.
|
||||
*
|
||||
* @return Current orientation.
|
||||
* @see #mOrientation
|
||||
* @return Current orientation, either {@link #HORIZONTAL} or {@link #VERTICAL}
|
||||
* @see #setOrientation(int)
|
||||
*/
|
||||
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.
|
||||
*
|
||||
* @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.
|
||||
*
|
||||
* @return If layout is reversed or not.
|
||||
* @see {@link #setReverseLayout(boolean)}
|
||||
* @see #setReverseLayout(boolean)
|
||||
*/
|
||||
public boolean getReverseLayout() {
|
||||
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.
|
||||
*
|
||||
* For horizontal layouts, it depends on the layout direction.
|
||||
* When set to true, If {@link RecyclerView} is LTR, than it will
|
||||
* layout from RTL, if {@link RecyclerView}} is RTL, it will layout
|
||||
* When set to true, If {@link android.support.v7.widget.RecyclerView} is LTR, than it will
|
||||
* layout from RTL, if {@link android.support.v7.widget.RecyclerView}} is RTL, it will layout
|
||||
* from LTR.
|
||||
*
|
||||
* 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.
|
||||
* 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
|
||||
* custom layout pre-cache logic.</p>
|
||||
* <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 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);
|
||||
mLayoutState.mInfinite = mOrientationHelper.getMode() == View.MeasureSpec.UNSPECIFIED;
|
||||
mLayoutState.mIsPreLayout = state.isPreLayout();
|
||||
if (mAnchorInfo.mLayoutFromEnd) {
|
||||
// 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
|
||||
* even update anchor info if necessary.
|
||||
*
|
||||
* @param recycler
|
||||
* @param state
|
||||
* @param anchorInfo Simple data structure to keep anchor point information for the next layout
|
||||
* @param recycler The recycler for the layout
|
||||
* @param state The layout state
|
||||
* @param anchorInfo The mutable POJO that keeps the position and offset.
|
||||
* @param firstLayoutItemDirection The direction of the first layout filling in terms of adapter
|
||||
* indices.
|
||||
*/
|
||||
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,
|
||||
boolean canUseExistingSpace, RecyclerView.State state) {
|
||||
mLayoutState.mInfinite = mOrientationHelper.getMode() == View.MeasureSpec.UNSPECIFIED;
|
||||
mLayoutState.mExtra = getExtraLayoutSpace(state);
|
||||
mLayoutState.mLayoutDirection = layoutDirection;
|
||||
int fastScrollSpace;
|
||||
int scrollingOffset;
|
||||
if (layoutDirection == LayoutState.LAYOUT_END) {
|
||||
mLayoutState.mExtra += mOrientationHelper.getEndPadding();
|
||||
// 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.mOffset = mOrientationHelper.getDecoratedEnd(child);
|
||||
// calculate how much we can scroll without adding new children (independent of layout)
|
||||
fastScrollSpace = mOrientationHelper.getDecoratedEnd(child)
|
||||
scrollingOffset = mOrientationHelper.getDecoratedEnd(child)
|
||||
- mOrientationHelper.getEndAfterPadding();
|
||||
|
||||
} else {
|
||||
|
@ -1123,14 +1152,14 @@ public class LinearLayoutManager extends RecyclerView.LayoutManager implements
|
|||
: LayoutState.ITEM_DIRECTION_HEAD;
|
||||
mLayoutState.mCurrentPosition = getPosition(child) + mLayoutState.mItemDirection;
|
||||
mLayoutState.mOffset = mOrientationHelper.getDecoratedStart(child);
|
||||
fastScrollSpace = -mOrientationHelper.getDecoratedStart(child)
|
||||
scrollingOffset = -mOrientationHelper.getDecoratedStart(child)
|
||||
+ mOrientationHelper.getStartAfterPadding();
|
||||
}
|
||||
mLayoutState.mAvailable = requiredSpace;
|
||||
if (canUseExistingSpace) {
|
||||
mLayoutState.mAvailable -= fastScrollSpace;
|
||||
mLayoutState.mAvailable -= scrollingOffset;
|
||||
}
|
||||
mLayoutState.mScrollingOffset = fastScrollSpace;
|
||||
mLayoutState.mScrollingOffset = scrollingOffset;
|
||||
}
|
||||
|
||||
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 absDy = Math.abs(dy);
|
||||
updateLayoutState(layoutDirection, absDy, true, state);
|
||||
final int freeScroll = mLayoutState.mScrollingOffset;
|
||||
final int consumed = freeScroll + fill(recycler, mLayoutState, state, false);
|
||||
final int consumed = mLayoutState.mScrollingOffset
|
||||
+ fill(recycler, mLayoutState, state, false);
|
||||
if (consumed < 0) {
|
||||
if (DEBUG) {
|
||||
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.
|
||||
*
|
||||
* @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
|
||||
* to detect children that will go out of bounds after scrolling, without
|
||||
* 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.
|
||||
*
|
||||
* @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
|
||||
* to detect children that will go out of bounds after scrolling, without
|
||||
* 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
|
||||
* we may consider moving it out of this view so passing around as a
|
||||
* parameter for now, rather than accessing {@link #mLayoutState}
|
||||
* @see #recycleViewsFromStart(RecyclerView.Recycler, int)
|
||||
* @see #recycleViewsFromEnd(RecyclerView.Recycler, int)
|
||||
* @see org.telegram.messenger.support.widget.LinearLayoutManager.LayoutState#mLayoutDirection
|
||||
* @see #recycleViewsFromStart(android.support.v7.widget.RecyclerView.Recycler, int)
|
||||
* @see #recycleViewsFromEnd(android.support.v7.widget.RecyclerView.Recycler, int)
|
||||
* @see android.support.v7.widget.LinearLayoutManager.LayoutState#mLayoutDirection
|
||||
*/
|
||||
private void recycleByLayoutState(RecyclerView.Recycler recycler, LayoutState layoutState) {
|
||||
if (!layoutState.mRecycle) {
|
||||
if (!layoutState.mRecycle || layoutState.mInfinite) {
|
||||
return;
|
||||
}
|
||||
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
|
||||
* 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.
|
||||
*
|
||||
* @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;
|
||||
LayoutChunkResult layoutChunkResult = new LayoutChunkResult();
|
||||
while (remainingSpace > 0 && layoutState.hasMore(state)) {
|
||||
while ((layoutState.mInfinite || remainingSpace > 0) && layoutState.hasMore(state)) {
|
||||
layoutChunkResult.resetInternal();
|
||||
layoutChunk(recycler, state, layoutState, layoutChunkResult);
|
||||
if (layoutChunkResult.mFinished) {
|
||||
|
@ -1424,6 +1453,13 @@ public class LinearLayoutManager extends RecyclerView.LayoutManager implements
|
|||
result.mFocusable = view.isFocusable();
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean shouldMeasureTwice() {
|
||||
return getHeightMode() != View.MeasureSpec.EXACTLY
|
||||
&& getWidthMode() != View.MeasureSpec.EXACTLY
|
||||
&& hasFlexibleChildInBothOrientations();
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
* is applicable to current state, {@link LayoutState#INVALID_LAYOUT} otherwise.
|
||||
*/
|
||||
private int convertFocusDirectionToLayoutDirection(int focusDirection) {
|
||||
int convertFocusDirectionToLayoutDirection(int focusDirection) {
|
||||
switch (focusDirection) {
|
||||
case View.FOCUS_BACKWARD:
|
||||
return LayoutState.LAYOUT_START;
|
||||
|
@ -1916,7 +1952,8 @@ public class LinearLayoutManager extends RecyclerView.LayoutManager implements
|
|||
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;
|
||||
|
||||
|
@ -1926,6 +1963,11 @@ public class LinearLayoutManager extends RecyclerView.LayoutManager implements
|
|||
*/
|
||||
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
|
||||
*/
|
||||
|
@ -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;
|
||||
|
||||
|
|
|
@ -24,8 +24,6 @@ import android.view.View;
|
|||
import android.view.animation.DecelerateInterpolator;
|
||||
import android.view.animation.LinearInterpolator;
|
||||
|
||||
import org.telegram.messenger.support.widget.RecyclerView;
|
||||
|
||||
/**
|
||||
* {@link RecyclerView.SmoothScroller} implementation which uses
|
||||
* {@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();
|
||||
return;
|
||||
}
|
||||
//noinspection PointlessBooleanExpression
|
||||
if (DEBUG && mTargetVector != null
|
||||
&& ((mTargetVector.x * dx < 0 || mTargetVector.y * dy < 0))) {
|
||||
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 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
|
||||
* {@link #SNAP_TO_END}.
|
||||
* {@link #SNAP_TO_ANY}.
|
||||
* @return The vertical scroll amount necessary to make the view visible with the given
|
||||
* snap preference.
|
||||
*/
|
||||
public int calculateDyToMakeVisible(View view, int snapPreference) {
|
||||
final RecyclerView.LayoutManager layoutManager = getLayoutManager();
|
||||
if (!layoutManager.canScrollVertically()) {
|
||||
if (layoutManager == null || !layoutManager.canScrollVertically()) {
|
||||
return 0;
|
||||
}
|
||||
final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams)
|
||||
|
@ -324,7 +323,7 @@ abstract public class LinearSmoothScroller extends RecyclerView.SmoothScroller {
|
|||
*/
|
||||
public int calculateDxToMakeVisible(View view, int snapPreference) {
|
||||
final RecyclerView.LayoutManager layoutManager = getLayoutManager();
|
||||
if (!layoutManager.canScrollHorizontally()) {
|
||||
if (layoutManager == null || !layoutManager.canScrollHorizontally()) {
|
||||
return 0;
|
||||
}
|
||||
final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams)
|
||||
|
|
|
@ -19,8 +19,6 @@ package org.telegram.messenger.support.widget;
|
|||
import android.view.View;
|
||||
import android.widget.LinearLayout;
|
||||
|
||||
import org.telegram.messenger.support.widget.RecyclerView;
|
||||
|
||||
/**
|
||||
* Helper class for LayoutManagers to abstract measurements depending on the View's orientation.
|
||||
* <p>
|
||||
|
@ -167,6 +165,28 @@ public abstract class OrientationHelper {
|
|||
*/
|
||||
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.
|
||||
*
|
||||
|
@ -259,6 +279,16 @@ public abstract class OrientationHelper {
|
|||
public int getEndPadding() {
|
||||
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() {
|
||||
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.accessibility.AccessibilityEvent;
|
||||
|
||||
import org.telegram.messenger.support.widget.RecyclerView;
|
||||
|
||||
/**
|
||||
* The AccessibilityDelegate used by RecyclerView.
|
||||
* <p>
|
||||
|
|
|
@ -17,8 +17,6 @@ package org.telegram.messenger.support.widget;
|
|||
|
||||
import android.view.View;
|
||||
|
||||
import org.telegram.messenger.support.widget.RecyclerView;
|
||||
|
||||
/**
|
||||
* 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;
|
||||
|
||||
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.graphics.PointF;
|
||||
import android.graphics.Rect;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v4.view.ViewCompat;
|
||||
import android.support.v4.view.accessibility.AccessibilityEventCompat;
|
||||
import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat;
|
||||
|
@ -31,24 +38,11 @@ import android.view.View;
|
|||
import android.view.ViewGroup;
|
||||
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.Arrays;
|
||||
import java.util.BitSet;
|
||||
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.
|
||||
* 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;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
@Deprecated
|
||||
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;
|
||||
|
||||
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
|
||||
|
@ -175,7 +176,7 @@ public class StaggeredGridLayoutManager extends RecyclerView.LayoutManager {
|
|||
/**
|
||||
* Re-used measurement specs. updated by onLayout.
|
||||
*/
|
||||
private int mFullSizeSpec, mWidthSpec, mHeightSpec;
|
||||
private int mFullSizeSpec;
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
|
@ -218,6 +233,7 @@ public class StaggeredGridLayoutManager extends RecyclerView.LayoutManager {
|
|||
public StaggeredGridLayoutManager(int spanCount, int orientation) {
|
||||
mOrientation = orientation;
|
||||
setSpanCount(spanCount);
|
||||
setAutoMeasureEnabled(mGapStrategy != GAP_HANDLING_NONE);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -358,10 +374,16 @@ public class StaggeredGridLayoutManager extends RecyclerView.LayoutManager {
|
|||
private boolean checkSpanForGap(Span span) {
|
||||
if (mShouldReverseLayout) {
|
||||
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()) {
|
||||
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;
|
||||
}
|
||||
|
@ -473,6 +495,7 @@ public class StaggeredGridLayoutManager extends RecyclerView.LayoutManager {
|
|||
+ "or GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS");
|
||||
}
|
||||
mGapStrategy = gapStrategy;
|
||||
setAutoMeasureEnabled(mGapStrategy != GAP_HANDLING_NONE);
|
||||
requestLayout();
|
||||
}
|
||||
|
||||
|
@ -541,8 +564,35 @@ public class StaggeredGridLayoutManager extends RecyclerView.LayoutManager {
|
|||
public boolean getReverseLayout() {
|
||||
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
|
||||
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();
|
||||
final AnchorInfo anchorInfo = mAnchorInfo;
|
||||
anchorInfo.reset();
|
||||
|
@ -588,8 +638,9 @@ public class StaggeredGridLayoutManager extends RecyclerView.LayoutManager {
|
|||
}
|
||||
}
|
||||
detachAndScrapAttachedViews(recycler);
|
||||
mLayoutState.mRecycle = false;
|
||||
mLaidOutInvalidFullSpan = false;
|
||||
updateMeasureSpecs();
|
||||
updateMeasureSpecs(mSecondaryOrientation.getTotalSpace());
|
||||
updateLayoutState(anchorInfo.mPosition, state);
|
||||
if (anchorInfo.mLayoutFromEnd) {
|
||||
// Layout start.
|
||||
|
@ -609,6 +660,8 @@ public class StaggeredGridLayoutManager extends RecyclerView.LayoutManager {
|
|||
fill(recycler, mLayoutState, state);
|
||||
}
|
||||
|
||||
repositionToWrapContentIfNecessary();
|
||||
|
||||
if (getChildCount() > 0) {
|
||||
if (mShouldReverseLayout) {
|
||||
fixEndGap(recycler, state, true);
|
||||
|
@ -618,14 +671,16 @@ public class StaggeredGridLayoutManager extends RecyclerView.LayoutManager {
|
|||
fixEndGap(recycler, state, false);
|
||||
}
|
||||
}
|
||||
|
||||
if (!state.isPreLayout()) {
|
||||
boolean hasGaps = false;
|
||||
if (shouldCheckForGaps && !state.isPreLayout()) {
|
||||
final boolean needToCheckForGaps = mGapStrategy != GAP_HANDLING_NONE
|
||||
&& getChildCount() > 0
|
||||
&& (mLaidOutInvalidFullSpan || hasGapsToFix() != null);
|
||||
if (needToCheckForGaps) {
|
||||
removeCallbacks(mCheckForGapsRunnable);
|
||||
postOnAnimation(mCheckForGapsRunnable);
|
||||
if (checkForGaps()) {
|
||||
hasGaps = true;
|
||||
}
|
||||
}
|
||||
mPendingScrollPosition = NO_POSITION;
|
||||
mPendingScrollPositionOffset = INVALID_OFFSET;
|
||||
|
@ -633,6 +688,58 @@ public class StaggeredGridLayoutManager extends RecyclerView.LayoutManager {
|
|||
mLastLayoutFromEnd = anchorInfo.mLayoutFromEnd;
|
||||
mLastLayoutRTL = isLayoutRTL();
|
||||
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) {
|
||||
|
@ -780,17 +887,11 @@ public class StaggeredGridLayoutManager extends RecyclerView.LayoutManager {
|
|||
return true;
|
||||
}
|
||||
|
||||
void updateMeasureSpecs() {
|
||||
mSizePerSpan = mSecondaryOrientation.getTotalSpace() / mSpanCount;
|
||||
void updateMeasureSpecs(int totalSpace) {
|
||||
mSizePerSpan = totalSpace / mSpanCount;
|
||||
//noinspection ResourceType
|
||||
mFullSizeSpec = View.MeasureSpec.makeMeasureSpec(
|
||||
mSecondaryOrientation.getTotalSpace(), View.MeasureSpec.EXACTLY);
|
||||
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);
|
||||
}
|
||||
totalSpace, mSecondaryOrientation.getMode());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -989,43 +1090,48 @@ public class StaggeredGridLayoutManager extends RecyclerView.LayoutManager {
|
|||
return computeScrollRange(state);
|
||||
}
|
||||
|
||||
private void measureChildWithDecorationsAndMargin(View child, LayoutParams lp) {
|
||||
private void measureChildWithDecorationsAndMargin(View child, LayoutParams lp,
|
||||
boolean alreadyMeasured) {
|
||||
if (lp.mFullSpan) {
|
||||
if (mOrientation == VERTICAL) {
|
||||
measureChildWithDecorationsAndMargin(child, mFullSizeSpec,
|
||||
getSpecForDimension(lp.height, mHeightSpec));
|
||||
getChildMeasureSpec(getHeight(), getHeightMode(), 0, lp.height, true),
|
||||
alreadyMeasured);
|
||||
} else {
|
||||
measureChildWithDecorationsAndMargin(child,
|
||||
getSpecForDimension(lp.width, mWidthSpec), mFullSizeSpec);
|
||||
getChildMeasureSpec(getWidth(), getWidthMode(), 0, lp.width, true),
|
||||
mFullSizeSpec, alreadyMeasured);
|
||||
}
|
||||
} else {
|
||||
if (mOrientation == VERTICAL) {
|
||||
measureChildWithDecorationsAndMargin(child, mWidthSpec,
|
||||
getSpecForDimension(lp.height, mHeightSpec));
|
||||
measureChildWithDecorationsAndMargin(child,
|
||||
getChildMeasureSpec(mSizePerSpan, getWidthMode(), 0, lp.width, false),
|
||||
getChildMeasureSpec(getHeight(), getHeightMode(), 0, lp.height, true),
|
||||
alreadyMeasured);
|
||||
} else {
|
||||
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,
|
||||
int heightSpec) {
|
||||
int heightSpec, boolean alreadyMeasured) {
|
||||
calculateItemDecorationsForChild(child, mTmpRect);
|
||||
LayoutParams lp = (LayoutParams) child.getLayoutParams();
|
||||
widthSpec = updateSpecWithExtra(widthSpec, lp.leftMargin + mTmpRect.left,
|
||||
lp.rightMargin + mTmpRect.right);
|
||||
heightSpec = updateSpecWithExtra(heightSpec, lp.topMargin + mTmpRect.top,
|
||||
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) {
|
||||
|
@ -1035,7 +1141,7 @@ public class StaggeredGridLayoutManager extends RecyclerView.LayoutManager {
|
|||
final int mode = View.MeasureSpec.getMode(spec);
|
||||
if (mode == View.MeasureSpec.AT_MOST || mode == View.MeasureSpec.EXACTLY) {
|
||||
return View.MeasureSpec.makeMeasureSpec(
|
||||
View.MeasureSpec.getSize(spec) - startInset - endInset, mode);
|
||||
Math.max(0, View.MeasureSpec.getSize(spec) - startInset - endInset), mode);
|
||||
}
|
||||
return spec;
|
||||
}
|
||||
|
@ -1238,7 +1344,10 @@ public class StaggeredGridLayoutManager extends RecyclerView.LayoutManager {
|
|||
|
||||
private void fixEndGap(RecyclerView.Recycler recycler, RecyclerView.State state,
|
||||
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 fixOffset;
|
||||
if (gap > 0) {
|
||||
|
@ -1254,7 +1363,10 @@ public class StaggeredGridLayoutManager extends RecyclerView.LayoutManager {
|
|||
|
||||
private void fixStartGap(RecyclerView.Recycler recycler, RecyclerView.State state,
|
||||
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 fixOffset;
|
||||
if (gap > 0) {
|
||||
|
@ -1293,6 +1405,9 @@ public class StaggeredGridLayoutManager extends RecyclerView.LayoutManager {
|
|||
mLayoutState.mEndLine = mPrimaryOrientation.getEnd() + endExtra;
|
||||
mLayoutState.mStartLine = -startExtra;
|
||||
}
|
||||
mLayoutState.mStopInFocusable = false;
|
||||
mLayoutState.mRecycle = true;
|
||||
mLayoutState.mInfinite = mPrimaryOrientation.getMode() == View.MeasureSpec.UNSPECIFIED;
|
||||
}
|
||||
|
||||
private void setLayoutStateDirection(int direction) {
|
||||
|
@ -1397,10 +1512,18 @@ public class StaggeredGridLayoutManager extends RecyclerView.LayoutManager {
|
|||
final int targetLine;
|
||||
|
||||
// Line of the furthest row.
|
||||
if (layoutState.mLayoutDirection == LAYOUT_END) {
|
||||
targetLine = layoutState.mEndLine + layoutState.mAvailable;
|
||||
} else { // LAYOUT_START
|
||||
targetLine = layoutState.mStartLine - layoutState.mAvailable;
|
||||
if (mLayoutState.mInfinite) {
|
||||
if (layoutState.mLayoutDirection == LAYOUT_END) {
|
||||
targetLine = Integer.MAX_VALUE;
|
||||
} 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);
|
||||
|
@ -1414,7 +1537,8 @@ public class StaggeredGridLayoutManager extends RecyclerView.LayoutManager {
|
|||
? mPrimaryOrientation.getEndAfterPadding()
|
||||
: mPrimaryOrientation.getStartAfterPadding();
|
||||
boolean added = false;
|
||||
while (layoutState.hasMore(state) && !mRemainingSpans.isEmpty()) {
|
||||
while (layoutState.hasMore(state)
|
||||
&& (mLayoutState.mInfinite || !mRemainingSpans.isEmpty())) {
|
||||
View view = layoutState.next(recycler);
|
||||
LayoutParams lp = ((LayoutParams) view.getLayoutParams());
|
||||
final int position = lp.getViewLayoutPosition();
|
||||
|
@ -1440,7 +1564,7 @@ public class StaggeredGridLayoutManager extends RecyclerView.LayoutManager {
|
|||
} else {
|
||||
addView(view, 0);
|
||||
}
|
||||
measureChildWithDecorationsAndMargin(view, lp);
|
||||
measureChildWithDecorationsAndMargin(view, lp, false);
|
||||
|
||||
final int start;
|
||||
final int end;
|
||||
|
@ -1488,13 +1612,22 @@ public class StaggeredGridLayoutManager extends RecyclerView.LayoutManager {
|
|||
mLaidOutInvalidFullSpan = true;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
attachViewToSpans(view, lp, layoutState);
|
||||
final int otherStart = lp.mFullSpan ? mSecondaryOrientation.getStartAfterPadding()
|
||||
: currentSpan.mIndex * mSizePerSpan +
|
||||
mSecondaryOrientation.getStartAfterPadding();
|
||||
final int otherEnd = otherStart + mSecondaryOrientation.getDecoratedMeasurement(view);
|
||||
final int otherStart;
|
||||
final int otherEnd;
|
||||
if (isLayoutRTL() && mOrientation == VERTICAL) {
|
||||
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) {
|
||||
layoutDecoratedWithMargins(view, otherStart, start, otherEnd, end);
|
||||
} else {
|
||||
|
@ -1507,6 +1640,13 @@ public class StaggeredGridLayoutManager extends RecyclerView.LayoutManager {
|
|||
updateRemainingSpans(currentSpan, mLayoutState.mLayoutDirection, targetLine);
|
||||
}
|
||||
recycle(recycler, mLayoutState);
|
||||
if (mLayoutState.mStopInFocusable && view.isFocusable()) {
|
||||
if (lp.mFullSpan) {
|
||||
mRemainingSpans.clear();
|
||||
} else {
|
||||
mRemainingSpans.set(currentSpan.mIndex, false);
|
||||
}
|
||||
}
|
||||
added = true;
|
||||
}
|
||||
if (!added) {
|
||||
|
@ -1558,6 +1698,9 @@ public class StaggeredGridLayoutManager extends RecyclerView.LayoutManager {
|
|||
}
|
||||
|
||||
private void recycle(RecyclerView.Recycler recycler, LayoutState layoutState) {
|
||||
if (!layoutState.mRecycle || layoutState.mInfinite) {
|
||||
return;
|
||||
}
|
||||
if (layoutState.mAvailable == 0) {
|
||||
// easy, recycle line is still valid
|
||||
if (layoutState.mLayoutDirection == LAYOUT_START) {
|
||||
|
@ -1913,6 +2056,7 @@ public class StaggeredGridLayoutManager extends RecyclerView.LayoutManager {
|
|||
layoutDir = LAYOUT_START;
|
||||
referenceChildPosition = getFirstChildPosition();
|
||||
}
|
||||
mLayoutState.mRecycle = true;
|
||||
updateLayoutState(referenceChildPosition, state);
|
||||
setLayoutStateDirection(layoutDir);
|
||||
mLayoutState.mCurrentPosition = referenceChildPosition + mLayoutState.mItemDirection;
|
||||
|
@ -1982,8 +2126,13 @@ public class StaggeredGridLayoutManager extends RecyclerView.LayoutManager {
|
|||
|
||||
@Override
|
||||
public RecyclerView.LayoutParams generateDefaultLayoutParams() {
|
||||
return new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT);
|
||||
if (mOrientation == HORIZONTAL) {
|
||||
return new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
|
||||
ViewGroup.LayoutParams.FILL_PARENT);
|
||||
} else {
|
||||
return new LayoutParams(ViewGroup.LayoutParams.FILL_PARENT,
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -2009,6 +2158,105 @@ public class StaggeredGridLayoutManager extends RecyclerView.LayoutManager {
|
|||
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.
|
||||
|
@ -2089,7 +2337,7 @@ public class StaggeredGridLayoutManager extends RecyclerView.LayoutManager {
|
|||
class Span {
|
||||
|
||||
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 mCachedEnd = INVALID_LINE;
|
||||
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() {
|
||||
return mReverseLayout
|
||||
? findOneVisibleChild(mViews.size() - 1, -1, false)
|
||||
|
@ -2356,6 +2565,36 @@ public class StaggeredGridLayoutManager extends RecyclerView.LayoutManager {
|
|||
}
|
||||
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) {
|
||||
if (mFullSpanItems == null) {
|
||||
mFullSpanItems = new ArrayList<FullSpanItem>();
|
||||
mFullSpanItems = new ArrayList<>();
|
||||
}
|
||||
final int size = mFullSpanItems.size();
|
||||
for (int i = 0; i < size; i++) {
|
||||
|
@ -2624,10 +2863,6 @@ public class StaggeredGridLayoutManager extends RecyclerView.LayoutManager {
|
|||
return mGapPerSpan == null ? 0 : mGapPerSpan[spanIndex];
|
||||
}
|
||||
|
||||
public void invalidateSpanGaps() {
|
||||
mGapPerSpan = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
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 mVisibleAnchorPosition; // Replacement for span info when spans are invalidated
|
||||
|
@ -2704,6 +2942,7 @@ public class StaggeredGridLayoutManager extends RecyclerView.LayoutManager {
|
|||
mReverseLayout = in.readInt() == 1;
|
||||
mAnchorLayoutFromEnd = in.readInt() == 1;
|
||||
mLastLayoutRTL = in.readInt() == 1;
|
||||
//noinspection unchecked
|
||||
mFullSpanItems = in.readArrayList(
|
||||
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;
|
||||
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Rect;
|
||||
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.AnimatorListenerCompat;
|
||||
import android.support.v4.animation.AnimatorUpdateListenerCompat;
|
||||
import android.support.v4.animation.ValueAnimatorCompat;
|
||||
import android.support.v4.view.GestureDetectorCompat;
|
||||
import android.support.v4.view.MotionEventCompat;
|
||||
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.support.widget.LinearLayoutManager;
|
||||
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.view.GestureDetector;
|
||||
import android.view.HapticFeedbackConstants;
|
||||
|
@ -39,14 +43,11 @@ import android.view.VelocityTracker;
|
|||
import android.view.View;
|
||||
import android.view.ViewConfiguration;
|
||||
import android.view.ViewParent;
|
||||
import android.view.animation.Interpolator;
|
||||
|
||||
import java.util.ArrayList;
|
||||
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.
|
||||
* <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;
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
|
@ -367,11 +383,11 @@ public class ItemTouchHelper extends RecyclerView.ItemDecoration
|
|||
break;
|
||||
}
|
||||
case MotionEvent.ACTION_CANCEL:
|
||||
case MotionEvent.ACTION_UP:
|
||||
if (mVelocityTracker != null) {
|
||||
mVelocityTracker
|
||||
.computeCurrentVelocity(1000, mRecyclerView.getMaxFlingVelocity());
|
||||
mVelocityTracker.clear();
|
||||
}
|
||||
// fall through
|
||||
case MotionEvent.ACTION_UP:
|
||||
select(null, ACTION_STATE_IDLE);
|
||||
mActivePointerId = ACTIVE_POINTER_ID_NONE;
|
||||
break;
|
||||
|
@ -379,11 +395,6 @@ public class ItemTouchHelper extends RecyclerView.ItemDecoration
|
|||
final int pointerIndex = MotionEventCompat.getActionIndex(event);
|
||||
final int pointerId = MotionEventCompat.getPointerId(event, pointerIndex);
|
||||
if (pointerId == mActivePointerId) {
|
||||
if (mVelocityTracker != null) {
|
||||
mVelocityTracker
|
||||
.computeCurrentVelocity(1000,
|
||||
mRecyclerView.getMaxFlingVelocity());
|
||||
}
|
||||
// This was our active pointer going up. Choose a new
|
||||
// active pointer and adjust accordingly.
|
||||
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
|
||||
* attached
|
||||
* to a RecyclerView, it will first detach from the previous one.
|
||||
* attached to a RecyclerView, it will first detach from the previous one. You can call this
|
||||
* 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) {
|
||||
return; // nothing to do
|
||||
}
|
||||
|
@ -450,6 +463,9 @@ public class ItemTouchHelper extends RecyclerView.ItemDecoration
|
|||
}
|
||||
mRecyclerView = recyclerView;
|
||||
if (mRecyclerView != null) {
|
||||
final Resources resources = recyclerView.getResources();
|
||||
mSwipeEscapeVelocity = AndroidUtilities.dp(120);
|
||||
mMaxSwipeVelocity = AndroidUtilities.dp(800);
|
||||
setupCallbacks();
|
||||
}
|
||||
}
|
||||
|
@ -874,7 +890,6 @@ public class ItemTouchHelper extends RecyclerView.ItemDecoration
|
|||
anim.cancel();
|
||||
}
|
||||
mRecoverAnimations.remove(i);
|
||||
anim.mViewHolder.setIsRecyclable(true);
|
||||
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
|
||||
* 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()}.
|
||||
* <p>
|
||||
* For this method to work:
|
||||
|
@ -1189,11 +1204,17 @@ public class ItemTouchHelper extends RecyclerView.ItemDecoration
|
|||
if ((flags & (LEFT | RIGHT)) != 0) {
|
||||
final int dirFlag = mDx > 0 ? RIGHT : LEFT;
|
||||
if (mVelocityTracker != null && mActivePointerId > -1) {
|
||||
mVelocityTracker.computeCurrentVelocity(PIXELS_PER_SECOND,
|
||||
mCallback.getSwipeVelocityThreshold(mMaxSwipeVelocity));
|
||||
final float xVelocity = VelocityTrackerCompat
|
||||
.getXVelocity(mVelocityTracker, mActivePointerId);
|
||||
final float yVelocity = VelocityTrackerCompat
|
||||
.getYVelocity(mVelocityTracker, mActivePointerId);
|
||||
final int velDirFlag = xVelocity > 0f ? RIGHT : LEFT;
|
||||
final float absXVelocity = Math.abs(xVelocity);
|
||||
if ((velDirFlag & flags) != 0 && dirFlag == velDirFlag &&
|
||||
Math.abs(xVelocity) >= mRecyclerView.getMinFlingVelocity()) {
|
||||
absXVelocity >= mCallback.getSwipeEscapeVelocity(mSwipeEscapeVelocity) &&
|
||||
absXVelocity > Math.abs(yVelocity)) {
|
||||
return velDirFlag;
|
||||
}
|
||||
}
|
||||
|
@ -1212,11 +1233,17 @@ public class ItemTouchHelper extends RecyclerView.ItemDecoration
|
|||
if ((flags & (UP | DOWN)) != 0) {
|
||||
final int dirFlag = mDy > 0 ? DOWN : UP;
|
||||
if (mVelocityTracker != null && mActivePointerId > -1) {
|
||||
mVelocityTracker.computeCurrentVelocity(PIXELS_PER_SECOND,
|
||||
mCallback.getSwipeVelocityThreshold(mMaxSwipeVelocity));
|
||||
final float xVelocity = VelocityTrackerCompat
|
||||
.getXVelocity(mVelocityTracker, mActivePointerId);
|
||||
final float yVelocity = VelocityTrackerCompat
|
||||
.getYVelocity(mVelocityTracker, mActivePointerId);
|
||||
final int velDirFlag = yVelocity > 0f ? DOWN : UP;
|
||||
final float absYVelocity = Math.abs(yVelocity);
|
||||
if ((velDirFlag & flags) != 0 && velDirFlag == dirFlag &&
|
||||
Math.abs(yVelocity) >= mRecyclerView.getMinFlingVelocity()) {
|
||||
absYVelocity >= mCallback.getSwipeEscapeVelocity(mSwipeEscapeVelocity) &&
|
||||
absYVelocity > Math.abs(xVelocity)) {
|
||||
return velDirFlag;
|
||||
}
|
||||
}
|
||||
|
@ -1357,7 +1384,7 @@ public class ItemTouchHelper extends RecyclerView.ItemDecoration
|
|||
/**
|
||||
* 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;
|
||||
|
||||
|
@ -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
|
||||
* implementations for different platform versions.
|
||||
* <p>
|
||||
|
@ -1661,6 +1689,54 @@ public class ItemTouchHelper extends RecyclerView.ItemDecoration
|
|||
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
|
||||
* are under the dragged View.
|
||||
|
@ -1779,7 +1855,6 @@ public class ItemTouchHelper extends RecyclerView.ItemDecoration
|
|||
* @param actionState One of {@link ItemTouchHelper#ACTION_STATE_IDLE},
|
||||
* {@link ItemTouchHelper#ACTION_STATE_SWIPE} or
|
||||
* {@link ItemTouchHelper#ACTION_STATE_DRAG}.
|
||||
*
|
||||
* @see #clearView(RecyclerView, RecyclerView.ViewHolder)
|
||||
*/
|
||||
public void onSelectedChanged(ViewHolder viewHolder, int actionState) {
|
||||
|
@ -1902,7 +1977,6 @@ public class ItemTouchHelper extends RecyclerView.ItemDecoration
|
|||
final RecoverAnimation anim = recoverAnimationList.get(i);
|
||||
if (anim.mEnded && !anim.mIsPendingCleanup) {
|
||||
recoverAnimationList.remove(i);
|
||||
anim.mViewHolder.setIsRecyclable(true);
|
||||
} else if (!anim.mEnded) {
|
||||
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
|
||||
* bounds, the faster the RecyclerView will scroll.
|
||||
*
|
||||
* @param recyclerView The RecyclerView instance to which ItemTouchHelper is attached
|
||||
* to.
|
||||
* @param recyclerView The RecyclerView instance to which ItemTouchHelper is
|
||||
* attached to.
|
||||
* @param viewSize The total size of the View in scroll direction, excluding
|
||||
* item decorations.
|
||||
* @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.
|
||||
* @param totalSize The total size of RecyclerView in the scroll direction.
|
||||
* @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
|
||||
* be passed to {@link RecyclerView#scrollBy(int, int)} method.
|
||||
*/
|
||||
|
@ -2314,6 +2387,9 @@ public class ItemTouchHelper extends RecyclerView.ItemDecoration
|
|||
|
||||
@Override
|
||||
public void onAnimationEnd(ValueAnimatorCompat animation) {
|
||||
if (!mEnded) {
|
||||
mViewHolder.setIsRecyclable(true);
|
||||
}
|
||||
mEnded = true;
|
||||
}
|
||||
|
||||
|
|
|
@ -21,16 +21,16 @@ import android.support.v4.view.ViewCompat;
|
|||
import org.telegram.messenger.support.widget.RecyclerView;
|
||||
import android.view.View;
|
||||
|
||||
|
||||
/**
|
||||
* Package private class to keep implementations. Putting them inside ItemTouchUIUtil makes them
|
||||
* public API, which is not desired in this case.
|
||||
*/
|
||||
class ItemTouchUIUtilImpl {
|
||||
|
||||
static class Lollipop extends Honeycomb {
|
||||
@Override
|
||||
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) {
|
||||
Object originalElevation = view.getTag();
|
||||
if (originalElevation == null) {
|
||||
|
@ -85,14 +85,14 @@ class ItemTouchUIUtilImpl {
|
|||
|
||||
@Override
|
||||
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.setTranslationY(view, dY);
|
||||
}
|
||||
|
||||
@Override
|
||||
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 {
|
||||
|
||||
private void draw(Canvas c, RecyclerView parent, View view,
|
||||
float dX, float dY) {
|
||||
float dX, float dY) {
|
||||
c.save();
|
||||
c.translate(dX, dY);
|
||||
parent.drawChild(c, view, 0);
|
||||
|
@ -119,7 +119,7 @@ class ItemTouchUIUtilImpl {
|
|||
|
||||
@Override
|
||||
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) {
|
||||
draw(c, recyclerView, view, dX, dY);
|
||||
}
|
||||
|
@ -127,8 +127,8 @@ class ItemTouchUIUtilImpl {
|
|||
|
||||
@Override
|
||||
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) {
|
||||
if (actionState == ItemTouchHelper.ACTION_STATE_DRAG) {
|
||||
draw(c, recyclerView, view, dX, dY);
|
||||
}
|
||||
|
|
|
@ -67,8 +67,9 @@ public class Track {
|
|||
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;
|
||||
isAudio = audio;
|
||||
if (!isAudio) {
|
||||
sampleDurations.add((long) 3015);
|
||||
duration = 3015;
|
||||
|
@ -136,7 +137,6 @@ public class Track {
|
|||
} else {
|
||||
sampleDurations.add((long) 1024);
|
||||
duration = 1024;
|
||||
isAudio = true;
|
||||
volume = 1;
|
||||
timeScale = format.getInteger(MediaFormat.KEY_SAMPLE_RATE);
|
||||
handler = "soun";
|
||||
|
@ -184,15 +184,18 @@ public class Track {
|
|||
}
|
||||
|
||||
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;
|
||||
samples.add(new Sample(offset, bufferInfo.size));
|
||||
if (syncSamples != null && isSyncFrame) {
|
||||
syncSamples.add(samples.size());
|
||||
}
|
||||
|
||||
long delta = bufferInfo.presentationTimeUs - lastPresentationTimeUs;
|
||||
lastPresentationTimeUs = bufferInfo.presentationTimeUs;
|
||||
delta = (delta * timeScale + 500000L) / 1000000L;
|
||||
lastPresentationTimeUs = bufferInfo.presentationTimeUs;
|
||||
if (!first) {
|
||||
sampleDurations.add(sampleDurations.size() - 1, 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) {
|
||||
onSlideAnimationEnd(backAnimation);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationCancel(Object animator) {
|
||||
onSlideAnimationEnd(backAnimation);
|
||||
}
|
||||
});
|
||||
animatorSet.start();
|
||||
animationInProgress = true;
|
||||
|
@ -693,11 +688,6 @@ public class ActionBarLayout extends FrameLayout {
|
|||
public void onAnimationEnd(Object animation) {
|
||||
onAnimationEndCheck(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationCancel(Object animation) {
|
||||
onAnimationEndCheck(false);
|
||||
}
|
||||
});
|
||||
currentAnimation.start();
|
||||
} else {
|
||||
|
@ -927,11 +917,6 @@ public class ActionBarLayout extends FrameLayout {
|
|||
public void onAnimationEnd(Object animation) {
|
||||
onAnimationEndCheck(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationCancel(Object animation) {
|
||||
onAnimationEndCheck(false);
|
||||
}
|
||||
});
|
||||
currentAnimation.start();
|
||||
} else {
|
||||
|
|
|
@ -610,11 +610,6 @@ public class BottomSheet extends Dialog {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationCancel(Animator animation) {
|
||||
onAnimationEnd(animation);
|
||||
}
|
||||
});
|
||||
animatorSet.start();
|
||||
}
|
||||
|
@ -706,11 +701,6 @@ public class BottomSheet extends Dialog {
|
|||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationCancel(Object animation) {
|
||||
onAnimationEnd(animation);
|
||||
}
|
||||
});
|
||||
animatorSetProxy.start();
|
||||
}
|
||||
|
@ -745,11 +735,6 @@ public class BottomSheet extends Dialog {
|
|||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationCancel(Object animation) {
|
||||
onAnimationEnd(animation);
|
||||
}
|
||||
});
|
||||
animatorSetProxy.start();
|
||||
}
|
||||
|
|
|
@ -187,11 +187,6 @@ public class DrawerLayoutContainer extends FrameLayout {
|
|||
public void onAnimationEnd(Object animator) {
|
||||
onDrawerAnimationEnd(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationCancel(Object animator) {
|
||||
onDrawerAnimationEnd(true);
|
||||
}
|
||||
});
|
||||
animatorSet.start();
|
||||
currentAnimation = animatorSet;
|
||||
|
@ -214,11 +209,6 @@ public class DrawerLayoutContainer extends FrameLayout {
|
|||
public void onAnimationEnd(Object animator) {
|
||||
onDrawerAnimationEnd(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationCancel(Object animator) {
|
||||
onDrawerAnimationEnd(false);
|
||||
}
|
||||
});
|
||||
animatorSet.start();
|
||||
}
|
||||
|
|
|
@ -238,7 +238,7 @@ public class ContactsAdapter extends BaseSectionsAdapter {
|
|||
}
|
||||
} else if (type == 0) {
|
||||
if (convertView == null) {
|
||||
convertView = new UserCell(mContext, 58, 1);
|
||||
convertView = new UserCell(mContext, 58, 1, false);
|
||||
((UserCell) convertView).setStatusColors(0xffa8a8a8, 0xff3b84c0);
|
||||
}
|
||||
|
||||
|
|
|
@ -94,6 +94,7 @@ public class DialogsAdapter extends RecyclerView.Adapter {
|
|||
} else if (viewType == 1) {
|
||||
view = new LoadingCell(mContext);
|
||||
}
|
||||
view.setLayoutParams(new RecyclerView.LayoutParams(RecyclerView.LayoutParams.MATCH_PARENT, RecyclerView.LayoutParams.WRAP_CONTENT));
|
||||
return new Holder(view);
|
||||
}
|
||||
|
||||
|
|
|
@ -885,6 +885,7 @@ public class DialogsSearchAdapter extends BaseSearchAdapterRecycler {
|
|||
view = new HashtagSearchCell(mContext);
|
||||
break;
|
||||
}
|
||||
view.setLayoutParams(new RecyclerView.LayoutParams(RecyclerView.LayoutParams.MATCH_PARENT, RecyclerView.LayoutParams.WRAP_CONTENT));
|
||||
return new Holder(view);
|
||||
}
|
||||
|
||||
|
|
|
@ -419,6 +419,7 @@ public class MentionsAdapter extends BaseSearchAdapterRecycler {
|
|||
boolean added = false;
|
||||
if (searchResultBotContext == null || offset.length() == 0) {
|
||||
searchResultBotContext = res.results;
|
||||
contextMedia = res.gallery;
|
||||
} else {
|
||||
added = true;
|
||||
searchResultBotContext.addAll(res.results);
|
||||
|
@ -426,7 +427,6 @@ public class MentionsAdapter extends BaseSearchAdapterRecycler {
|
|||
nextQueryOffset = "";
|
||||
}
|
||||
}
|
||||
contextMedia = res.gallery;
|
||||
searchResultHashtags = null;
|
||||
searchResultUsernames = null;
|
||||
searchResultCommands = null;
|
||||
|
|
|
@ -238,7 +238,7 @@ public class SearchAdapter extends BaseSearchAdapter {
|
|||
} else {
|
||||
if (view == null) {
|
||||
if (useUserCell) {
|
||||
view = new UserCell(mContext, 1, 1);
|
||||
view = new UserCell(mContext, 1, 1, false);
|
||||
if (checkedMap != null) {
|
||||
((UserCell) view).setChecked(false, false);
|
||||
}
|
||||
|
|
|
@ -263,11 +263,19 @@ public class BlockedUsersActivity extends BaseFragment implements NotificationCe
|
|||
int type = getItemViewType(i);
|
||||
if (type == 0) {
|
||||
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));
|
||||
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) {
|
||||
if (view == null) {
|
||||
|
|
|
@ -413,10 +413,9 @@ public class CacheControlActivity extends BaseFragment {
|
|||
NativeByteBuffer data = new NativeByteBuffer(cursor2.byteArrayLength(0));
|
||||
if (data != null && cursor2.byteBufferValue(0, data) != 0) {
|
||||
TLRPC.Message message = TLRPC.Message.TLdeserialize(data, data.readInt32(false), false);
|
||||
if (message == null) {
|
||||
continue;
|
||||
if (message != null) {
|
||||
arrayList.add(message);
|
||||
}
|
||||
arrayList.add(message);
|
||||
}
|
||||
data.reuse();
|
||||
}
|
||||
|
|
|
@ -100,12 +100,16 @@ public class BotHelpCell extends View {
|
|||
MessageObject.addLinks(stringBuilder);
|
||||
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);
|
||||
textLayout = new StaticLayout(stringBuilder, textPaint, width, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false);
|
||||
width = 0;
|
||||
height = textLayout.getHeight() + AndroidUtilities.dp(4 + 18);
|
||||
int count = textLayout.getLineCount();
|
||||
for (int a = 0; a < count; a++) {
|
||||
width = (int) Math.ceil(Math.max(width, textLayout.getLineWidth(a) + textLayout.getLineLeft(a)));
|
||||
try {
|
||||
textLayout = new StaticLayout(stringBuilder, textPaint, width, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false);
|
||||
width = 0;
|
||||
height = textLayout.getHeight() + AndroidUtilities.dp(4 + 18);
|
||||
int count = textLayout.getLineCount();
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -57,6 +57,8 @@ public class ChatActionCell extends BaseCell {
|
|||
private int previousWidth = 0;
|
||||
private boolean imagePressed = false;
|
||||
|
||||
private boolean hasReplyMessage;
|
||||
|
||||
private MessageObject currentMessageObject;
|
||||
|
||||
private ChatActionCellDelegate delegate;
|
||||
|
@ -79,10 +81,11 @@ public class ChatActionCell extends BaseCell {
|
|||
}
|
||||
|
||||
public void setMessageObject(MessageObject messageObject) {
|
||||
if (currentMessageObject == messageObject) {
|
||||
if (currentMessageObject == messageObject && (hasReplyMessage || messageObject.replyMessageObject == null)) {
|
||||
return;
|
||||
}
|
||||
currentMessageObject = messageObject;
|
||||
hasReplyMessage = messageObject.replyMessageObject != null;
|
||||
previousWidth = 0;
|
||||
if (currentMessageObject.type == 11) {
|
||||
int id = 0;
|
||||
|
@ -220,8 +223,8 @@ public class ChatActionCell extends BaseCell {
|
|||
int width = Math.max(AndroidUtilities.dp(30), MeasureSpec.getSize(widthMeasureSpec));
|
||||
if (width != previousWidth) {
|
||||
previousWidth = width;
|
||||
|
||||
textLayout = new StaticLayout(currentMessageObject.messageText, textPaint, width - AndroidUtilities.dp(30), Layout.Alignment.ALIGN_CENTER, 1.0f, 0.0f, false);
|
||||
int maxWidth = width - AndroidUtilities.dp(30);
|
||||
textLayout = new StaticLayout(currentMessageObject.messageText, textPaint, maxWidth, Layout.Alignment.ALIGN_CENTER, 1.0f, 0.0f, false);
|
||||
textHeight = 0;
|
||||
textWidth = 0;
|
||||
try {
|
||||
|
@ -230,6 +233,9 @@ public class ChatActionCell extends BaseCell {
|
|||
float lineWidth;
|
||||
try {
|
||||
lineWidth = textLayout.getLineWidth(a);
|
||||
if (lineWidth > maxWidth) {
|
||||
lineWidth = maxWidth;
|
||||
}
|
||||
textHeight = (int)Math.max(textHeight, Math.ceil(textLayout.getLineBottom(a)));
|
||||
} catch (Exception 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.
|
||||
* 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.ImageReceiver;
|
||||
import org.telegram.ui.Components.AvatarDrawable;
|
||||
import org.telegram.ui.Components.LinkPath;
|
||||
import org.telegram.ui.Components.ResourceLoader;
|
||||
import org.telegram.ui.Components.StaticLayoutEx;
|
||||
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 didPressedCancelSendButton(ChatBaseCell cell);
|
||||
void didLongPressed(ChatBaseCell cell);
|
||||
void didPressReplyMessage(ChatBaseCell cell, int id);
|
||||
void didPressUrl(MessageObject messageObject, ClickableSpan url, boolean longPress);
|
||||
void didPressedReplyMessage(ChatBaseCell cell, int id);
|
||||
void didPressedUrl(MessageObject messageObject, ClickableSpan url, boolean longPress);
|
||||
void needOpenWebView(String url, String title, String originalUrl, int w, int h);
|
||||
void didClickedImage(ChatBaseCell cell);
|
||||
void didPressShare(ChatBaseCell cell);
|
||||
void didPressedImage(ChatBaseCell cell);
|
||||
void didPressedShare(ChatBaseCell cell);
|
||||
void didPressedOther(ChatBaseCell cell);
|
||||
boolean canPerformActions();
|
||||
}
|
||||
|
||||
protected ClickableSpan pressedLink;
|
||||
protected boolean linkPreviewPressed;
|
||||
protected LinkPath urlPath = new LinkPath();
|
||||
protected static Paint urlPaint;
|
||||
private int TAG;
|
||||
|
||||
public boolean isChat;
|
||||
protected boolean isPressed;
|
||||
protected boolean forwardName;
|
||||
protected boolean isHighlighted;
|
||||
protected boolean media;
|
||||
protected boolean mediaBackground;
|
||||
protected boolean isCheckPressed = true;
|
||||
private boolean wasLayout;
|
||||
protected boolean isAvatarVisible;
|
||||
|
@ -180,9 +176,6 @@ public class ChatBaseCell extends BaseCell implements MediaController.FileDownlo
|
|||
replyTextPaint.linkColor = 0xff316f9f;
|
||||
|
||||
replyLinePaint = new Paint();
|
||||
|
||||
urlPaint = new Paint();
|
||||
urlPaint.setColor(0x33316f9f);
|
||||
}
|
||||
avatarImage = new ImageReceiver(this);
|
||||
avatarImage.setRoundRadius(AndroidUtilities.dp(21));
|
||||
|
@ -211,14 +204,6 @@ public class ChatBaseCell extends BaseCell implements MediaController.FileDownlo
|
|||
invalidate();
|
||||
}
|
||||
|
||||
protected void resetPressedLink() {
|
||||
if (pressedLink != null) {
|
||||
pressedLink = null;
|
||||
}
|
||||
linkPreviewPressed = false;
|
||||
invalidate();
|
||||
}
|
||||
|
||||
public void setDelegate(ChatBaseCellDelegate delegate) {
|
||||
this.delegate = delegate;
|
||||
}
|
||||
|
@ -487,7 +472,7 @@ public class ChatBaseCell extends BaseCell implements MediaController.FileDownlo
|
|||
}
|
||||
}
|
||||
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) {
|
||||
nameWidth = (int)Math.ceil(nameLayout.getLineWidth(0));
|
||||
namesOffset += AndroidUtilities.dp(19);
|
||||
|
@ -557,7 +542,7 @@ public class ChatBaseCell extends BaseCell implements MediaController.FileDownlo
|
|||
namesOffset += AndroidUtilities.dp(42);
|
||||
if (messageObject.contentType == 2 || messageObject.contentType == 3) {
|
||||
namesOffset += AndroidUtilities.dp(4);
|
||||
} else if (messageObject.contentType == 1) {
|
||||
} else if (messageObject.type != 0) {
|
||||
if (messageObject.type == 13) {
|
||||
namesOffset -= AndroidUtilities.dp(42);
|
||||
} else {
|
||||
|
@ -590,7 +575,7 @@ public class ChatBaseCell extends BaseCell implements MediaController.FileDownlo
|
|||
} else {
|
||||
maxWidth = getMaxNameWidth() - AndroidUtilities.dp(22);
|
||||
}
|
||||
if (!media && messageObject.contentType != 0) {
|
||||
if (!mediaBackground) {
|
||||
maxWidth -= AndroidUtilities.dp(8);
|
||||
}
|
||||
|
||||
|
@ -772,7 +757,7 @@ public class ChatBaseCell extends BaseCell implements MediaController.FileDownlo
|
|||
replyPressed = false;
|
||||
playSoundEffect(SoundEffectConstants.CLICK);
|
||||
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) {
|
||||
replyPressed = false;
|
||||
|
@ -786,7 +771,7 @@ public class ChatBaseCell extends BaseCell implements MediaController.FileDownlo
|
|||
sharePressed = false;
|
||||
playSoundEffect(SoundEffectConstants.CLICK);
|
||||
if (delegate != null) {
|
||||
delegate.didPressShare(this);
|
||||
delegate.didPressedShare(this);
|
||||
}
|
||||
} else if (event.getAction() == MotionEvent.ACTION_CANCEL) {
|
||||
sharePressed = false;
|
||||
|
@ -812,9 +797,11 @@ public class ChatBaseCell extends BaseCell implements MediaController.FileDownlo
|
|||
if (changed || !wasLayout) {
|
||||
layoutWidth = getMeasuredWidth();
|
||||
layoutHeight = getMeasuredHeight();
|
||||
|
||||
if (timeTextWidth < 0) {
|
||||
timeTextWidth = AndroidUtilities.dp(10);
|
||||
}
|
||||
timeLayout = new StaticLayout(currentTimeString, timePaint, timeTextWidth, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false);
|
||||
if (!media) {
|
||||
if (!mediaBackground) {
|
||||
if (!currentMessageObject.isOutOwner()) {
|
||||
timeX = backgroundWidth - AndroidUtilities.dp(9) - timeWidth + (isChat && currentMessageObject.isFromUser() ? AndroidUtilities.dp(52) : 0);
|
||||
} else {
|
||||
|
@ -876,7 +863,7 @@ public class ChatBaseCell extends BaseCell implements MediaController.FileDownlo
|
|||
avatarImage.draw(canvas);
|
||||
}
|
||||
|
||||
if (media) {
|
||||
if (mediaBackground) {
|
||||
timePaint.setColor(0xffffffff);
|
||||
} else {
|
||||
if (currentMessageObject.isOutOwner()) {
|
||||
|
@ -889,37 +876,37 @@ public class ChatBaseCell extends BaseCell implements MediaController.FileDownlo
|
|||
Drawable currentBackgroundDrawable;
|
||||
if (currentMessageObject.isOutOwner()) {
|
||||
if (isDrawSelectedBackground()) {
|
||||
if (!media) {
|
||||
if (!mediaBackground) {
|
||||
currentBackgroundDrawable = ResourceLoader.backgroundDrawableOutSelected;
|
||||
} else {
|
||||
currentBackgroundDrawable = ResourceLoader.backgroundMediaDrawableOutSelected;
|
||||
}
|
||||
} else {
|
||||
if (!media) {
|
||||
if (!mediaBackground) {
|
||||
currentBackgroundDrawable = ResourceLoader.backgroundDrawableOut;
|
||||
} else {
|
||||
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 {
|
||||
if (isDrawSelectedBackground()) {
|
||||
if (!media) {
|
||||
if (!mediaBackground) {
|
||||
currentBackgroundDrawable = ResourceLoader.backgroundDrawableInSelected;
|
||||
} else {
|
||||
currentBackgroundDrawable = ResourceLoader.backgroundMediaDrawableInSelected;
|
||||
}
|
||||
} else {
|
||||
if (!media) {
|
||||
if (!mediaBackground) {
|
||||
currentBackgroundDrawable = ResourceLoader.backgroundDrawableIn;
|
||||
} else {
|
||||
currentBackgroundDrawable = ResourceLoader.backgroundMediaDrawableIn;
|
||||
}
|
||||
}
|
||||
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 {
|
||||
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) {
|
||||
|
@ -935,7 +922,7 @@ public class ChatBaseCell extends BaseCell implements MediaController.FileDownlo
|
|||
|
||||
if (drawName && nameLayout != null) {
|
||||
canvas.save();
|
||||
if (media || currentMessageObject.isOutOwner()) {
|
||||
if (mediaBackground || currentMessageObject.isOutOwner()) {
|
||||
canvas.translate(nameX = currentBackgroundDrawable.getBounds().left + AndroidUtilities.dp(10) - nameOffsetX, AndroidUtilities.dp(10));
|
||||
} else {
|
||||
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);
|
||||
} else {
|
||||
forwardNamePaint.setColor(0xff006fc8);
|
||||
if (media) {
|
||||
if (mediaBackground) {
|
||||
forwardNameX = currentBackgroundDrawable.getBounds().left + AndroidUtilities.dp(10);
|
||||
} else {
|
||||
forwardNameX = currentBackgroundDrawable.getBounds().left + AndroidUtilities.dp(19);
|
||||
|
@ -972,10 +959,6 @@ public class ChatBaseCell extends BaseCell implements MediaController.FileDownlo
|
|||
canvas.translate(forwardNameX - forwardNameOffsetX, forwardNameY);
|
||||
forwardedNameLayout.draw(canvas);
|
||||
canvas.restore();
|
||||
|
||||
/*if (viaWidth != 0) {
|
||||
canvas.drawRect(forwardNameX + viaNameWidth, forwardNameY, forwardNameX + viaNameWidth + viaWidth, forwardNameY + AndroidUtilities.dp(32), namePaint);
|
||||
}*/
|
||||
}
|
||||
|
||||
if (currentMessageObject.isReply()) {
|
||||
|
@ -1018,7 +1001,7 @@ public class ChatBaseCell extends BaseCell implements MediaController.FileDownlo
|
|||
} else {
|
||||
replyTextPaint.setColor(0xff999999);
|
||||
}
|
||||
if (currentMessageObject.contentType == 1 && media) {
|
||||
if (mediaBackground) {
|
||||
replyStartX = currentBackgroundDrawable.getBounds().left + AndroidUtilities.dp(11);
|
||||
} else {
|
||||
replyStartX = currentBackgroundDrawable.getBounds().left + AndroidUtilities.dp(20);
|
||||
|
@ -1045,8 +1028,8 @@ public class ChatBaseCell extends BaseCell implements MediaController.FileDownlo
|
|||
}
|
||||
}
|
||||
|
||||
if (drawTime || !media) {
|
||||
if (media) {
|
||||
if (drawTime || !mediaBackground) {
|
||||
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));
|
||||
ResourceLoader.mediaBackgroundDrawable.draw(canvas);
|
||||
|
||||
|
@ -1152,7 +1135,7 @@ public class ChatBaseCell extends BaseCell implements MediaController.FileDownlo
|
|||
}
|
||||
|
||||
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());
|
||||
ResourceLoader.clockDrawable.draw(canvas);
|
||||
} else {
|
||||
|
@ -1162,7 +1145,7 @@ public class ChatBaseCell extends BaseCell implements MediaController.FileDownlo
|
|||
}
|
||||
if (isBroadcast) {
|
||||
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());
|
||||
ResourceLoader.broadcastDrawable.draw(canvas);
|
||||
} else {
|
||||
|
@ -1172,7 +1155,7 @@ public class ChatBaseCell extends BaseCell implements MediaController.FileDownlo
|
|||
}
|
||||
} else {
|
||||
if (drawCheck2) {
|
||||
if (!media) {
|
||||
if (!mediaBackground) {
|
||||
if (drawCheck1) {
|
||||
setDrawableBounds(ResourceLoader.checkDrawable, layoutWidth - AndroidUtilities.dp(22.5f) - ResourceLoader.checkDrawable.getIntrinsicWidth(), layoutHeight - AndroidUtilities.dp(8.0f) - ResourceLoader.checkDrawable.getIntrinsicHeight());
|
||||
} else {
|
||||
|
@ -1189,7 +1172,7 @@ public class ChatBaseCell extends BaseCell implements MediaController.FileDownlo
|
|||
}
|
||||
}
|
||||
if (drawCheck1) {
|
||||
if (!media) {
|
||||
if (!mediaBackground) {
|
||||
setDrawableBounds(ResourceLoader.halfCheckDrawable, layoutWidth - AndroidUtilities.dp(18) - ResourceLoader.halfCheckDrawable.getIntrinsicWidth(), layoutHeight - AndroidUtilities.dp(8.0f) - ResourceLoader.halfCheckDrawable.getIntrinsicHeight());
|
||||
ResourceLoader.halfCheckDrawable.draw(canvas);
|
||||
} else {
|
||||
|
@ -1199,7 +1182,7 @@ public class ChatBaseCell extends BaseCell implements MediaController.FileDownlo
|
|||
}
|
||||
}
|
||||
if (drawError) {
|
||||
if (!media) {
|
||||
if (!mediaBackground) {
|
||||
setDrawableBounds(ResourceLoader.errorDrawable, layoutWidth - AndroidUtilities.dp(18) - ResourceLoader.errorDrawable.getIntrinsicWidth(), layoutHeight - AndroidUtilities.dp(6.5f) - ResourceLoader.errorDrawable.getIntrinsicHeight());
|
||||
ResourceLoader.errorDrawable.draw(canvas);
|
||||
} 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.Drawable;
|
||||
import android.os.Build;
|
||||
import android.text.TextUtils;
|
||||
import android.util.TypedValue;
|
||||
import android.view.Gravity;
|
||||
import android.widget.FrameLayout;
|
||||
|
@ -66,6 +67,7 @@ public class DrawerProfileCell extends FrameLayout {
|
|||
nameTextView.setMaxLines(1);
|
||||
nameTextView.setSingleLine(true);
|
||||
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));
|
||||
|
||||
phoneTextView = new TextView(context);
|
||||
|
|
|
@ -16,13 +16,19 @@ import org.telegram.messenger.R;
|
|||
|
||||
public class ShadowSectionCell extends View {
|
||||
|
||||
private int size = 12;
|
||||
|
||||
public ShadowSectionCell(Context context) {
|
||||
super(context);
|
||||
setBackgroundResource(R.drawable.greydivider);
|
||||
}
|
||||
|
||||
public void setSize(int value) {
|
||||
size = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
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.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16);
|
||||
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) {
|
||||
|
|
|
@ -25,6 +25,7 @@ import org.telegram.ui.Components.Switch;
|
|||
public class TextCheckCell extends FrameLayoutFixed {
|
||||
|
||||
private TextView textView;
|
||||
private TextView valueTextView;
|
||||
private Switch checkBox;
|
||||
private static Paint paint;
|
||||
private boolean needDivider;
|
||||
|
@ -47,6 +48,16 @@ public class TextCheckCell extends FrameLayoutFixed {
|
|||
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));
|
||||
|
||||
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.setDuplicateParentStateEnabled(false);
|
||||
checkBox.setFocusable(false);
|
||||
|
@ -57,7 +68,7 @@ public class TextCheckCell extends FrameLayoutFixed {
|
|||
|
||||
@Override
|
||||
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) {
|
||||
|
@ -68,6 +79,28 @@ public class TextCheckCell extends FrameLayoutFixed {
|
|||
}
|
||||
checkBox.setChecked(checked);
|
||||
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);
|
||||
}
|
||||
|
||||
|
|
|
@ -87,6 +87,10 @@ public class TextSettingsCell extends FrameLayout {
|
|||
textView.setTextColor(color);
|
||||
}
|
||||
|
||||
public void setTextValueColor(int color) {
|
||||
valueTextView.setTextColor(color);
|
||||
}
|
||||
|
||||
public void setText(String text, boolean divider) {
|
||||
textView.setText(text);
|
||||
valueTextView.setVisibility(INVISIBLE);
|
||||
|
|
|
@ -37,6 +37,7 @@ public class UserCell extends FrameLayout {
|
|||
private ImageView imageView;
|
||||
private CheckBox checkBox;
|
||||
private CheckBoxSquare checkBoxBig;
|
||||
private ImageView adminImage;
|
||||
|
||||
private AvatarDrawable avatarDrawable;
|
||||
private TLObject currentObject = null;
|
||||
|
@ -52,7 +53,7 @@ public class UserCell extends FrameLayout {
|
|||
private int statusColor = 0xffa8a8a8;
|
||||
private int statusOnlineColor = 0xff3b84c0;
|
||||
|
||||
public UserCell(Context context, int padding, int checkbox) {
|
||||
public UserCell(Context context, int padding, int checkbox, boolean admin) {
|
||||
super(context);
|
||||
|
||||
avatarDrawable = new AvatarDrawable();
|
||||
|
@ -65,7 +66,7 @@ public class UserCell extends FrameLayout {
|
|||
nameTextView.setTextColor(0xff212121);
|
||||
nameTextView.setTextSize(17);
|
||||
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.setTextSize(14);
|
||||
|
@ -85,6 +86,20 @@ public class UserCell extends FrameLayout {
|
|||
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));
|
||||
}
|
||||
|
||||
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) {
|
||||
|
|
|
@ -166,6 +166,7 @@ public class ChangeNameActivity extends BaseFragment {
|
|||
return;
|
||||
}
|
||||
TLRPC.TL_account_updateProfile req = new TLRPC.TL_account_updateProfile();
|
||||
req.flags = 3;
|
||||
currentUser.first_name = req.first_name = newFirst;
|
||||
currentUser.last_name = req.last_name = newLast;
|
||||
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.
|
||||
* You should have received a copy of the license in this archive (see LICENSE).
|
||||
*
|
||||
|
@ -8,17 +8,25 @@
|
|||
|
||||
package org.telegram.ui;
|
||||
|
||||
import android.Manifest;
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.Activity;
|
||||
import android.app.AlertDialog;
|
||||
import android.app.Dialog;
|
||||
import android.app.ProgressDialog;
|
||||
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.telephony.TelephonyManager;
|
||||
import android.text.Editable;
|
||||
import android.text.InputFilter;
|
||||
import android.text.InputType;
|
||||
import android.text.SpannableStringBuilder;
|
||||
import android.text.Spanned;
|
||||
import android.text.TextUtils;
|
||||
import android.text.TextWatcher;
|
||||
import android.util.TypedValue;
|
||||
|
@ -30,6 +38,7 @@ import android.view.inputmethod.EditorInfo;
|
|||
import android.widget.AdapterView;
|
||||
import android.widget.EditText;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.ScrollView;
|
||||
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.LayoutHelper;
|
||||
import org.telegram.ui.Components.SlideView;
|
||||
import org.telegram.ui.Components.TypefaceSpan;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.InputStreamReader;
|
||||
|
@ -74,17 +82,21 @@ import java.util.TimerTask;
|
|||
public class ChangePhoneActivity extends BaseFragment {
|
||||
|
||||
private int currentViewNum = 0;
|
||||
private SlideView[] views = new SlideView[2];
|
||||
private SlideView[] views = new SlideView[5];
|
||||
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;
|
||||
|
||||
@Override
|
||||
public void onFragmentDestroy() {
|
||||
super.onFragmentDestroy();
|
||||
for (SlideView v : views) {
|
||||
if (v != null) {
|
||||
v.onDestroyActivity();
|
||||
for (int a = 0; a < views.length; a++) {
|
||||
if (views[a] != null) {
|
||||
views[a].onDestroyActivity();
|
||||
}
|
||||
}
|
||||
if (progressDialog != null) {
|
||||
|
@ -114,39 +126,25 @@ public class ChangePhoneActivity extends BaseFragment {
|
|||
});
|
||||
|
||||
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);
|
||||
ScrollView scrollView = (ScrollView) fragmentView;
|
||||
scrollView.setFillViewport(true);
|
||||
|
||||
FrameLayout frameLayout = new FrameLayout(context);
|
||||
scrollView.addView(frameLayout);
|
||||
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);
|
||||
scrollView.addView(frameLayout, LayoutHelper.createScroll(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.TOP | Gravity.LEFT));
|
||||
|
||||
views[0] = new PhoneView(context);
|
||||
views[0].setVisibility(View.VISIBLE);
|
||||
frameLayout.addView(views[0], LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.TOP | Gravity.LEFT, 16, 30, 16, 0));
|
||||
views[1] = new LoginActivitySmsView(context, 1);
|
||||
views[2] = new LoginActivitySmsView(context, 2);
|
||||
views[3] = new LoginActivitySmsView(context, 3);
|
||||
views[4] = new LoginActivitySmsView(context, 4);
|
||||
|
||||
views[1] = new LoginActivitySmsView(context);
|
||||
views[1].setVisibility(View.GONE);
|
||||
frameLayout.addView(views[1], LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, 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);
|
||||
for (int a = 0; a < views.length; a++) {
|
||||
views[a].setVisibility(a == 0 ? View.VISIBLE : View.GONE);
|
||||
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)
|
||||
}
|
||||
|
||||
actionBar.setTitle(views[0].getHeaderName());
|
||||
|
@ -160,16 +158,34 @@ public class ChangePhoneActivity extends BaseFragment {
|
|||
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
|
||||
public boolean onBackPressed() {
|
||||
if (currentViewNum == 0) {
|
||||
for (SlideView v : views) {
|
||||
if (v != null) {
|
||||
v.onDestroyActivity();
|
||||
for (int a = 0; a < views.length; a++) {
|
||||
if (views[a] != null) {
|
||||
views[a].onDestroyActivity();
|
||||
}
|
||||
}
|
||||
return true;
|
||||
} else if (currentViewNum == 1) {
|
||||
} else {
|
||||
views[currentViewNum].onBackPressed();
|
||||
setPage(0, true, null, true);
|
||||
}
|
||||
return false;
|
||||
|
@ -217,6 +233,14 @@ public class ChangePhoneActivity extends BaseFragment {
|
|||
}
|
||||
|
||||
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) {
|
||||
final SlideView outView = views[currentViewNum];
|
||||
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 {
|
||||
|
||||
private EditText codeField;
|
||||
|
@ -287,9 +345,9 @@ public class ChangePhoneActivity extends BaseFragment {
|
|||
countryButton.setMaxLines(1);
|
||||
countryButton.setSingleLine(true);
|
||||
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);
|
||||
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() {
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
|
@ -315,7 +373,7 @@ public class ChangePhoneActivity extends BaseFragment {
|
|||
View view = new View(context);
|
||||
view.setPadding(AndroidUtilities.dp(12), 0, AndroidUtilities.dp(12), 0);
|
||||
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.setOrientation(HORIZONTAL);
|
||||
|
@ -325,7 +383,7 @@ public class ChangePhoneActivity extends BaseFragment {
|
|||
textView.setText("+");
|
||||
textView.setTextColor(0xff212121);
|
||||
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.setInputType(InputType.TYPE_CLASS_PHONE);
|
||||
|
@ -354,7 +412,6 @@ public class ChangePhoneActivity extends BaseFragment {
|
|||
@Override
|
||||
public void afterTextChanged(Editable editable) {
|
||||
if (ignoreOnTextChange) {
|
||||
ignoreOnTextChange = false;
|
||||
return;
|
||||
}
|
||||
ignoreOnTextChange = true;
|
||||
|
@ -414,6 +471,7 @@ public class ChangePhoneActivity extends BaseFragment {
|
|||
phoneField.setSelection(phoneField.length());
|
||||
}
|
||||
}
|
||||
ignoreOnTextChange = false;
|
||||
}
|
||||
});
|
||||
codeField.setOnEditorActionListener(new TextView.OnEditorActionListener() {
|
||||
|
@ -438,7 +496,7 @@ public class ChangePhoneActivity extends BaseFragment {
|
|||
phoneField.setMaxLines(1);
|
||||
phoneField.setGravity(Gravity.LEFT | Gravity.CENTER_VERTICAL);
|
||||
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() {
|
||||
|
||||
private int characterAction = -1;
|
||||
|
@ -528,9 +586,9 @@ public class ChangePhoneActivity extends BaseFragment {
|
|||
textView.setText(LocaleController.getString("ChangePhoneHelp", R.string.ChangePhoneHelp));
|
||||
textView.setTextColor(0xff757575);
|
||||
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);
|
||||
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<>();
|
||||
try {
|
||||
|
@ -561,7 +619,7 @@ public class ChangePhoneActivity extends BaseFragment {
|
|||
String country = null;
|
||||
|
||||
try {
|
||||
TelephonyManager telephonyManager = (TelephonyManager)ApplicationLoader.applicationContext.getSystemService(Context.TELEPHONY_SERVICE);
|
||||
TelephonyManager telephonyManager = (TelephonyManager) ApplicationLoader.applicationContext.getSystemService(Context.TELEPHONY_SERVICE);
|
||||
if (telephonyManager != null) {
|
||||
country = telephonyManager.getSimCountryIso().toUpperCase();
|
||||
}
|
||||
|
@ -605,6 +663,7 @@ public class ChangePhoneActivity extends BaseFragment {
|
|||
String hint = phoneFormatMap.get(code);
|
||||
phoneField.setHintText(hint != null ? hint.replace('X', '–') : null);
|
||||
countryState = 0;
|
||||
ignoreOnTextChange = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -617,6 +676,7 @@ public class ChangePhoneActivity extends BaseFragment {
|
|||
ignoreOnTextChange = true;
|
||||
String str = countriesArray.get(i);
|
||||
codeField.setText(countriesMap.get(str));
|
||||
ignoreOnTextChange = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -626,9 +686,46 @@ public class ChangePhoneActivity extends BaseFragment {
|
|||
|
||||
@Override
|
||||
public void onNextPressed() {
|
||||
if (nextPressed) {
|
||||
if (getParentActivity() == null || nextPressed) {
|
||||
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) {
|
||||
needShowAlert(LocaleController.getString("ChooseCountry", R.string.ChooseCountry));
|
||||
return;
|
||||
|
@ -643,10 +740,20 @@ public class ChangePhoneActivity extends BaseFragment {
|
|||
TLRPC.TL_account_sendChangePhoneCode req = new TLRPC.TL_account_sendChangePhoneCode();
|
||||
String phone = PhoneFormat.stripExceptNumbers("" + codeField.getText() + phoneField.getText());
|
||||
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();
|
||||
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);
|
||||
nextPressed = true;
|
||||
needShowProgress();
|
||||
|
@ -658,10 +765,7 @@ public class ChangePhoneActivity extends BaseFragment {
|
|||
public void run() {
|
||||
nextPressed = false;
|
||||
if (error == null) {
|
||||
TLRPC.TL_account_sentChangePhoneCode res = (TLRPC.TL_account_sentChangePhoneCode)response;
|
||||
params.putString("phoneHash", res.phone_code_hash);
|
||||
params.putInt("calltime", res.send_call_timeout * 1000);
|
||||
setPage(1, true, params, false);
|
||||
fillNextCodeParams(params, (TLRPC.TL_auth_sentCode) response);
|
||||
} else {
|
||||
if (error.text != null) {
|
||||
if (error.text.contains("PHONE_NUMBER_INVALID")) {
|
||||
|
@ -673,7 +777,7 @@ public class ChangePhoneActivity extends BaseFragment {
|
|||
} else if (error.text.startsWith("FLOOD_WAIT")) {
|
||||
needShowAlert(LocaleController.getString("FloodWait", R.string.FloodWait));
|
||||
} 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 {
|
||||
needShowAlert(LocaleController.getString("ErrorOccurred", R.string.ErrorOccurred));
|
||||
}
|
||||
|
@ -709,43 +813,88 @@ public class ChangePhoneActivity extends BaseFragment {
|
|||
|
||||
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 requestPhone;
|
||||
private String emailPhone;
|
||||
private EditText codeField;
|
||||
private TextView confirmTextView;
|
||||
private TextView timeText;
|
||||
private TextView problemText;
|
||||
private Bundle currentParams;
|
||||
private ProgressView progressView;
|
||||
|
||||
private Timer timeTimer;
|
||||
private Timer codeTimer;
|
||||
private int openTime;
|
||||
private final Object timerSync = new Object();
|
||||
private volatile int time = 60000;
|
||||
private volatile int codeTime = 15000;
|
||||
private double lastCurrentTime;
|
||||
private double lastCodeTime;
|
||||
private boolean ignoreOnTextChange;
|
||||
private boolean waitingForSms = false;
|
||||
private boolean nextPressed = false;
|
||||
private boolean waitingForEvent;
|
||||
private boolean nextPressed;
|
||||
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);
|
||||
|
||||
currentType = type;
|
||||
setOrientation(VERTICAL);
|
||||
|
||||
confirmTextView = new TextView(context);
|
||||
confirmTextView.setTextColor(0xff757575);
|
||||
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);
|
||||
addView(confirmTextView);
|
||||
LayoutParams layoutParams = (LayoutParams) confirmTextView.getLayoutParams();
|
||||
layoutParams.width = LayoutHelper.WRAP_CONTENT;
|
||||
layoutParams.height = LayoutHelper.WRAP_CONTENT;
|
||||
layoutParams.gravity = Gravity.LEFT;
|
||||
layoutParams.leftMargin = AndroidUtilities.dp(24);
|
||||
layoutParams.rightMargin = AndroidUtilities.dp(24);
|
||||
confirmTextView.setLayoutParams(layoutParams);
|
||||
|
||||
if (currentType == 3) {
|
||||
FrameLayout frameLayout = new FrameLayout(context);
|
||||
|
||||
ImageView imageView = new ImageView(context);
|
||||
imageView.setImageResource(R.drawable.phone_activate);
|
||||
if (LocaleController.isRTL) {
|
||||
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.setTextColor(0xff212121);
|
||||
|
@ -757,15 +906,7 @@ public class ChangePhoneActivity extends BaseFragment {
|
|||
codeField.setInputType(InputType.TYPE_CLASS_PHONE);
|
||||
codeField.setMaxLines(1);
|
||||
codeField.setPadding(0, 0, 0, 0);
|
||||
addView(codeField);
|
||||
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);
|
||||
addView(codeField, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 36, Gravity.CENTER_HORIZONTAL, 0, 20, 0, 0));
|
||||
codeField.addTextChangedListener(new TextWatcher() {
|
||||
@Override
|
||||
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
|
||||
|
@ -782,7 +923,7 @@ public class ChangePhoneActivity extends BaseFragment {
|
|||
if (ignoreOnTextChange) {
|
||||
return;
|
||||
}
|
||||
if (codeField.length() == 5) {
|
||||
if (length != 0 && codeField.length() == length) {
|
||||
onNextPressed();
|
||||
}
|
||||
}
|
||||
|
@ -797,55 +938,133 @@ public class ChangePhoneActivity extends BaseFragment {
|
|||
return false;
|
||||
}
|
||||
});
|
||||
if (currentType == 3) {
|
||||
codeField.setEnabled(false);
|
||||
codeField.setInputType(InputType.TYPE_NULL);
|
||||
codeField.setVisibility(GONE);
|
||||
}
|
||||
|
||||
timeText = new TextView(context);
|
||||
timeText.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14);
|
||||
timeText.setTextColor(0xff757575);
|
||||
timeText.setLineSpacing(AndroidUtilities.dp(2), 1.0f);
|
||||
timeText.setGravity(Gravity.LEFT);
|
||||
addView(timeText);
|
||||
layoutParams = (LayoutParams) timeText.getLayoutParams();
|
||||
layoutParams.width = LayoutHelper.WRAP_CONTENT;
|
||||
layoutParams.height = LayoutHelper.WRAP_CONTENT;
|
||||
layoutParams.gravity = Gravity.LEFT;
|
||||
layoutParams.topMargin = AndroidUtilities.dp(30);
|
||||
layoutParams.leftMargin = AndroidUtilities.dp(24);
|
||||
layoutParams.rightMargin = AndroidUtilities.dp(24);
|
||||
timeText.setLayoutParams(layoutParams);
|
||||
timeText.setGravity(LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT);
|
||||
addView(timeText, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT, 0, 30, 0, 0));
|
||||
|
||||
if (currentType == 3) {
|
||||
progressView = new ProgressView(context);
|
||||
addView(progressView, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 3, 0, 12, 0, 0));
|
||||
}
|
||||
|
||||
problemText = new TextView(context);
|
||||
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.setGravity(Gravity.BOTTOM | Gravity.CENTER_VERTICAL);
|
||||
addView(linearLayout);
|
||||
layoutParams = (LayoutParams) linearLayout.getLayoutParams();
|
||||
layoutParams.width = LayoutHelper.MATCH_PARENT;
|
||||
layoutParams.height = LayoutHelper.MATCH_PARENT;
|
||||
linearLayout.setLayoutParams(layoutParams);
|
||||
linearLayout.setGravity((LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.CENTER_VERTICAL);
|
||||
addView(linearLayout, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT));
|
||||
|
||||
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.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14);
|
||||
wrongNumber.setLineSpacing(AndroidUtilities.dp(2), 1.0f);
|
||||
wrongNumber.setPadding(0, AndroidUtilities.dp(24), 0, 0);
|
||||
linearLayout.addView(wrongNumber);
|
||||
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);
|
||||
linearLayout.addView(wrongNumber, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.BOTTOM | (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT), 0, 0, 0, 10));
|
||||
wrongNumber.setText(LocaleController.getString("WrongNumber", R.string.WrongNumber));
|
||||
wrongNumber.setOnClickListener(new OnClickListener() {
|
||||
@Override
|
||||
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();
|
||||
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
|
||||
public String getHeaderName() {
|
||||
return LocaleController.getString("YourCode", R.string.YourCode);
|
||||
|
@ -857,41 +1076,87 @@ public class ChangePhoneActivity extends BaseFragment {
|
|||
return;
|
||||
}
|
||||
codeField.setText("");
|
||||
AndroidUtilities.setWaitingForSms(true);
|
||||
NotificationCenter.getInstance().addObserver(this, NotificationCenter.didReceiveSmsCode);
|
||||
waitingForEvent = true;
|
||||
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;
|
||||
waitingForSms = true;
|
||||
String phone = params.getString("phone");
|
||||
phone = params.getString("phone");
|
||||
emailPhone = params.getString("ephone");
|
||||
requestPhone = params.getString("phoneFormated");
|
||||
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) {
|
||||
return;
|
||||
}
|
||||
|
||||
String number = PhoneFormat.getInstance().format(phone);
|
||||
String str = String.format(Locale.US, LocaleController.getString("SentSmsCode", R.string.SentSmsCode) + " %s", number);
|
||||
try {
|
||||
SpannableStringBuilder stringBuilder = new SpannableStringBuilder(str);
|
||||
TypefaceSpan span = new TypefaceSpan(AndroidUtilities.getTypeface("fonts/rmedium.ttf"));
|
||||
int idx = str.indexOf(number);
|
||||
stringBuilder.setSpan(span, idx, idx + number.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
|
||||
confirmTextView.setText(stringBuilder);
|
||||
} catch (Exception e) {
|
||||
FileLog.e("tmessages", e);
|
||||
confirmTextView.setText(str);
|
||||
CharSequence str = "";
|
||||
if (currentType == 1) {
|
||||
str = AndroidUtilities.replaceTags(LocaleController.getString("SentAppCode", R.string.SentAppCode));
|
||||
} else if (currentType == 2) {
|
||||
str = AndroidUtilities.replaceTags(LocaleController.formatString("SentSmsCode", R.string.SentSmsCode, number));
|
||||
} else if (currentType == 3) {
|
||||
str = AndroidUtilities.replaceTags(LocaleController.formatString("SentCallCode", R.string.SentCallCode, number));
|
||||
} else if (currentType == 4) {
|
||||
str = AndroidUtilities.replaceTags(LocaleController.formatString("SentCallOnly", R.string.SentCallOnly, number));
|
||||
}
|
||||
confirmTextView.setText(str);
|
||||
|
||||
AndroidUtilities.showKeyboard(codeField);
|
||||
codeField.requestFocus();
|
||||
if (currentType != 3) {
|
||||
AndroidUtilities.showKeyboard(codeField);
|
||||
codeField.requestFocus();
|
||||
} else {
|
||||
AndroidUtilities.hideKeyboard(codeField);
|
||||
}
|
||||
|
||||
destroyTimer();
|
||||
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() {
|
||||
|
@ -912,6 +1177,7 @@ public class ChangePhoneActivity extends BaseFragment {
|
|||
@Override
|
||||
public void run() {
|
||||
if (codeTime <= 1000) {
|
||||
problemText.setVisibility(VISIBLE);
|
||||
destroyCodeTimer();
|
||||
}
|
||||
}
|
||||
|
@ -922,7 +1188,7 @@ public class ChangePhoneActivity extends BaseFragment {
|
|||
|
||||
private void destroyCodeTimer() {
|
||||
try {
|
||||
synchronized(timerSync) {
|
||||
synchronized (timerSync) {
|
||||
if (codeTimer != null) {
|
||||
codeTimer.cancel();
|
||||
codeTimer = null;
|
||||
|
@ -941,7 +1207,10 @@ public class ChangePhoneActivity extends BaseFragment {
|
|||
timeTimer.schedule(new TimerTask() {
|
||||
@Override
|
||||
public void run() {
|
||||
double currentTime = System.currentTimeMillis();
|
||||
if (timeTimer == null) {
|
||||
return;
|
||||
}
|
||||
final double currentTime = System.currentTimeMillis();
|
||||
double diff = currentTime - lastCurrentTime;
|
||||
time -= diff;
|
||||
lastCurrentTime = currentTime;
|
||||
|
@ -951,27 +1220,45 @@ public class ChangePhoneActivity extends BaseFragment {
|
|||
if (time >= 1000) {
|
||||
int minutes = time / 1000 / 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 {
|
||||
timeText.setText(LocaleController.getString("Calling", R.string.Calling));
|
||||
if (progressView != null) {
|
||||
progressView.setProgress(1.0f);
|
||||
}
|
||||
destroyTimer();
|
||||
createCodeTimer();
|
||||
TLRPC.TL_auth_sendCall req = new TLRPC.TL_auth_sendCall();
|
||||
req.phone_number = requestPhone;
|
||||
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;
|
||||
}
|
||||
});
|
||||
if (currentType == 3) {
|
||||
AndroidUtilities.setWaitingForCall(false);
|
||||
NotificationCenter.getInstance().removeObserver(this, NotificationCenter.didReceiveCall);
|
||||
waitingForEvent = false;
|
||||
destroyCodeTimer();
|
||||
resendCode();
|
||||
} else {
|
||||
timeText.setText(LocaleController.getString("Calling", R.string.Calling));
|
||||
createCodeTimer();
|
||||
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(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() {
|
||||
try {
|
||||
synchronized(timerSync) {
|
||||
synchronized (timerSync) {
|
||||
if (timeTimer != null) {
|
||||
timeTimer.cancel();
|
||||
timeTimer = null;
|
||||
|
@ -998,9 +1285,14 @@ public class ChangePhoneActivity extends BaseFragment {
|
|||
return;
|
||||
}
|
||||
nextPressed = true;
|
||||
waitingForSms = false;
|
||||
AndroidUtilities.setWaitingForSms(false);
|
||||
NotificationCenter.getInstance().removeObserver(this, NotificationCenter.didReceiveSmsCode);
|
||||
if (currentType == 2) {
|
||||
AndroidUtilities.setWaitingForSms(false);
|
||||
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();
|
||||
req.phone_number = requestPhone;
|
||||
req.phone_code = codeField.getText().toString();
|
||||
|
@ -1028,17 +1320,29 @@ public class ChangePhoneActivity extends BaseFragment {
|
|||
finishFragment();
|
||||
} else {
|
||||
lastError = error.text;
|
||||
createTimer();
|
||||
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);
|
||||
if (currentType == 3 && (nextType == 4 || nextType == 2) || currentType == 2 && nextType == 4) {
|
||||
createTimer();
|
||||
}
|
||||
if (currentType == 2) {
|
||||
AndroidUtilities.setWaitingForSms(true);
|
||||
NotificationCenter.getInstance().addObserver(LoginActivitySmsView.this, NotificationCenter.didReceiveSmsCode);
|
||||
} else if (currentType == 3) {
|
||||
AndroidUtilities.setWaitingForCall(true);
|
||||
NotificationCenter.getInstance().addObserver(LoginActivitySmsView.this, NotificationCenter.didReceiveCall);
|
||||
}
|
||||
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();
|
||||
destroyCodeTimer();
|
||||
currentParams = null;
|
||||
AndroidUtilities.setWaitingForSms(false);
|
||||
NotificationCenter.getInstance().removeObserver(this, NotificationCenter.didReceiveSmsCode);
|
||||
waitingForSms = false;
|
||||
if (currentType == 2) {
|
||||
AndroidUtilities.setWaitingForSms(false);
|
||||
NotificationCenter.getInstance().removeObserver(this, NotificationCenter.didReceiveSmsCode);
|
||||
} else if (currentType == 3) {
|
||||
AndroidUtilities.setWaitingForCall(false);
|
||||
NotificationCenter.getInstance().removeObserver(this, NotificationCenter.didReceiveCall);
|
||||
}
|
||||
waitingForEvent = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroyActivity() {
|
||||
super.onDestroyActivity();
|
||||
AndroidUtilities.setWaitingForSms(false);
|
||||
NotificationCenter.getInstance().removeObserver(this, NotificationCenter.didReceiveSmsCode);
|
||||
if (currentType == 2) {
|
||||
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();
|
||||
destroyCodeTimer();
|
||||
waitingForSms = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -1078,15 +1392,26 @@ public class ChangePhoneActivity extends BaseFragment {
|
|||
|
||||
@Override
|
||||
public void didReceivedNotification(int id, final Object... args) {
|
||||
if (!waitingForEvent || codeField == null) {
|
||||
return;
|
||||
}
|
||||
if (id == NotificationCenter.didReceiveSmsCode) {
|
||||
if (!waitingForSms) {
|
||||
return;
|
||||
}
|
||||
if (codeField != null) {
|
||||
ignoreOnTextChange = true;
|
||||
codeField.setText("" + args[0]);
|
||||
onNextPressed();
|
||||
ignoreOnTextChange = true;
|
||||
codeField.setText("" + args[0]);
|
||||
ignoreOnTextChange = false;
|
||||
onNextPressed();
|
||||
} else if (id == NotificationCenter.didReceiveCall) {
|
||||
String num = "" + args[0];
|
||||
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.R;
|
||||
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.ui.ActionBar.ActionBar;
|
||||
import org.telegram.ui.ActionBar.ActionBarMenu;
|
||||
|
@ -63,25 +60,19 @@ public class ChannelEditActivity extends BaseFragment implements AvatarUpdater.A
|
|||
private View doneButton;
|
||||
private EditText nameTextView;
|
||||
private EditText descriptionTextView;
|
||||
private EditText userNameTextView;
|
||||
private BackupImageView avatarImage;
|
||||
private AvatarDrawable avatarDrawable;
|
||||
private AvatarUpdater avatarUpdater;
|
||||
private TextView checkTextView;
|
||||
private ProgressDialog progressDialog = null;
|
||||
private ProgressDialog progressDialog;
|
||||
private TextSettingsCell typeCell;
|
||||
private TextSettingsCell adminCell;
|
||||
|
||||
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.ChatFull info;
|
||||
private int chatId;
|
||||
private boolean allowComments = true;
|
||||
private TLRPC.InputFile uploadedAvatar;
|
||||
private boolean wasPrivate;
|
||||
private boolean privateAlertShown;
|
||||
private boolean signMessages;
|
||||
|
||||
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.delegate = this;
|
||||
allowComments = !currentChat.broadcast;
|
||||
signMessages = currentChat.signatures;
|
||||
NotificationCenter.getInstance().addObserver(this, NotificationCenter.chatInfoDidLoaded);
|
||||
NotificationCenter.getInstance().addObserver(this, NotificationCenter.updateInterfaces);
|
||||
return super.onFragmentCreate();
|
||||
}
|
||||
|
||||
public void setInfo(TLRPC.ChatFull chatFull) {
|
||||
info = chatFull;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFragmentDestroy() {
|
||||
super.onFragmentDestroy();
|
||||
if (avatarUpdater != null) {
|
||||
avatarUpdater.clear();
|
||||
}
|
||||
NotificationCenter.getInstance().removeObserver(this, NotificationCenter.chatInfoDidLoaded);
|
||||
NotificationCenter.getInstance().removeObserver(this, NotificationCenter.updateInterfaces);
|
||||
AndroidUtilities.removeAdjustResize(getParentActivity(), classGuid);
|
||||
}
|
||||
|
||||
|
@ -172,7 +162,6 @@ public class ChannelEditActivity extends BaseFragment implements AvatarUpdater.A
|
|||
if (donePressed) {
|
||||
return;
|
||||
}
|
||||
donePressed = true;
|
||||
if (nameTextView.length() == 0) {
|
||||
Vibrator v = (Vibrator) getParentActivity().getSystemService(Context.VIBRATOR_SERVICE);
|
||||
if (v != null) {
|
||||
|
@ -181,18 +170,7 @@ public class ChannelEditActivity extends BaseFragment implements AvatarUpdater.A
|
|||
AndroidUtilities.shakeView(nameTextView, 2, 0);
|
||||
return;
|
||||
}
|
||||
if (userNameTextView != null) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
donePressed = true;
|
||||
|
||||
if (avatarUpdater.uploadingAvatar != null) {
|
||||
createAfterUpload = true;
|
||||
|
@ -226,12 +204,6 @@ public class ChannelEditActivity extends BaseFragment implements AvatarUpdater.A
|
|||
if (info != null && !info.about.equals(descriptionTextView.getText().toString())) {
|
||||
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) {
|
||||
currentChat.signatures = true;
|
||||
MessagesController.getInstance().toogleChannelSignatures(chatId, signMessages);
|
||||
|
@ -346,8 +318,9 @@ public class ChannelEditActivity extends BaseFragment implements AvatarUpdater.A
|
|||
}
|
||||
});
|
||||
|
||||
ShadowSectionCell sectionCell = new ShadowSectionCell(context);
|
||||
linearLayout.addView(sectionCell, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT));
|
||||
View lineView = new View(context);
|
||||
lineView.setBackgroundColor(0xffcfcfcf);
|
||||
linearLayout.addView(lineView, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 1));
|
||||
|
||||
linearLayout2 = new LinearLayout(context);
|
||||
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));
|
||||
|
||||
descriptionTextView = new EditText(context);
|
||||
descriptionTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 18);
|
||||
descriptionTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16);
|
||||
descriptionTextView.setHintTextColor(0xff979797);
|
||||
descriptionTextView.setTextColor(0xff212121);
|
||||
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.setImeOptions(EditorInfo.IME_ACTION_DONE);
|
||||
inputFilters = new InputFilter[1];
|
||||
inputFilters[0] = new InputFilter.LengthFilter(120);
|
||||
inputFilters[0] = new InputFilter.LengthFilter(255);
|
||||
descriptionTextView.setFilters(inputFilters);
|
||||
descriptionTextView.setHint(LocaleController.getString("DescriptionPlaceholder", R.string.DescriptionPlaceholder));
|
||||
descriptionTextView.setHint(LocaleController.getString("DescriptionOptionalPlaceholder", R.string.DescriptionOptionalPlaceholder));
|
||||
AndroidUtilities.clearCursorDrawable(descriptionTextView);
|
||||
linearLayout2.addView(descriptionTextView, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, 17, 12, 17, 6));
|
||||
descriptionTextView.setOnEditorActionListener(new TextView.OnEditorActionListener() {
|
||||
|
@ -396,148 +369,68 @@ public class ChannelEditActivity extends BaseFragment implements AvatarUpdater.A
|
|||
}
|
||||
});
|
||||
|
||||
TextInfoPrivacyCell infoCell = new TextInfoPrivacyCell(context);
|
||||
if (currentChat.megagroup) {
|
||||
infoCell.setText(LocaleController.getString("DescriptionInfoMega", R.string.DescriptionInfoMega));
|
||||
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));
|
||||
ShadowSectionCell sectionCell = new ShadowSectionCell(context);
|
||||
sectionCell.setSize(20);
|
||||
linearLayout.addView(sectionCell, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT));
|
||||
|
||||
if (/*BuildVars.DEBUG_VERSION && currentChat.megagroup && currentChat.creator || */!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) {
|
||||
if (currentChat.megagroup || !currentChat.megagroup) {
|
||||
frameLayout = new FrameLayoutFixed(context);
|
||||
frameLayout.setBackgroundColor(0xffffffff);
|
||||
linearLayout.addView(frameLayout, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT));
|
||||
|
||||
TextCheckCell textCell = new TextCheckCell(context);
|
||||
textCell.setBackgroundResource(R.drawable.list_selector);
|
||||
textCell.setTextAndCheck(LocaleController.getString("ChannelSignMessages", R.string.ChannelSignMessages), signMessages, false);
|
||||
frameLayout.addView(textCell, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT));
|
||||
textCell.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
signMessages = !signMessages;
|
||||
((TextCheckCell) v).setChecked(signMessages);
|
||||
}
|
||||
});
|
||||
typeCell = new TextSettingsCell(context);
|
||||
updateTypeCell();
|
||||
typeCell.setBackgroundResource(R.drawable.list_selector);
|
||||
frameLayout.addView(typeCell, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT));
|
||||
//TODO
|
||||
|
||||
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));
|
||||
lineView = new View(context);
|
||||
lineView.setBackgroundColor(0xffcfcfcf);
|
||||
linearLayout.addView(lineView, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 1));
|
||||
|
||||
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) {
|
||||
|
@ -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);
|
||||
if (currentChat.megagroup) {
|
||||
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));
|
||||
}
|
||||
|
||||
/*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.setSelection(nameTextView.length());
|
||||
if (info != null) {
|
||||
|
@ -616,6 +530,13 @@ public class ChannelEditActivity extends BaseFragment implements AvatarUpdater.A
|
|||
descriptionTextView.setText(chatFull.about);
|
||||
}
|
||||
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) {
|
||||
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("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;
|
||||
public void setInfo(TLRPC.ChatFull chatFull) {
|
||||
info = chatFull;
|
||||
}
|
||||
|
||||
private void showErrorAlert(String error) {
|
||||
if (getParentActivity() == null) {
|
||||
private void updateTypeCell() {
|
||||
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;
|
||||
}
|
||||
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;
|
||||
if (info != null) {
|
||||
adminCell.setTextAndValue(LocaleController.getString("ChannelAdministrators", R.string.ChannelAdministrators), String.format("%d", info.admins_count), false);
|
||||
} else {
|
||||
adminCell.setText(LocaleController.getString("ChannelAdministrators", R.string.ChannelAdministrators), false);
|
||||
}
|
||||
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);
|
||||
if (viewType == 0) {
|
||||
if (view == null) {
|
||||
view = new UserCell(mContext, 1, 0);
|
||||
view = new UserCell(mContext, 1, 0, false);
|
||||
view.setBackgroundColor(0xffffffff);
|
||||
}
|
||||
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.DialogInterface;
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.Bundle;
|
||||
|
||||
import org.telegram.messenger.AndroidUtilities;
|
||||
import org.telegram.messenger.LocaleController;
|
||||
|
@ -22,10 +23,14 @@ import org.telegram.messenger.MessagesStorage;
|
|||
import org.telegram.messenger.NotificationsController;
|
||||
import org.telegram.messenger.ApplicationLoader;
|
||||
import org.telegram.messenger.R;
|
||||
import org.telegram.messenger.Utilities;
|
||||
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.BaseFragment;
|
||||
import org.telegram.ui.ActionBar.BottomSheet;
|
||||
import org.telegram.ui.ReportOtherActivity;
|
||||
|
||||
public class AlertsCreator {
|
||||
|
||||
|
@ -82,6 +87,68 @@ public class AlertsCreator {
|
|||
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) {
|
||||
if (error == null || fragment == null || fragment.getParentActivity() == null) {
|
||||
return;
|
||||
|
|
|
@ -11,7 +11,9 @@ package org.telegram.ui.Components;
|
|||
import android.Manifest;
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.Activity;
|
||||
import android.app.AlertDialog;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.graphics.Canvas;
|
||||
|
@ -482,8 +484,13 @@ public class ChatActivityEnterView extends FrameLayoutFixed implements Notificat
|
|||
emojiButton = new ImageView(context);
|
||||
emojiButton.setImageResource(R.drawable.ic_msg_panel_smiles);
|
||||
emojiButton.setScaleType(ImageView.ScaleType.CENTER_INSIDE);
|
||||
emojiButton.setPadding(AndroidUtilities.dp(4), AndroidUtilities.dp(1), 0, 0);
|
||||
frameLayout.addView(emojiButton, LayoutHelper.createFrame(48, 48, Gravity.BOTTOM));
|
||||
emojiButton.setPadding(0, AndroidUtilities.dp(1), 0, 0);
|
||||
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() {
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
|
@ -583,7 +590,7 @@ public class ChatActivityEnterView extends FrameLayoutFixed implements Notificat
|
|||
if (innerTextChange != 2 && before != count && (count - before) > 1) {
|
||||
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();
|
||||
TLRPC.User currentUser = null;
|
||||
if ((int) dialog_id > 0) {
|
||||
|
@ -633,7 +640,12 @@ public class ChatActivityEnterView extends FrameLayoutFixed implements Notificat
|
|||
botButton.setImageResource(R.drawable.bot_keyboard2);
|
||||
botButton.setScaleType(ImageView.ScaleType.CENTER);
|
||||
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() {
|
||||
@Override
|
||||
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.setScaleType(ImageView.ScaleType.CENTER);
|
||||
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() {
|
||||
@Override
|
||||
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.setScaleType(ImageView.ScaleType.CENTER);
|
||||
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() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
|
@ -689,6 +711,7 @@ public class ChatActivityEnterView extends FrameLayoutFixed implements Notificat
|
|||
} else {
|
||||
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) {
|
||||
if (motionEvent.getAction() == MotionEvent.ACTION_DOWN) {
|
||||
if (parentFragment != null) {
|
||||
if (Build.VERSION.SDK_INT >= 23) {
|
||||
if (parentActivity.checkSelfPermission(Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED) {
|
||||
parentActivity.requestPermissions(new String[]{Manifest.permission.RECORD_AUDIO}, 3);
|
||||
return false;
|
||||
}
|
||||
if (Build.VERSION.SDK_INT >= 23 && parentActivity.checkSelfPermission(Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED) {
|
||||
parentActivity.requestPermissions(new String[]{Manifest.permission.RECORD_AUDIO}, 3);
|
||||
return false;
|
||||
}
|
||||
|
||||
String action;
|
||||
|
@ -1171,7 +1192,15 @@ public class ChatActivityEnterView extends FrameLayoutFixed implements Notificat
|
|||
if (editingMessageObject != null) {
|
||||
messageEditText.setHint(editingCaption ? LocaleController.getString("Caption", R.string.Caption) : LocaleController.getString("TypeMessage", R.string.TypeMessage));
|
||||
} 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 {
|
||||
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.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() {
|
||||
|
@ -1920,7 +1954,10 @@ public class ChatActivityEnterView extends FrameLayoutFixed implements Notificat
|
|||
|
||||
@Override
|
||||
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) {
|
||||
delegate.onMessageSend(null);
|
||||
}
|
||||
|
@ -1944,6 +1981,24 @@ public class ChatActivityEnterView extends FrameLayoutFixed implements Notificat
|
|||
public void onStickersTab(boolean 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);
|
||||
sizeNotifierLayout.addView(emojiView);
|
||||
|
@ -2066,6 +2121,10 @@ public class ChatActivityEnterView extends FrameLayoutFixed implements Notificat
|
|||
return editingCaption;
|
||||
}
|
||||
|
||||
public boolean hasAudioToSend() {
|
||||
return audioToSendMessageObject != null;
|
||||
}
|
||||
|
||||
public void openKeyboard() {
|
||||
AndroidUtilities.showKeyboard(messageEditText);
|
||||
}
|
||||
|
|
|
@ -48,6 +48,7 @@ import org.telegram.messenger.LocaleController;
|
|||
import org.telegram.messenger.MediaController;
|
||||
import org.telegram.messenger.MessagesStorage;
|
||||
import org.telegram.messenger.NotificationCenter;
|
||||
import org.telegram.messenger.Utilities;
|
||||
import org.telegram.messenger.query.StickersQuery;
|
||||
import org.telegram.messenger.FileLog;
|
||||
import org.telegram.messenger.R;
|
||||
|
@ -77,6 +78,7 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific
|
|||
void onGifSelected(TLRPC.Document gif);
|
||||
void onGifTab(boolean opened);
|
||||
void onStickersTab(boolean opened);
|
||||
void onClearEmojiRecent();
|
||||
}
|
||||
|
||||
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);
|
||||
view.getParent().requestDisallowInterceptTouchEvent(true);
|
||||
return true;
|
||||
} else if (pager.getCurrentItem() == 0) {
|
||||
listener.onClearEmojiRecent();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -519,7 +523,6 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific
|
|||
private GifsAdapter gifsAdapter;
|
||||
private AdapterView.OnItemClickListener stickersOnItemClickListener;
|
||||
|
||||
|
||||
private EmojiColorPickerView pickerView;
|
||||
private EmojiPopupWindow pickerViewPopup;
|
||||
private int popupWidth;
|
||||
|
@ -531,8 +534,6 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific
|
|||
private int gifTabBum = -2;
|
||||
private boolean switchToGifTab;
|
||||
|
||||
|
||||
|
||||
private int oldWidth;
|
||||
private int lastNotifyWidth;
|
||||
|
||||
|
@ -667,7 +668,7 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific
|
|||
return;
|
||||
}
|
||||
TLRPC.Document document = recentImages.get(position).document;
|
||||
listener.onStickerSelected(document);
|
||||
listener.onGifSelected(document);
|
||||
}
|
||||
});
|
||||
gifsGridView.setOnItemLongClickListener(new RecyclerListView.OnItemLongClickListener() {
|
||||
|
@ -966,6 +967,15 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific
|
|||
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() {
|
||||
gifsGridView.setVisibility(VISIBLE);
|
||||
stickersGridView.setVisibility(GONE);
|
||||
|
@ -1268,7 +1278,7 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific
|
|||
String[] args = str.split(",");
|
||||
for (String arg : args) {
|
||||
String[] args2 = arg.split("=");
|
||||
long value = Long.parseLong(args2[0]);
|
||||
long value = Utilities.parseLong(args2[0]);
|
||||
String string = "";
|
||||
for (int a = 0; a < 4; a++) {
|
||||
char ch = (char) value;
|
||||
|
@ -1279,7 +1289,7 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific
|
|||
}
|
||||
}
|
||||
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(",");
|
||||
for (String arg : args) {
|
||||
String[] args2 = arg.split("=");
|
||||
emojiUseHistory.put(args2[0], Integer.parseInt(args2[1]));
|
||||
emojiUseHistory.put(args2[0], Utilities.parseInt(args2[1]));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (emojiUseHistory.isEmpty()) {
|
||||
String[] newRecent = new String[]{
|
||||
"\uD83D\uDE02", "\uD83D\uDE18", "\u2764", "\uD83D\uDE0D", "\uD83D\uDE0A", "\uD83D\uDE01",
|
||||
"\uD83D\uDC4D", "\u263A", "\uD83D\uDE14", "\uD83D\uDE04", "\uD83D\uDE2D", "\uD83D\uDC8B",
|
||||
"\uD83D\uDE12", "\uD83D\uDE33", "\uD83D\uDE1C", "\uD83D\uDE48", "\uD83D\uDE09", "\uD83D\uDE03",
|
||||
"\uD83D\uDE22", "\uD83D\uDE1D", "\uD83D\uDE31", "\uD83D\uDE21", "\uD83D\uDE0F", "\uD83D\uDE1E",
|
||||
"\uD83D\uDE05", "\uD83D\uDE1A", "\uD83D\uDE4A", "\uD83D\uDE0C", "\uD83D\uDE00", "\uD83D\uDE0B",
|
||||
"\uD83D\uDE06", "\uD83D\uDC4C", "\uD83D\uDE10", "\uD83D\uDE15"};
|
||||
for (int i = 0; i < newRecent.length; i++) {
|
||||
emojiUseHistory.put(newRecent[i], newRecent.length - i);
|
||||
if (!preferences.getBoolean("filled_default", false)) {
|
||||
String[] newRecent = new String[]{
|
||||
"\uD83D\uDE02", "\uD83D\uDE18", "\u2764", "\uD83D\uDE0D", "\uD83D\uDE0A", "\uD83D\uDE01",
|
||||
"\uD83D\uDC4D", "\u263A", "\uD83D\uDE14", "\uD83D\uDE04", "\uD83D\uDE2D", "\uD83D\uDC8B",
|
||||
"\uD83D\uDE12", "\uD83D\uDE33", "\uD83D\uDE1C", "\uD83D\uDE48", "\uD83D\uDE09", "\uD83D\uDE03",
|
||||
"\uD83D\uDE22", "\uD83D\uDE1D", "\uD83D\uDE31", "\uD83D\uDE21", "\uD83D\uDE0F", "\uD83D\uDE1E",
|
||||
"\uD83D\uDE05", "\uD83D\uDE1A", "\uD83D\uDE4A", "\uD83D\uDE0C", "\uD83D\uDE00", "\uD83D\uDE0B",
|
||||
"\uD83D\uDE06", "\uD83D\uDC4C", "\uD83D\uDE10", "\uD83D\uDE15"};
|
||||
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();
|
||||
adapters.get(0).notifyDataSetChanged();
|
||||
|
@ -1338,8 +1351,8 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific
|
|||
for (int a = 0; a < args.length; a++) {
|
||||
String arg = args[a];
|
||||
String[] args2 = arg.split("=");
|
||||
Long key = Long.parseLong(args2[0]);
|
||||
stickersUseHistory.put(key, Integer.parseInt(args2[1]));
|
||||
Long key = Utilities.parseLong(args2[0]);
|
||||
stickersUseHistory.put(key, Utilities.parseInt(args2[1]));
|
||||
newRecentStickers.add(key);
|
||||
}
|
||||
Collections.sort(newRecentStickers, new Comparator<Long>() {
|
||||
|
@ -1367,7 +1380,13 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific
|
|||
str = preferences.getString("stickers2", "");
|
||||
String[] args = str.split(",");
|
||||
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();
|
||||
|
|
|
@ -14,6 +14,7 @@ import android.util.AttributeSet;
|
|||
import android.view.View;
|
||||
import android.widget.FrameLayout;
|
||||
|
||||
import org.telegram.messenger.AndroidUtilities;
|
||||
import org.telegram.messenger.FileLog;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
@ -155,6 +156,7 @@ public class FrameLayoutFixed extends FrameLayout {
|
|||
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
|
||||
} catch (Exception 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 {
|
||||
void needMoveImageTo(float x, float y, float s, boolean animated);
|
||||
Bitmap getBitmap();
|
||||
}
|
||||
|
||||
private boolean freeformCrop = true;
|
||||
|
@ -38,11 +39,11 @@ public class PhotoCropView extends FrameLayout {
|
|||
private float oldX = 0, oldY = 0;
|
||||
private int bitmapWidth = 1, bitmapHeight = 1, bitmapX, bitmapY;
|
||||
private float rectX = -1, rectY = -1;
|
||||
private Bitmap bitmapToEdit;
|
||||
private float bitmapGlobalScale = 1;
|
||||
private float bitmapGlobalX = 0;
|
||||
private float bitmapGlobalY = 0;
|
||||
private PhotoCropViewDelegate delegate;
|
||||
private Bitmap bitmapToEdit;
|
||||
|
||||
private RectF animationStartValues;
|
||||
private RectF animationEndValues;
|
||||
|
@ -472,6 +473,11 @@ public class PhotoCropView extends FrameLayout {
|
|||
}
|
||||
|
||||
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);
|
||||
Canvas canvas = new Canvas(bitmap);
|
||||
Paint paint = new Paint(Paint.FILTER_BITMAP_FLAG | Paint.DITHER_FLAG);
|
||||
|
@ -495,6 +501,11 @@ public class PhotoCropView extends FrameLayout {
|
|||
}
|
||||
|
||||
public Bitmap getBitmap() {
|
||||
Bitmap newBimap = delegate.getBitmap();
|
||||
if (newBimap != null) {
|
||||
bitmapToEdit = newBimap;
|
||||
}
|
||||
|
||||
float bitmapScaledWidth = bitmapWidth * bitmapGlobalScale;
|
||||
float bitmapScaledHeight = bitmapHeight * bitmapGlobalScale;
|
||||
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) {
|
||||
super.onLayout(changed, left, top, right, bottom);
|
||||
|
||||
Bitmap newBimap = delegate.getBitmap();
|
||||
if (newBimap != null) {
|
||||
bitmapToEdit = newBimap;
|
||||
}
|
||||
|
||||
if (bitmapToEdit == null) {
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -2006,7 +2006,9 @@ public class PhotoFilterView extends FrameLayout {
|
|||
eglThread.postRunnable(new Runnable() {
|
||||
@Override
|
||||
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) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClearEmojiRecent() {
|
||||
|
||||
}
|
||||
});
|
||||
sizeNotifierLayout.addView(emojiView);
|
||||
}
|
||||
|
|
|
@ -84,6 +84,7 @@ public class SimpleTextView extends View {
|
|||
} else {
|
||||
offsetX = 0;
|
||||
}
|
||||
offsetX += getPaddingLeft();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
//ignore
|
||||
|
@ -94,7 +95,7 @@ public class SimpleTextView extends View {
|
|||
@Override
|
||||
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
|
||||
if (changed) {
|
||||
createLayout(right - left);
|
||||
createLayout(right - left - getPaddingLeft() - getPaddingRight());
|
||||
invalidate();
|
||||
wasLayout = true;
|
||||
}
|
||||
|
@ -103,7 +104,7 @@ public class SimpleTextView extends View {
|
|||
public void setText(CharSequence value) {
|
||||
text = value;
|
||||
if (wasLayout) {
|
||||
createLayout(getMeasuredWidth());
|
||||
createLayout(getMeasuredWidth() - getPaddingLeft() - getPaddingRight());
|
||||
invalidate();
|
||||
} else {
|
||||
requestLayout();
|
||||
|
|
|
@ -391,6 +391,7 @@ public class Switch extends CompoundButton {
|
|||
protected void onAttachedToWindow() {
|
||||
super.onAttachedToWindow();
|
||||
attachedToWindow = true;
|
||||
requestLayout();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -40,6 +40,7 @@ import org.telegram.messenger.ApplicationLoader;
|
|||
import org.telegram.messenger.LocaleController;
|
||||
import org.telegram.messenger.MessagesStorage;
|
||||
import org.telegram.messenger.SecretChatHelper;
|
||||
import org.telegram.messenger.UserConfig;
|
||||
import org.telegram.messenger.UserObject;
|
||||
import org.telegram.tgnet.TLRPC;
|
||||
import org.telegram.messenger.ContactsController;
|
||||
|
@ -289,12 +290,17 @@ public class ContactsActivity extends BaseFragment implements NotificationCenter
|
|||
didSelectResult(user, true, null);
|
||||
} else {
|
||||
if (createSecretChat) {
|
||||
if (user.id == UserConfig.getClientUserId()) {
|
||||
return;
|
||||
}
|
||||
creatingChat = true;
|
||||
SecretChatHelper.getInstance().startSecretChat(getParentActivity(), user);
|
||||
} else {
|
||||
Bundle args = new Bundle();
|
||||
args.putInt("user_id", user.id);
|
||||
presentFragment(new ChatActivity(args), true);
|
||||
if (MessagesController.checkCanOpenChat(args, ContactsActivity.this)) {
|
||||
presentFragment(new ChatActivity(args), true);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
@ -330,6 +336,7 @@ public class ContactsActivity extends BaseFragment implements NotificationCenter
|
|||
args.putBoolean("onlyUsers", true);
|
||||
args.putBoolean("destroyAfterSelect", true);
|
||||
args.putBoolean("createSecretChat", true);
|
||||
args.putBoolean("allowBots", false);
|
||||
presentFragment(new ContactsActivity(args), false);
|
||||
} else if (row == 2) {
|
||||
if (!MessagesController.isFeatureEnabled("broadcast_create", ContactsActivity.this)) {
|
||||
|
@ -363,7 +370,9 @@ public class ContactsActivity extends BaseFragment implements NotificationCenter
|
|||
} else {
|
||||
Bundle args = new Bundle();
|
||||
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) {
|
||||
|
|
|
@ -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.didSetPasscode);
|
||||
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.didSetPasscode);
|
||||
NotificationCenter.getInstance().removeObserver(this, NotificationCenter.needReloadRecentDialogsSearch);
|
||||
NotificationCenter.getInstance().removeObserver(this, NotificationCenter.didLoadedReplyMessages);
|
||||
}
|
||||
delegate = null;
|
||||
}
|
||||
|
@ -429,10 +431,14 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter.
|
|||
}
|
||||
}
|
||||
if (searchString != null) {
|
||||
NotificationCenter.getInstance().postNotificationName(NotificationCenter.closeChats);
|
||||
presentFragment(new ChatActivity(args));
|
||||
if (MessagesController.checkCanOpenChat(args, DialogsActivity.this)) {
|
||||
NotificationCenter.getInstance().postNotificationName(NotificationCenter.closeChats);
|
||||
presentFragment(new ChatActivity(args));
|
||||
}
|
||||
} 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) {
|
||||
if (listView != null) {
|
||||
updateVisibleRows(0);
|
||||
}
|
||||
updateVisibleRows(0);
|
||||
} else if (id == NotificationCenter.updateInterfaces) {
|
||||
updateVisibleRows((Integer) args[0]);
|
||||
} else if (id == NotificationCenter.appDidLogout) {
|
||||
|
@ -933,6 +937,8 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter.
|
|||
if (dialogsSearchAdapter != null) {
|
||||
dialogsSearchAdapter.loadRecentSearch();
|
||||
}
|
||||
} else if (id == NotificationCenter.didLoadedReplyMessages) {
|
||||
updateVisibleRows(0);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -78,7 +78,7 @@ public class GroupCreateActivity extends BaseFragment implements NotificationCen
|
|||
private int beforeChangeIndex;
|
||||
private boolean ignoreChange;
|
||||
private CharSequence changeString;
|
||||
private int maxCount = 1000;
|
||||
private int maxCount = 5000;
|
||||
private int chatType = ChatObject.CHAT_TYPE_CHAT;
|
||||
private boolean isAlwaysShare;
|
||||
private boolean isNeverShare;
|
||||
|
|
|
@ -450,7 +450,7 @@ public class GroupCreateFinalActivity extends BaseFragment implements Notificati
|
|||
@Override
|
||||
public View getView(int i, View view, ViewGroup viewGroup) {
|
||||
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));
|
||||
|
|
|
@ -127,7 +127,7 @@ public class LaunchActivity extends Activity implements ActionBarLayout.ActionBa
|
|||
return;
|
||||
}
|
||||
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();
|
||||
if (state.isEmpty()) {
|
||||
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("destroyAfterSelect", true);
|
||||
args.putBoolean("createSecretChat", true);
|
||||
args.putBoolean("allowBots", false);
|
||||
presentFragment(new ContactsActivity(args));
|
||||
drawerLayoutContainer.closeDrawer(false);
|
||||
} else if (position == 4) {
|
||||
|
@ -768,7 +769,7 @@ public class LaunchActivity extends Activity implements ActionBarLayout.ActionBa
|
|||
if (scheme != null) {
|
||||
if ((scheme.equals("http") || scheme.equals("https"))) {
|
||||
String host = data.getHost().toLowerCase();
|
||||
if (host.equals("telegram.me")) {
|
||||
if (host.equals("telegram.me") || host.equals("telegram.dog")) {
|
||||
String path = data.getPath();
|
||||
if (path != null && path.length() > 1) {
|
||||
path = path.substring(1);
|
||||
|
@ -882,16 +883,20 @@ public class LaunchActivity extends Activity implements ActionBarLayout.ActionBa
|
|||
if (push_user_id != 0) {
|
||||
Bundle args = new Bundle();
|
||||
args.putInt("user_id", push_user_id);
|
||||
ChatActivity fragment = new ChatActivity(args);
|
||||
if (actionBarLayout.presentFragment(fragment, false, true, true)) {
|
||||
pushOpened = true;
|
||||
if (mainFragmentsStack.isEmpty() || MessagesController.checkCanOpenChat(args, mainFragmentsStack.get(mainFragmentsStack.size() - 1))) {
|
||||
ChatActivity fragment = new ChatActivity(args);
|
||||
if (actionBarLayout.presentFragment(fragment, false, true, true)) {
|
||||
pushOpened = true;
|
||||
}
|
||||
}
|
||||
} else if (push_chat_id != 0) {
|
||||
Bundle args = new Bundle();
|
||||
args.putInt("chat_id", push_chat_id);
|
||||
ChatActivity fragment = new ChatActivity(args);
|
||||
if (actionBarLayout.presentFragment(fragment, false, true, true)) {
|
||||
pushOpened = true;
|
||||
if (mainFragmentsStack.isEmpty() || MessagesController.checkCanOpenChat(args, mainFragmentsStack.get(mainFragmentsStack.size() - 1))) {
|
||||
ChatActivity fragment = new ChatActivity(args);
|
||||
if (actionBarLayout.presentFragment(fragment, false, true, true)) {
|
||||
pushOpened = true;
|
||||
}
|
||||
}
|
||||
} else if (push_enc_id != 0) {
|
||||
Bundle args = new Bundle();
|
||||
|
@ -1071,12 +1076,14 @@ public class LaunchActivity extends Activity implements ActionBarLayout.ActionBa
|
|||
fragment.setDelegate(new DialogsActivity.MessagesActivityDelegate() {
|
||||
@Override
|
||||
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();
|
||||
args.putBoolean("scrollToTopOnResume", true);
|
||||
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);
|
||||
|
@ -1093,9 +1100,11 @@ public class LaunchActivity extends Activity implements ActionBarLayout.ActionBa
|
|||
if (messageId != null) {
|
||||
args.putInt("message_id", messageId);
|
||||
}
|
||||
ChatActivity fragment = new ChatActivity(args);
|
||||
NotificationCenter.getInstance().postNotificationName(NotificationCenter.closeChats);
|
||||
actionBarLayout.presentFragment(fragment, false, true, true);
|
||||
if (mainFragmentsStack.isEmpty() || MessagesController.checkCanOpenChat(args, mainFragmentsStack.get(mainFragmentsStack.size() - 1))) {
|
||||
ChatActivity fragment = new ChatActivity(args);
|
||||
NotificationCenter.getInstance().postNotificationName(NotificationCenter.closeChats);
|
||||
actionBarLayout.presentFragment(fragment, false, true, true);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
|
@ -1134,9 +1143,11 @@ public class LaunchActivity extends Activity implements ActionBarLayout.ActionBa
|
|||
MessagesStorage.getInstance().putUsersAndChats(null, chats, false, true);
|
||||
Bundle args = new Bundle();
|
||||
args.putInt("chat_id", invite.chat.id);
|
||||
ChatActivity fragment = new ChatActivity(args);
|
||||
NotificationCenter.getInstance().postNotificationName(NotificationCenter.closeChats);
|
||||
actionBarLayout.presentFragment(fragment, false, true, true);
|
||||
if (mainFragmentsStack.isEmpty() || MessagesController.checkCanOpenChat(args, mainFragmentsStack.get(mainFragmentsStack.size() - 1))) {
|
||||
ChatActivity fragment = new ChatActivity(args);
|
||||
NotificationCenter.getInstance().postNotificationName(NotificationCenter.closeChats);
|
||||
actionBarLayout.presentFragment(fragment, false, true, true);
|
||||
}
|
||||
} else {
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(LaunchActivity.this);
|
||||
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);
|
||||
Bundle args = new Bundle();
|
||||
args.putInt("chat_id", chat.id);
|
||||
ChatActivity fragment = new ChatActivity(args);
|
||||
NotificationCenter.getInstance().postNotificationName(NotificationCenter.closeChats);
|
||||
actionBarLayout.presentFragment(fragment, false, true, true);
|
||||
if (mainFragmentsStack.isEmpty() || MessagesController.checkCanOpenChat(args, mainFragmentsStack.get(mainFragmentsStack.size() - 1))) {
|
||||
ChatActivity fragment = new ChatActivity(args);
|
||||
NotificationCenter.getInstance().postNotificationName(NotificationCenter.closeChats);
|
||||
actionBarLayout.presentFragment(fragment, false, true, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
@ -1238,11 +1251,6 @@ public class LaunchActivity extends Activity implements ActionBarLayout.ActionBa
|
|||
fragment.setDelegate(new DialogsActivity.MessagesActivityDelegate() {
|
||||
@Override
|
||||
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();
|
||||
args.putBoolean("scrollToTopOnResume", true);
|
||||
args.putBoolean("hasUrl", hasUrl);
|
||||
|
@ -1261,7 +1269,14 @@ public class LaunchActivity extends Activity implements ActionBarLayout.ActionBa
|
|||
} else {
|
||||
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);
|
||||
|
@ -1339,6 +1354,9 @@ public class LaunchActivity extends Activity implements ActionBarLayout.ActionBa
|
|||
} else {
|
||||
args.putInt("enc_id", high_id);
|
||||
}
|
||||
if (!MessagesController.checkCanOpenChat(args, dialogsFragment)) {
|
||||
return;
|
||||
}
|
||||
ChatActivity fragment = new ChatActivity(args);
|
||||
|
||||
if (videoPath != null) {
|
||||
|
@ -1495,7 +1513,12 @@ public class LaunchActivity extends Activity implements ActionBarLayout.ActionBa
|
|||
actionBarLayout.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
|
||||
@Override
|
||||
public void onGlobalLayout() {
|
||||
needLayout();
|
||||
AndroidUtilities.runOnUIThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
needLayout();
|
||||
}
|
||||
});
|
||||
if (actionBarLayout != null) {
|
||||
if (Build.VERSION.SDK_INT < 16) {
|
||||
actionBarLayout.getViewTreeObserver().removeGlobalOnLayoutListener(this);
|
||||
|
|
|
@ -929,7 +929,11 @@ public class LocationActivity extends BaseFragment implements NotificationCenter
|
|||
super.onResume();
|
||||
AndroidUtilities.removeAdjustResize(getParentActivity(), classGuid);
|
||||
if (mapView != null) {
|
||||
mapView.onResume();
|
||||
try {
|
||||
mapView.onResume();
|
||||
} catch (Throwable e) {
|
||||
FileLog.e("tmessages", e);
|
||||
}
|
||||
}
|
||||
updateUserData();
|
||||
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) {
|
||||
args.putInt("chat_id", -lower_part);
|
||||
}
|
||||
if (!MessagesController.checkCanOpenChat(args, fragment)) {
|
||||
return;
|
||||
}
|
||||
|
||||
ArrayList<MessageObject> fmessages = new ArrayList<>();
|
||||
for (int a = 1; a >= 0; a--) {
|
||||
|
@ -364,6 +367,7 @@ public class MediaActivity extends BaseFragment implements NotificationCenter.No
|
|||
actionBar.hideActionMode();
|
||||
|
||||
NotificationCenter.getInstance().postNotificationName(NotificationCenter.closeChats);
|
||||
|
||||
ChatActivity chatActivity = new ChatActivity(args);
|
||||
presentFragment(chatActivity, true);
|
||||
chatActivity.showReplyPanel(true, null, fmessages, null, false, false);
|
||||
|
@ -901,7 +905,11 @@ public class MediaActivity extends BaseFragment implements NotificationCenter.No
|
|||
listView.setAdapter(photoVideoAdapter);
|
||||
dropDown.setText(LocaleController.getString("SharedMediaTitle", R.string.SharedMediaTitle));
|
||||
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);
|
||||
if (sharedMediaData[selectedMode].loading && sharedMediaData[selectedMode].messages.isEmpty()) {
|
||||
progressView.setVisibility(View.VISIBLE);
|
||||
|
@ -918,12 +926,20 @@ public class MediaActivity extends BaseFragment implements NotificationCenter.No
|
|||
listView.setAdapter(documentsAdapter);
|
||||
dropDown.setText(LocaleController.getString("DocumentsTitle", R.string.DocumentsTitle));
|
||||
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) {
|
||||
listView.setAdapter(audioAdapter);
|
||||
dropDown.setText(LocaleController.getString("AudioTitle", R.string.AudioTitle));
|
||||
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);
|
||||
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);
|
||||
dropDown.setText(LocaleController.getString("LinksTitle", R.string.LinksTitle));
|
||||
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);
|
||||
if (!sharedMediaData[selectedMode].loading && !sharedMediaData[selectedMode].endReached[0] && sharedMediaData[selectedMode].messages.isEmpty()) {
|
||||
sharedMediaData[selectedMode].loading = true;
|
||||
|
|
|
@ -15,7 +15,6 @@ import android.graphics.Paint;
|
|||
import android.graphics.drawable.BitmapDrawable;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.widget.FrameLayout;
|
||||
|
@ -58,16 +57,6 @@ public class PhotoCropActivity extends BaseFragment {
|
|||
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() {
|
||||
rectPaint = new Paint();
|
||||
rectPaint.setColor(0x3ffafafa);
|
||||
|
|
|
@ -914,6 +914,9 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat
|
|||
};
|
||||
windowView.setBackgroundDrawable(backgroundDrawable);
|
||||
windowView.setFocusable(false);
|
||||
if (Build.VERSION.SDK_INT >= 23) {
|
||||
windowView.setFitsSystemWindows(true); //TODO ?
|
||||
}
|
||||
|
||||
animatingImageView = new ClippingImageView(activity);
|
||||
animatingImageView.setAnimationValues(animationValues);
|
||||
|
@ -1206,10 +1209,10 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat
|
|||
|
||||
if (currentMessageObject != null) {
|
||||
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);
|
||||
return;
|
||||
}
|
||||
}*/
|
||||
f = FileLoader.getPathToMessage(currentMessageObject.messageOwner);
|
||||
} else if (currentFileLocation != null) {
|
||||
f = FileLoader.getPathToAttach(currentFileLocation, avatarsUserId != 0);
|
||||
|
@ -1800,6 +1803,11 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat
|
|||
containerView.invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Bitmap getBitmap() {
|
||||
return centerImage.getBitmap();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -2579,7 +2587,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat
|
|||
captionTextViewNew = captionTextView;
|
||||
|
||||
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.setText(str);
|
||||
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();
|
||||
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();
|
||||
if (Build.VERSION.SDK_INT >= 18) {
|
||||
|
|
|
@ -285,7 +285,7 @@ public class PrivacyUsersActivity extends BaseFragment implements NotificationCe
|
|||
int type = getItemViewType(i);
|
||||
if (type == 0) {
|
||||
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));
|
||||
((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