1
0
mirror of https://github.com/MGislv/NekoX.git synced 2024-07-02 22:43:36 +00:00

Update to 3.3.1

This commit is contained in:
DrKLO 2015-11-27 00:04:02 +03:00
parent 496c336d5f
commit 74def22213
160 changed files with 36825 additions and 8207 deletions

View File

@ -7,22 +7,16 @@ repositories {
dependencies { dependencies {
compile 'com.android.support:support-v4:23.1.+' compile 'com.android.support:support-v4:23.1.+'
compile 'com.google.android.gms:play-services:3.2.+' compile 'com.google.android.gms:play-services:3.2.+'
compile 'net.hockeyapp.android:HockeySDK:3.5.+' compile 'net.hockeyapp.android:HockeySDK:3.6.+'
compile 'com.googlecode.mp4parser:isoparser:1.0.+' compile 'com.googlecode.mp4parser:isoparser:1.0.+'
compile 'org.apache.httpcomponents:httpmime:4.2.1'
} }
android { android {
compileSdkVersion 23 compileSdkVersion 23
buildToolsVersion '23.0.1' buildToolsVersion '23.0.2'
useLibrary 'org.apache.http.legacy' useLibrary 'org.apache.http.legacy'
packagingOptions {
exclude 'META-INF/NOTICE.txt'
exclude 'META-INF/LICENSE.txt'
}
compileOptions { compileOptions {
sourceCompatibility JavaVersion.VERSION_1_7 sourceCompatibility JavaVersion.VERSION_1_7
targetCompatibility JavaVersion.VERSION_1_7 targetCompatibility JavaVersion.VERSION_1_7
@ -30,7 +24,10 @@ android {
signingConfigs { signingConfigs {
debug { debug {
storeFile file("config/debug.keystore") storeFile file("config/release.keystore")
storePassword RELEASE_STORE_PASSWORD
keyAlias RELEASE_KEY_ALIAS
keyPassword RELEASE_KEY_PASSWORD
} }
release { release {
@ -46,6 +43,7 @@ android {
debuggable true debuggable true
jniDebuggable true jniDebuggable true
signingConfig signingConfigs.debug signingConfig signingConfigs.debug
applicationIdSuffix ".beta"
} }
release { release {
@ -81,7 +79,7 @@ android {
defaultConfig { defaultConfig {
minSdkVersion 8 minSdkVersion 8
targetSdkVersion 23 targetSdkVersion 23
versionCode 654 versionCode 685
versionName "3.2.6" versionName "3.3.1"
} }
} }

View File

@ -21,13 +21,13 @@
<application <application
android:allowBackup="false" android:allowBackup="false"
android:icon="@drawable/ic_launcher" android:icon="@drawable/ic_launcher"
android:label="@string/AppName" android:label="@string/AppNameBeta"
android:theme="@style/Theme.TMessages.Start" android:theme="@style/Theme.TMessages.Start"
android:name=".ApplicationLoader" android:name=".ApplicationLoader"
android:hardwareAccelerated="@bool/useHardwareAcceleration" android:hardwareAccelerated="@bool/useHardwareAcceleration"
android:largeHeap="true"> android:largeHeap="true">
<meta-data android:name="com.google.android.maps.v2.API_KEY" android:value="AIzaSyCTNmNqbWovP9ETcAob98YlrfOQEAC0CJ4" /> <meta-data android:name="com.google.android.maps.v2.API_KEY" android:value="AIzaSyA-t0jLPjUt2FxrA8VPK2EiYHcYcboIR6k" />
<activity android:name="net.hockeyapp.android.UpdateActivity" /> <activity android:name="net.hockeyapp.android.UpdateActivity" />

View File

@ -187,7 +187,7 @@ include $(CLEAR_VARS)
LOCAL_PRELINK_MODULE := false LOCAL_PRELINK_MODULE := false
LOCAL_STATIC_LIBRARIES := webp sqlite tgnet breakpad LOCAL_STATIC_LIBRARIES := webp sqlite tgnet breakpad
LOCAL_MODULE := tmessages.14 LOCAL_MODULE := tmessages.15
LOCAL_CFLAGS := -w -std=c11 -Os -DNULL=0 -DSOCKLEN_T=socklen_t -DLOCALE_NOT_USED -D_LARGEFILE_SOURCE=1 -D_FILE_OFFSET_BITS=64 LOCAL_CFLAGS := -w -std=c11 -Os -DNULL=0 -DSOCKLEN_T=socklen_t -DLOCALE_NOT_USED -D_LARGEFILE_SOURCE=1 -D_FILE_OFFSET_BITS=64
LOCAL_CFLAGS += -Drestrict='' -D__EMX__ -DOPUS_BUILD -DFIXED_POINT -DUSE_ALLOCA -DHAVE_LRINT -DHAVE_LRINTF -fno-math-errno LOCAL_CFLAGS += -Drestrict='' -D__EMX__ -DOPUS_BUILD -DFIXED_POINT -DUSE_ALLOCA -DHAVE_LRINT -DHAVE_LRINTF -fno-math-errno
LOCAL_CFLAGS += -DANDROID_NDK -DDISABLE_IMPORTGL -fno-strict-aliasing -fprefetch-loop-arrays -DAVOID_TABLES -DANDROID_TILE_BASED_DECODE -DANDROID_ARMV6_IDCT -ffast-math LOCAL_CFLAGS += -DANDROID_NDK -DDISABLE_IMPORTGL -fno-strict-aliasing -fprefetch-loop-arrays -DAVOID_TABLES -DANDROID_TILE_BASED_DECODE -DANDROID_ARMV6_IDCT -ffast-math

View File

@ -96,7 +96,7 @@ void sendRequest(JNIEnv *env, jclass c, jint object, jobject onComplete, jobject
if (onQuickAck != nullptr) { if (onQuickAck != nullptr) {
jniEnv->CallVoidMethod(onQuickAck, jclass_QuickAckDelegate_run); jniEnv->CallVoidMethod(onQuickAck, jclass_QuickAckDelegate_run);
} }
}), flags, datacenterId, (ConnectionType) connetionType, immediate, onComplete, onQuickAck); }), flags, datacenterId, (ConnectionType) connetionType, immediate, token, onComplete, onQuickAck);
} }
void cancelRequest(JNIEnv *env, jclass c, jint token, jboolean notifyServer) { void cancelRequest(JNIEnv *env, jclass c, jint token, jboolean notifyServer) {

File diff suppressed because it is too large Load Diff

View File

@ -31,7 +31,7 @@
** part of the build process. ** part of the build process.
*/ */
#ifndef _SQLITE3_H_ #ifndef _SQLITE3_H_
#define _SQLITE3_H_ #define _SQLITE3_H_
#include <stdarg.h> /* Needed for the definition of va_list */ #include <stdarg.h> /* Needed for the definition of va_list */
/* /*
@ -111,9 +111,9 @@ extern "C" {
** [sqlite3_libversion_number()], [sqlite3_sourceid()], ** [sqlite3_libversion_number()], [sqlite3_sourceid()],
** [sqlite_version()] and [sqlite_source_id()]. ** [sqlite_version()] and [sqlite_source_id()].
*/ */
#define SQLITE_VERSION "3.8.11.1" #define SQLITE_VERSION "3.9.2"
#define SQLITE_VERSION_NUMBER 3008011 #define SQLITE_VERSION_NUMBER 3009002
#define SQLITE_SOURCE_ID "2015-07-29 20:00:57 cf538e2783e468bbc25e7cb2a9ee64d3e0e80b2f" #define SQLITE_SOURCE_ID "2015-11-02 18:31:45 bda77dda9697c463c3d0704014d51627fceee328"
/* /*
** CAPI3REF: Run-Time Library Version Numbers ** CAPI3REF: Run-Time Library Version Numbers
@ -124,7 +124,7 @@ extern "C" {
** but are associated with the library instead of the header file. ^(Cautious ** but are associated with the library instead of the header file. ^(Cautious
** programmers might include assert() statements in their application to ** programmers might include assert() statements in their application to
** verify that values returned by these interfaces match the macros in ** verify that values returned by these interfaces match the macros in
** the header, and thus insure that the application is ** the header, and thus ensure that the application is
** compiled with matching library and header files. ** compiled with matching library and header files.
** **
** <blockquote><pre> ** <blockquote><pre>
@ -374,7 +374,7 @@ typedef int (*sqlite3_callback)(void*,int,char**, char**);
** Restrictions: ** Restrictions:
** **
** <ul> ** <ul>
** <li> The application must insure that the 1st parameter to sqlite3_exec() ** <li> The application must ensure that the 1st parameter to sqlite3_exec()
** is a valid and open [database connection]. ** is a valid and open [database connection].
** <li> The application must not close the [database connection] specified by ** <li> The application must not close the [database connection] specified by
** the 1st parameter to sqlite3_exec() while sqlite3_exec() is running. ** the 1st parameter to sqlite3_exec() while sqlite3_exec() is running.
@ -477,6 +477,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_exec(
#define SQLITE_IOERR_MMAP (SQLITE_IOERR | (24<<8)) #define SQLITE_IOERR_MMAP (SQLITE_IOERR | (24<<8))
#define SQLITE_IOERR_GETTEMPPATH (SQLITE_IOERR | (25<<8)) #define SQLITE_IOERR_GETTEMPPATH (SQLITE_IOERR | (25<<8))
#define SQLITE_IOERR_CONVPATH (SQLITE_IOERR | (26<<8)) #define SQLITE_IOERR_CONVPATH (SQLITE_IOERR | (26<<8))
#define SQLITE_IOERR_VNODE (SQLITE_IOERR | (27<<8))
#define SQLITE_LOCKED_SHAREDCACHE (SQLITE_LOCKED | (1<<8)) #define SQLITE_LOCKED_SHAREDCACHE (SQLITE_LOCKED | (1<<8))
#define SQLITE_BUSY_RECOVERY (SQLITE_BUSY | (1<<8)) #define SQLITE_BUSY_RECOVERY (SQLITE_BUSY | (1<<8))
#define SQLITE_BUSY_SNAPSHOT (SQLITE_BUSY | (2<<8)) #define SQLITE_BUSY_SNAPSHOT (SQLITE_BUSY | (2<<8))
@ -1366,9 +1367,11 @@ SQLITE_API int SQLITE_STDCALL sqlite3_os_end(void);
** applications and so this routine is usually not necessary. It is ** applications and so this routine is usually not necessary. It is
** provided to support rare applications with unusual needs. ** provided to support rare applications with unusual needs.
** **
** The sqlite3_config() interface is not threadsafe. The application ** <b>The sqlite3_config() interface is not threadsafe. The application
** must insure that no other SQLite interfaces are invoked by other ** must ensure that no other SQLite interfaces are invoked by other
** threads while sqlite3_config() is running. Furthermore, sqlite3_config() ** threads while sqlite3_config() is running.</b>
**
** The sqlite3_config() interface
** may only be invoked prior to library initialization using ** may only be invoked prior to library initialization using
** [sqlite3_initialize()] or after shutdown by [sqlite3_shutdown()]. ** [sqlite3_initialize()] or after shutdown by [sqlite3_shutdown()].
** ^If sqlite3_config() is called after [sqlite3_initialize()] and before ** ^If sqlite3_config() is called after [sqlite3_initialize()] and before
@ -3373,7 +3376,8 @@ SQLITE_API int SQLITE_STDCALL sqlite3_stmt_readonly(sqlite3_stmt *pStmt);
** **
** ^The sqlite3_stmt_busy(S) interface returns true (non-zero) if the ** ^The sqlite3_stmt_busy(S) interface returns true (non-zero) if the
** [prepared statement] S has been stepped at least once using ** [prepared statement] S has been stepped at least once using
** [sqlite3_step(S)] but has not run to completion and/or has not ** [sqlite3_step(S)] but has neither run to completion (returned
** [SQLITE_DONE] from [sqlite3_step(S)]) nor
** been reset using [sqlite3_reset(S)]. ^The sqlite3_stmt_busy(S) ** been reset using [sqlite3_reset(S)]. ^The sqlite3_stmt_busy(S)
** interface returns false if S is a NULL pointer. If S is not a ** interface returns false if S is a NULL pointer. If S is not a
** NULL pointer and is not a pointer to a valid [prepared statement] ** NULL pointer and is not a pointer to a valid [prepared statement]
@ -3626,7 +3630,7 @@ SQLITE_API const char *SQLITE_STDCALL sqlite3_bind_parameter_name(sqlite3_stmt*,
** **
** See also: [sqlite3_bind_blob|sqlite3_bind()], ** See also: [sqlite3_bind_blob|sqlite3_bind()],
** [sqlite3_bind_parameter_count()], and ** [sqlite3_bind_parameter_count()], and
** [sqlite3_bind_parameter_index()]. ** [sqlite3_bind_parameter_name()].
*/ */
SQLITE_API int SQLITE_STDCALL sqlite3_bind_parameter_index(sqlite3_stmt*, const char *zName); SQLITE_API int SQLITE_STDCALL sqlite3_bind_parameter_index(sqlite3_stmt*, const char *zName);
@ -4355,6 +4359,22 @@ SQLITE_API const void *SQLITE_STDCALL sqlite3_value_text16be(sqlite3_value*);
SQLITE_API int SQLITE_STDCALL sqlite3_value_type(sqlite3_value*); SQLITE_API int SQLITE_STDCALL sqlite3_value_type(sqlite3_value*);
SQLITE_API int SQLITE_STDCALL sqlite3_value_numeric_type(sqlite3_value*); SQLITE_API int SQLITE_STDCALL sqlite3_value_numeric_type(sqlite3_value*);
/*
** CAPI3REF: Finding The Subtype Of SQL Values
** METHOD: sqlite3_value
**
** The sqlite3_value_subtype(V) function returns the subtype for
** an [application-defined SQL function] argument V. The subtype
** information can be used to pass a limited amount of context from
** one SQL function to another. Use the [sqlite3_result_subtype()]
** routine to set the subtype for the return value of an SQL function.
**
** SQLite makes no use of subtype itself. It merely passes the subtype
** from the result of one [application-defined SQL function] into the
** input of another.
*/
SQLITE_API unsigned int SQLITE_STDCALL sqlite3_value_subtype(sqlite3_value*);
/* /*
** CAPI3REF: Copy And Free SQL Values ** CAPI3REF: Copy And Free SQL Values
** METHOD: sqlite3_value ** METHOD: sqlite3_value
@ -4654,6 +4674,21 @@ SQLITE_API void SQLITE_STDCALL sqlite3_result_value(sqlite3_context*, sqlite3_va
SQLITE_API void SQLITE_STDCALL sqlite3_result_zeroblob(sqlite3_context*, int n); SQLITE_API void SQLITE_STDCALL sqlite3_result_zeroblob(sqlite3_context*, int n);
SQLITE_API int SQLITE_STDCALL sqlite3_result_zeroblob64(sqlite3_context*, sqlite3_uint64 n); SQLITE_API int SQLITE_STDCALL sqlite3_result_zeroblob64(sqlite3_context*, sqlite3_uint64 n);
/*
** CAPI3REF: Setting The Subtype Of An SQL Function
** METHOD: sqlite3_context
**
** The sqlite3_result_subtype(C,T) function causes the subtype of
** the result from the [application-defined SQL function] with
** [sqlite3_context] C to be the value T. Only the lower 8 bits
** of the subtype T are preserved in current versions of SQLite;
** higher order bits are discarded.
** The number of subtype bytes preserved by SQLite might increase
** in future releases of SQLite.
*/
SQLITE_API void SQLITE_STDCALL sqlite3_result_subtype(sqlite3_context*,unsigned int);
/* /*
** CAPI3REF: Define New Collating Sequences ** CAPI3REF: Define New Collating Sequences
** METHOD: sqlite3 ** METHOD: sqlite3
@ -5599,13 +5634,31 @@ struct sqlite3_module {
** ^The estimatedRows value is an estimate of the number of rows that ** ^The estimatedRows value is an estimate of the number of rows that
** will be returned by the strategy. ** will be returned by the strategy.
** **
** The xBestIndex method may optionally populate the idxFlags field with a
** mask of SQLITE_INDEX_SCAN_* flags. Currently there is only one such flag -
** SQLITE_INDEX_SCAN_UNIQUE. If the xBestIndex method sets this flag, SQLite
** assumes that the strategy may visit at most one row.
**
** Additionally, if xBestIndex sets the SQLITE_INDEX_SCAN_UNIQUE flag, then
** SQLite also assumes that if a call to the xUpdate() method is made as
** part of the same statement to delete or update a virtual table row and the
** implementation returns SQLITE_CONSTRAINT, then there is no need to rollback
** any database changes. In other words, if the xUpdate() returns
** SQLITE_CONSTRAINT, the database contents must be exactly as they were
** before xUpdate was called. By contrast, if SQLITE_INDEX_SCAN_UNIQUE is not
** set and xUpdate returns SQLITE_CONSTRAINT, any database changes made by
** the xUpdate method are automatically rolled back by SQLite.
**
** IMPORTANT: The estimatedRows field was added to the sqlite3_index_info ** IMPORTANT: The estimatedRows field was added to the sqlite3_index_info
** structure for SQLite version 3.8.2. If a virtual table extension is ** structure for SQLite version 3.8.2. If a virtual table extension is
** used with an SQLite version earlier than 3.8.2, the results of attempting ** used with an SQLite version earlier than 3.8.2, the results of attempting
** to read or write the estimatedRows field are undefined (but are likely ** to read or write the estimatedRows field are undefined (but are likely
** to included crashing the application). The estimatedRows field should ** to included crashing the application). The estimatedRows field should
** therefore only be used if [sqlite3_libversion_number()] returns a ** therefore only be used if [sqlite3_libversion_number()] returns a
** value greater than or equal to 3008002. ** value greater than or equal to 3008002. Similarly, the idxFlags field
** was added for version 3.9.0. It may therefore only be used if
** sqlite3_libversion_number() returns a value greater than or equal to
** 3009000.
*/ */
struct sqlite3_index_info { struct sqlite3_index_info {
/* Inputs */ /* Inputs */
@ -5633,8 +5686,15 @@ struct sqlite3_index_info {
double estimatedCost; /* Estimated cost of using this index */ double estimatedCost; /* Estimated cost of using this index */
/* Fields below are only available in SQLite 3.8.2 and later */ /* Fields below are only available in SQLite 3.8.2 and later */
sqlite3_int64 estimatedRows; /* Estimated number of rows returned */ sqlite3_int64 estimatedRows; /* Estimated number of rows returned */
/* Fields below are only available in SQLite 3.9.0 and later */
int idxFlags; /* Mask of SQLITE_INDEX_SCAN_* flags */
}; };
/*
** CAPI3REF: Virtual Table Scan Flags
*/
#define SQLITE_INDEX_SCAN_UNIQUE 1 /* Scan visits at most 1 row */
/* /*
** CAPI3REF: Virtual Table Constraint Operator Codes ** CAPI3REF: Virtual Table Constraint Operator Codes
** **
@ -6092,6 +6152,9 @@ SQLITE_API int SQLITE_STDCALL sqlite3_vfs_unregister(sqlite3_vfs*);
** <li> SQLITE_MUTEX_STATIC_APP1 ** <li> SQLITE_MUTEX_STATIC_APP1
** <li> SQLITE_MUTEX_STATIC_APP2 ** <li> SQLITE_MUTEX_STATIC_APP2
** <li> SQLITE_MUTEX_STATIC_APP3 ** <li> SQLITE_MUTEX_STATIC_APP3
** <li> SQLITE_MUTEX_STATIC_VFS1
** <li> SQLITE_MUTEX_STATIC_VFS2
** <li> SQLITE_MUTEX_STATIC_VFS3
** </ul> ** </ul>
** **
** ^The first two constants (SQLITE_MUTEX_FAST and SQLITE_MUTEX_RECURSIVE) ** ^The first two constants (SQLITE_MUTEX_FAST and SQLITE_MUTEX_RECURSIVE)
@ -7858,3 +7921,523 @@ struct sqlite3_rtree_query_info {
#endif /* ifndef _SQLITE3RTREE_H_ */ #endif /* ifndef _SQLITE3RTREE_H_ */
/*
** 2014 May 31
**
** The author disclaims copyright to this source code. In place of
** a legal notice, here is a blessing:
**
** May you do good and not evil.
** May you find forgiveness for yourself and forgive others.
** May you share freely, never taking more than you give.
**
******************************************************************************
**
** Interfaces to extend FTS5. Using the interfaces defined in this file,
** FTS5 may be extended with:
**
** * custom tokenizers, and
** * custom auxiliary functions.
*/
#ifndef _FTS5_H
#define _FTS5_H
#ifdef __cplusplus
extern "C" {
#endif
/*************************************************************************
** CUSTOM AUXILIARY FUNCTIONS
**
** Virtual table implementations may overload SQL functions by implementing
** the sqlite3_module.xFindFunction() method.
*/
typedef struct Fts5ExtensionApi Fts5ExtensionApi;
typedef struct Fts5Context Fts5Context;
typedef struct Fts5PhraseIter Fts5PhraseIter;
typedef void (*fts5_extension_function)(
const Fts5ExtensionApi *pApi, /* API offered by current FTS version */
Fts5Context *pFts, /* First arg to pass to pApi functions */
sqlite3_context *pCtx, /* Context for returning result/error */
int nVal, /* Number of values in apVal[] array */
sqlite3_value **apVal /* Array of trailing arguments */
);
struct Fts5PhraseIter {
const unsigned char *a;
const unsigned char *b;
};
/*
** EXTENSION API FUNCTIONS
**
** xUserData(pFts):
** Return a copy of the context pointer the extension function was
** registered with.
**
** xColumnTotalSize(pFts, iCol, pnToken):
** If parameter iCol is less than zero, set output variable *pnToken
** to the total number of tokens in the FTS5 table. Or, if iCol is
** non-negative but less than the number of columns in the table, return
** the total number of tokens in column iCol, considering all rows in
** the FTS5 table.
**
** If parameter iCol is greater than or equal to the number of columns
** in the table, SQLITE_RANGE is returned. Or, if an error occurs (e.g.
** an OOM condition or IO error), an appropriate SQLite error code is
** returned.
**
** xColumnCount(pFts):
** Return the number of columns in the table.
**
** xColumnSize(pFts, iCol, pnToken):
** If parameter iCol is less than zero, set output variable *pnToken
** to the total number of tokens in the current row. Or, if iCol is
** non-negative but less than the number of columns in the table, set
** *pnToken to the number of tokens in column iCol of the current row.
**
** If parameter iCol is greater than or equal to the number of columns
** in the table, SQLITE_RANGE is returned. Or, if an error occurs (e.g.
** an OOM condition or IO error), an appropriate SQLite error code is
** returned.
**
** xColumnText:
** This function attempts to retrieve the text of column iCol of the
** current document. If successful, (*pz) is set to point to a buffer
** containing the text in utf-8 encoding, (*pn) is set to the size in bytes
** (not characters) of the buffer and SQLITE_OK is returned. Otherwise,
** if an error occurs, an SQLite error code is returned and the final values
** of (*pz) and (*pn) are undefined.
**
** xPhraseCount:
** Returns the number of phrases in the current query expression.
**
** xPhraseSize:
** Returns the number of tokens in phrase iPhrase of the query. Phrases
** are numbered starting from zero.
**
** xInstCount:
** Set *pnInst to the total number of occurrences of all phrases within
** the query within the current row. Return SQLITE_OK if successful, or
** an error code (i.e. SQLITE_NOMEM) if an error occurs.
**
** xInst:
** Query for the details of phrase match iIdx within the current row.
** Phrase matches are numbered starting from zero, so the iIdx argument
** should be greater than or equal to zero and smaller than the value
** output by xInstCount().
**
** Returns SQLITE_OK if successful, or an error code (i.e. SQLITE_NOMEM)
** if an error occurs.
**
** xRowid:
** Returns the rowid of the current row.
**
** xTokenize:
** Tokenize text using the tokenizer belonging to the FTS5 table.
**
** xQueryPhrase(pFts5, iPhrase, pUserData, xCallback):
** This API function is used to query the FTS table for phrase iPhrase
** of the current query. Specifically, a query equivalent to:
**
** ... FROM ftstable WHERE ftstable MATCH $p ORDER BY rowid
**
** with $p set to a phrase equivalent to the phrase iPhrase of the
** current query is executed. For each row visited, the callback function
** passed as the fourth argument is invoked. The context and API objects
** passed to the callback function may be used to access the properties of
** each matched row. Invoking Api.xUserData() returns a copy of the pointer
** passed as the third argument to pUserData.
**
** If the callback function returns any value other than SQLITE_OK, the
** query is abandoned and the xQueryPhrase function returns immediately.
** If the returned value is SQLITE_DONE, xQueryPhrase returns SQLITE_OK.
** Otherwise, the error code is propagated upwards.
**
** If the query runs to completion without incident, SQLITE_OK is returned.
** Or, if some error occurs before the query completes or is aborted by
** the callback, an SQLite error code is returned.
**
**
** xSetAuxdata(pFts5, pAux, xDelete)
**
** Save the pointer passed as the second argument as the extension functions
** "auxiliary data". The pointer may then be retrieved by the current or any
** future invocation of the same fts5 extension function made as part of
** of the same MATCH query using the xGetAuxdata() API.
**
** Each extension function is allocated a single auxiliary data slot for
** each FTS query (MATCH expression). If the extension function is invoked
** more than once for a single FTS query, then all invocations share a
** single auxiliary data context.
**
** If there is already an auxiliary data pointer when this function is
** invoked, then it is replaced by the new pointer. If an xDelete callback
** was specified along with the original pointer, it is invoked at this
** point.
**
** The xDelete callback, if one is specified, is also invoked on the
** auxiliary data pointer after the FTS5 query has finished.
**
** If an error (e.g. an OOM condition) occurs within this function, an
** the auxiliary data is set to NULL and an error code returned. If the
** xDelete parameter was not NULL, it is invoked on the auxiliary data
** pointer before returning.
**
**
** xGetAuxdata(pFts5, bClear)
**
** Returns the current auxiliary data pointer for the fts5 extension
** function. See the xSetAuxdata() method for details.
**
** If the bClear argument is non-zero, then the auxiliary data is cleared
** (set to NULL) before this function returns. In this case the xDelete,
** if any, is not invoked.
**
**
** xRowCount(pFts5, pnRow)
**
** This function is used to retrieve the total number of rows in the table.
** In other words, the same value that would be returned by:
**
** SELECT count(*) FROM ftstable;
**
** xPhraseFirst()
** This function is used, along with type Fts5PhraseIter and the xPhraseNext
** method, to iterate through all instances of a single query phrase within
** the current row. This is the same information as is accessible via the
** xInstCount/xInst APIs. While the xInstCount/xInst APIs are more convenient
** to use, this API may be faster under some circumstances. To iterate
** through instances of phrase iPhrase, use the following code:
**
** Fts5PhraseIter iter;
** int iCol, iOff;
** for(pApi->xPhraseFirst(pFts, iPhrase, &iter, &iCol, &iOff);
** iOff>=0;
** pApi->xPhraseNext(pFts, &iter, &iCol, &iOff)
** ){
** // An instance of phrase iPhrase at offset iOff of column iCol
** }
**
** The Fts5PhraseIter structure is defined above. Applications should not
** modify this structure directly - it should only be used as shown above
** with the xPhraseFirst() and xPhraseNext() API methods.
**
** xPhraseNext()
** See xPhraseFirst above.
*/
struct Fts5ExtensionApi {
int iVersion; /* Currently always set to 1 */
void *(*xUserData)(Fts5Context*);
int (*xColumnCount)(Fts5Context*);
int (*xRowCount)(Fts5Context*, sqlite3_int64 *pnRow);
int (*xColumnTotalSize)(Fts5Context*, int iCol, sqlite3_int64 *pnToken);
int (*xTokenize)(Fts5Context*,
const char *pText, int nText, /* Text to tokenize */
void *pCtx, /* Context passed to xToken() */
int (*xToken)(void*, int, const char*, int, int, int) /* Callback */
);
int (*xPhraseCount)(Fts5Context*);
int (*xPhraseSize)(Fts5Context*, int iPhrase);
int (*xInstCount)(Fts5Context*, int *pnInst);
int (*xInst)(Fts5Context*, int iIdx, int *piPhrase, int *piCol, int *piOff);
sqlite3_int64 (*xRowid)(Fts5Context*);
int (*xColumnText)(Fts5Context*, int iCol, const char **pz, int *pn);
int (*xColumnSize)(Fts5Context*, int iCol, int *pnToken);
int (*xQueryPhrase)(Fts5Context*, int iPhrase, void *pUserData,
int(*)(const Fts5ExtensionApi*,Fts5Context*,void*)
);
int (*xSetAuxdata)(Fts5Context*, void *pAux, void(*xDelete)(void*));
void *(*xGetAuxdata)(Fts5Context*, int bClear);
void (*xPhraseFirst)(Fts5Context*, int iPhrase, Fts5PhraseIter*, int*, int*);
void (*xPhraseNext)(Fts5Context*, Fts5PhraseIter*, int *piCol, int *piOff);
};
/*
** CUSTOM AUXILIARY FUNCTIONS
*************************************************************************/
/*************************************************************************
** CUSTOM TOKENIZERS
**
** Applications may also register custom tokenizer types. A tokenizer
** is registered by providing fts5 with a populated instance of the
** following structure. All structure methods must be defined, setting
** any member of the fts5_tokenizer struct to NULL leads to undefined
** behaviour. The structure methods are expected to function as follows:
**
** xCreate:
** This function is used to allocate and inititalize a tokenizer instance.
** A tokenizer instance is required to actually tokenize text.
**
** The first argument passed to this function is a copy of the (void*)
** pointer provided by the application when the fts5_tokenizer object
** was registered with FTS5 (the third argument to xCreateTokenizer()).
** The second and third arguments are an array of nul-terminated strings
** containing the tokenizer arguments, if any, specified following the
** tokenizer name as part of the CREATE VIRTUAL TABLE statement used
** to create the FTS5 table.
**
** The final argument is an output variable. If successful, (*ppOut)
** should be set to point to the new tokenizer handle and SQLITE_OK
** returned. If an error occurs, some value other than SQLITE_OK should
** be returned. In this case, fts5 assumes that the final value of *ppOut
** is undefined.
**
** xDelete:
** This function is invoked to delete a tokenizer handle previously
** allocated using xCreate(). Fts5 guarantees that this function will
** be invoked exactly once for each successful call to xCreate().
**
** xTokenize:
** This function is expected to tokenize the nText byte string indicated
** by argument pText. pText may or may not be nul-terminated. The first
** argument passed to this function is a pointer to an Fts5Tokenizer object
** returned by an earlier call to xCreate().
**
** The second argument indicates the reason that FTS5 is requesting
** tokenization of the supplied text. This is always one of the following
** four values:
**
** <ul><li> <b>FTS5_TOKENIZE_DOCUMENT</b> - A document is being inserted into
** or removed from the FTS table. The tokenizer is being invoked to
** determine the set of tokens to add to (or delete from) the
** FTS index.
**
** <li> <b>FTS5_TOKENIZE_QUERY</b> - A MATCH query is being executed
** against the FTS index. The tokenizer is being called to tokenize
** a bareword or quoted string specified as part of the query.
**
** <li> <b>(FTS5_TOKENIZE_QUERY | FTS5_TOKENIZE_PREFIX)</b> - Same as
** FTS5_TOKENIZE_QUERY, except that the bareword or quoted string is
** followed by a "*" character, indicating that the last token
** returned by the tokenizer will be treated as a token prefix.
**
** <li> <b>FTS5_TOKENIZE_AUX</b> - The tokenizer is being invoked to
** satisfy an fts5_api.xTokenize() request made by an auxiliary
** function. Or an fts5_api.xColumnSize() request made by the same
** on a columnsize=0 database.
** </ul>
**
** For each token in the input string, the supplied callback xToken() must
** be invoked. The first argument to it should be a copy of the pointer
** passed as the second argument to xTokenize(). The third and fourth
** arguments are a pointer to a buffer containing the token text, and the
** size of the token in bytes. The 4th and 5th arguments are the byte offsets
** of the first byte of and first byte immediately following the text from
** which the token is derived within the input.
**
** The second argument passed to the xToken() callback ("tflags") should
** normally be set to 0. The exception is if the tokenizer supports
** synonyms. In this case see the discussion below for details.
**
** FTS5 assumes the xToken() callback is invoked for each token in the
** order that they occur within the input text.
**
** If an xToken() callback returns any value other than SQLITE_OK, then
** the tokenization should be abandoned and the xTokenize() method should
** immediately return a copy of the xToken() return value. Or, if the
** input buffer is exhausted, xTokenize() should return SQLITE_OK. Finally,
** if an error occurs with the xTokenize() implementation itself, it
** may abandon the tokenization and return any error code other than
** SQLITE_OK or SQLITE_DONE.
**
** SYNONYM SUPPORT
**
** Custom tokenizers may also support synonyms. Consider a case in which a
** user wishes to query for a phrase such as "first place". Using the
** built-in tokenizers, the FTS5 query 'first + place' will match instances
** of "first place" within the document set, but not alternative forms
** such as "1st place". In some applications, it would be better to match
** all instances of "first place" or "1st place" regardless of which form
** the user specified in the MATCH query text.
**
** There are several ways to approach this in FTS5:
**
** <ol><li> By mapping all synonyms to a single token. In this case, the
** In the above example, this means that the tokenizer returns the
** same token for inputs "first" and "1st". Say that token is in
** fact "first", so that when the user inserts the document "I won
** 1st place" entries are added to the index for tokens "i", "won",
** "first" and "place". If the user then queries for '1st + place',
** the tokenizer substitutes "first" for "1st" and the query works
** as expected.
**
** <li> By adding multiple synonyms for a single term to the FTS index.
** In this case, when tokenizing query text, the tokenizer may
** provide multiple synonyms for a single term within the document.
** FTS5 then queries the index for each synonym individually. For
** example, faced with the query:
**
** <codeblock>
** ... MATCH 'first place'</codeblock>
**
** the tokenizer offers both "1st" and "first" as synonyms for the
** first token in the MATCH query and FTS5 effectively runs a query
** similar to:
**
** <codeblock>
** ... MATCH '(first OR 1st) place'</codeblock>
**
** except that, for the purposes of auxiliary functions, the query
** still appears to contain just two phrases - "(first OR 1st)"
** being treated as a single phrase.
**
** <li> By adding multiple synonyms for a single term to the FTS index.
** Using this method, when tokenizing document text, the tokenizer
** provides multiple synonyms for each token. So that when a
** document such as "I won first place" is tokenized, entries are
** added to the FTS index for "i", "won", "first", "1st" and
** "place".
**
** This way, even if the tokenizer does not provide synonyms
** when tokenizing query text (it should not - to do would be
** inefficient), it doesn't matter if the user queries for
** 'first + place' or '1st + place', as there are entires in the
** FTS index corresponding to both forms of the first token.
** </ol>
**
** Whether it is parsing document or query text, any call to xToken that
** specifies a <i>tflags</i> argument with the FTS5_TOKEN_COLOCATED bit
** is considered to supply a synonym for the previous token. For example,
** when parsing the document "I won first place", a tokenizer that supports
** synonyms would call xToken() 5 times, as follows:
**
** <codeblock>
** xToken(pCtx, 0, "i", 1, 0, 1);
** xToken(pCtx, 0, "won", 3, 2, 5);
** xToken(pCtx, 0, "first", 5, 6, 11);
** xToken(pCtx, FTS5_TOKEN_COLOCATED, "1st", 3, 6, 11);
** xToken(pCtx, 0, "place", 5, 12, 17);
**</codeblock>
**
** It is an error to specify the FTS5_TOKEN_COLOCATED flag the first time
** xToken() is called. Multiple synonyms may be specified for a single token
** by making multiple calls to xToken(FTS5_TOKEN_COLOCATED) in sequence.
** There is no limit to the number of synonyms that may be provided for a
** single token.
**
** In many cases, method (1) above is the best approach. It does not add
** extra data to the FTS index or require FTS5 to query for multiple terms,
** so it is efficient in terms of disk space and query speed. However, it
** does not support prefix queries very well. If, as suggested above, the
** token "first" is subsituted for "1st" by the tokenizer, then the query:
**
** <codeblock>
** ... MATCH '1s*'</codeblock>
**
** will not match documents that contain the token "1st" (as the tokenizer
** will probably not map "1s" to any prefix of "first").
**
** For full prefix support, method (3) may be preferred. In this case,
** because the index contains entries for both "first" and "1st", prefix
** queries such as 'fi*' or '1s*' will match correctly. However, because
** extra entries are added to the FTS index, this method uses more space
** within the database.
**
** Method (2) offers a midpoint between (1) and (3). Using this method,
** a query such as '1s*' will match documents that contain the literal
** token "1st", but not "first" (assuming the tokenizer is not able to
** provide synonyms for prefixes). However, a non-prefix query like '1st'
** will match against "1st" and "first". This method does not require
** extra disk space, as no extra entries are added to the FTS index.
** On the other hand, it may require more CPU cycles to run MATCH queries,
** as separate queries of the FTS index are required for each synonym.
**
** When using methods (2) or (3), it is important that the tokenizer only
** provide synonyms when tokenizing document text (method (2)) or query
** text (method (3)), not both. Doing so will not cause any errors, but is
** inefficient.
*/
typedef struct Fts5Tokenizer Fts5Tokenizer;
typedef struct fts5_tokenizer fts5_tokenizer;
struct fts5_tokenizer {
int (*xCreate)(void*, const char **azArg, int nArg, Fts5Tokenizer **ppOut);
void (*xDelete)(Fts5Tokenizer*);
int (*xTokenize)(Fts5Tokenizer*,
void *pCtx,
int flags, /* Mask of FTS5_TOKENIZE_* flags */
const char *pText, int nText,
int (*xToken)(
void *pCtx, /* Copy of 2nd argument to xTokenize() */
int tflags, /* Mask of FTS5_TOKEN_* flags */
const char *pToken, /* Pointer to buffer containing token */
int nToken, /* Size of token in bytes */
int iStart, /* Byte offset of token within input text */
int iEnd /* Byte offset of end of token within input text */
)
);
};
/* Flags that may be passed as the third argument to xTokenize() */
#define FTS5_TOKENIZE_QUERY 0x0001
#define FTS5_TOKENIZE_PREFIX 0x0002
#define FTS5_TOKENIZE_DOCUMENT 0x0004
#define FTS5_TOKENIZE_AUX 0x0008
/* Flags that may be passed by the tokenizer implementation back to FTS5
** as the third argument to the supplied xToken callback. */
#define FTS5_TOKEN_COLOCATED 0x0001 /* Same position as prev. token */
/*
** END OF CUSTOM TOKENIZERS
*************************************************************************/
/*************************************************************************
** FTS5 EXTENSION REGISTRATION API
*/
typedef struct fts5_api fts5_api;
struct fts5_api {
int iVersion; /* Currently always set to 2 */
/* Create a new tokenizer */
int (*xCreateTokenizer)(
fts5_api *pApi,
const char *zName,
void *pContext,
fts5_tokenizer *pTokenizer,
void (*xDestroy)(void*)
);
/* Find an existing tokenizer */
int (*xFindTokenizer)(
fts5_api *pApi,
const char *zName,
void **ppContext,
fts5_tokenizer *pTokenizer
);
/* Create a new auxiliary function */
int (*xCreateFunction)(
fts5_api *pApi,
const char *zName,
void *pContext,
fts5_extension_function xFunction,
void (*xDestroy)(void*)
);
};
/*
** END OF REGISTRATION API
*************************************************************************/
#ifdef __cplusplus
} /* end of the 'extern "C"' block */
#endif
#endif /* _FTS5_H */

View File

@ -6,6 +6,7 @@
* Copyright Nikolai Kudashov, 2015. * Copyright Nikolai Kudashov, 2015.
*/ */
#include <sys/stat.h>
#include "Config.h" #include "Config.h"
#include "ConnectionsManager.h" #include "ConnectionsManager.h"
#include "FileLog.h" #include "FileLog.h"
@ -16,9 +17,10 @@ Config::Config(std::string fileName) {
backupPath = configPath + ".bak"; backupPath = configPath + ".bak";
FILE *backup = fopen(backupPath.c_str(), "rb"); FILE *backup = fopen(backupPath.c_str(), "rb");
if (backup != nullptr) { if (backup != nullptr) {
DEBUG_D("Config(%p, %s) backup file found %s", this, configPath.c_str(), backupPath.c_str());
fclose(backup);
remove(configPath.c_str()); remove(configPath.c_str());
rename(backupPath.c_str(), configPath.c_str()); rename(backupPath.c_str(), configPath.c_str());
fclose(backup);
} }
} }
@ -28,10 +30,14 @@ NativeByteBuffer *Config::readConfig() {
if (file != nullptr) { if (file != nullptr) {
fseek(file, 0, SEEK_END); fseek(file, 0, SEEK_END);
long fileSize = ftell(file); long fileSize = ftell(file);
fseek(file, 0, SEEK_SET); if (fseek(file, 0, SEEK_SET)) {
DEBUG_E("Config(%p, %s) failed fseek to begin, reopen it", this, configPath.c_str());
fclose(file);
file = fopen(configPath.c_str(), "rb");
}
uint32_t size = 0; uint32_t size = 0;
int bytesRead = fread(&size, sizeof(uint32_t), 1, file); int bytesRead = fread(&size, sizeof(uint32_t), 1, file);
DEBUG_D("Config(%p, %s) load, size = %u", this, configPath.c_str(), size); DEBUG_D("Config(%p, %s) load, size = %u, fileSize = %u", this, configPath.c_str(), size, (uint32_t) fileSize);
if (bytesRead > 0 && size > 0 && (int32_t) size < fileSize) { if (bytesRead > 0 && size > 0 && (int32_t) size < fileSize) {
buffer = BuffersStorage::getInstance().getFreeBuffer(size); buffer = BuffersStorage::getInstance().getFreeBuffer(size);
if (fread(buffer->bytes(), sizeof(uint8_t), size, file) != size) { if (fread(buffer->bytes(), sizeof(uint8_t), size, file) != size) {
@ -45,6 +51,7 @@ NativeByteBuffer *Config::readConfig() {
} }
void Config::writeConfig(NativeByteBuffer *buffer) { void Config::writeConfig(NativeByteBuffer *buffer) {
DEBUG_D("Config(%p, %s) start write config", this, configPath.c_str());
FILE *file = fopen(configPath.c_str(), "rb"); FILE *file = fopen(configPath.c_str(), "rb");
FILE *backup = fopen(backupPath.c_str(), "rb"); FILE *backup = fopen(backupPath.c_str(), "rb");
bool error = false; bool error = false;
@ -65,21 +72,53 @@ void Config::writeConfig(NativeByteBuffer *buffer) {
return; return;
} }
file = fopen(configPath.c_str(), "wb"); file = fopen(configPath.c_str(), "wb");
if (chmod(configPath.c_str(), 0660)) {
DEBUG_E("Config(%p, %s) chmod failed", this, configPath.c_str());
}
if (file == nullptr) { if (file == nullptr) {
DEBUG_E("Config(%p, %s) unable to open file for writing", this, configPath.c_str());
return; return;
} }
uint32_t size = buffer->position(); uint32_t size = buffer->position();
if (fwrite(&size, sizeof(uint32_t), 1, file) == 1) { if (fwrite(&size, sizeof(uint32_t), 1, file) == 1) {
if (fwrite(buffer->bytes(), sizeof(uint8_t), size, file) != size) { if (fwrite(buffer->bytes(), sizeof(uint8_t), size, file) != size) {
DEBUG_E("Config(%p, %s) failed to write config data to file", this, configPath.c_str());
error = true; error = true;
} }
} else { } else {
DEBUG_E("Config(%p, %s) failed to write config size to file", this, configPath.c_str());
error = true; error = true;
} }
fclose(file); if (fflush(file)) {
if (error) { DEBUG_E("Config(%p, %s) fflush failed", this, configPath.c_str());
remove(configPath.c_str()); error = true;
}
int fd = fileno(file);
if (fd == -1) {
DEBUG_E("Config(%p, %s) fileno failed", this, configPath.c_str());
error = true;
} else { } else {
remove(backupPath.c_str()); DEBUG_D("Config(%p, %s) fileno = %d", this, configPath.c_str(), fd);
}
if (fd != -1 && fsync(fd) == -1) {
DEBUG_E("Config(%p, %s) fsync failed", this, configPath.c_str());
error = true;
}
if (fclose(file)) {
DEBUG_E("Config(%p, %s) fclose failed", this, configPath.c_str());
error = true;
}
if (error) {
DEBUG_E("Config(%p, %s) failed to write config", this, configPath.c_str());
if (remove(configPath.c_str())) {
DEBUG_E("Config(%p, %s) remove config failed", this, configPath.c_str());
}
} else {
if (remove(backupPath.c_str())) {
DEBUG_E("Config(%p, %s) remove backup failed failed", this, configPath.c_str());
}
}
if (!error) {
DEBUG_D("Config(%p, %s) config write ok", this, configPath.c_str());
} }
} }

View File

@ -220,7 +220,7 @@ void ConnectionsManager::select() {
return; return;
} else { } else {
lastPauseTime = now; lastPauseTime = now;
DEBUG_D("don't sleep 10 seconds because of salt, upload or download request"); DEBUG_D("don't sleep 30 seconds because of salt, upload or download request");
} }
} }
if (networkPaused) { if (networkPaused) {
@ -595,7 +595,7 @@ void ConnectionsManager::onConnectionConnected(Connection *connection) {
} else { } else {
if (networkPaused && lastPauseTime != 0) { if (networkPaused && lastPauseTime != 0) {
lastPauseTime = getCurrentTimeMillis(); lastPauseTime = getCurrentTimeMillis();
nextSleepTimeout = 10000; nextSleepTimeout = 30000;
} }
processRequestQueue(connection->getConnectionType(), datacenter->getDatacenterId()); processRequestQueue(connection->getConnectionType(), datacenter->getDatacenterId());
} }
@ -821,6 +821,7 @@ void ConnectionsManager::processServerResponse(TLObject *message, int64_t messag
Request *request = iter->get(); Request *request = iter->get();
Datacenter *requestDatacenter = getDatacenterWithId(request->datacenterId); Datacenter *requestDatacenter = getDatacenterWithId(request->datacenterId);
if (request->messageId < response->first_msg_id && request->connectionType & connection->getConnectionType() && requestDatacenter != nullptr && requestDatacenter->getDatacenterId() == datacenter->getDatacenterId()) { if (request->messageId < response->first_msg_id && request->connectionType & connection->getConnectionType() && requestDatacenter != nullptr && requestDatacenter->getDatacenterId() == datacenter->getDatacenterId()) {
DEBUG_D("clear request %p - %s", request->rawRequest, typeid(*request->rawRequest).name());
request->clear(true); request->clear(true);
} }
} }
@ -943,6 +944,7 @@ void ConnectionsManager::processServerResponse(TLObject *message, int64_t messag
for (requestsIter iter = runningRequests.begin(); iter != runningRequests.end(); iter++) { for (requestsIter iter = runningRequests.begin(); iter != runningRequests.end(); iter++) {
Request *request = iter->get(); Request *request = iter->get();
if (request->respondsToMessageId(resultMid)) { if (request->respondsToMessageId(resultMid)) {
DEBUG_D("got response for request %p - %s", request->rawRequest, typeid(*request->rawRequest).name());
bool discardResponse = false; bool discardResponse = false;
bool isError = false; bool isError = false;
bool allowInitConnection = true; bool allowInitConnection = true;
@ -984,8 +986,16 @@ void ConnectionsManager::processServerResponse(TLObject *message, int64_t messag
} }
discardResponse = true; discardResponse = true;
request->failedByFloodWait = true; request->failedByFloodWait = waitTime;
request->startTime = 0;
request->minStartTime = (int32_t) (getCurrentTimeMillis() / 1000 + waitTime); request->minStartTime = (int32_t) (getCurrentTimeMillis() / 1000 + waitTime);
} else if (error->error_code == 400) {
static std::string waitFailed = "MSG_WAIT_FAILED";
if (error->error_message.find(waitFailed) != std::string::npos) {
discardResponse = true;
request->minStartTime = (int32_t) (getCurrentTimeMillis() / 1000 + 1);
request->startTime = 0;
}
} }
} }
if (!discardResponse) { if (!discardResponse) {
@ -1124,10 +1134,10 @@ void ConnectionsManager::processServerResponse(TLObject *message, int64_t messag
if ((request->connectionType & ConnectionTypeDownload) == 0) { if ((request->connectionType & ConnectionTypeDownload) == 0) {
continue; continue;
} }
if (request->respondsToMessageId(resultMid)) { Datacenter *requestDatacenter = getDatacenterWithId(request->datacenterId);
if (requestDatacenter != nullptr && requestDatacenter->getDatacenterId() == datacenter->getDatacenterId()) {
request->retryCount = 0; request->retryCount = 0;
request->failedBySalt = true; request->failedBySalt = true;
break;
} }
} }
} }
@ -1208,7 +1218,7 @@ void ConnectionsManager::processServerResponse(TLObject *message, int64_t messag
} else if (connection->connectionType == ConnectionTypePush && typeInfo == typeid(TL_updatesTooLong)) { } else if (connection->connectionType == ConnectionTypePush && typeInfo == typeid(TL_updatesTooLong)) {
if (networkPaused) { if (networkPaused) {
lastPauseTime = getCurrentTimeMillis(); lastPauseTime = getCurrentTimeMillis();
nextSleepTimeout = 10000; nextSleepTimeout = 30000;
DEBUG_D("received internal push: wakeup network in background"); DEBUG_D("received internal push: wakeup network in background");
} else if (lastPauseTime != 0) { } else if (lastPauseTime != 0) {
lastPauseTime = getCurrentTimeMillis(); lastPauseTime = getCurrentTimeMillis();
@ -1364,12 +1374,6 @@ void ConnectionsManager::sendRequest(TLObject *object, onCompleteFunc onComplete
} }
#ifdef ANDROID #ifdef ANDROID
int32_t ConnectionsManager::sendRequest(TLObject *object, onCompleteFunc onComplete, onQuickAckFunc onQuickAck, uint32_t flags, uint32_t datacenterId, ConnectionType connetionType, bool immediate, jobject ptr1, jobject ptr2) {
int32_t requestToken = lastRequestToken++;
sendRequest(object, onComplete, onQuickAck, flags, datacenterId, connetionType, immediate, requestToken, ptr1, ptr2);
return requestToken;
}
void ConnectionsManager::sendRequest(TLObject *object, onCompleteFunc onComplete, onQuickAckFunc onQuickAck, uint32_t flags, uint32_t datacenterId, ConnectionType connetionType, bool immediate, int32_t requestToken, jobject ptr1, jobject ptr2) { void ConnectionsManager::sendRequest(TLObject *object, onCompleteFunc onComplete, onQuickAckFunc onQuickAck, uint32_t flags, uint32_t datacenterId, ConnectionType connetionType, bool immediate, int32_t requestToken, jobject ptr1, jobject ptr2) {
if (!currentUserId && !(flags & RequestFlagWithoutLogin)) { if (!currentUserId && !(flags & RequestFlagWithoutLogin)) {
DEBUG_D("can't do request without login %s", typeid(*object).name()); DEBUG_D("can't do request without login %s", typeid(*object).name());
@ -1489,7 +1493,7 @@ void ConnectionsManager::cancelRequestInternal(int32_t token, bool notifyServer,
Request *request = iter->get(); Request *request = iter->get();
if (request->requestToken == token) { if (request->requestToken == token) {
request->cancelled = true; request->cancelled = true;
DEBUG_D("cancelled queued rpc request %s", typeid(*request->rawRequest).name()); DEBUG_D("cancelled queued rpc request %p - %s", request->rawRequest, typeid(*request->rawRequest).name());
requestsQueue.erase(iter); requestsQueue.erase(iter);
if (removeFromClass) { if (removeFromClass) {
removeRequestFromGuid(token); removeRequestFromGuid(token);
@ -1507,7 +1511,7 @@ void ConnectionsManager::cancelRequestInternal(int32_t token, bool notifyServer,
sendRequest(dropAnswer, nullptr, nullptr, RequestFlagEnableUnauthorized | RequestFlagWithoutLogin | RequestFlagFailOnServerErrors, request->datacenterId, request->connectionType, true); sendRequest(dropAnswer, nullptr, nullptr, RequestFlagEnableUnauthorized | RequestFlagWithoutLogin | RequestFlagFailOnServerErrors, request->datacenterId, request->connectionType, true);
} }
request->cancelled = true; request->cancelled = true;
DEBUG_D("cancelled running rpc request %s", typeid(*request->rawRequest).name()); DEBUG_D("cancelled running rpc request %p - %s", request->rawRequest, typeid(*request->rawRequest).name());
runningRequests.erase(iter); runningRequests.erase(iter);
if (removeFromClass) { if (removeFromClass) {
removeRequestFromGuid(token); removeRequestFromGuid(token);
@ -1795,7 +1799,12 @@ void ConnectionsManager::processRequestQueue(uint32_t connectionTypes, uint32_t
forceThisRequest = false; forceThisRequest = false;
} }
if (forceThisRequest || (abs(currentTime - request->startTime) > maxTimeout && (currentTime > request->minStartTime || abs(currentTime - request->minStartTime) > 60))) { if (forceThisRequest || (abs(currentTime - request->startTime) > maxTimeout &&
(currentTime >= request->minStartTime ||
(request->failedByFloodWait != 0 && (request->minStartTime - currentTime) > request->failedByFloodWait) ||
(request->failedByFloodWait == 0 && abs(currentTime - request->minStartTime) >= 60))
)
) {
if (!forceThisRequest && request->connectionToken > 0) { if (!forceThisRequest && request->connectionToken > 0) {
if (request->connectionType & ConnectionTypeGeneric && request->connectionToken == connection->getConnectionToken()) { if (request->connectionType & ConnectionTypeGeneric && request->connectionToken == connection->getConnectionToken()) {
DEBUG_D("request token is valid, not retrying %s", typeInfo.name()); DEBUG_D("request token is valid, not retrying %s", typeInfo.name());
@ -1816,25 +1825,29 @@ void ConnectionsManager::processRequestQueue(uint32_t connectionTypes, uint32_t
request->retryCount++; request->retryCount++;
if (!request->failedBySalt && request->connectionType & ConnectionTypeDownload) { if (!request->failedBySalt) {
uint32_t retryMax = 10; if (request->connectionType & ConnectionTypeDownload) {
if (!(request->requestFlags & RequestFlagForceDownload)) { uint32_t retryMax = 10;
if (request->failedByFloodWait) { if (!(request->requestFlags & RequestFlagForceDownload)) {
retryMax = 1; if (request->failedByFloodWait) {
} else { retryMax = 1;
retryMax = 6; } else {
retryMax = 6;
}
}
if (request->retryCount >= retryMax) {
DEBUG_E("timed out %s", typeInfo.name());
TL_error *error = new TL_error();
error->code = -123;
error->text = "RETRY_LIMIT";
request->onComplete(nullptr, error);
delete error;
iter = runningRequests.erase(iter);
continue;
} }
} }
if (request->retryCount >= retryMax) { } else {
DEBUG_E("timed out %s", typeInfo.name()); request->failedBySalt = false;
TL_error *error = new TL_error();
error->code = -123;
error->text = "RETRY_LIMIT";
request->onComplete(nullptr, error);
delete error;
iter = runningRequests.erase(iter);
continue;
}
} }
if (request->messageSeqNo == 0) { if (request->messageSeqNo == 0) {
@ -2103,9 +2116,11 @@ void ConnectionsManager::processRequestQueue(uint32_t connectionTypes, uint32_t
TL_invokeAfterMsg *request = new TL_invokeAfterMsg(); TL_invokeAfterMsg *request = new TL_invokeAfterMsg();
request->msg_id = lastSentMessageRpcId; request->msg_id = lastSentMessageRpcId;
if (message->outgoingBody != nullptr) { if (message->outgoingBody != nullptr) {
DEBUG_D("wrap outgoingBody(%p, %s) to TL_invokeAfterMsg", message->outgoingBody, typeid(*message->outgoingBody).name());
request->outgoingQuery = message->outgoingBody; request->outgoingQuery = message->outgoingBody;
message->outgoingBody = nullptr; message->outgoingBody = nullptr;
} else { } else {
DEBUG_D("wrap body(%p, %s) to TL_invokeAfterMsg", message->body.get(), typeid(*message->body.get()).name());
request->query = std::move(message->body); request->query = std::move(message->body);
} }
message->body = std::unique_ptr<TLObject>(request); message->body = std::unique_ptr<TLObject>(request);
@ -2407,7 +2422,7 @@ void ConnectionsManager::resumeNetwork(bool partial) {
if (partial) { if (partial) {
if (networkPaused) { if (networkPaused) {
lastPauseTime = getCurrentTimeMillis(); lastPauseTime = getCurrentTimeMillis();
nextSleepTimeout = 10000; nextSleepTimeout = 30000;
networkPaused = false; networkPaused = false;
DEBUG_D("wakeup network in background"); DEBUG_D("wakeup network in background");
} else if (lastPauseTime != 0) { } else if (lastPauseTime != 0) {

View File

@ -14,6 +14,7 @@
#include <functional> #include <functional>
#include <sys/epoll.h> #include <sys/epoll.h>
#include <map> #include <map>
#include <atomic>
#include <bits/unique_ptr.h> #include <bits/unique_ptr.h>
#include "Defines.h" #include "Defines.h"
@ -63,7 +64,6 @@ public:
void updateDcSettings(uint32_t datacenterId); void updateDcSettings(uint32_t datacenterId);
#ifdef ANDROID #ifdef ANDROID
int32_t sendRequest(TLObject *object, onCompleteFunc onComplete, onQuickAckFunc onQuickAck, uint32_t flags, uint32_t datacenterId, ConnectionType connetionType, bool immediate, jobject ptr1, jobject ptr2);
void sendRequest(TLObject *object, onCompleteFunc onComplete, onQuickAckFunc onQuickAck, uint32_t flags, uint32_t datacenterId, ConnectionType connetionType, bool immediate, int32_t requestToken, jobject ptr1, jobject ptr2); void sendRequest(TLObject *object, onCompleteFunc onComplete, onQuickAckFunc onQuickAck, uint32_t flags, uint32_t datacenterId, ConnectionType connetionType, bool immediate, int32_t requestToken, jobject ptr1, jobject ptr2);
static void useJavaVM(JavaVM *vm, bool useJavaByteBuffers); static void useJavaVM(JavaVM *vm, bool useJavaByteBuffers);
#endif #endif
@ -120,7 +120,7 @@ private:
std::map<int32_t, std::vector<std::int32_t>> quickAckIdToRequestIds; std::map<int32_t, std::vector<std::int32_t>> quickAckIdToRequestIds;
int32_t pingTime; int32_t pingTime;
bool testBackend = false; bool testBackend = false;
volatile uint32_t lastRequestToken = 1; std::atomic<uint32_t> lastRequestToken{1};
uint32_t currentDatacenterId = 0; uint32_t currentDatacenterId = 0;
uint32_t movingToDatacenterId = DEFAULT_DATACENTER_ID; uint32_t movingToDatacenterId = DEFAULT_DATACENTER_ID;
int64_t pushSessionId = 0; int64_t pushSessionId = 0;

View File

@ -668,9 +668,7 @@ void Datacenter::onHandshakeConnectionConnected(Connection *connection) {
if (handshakeState == 0 || !needResendData) { if (handshakeState == 0 || !needResendData) {
return; return;
} }
if (handshakeRequest != nullptr) { beginHandshake(false);
sendRequestData(handshakeRequest, true);
}
} }
inline uint64_t gcd(uint64_t a, uint64_t b) { inline uint64_t gcd(uint64_t a, uint64_t b) {
@ -1383,6 +1381,7 @@ NativeByteBuffer *Datacenter::createRequestsData(std::vector<std::unique_ptr<Net
int64_t currentTime = ConnectionsManager::getInstance().getCurrentTimeMillis() + (int64_t) timeDifference * 1000; int64_t currentTime = ConnectionsManager::getInstance().getCurrentTimeMillis() + (int64_t) timeDifference * 1000;
if (messageTime < currentTime - 30000 || messageTime > currentTime + 25000) { if (messageTime < currentTime - 30000 || messageTime > currentTime + 25000) {
DEBUG_D("wrap message in container");
TL_msg_container *messageContainer = new TL_msg_container(); TL_msg_container *messageContainer = new TL_msg_container();
messageContainer->messages.push_back(std::move(networkMessage->message)); messageContainer->messages.push_back(std::move(networkMessage->message));
@ -1395,6 +1394,7 @@ NativeByteBuffer *Datacenter::createRequestsData(std::vector<std::unique_ptr<Net
messageSeqNo = networkMessage->message->seqno; messageSeqNo = networkMessage->message->seqno;
} }
} else { } else {
DEBUG_D("start write messages to container");
TL_msg_container *messageContainer = new TL_msg_container(); TL_msg_container *messageContainer = new TL_msg_container();
size_t count = requests.size(); size_t count = requests.size();
for (uint32_t a = 0; a < count; a++) { for (uint32_t a = 0; a < count; a++) {

View File

@ -18,7 +18,9 @@
FILE *logFile = nullptr; FILE *logFile = nullptr;
void FileLog::init(std::string path) { void FileLog::init(std::string path) {
logFile = fopen(path.c_str(), "w"); if (path.size() > 0) {
logFile = fopen(path.c_str(), "w");
}
} }
void FileLog::e(const char *message, ...) { void FileLog::e(const char *message, ...) {

View File

@ -931,7 +931,7 @@ void TL_config::readParams(NativeByteBuffer *stream, bool &error) {
dc_options.push_back(std::unique_ptr<TL_dcOption>(object)); dc_options.push_back(std::unique_ptr<TL_dcOption>(object));
} }
chat_size_max = stream->readInt32(&error); chat_size_max = stream->readInt32(&error);
broadcast_size_max = stream->readInt32(&error); megagroup_size_max = stream->readInt32(&error);
forwarded_count_max = stream->readInt32(&error); forwarded_count_max = stream->readInt32(&error);
online_update_period_ms = stream->readInt32(&error); online_update_period_ms = stream->readInt32(&error);
offline_blur_timeout_ms = stream->readInt32(&error); offline_blur_timeout_ms = stream->readInt32(&error);
@ -971,7 +971,7 @@ void TL_config::serializeToStream(NativeByteBuffer *stream) {
dc_options[a]->serializeToStream(stream); dc_options[a]->serializeToStream(stream);
} }
stream->writeInt32(chat_size_max); stream->writeInt32(chat_size_max);
stream->writeInt32(broadcast_size_max); stream->writeInt32(megagroup_size_max);
stream->writeInt32(forwarded_count_max); stream->writeInt32(forwarded_count_max);
stream->writeInt32(online_update_period_ms); stream->writeInt32(online_update_period_ms);
stream->writeInt32(offline_blur_timeout_ms); stream->writeInt32(offline_blur_timeout_ms);

View File

@ -657,7 +657,7 @@ public:
class TL_config : public TLObject { class TL_config : public TLObject {
public: public:
static const uint32_t constructor = 0x4e32b894; static const uint32_t constructor = 0x6cb6e65e;
int32_t date; int32_t date;
int32_t expires; int32_t expires;
@ -665,7 +665,7 @@ public:
int32_t this_dc; int32_t this_dc;
std::vector<std::unique_ptr<TL_dcOption>> dc_options; std::vector<std::unique_ptr<TL_dcOption>> dc_options;
int32_t chat_size_max; int32_t chat_size_max;
int32_t broadcast_size_max; int32_t megagroup_size_max;
int32_t forwarded_count_max; int32_t forwarded_count_max;
int32_t online_update_period_ms; int32_t online_update_period_ms;
int32_t offline_blur_timeout_ms; int32_t offline_blur_timeout_ms;

View File

@ -34,7 +34,7 @@ public:
int32_t requestToken; int32_t requestToken;
uint32_t retryCount = 0; uint32_t retryCount = 0;
bool failedBySalt = false; bool failedBySalt = false;
bool failedByFloodWait = false; int32_t failedByFloodWait = 0;
ConnectionType connectionType; ConnectionType connectionType;
uint32_t requestFlags; uint32_t requestFlags;
bool completed = false; bool completed = false;

Binary file not shown.

View File

@ -43,7 +43,6 @@
android:allowBackup="false" android:allowBackup="false"
android:hardwareAccelerated="@bool/useHardwareAcceleration" android:hardwareAccelerated="@bool/useHardwareAcceleration"
android:icon="@drawable/ic_launcher" android:icon="@drawable/ic_launcher"
android:label="@string/AppName"
android:largeHeap="true" android:largeHeap="true"
android:theme="@style/Theme.TMessages.Start"> android:theme="@style/Theme.TMessages.Start">
@ -159,7 +158,7 @@
</service> </service>
<service <service
android:name=".TgChooserTargetService" android:name="org.telegram.messenger.TgChooserTargetService"
android:label="@string/AppName" android:label="@string/AppName"
android:permission="android.permission.BIND_CHOOSER_TARGET_SERVICE"> android:permission="android.permission.BIND_CHOOSER_TARGET_SERVICE">
<intent-filter> <intent-filter>

View File

@ -1,53 +1,53 @@
1876;JM;Jamaica 1876;JM;Jamaica;XXX XXXX
1869;KN;Saint Kitts & Nevis 1869;KN;Saint Kitts & Nevis;XXX XXXX
1868;TT;Trinidad & Tobago 1868;TT;Trinidad & Tobago;XXX XXXX
1784;VC;Saint Vincent & the Grenadines 1784;VC;Saint Vincent & the Grenadines;XXX XXXX
1767;DM;Dominica 1767;DM;Dominica;XXX XXXX
1758;LC;Saint Lucia 1758;LC;Saint Lucia;XXX XXXX
1721;SX;Sint Maarten 1721;SX;Sint Maarten;XXX XXXX
1684;AS;American Samoa 1684;AS;American Samoa;XXX XXXX
1671;GU;Guam 1671;GU;Guam;XXX XXXX
1670;MP;Northern Mariana Islands 1670;MP;Northern Mariana Islands;XXX XXXX
1664;MS;Montserrat 1664;MS;Montserrat;XXX XXXX
1649;TC;Turks & Caicos Islands 1649;TC;Turks & Caicos Islands;XXX XXXX
1473;GD;Grenada 1473;GD;Grenada;XXX XXXX
1441;BM;Bermuda 1441;BM;Bermuda;XXX XXXX
1345;KY;Cayman Islands 1345;KY;Cayman Islands;XXX XXXX
1340;VI;US Virgin Islands 1340;VI;US Virgin Islands;XXX XXXX
1284;VG;British Virgin Islands 1284;VG;British Virgin Islands;XXX XXXX
1268;AG;Antigua & Barbuda 1268;AG;Antigua & Barbuda;XXX XXXX
1264;AI;Anguilla 1264;AI;Anguilla;XXX XXXX
1246;BB;Barbados 1246;BB;Barbados;XXX XXXX
1242;BS;Bahamas 1242;BS;Bahamas;XXX XXXX
998;UZ;Uzbekistan 998;UZ;Uzbekistan;XX XXXXXXX
996;KG;Kyrgyzstan 996;KG;Kyrgyzstan;XXX XXXXXX
995;GE;Georgia 995;GE;Georgia;XXX XXX XXX
994;AZ;Azerbaijan 994;AZ;Azerbaijan;XX XXX XXXX
993;TM;Turkmenistan 993;TM;Turkmenistan;XX XXXXXX
992;TJ;Tajikistan 992;TJ;Tajikistan;XX XXX XXXX
977;NP;Nepal 977;NP;Nepal;XX XXXX XXXX
976;MN;Mongolia 976;MN;Mongolia;XX XX XXXX
975;BT;Bhutan 975;BT;Bhutan;XX XXX XXX
974;QA;Qatar 974;QA;Qatar;XX XXX XXX
973;BH;Bahrain 973;BH;Bahrain;XXXX XXXX
972;IL;Israel 972;IL;Israel;XX XXX XXXX
971;AE;United Arab Emirates 971;AE;United Arab Emirates;XX XXX XXXX
970;PS;Palestine 970;PS;Palestine;XXX XX XXXX
968;OM;Oman 968;OM;Oman;XXXX XXXX
967;YE;Yemen 967;YE;Yemen;XXX XXX XXX
966;SA;Saudi Arabia 966;SA;Saudi Arabia;XX XXX XXXX
965;KW;Kuwait 965;KW;Kuwait;XXXX XXXX
964;IQ;Iraq 964;IQ;Iraq;XXX XXX XXXX
963;SY;Syrian Arab Republic 963;SY;Syria;XXX XXX XXX
962;JO;Jordan 962;JO;Jordan;X XXXX XXXX
961;LB;Lebanon 961;LB;Lebanon
960;MV;Maldives 960;MV;Maldives;XXX XXXX
886;TW;Taiwan 886;TW;Taiwan;XXX XXX XXX
880;BD;Bangladesh 880;BD;Bangladesh
856;LA;Laos 856;LA;Laos;XX XX XXX XXX
855;KH;Cambodia 855;KH;Cambodia
853;MO;Macau 853;MO;Macau;XXXX XXXX
852;HK;Hong Kong 852;HK;Hong Kong;X XXX XXXX
850;KP;North Korea 850;KP;North Korea
692;MH;Marshall Islands 692;MH;Marshall Islands
691;FM;Micronesia 691;FM;Micronesia
@ -67,166 +67,166 @@
676;TO;Tonga 676;TO;Tonga
675;PG;Papua New Guinea 675;PG;Papua New Guinea
674;NR;Nauru 674;NR;Nauru
673;BN;Brunei Darussalam 673;BN;Brunei Darussalam;XXX XXXX
672;NF;Norfolk Island 672;NF;Norfolk Island
670;TL;Timor-Leste 670;TL;Timor-Leste
599;BQ;Bonaire, Sint Eustatius & Saba 599;BQ;Bonaire, Sint Eustatius & Saba
599;CW;Curaçao 599;CW;Curaçao
598;UY;Uruguay 598;UY;Uruguay;X XXX XXXX
597;SR;Suriname 597;SR;Suriname;XXX XXXX
596;MQ;Martinique 596;MQ;Martinique
595;PY;Paraguay 595;PY;Paraguay;XXX XXX XXX
594;GF;French Guiana 594;GF;French Guiana
593;EC;Ecuador 593;EC;Ecuador;XX XXX XXXX
592;GY;Guyana 592;GY;Guyana
591;BO;Bolivia 591;BO;Bolivia;X XXX XXXX
590;GP;Guadeloupe 590;GP;Guadeloupe;XXX XX XX XX
509;HT;Haiti 509;HT;Haiti
508;PM;Saint Pierre & Miquelon 508;PM;Saint Pierre & Miquelon
507;PA;Panama 507;PA;Panama;XXXX XXXX
506;CR;Costa Rica 506;CR;Costa Rica;XXXX XXXX
505;NI;Nicaragua 505;NI;Nicaragua;XXXX XXXX
504;HN;Honduras 504;HN;Honduras;XXXX XXXX
503;SV;El Salvador 503;SV;El Salvador;XXXX XXXX
502;GT;Guatemala 502;GT;Guatemala;X XXX XXXX
501;BZ;Belize 501;BZ;Belize
500;FK;Falkland Islands 500;FK;Falkland Islands
423;LI;Liechtenstein 423;LI;Liechtenstein
421;SK;Slovakia 421;SK;Slovakia;XXX XXX XXX
420;CZ;Czech Republic 420;CZ;Czech Republic;XXX XXX XXX
389;MK;Macedonia 389;MK;Macedonia;XX XXX XXX
387;BA;Bosnia & Herzegovina 387;BA;Bosnia & Herzegovina;XX XXX XXX
386;SI;Slovenia 386;SI;Slovenia;XX XXX XXX
385;HR;Croatia 385;HR;Croatia
382;ME;Montenegro 382;ME;Montenegro
381;RS;Serbia 381;RS;Serbia;XX XXX XXXX
380;UA;Ukraine 380;UA;Ukraine;XX XXX XX XX
378;SM;San Marino 378;SM;San Marino;XXX XXX XXXX
377;MC;Monaco 377;MC;Monaco;XXXX XXXX
376;AD;Andorra 376;AD;Andorra;XX XX XX
375;BY;Belarus 375;BY;Belarus;XX XXX XXXX
374;AM;Armenia 374;AM;Armenia;XX XXX XXX
373;MD;Moldova 373;MD;Moldova;XX XXX XXX
372;EE;Estonia 372;EE;Estonia
371;LV;Latvia 371;LV;Latvia;XXX XXXXX
370;LT;Lithuania 370;LT;Lithuania;XXX XXXXX
359;BG;Bulgaria 359;BG;Bulgaria
358;FI;Finland 358;FI;Finland
357;CY;Cyprus 357;CY;Cyprus;XXXX XXXX
356;MT;Malta 356;MT;Malta;XX XX XX XX
355;AL;Albania 355;AL;Albania;XX XXX XXXX
354;IS;Iceland 354;IS;Iceland;XXX XXXX
353;IE;Ireland 353;IE;Ireland;XX XXX XXXX
352;LU;Luxembourg 352;LU;Luxembourg
351;PT;Portugal 351;PT;Portugal;X XXXX XXXX
350;GI;Gibraltar 350;GI;Gibraltar;XXXX XXXX
299;GL;Greenland 299;GL;Greenland;XXX XXX
298;FO;Faroe Islands 298;FO;Faroe Islands;XXX XXX
297;AW;Aruba 297;AW;Aruba;XXX XXXX
291;ER;Eritrea 291;ER;Eritrea;X XXX XXX
290;SH;Saint Helena 290;SH;Saint Helena;XX XXX
269;KM;Comoros 269;KM;Comoros;XXX XXXX
268;SZ;Swaziland 268;SZ;Swaziland;XXXX XXXX
267;BW;Botswana 267;BW;Botswana;XX XXX XXX
266;LS;Lesotho 266;LS;Lesotho;XX XXX XXX
265;MW;Malawi 265;MW;Malawi;77 XXX XXXX
264;NA;Namibia 264;NA;Namibia;XX XXX XXXX
263;ZW;Zimbabwe 263;ZW;Zimbabwe;XX XXX XXXX
262;RE;Réunion 262;RE;Réunion;XXX XXX XXX
261;MG;Madagascar 261;MG;Madagascar;XX XX XXX XX
260;ZM;Zambia 260;ZM;Zambia;XX XXX XXXX
258;MZ;Mozambique 258;MZ;Mozambique;XX XXX XXXX
257;BI;Burundi 257;BI;Burundi;XX XX XXXX
256;UG;Uganda 256;UG;Uganda;XX XXX XXXX
255;TZ;Tanzania 255;TZ;Tanzania;XX XXX XXXX
254;KE;Kenya 254;KE;Kenya;XXX XXX XXX
253;DJ;Djibouti 253;DJ;Djibouti;XX XX XX XX
252;SO;Somalia 252;SO;Somalia;XX XXX XXX
251;ET;Ethiopia 251;ET;Ethiopia;XX XXX XXXX
250;RW;Rwanda 250;RW;Rwanda;XXX XXX XXX
249;SD;Sudan 249;SD;Sudan;XX XXX XXXX
248;SC;Seychelles 248;SC;Seychelles;X XX XX XX
247;SH;Saint Helena 247;SH;Saint Helena;XXXX
246;IO;Diego Garcia 246;IO;Diego Garcia;XXX XXXX
245;GW;Guinea-Bissau 245;GW;Guinea-Bissau;XXX XXXX
244;AO;Angola 244;AO;Angola;XXX XXX XXX
243;CD;Congo (Dem. Rep.) 243;CD;Congo (Dem. Rep.);XX XXX XXXX
242;CG;Congo (Rep.) 242;CG;Congo (Rep.);XX XXX XXXX
241;GA;Gabon 241;GA;Gabon;X XX XX XX
240;GQ;Equatorial Guinea 240;GQ;Equatorial Guinea;XXX XXX XXX
239;ST;São Tomé & Príncipe 239;ST;São Tomé & Príncipe;XX XXXXX
238;CV;Cape Verde 238;CV;Cape Verde;XXX XXXX
237;CM;Cameroon 237;CM;Cameroon;XXXX XXXX
236;CF;Central African Rep. 236;CF;Central African Rep.;XX XX XX XX
235;TD;Chad 235;TD;Chad;XX XX XX XX
234;NG;Nigeria 234;NG;Nigeria
233;GH;Ghana 233;GH;Ghana
232;SL;Sierra Leone 232;SL;Sierra Leone;XX XXX XXX
231;LR;Liberia 231;LR;Liberia
230;MU;Mauritius 230;MU;Mauritius
229;BJ;Benin 229;BJ;Benin;XX XXX XXX
228;TG;Togo 228;TG;Togo;XX XXX XXX
227;NE;Niger 227;NE;Niger;XX XX XX XX
226;BF;Burkina Faso 226;BF;Burkina Faso;XX XX XX XX
225;CI;Côte d`Ivoire 225;CI;Côte d`Ivoire;XX XXX XXX
224;GN;Guinea 224;GN;Guinea;XXX XXX XXX
223;ML;Mali 223;ML;Mali;XXXX XXXX
222;MR;Mauritania 222;MR;Mauritania;XXXX XXXX
221;SN;Senegal 221;SN;Senegal;XX XXX XXXX
220;GM;Gambia 220;GM;Gambia;XXX XXXX
218;LY;Libya 218;LY;Libya;XX XXX XXXX
216;TN;Tunisia 216;TN;Tunisia;XX XXX XXX
213;DZ;Algeria 213;DZ;Algeria;XXX XX XX XX
212;MA;Morocco 212;MA;Morocco;XX XXX XXXX
211;SS;South Sudan 211;SS;South Sudan;XX XXX XXXX
98;IR;Iran 98;IR;Iran;XXX XXX XXXX
95;MM;Myanmar 95;MM;Myanmar
94;LK;Sri Lanka 94;LK;Sri Lanka;XX XXX XXXX
93;AF;Afghanistan 93;AF;Afghanistan;XXX XXX XXX
92;PK;Pakistan 92;PK;Pakistan;XXX XXX XXXX
91;IN;India 91;IN;India;XXXXX XXXXX
90;TR;Turkey 90;TR;Turkey;XXX XXX XXXX
86;CN;China 86;CN;China;XXX XXXX XXXX
84;VN;Vietnam 84;VN;Vietnam
82;KR;South Korea 82;KR;South Korea
81;JP;Japan 81;JP;Japan;XX XXXX XXXX
66;TH;Thailand 66;TH;Thailand;X XXXX XXXX
65;SG;Singapore 65;SG;Singapore;XXXX XXXX
64;NZ;New Zealand 64;NZ;New Zealand
63;PH;Philippines 63;PH;Philippines;XXX XXX XXXX
62;ID;Indonesia 62;ID;Indonesia
61;AU;Australia 61;AU;Australia;XXX XXX XXX
60;MY;Malaysia 60;MY;Malaysia
58;VE;Venezuela 58;VE;Venezuela;XXX XXX XXXX
57;CO;Colombia 57;CO;Colombia;XXX XXX XXXX
56;CL;Chile 56;CL;Chile;X XXXX XXXX
55;BR;Brazil 55;BR;Brazil;XX XXXXX XXXX
54;AR;Argentina 54;AR;Argentina
53;CU;Cuba 53;CU;Cuba;XXXX XXXX
52;MX;Mexico 52;MX;Mexico
51;PE;Peru 51;PE;Peru;XXX XXX XXX
49;DE;Germany 49;DE;Germany
48;PL;Poland 48;PL;Poland;XX XXX XXXX
47;NO;Norway 47;NO;Norway;XXXX XXXX
46;SE;Sweden 46;SE;Sweden;XX XXX XXXX
45;DK;Denmark 45;DK;Denmark;XXXX XXXX
44;GB;United Kingdom 44;GB;United Kingdom;XXXX XXXXXX
43;AT;Austria 43;AT;Austria
42;YL;Y-land 42;YL;Y-land
41;CH;Switzerland 41;CH;Switzerland;XX XXX XXXX
40;RO;Romania 40;RO;Romania;XXX XXX XXX
39;IT;Italy 39;IT;Italy
36;HU;Hungary 36;HU;Hungary;XXX XXX XXX
34;ES;Spain 34;ES;Spain;XXX XXX XXX
33;FR;France 33;FR;France;X XX XX XX XX
32;BE;Belgium 32;BE;Belgium;XXX XX XX XX
31;NL;Netherlands 31;NL;Netherlands;X XX XX XX XX
30;GR;Greece 30;GR;Greece;XXX XXX XXXX
27;ZA;South Africa 27;ZA;South Africa;XX XXX XXXX
20;EG;Egypt 20;EG;Egypt;XX XXXX XXXX
7;KZ;Kazakhstan 7;KZ;Kazakhstan;XXX XXX XX XX
7;RU;Russian Federation 7;RU;Russian Federation;XXX XXX XXXX
1;PR;Puerto Rico 1;PR;Puerto Rico;XXX XXX XXXX
1;DO;Dominican Rep. 1;DO;Dominican Rep.;XXX XXX XXXX
1;CA;Canada 1;CA;Canada;XXX XXX XXXX
1;US;USA 1;US;USA;XXX XXX XXXX

View File

@ -75,6 +75,7 @@ import java.util.ArrayList;
import java.util.Date; import java.util.Date;
import java.util.Hashtable; import java.util.Hashtable;
import java.util.Locale; import java.util.Locale;
import java.util.regex.Pattern;
public class AndroidUtilities { public class AndroidUtilities {
@ -93,6 +94,36 @@ public class AndroidUtilities {
private static Boolean isTablet = null; private static Boolean isTablet = null;
private static int adjustOwnerClassGuid = 0; private static int adjustOwnerClassGuid = 0;
public static Pattern WEB_URL = null;
static {
try {
final String GOOD_IRI_CHAR = "a-zA-Z0-9\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF";
final Pattern IP_ADDRESS = Pattern.compile(
"((25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}|[1-9][0-9]|[1-9])\\.(25[0-5]|2[0-4]"
+ "[0-9]|[0-1][0-9]{2}|[1-9][0-9]|[1-9]|0)\\.(25[0-5]|2[0-4][0-9]|[0-1]"
+ "[0-9]{2}|[1-9][0-9]|[1-9]|0)\\.(25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}"
+ "|[1-9][0-9]|[0-9]))");
final String IRI = "[" + GOOD_IRI_CHAR + "]([" + GOOD_IRI_CHAR + "\\-]{0,61}[" + GOOD_IRI_CHAR + "]){0,1}";
final String GOOD_GTLD_CHAR = "a-zA-Z\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF";
final String GTLD = "[" + GOOD_GTLD_CHAR + "]{2,63}";
final String HOST_NAME = "(" + IRI + "\\.)+" + GTLD;
final Pattern DOMAIN_NAME = Pattern.compile("(" + HOST_NAME + "|" + IP_ADDRESS + ")");
WEB_URL = Pattern.compile(
"((?:(http|https|Http|Https):\\/\\/(?:(?:[a-zA-Z0-9\\$\\-\\_\\.\\+\\!\\*\\'\\(\\)"
+ "\\,\\;\\?\\&\\=]|(?:\\%[a-fA-F0-9]{2})){1,64}(?:\\:(?:[a-zA-Z0-9\\$\\-\\_"
+ "\\.\\+\\!\\*\\'\\(\\)\\,\\;\\?\\&\\=]|(?:\\%[a-fA-F0-9]{2})){1,25})?\\@)?)?"
+ "(?:" + DOMAIN_NAME + ")"
+ "(?:\\:\\d{1,5})?)" // plus option port number
+ "(\\/(?:(?:[" + GOOD_IRI_CHAR + "\\;\\/\\?\\:\\@\\&\\=\\#\\~" // plus option query params
+ "\\-\\.\\+\\!\\*\\'\\(\\)\\,\\_])|(?:\\%[a-fA-F0-9]{2}))*)?"
+ "(?:\\b|$)");
} catch (Exception e) {
FileLog.e("tmessages", e);
}
}
static { static {
density = ApplicationLoader.applicationContext.getResources().getDisplayMetrics().density; density = ApplicationLoader.applicationContext.getResources().getDisplayMetrics().density;
leftBaseline = isTablet() ? 80 : 72; leftBaseline = isTablet() ? 80 : 72;
@ -735,7 +766,7 @@ public class AndroidUtilities {
}*/ }*/
public static void checkForCrashes(Activity context) { public static void checkForCrashes(Activity context) {
CrashManager.register(context, BuildVars.HOCKEY_APP_HASH, new CrashManagerListener() { CrashManager.register(context, BuildVars.DEBUG_VERSION ? BuildVars.HOCKEY_APP_HASH_DEBUG : BuildVars.HOCKEY_APP_HASH, new CrashManagerListener() {
@Override @Override
public boolean includeDeviceData() { public boolean includeDeviceData() {
return true; return true;
@ -745,7 +776,7 @@ public class AndroidUtilities {
public static void checkForUpdates(Activity context) { public static void checkForUpdates(Activity context) {
if (BuildVars.DEBUG_VERSION) { if (BuildVars.DEBUG_VERSION) {
UpdateManager.register(context, BuildVars.HOCKEY_APP_HASH); UpdateManager.register(context, BuildVars.DEBUG_VERSION ? BuildVars.HOCKEY_APP_HASH_DEBUG : BuildVars.HOCKEY_APP_HASH);
} }
} }

View File

@ -327,18 +327,23 @@ public class ApplicationLoader extends Application {
} }
private void initPlayServices() { private void initPlayServices() {
if (checkPlayServices()) { AndroidUtilities.runOnUIThread(new Runnable() {
gcm = GoogleCloudMessaging.getInstance(this); @Override
regid = getRegistrationId(); public void run() {
if (checkPlayServices()) {
gcm = GoogleCloudMessaging.getInstance(ApplicationLoader.this);
regid = getRegistrationId();
if (regid.length() == 0) { if (regid.length() == 0) {
registerInBackground(); registerInBackground();
} else { } else {
sendRegistrationIdToBackend(false); sendRegistrationIdToBackend(false);
}
} else {
FileLog.d("tmessages", "No valid Google Play Services APK found.");
}
} }
} else { }, 1000);
FileLog.d("tmessages", "No valid Google Play Services APK found.");
}
} }
private boolean checkPlayServices() { private boolean checkPlayServices() {

View File

@ -21,6 +21,6 @@ public class AutoMessageHeardReceiver extends BroadcastReceiver {
if (dialog_id == 0 || max_id == 0) { if (dialog_id == 0 || max_id == 0) {
return; return;
} }
MessagesController.getInstance().markDialogAsRead(dialog_id, max_id, max_id, 0, 0, true, false); MessagesController.getInstance().markDialogAsRead(dialog_id, max_id, max_id, 0, true, false);
} }
} }

View File

@ -32,6 +32,6 @@ public class AutoMessageReplyReceiver extends BroadcastReceiver {
return; return;
} }
SendMessagesHelper.getInstance().sendMessage(text.toString(), dialog_id, null, null, true, false); SendMessagesHelper.getInstance().sendMessage(text.toString(), dialog_id, null, null, true, false);
MessagesController.getInstance().markDialogAsRead(dialog_id, max_id, max_id, 0, 0, true, false); MessagesController.getInstance().markDialogAsRead(dialog_id, max_id, max_id, 0, true, false);
} }
} }

View File

@ -10,10 +10,11 @@ package org.telegram.messenger;
public class BuildVars { public class BuildVars {
public static boolean DEBUG_VERSION = false; public static boolean DEBUG_VERSION = false;
public static int BUILD_VERSION = 654; public static int BUILD_VERSION = 685;
public static int APP_ID = 0; //obtain your own APP_ID at https://core.telegram.org/api/obtaining_api_id public static int APP_ID = 0; //obtain your own APP_ID at https://core.telegram.org/api/obtaining_api_id
public static String APP_HASH = ""; //obtain your own APP_HASH at https://core.telegram.org/api/obtaining_api_id public static String APP_HASH = ""; //obtain your own APP_HASH at https://core.telegram.org/api/obtaining_api_id
public static String HOCKEY_APP_HASH = "your-hockeyapp-api-key-here"; public static String HOCKEY_APP_HASH = "your-hockeyapp-api-key-here";
public static String HOCKEY_APP_HASH_DEBUG = "your-hockeyapp-api-key-here";
public static String GCM_SENDER_ID = "760348033672"; public static String GCM_SENDER_ID = "760348033672";
public static String SEND_LOGS_EMAIL = "email@gmail.com"; public static String SEND_LOGS_EMAIL = "email@gmail.com";
public static String BING_SEARCH_KEY = ""; //obtain your own KEY at https://www.bing.com/dev/en-us/dev-center public static String BING_SEARCH_KEY = ""; //obtain your own KEY at https://www.bing.com/dev/en-us/dev-center

View File

@ -16,17 +16,18 @@ public class ChatObject {
public static final int CHAT_TYPE_BROADCAST = 1; public static final int CHAT_TYPE_BROADCAST = 1;
public static final int CHAT_TYPE_CHANNEL = 2; public static final int CHAT_TYPE_CHANNEL = 2;
public static final int CHAT_TYPE_USER = 3; public static final int CHAT_TYPE_USER = 3;
public static final int CHAT_TYPE_MEGAGROUP = 4;
public static boolean isLeftFromChat(TLRPC.Chat chat) { public static boolean isLeftFromChat(TLRPC.Chat chat) {
return chat == null || chat instanceof TLRPC.TL_chatForbidden || chat instanceof TLRPC.TL_channelForbidden || (chat.flags & TLRPC.CHAT_FLAG_USER_LEFT) != 0; return chat == null || chat instanceof TLRPC.TL_chatEmpty || chat instanceof TLRPC.TL_chatForbidden || chat instanceof TLRPC.TL_channelForbidden || chat.left || chat.deactivated;
} }
public static boolean isKickedFromChat(TLRPC.Chat chat) { public static boolean isKickedFromChat(TLRPC.Chat chat) {
return chat == null || chat instanceof TLRPC.TL_chatForbidden || chat instanceof TLRPC.TL_channelForbidden || (chat.flags & TLRPC.CHAT_FLAG_USER_KICKED) != 0; return chat == null || chat instanceof TLRPC.TL_chatEmpty || chat instanceof TLRPC.TL_chatForbidden || chat instanceof TLRPC.TL_channelForbidden || chat.kicked || chat.deactivated;
} }
public static boolean isNotInChat(TLRPC.Chat chat) { public static boolean isNotInChat(TLRPC.Chat chat) {
return chat == null || chat instanceof TLRPC.TL_chatForbidden || chat instanceof TLRPC.TL_channelForbidden || (chat.flags & TLRPC.CHAT_FLAG_USER_LEFT) != 0 || (chat.flags & TLRPC.CHAT_FLAG_USER_KICKED) != 0; return chat == null || chat instanceof TLRPC.TL_chatEmpty || chat instanceof TLRPC.TL_chatForbidden || chat instanceof TLRPC.TL_channelForbidden || chat.left || chat.kicked || chat.deactivated;
} }
public static boolean isChannel(TLRPC.Chat chat) { public static boolean isChannel(TLRPC.Chat chat) {
@ -40,11 +41,11 @@ public class ChatObject {
public static boolean isCanWriteToChannel(int chatId) { public static boolean isCanWriteToChannel(int chatId) {
TLRPC.Chat chat = MessagesController.getInstance().getChat(chatId); TLRPC.Chat chat = MessagesController.getInstance().getChat(chatId);
return chat != null && ((chat.flags & TLRPC.CHAT_FLAG_ADMIN) != 0 || (chat.flags & TLRPC.CHAT_FLAG_USER_IS_EDITOR) != 0); return chat != null && (chat.creator || chat.editor || chat.megagroup);
} }
public static boolean canWriteToChat(TLRPC.Chat chat) { public static boolean canWriteToChat(TLRPC.Chat chat) {
return !isChannel(chat) || (chat.flags & TLRPC.CHAT_FLAG_ADMIN) != 0 || (chat.flags & TLRPC.CHAT_FLAG_USER_IS_EDITOR) != 0 || (chat.flags & TLRPC.CHAT_FLAG_IS_BROADCAST) == 0; return !isChannel(chat) || chat.creator || chat.editor || !chat.broadcast;
} }
public static TLRPC.Chat getChatByDialog(long did) { public static TLRPC.Chat getChatByDialog(long did) {

View File

@ -208,8 +208,8 @@ public class ContactsController {
try { try {
accounts = am.getAccountsByType("org.telegram.account"); accounts = am.getAccountsByType("org.telegram.account");
if (accounts != null && accounts.length > 0) { if (accounts != null && accounts.length > 0) {
for (Account c : accounts) { for (int a = 0; a < accounts.length; a++) {
am.removeAccount(c, null, null); am.removeAccount(accounts[a], null, null);
} }
} }
} catch (Exception e) { } catch (Exception e) {
@ -221,7 +221,7 @@ public class ContactsController {
if (UserConfig.isClientActivated()) { if (UserConfig.isClientActivated()) {
if (accounts.length == 1) { if (accounts.length == 1) {
Account acc = accounts[0]; Account acc = accounts[0];
if (!acc.name.equals(UserConfig.getCurrentUser().phone)) { if (!acc.name.equals("" + UserConfig.getClientUserId())) {
recreateAccount = true; recreateAccount = true;
} else { } else {
currentAccount = acc; currentAccount = acc;
@ -236,12 +236,16 @@ public class ContactsController {
} }
} }
if (recreateAccount) { if (recreateAccount) {
for (Account c : accounts) { try {
am.removeAccount(c, null, null); for (int a = 0; a < accounts.length; a++) {
am.removeAccount(accounts[a], null, null);
}
} catch (Exception e) {
FileLog.e("tmessages", e);
} }
if (UserConfig.isClientActivated()) { if (UserConfig.isClientActivated()) {
try { try {
currentAccount = new Account(UserConfig.getCurrentUser().phone, "org.telegram.messenger"); currentAccount = new Account("" + UserConfig.getClientUserId(), "org.telegram.messenger");
am.addAccountExplicitly(currentAccount, "", null); am.addAccountExplicitly(currentAccount, "", null);
} catch (Exception e) { } catch (Exception e) {
FileLog.e("tmessages", e); FileLog.e("tmessages", e);
@ -254,8 +258,8 @@ public class ContactsController {
try { try {
AccountManager am = AccountManager.get(ApplicationLoader.applicationContext); AccountManager am = AccountManager.get(ApplicationLoader.applicationContext);
Account[] accounts = am.getAccountsByType("org.telegram.messenger"); Account[] accounts = am.getAccountsByType("org.telegram.messenger");
for (Account c : accounts) { for (int a = 0; a < accounts.length; a++) {
am.removeAccount(c, null, null); am.removeAccount(accounts[a], null, null);
} }
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
@ -277,7 +281,7 @@ public class ContactsController {
private boolean checkContactsInternal() { private boolean checkContactsInternal() {
boolean reload = false; boolean reload = false;
try { try {
if (Build.VERSION.SDK_INT >= 23 && ApplicationLoader.applicationContext.checkSelfPermission(android.Manifest.permission.READ_CONTACTS) != PackageManager.PERMISSION_GRANTED) { if (!hasContactsPermission()) {
return false; return false;
} }
ContentResolver cr = ApplicationLoader.applicationContext.getContentResolver(); ContentResolver cr = ApplicationLoader.applicationContext.getContentResolver();
@ -334,7 +338,7 @@ public class ContactsController {
private HashMap<Integer, Contact> readContactsFromPhoneBook() { private HashMap<Integer, Contact> readContactsFromPhoneBook() {
HashMap<Integer, Contact> contactsMap = new HashMap<>(); HashMap<Integer, Contact> contactsMap = new HashMap<>();
try { try {
if (Build.VERSION.SDK_INT >= 23 && ApplicationLoader.applicationContext.checkSelfPermission(android.Manifest.permission.READ_CONTACTS) != PackageManager.PERMISSION_GRANTED) { if (!hasContactsPermission()) {
return contactsMap; return contactsMap;
} }
ContentResolver cr = ApplicationLoader.applicationContext.getContentResolver(); ContentResolver cr = ApplicationLoader.applicationContext.getContentResolver();
@ -1044,7 +1048,7 @@ public class ContactsController {
sortedSectionsArray.add(key); sortedSectionsArray.add(key);
} }
arr.add(value); arr.add(value);
if ((user.flags & TLRPC.USER_FLAG_MUTUAL_CONTACT) != 0) { if (user.mutual_contact) {
arr = sectionsDictMutual.get(key); arr = sectionsDictMutual.get(key);
if (arr == null) { if (arr == null) {
arr = new ArrayList<>(); arr = new ArrayList<>();
@ -1280,9 +1284,34 @@ public class ContactsController {
sortedUsersSectionsArray = sortedSectionsArray; sortedUsersSectionsArray = sortedSectionsArray;
} }
private boolean hasContactsPermission() {
if (Build.VERSION.SDK_INT >= 23) {
return ApplicationLoader.applicationContext.checkSelfPermission(android.Manifest.permission.READ_CONTACTS) == PackageManager.PERMISSION_GRANTED;
}
Cursor cursor = null;
try {
ContentResolver cr = ApplicationLoader.applicationContext.getContentResolver();
cursor = cr.query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, projectionPhones, null, null, null);
if (cursor == null || cursor.getCount() == 0) {
return false;
}
} catch (Exception e) {
FileLog.e("tmessages", e);
} finally {
try {
if (cursor != null) {
cursor.close();
}
} catch (Exception e) {
FileLog.e("tmessages", e);
}
}
return true;
}
private void performWriteContactsToPhoneBookInternal(ArrayList<TLRPC.TL_contact> contactsArray) { private void performWriteContactsToPhoneBookInternal(ArrayList<TLRPC.TL_contact> contactsArray) {
try { try {
if (Build.VERSION.SDK_INT >= 23 && ApplicationLoader.applicationContext.checkSelfPermission(android.Manifest.permission.READ_CONTACTS) != PackageManager.PERMISSION_GRANTED) { if (!hasContactsPermission()) {
return; return;
} }
Uri rawContactUri = ContactsContract.RawContacts.CONTENT_URI.buildUpon().appendQueryParameter(ContactsContract.RawContacts.ACCOUNT_NAME, currentAccount.name).appendQueryParameter(ContactsContract.RawContacts.ACCOUNT_TYPE, currentAccount.type).build(); Uri rawContactUri = ContactsContract.RawContacts.CONTENT_URI.buildUpon().appendQueryParameter(ContactsContract.RawContacts.ACCOUNT_NAME, currentAccount.name).appendQueryParameter(ContactsContract.RawContacts.ACCOUNT_TYPE, currentAccount.type).build();
@ -1294,7 +1323,8 @@ public class ContactsController {
} }
c1.close(); c1.close();
for (TLRPC.TL_contact u : contactsArray) { for (int a = 0; a < contactsArray.size(); a++) {
TLRPC.TL_contact u = contactsArray.get(a);
if (!bookContacts.containsKey(u.user_id)) { if (!bookContacts.containsKey(u.user_id)) {
TLRPC.User user = MessagesController.getInstance().getUser(u.user_id); TLRPC.User user = MessagesController.getInstance().getUser(u.user_id);
addContactToPhoneBook(user, false); addContactToPhoneBook(user, false);
@ -1486,7 +1516,7 @@ public class ContactsController {
if (currentAccount == null || user == null || user.phone == null || user.phone.length() == 0) { if (currentAccount == null || user == null || user.phone == null || user.phone.length() == 0) {
return -1; return -1;
} }
if (Build.VERSION.SDK_INT >= 23 && ApplicationLoader.applicationContext.checkSelfPermission(android.Manifest.permission.READ_CONTACTS) != PackageManager.PERMISSION_GRANTED) { if (!hasContactsPermission()) {
return -1; return -1;
} }
long res = -1; long res = -1;
@ -1536,7 +1566,9 @@ public class ContactsController {
query.add(builder.build()); query.add(builder.build());
try { try {
ContentProviderResult[] result = contentResolver.applyBatch(ContactsContract.AUTHORITY, query); ContentProviderResult[] result = contentResolver.applyBatch(ContactsContract.AUTHORITY, query);
res = Long.parseLong(result[0].uri.getLastPathSegment()); if (result != null && result.length > 0 && result[0].uri != null) {
res = Long.parseLong(result[0].uri.getLastPathSegment());
}
} catch (Exception e) { } catch (Exception e) {
FileLog.e("tmessages", e); FileLog.e("tmessages", e);
} }
@ -1547,7 +1579,7 @@ public class ContactsController {
} }
private void deleteContactFromPhoneBook(int uid) { private void deleteContactFromPhoneBook(int uid) {
if (Build.VERSION.SDK_INT >= 23 && ApplicationLoader.applicationContext.checkSelfPermission(android.Manifest.permission.READ_CONTACTS) != PackageManager.PERMISSION_GRANTED) { if (!hasContactsPermission()) {
return; return;
} }
synchronized (observerLock) { synchronized (observerLock) {

View File

@ -12,9 +12,12 @@ import android.os.Handler;
import android.os.Looper; import android.os.Looper;
import android.os.Message; import android.os.Message;
import java.util.concurrent.CountDownLatch;
public class DispatchQueue extends Thread { public class DispatchQueue extends Thread {
public volatile Handler handler = null;
private final Object handlerSyncObject = new Object(); private volatile Handler handler = null;
private CountDownLatch syncLatch = new CountDownLatch(1);
public DispatchQueue(final String threadName) { public DispatchQueue(final String threadName) {
setName(threadName); setName(threadName);
@ -22,40 +25,24 @@ public class DispatchQueue extends Thread {
} }
private void sendMessage(Message msg, int delay) { private void sendMessage(Message msg, int delay) {
if (handler == null) { try {
try { syncLatch.await();
synchronized (handlerSyncObject) {
handlerSyncObject.wait();
}
} catch (Throwable t) {
t.printStackTrace();
}
}
if (handler != null) {
if (delay <= 0) { if (delay <= 0) {
handler.sendMessage(msg); handler.sendMessage(msg);
} else { } else {
handler.sendMessageDelayed(msg, delay); handler.sendMessageDelayed(msg, delay);
} }
} catch (Exception e) {
FileLog.e("tmessages", e);
} }
} }
public void cancelRunnable(Runnable runnable) { public void cancelRunnable(Runnable runnable) {
if (handler == null) { try {
synchronized (handlerSyncObject) { syncLatch.await();
if (handler == null) {
try {
handlerSyncObject.wait();
} catch (Throwable t) {
t.printStackTrace();
}
}
}
}
if (handler != null) {
handler.removeCallbacks(runnable); handler.removeCallbacks(runnable);
} catch (Exception e) {
FileLog.e("tmessages", e);
} }
} }
@ -64,39 +51,32 @@ public class DispatchQueue extends Thread {
} }
public void postRunnable(Runnable runnable, long delay) { public void postRunnable(Runnable runnable, long delay) {
if (handler == null) { try {
synchronized (handlerSyncObject) { syncLatch.await();
if (handler == null) {
try {
handlerSyncObject.wait();
} catch (Throwable t) {
t.printStackTrace();
}
}
}
}
if (handler != null) {
if (delay <= 0) { if (delay <= 0) {
handler.post(runnable); handler.post(runnable);
} else { } else {
handler.postDelayed(runnable, delay); handler.postDelayed(runnable, delay);
} }
} catch (Exception e) {
FileLog.e("tmessages", e);
} }
} }
public void cleanupQueue() { public void cleanupQueue() {
if (handler != null) { try {
syncLatch.await();
handler.removeCallbacksAndMessages(null); handler.removeCallbacksAndMessages(null);
} catch (Exception e) {
FileLog.e("tmessages", e);
} }
} }
@Override
public void run() { public void run() {
Looper.prepare(); Looper.prepare();
synchronized (handlerSyncObject) { handler = new Handler();
handler = new Handler(); syncLatch.countDown();
handlerSyncObject.notify();
}
Looper.loop(); Looper.loop();
} }
} }

View File

@ -266,10 +266,7 @@ public class Emoji {
} }
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.save(); canvas.drawBitmap(emojiBmp[info.page][info.page2], info.rect, b, paint);
canvas.clipRect(b);
canvas.drawBitmap(emojiBmp[info.page][info.page2], info.rect, b, fullSize ? null : paint);
canvas.restore();
} }
} }

View File

@ -468,7 +468,7 @@ public class FileLoadOperation {
delegate.didFailedLoadingFile(FileLoadOperation.this, 2); delegate.didFailedLoadingFile(FileLoadOperation.this, 2);
} else { } else {
if (location != null) { if (location != null) {
FileLog.e("tmessages", "" + location + " id = " + location.id + " access_hash = " + location.access_hash + " volume_id = " + location.local_id + " secret = " + location.secret); FileLog.e("tmessages", "" + location + " id = " + location.id + " local_id = " + location.local_id + " access_hash = " + location.access_hash + " volume_id = " + location.volume_id + " secret = " + location.secret);
} }
cleanup(); cleanup();
delegate.didFailedLoadingFile(FileLoadOperation.this, 0); delegate.didFailedLoadingFile(FileLoadOperation.this, 0);

View File

@ -753,7 +753,8 @@ public class FileLoader {
fileLoaderQueue.postRunnable(new Runnable() { fileLoaderQueue.postRunnable(new Runnable() {
@Override @Override
public void run() { public void run() {
for (File file : files) { for (int a = 0; a < files.size(); a++) {
File file = files.get(a);
if (file.exists()) { if (file.exists()) {
try { try {
if (!file.delete()) { if (!file.delete()) {
@ -763,6 +764,16 @@ public class FileLoader {
FileLog.e("tmessages", e); FileLog.e("tmessages", e);
} }
} }
try {
File qFile = new File(file.getPath(), "q_" + file.getName());
if (qFile.exists()) {
if (!file.delete()) {
file.deleteOnExit();
}
}
} catch (Exception e) {
FileLog.e("tmessages", e);
}
} }
} }
}); });

View File

@ -67,6 +67,9 @@ public class FileLog {
} }
public static String getNetworkLogPath() { public static String getNetworkLogPath() {
if (!BuildVars.DEBUG_VERSION) {
return "";
}
try { try {
File sdCard = ApplicationLoader.applicationContext.getExternalFilesDir(null); File sdCard = ApplicationLoader.applicationContext.getExternalFilesDir(null);
if (sdCard == null) { if (sdCard == null) {

View File

@ -75,7 +75,7 @@ public class ImageLoader {
private HashMap<String, Runnable> retryHttpsTasks = new HashMap<>(); private HashMap<String, Runnable> retryHttpsTasks = new HashMap<>();
private int currentHttpFileLoadTasksCount = 0; private int currentHttpFileLoadTasksCount = 0;
protected VMRuntimeHack runtimeHack = null; public VMRuntimeHack runtimeHack = null;
private String ignoreRemoval = null; private String ignoreRemoval = null;
private volatile long lastCacheOutTime = 0; private volatile long lastCacheOutTime = 0;
@ -1162,7 +1162,18 @@ public class ImageLoader {
FileLog.e("tmessages", "file system changed"); FileLog.e("tmessages", "file system changed");
Runnable r = new Runnable() { Runnable r = new Runnable() {
public void run() { public void run() {
FileLoader.getInstance().setMediaDirs(createMediaPaths()); cacheOutQueue.postRunnable(new Runnable() {
@Override
public void run() {
final HashMap<Integer, File> paths = createMediaPaths();
AndroidUtilities.runOnUIThread(new Runnable() {
@Override
public void run() {
FileLoader.getInstance().setMediaDirs(paths);
}
});
}
});
} }
}; };
if (Intent.ACTION_MEDIA_UNMOUNTED.equals(intent.getAction())) { if (Intent.ACTION_MEDIA_UNMOUNTED.equals(intent.getAction())) {
@ -1186,7 +1197,35 @@ public class ImageLoader {
filter.addDataScheme("file"); filter.addDataScheme("file");
ApplicationLoader.applicationContext.registerReceiver(receiver, filter); ApplicationLoader.applicationContext.registerReceiver(receiver, filter);
FileLoader.getInstance().setMediaDirs(createMediaPaths()); HashMap<Integer, File> mediaDirs = new HashMap<>();
File cachePath = AndroidUtilities.getCacheDir();
if (!cachePath.isDirectory()) {
try {
cachePath.mkdirs();
} catch (Exception e) {
FileLog.e("tmessages", e);
}
}
try {
new File(cachePath, ".nomedia").createNewFile();
} catch (Exception e) {
FileLog.e("tmessages", e);
}
mediaDirs.put(FileLoader.MEDIA_DIR_CACHE, cachePath);
FileLoader.getInstance().setMediaDirs(mediaDirs);
cacheOutQueue.postRunnable(new Runnable() {
@Override
public void run() {
final HashMap<Integer, File> paths = createMediaPaths();
AndroidUtilities.runOnUIThread(new Runnable() {
@Override
public void run() {
FileLoader.getInstance().setMediaDirs(paths);
}
});
}
});
} }
public HashMap<Integer, File> createMediaPaths() { public HashMap<Integer, File> createMediaPaths() {

View File

@ -46,14 +46,14 @@ public class LocaleController {
public static boolean isRTL = false; public static boolean isRTL = false;
public static int nameDisplayOrder = 1; public static int nameDisplayOrder = 1;
private static boolean is24HourFormat = false; private static boolean is24HourFormat = false;
public static FastDateFormat formatterDay; public FastDateFormat formatterDay;
public static FastDateFormat formatterWeek; public FastDateFormat formatterWeek;
public static FastDateFormat formatterMonth; public FastDateFormat formatterMonth;
public static FastDateFormat formatterYear; public FastDateFormat formatterYear;
public static FastDateFormat formatterMonthYear; public FastDateFormat formatterMonthYear;
public static FastDateFormat formatterYearMax; public FastDateFormat formatterYearMax;
public static FastDateFormat chatDate; public FastDateFormat chatDate;
public static FastDateFormat chatFullDate; public FastDateFormat chatFullDate;
private HashMap<String, PluralRules> allRules = new HashMap<>(); private HashMap<String, PluralRules> allRules = new HashMap<>();
@ -671,9 +671,9 @@ public class LocaleController {
int dateYear = rightNow.get(Calendar.YEAR); int dateYear = rightNow.get(Calendar.YEAR);
if (year == dateYear) { if (year == dateYear) {
return chatDate.format(date * 1000); return getInstance().chatDate.format(date * 1000);
} }
return chatFullDate.format(date * 1000); return getInstance().chatFullDate.format(date * 1000);
} }
public static String formatDate(long date) { public static String formatDate(long date) {
@ -686,13 +686,13 @@ public class LocaleController {
int dateYear = rightNow.get(Calendar.YEAR); int dateYear = rightNow.get(Calendar.YEAR);
if (dateDay == day && year == dateYear) { if (dateDay == day && year == dateYear) {
return formatterDay.format(new Date(date * 1000)); return getInstance().formatterDay.format(new Date(date * 1000));
} else if (dateDay + 1 == day && year == dateYear) { } else if (dateDay + 1 == day && year == dateYear) {
return getString("Yesterday", R.string.Yesterday); return getString("Yesterday", R.string.Yesterday);
} else if (year == dateYear) { } else if (year == dateYear) {
return formatterMonth.format(new Date(date * 1000)); return getInstance().formatterMonth.format(new Date(date * 1000));
} else { } else {
return formatterYear.format(new Date(date * 1000)); return getInstance().formatterYear.format(new Date(date * 1000));
} }
} catch (Exception e) { } catch (Exception e) {
FileLog.e("tmessages", e); FileLog.e("tmessages", e);
@ -710,7 +710,7 @@ public class LocaleController {
int dateYear = rightNow.get(Calendar.YEAR); int dateYear = rightNow.get(Calendar.YEAR);
if (dateDay == day && year == dateYear) { if (dateDay == day && year == dateYear) {
return String.format("%s %s %s", LocaleController.getString("LastSeen", R.string.LastSeen), LocaleController.getString("TodayAt", R.string.TodayAt), formatterDay.format(new Date(date * 1000))); return String.format("%s %s %s", LocaleController.getString("LastSeen", R.string.LastSeen), LocaleController.getString("TodayAt", R.string.TodayAt), getInstance().formatterDay.format(new Date(date * 1000)));
/*int diff = (int) (ConnectionsManager.getInstance().getCurrentTime() - date) / 60; /*int diff = (int) (ConnectionsManager.getInstance().getCurrentTime() - date) / 60;
if (diff < 1) { if (diff < 1) {
return LocaleController.getString("LastSeenNow", R.string.LastSeenNow); return LocaleController.getString("LastSeenNow", R.string.LastSeenNow);
@ -720,12 +720,12 @@ public class LocaleController {
return LocaleController.formatPluralString("LastSeenHours", (int) Math.ceil(diff / 60.0f)); return LocaleController.formatPluralString("LastSeenHours", (int) Math.ceil(diff / 60.0f));
}*/ }*/
} else if (dateDay + 1 == day && year == dateYear) { } else if (dateDay + 1 == day && year == dateYear) {
return String.format("%s %s %s", LocaleController.getString("LastSeen", R.string.LastSeen), LocaleController.getString("YesterdayAt", R.string.YesterdayAt), formatterDay.format(new Date(date * 1000))); return String.format("%s %s %s", LocaleController.getString("LastSeen", R.string.LastSeen), LocaleController.getString("YesterdayAt", R.string.YesterdayAt), getInstance().formatterDay.format(new Date(date * 1000)));
} else if (year == dateYear) { } else if (year == dateYear) {
String format = LocaleController.formatString("formatDateAtTime", R.string.formatDateAtTime, formatterMonth.format(new Date(date * 1000)), formatterDay.format(new Date(date * 1000))); String format = LocaleController.formatString("formatDateAtTime", R.string.formatDateAtTime, getInstance().formatterMonth.format(new Date(date * 1000)), getInstance().formatterDay.format(new Date(date * 1000)));
return String.format("%s %s", LocaleController.getString("LastSeenDate", R.string.LastSeenDate), format); return String.format("%s %s", LocaleController.getString("LastSeenDate", R.string.LastSeenDate), format);
} else { } else {
String format = LocaleController.formatString("formatDateAtTime", R.string.formatDateAtTime, formatterYear.format(new Date(date * 1000)), formatterDay.format(new Date(date * 1000))); String format = LocaleController.formatString("formatDateAtTime", R.string.formatDateAtTime, getInstance().formatterYear.format(new Date(date * 1000)), getInstance().formatterDay.format(new Date(date * 1000)));
return String.format("%s %s", LocaleController.getString("LastSeenDate", R.string.LastSeenDate), format); return String.format("%s %s", LocaleController.getString("LastSeenDate", R.string.LastSeenDate), format);
} }
} catch (Exception e) { } catch (Exception e) {
@ -780,15 +780,15 @@ public class LocaleController {
int dateYear = rightNow.get(Calendar.YEAR); int dateYear = rightNow.get(Calendar.YEAR);
if (year != dateYear) { if (year != dateYear) {
return formatterYear.format(new Date(date * 1000)); return getInstance().formatterYear.format(new Date(date * 1000));
} else { } else {
int dayDiff = dateDay - day; int dayDiff = dateDay - day;
if(dayDiff == 0 || dayDiff == -1 && (int)(System.currentTimeMillis() / 1000) - date < 60 * 60 * 8) { if(dayDiff == 0 || dayDiff == -1 && (int)(System.currentTimeMillis() / 1000) - date < 60 * 60 * 8) {
return formatterDay.format(new Date(date * 1000)); return getInstance().formatterDay.format(new Date(date * 1000));
} else if(dayDiff > -7 && dayDiff <= -1) { } else if(dayDiff > -7 && dayDiff <= -1) {
return formatterWeek.format(new Date(date * 1000)); return getInstance().formatterWeek.format(new Date(date * 1000));
} else { } else {
return formatterMonth.format(new Date(date * 1000)); return getInstance().formatterMonth.format(new Date(date * 1000));
} }
} }
} catch (Exception e) { } catch (Exception e) {

View File

@ -542,13 +542,18 @@ public class MediaController implements NotificationCenter.NotificationCenterDel
shuffleMusic = preferences.getBoolean("shuffleMusic", false); shuffleMusic = preferences.getBoolean("shuffleMusic", false);
repeatMode = preferences.getInt("repeatMode", 0); repeatMode = preferences.getInt("repeatMode", 0);
NotificationCenter.getInstance().addObserver(this, NotificationCenter.FileDidFailedLoad); AndroidUtilities.runOnUIThread(new Runnable() {
NotificationCenter.getInstance().addObserver(this, NotificationCenter.FileDidLoaded); @Override
NotificationCenter.getInstance().addObserver(this, NotificationCenter.FileLoadProgressChanged); public void run() {
NotificationCenter.getInstance().addObserver(this, NotificationCenter.FileUploadProgressChanged); NotificationCenter.getInstance().addObserver(MediaController.this, NotificationCenter.FileDidFailedLoad);
NotificationCenter.getInstance().addObserver(this, NotificationCenter.messagesDeleted); NotificationCenter.getInstance().addObserver(MediaController.this, NotificationCenter.FileDidLoaded);
NotificationCenter.getInstance().addObserver(this, NotificationCenter.removeAllMessagesFromDialog); NotificationCenter.getInstance().addObserver(MediaController.this, NotificationCenter.FileLoadProgressChanged);
NotificationCenter.getInstance().addObserver(this, NotificationCenter.musicDidLoaded); NotificationCenter.getInstance().addObserver(MediaController.this, NotificationCenter.FileUploadProgressChanged);
NotificationCenter.getInstance().addObserver(MediaController.this, NotificationCenter.messagesDeleted);
NotificationCenter.getInstance().addObserver(MediaController.this, NotificationCenter.removeAllMessagesFromDialog);
NotificationCenter.getInstance().addObserver(MediaController.this, NotificationCenter.musicDidLoaded);
}
});
BroadcastReceiver networkStateReceiver = new BroadcastReceiver() { BroadcastReceiver networkStateReceiver = new BroadcastReceiver() {
@Override @Override
@ -1117,7 +1122,8 @@ public class MediaController implements NotificationCenter.NotificationCenterDel
try { try {
ArrayList<SendMessagesHelper.DelayedMessage> delayedMessages = SendMessagesHelper.getInstance().getDelayedMessages(fileName); ArrayList<SendMessagesHelper.DelayedMessage> delayedMessages = SendMessagesHelper.getInstance().getDelayedMessages(fileName);
if (delayedMessages != null) { if (delayedMessages != null) {
for (SendMessagesHelper.DelayedMessage delayedMessage : delayedMessages) { for (int a = 0; a < delayedMessages.size(); a++) {
SendMessagesHelper.DelayedMessage delayedMessage = delayedMessages.get(a);
if (delayedMessage.encryptedChat == null) { if (delayedMessage.encryptedChat == null) {
long dialog_id = delayedMessage.obj.getDialogId(); long dialog_id = delayedMessage.obj.getDialogId();
Long lastTime = typingTimes.get(dialog_id); Long lastTime = typingTimes.get(dialog_id);
@ -2477,7 +2483,7 @@ public class MediaController implements NotificationCenter.NotificationCenterDel
Cursor cursor = null; Cursor cursor = null;
try { try {
if (Build.VERSION.SDK_INT < 23 || Build.VERSION.SDK_INT >= 23 && ApplicationLoader.applicationContext.checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) { if (Build.VERSION.SDK_INT < 23 || Build.VERSION.SDK_INT >= 23 && ApplicationLoader.applicationContext.checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) {
cursor = MediaStore.Images.Media.query(ApplicationLoader.applicationContext.getContentResolver(), MediaStore.Images.Media.EXTERNAL_CONTENT_URI, projectionPhotos, "", null, MediaStore.Images.Media.DATE_TAKEN + " DESC"); cursor = MediaStore.Images.Media.query(ApplicationLoader.applicationContext.getContentResolver(), MediaStore.Images.Media.EXTERNAL_CONTENT_URI, projectionPhotos, null, null, MediaStore.Images.Media.DATE_TAKEN + " DESC");
if (cursor != null) { if (cursor != null) {
int imageIdColumn = cursor.getColumnIndex(MediaStore.Images.Media._ID); int imageIdColumn = cursor.getColumnIndex(MediaStore.Images.Media._ID);
int bucketIdColumn = cursor.getColumnIndex(MediaStore.Images.Media.BUCKET_ID); int bucketIdColumn = cursor.getColumnIndex(MediaStore.Images.Media.BUCKET_ID);
@ -2540,7 +2546,7 @@ public class MediaController implements NotificationCenter.NotificationCenterDel
if (Build.VERSION.SDK_INT < 23 || Build.VERSION.SDK_INT >= 23 && ApplicationLoader.applicationContext.checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) { if (Build.VERSION.SDK_INT < 23 || Build.VERSION.SDK_INT >= 23 && ApplicationLoader.applicationContext.checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) {
albums.clear(); albums.clear();
AlbumEntry allVideosAlbum = null; AlbumEntry allVideosAlbum = null;
cursor = MediaStore.Images.Media.query(ApplicationLoader.applicationContext.getContentResolver(), MediaStore.Video.Media.EXTERNAL_CONTENT_URI, projectionVideo, "", null, MediaStore.Video.Media.DATE_TAKEN + " DESC"); cursor = MediaStore.Images.Media.query(ApplicationLoader.applicationContext.getContentResolver(), MediaStore.Video.Media.EXTERNAL_CONTENT_URI, projectionVideo, null, null, MediaStore.Video.Media.DATE_TAKEN + " DESC");
if (cursor != null) { if (cursor != null) {
int imageIdColumn = cursor.getColumnIndex(MediaStore.Video.Media._ID); int imageIdColumn = cursor.getColumnIndex(MediaStore.Video.Media._ID);
int bucketIdColumn = cursor.getColumnIndex(MediaStore.Video.Media.BUCKET_ID); int bucketIdColumn = cursor.getColumnIndex(MediaStore.Video.Media.BUCKET_ID);

View File

@ -21,6 +21,7 @@ import android.text.style.URLSpan;
import android.text.util.Linkify; import android.text.util.Linkify;
import org.telegram.tgnet.ConnectionsManager; import org.telegram.tgnet.ConnectionsManager;
import org.telegram.tgnet.TLObject;
import org.telegram.tgnet.TLRPC; import org.telegram.tgnet.TLRPC;
import org.telegram.ui.Components.TypefaceSpan; import org.telegram.ui.Components.TypefaceSpan;
import org.telegram.ui.Components.URLSpanBotCommand; import org.telegram.ui.Components.URLSpanBotCommand;
@ -77,6 +78,10 @@ public class MessageObject {
public ArrayList<TextLayoutBlock> textLayoutBlocks; public ArrayList<TextLayoutBlock> textLayoutBlocks;
public MessageObject(TLRPC.Message message, AbstractMap<Integer, TLRPC.User> users, boolean generateLayout) { public MessageObject(TLRPC.Message message, AbstractMap<Integer, TLRPC.User> users, boolean generateLayout) {
this(message, users, null, generateLayout);
}
public MessageObject(TLRPC.Message message, AbstractMap<Integer, TLRPC.User> users, AbstractMap<Integer, TLRPC.Chat> chats, boolean generateLayout) {
if (textPaint == null) { if (textPaint == null) {
textPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG); textPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG);
textPaint.setColor(0xff000000); textPaint.setColor(0xff000000);
@ -88,7 +93,7 @@ public class MessageObject {
messageOwner = message; messageOwner = message;
if (message.replyMessage != null) { if (message.replyMessage != null) {
replyMessageObject = new MessageObject(message.replyMessage, users, false); replyMessageObject = new MessageObject(message.replyMessage, users, chats, false);
} }
if (message instanceof TLRPC.TL_messageService) { if (message instanceof TLRPC.TL_messageService) {
@ -143,39 +148,56 @@ public class MessageObject {
} }
} }
} else if (message.action instanceof TLRPC.TL_messageActionChatAddUser) { } else if (message.action instanceof TLRPC.TL_messageActionChatAddUser) {
TLRPC.User whoUser = null; int singleUserId = messageOwner.action.user_id;
if (users != null) { if (singleUserId == 0 && messageOwner.action.users.size() == 1) {
whoUser = users.get(message.action.user_id); singleUserId = messageOwner.action.users.get(0);
} }
if (whoUser == null) { if (singleUserId != 0) {
whoUser = MessagesController.getInstance().getUser(message.action.user_id); TLRPC.User whoUser = null;
} if (users != null) {
if (message.to_id.channel_id != 0) { whoUser = users.get(singleUserId);
if (whoUser != null && whoUser.id != UserConfig.getClientUserId()) {
messageText = replaceWithLink(LocaleController.getString("ChannelAddedBy", R.string.ChannelAddedBy), "un1", whoUser);
} else {
messageText = LocaleController.getString("ChannelJoined", R.string.ChannelJoined);
} }
} else { if (whoUser == null) {
if (whoUser != null && fromUser != null) { whoUser = MessagesController.getInstance().getUser(singleUserId);
if (whoUser.id == fromUser.id) { }
if (isOut()) { if (message.to_id.channel_id != 0 && !isMegagroup()) {
messageText = LocaleController.getString("ActionAddUserSelfYou", R.string.ActionAddUserSelfYou); if (whoUser != null && whoUser.id != UserConfig.getClientUserId()) {
if (isMegagroup()) {
messageText = replaceWithLink(LocaleController.getString("MegaAddedBy", R.string.MegaAddedBy), "un1", whoUser);
} else { } else {
messageText = replaceWithLink(LocaleController.getString("ActionAddUserSelf", R.string.ActionAddUserSelf), "un1", fromUser); messageText = replaceWithLink(LocaleController.getString("ChannelAddedBy", R.string.ChannelAddedBy), "un1", whoUser);
} }
} else { } else {
if (isOut()) { messageText = LocaleController.getString("ChannelJoined", R.string.ChannelJoined);
messageText = replaceWithLink(LocaleController.getString("ActionYouAddUser", R.string.ActionYouAddUser), "un2", whoUser);
} else if (message.action.user_id == UserConfig.getClientUserId()) {
messageText = replaceWithLink(LocaleController.getString("ActionAddUserYou", R.string.ActionAddUserYou), "un1", fromUser);
} else {
messageText = replaceWithLink(LocaleController.getString("ActionAddUser", R.string.ActionAddUser), "un2", whoUser);
messageText = replaceWithLink(messageText, "un1", fromUser);
}
} }
} else { } else {
messageText = LocaleController.getString("ActionAddUser", R.string.ActionAddUser).replace("un2", "").replace("un1", ""); if (whoUser != null && fromUser != null) {
if (whoUser.id == fromUser.id) {
if (isOut()) {
messageText = LocaleController.getString("ActionAddUserSelfYou", R.string.ActionAddUserSelfYou);
} else {
messageText = replaceWithLink(LocaleController.getString("ActionAddUserSelf", R.string.ActionAddUserSelf), "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);
}
}
} else {
messageText = LocaleController.getString("ActionAddUser", R.string.ActionAddUser).replace("un2", "").replace("un1", "");
}
}
} else {
if (isOut()) {
messageText = replaceWithLink(LocaleController.getString("ActionYouAddUser", R.string.ActionYouAddUser), "un2", message.action.users, users);
} else {
messageText = replaceWithLink(LocaleController.getString("ActionAddUser", R.string.ActionAddUser), "un2", message.action.users, users);
messageText = replaceWithLink(messageText, "un1", fromUser);
} }
} }
} else if (message.action instanceof TLRPC.TL_messageActionChatJoinedByLink) { } else if (message.action instanceof TLRPC.TL_messageActionChatJoinedByLink) {
@ -189,7 +211,7 @@ public class MessageObject {
messageText = LocaleController.getString("ActionInviteUser", R.string.ActionInviteUser).replace("un1", ""); messageText = LocaleController.getString("ActionInviteUser", R.string.ActionInviteUser).replace("un1", "");
} }
} else if (message.action instanceof TLRPC.TL_messageActionChatEditPhoto) { } else if (message.action instanceof TLRPC.TL_messageActionChatEditPhoto) {
if (message.to_id.channel_id != 0) { if (message.to_id.channel_id != 0 && !isMegagroup()) {
messageText = LocaleController.getString("ActionChannelChangedPhoto", R.string.ActionChannelChangedPhoto); messageText = LocaleController.getString("ActionChannelChangedPhoto", R.string.ActionChannelChangedPhoto);
} else { } else {
if (isOut()) { if (isOut()) {
@ -203,7 +225,7 @@ public class MessageObject {
} }
} }
} else if (message.action instanceof TLRPC.TL_messageActionChatEditTitle) { } else if (message.action instanceof TLRPC.TL_messageActionChatEditTitle) {
if (message.to_id.channel_id != 0) { if (message.to_id.channel_id != 0 && !isMegagroup()) {
messageText = LocaleController.getString("ActionChannelChangedTitle", R.string.ActionChannelChangedTitle).replace("un2", message.action.title); messageText = LocaleController.getString("ActionChannelChangedTitle", R.string.ActionChannelChangedTitle).replace("un2", message.action.title);
} else { } else {
if (isOut()) { if (isOut()) {
@ -217,7 +239,7 @@ public class MessageObject {
} }
} }
} else if (message.action instanceof TLRPC.TL_messageActionChatDeletePhoto) { } else if (message.action instanceof TLRPC.TL_messageActionChatDeletePhoto) {
if (message.to_id.channel_id != 0) { if (message.to_id.channel_id != 0 && !isMegagroup()) {
messageText = LocaleController.getString("ActionChannelRemovedPhoto", R.string.ActionChannelRemovedPhoto); messageText = LocaleController.getString("ActionChannelRemovedPhoto", R.string.ActionChannelRemovedPhoto);
} else { } else {
if (isOut()) { if (isOut()) {
@ -253,7 +275,13 @@ public class MessageObject {
} }
} }
} else if (message.action instanceof TLRPC.TL_messageActionLoginUnknownLocation) { } else if (message.action instanceof TLRPC.TL_messageActionLoginUnknownLocation) {
String date = LocaleController.formatString("formatDateAtTime", R.string.formatDateAtTime, LocaleController.formatterYear.format(((long) message.date) * 1000), LocaleController.formatterDay.format(((long) message.date) * 1000)); String date;
long time = ((long) message.date) * 1000;
if (LocaleController.getInstance().formatterDay != null && LocaleController.getInstance().formatterYear != null) {
date = LocaleController.formatString("formatDateAtTime", R.string.formatDateAtTime, LocaleController.getInstance().formatterYear.format(time), LocaleController.getInstance().formatterDay.format(time));
} else {
date = "" + message.date;
}
TLRPC.User to_user = UserConfig.getCurrentUser(); TLRPC.User to_user = UserConfig.getCurrentUser();
if (to_user == null) { if (to_user == null) {
if (users != null) { if (users != null) {
@ -315,7 +343,15 @@ public class MessageObject {
} else if (message.action instanceof TLRPC.TL_messageActionCreatedBroadcastList) { } else if (message.action instanceof TLRPC.TL_messageActionCreatedBroadcastList) {
messageText = LocaleController.formatString("YouCreatedBroadcastList", R.string.YouCreatedBroadcastList); messageText = LocaleController.formatString("YouCreatedBroadcastList", R.string.YouCreatedBroadcastList);
} else if (message.action instanceof TLRPC.TL_messageActionChannelCreate) { } else if (message.action instanceof TLRPC.TL_messageActionChannelCreate) {
messageText = LocaleController.getString("ActionCreateChannel", R.string.ActionCreateChannel); if (isMegagroup()) {
messageText = LocaleController.getString("ActionCreateMega", R.string.ActionCreateMega);
} else {
messageText = LocaleController.getString("ActionCreateChannel", R.string.ActionCreateChannel);
}
} else if (message.action instanceof TLRPC.TL_messageActionChatMigrateTo) {
messageText = LocaleController.getString("ActionMigrateFromGroup", R.string.ActionMigrateFromGroup);
} else if (message.action instanceof TLRPC.TL_messageActionChannelMigrateFrom) {
messageText = LocaleController.getString("ActionMigrateFromGroup", R.string.ActionMigrateFromGroup);
} }
} }
} else if (!isMediaEmpty()) { } else if (!isMediaEmpty()) {
@ -353,6 +389,9 @@ public class MessageObject {
} else { } else {
messageText = message.message; messageText = message.message;
} }
if (messageText == null) {
messageText = "";
}
if (generateLayout) { if (generateLayout) {
messageText = Emoji.replaceEmoji(messageText, textPaint.getFontMetricsInt(), AndroidUtilities.dp(20), false); messageText = Emoji.replaceEmoji(messageText, textPaint.getFontMetricsInt(), AndroidUtilities.dp(20), false);
} }
@ -360,7 +399,7 @@ public class MessageObject {
if (message instanceof TLRPC.TL_message || message instanceof TLRPC.TL_messageForwarded_old2) { if (message instanceof TLRPC.TL_message || message instanceof TLRPC.TL_messageForwarded_old2) {
if (isMediaEmpty()) { if (isMediaEmpty()) {
contentType = type = 0; contentType = type = 0;
if (messageText.length() == 0) { if (messageText == null || messageText.length() == 0) {
messageText = "Empty message"; messageText = "Empty message";
} }
} else if (message.media instanceof TLRPC.TL_messageMediaPhoto) { } else if (message.media instanceof TLRPC.TL_messageMediaPhoto) {
@ -423,6 +462,8 @@ public class MessageObject {
dateKey = String.format("%d_%02d_%02d", dateYear, dateMonth, dateDay); dateKey = String.format("%d_%02d_%02d", dateYear, dateMonth, dateDay);
if (contentType == 1 || contentType == 2 || contentType == 0 || contentType == 8) { if (contentType == 1 || contentType == 2 || contentType == 0 || contentType == 8) {
monthKey = String.format("%d_%02d", dateYear, dateMonth); monthKey = String.format("%d_%02d", dateYear, dateMonth);
} else if (contentType == 9) {
//dateKey = "0_0_0";
} }
if (messageOwner.message != null && messageOwner.id < 0 && messageOwner.message.length() > 6 && messageOwner.media instanceof TLRPC.TL_messageMediaVideo) { if (messageOwner.message != null && messageOwner.id < 0 && messageOwner.message.length() > 6 && messageOwner.media instanceof TLRPC.TL_messageMediaVideo) {
@ -513,13 +554,50 @@ public class MessageObject {
} }
} }
public CharSequence replaceWithLink(CharSequence source, String param, TLRPC.User user) { public CharSequence replaceWithLink(CharSequence source, String param, ArrayList<Integer> uids, AbstractMap<Integer, TLRPC.User> usersDict) {
int start = TextUtils.indexOf(source, param); int start = TextUtils.indexOf(source, param);
if (start >= 0) { if (start >= 0) {
String name = UserObject.getUserName(user); SpannableStringBuilder names = new SpannableStringBuilder("");
URLSpanNoUnderlineBold span = new URLSpanNoUnderlineBold("" + user.id); for (int a = 0; a < uids.size(); a++) {
TLRPC.User user = null;
if (usersDict != null) {
user = usersDict.get(uids.get(a));
}
if (user == null) {
user = MessagesController.getInstance().getUser(uids.get(a));
}
if (user != null) {
String name = UserObject.getUserName(user);
start = names.length();
if (names.length() != 0) {
names.append(", ");
}
names.append(name);
names.setSpan(new URLSpanNoUnderlineBold("" + user.id), start, start + name.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
}
}
return TextUtils.replace(source, new String[]{param}, new CharSequence[]{names});
}
return source;
}
public CharSequence replaceWithLink(CharSequence source, String param, TLObject object) {
int start = TextUtils.indexOf(source, param);
if (start >= 0) {
String name;
int id;
if (object instanceof TLRPC.User) {
name = UserObject.getUserName((TLRPC.User) object);
id = ((TLRPC.User) object).id;
} else if (object instanceof TLRPC.Chat) {
name = ((TLRPC.Chat) object).title;
id = -((TLRPC.Chat) object).id;
} else {
name = "";
id = 0;
}
SpannableStringBuilder builder = new SpannableStringBuilder(TextUtils.replace(source, new String[]{param}, new String[]{name})); SpannableStringBuilder builder = new SpannableStringBuilder(TextUtils.replace(source, new String[]{param}, new String[]{name}));
builder.setSpan(span, start, start + name.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); builder.setSpan(new URLSpanNoUnderlineBold("" + id), start, start + name.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
return builder; return builder;
} }
return source; return source;
@ -647,6 +725,7 @@ public class MessageObject {
FileLog.e("tmessages", e); FileLog.e("tmessages", e);
} }
} }
linkDescription = Emoji.replaceEmoji(linkDescription, textPaint.getFontMetricsInt(), AndroidUtilities.dp(20), false);
} }
} }
@ -662,12 +741,12 @@ public class MessageObject {
} catch (Exception e) { } catch (Exception e) {
FileLog.e("tmessages", e); FileLog.e("tmessages", e);
} }
addUsernamesAndHashtags(caption); addUsernamesAndHashtags(caption, true);
} }
} }
} }
private static void addUsernamesAndHashtags(CharSequence charSequence) { private static void addUsernamesAndHashtags(CharSequence charSequence, boolean botCommands) {
try { try {
if (urlPattern == null) { if (urlPattern == null) {
urlPattern = Pattern.compile("(^|\\s)/[a-zA-Z@\\d_]{1,255}|(^|\\s)@[a-zA-Z\\d_]{5,32}|(^|\\s)#[\\w\\.]+"); urlPattern = Pattern.compile("(^|\\s)/[a-zA-Z@\\d_]{1,255}|(^|\\s)@[a-zA-Z\\d_]{5,32}|(^|\\s)#[\\w\\.]+");
@ -679,20 +758,29 @@ public class MessageObject {
if (charSequence.charAt(start) != '@' && charSequence.charAt(start) != '#' && charSequence.charAt(start) != '/') { if (charSequence.charAt(start) != '@' && charSequence.charAt(start) != '#' && charSequence.charAt(start) != '/') {
start++; start++;
} }
URLSpanNoUnderline url; URLSpanNoUnderline url = null;
if (charSequence.charAt(start) == '/') { if (charSequence.charAt(start) == '/') {
url = new URLSpanBotCommand(charSequence.subSequence(start, end).toString()); if (botCommands) {
url = new URLSpanBotCommand(charSequence.subSequence(start, end).toString());
}
} else { } else {
url = new URLSpanNoUnderline(charSequence.subSequence(start, end).toString()); url = new URLSpanNoUnderline(charSequence.subSequence(start, end).toString());
} }
((Spannable) charSequence).setSpan(url, start, end, 0); if (url != null) {
((Spannable) charSequence).setSpan(url, start, end, 0);
}
} }
} catch (Exception e) { } catch (Exception e) {
FileLog.e("tmessages", e); FileLog.e("tmessages", e);
} }
} }
public static void addLinks(CharSequence messageText) { public static void addLinks(CharSequence messageText) {
addLinks(messageText, true);
}
public static void addLinks(CharSequence messageText, boolean botCommands) {
if (messageText instanceof Spannable && containsUrls(messageText)) { if (messageText instanceof Spannable && containsUrls(messageText)) {
if (messageText.length() < 100) { if (messageText.length() < 100) {
try { try {
@ -707,7 +795,7 @@ public class MessageObject {
FileLog.e("tmessages", e); FileLog.e("tmessages", e);
} }
} }
addUsernamesAndHashtags(messageText); addUsernamesAndHashtags(messageText, botCommands);
} }
} }
@ -755,7 +843,7 @@ public class MessageObject {
spannable.setSpan(new TypefaceSpan(AndroidUtilities.getTypeface("fonts/rmedium.ttf")), entity.offset, entity.offset + entity.length, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); spannable.setSpan(new TypefaceSpan(AndroidUtilities.getTypeface("fonts/rmedium.ttf")), entity.offset, entity.offset + entity.length, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
} else if (entity instanceof TLRPC.TL_messageEntityItalic) { } else if (entity instanceof TLRPC.TL_messageEntityItalic) {
spannable.setSpan(new TypefaceSpan(AndroidUtilities.getTypeface("fonts/ritalic.ttf")), entity.offset, entity.offset + entity.length, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); spannable.setSpan(new TypefaceSpan(AndroidUtilities.getTypeface("fonts/ritalic.ttf")), entity.offset, entity.offset + entity.length, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
} else if (entity instanceof TLRPC.TL_messageEntityCode) { } else if (entity instanceof TLRPC.TL_messageEntityCode || entity instanceof TLRPC.TL_messageEntityPre) {
spannable.setSpan(new TypefaceSpan(Typeface.MONOSPACE), entity.offset, entity.offset + entity.length, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); spannable.setSpan(new TypefaceSpan(Typeface.MONOSPACE), entity.offset, entity.offset + entity.length, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
} else if (!useManualParse) { } else if (!useManualParse) {
String url = messageOwner.message.substring(entity.offset, entity.offset + entity.length); String url = messageOwner.message.substring(entity.offset, entity.offset + entity.length);
@ -940,23 +1028,23 @@ public class MessageObject {
} }
public boolean isOut() { public boolean isOut() {
return (messageOwner.flags & TLRPC.MESSAGE_FLAG_OUT) != 0; return messageOwner.out;
} }
public boolean isOutOwner() { public boolean isOutOwner() {
return (messageOwner.flags & TLRPC.MESSAGE_FLAG_OUT) != 0 && messageOwner.from_id > 0; return messageOwner.out && messageOwner.from_id > 0;
} }
public boolean isUnread() { public boolean isUnread() {
return (messageOwner.flags & TLRPC.MESSAGE_FLAG_UNREAD) != 0; return messageOwner.unread;
} }
public boolean isContentUnread() { public boolean isContentUnread() {
return (messageOwner.flags & TLRPC.MESSAGE_FLAG_CONTENT_UNREAD) != 0; return messageOwner.media_unread;
} }
public void setIsRead() { public void setIsRead() {
messageOwner.flags &= ~TLRPC.MESSAGE_FLAG_UNREAD; messageOwner.unread = false;
} }
public int getUnradFlags() { public int getUnradFlags() {
@ -965,17 +1053,17 @@ public class MessageObject {
public static int getUnreadFlags(TLRPC.Message message) { public static int getUnreadFlags(TLRPC.Message message) {
int flags = 0; int flags = 0;
if ((message.flags & TLRPC.MESSAGE_FLAG_UNREAD) == 0) { if (!message.unread) {
flags |= 1; flags |= 1;
} }
if ((message.flags & TLRPC.MESSAGE_FLAG_CONTENT_UNREAD) == 0) { if (!message.media_unread) {
flags |= 2; flags |= 2;
} }
return flags; return flags;
} }
public void setContentIsRead() { public void setContentIsRead() {
messageOwner.flags &= ~TLRPC.MESSAGE_FLAG_CONTENT_UNREAD; messageOwner.media_unread = false;
} }
public int getId() { public int getId() {
@ -983,66 +1071,73 @@ public class MessageObject {
} }
public boolean isSecretPhoto() { public boolean isSecretPhoto() {
return messageOwner instanceof TLRPC.TL_message_secret && messageOwner.media instanceof TLRPC.TL_messageMediaPhoto && messageOwner.ttl != 0 && messageOwner.ttl <= 60; return messageOwner instanceof TLRPC.TL_message_secret && messageOwner.media instanceof TLRPC.TL_messageMediaPhoto && messageOwner.ttl > 0 && messageOwner.ttl <= 60;
} }
public boolean isSecretMedia() { public boolean isSecretMedia() {
return messageOwner instanceof TLRPC.TL_message_secret && return messageOwner instanceof TLRPC.TL_message_secret &&
(messageOwner.media instanceof TLRPC.TL_messageMediaPhoto && messageOwner.ttl != 0 && messageOwner.ttl <= 60 || (messageOwner.media instanceof TLRPC.TL_messageMediaPhoto && messageOwner.ttl > 0 && messageOwner.ttl <= 60 ||
messageOwner.media instanceof TLRPC.TL_messageMediaAudio || messageOwner.media instanceof TLRPC.TL_messageMediaAudio ||
messageOwner.media instanceof TLRPC.TL_messageMediaVideo); messageOwner.media instanceof TLRPC.TL_messageMediaVideo);
} }
public static void setUnreadFlags(TLRPC.Message message, int flag) { public static void setUnreadFlags(TLRPC.Message message, int flag) {
if ((flag & 1) == 0) { message.unread = (flag & 1) == 0;
message.flags |= TLRPC.MESSAGE_FLAG_UNREAD; message.media_unread = (flag & 2) == 0;
} else {
message.flags &= ~TLRPC.MESSAGE_FLAG_UNREAD;
}
if ((flag & 2) == 0) {
message.flags |= TLRPC.MESSAGE_FLAG_CONTENT_UNREAD;
} else {
message.flags &= ~TLRPC.MESSAGE_FLAG_CONTENT_UNREAD;
}
} }
public static boolean isUnread(TLRPC.Message message) { public static boolean isUnread(TLRPC.Message message) {
return (message.flags & TLRPC.MESSAGE_FLAG_UNREAD) != 0; return message.unread;
} }
public static boolean isContentUnread(TLRPC.Message message) { public static boolean isContentUnread(TLRPC.Message message) {
return (message.flags & TLRPC.MESSAGE_FLAG_CONTENT_UNREAD) != 0; return message.media_unread;
} }
public boolean isImportant() { public boolean isImportant() {
return isImportant(messageOwner); return isImportant(messageOwner);
} }
public boolean isMegagroup() {
return isMegagroup(messageOwner);
}
public static boolean isImportant(TLRPC.Message message) { public static boolean isImportant(TLRPC.Message message) {
return message.to_id.channel_id != 0 && (message.from_id <= 0 || (message.flags & TLRPC.MESSAGE_FLAG_MENTION) != 0 || (message.flags & TLRPC.MESSAGE_FLAG_OUT) != 0 || (message.flags & TLRPC.MESSAGE_FLAG_HAS_FROM_ID) == 0); if (isMegagroup(message)) {
return message.from_id <= 0;
}
return message.to_id.channel_id != 0 && (message.from_id <= 0 || message.mentioned || message.out || (message.flags & TLRPC.MESSAGE_FLAG_HAS_FROM_ID) == 0);
}
public static boolean isMegagroup(TLRPC.Message message) {
return (message.flags & TLRPC.MESSAGE_FLAG_MEGAGROUP) != 0;
} }
public static boolean isOut(TLRPC.Message message) { public static boolean isOut(TLRPC.Message message) {
return (message.flags & TLRPC.MESSAGE_FLAG_OUT) != 0; return message.out;
} }
public long getDialogId() { public long getDialogId() {
if (messageOwner.dialog_id == 0) { return getDialogId(messageOwner);
if (messageOwner.to_id.chat_id != 0) { }
if (messageOwner.to_id.chat_id < 0) {
messageOwner.dialog_id = AndroidUtilities.makeBroadcastId(messageOwner.to_id.chat_id); public static long getDialogId(TLRPC.Message message) {
if (message.dialog_id == 0 && message.to_id != null) {
if (message.to_id.chat_id != 0) {
if (message.to_id.chat_id < 0) {
message.dialog_id = AndroidUtilities.makeBroadcastId(message.to_id.chat_id);
} else { } else {
messageOwner.dialog_id = -messageOwner.to_id.chat_id; message.dialog_id = -message.to_id.chat_id;
} }
} else if (messageOwner.to_id.channel_id != 0) { } else if (message.to_id.channel_id != 0) {
messageOwner.dialog_id = -messageOwner.to_id.channel_id; message.dialog_id = -message.to_id.channel_id;
} else if (isOut()) { } else if (isOut(message)) {
messageOwner.dialog_id = messageOwner.to_id.user_id; message.dialog_id = message.to_id.user_id;
} else { } else {
messageOwner.dialog_id = messageOwner.from_id; message.dialog_id = message.from_id;
} }
} }
return messageOwner.dialog_id; return message.dialog_id;
} }
public boolean isSending() { public boolean isSending() {
@ -1274,6 +1369,9 @@ public class MessageObject {
} }
public static boolean canDeleteMessage(TLRPC.Message message, TLRPC.Chat chat) { public static boolean canDeleteMessage(TLRPC.Message message, TLRPC.Chat chat) {
if (message.id < 0) {
return true;
}
if (chat == null && message.to_id.channel_id != 0) { if (chat == null && message.to_id.channel_id != 0) {
chat = MessagesController.getInstance().getChat(message.to_id.channel_id); chat = MessagesController.getInstance().getChat(message.to_id.channel_id);
} }
@ -1281,13 +1379,13 @@ public class MessageObject {
if (message.id == 1) { if (message.id == 1) {
return false; return false;
} }
if ((chat.flags & TLRPC.CHAT_FLAG_ADMIN) != 0) { if (chat.creator) {
return true; return true;
} else if ((chat.flags & TLRPC.CHAT_FLAG_USER_IS_EDITOR) != 0) { } else if (chat.editor) {
if (isOut(message) || message.from_id > 0) { if (isOut(message) || message.from_id > 0) {
return true; return true;
} }
} else if ((chat.flags & TLRPC.CHAT_FLAG_USER_IS_MODERATOR) != 0) { } else if (chat.moderator) {
if (message.from_id > 0) { if (message.from_id > 0) {
return true; return true;
} }

View File

@ -1,19 +1,20 @@
package org.telegram.messenger; package org.telegram.messenger;
import android.app.Activity; import android.app.Activity;
import android.net.Uri;
import android.util.Log; import android.util.Log;
import net.hockeyapp.android.Constants; import net.hockeyapp.android.Constants;
import net.hockeyapp.android.utils.SimpleMultipartEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.mime.MultipartEntity;
import org.apache.http.entity.mime.content.FileBody;
import org.apache.http.impl.client.DefaultHttpClient;
import java.io.BufferedWriter; import java.io.BufferedWriter;
import java.io.File; import java.io.File;
import java.io.FileWriter; import java.io.FileWriter;
import java.io.FilenameFilter; import java.io.FilenameFilter;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Date; import java.util.Date;
import java.util.UUID; import java.util.UUID;
@ -24,7 +25,7 @@ public class NativeCrashManager {
for (String dumpFilename : filenames) { for (String dumpFilename : filenames) {
String logFilename = createLogFile(); String logFilename = createLogFile();
if (logFilename != null) { if (logFilename != null) {
uploadDumpAndLog(activity, BuildVars.HOCKEY_APP_HASH, dumpFilename, logFilename); uploadDumpAndLog(activity, BuildVars.DEBUG_VERSION ? BuildVars.HOCKEY_APP_HASH_DEBUG : BuildVars.HOCKEY_APP_HASH, dumpFilename, logFilename);
} }
} }
} }
@ -61,17 +62,29 @@ public class NativeCrashManager {
@Override @Override
public void run() { public void run() {
try { try {
DefaultHttpClient httpClient = new DefaultHttpClient(); SimpleMultipartEntity entity = new SimpleMultipartEntity();
HttpPost httpPost = new HttpPost("https://rink.hockeyapp.net/api/2/apps/" + identifier + "/crashes/upload"); entity.writeFirstBoundaryIfNeeds();
MultipartEntity entity = new MultipartEntity();
File dumpFile = new File(Constants.FILES_PATH, dumpFilename); Uri attachmentUri = Uri.fromFile(new File(Constants.FILES_PATH, dumpFilename));
entity.addPart("attachment0", new FileBody(dumpFile)); InputStream input = activity.getContentResolver().openInputStream(attachmentUri);
File logFile = new File(Constants.FILES_PATH, logFilename); entity.addPart("attachment0", attachmentUri.getLastPathSegment(), input, false);
entity.addPart("log", new FileBody(logFile));
httpPost.setEntity(entity); attachmentUri = Uri.fromFile(new File(Constants.FILES_PATH, logFilename));
httpClient.execute(httpPost); input = activity.getContentResolver().openInputStream(attachmentUri);
} catch (Exception e) { entity.addPart("log", attachmentUri.getLastPathSegment(), input, false);
FileLog.e("tmessages", e);
entity.writeLastBoundaryIfNeeds();
HttpURLConnection urlConnection = (HttpURLConnection) new URL("https://rink.hockeyapp.net/api/2/apps/" + identifier + "/crashes/upload").openConnection();
urlConnection.setDoOutput(true);
urlConnection.setRequestMethod("POST");
urlConnection.setRequestProperty("Content-Type", entity.getContentType());
urlConnection.setRequestProperty("Content-Length", String.valueOf(entity.getContentLength()));
urlConnection.getOutputStream().write(entity.getOutputStream().toByteArray());
urlConnection.connect();
} catch (IOException e) {
e.printStackTrace();
} finally { } finally {
activity.deleteFile(logFilename); activity.deleteFile(logFilename);
activity.deleteFile(dumpFilename); activity.deleteFile(dumpFilename);

View File

@ -23,7 +23,7 @@ import java.util.zip.ZipFile;
public class NativeLoader { public class NativeLoader {
private final static int LIB_VERSION = 14; private final static int LIB_VERSION = 15;
private final static String LIB_NAME = "tmessages." + LIB_VERSION; private final static String LIB_NAME = "tmessages." + LIB_VERSION;
private final static String LIB_SO_NAME = "lib" + LIB_NAME + ".so"; private final static String LIB_SO_NAME = "lib" + LIB_NAME + ".so";
private final static String LOCALE_LIB_SO_NAME = "lib" + LIB_NAME + "loc.so"; private final static String LOCALE_LIB_SO_NAME = "lib" + LIB_NAME + "loc.so";

View File

@ -195,6 +195,87 @@ public class NotificationsController {
}); });
} }
public void removeNotificationsForDialog(long did) {
NotificationsController.getInstance().processReadMessages(null, did, 0, Integer.MAX_VALUE, false);
HashMap<Long, Integer> dialogsToUpdate = new HashMap<>();
dialogsToUpdate.put(did, 0);
NotificationsController.getInstance().processDialogsUpdateRead(dialogsToUpdate);
}
public void removeDeletedMessagesFromNotifications(final SparseArray<ArrayList<Integer>> deletedMessages) {
final ArrayList<MessageObject> popupArray = popupMessages.isEmpty() ? null : new ArrayList<>(popupMessages);
notificationsQueue.postRunnable(new Runnable() {
@Override
public void run() {
int old_unread_count = total_unread_count;
SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("Notifications", Context.MODE_PRIVATE);
for (int a = 0; a < deletedMessages.size(); a++) {
int key = deletedMessages.keyAt(a);
long dialog_id = -key;
ArrayList<Integer> mids = deletedMessages.get(key);
Integer currentCount = pushDialogs.get(dialog_id);
if (currentCount == null) {
currentCount = 0;
}
Integer newCount = currentCount;
for (int b = 0; b < mids.size(); b++) {
long mid = mids.get(b);
mid |= ((long) key) << 32;
MessageObject messageObject = pushMessagesDict.get(mid);
if (messageObject != null) {
pushMessagesDict.remove(mid);
delayedPushMessages.remove(messageObject);
pushMessages.remove(messageObject);
if (isPersonalMessage(messageObject)) {
personal_count--;
}
if (popupArray != null) {
popupArray.remove(messageObject);
}
newCount--;
}
}
if (newCount <= 0) {
newCount = 0;
smartNotificationsDialogs.remove(dialog_id);
}
if (!newCount.equals(currentCount)) {
total_unread_count -= currentCount;
total_unread_count += newCount;
pushDialogs.put(dialog_id, newCount);
}
if (newCount == 0) {
pushDialogs.remove(dialog_id);
pushDialogsOverrideMention.remove(dialog_id);
if (popupArray != null && pushMessages.isEmpty() && !popupArray.isEmpty()) {
popupArray.clear();
}
}
}
if (popupArray != null) {
AndroidUtilities.runOnUIThread(new Runnable() {
@Override
public void run() {
popupMessages = popupArray;
}
});
}
if (old_unread_count != total_unread_count) {
if (!notifyCheck) {
delayedPushMessages.clear();
showOrUpdateNotification(notifyCheck);
} else {
scheduleNotificationDelay(lastOnlineFromOtherDevice > ConnectionsManager.getInstance().getCurrentTime());
}
}
notifyCheck = false;
if (preferences.getBoolean("badgeNumber", true)) {
setBadge(total_unread_count);
}
}
});
}
public void processReadMessages(final SparseArray<Long> inbox, final long dialog_id, final int max_date, final int max_id, final boolean isPopup) { public void processReadMessages(final SparseArray<Long> inbox, final long dialog_id, final int max_date, final int max_id, final boolean isPopup) {
final ArrayList<MessageObject> popupArray = popupMessages.isEmpty() ? null : new ArrayList<>(popupMessages); final ArrayList<MessageObject> popupArray = popupMessages.isEmpty() ? null : new ArrayList<>(popupMessages);
notificationsQueue.postRunnable(new Runnable() { notificationsQueue.postRunnable(new Runnable() {
@ -314,7 +395,7 @@ public class NotificationsController {
playInChatSound(); playInChatSound();
continue; continue;
} }
if ((messageObject.messageOwner.flags & TLRPC.MESSAGE_FLAG_MENTION) != 0) { if (messageObject.messageOwner.mentioned) {
dialog_id = messageObject.messageOwner.from_id; dialog_id = messageObject.messageOwner.from_id;
} }
if (isPersonalMessage(messageObject)) { if (isPersonalMessage(messageObject)) {
@ -490,7 +571,7 @@ public class NotificationsController {
} }
long dialog_id = messageObject.getDialogId(); long dialog_id = messageObject.getDialogId();
long original_dialog_id = dialog_id; long original_dialog_id = dialog_id;
if ((messageObject.messageOwner.flags & TLRPC.MESSAGE_FLAG_MENTION) != 0) { if (messageObject.messageOwner.mentioned) {
dialog_id = messageObject.messageOwner.from_id; dialog_id = messageObject.messageOwner.from_id;
} }
Boolean value = settingsCache.get(dialog_id); Boolean value = settingsCache.get(dialog_id);
@ -650,7 +731,7 @@ public class NotificationsController {
} else if (messageObject.messageOwner.action instanceof TLRPC.TL_messageActionUserUpdatedPhoto) { } else if (messageObject.messageOwner.action instanceof TLRPC.TL_messageActionUserUpdatedPhoto) {
msg = LocaleController.formatString("NotificationContactNewPhoto", R.string.NotificationContactNewPhoto, name); msg = LocaleController.formatString("NotificationContactNewPhoto", R.string.NotificationContactNewPhoto, name);
} else if (messageObject.messageOwner.action instanceof TLRPC.TL_messageActionLoginUnknownLocation) { } else if (messageObject.messageOwner.action instanceof TLRPC.TL_messageActionLoginUnknownLocation) {
String date = LocaleController.formatString("formatDateAtTime", R.string.formatDateAtTime, LocaleController.formatterYear.format(((long) messageObject.messageOwner.date) * 1000), LocaleController.formatterDay.format(((long) messageObject.messageOwner.date) * 1000)); String date = LocaleController.formatString("formatDateAtTime", R.string.formatDateAtTime, LocaleController.getInstance().formatterYear.format(((long) messageObject.messageOwner.date) * 1000), LocaleController.getInstance().formatterDay.format(((long) messageObject.messageOwner.date) * 1000));
msg = LocaleController.formatString("NotificationUnrecognizedDevice", R.string.NotificationUnrecognizedDevice, UserConfig.getCurrentUser().first_name, date, messageObject.messageOwner.action.title, messageObject.messageOwner.action.address); msg = LocaleController.formatString("NotificationUnrecognizedDevice", R.string.NotificationUnrecognizedDevice, UserConfig.getCurrentUser().first_name, date, messageObject.messageOwner.action.title, messageObject.messageOwner.action.address);
} }
} else { } else {
@ -690,35 +771,54 @@ public class NotificationsController {
if (preferences.getBoolean("EnablePreviewGroup", true)) { if (preferences.getBoolean("EnablePreviewGroup", true)) {
if (messageObject.messageOwner instanceof TLRPC.TL_messageService) { if (messageObject.messageOwner instanceof TLRPC.TL_messageService) {
if (messageObject.messageOwner.action instanceof TLRPC.TL_messageActionChatAddUser) { if (messageObject.messageOwner.action instanceof TLRPC.TL_messageActionChatAddUser) {
if (messageObject.messageOwner.to_id.channel_id != 0) { int singleUserId = messageObject.messageOwner.action.user_id;
TLRPC.User user = MessagesController.getInstance().getUser(messageObject.messageOwner.action.user_id); if (singleUserId == 0 && messageObject.messageOwner.action.users.size() == 1) {
if (user != null) { singleUserId = messageObject.messageOwner.action.users.get(0);
name = UserObject.getUserName(user); }
} else { if (singleUserId != 0) {
name = ""; if (messageObject.messageOwner.to_id.channel_id != 0 && !messageObject.isMegagroup()) {
} TLRPC.User user = MessagesController.getInstance().getUser(singleUserId);
msg = LocaleController.formatString("ChannelAddedByNotification", R.string.ChannelAddedByNotification, name, chat.title); if (user != null) {
} else { name = UserObject.getUserName(user);
if (messageObject.messageOwner.action.user_id == UserConfig.getClientUserId()) {
msg = LocaleController.formatString("NotificationInvitedToGroup", R.string.NotificationInvitedToGroup, name, chat.title);
} else {
TLRPC.User u2 = MessagesController.getInstance().getUser(messageObject.messageOwner.action.user_id);
if (u2 == null) {
return null;
}
if (from_id == u2.id) {
msg = LocaleController.formatString("NotificationGroupAddSelf", R.string.NotificationGroupAddSelf, name, chat.title);
} else { } else {
msg = LocaleController.formatString("NotificationGroupAddMember", R.string.NotificationGroupAddMember, name, chat.title, UserObject.getUserName(u2)); name = "";
}
msg = LocaleController.formatString("ChannelAddedByNotification", R.string.ChannelAddedByNotification, name, chat.title);
} else {
if (singleUserId == UserConfig.getClientUserId()) {
msg = LocaleController.formatString("NotificationInvitedToGroup", R.string.NotificationInvitedToGroup, name, chat.title);
} else {
TLRPC.User u2 = MessagesController.getInstance().getUser(singleUserId);
if (u2 == null) {
return null;
}
if (from_id == u2.id) {
msg = LocaleController.formatString("NotificationGroupAddSelf", R.string.NotificationGroupAddSelf, name, chat.title);
} else {
msg = LocaleController.formatString("NotificationGroupAddMember", R.string.NotificationGroupAddMember, name, chat.title, UserObject.getUserName(u2));
}
} }
} }
} else {
StringBuilder names = new StringBuilder("");
for (int a = 0; a < messageObject.messageOwner.action.users.size(); a++) {
TLRPC.User user = MessagesController.getInstance().getUser(messageObject.messageOwner.action.users.get(a));
if (user != null) {
String name2 = UserObject.getUserName(user);
if (names.length() != 0) {
names.append(", ");
}
names.append(name2);
}
}
msg = LocaleController.formatString("NotificationGroupAddMember", R.string.NotificationGroupAddMember, name, chat.title, names.toString());
} }
} else if (messageObject.messageOwner.action instanceof TLRPC.TL_messageActionChatJoinedByLink) { } else if (messageObject.messageOwner.action instanceof TLRPC.TL_messageActionChatJoinedByLink) {
msg = LocaleController.formatString("NotificationInvitedToGroupByLink", R.string.NotificationInvitedToGroupByLink, name, chat.title); msg = LocaleController.formatString("NotificationInvitedToGroupByLink", R.string.NotificationInvitedToGroupByLink, name, chat.title);
} else if (messageObject.messageOwner.action instanceof TLRPC.TL_messageActionChatEditTitle) { } else if (messageObject.messageOwner.action instanceof TLRPC.TL_messageActionChatEditTitle) {
msg = LocaleController.formatString("NotificationEditedGroupName", R.string.NotificationEditedGroupName, name, messageObject.messageOwner.action.title); msg = LocaleController.formatString("NotificationEditedGroupName", R.string.NotificationEditedGroupName, name, messageObject.messageOwner.action.title);
} else if (messageObject.messageOwner.action instanceof TLRPC.TL_messageActionChatEditPhoto || messageObject.messageOwner.action instanceof TLRPC.TL_messageActionChatDeletePhoto) { } else if (messageObject.messageOwner.action instanceof TLRPC.TL_messageActionChatEditPhoto || messageObject.messageOwner.action instanceof TLRPC.TL_messageActionChatDeletePhoto) {
if (messageObject.messageOwner.to_id.channel_id != 0) { if (messageObject.messageOwner.to_id.channel_id != 0 && !messageObject.isMegagroup()) {
msg = LocaleController.formatString("ChannelPhotoEditNotification", R.string.ChannelPhotoEditNotification, chat.title); msg = LocaleController.formatString("ChannelPhotoEditNotification", R.string.ChannelPhotoEditNotification, chat.title);
} else { } else {
msg = LocaleController.formatString("NotificationEditedGroupPhoto", R.string.NotificationEditedGroupPhoto, name, chat.title); msg = LocaleController.formatString("NotificationEditedGroupPhoto", R.string.NotificationEditedGroupPhoto, name, chat.title);
@ -739,9 +839,13 @@ public class NotificationsController {
msg = messageObject.messageText.toString(); msg = messageObject.messageText.toString();
} else if (messageObject.messageOwner.action instanceof TLRPC.TL_messageActionChannelCreate) { } else if (messageObject.messageOwner.action instanceof TLRPC.TL_messageActionChannelCreate) {
msg = messageObject.messageText.toString(); msg = messageObject.messageText.toString();
} else if (messageObject.messageOwner.action instanceof TLRPC.TL_messageActionChatMigrateTo) {
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 { } else {
if (ChatObject.isChannel(chat)) { if (ChatObject.isChannel(chat) && !chat.megagroup) {
if (from_id < 0) { if (from_id < 0) {
if (messageObject.isMediaEmpty()) { if (messageObject.isMediaEmpty()) {
if (!shortMessage && messageObject.messageOwner.message != null && messageObject.messageOwner.message.length() != 0) { if (!shortMessage && messageObject.messageOwner.message != null && messageObject.messageOwner.message.length() != 0) {
@ -921,7 +1025,7 @@ public class NotificationsController {
notificationsQueue.postRunnable(new Runnable() { notificationsQueue.postRunnable(new Runnable() {
@Override @Override
public void run() { public void run() {
if (lastSoundPlay > System.currentTimeMillis() - 500) { if (Math.abs(System.currentTimeMillis() - lastSoundPlay) <= 500) {
return; return;
} }
try { try {
@ -992,7 +1096,7 @@ public class NotificationsController {
long dialog_id = lastMessageObject.getDialogId(); long dialog_id = lastMessageObject.getDialogId();
long override_dialog_id = dialog_id; long override_dialog_id = dialog_id;
if ((lastMessageObject.messageOwner.flags & TLRPC.MESSAGE_FLAG_MENTION) != 0) { if (lastMessageObject.messageOwner.mentioned) {
override_dialog_id = lastMessageObject.messageOwner.from_id; override_dialog_id = lastMessageObject.messageOwner.from_id;
} }
int mid = lastMessageObject.getId(); int mid = lastMessageObject.getId();
@ -1158,7 +1262,7 @@ public class NotificationsController {
String name; String name;
boolean replace = true; boolean replace = true;
if ((int)dialog_id == 0 || pushDialogs.size() > 1 || AndroidUtilities.needShowPasscode(false) || UserConfig.isWaitingForPasscodeEnter) { if ((int) dialog_id == 0 || pushDialogs.size() > 1 || AndroidUtilities.needShowPasscode(false) || UserConfig.isWaitingForPasscodeEnter) {
name = LocaleController.getString("AppName", R.string.AppName); name = LocaleController.getString("AppName", R.string.AppName);
replace = false; replace = false;
} else { } else {
@ -1348,10 +1452,24 @@ public class NotificationsController {
continue; continue;
} }
} }
if (chat != null) { TLRPC.FileLocation photoPath = null;
name = chat.title; if (AndroidUtilities.needShowPasscode(false) || UserConfig.isWaitingForPasscodeEnter) {
name = LocaleController.getString("AppName", R.string.AppName);
} else { } else {
name = UserObject.getUserName(user); if (chat != null) {
name = chat.title;
} else {
name = UserObject.getUserName(user);
}
if (chat != null) {
if (chat.photo != null && chat.photo.photo_small != null && chat.photo.photo_small.volume_id != 0 && chat.photo.photo_small.local_id != 0) {
photoPath = chat.photo.photo_small;
}
} else {
if (user.photo != null && user.photo.photo_small != null && user.photo.photo_small.volume_id != 0 && user.photo.photo_small.local_id != 0) {
photoPath = user.photo.photo_small;
}
}
} }
Integer notificationIdWear = oldIdsWear.get(dialog_id); Integer notificationIdWear = oldIdsWear.get(dialog_id);
@ -1380,7 +1498,7 @@ public class NotificationsController {
NotificationCompat.Action wearReplyAction = null; NotificationCompat.Action wearReplyAction = null;
if (!ChatObject.isChannel(chat)) { if (!ChatObject.isChannel(chat) && !AndroidUtilities.needShowPasscode(false) && !UserConfig.isWaitingForPasscodeEnter) {
Intent msgReplyIntent = new Intent(); Intent msgReplyIntent = new Intent();
msgReplyIntent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES); msgReplyIntent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
msgReplyIntent.setAction("org.telegram.messenger.ACTION_MESSAGE_REPLY"); msgReplyIntent.setAction("org.telegram.messenger.ACTION_MESSAGE_REPLY");
@ -1424,17 +1542,6 @@ public class NotificationsController {
unreadConvBuilder.addMessage(message); unreadConvBuilder.addMessage(message);
} }
TLRPC.FileLocation photoPath = null;
if (chat != null) {
if (chat.photo != null && chat.photo.photo_small != null && chat.photo.photo_small.volume_id != 0 && chat.photo.photo_small.local_id != 0) {
photoPath = chat.photo.photo_small;
}
} else {
if (user.photo != null && user.photo.photo_small != null && user.photo.photo_small.volume_id != 0 && user.photo.photo_small.local_id != 0) {
photoPath = user.photo.photo_small;
}
}
Intent intent = new Intent(ApplicationLoader.applicationContext, LaunchActivity.class); Intent intent = new Intent(ApplicationLoader.applicationContext, LaunchActivity.class);
intent.setAction("com.tmessages.openchat" + Math.random() + Integer.MAX_VALUE); intent.setAction("com.tmessages.openchat" + Math.random() + Integer.MAX_VALUE);
intent.setFlags(32768); intent.setFlags(32768);
@ -1496,7 +1603,7 @@ public class NotificationsController {
@Override @Override
public void run() { public void run() {
try { try {
if (lastSoundOutPlay > System.currentTimeMillis() - 100) { if (Math.abs(System.currentTimeMillis() - lastSoundOutPlay) <= 100) {
return; return;
} }
lastSoundOutPlay = System.currentTimeMillis(); lastSoundOutPlay = System.currentTimeMillis();

View File

@ -80,7 +80,9 @@ public class SecretChatHelper {
newMsg.action.encryptedAction = decryptedMessage; newMsg.action.encryptedAction = decryptedMessage;
newMsg.local_id = newMsg.id = UserConfig.getNewMessageId(); newMsg.local_id = newMsg.id = UserConfig.getNewMessageId();
newMsg.from_id = UserConfig.getClientUserId(); newMsg.from_id = UserConfig.getClientUserId();
newMsg.flags = TLRPC.MESSAGE_FLAG_UNREAD | TLRPC.MESSAGE_FLAG_OUT | TLRPC.MESSAGE_FLAG_HAS_FROM_ID; newMsg.unread = true;
newMsg.out = true;
newMsg.flags = TLRPC.MESSAGE_FLAG_HAS_FROM_ID;
newMsg.dialog_id = ((long) encryptedChat.id) << 32; newMsg.dialog_id = ((long) encryptedChat.id) << 32;
newMsg.to_id = new TLRPC.TL_peerUser(); newMsg.to_id = new TLRPC.TL_peerUser();
newMsg.send_state = MessageObject.MESSAGE_SEND_STATE_SENDING; newMsg.send_state = MessageObject.MESSAGE_SEND_STATE_SENDING;
@ -869,7 +871,8 @@ public class SecretChatHelper {
newMessage.to_id = new TLRPC.TL_peerUser(); newMessage.to_id = new TLRPC.TL_peerUser();
newMessage.random_id = random_id; newMessage.random_id = random_id;
newMessage.to_id.user_id = UserConfig.getClientUserId(); newMessage.to_id.user_id = UserConfig.getClientUserId();
newMessage.flags = TLRPC.MESSAGE_FLAG_UNREAD | TLRPC.MESSAGE_FLAG_HAS_MEDIA | TLRPC.MESSAGE_FLAG_HAS_FROM_ID; newMessage.unread = true;
newMessage.flags = TLRPC.MESSAGE_FLAG_HAS_MEDIA | TLRPC.MESSAGE_FLAG_HAS_FROM_ID;
newMessage.dialog_id = ((long) chat.id) << 32; newMessage.dialog_id = ((long) chat.id) << 32;
if (decryptedMessage.media instanceof TLRPC.TL_decryptedMessageMediaEmpty) { if (decryptedMessage.media instanceof TLRPC.TL_decryptedMessageMediaEmpty) {
newMessage.media = new TLRPC.TL_messageMediaEmpty(); newMessage.media = new TLRPC.TL_messageMediaEmpty();
@ -1043,7 +1046,8 @@ public class SecretChatHelper {
} }
newMessage.local_id = newMessage.id = UserConfig.getNewMessageId(); newMessage.local_id = newMessage.id = UserConfig.getNewMessageId();
UserConfig.saveConfig(false); UserConfig.saveConfig(false);
newMessage.flags = TLRPC.MESSAGE_FLAG_UNREAD | TLRPC.MESSAGE_FLAG_HAS_FROM_ID; newMessage.unread = true;
newMessage.flags = TLRPC.MESSAGE_FLAG_HAS_FROM_ID;
newMessage.date = date; newMessage.date = date;
newMessage.from_id = from_id; newMessage.from_id = from_id;
newMessage.to_id = new TLRPC.TL_peerUser(); newMessage.to_id = new TLRPC.TL_peerUser();

View File

@ -250,7 +250,8 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter
String file = (String) args[1]; String file = (String) args[1];
ArrayList<DelayedMessage> arr = delayedMessages.get(path); ArrayList<DelayedMessage> arr = delayedMessages.get(path);
if (arr != null) { if (arr != null) {
for (final DelayedMessage message : arr) { for (int a = 0; a < arr.size(); a++) {
final DelayedMessage message = arr.get(a);
if (message.type == 0) { if (message.type == 0) {
String md5 = Utilities.MD5(message.httpLocation) + ".jpg"; String md5 = Utilities.MD5(message.httpLocation) + ".jpg";
final File cacheFile = new File(FileLoader.getInstance().getDirectory(FileLoader.MEDIA_DIR_CACHE), md5); final File cacheFile = new File(FileLoader.getInstance().getDirectory(FileLoader.MEDIA_DIR_CACHE), md5);
@ -525,7 +526,7 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter
} }
public void sendMessage(TLRPC.User user, long peer, MessageObject reply_to_msg, boolean asAdmin) { public void sendMessage(TLRPC.User user, long peer, MessageObject reply_to_msg, boolean asAdmin) {
sendMessage(null, null, null, null, null, null, user, null, null, null, peer, false, null, reply_to_msg, null, true, asAdmin); sendMessage(null, null, null, null, null, user, null, null, null, peer, null, reply_to_msg, null, true, asAdmin, null);
} }
public void sendMessage(ArrayList<MessageObject> messages, final long peer, boolean asAdmin) { public void sendMessage(ArrayList<MessageObject> messages, final long peer, boolean asAdmin) {
@ -534,11 +535,15 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter
} }
int lower_id = (int) peer; int lower_id = (int) peer;
final TLRPC.Peer to_id = MessagesController.getPeer((int) peer); final TLRPC.Peer to_id = MessagesController.getPeer((int) peer);
boolean isMegagroup = false;
if (lower_id > 0) { if (lower_id > 0) {
TLRPC.User sendToUser = MessagesController.getInstance().getUser(lower_id); TLRPC.User sendToUser = MessagesController.getInstance().getUser(lower_id);
if (sendToUser == null) { if (sendToUser == null) {
return; return;
} }
} else {
TLRPC.Chat chat = MessagesController.getInstance().getChat(-lower_id);
isMegagroup = ChatObject.isChannel(chat) && chat.megagroup;
} }
ArrayList<MessageObject> objArr = new ArrayList<>(); ArrayList<MessageObject> objArr = new ArrayList<>();
@ -546,7 +551,8 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter
ArrayList<Long> randomIds = new ArrayList<>(); ArrayList<Long> randomIds = new ArrayList<>();
ArrayList<Integer> ids = new ArrayList<>(); ArrayList<Integer> ids = new ArrayList<>();
HashMap<Long, TLRPC.Message> messagesByRandomIds = new HashMap<>(); HashMap<Long, TLRPC.Message> messagesByRandomIds = new HashMap<>();
TLRPC.InputPeer inputPeer = MessagesController.getInputPeer((int) peer); TLRPC.InputPeer inputPeer = MessagesController.getInputPeer(lower_id);
long lastDialogId = 0;
for (int a = 0; a < messages.size(); a++) { for (int a = 0; a < messages.size(); a++) {
MessageObject msgObj = messages.get(a); MessageObject msgObj = messages.get(a);
if (msgObj.getId() <= 0) { if (msgObj.getId() <= 0) {
@ -571,6 +577,9 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter
if (newMsg.media != null) { if (newMsg.media != null) {
newMsg.flags |= TLRPC.MESSAGE_FLAG_HAS_MEDIA; newMsg.flags |= TLRPC.MESSAGE_FLAG_HAS_MEDIA;
} }
if (isMegagroup) {
newMsg.flags |= TLRPC.MESSAGE_FLAG_MEGAGROUP;
}
newMsg.message = msgObj.messageOwner.message; newMsg.message = msgObj.messageOwner.message;
newMsg.fwd_msg_id = msgObj.getId(); newMsg.fwd_msg_id = msgObj.getId();
newMsg.attachPath = msgObj.messageOwner.attachPath; newMsg.attachPath = msgObj.messageOwner.attachPath;
@ -582,8 +591,8 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter
newMsg.attachPath = ""; newMsg.attachPath = "";
} }
newMsg.local_id = newMsg.id = UserConfig.getNewMessageId(); newMsg.local_id = newMsg.id = UserConfig.getNewMessageId();
newMsg.flags |= TLRPC.MESSAGE_FLAG_OUT; newMsg.out = true;
if (asAdmin && to_id.channel_id != 0) { if (asAdmin && to_id.channel_id != 0 && !isMegagroup) {
newMsg.from_id = -to_id.channel_id; newMsg.from_id = -to_id.channel_id;
} else { } else {
newMsg.from_id = UserConfig.getClientUserId(); newMsg.from_id = UserConfig.getClientUserId();
@ -597,10 +606,10 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter
ids.add(newMsg.fwd_msg_id); ids.add(newMsg.fwd_msg_id);
newMsg.date = ConnectionsManager.getInstance().getCurrentTime(); newMsg.date = ConnectionsManager.getInstance().getCurrentTime();
if (newMsg.media instanceof TLRPC.TL_messageMediaAudio) { if (newMsg.media instanceof TLRPC.TL_messageMediaAudio) {
newMsg.flags |= TLRPC.MESSAGE_FLAG_CONTENT_UNREAD; newMsg.media_unread = true;
} }
if (inputPeer instanceof TLRPC.TL_inputPeerChannel) { if (inputPeer instanceof TLRPC.TL_inputPeerChannel) {
if (asAdmin) { if (asAdmin && !isMegagroup) {
newMsg.views = 1; newMsg.views = 1;
newMsg.flags |= TLRPC.MESSAGE_FLAG_HAS_VIEWS; newMsg.flags |= TLRPC.MESSAGE_FLAG_HAS_VIEWS;
} }
@ -609,18 +618,22 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter
newMsg.views = msgObj.messageOwner.views; newMsg.views = msgObj.messageOwner.views;
newMsg.flags |= TLRPC.MESSAGE_FLAG_HAS_VIEWS; newMsg.flags |= TLRPC.MESSAGE_FLAG_HAS_VIEWS;
} }
newMsg.flags |= TLRPC.MESSAGE_FLAG_UNREAD; newMsg.unread = true;
} }
newMsg.dialog_id = peer; newMsg.dialog_id = peer;
newMsg.to_id = to_id; newMsg.to_id = to_id;
if (msgObj.messageOwner.to_id instanceof TLRPC.TL_peerChannel) {
newMsg.ttl = -msgObj.messageOwner.to_id.channel_id;
}
MessageObject newMsgObj = new MessageObject(newMsg, null, true); MessageObject newMsgObj = new MessageObject(newMsg, null, true);
newMsgObj.messageOwner.send_state = MessageObject.MESSAGE_SEND_STATE_SENDING; newMsgObj.messageOwner.send_state = MessageObject.MESSAGE_SEND_STATE_SENDING;
objArr.add(newMsgObj); objArr.add(newMsgObj);
arr.add(newMsg); arr.add(newMsg);
putToSendingMessages(newMsg); putToSendingMessages(newMsg);
boolean differentDialog = false;
if (arr.size() == 100 || a == messages.size() - 1) { if (arr.size() == 100 || a == messages.size() - 1 || a != messages.size() - 1 && messages.get(a + 1).getDialogId() != msgObj.getDialogId()) {
MessagesStorage.getInstance().putMessages(new ArrayList<>(arr), false, true, false, 0); MessagesStorage.getInstance().putMessages(new ArrayList<>(arr), false, true, false, 0);
MessagesController.getInstance().updateInterfaceWithMessages(peer, objArr); MessagesController.getInstance().updateInterfaceWithMessages(peer, objArr);
NotificationCenter.getInstance().postNotificationName(NotificationCenter.dialogsNeedReload); NotificationCenter.getInstance().postNotificationName(NotificationCenter.dialogsNeedReload);
@ -635,12 +648,13 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter
} }
req.random_id = randomIds; req.random_id = randomIds;
req.id = ids; req.id = ids;
if (asAdmin && req.to_peer.channel_id != 0) { if (asAdmin && req.to_peer.channel_id != 0 && !isMegagroup) {
req.flags |= 16; req.broadcast = true;
} }
final ArrayList<TLRPC.Message> newMsgObjArr = arr; final ArrayList<TLRPC.Message> newMsgObjArr = arr;
final HashMap<Long, TLRPC.Message> messagesByRandomIdsFinal = messagesByRandomIds; final HashMap<Long, TLRPC.Message> messagesByRandomIdsFinal = messagesByRandomIds;
final boolean isMegagroupFinal = isMegagroup;
ConnectionsManager.getInstance().sendRequest(req, new RequestDelegate() { ConnectionsManager.getInstance().sendRequest(req, new RequestDelegate() {
@Override @Override
public void run(TLObject response, final TLRPC.TL_error error) { public void run(TLObject response, final TLRPC.TL_error error) {
@ -655,7 +669,8 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter
a--; a--;
} }
} }
for (TLRPC.Update update : updates.updates) { for (int a = 0; a < updates.updates.size(); a++) {
TLRPC.Update update = updates.updates.get(a);
if (update instanceof TLRPC.TL_updateNewMessage || update instanceof TLRPC.TL_updateNewChannelMessage) { if (update instanceof TLRPC.TL_updateNewMessage || update instanceof TLRPC.TL_updateNewChannelMessage) {
TLRPC.Message message; TLRPC.Message message;
if (update instanceof TLRPC.TL_updateNewMessage) { if (update instanceof TLRPC.TL_updateNewMessage) {
@ -664,6 +679,9 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter
} else { } else {
message = ((TLRPC.TL_updateNewChannelMessage) update).message; message = ((TLRPC.TL_updateNewChannelMessage) update).message;
MessagesController.getInstance().processNewChannelDifferenceParams(update.pts, update.pts_count, message.to_id.channel_id); MessagesController.getInstance().processNewChannelDifferenceParams(update.pts, update.pts_count, message.to_id.channel_id);
if (isMegagroupFinal) {
message.flags |= TLRPC.MESSAGE_FLAG_MEGAGROUP;
}
} }
Long random_id = newMessagesByIds.get(message.id); Long random_id = newMessagesByIds.get(message.id);
if (random_id != null) { if (random_id != null) {
@ -738,35 +756,35 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter
} }
} }
public void sendMessage(MessageObject message, boolean asAdmin) { public void sendMessage(MessageObject retryMessageObject, boolean asAdmin) {
sendMessage(null, null, null, null, null, message, null, null, null, null, message.getDialogId(), true, message.messageOwner.attachPath, null, null, true, asAdmin); sendMessage(null, null, null, null, null, null, null, null, null, retryMessageObject.getDialogId(), retryMessageObject.messageOwner.attachPath, null, null, true, asAdmin, retryMessageObject);
} }
public void sendMessage(TLRPC.TL_document document, String originalPath, String path, long peer, MessageObject reply_to_msg, boolean asAdmin) { public void sendMessage(TLRPC.TL_document document, String originalPath, String path, long peer, MessageObject reply_to_msg, boolean asAdmin) {
sendMessage(null, null, null, null, null, null, null, document, null, originalPath, peer, false, path, reply_to_msg, null, true, asAdmin); sendMessage(null, null, null, null, null, null, document, null, originalPath, peer, path, reply_to_msg, null, true, asAdmin, null);
} }
public void sendMessage(String message, long peer, MessageObject reply_to_msg, TLRPC.WebPage webPage, boolean searchLinks, boolean asAdmin) { public void sendMessage(String message, long peer, MessageObject reply_to_msg, TLRPC.WebPage webPage, boolean searchLinks, boolean asAdmin) {
sendMessage(message, null, null, null, null, null, null, null, null, null, peer, false, null, reply_to_msg, webPage, searchLinks, asAdmin); sendMessage(message, null, null, null, null, null, null, null, null, peer, null, reply_to_msg, webPage, searchLinks, asAdmin, null);
} }
public void sendMessage(TLRPC.MessageMedia location, long peer, MessageObject reply_to_msg, boolean asAdmin) { public void sendMessage(TLRPC.MessageMedia location, long peer, MessageObject reply_to_msg, boolean asAdmin) {
sendMessage(null, location, null, null, null, null, null, null, null, null, peer, false, null, reply_to_msg, null, true, asAdmin); sendMessage(null, location, null, null, null, null, null, null, null, peer, null, reply_to_msg, null, true, asAdmin, null);
} }
public void sendMessage(TLRPC.TL_photo photo, String originalPath, String path, long peer, MessageObject reply_to_msg, boolean asAdmin) { public void sendMessage(TLRPC.TL_photo photo, String originalPath, String path, long peer, MessageObject reply_to_msg, boolean asAdmin) {
sendMessage(null, null, photo, null, null, null, null, null, null, originalPath, peer, false, path, reply_to_msg, null, true, asAdmin); sendMessage(null, null, photo, null, null, null, null, null, originalPath, peer, path, reply_to_msg, null, true, asAdmin, null);
} }
public void sendMessage(TLRPC.TL_video video, VideoEditedInfo videoEditedInfo, String originalPath, String path, long peer, MessageObject reply_to_msg, boolean asAdmin) { public void sendMessage(TLRPC.TL_video video, VideoEditedInfo videoEditedInfo, String originalPath, String path, long peer, MessageObject reply_to_msg, boolean asAdmin) {
sendMessage(null, null, null, video, videoEditedInfo, null, null, null, null, originalPath, peer, false, path, reply_to_msg, null, true, asAdmin); sendMessage(null, null, null, video, videoEditedInfo, null, null, null, originalPath, peer, path, reply_to_msg, null, true, asAdmin, null);
} }
public void sendMessage(TLRPC.TL_audio audio, String path, long peer, MessageObject reply_to_msg, boolean asAdmin) { public void sendMessage(TLRPC.TL_audio audio, String path, long peer, MessageObject reply_to_msg, boolean asAdmin) {
sendMessage(null, null, null, null, null, null, null, null, audio, null, peer, false, path, reply_to_msg, null, true, asAdmin); sendMessage(null, null, null, null, null, null, null, audio, null, peer, path, reply_to_msg, null, true, asAdmin, null);
} }
private void sendMessage(String message, TLRPC.MessageMedia location, TLRPC.TL_photo photo, TLRPC.TL_video video, VideoEditedInfo videoEditedInfo, MessageObject msgObj, TLRPC.User user, TLRPC.TL_document document, TLRPC.TL_audio audio, String originalPath, long peer, boolean retry, String path, MessageObject reply_to_msg, TLRPC.WebPage webPage, boolean searchLinks, boolean asAdmin) { private void sendMessage(String message, TLRPC.MessageMedia location, TLRPC.TL_photo photo, TLRPC.TL_video video, VideoEditedInfo videoEditedInfo, TLRPC.User user, TLRPC.TL_document document, TLRPC.TL_audio audio, String originalPath, long peer, String path, MessageObject reply_to_msg, TLRPC.WebPage webPage, boolean searchLinks, boolean asAdmin, MessageObject retryMessageObject) {
if (peer == 0) { if (peer == 0) {
return; return;
} }
@ -782,57 +800,54 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter
if (lower_id == 0) { if (lower_id == 0) {
encryptedChat = MessagesController.getInstance().getEncryptedChat(high_id); encryptedChat = MessagesController.getInstance().getEncryptedChat(high_id);
if (encryptedChat == null) { if (encryptedChat == null) {
if (msgObj != null) { if (retryMessageObject != null) {
MessagesStorage.getInstance().markMessageAsSendError(msgObj.messageOwner); MessagesStorage.getInstance().markMessageAsSendError(retryMessageObject.messageOwner);
msgObj.messageOwner.send_state = MessageObject.MESSAGE_SEND_STATE_SEND_ERROR; retryMessageObject.messageOwner.send_state = MessageObject.MESSAGE_SEND_STATE_SEND_ERROR;
NotificationCenter.getInstance().postNotificationName(NotificationCenter.messageSendError, msgObj.getId()); NotificationCenter.getInstance().postNotificationName(NotificationCenter.messageSendError, retryMessageObject.getId());
processSentMessage(msgObj.getId()); processSentMessage(retryMessageObject.getId());
} }
return; return;
} }
} else if (asAdmin && sendToPeer instanceof TLRPC.TL_inputPeerChannel) {
TLRPC.Chat chat = MessagesController.getInstance().getChat(sendToPeer.channel_id);
if (chat.megagroup) {
asAdmin = false;
}
} }
try { try {
if (retry) { if (retryMessageObject != null) {
newMsg = msgObj.messageOwner; newMsg = retryMessageObject.messageOwner;
if (msgObj.type == 0) { if (retryMessageObject.isForwarded()) {
if (msgObj.isForwarded()) { type = 4;
type = 4; } else {
} else { if (retryMessageObject.type == 0) {
message = newMsg.message; message = newMsg.message;
type = 0; type = 0;
} } else if (retryMessageObject.type == 4) {
} else if (msgObj.type == 4) { location = newMsg.media;
location = newMsg.media; type = 1;
type = 1; } else if (retryMessageObject.type == 1) {
} else if (msgObj.type == 1) {
if (msgObj.isForwarded()) {
type = 4;
} else {
photo = (TLRPC.TL_photo) newMsg.media.photo; photo = (TLRPC.TL_photo) newMsg.media.photo;
type = 2; type = 2;
} } else if (retryMessageObject.type == 3) {
} else if (msgObj.type == 3) {
if (msgObj.isForwarded()) {
type = 4;
} else {
type = 3; type = 3;
video = (TLRPC.TL_video) newMsg.media.video; video = (TLRPC.TL_video) newMsg.media.video;
} else if (retryMessageObject.type == 12) {
user = new TLRPC.TL_userRequest_old2();
user.phone = newMsg.media.phone_number;
user.first_name = newMsg.media.first_name;
user.last_name = newMsg.media.last_name;
user.id = newMsg.media.user_id;
type = 6;
} else if (retryMessageObject.type == 8 || retryMessageObject.type == 9 || retryMessageObject.type == 13) {
document = (TLRPC.TL_document) newMsg.media.document;
type = 7;
} else if (retryMessageObject.type == 2) {
audio = (TLRPC.TL_audio) newMsg.media.audio;
type = 8;
} }
} else if (msgObj.type == 12) {
user = new TLRPC.TL_userRequest_old2();
user.phone = newMsg.media.phone_number;
user.first_name = newMsg.media.first_name;
user.last_name = newMsg.media.last_name;
user.id = newMsg.media.user_id;
type = 6;
} else if (msgObj.type == 8 || msgObj.type == 9 || msgObj.type == 13) {
document = (TLRPC.TL_document) newMsg.media.document;
type = 7;
} else if (msgObj.type == 2) {
audio = (TLRPC.TL_audio) newMsg.media.audio;
type = 8;
} }
} else { } else {
if (message != null) { if (message != null) {
@ -891,22 +906,6 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter
newMsg.message = videoEditedInfo.getString(); newMsg.message = videoEditedInfo.getString();
} }
newMsg.attachPath = path; newMsg.attachPath = path;
} else if (msgObj != null) {
newMsg = new TLRPC.TL_message();
newMsg.flags |= TLRPC.MESSAGE_FLAG_FWD;
if (msgObj.isForwarded()) {
newMsg.fwd_from_id = msgObj.messageOwner.fwd_from_id;
newMsg.fwd_date = msgObj.messageOwner.fwd_date;
} else {
newMsg.fwd_from_id = new TLRPC.TL_peerUser();
newMsg.fwd_from_id.user_id = msgObj.messageOwner.from_id;
newMsg.fwd_date = msgObj.messageOwner.date;
}
newMsg.media = msgObj.messageOwner.media;
newMsg.message = msgObj.messageOwner.message;
newMsg.fwd_msg_id = msgObj.getId();
newMsg.attachPath = msgObj.messageOwner.attachPath;
type = 4;
} else if (user != null) { } else if (user != null) {
if (encryptedChat != null && AndroidUtilities.getPeerLayerVersion(encryptedChat.layer) >= 17) { if (encryptedChat != null && AndroidUtilities.getPeerLayerVersion(encryptedChat.layer) >= 17) {
newMsg = new TLRPC.TL_message_secret(); newMsg = new TLRPC.TL_message_secret();
@ -953,7 +952,7 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter
newMsg.attachPath = ""; newMsg.attachPath = "";
} }
newMsg.local_id = newMsg.id = UserConfig.getNewMessageId(); newMsg.local_id = newMsg.id = UserConfig.getNewMessageId();
newMsg.flags |= TLRPC.MESSAGE_FLAG_OUT; newMsg.out = true;
if (asAdmin && sendToPeer != null && sendToPeer.channel_id != 0) { if (asAdmin && sendToPeer != null && sendToPeer.channel_id != 0) {
newMsg.from_id = -sendToPeer.channel_id; newMsg.from_id = -sendToPeer.channel_id;
} else { } else {
@ -968,15 +967,19 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter
newMsg.date = ConnectionsManager.getInstance().getCurrentTime(); newMsg.date = ConnectionsManager.getInstance().getCurrentTime();
newMsg.flags |= TLRPC.MESSAGE_FLAG_HAS_MEDIA; newMsg.flags |= TLRPC.MESSAGE_FLAG_HAS_MEDIA;
if (encryptedChat == null && high_id != 1 && newMsg.media instanceof TLRPC.TL_messageMediaAudio) { if (encryptedChat == null && high_id != 1 && newMsg.media instanceof TLRPC.TL_messageMediaAudio) {
newMsg.flags |= TLRPC.MESSAGE_FLAG_CONTENT_UNREAD; newMsg.media_unread = true;
} }
if (sendToPeer instanceof TLRPC.TL_inputPeerChannel) { if (sendToPeer instanceof TLRPC.TL_inputPeerChannel) {
if (asAdmin) { if (asAdmin) {
newMsg.views = 1; newMsg.views = 1;
newMsg.flags |= TLRPC.MESSAGE_FLAG_HAS_VIEWS; newMsg.flags |= TLRPC.MESSAGE_FLAG_HAS_VIEWS;
} }
TLRPC.Chat chat = MessagesController.getInstance().getChat(sendToPeer.channel_id);
if (chat != null && chat.megagroup) {
newMsg.flags |= TLRPC.MESSAGE_FLAG_MEGAGROUP;
}
} else { } else {
newMsg.flags |= TLRPC.MESSAGE_FLAG_UNREAD; newMsg.unread = true;
} }
newMsg.dialog_id = peer; newMsg.dialog_id = peer;
if (reply_to_msg != null) { if (reply_to_msg != null) {
@ -992,7 +995,7 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter
return; return;
} }
sendToPeers = new ArrayList<>(); sendToPeers = new ArrayList<>();
for (TLRPC.TL_chatParticipant participant : currentChatInfo.participants.participants) { for (TLRPC.ChatParticipant participant : currentChatInfo.participants.participants) {
TLRPC.User sendToUser = MessagesController.getInstance().getUser(participant.user_id); TLRPC.User sendToUser = MessagesController.getInstance().getUser(participant.user_id);
TLRPC.InputUser peerUser = MessagesController.getInputUser(sendToUser); TLRPC.InputUser peerUser = MessagesController.getInputUser(sendToUser);
if (peerUser != null) { if (peerUser != null) {
@ -1009,8 +1012,8 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter
processSentMessage(newMsg.id); processSentMessage(newMsg.id);
return; return;
} }
if ((sendToUser.flags & TLRPC.USER_FLAG_BOT) != 0) { if (sendToUser.bot) {
newMsg.flags &= ~TLRPC.MESSAGE_FLAG_UNREAD; newMsg.unread = false;
} }
} }
} }
@ -1062,14 +1065,14 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter
reqSend.peer = sendToPeer; reqSend.peer = sendToPeer;
reqSend.random_id = newMsg.random_id; reqSend.random_id = newMsg.random_id;
if (asAdmin && sendToPeer instanceof TLRPC.TL_inputPeerChannel) { if (asAdmin && sendToPeer instanceof TLRPC.TL_inputPeerChannel) {
reqSend.flags |= 16; reqSend.broadcast = true;
} }
if (reply_to_msg != null) { if (reply_to_msg != null) {
reqSend.flags |= 1; reqSend.flags |= 1;
reqSend.reply_to_msg_id = reply_to_msg.getId(); reqSend.reply_to_msg_id = reply_to_msg.getId();
} }
if (!searchLinks) { if (!searchLinks) {
reqSend.flags |= 2; reqSend.no_webpage = true;
} }
performSendMessageRequest(reqSend, newMsgObj.messageOwner, null); performSendMessageRequest(reqSend, newMsgObj.messageOwner, null);
} }
@ -1223,7 +1226,7 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter
request.random_id = newMsg.random_id; request.random_id = newMsg.random_id;
request.media = inputMedia; request.media = inputMedia;
if (asAdmin && sendToPeer instanceof TLRPC.TL_inputPeerChannel) { if (asAdmin && sendToPeer instanceof TLRPC.TL_inputPeerChannel) {
request.flags |= 16; request.broadcast = true;
} }
if (reply_to_msg != null) { if (reply_to_msg != null) {
request.flags |= 1; request.flags |= 1;
@ -1444,13 +1447,21 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter
} }
} }
} else if (type == 4) { } else if (type == 4) {
TLRPC.TL_messages_forwardMessage reqSend = new TLRPC.TL_messages_forwardMessage(); //TODO remove TLRPC.TL_messages_forwardMessages reqSend = new TLRPC.TL_messages_forwardMessages();
reqSend.peer = sendToPeer; reqSend.to_peer = sendToPeer;
reqSend.random_id = newMsg.random_id; if (retryMessageObject.messageOwner.ttl != 0) {
if (msgObj.getId() >= 0) { reqSend.from_peer = MessagesController.getInputPeer(retryMessageObject.messageOwner.ttl);
reqSend.id = msgObj.getId();
} else { } else {
reqSend.id = msgObj.messageOwner.fwd_msg_id; reqSend.from_peer = new TLRPC.TL_inputPeerEmpty();
}
reqSend.random_id.add(newMsg.random_id);
if (retryMessageObject.getId() >= 0) {
reqSend.id.add(retryMessageObject.getId());
} else {
reqSend.id.add(retryMessageObject.messageOwner.fwd_msg_id);
}
if (asAdmin && reqSend.to_peer.channel_id != 0) {
reqSend.broadcast = true;
} }
performSendMessageRequest(reqSend, newMsgObj.messageOwner, null); performSendMessageRequest(reqSend, newMsgObj.messageOwner, null);
} }
@ -1608,6 +1619,8 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter
newMsgObj.local_id = newMsgObj.id = res.id; newMsgObj.local_id = newMsgObj.id = res.id;
newMsgObj.date = res.date; newMsgObj.date = res.date;
newMsgObj.entities = res.entities; newMsgObj.entities = res.entities;
newMsgObj.out = res.out;
newMsgObj.unread = res.unread;
if (res.media != null) { if (res.media != null) {
newMsgObj.media = res.media; newMsgObj.media = res.media;
newMsgObj.flags |= TLRPC.MESSAGE_FLAG_HAS_MEDIA; newMsgObj.flags |= TLRPC.MESSAGE_FLAG_HAS_MEDIA;
@ -1632,6 +1645,9 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter
TLRPC.TL_updateNewChannelMessage newMessage = (TLRPC.TL_updateNewChannelMessage) update; TLRPC.TL_updateNewChannelMessage newMessage = (TLRPC.TL_updateNewChannelMessage) update;
sentMessages.add(newMessage.message); sentMessages.add(newMessage.message);
newMsgObj.id = newMessage.message.id; newMsgObj.id = newMessage.message.id;
if ((newMsgObj.flags & TLRPC.MESSAGE_FLAG_MEGAGROUP) != 0) {
newMessage.message.flags |= TLRPC.MESSAGE_FLAG_MEGAGROUP;
}
processSentMessage(newMsgObj, newMessage.message, originalPath); processSentMessage(newMsgObj, newMessage.message, originalPath);
MessagesController.getInstance().processNewChannelDifferenceParams(newMessage.pts, newMessage.pts_count, newMessage.message.to_id.channel_id); MessagesController.getInstance().processNewChannelDifferenceParams(newMessage.pts, newMessage.pts_count, newMessage.message.to_id.channel_id);
ok = true; ok = true;
@ -1848,6 +1864,8 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter
} }
} else if (sentMessage.media instanceof TLRPC.TL_messageMediaContact && newMsg.media instanceof TLRPC.TL_messageMediaContact) { } else if (sentMessage.media instanceof TLRPC.TL_messageMediaContact && newMsg.media instanceof TLRPC.TL_messageMediaContact) {
newMsg.media = sentMessage.media; newMsg.media = sentMessage.media;
} else if (sentMessage.media instanceof TLRPC.TL_messageMediaWebPage) {
newMsg.media = sentMessage.media;
} }
} }

View File

@ -61,7 +61,7 @@ public class TgChooserTargetService extends ChooserTargetService {
ArrayList<Integer> usersToLoad = new ArrayList<>(); ArrayList<Integer> usersToLoad = new ArrayList<>();
usersToLoad.add(UserConfig.getClientUserId()); usersToLoad.add(UserConfig.getClientUserId());
ArrayList<Integer> chatsToLoad = new ArrayList<>(); ArrayList<Integer> chatsToLoad = new ArrayList<>();
SQLiteCursor cursor = MessagesStorage.getInstance().getDatabase().queryFinalized(String.format(Locale.US, "SELECT did FROM dialogs ORDER BY date DESC LIMIT %d,%d", 0, 20)); SQLiteCursor cursor = MessagesStorage.getInstance().getDatabase().queryFinalized(String.format(Locale.US, "SELECT did FROM dialogs ORDER BY date DESC LIMIT %d,%d", 0, 30));
while (cursor.next()) { while (cursor.next()) {
long id = cursor.longValue(0); long id = cursor.longValue(0);
@ -109,11 +109,13 @@ public class TgChooserTargetService extends ChooserTargetService {
for (int b = 0; b < users.size(); b++) { for (int b = 0; b < users.size(); b++) {
TLRPC.User user = users.get(b); TLRPC.User user = users.get(b);
if (user.id == id) { if (user.id == id) {
extras.putLong("dialogId", (long) id); if (!user.bot) {
if (user.photo != null && user.photo.photo_small != null) { extras.putLong("dialogId", (long) id);
icon = createRoundBitmap(FileLoader.getPathToAttach(user.photo.photo_small, true)); if (user.photo != null && user.photo.photo_small != null) {
icon = createRoundBitmap(FileLoader.getPathToAttach(user.photo.photo_small, true));
}
name = ContactsController.formatName(user.first_name, user.last_name);
} }
name = ContactsController.formatName(user.first_name, user.last_name);
break; break;
} }
} }
@ -121,11 +123,13 @@ public class TgChooserTargetService extends ChooserTargetService {
for (int b = 0; b < chats.size(); b++) { for (int b = 0; b < chats.size(); b++) {
TLRPC.Chat chat = chats.get(b); TLRPC.Chat chat = chats.get(b);
if (chat.id == -id) { if (chat.id == -id) {
extras.putLong("dialogId", (long) id); if (!ChatObject.isNotInChat(chat) && (!ChatObject.isChannel(chat) || chat.megagroup)) {
if (chat.photo != null && chat.photo.photo_small != null) { extras.putLong("dialogId", (long) id);
icon = createRoundBitmap(FileLoader.getPathToAttach(chat.photo.photo_small, true)); if (chat.photo != null && chat.photo.photo_small != null) {
icon = createRoundBitmap(FileLoader.getPathToAttach(chat.photo.photo_small, true));
}
name = chat.title;
} }
name = chat.title;
break; break;
} }
} }

View File

@ -41,7 +41,13 @@ public class UserConfig {
public static boolean useFingerprint = true; public static boolean useFingerprint = true;
public static int lastUpdateVersion; public static int lastUpdateVersion;
public static int lastContactsSyncTime; public static int lastContactsSyncTime;
public static boolean channelsLoaded = false;
public static int migrateOffsetId = -1;
public static int migrateOffsetDate = -1;
public static int migrateOffsetUserId = -1;
public static int migrateOffsetChatId = -1;
public static int migrateOffsetChannelId = -1;
public static long migrateOffsetAccess = -1;
public static int getNewMessageId() { public static int getNewMessageId() {
int id; int id;
@ -79,9 +85,17 @@ public class UserConfig {
editor.putInt("lastPauseTime", lastPauseTime); editor.putInt("lastPauseTime", lastPauseTime);
editor.putInt("lastUpdateVersion", lastUpdateVersion); editor.putInt("lastUpdateVersion", lastUpdateVersion);
editor.putInt("lastContactsSyncTime", lastContactsSyncTime); editor.putInt("lastContactsSyncTime", lastContactsSyncTime);
editor.putBoolean("channelsLoaded", channelsLoaded);
editor.putBoolean("useFingerprint", useFingerprint); editor.putBoolean("useFingerprint", useFingerprint);
editor.putInt("migrateOffsetId", migrateOffsetId);
if (migrateOffsetId != -1) {
editor.putInt("migrateOffsetDate", migrateOffsetDate);
editor.putInt("migrateOffsetUserId", migrateOffsetUserId);
editor.putInt("migrateOffsetChatId", migrateOffsetChatId);
editor.putInt("migrateOffsetChannelId", migrateOffsetChannelId);
editor.putLong("migrateOffsetAccess", migrateOffsetAccess);
}
if (currentUser != null) { if (currentUser != null) {
if (withFile) { if (withFile) {
SerializedData data = new SerializedData(); SerializedData data = new SerializedData();
@ -212,7 +226,16 @@ public class UserConfig {
useFingerprint = preferences.getBoolean("useFingerprint", true); useFingerprint = preferences.getBoolean("useFingerprint", true);
lastUpdateVersion = preferences.getInt("lastUpdateVersion", 511); lastUpdateVersion = preferences.getInt("lastUpdateVersion", 511);
lastContactsSyncTime = preferences.getInt("lastContactsSyncTime", (int) (System.currentTimeMillis() / 1000) - 23 * 60 * 60); lastContactsSyncTime = preferences.getInt("lastContactsSyncTime", (int) (System.currentTimeMillis() / 1000) - 23 * 60 * 60);
channelsLoaded = preferences.getBoolean("channelsLoaded", false);
migrateOffsetId = preferences.getInt("migrateOffsetId", 0);
if (migrateOffsetId != -1) {
migrateOffsetDate = preferences.getInt("migrateOffsetDate", 0);
migrateOffsetUserId = preferences.getInt("migrateOffsetUserId", 0);
migrateOffsetChatId = preferences.getInt("migrateOffsetChatId", 0);
migrateOffsetChannelId = preferences.getInt("migrateOffsetChannelId", 0);
migrateOffsetAccess = preferences.getLong("migrateOffsetAccess", 0);
}
String user = preferences.getString("user", null); String user = preferences.getString("user", null);
if (user != null) { if (user != null) {
byte[] userBytes = Base64.decode(user, Base64.DEFAULT); byte[] userBytes = Base64.decode(user, Base64.DEFAULT);
@ -277,7 +300,12 @@ public class UserConfig {
lastBroadcastId = -1; lastBroadcastId = -1;
saveIncomingPhotos = false; saveIncomingPhotos = false;
blockedUsersLoaded = false; blockedUsersLoaded = false;
channelsLoaded = false; migrateOffsetId = -1;
migrateOffsetDate = -1;
migrateOffsetUserId = -1;
migrateOffsetChatId = -1;
migrateOffsetChannelId = -1;
migrateOffsetAccess = -1;
appLocked = false; appLocked = false;
passcodeType = 0; passcodeType = 0;
passcodeHash = ""; passcodeHash = "";

View File

@ -14,15 +14,15 @@ import org.telegram.tgnet.TLRPC;
public class UserObject { public class UserObject {
public static boolean isDeleted(TLRPC.User user) { public static boolean isDeleted(TLRPC.User user) {
return user == null || user instanceof TLRPC.TL_userDeleted_old2 || user instanceof TLRPC.TL_userEmpty || (user.flags & TLRPC.USER_FLAG_DELETED) != 0; return user == null || user instanceof TLRPC.TL_userDeleted_old2 || user instanceof TLRPC.TL_userEmpty || user.deleted;
} }
public static boolean isContact(TLRPC.User user) { public static boolean isContact(TLRPC.User user) {
return user instanceof TLRPC.TL_userContact_old2 || (user.flags & TLRPC.USER_FLAG_CONTACT) != 0 || (user.flags & TLRPC.USER_FLAG_MUTUAL_CONTACT) != 0; return user instanceof TLRPC.TL_userContact_old2 || user.contact || user.mutual_contact;
} }
public static boolean isUserSelf(TLRPC.User user) { public static boolean isUserSelf(TLRPC.User user) {
return user instanceof TLRPC.TL_userSelf_old3 || (user.flags & TLRPC.USER_FLAG_SELF) != 0; return user instanceof TLRPC.TL_userSelf_old3 || user.self;
} }
public static String getUserName(TLRPC.User user) { public static String getUserName(TLRPC.User user) {

View File

@ -32,6 +32,6 @@ public class WearReplyReceiver extends BroadcastReceiver {
return; return;
} }
SendMessagesHelper.getInstance().sendMessage(text.toString(), dialog_id, null, null, true, false); SendMessagesHelper.getInstance().sendMessage(text.toString(), dialog_id, null, null, true, false);
MessagesController.getInstance().markDialogAsRead(dialog_id, max_id, max_id, 0, 0, true, false); MessagesController.getInstance().markDialogAsRead(dialog_id, max_id, max_id, 0, true, false);
} }
} }

View File

@ -20,18 +20,19 @@ import org.telegram.tgnet.TLRPC;
import java.util.ArrayList; import java.util.ArrayList;
@SuppressWarnings("unchecked")
public class MessagesSearchQuery { public class MessagesSearchQuery {
private static int reqId; private static int reqId;
private static int lastReqId; private static int lastReqId;
private static boolean messagesSearchEndReached; private static boolean messagesSearchEndReached[] = new boolean[] {false, false};
private static ArrayList<MessageObject> searchResultMessages = new ArrayList<>(); private static ArrayList<MessageObject> searchResultMessages = new ArrayList<>();
private static String lastSearchQuery; private static String lastSearchQuery;
private static int lastReturnedNum; private static int lastReturnedNum;
private static int getMask() { private static int getMask() {
int mask = 0; int mask = 0;
if (lastReturnedNum < searchResultMessages.size() - 1) { if (lastReturnedNum < searchResultMessages.size() - 1 || !messagesSearchEndReached[0] || !messagesSearchEndReached[1]) {
mask |= 1; mask |= 1;
} }
if (lastReturnedNum > 0) { if (lastReturnedNum > 0) {
@ -40,25 +41,37 @@ public class MessagesSearchQuery {
return mask; return mask;
} }
public static void searchMessagesInChat(String query, long dialog_id, final int guid, int direction) { public static void searchMessagesInChat(String query, final long dialog_id, final long mergeDialogId, final int guid, int direction) {
if (reqId != 0) { if (reqId != 0) {
ConnectionsManager.getInstance().cancelRequest(reqId, true); ConnectionsManager.getInstance().cancelRequest(reqId, true);
reqId = 0; reqId = 0;
} }
int max_id = 0; int max_id = 0;
long queryWithDialog = dialog_id;
if (query == null || query.length() == 0) { if (query == null || query.length() == 0) {
if (direction == 1) { if (direction == 1) {
lastReturnedNum++; lastReturnedNum++;
if (lastReturnedNum < searchResultMessages.size()) { if (lastReturnedNum < searchResultMessages.size()) {
NotificationCenter.getInstance().postNotificationName(NotificationCenter.chatSearchResultsAvailable, guid, searchResultMessages.get(lastReturnedNum).getId(), getMask()); MessageObject messageObject = searchResultMessages.get(lastReturnedNum);
NotificationCenter.getInstance().postNotificationName(NotificationCenter.chatSearchResultsAvailable, guid, messageObject.getId(), getMask(), messageObject.getDialogId());
return; return;
} else { } else {
if (messagesSearchEndReached) { if (messagesSearchEndReached[0] && mergeDialogId == 0 || messagesSearchEndReached[1]) {
lastReturnedNum--; lastReturnedNum--;
return; return;
} }
query = lastSearchQuery; query = lastSearchQuery;
max_id = searchResultMessages.get(searchResultMessages.size() - 1).getId(); MessageObject messageObject = searchResultMessages.get(searchResultMessages.size() - 1);
if (messageObject.getDialogId() == dialog_id && !messagesSearchEndReached[0]) {
max_id = messageObject.getId();
queryWithDialog = dialog_id;
} else {
if (messageObject.getDialogId() == mergeDialogId) {
max_id = messageObject.getId();
}
queryWithDialog = mergeDialogId;
messagesSearchEndReached[1] = false;
}
} }
} else if (direction == 2) { } else if (direction == 2) {
lastReturnedNum--; lastReturnedNum--;
@ -66,15 +79,22 @@ public class MessagesSearchQuery {
lastReturnedNum = 0; lastReturnedNum = 0;
return; return;
} }
NotificationCenter.getInstance().postNotificationName(NotificationCenter.chatSearchResultsAvailable, guid, searchResultMessages.get(lastReturnedNum).getId(), getMask()); if (lastReturnedNum >= searchResultMessages.size()) {
lastReturnedNum = searchResultMessages.size() - 1;
}
MessageObject messageObject = searchResultMessages.get(lastReturnedNum);
NotificationCenter.getInstance().postNotificationName(NotificationCenter.chatSearchResultsAvailable, guid, messageObject.getId(), getMask(), messageObject.getDialogId());
return; return;
} else { } else {
return; return;
} }
} }
if (messagesSearchEndReached[0] && !messagesSearchEndReached[1] && mergeDialogId != 0) {
queryWithDialog = mergeDialogId;
}
final TLRPC.TL_messages_search req = new TLRPC.TL_messages_search(); final TLRPC.TL_messages_search req = new TLRPC.TL_messages_search();
req.limit = 21; req.limit = 21;
int lower_part = (int) dialog_id; int lower_part = (int) queryWithDialog;
req.peer = MessagesController.getInputPeer(lower_part); req.peer = MessagesController.getInputPeer(lower_part);
if (req.peer == null) { if (req.peer == null) {
return; return;
@ -84,19 +104,21 @@ public class MessagesSearchQuery {
req.filter = new TLRPC.TL_inputMessagesFilterEmpty(); req.filter = new TLRPC.TL_inputMessagesFilterEmpty();
final int currentReqId = ++lastReqId; final int currentReqId = ++lastReqId;
lastSearchQuery = query; lastSearchQuery = query;
final long queryWithDialogFinal = queryWithDialog;
reqId = ConnectionsManager.getInstance().sendRequest(req, new RequestDelegate() { reqId = ConnectionsManager.getInstance().sendRequest(req, new RequestDelegate() {
@Override @Override
public void run(final TLObject response, final TLRPC.TL_error error) { public void run(final TLObject response, final TLRPC.TL_error error) {
AndroidUtilities.runOnUIThread(new Runnable() { AndroidUtilities.runOnUIThread(new Runnable() {
@Override @Override
public void run() { public void run() {
reqId = 0;
if (currentReqId == lastReqId) { if (currentReqId == lastReqId) {
if (error == null) { if (error == null) {
TLRPC.messages_Messages res = (TLRPC.messages_Messages) response; TLRPC.messages_Messages res = (TLRPC.messages_Messages) response;
MessagesStorage.getInstance().putUsersAndChats(res.users, res.chats, true, true); MessagesStorage.getInstance().putUsersAndChats(res.users, res.chats, true, true);
MessagesController.getInstance().putUsers(res.users, false); MessagesController.getInstance().putUsers(res.users, false);
MessagesController.getInstance().putChats(res.chats, false); MessagesController.getInstance().putChats(res.chats, false);
if (req.max_id == 0) { if (req.max_id == 0 && queryWithDialogFinal == dialog_id) {
lastReturnedNum = 0; lastReturnedNum = 0;
searchResultMessages.clear(); searchResultMessages.clear();
} }
@ -106,17 +128,27 @@ public class MessagesSearchQuery {
added = true; added = true;
searchResultMessages.add(new MessageObject(message, null, false)); searchResultMessages.add(new MessageObject(message, null, false));
} }
messagesSearchEndReached = res.messages.size() != 21; messagesSearchEndReached[queryWithDialogFinal == dialog_id ? 0 : 1] = res.messages.size() != 21;
if (mergeDialogId == 0) {
messagesSearchEndReached[1] = messagesSearchEndReached[0];
}
if (searchResultMessages.isEmpty()) { if (searchResultMessages.isEmpty()) {
NotificationCenter.getInstance().postNotificationName(NotificationCenter.chatSearchResultsAvailable, guid, 0, getMask()); NotificationCenter.getInstance().postNotificationName(NotificationCenter.chatSearchResultsAvailable, guid, 0, getMask(), (long) 0);
} else { } else {
if (added) { if (added) {
NotificationCenter.getInstance().postNotificationName(NotificationCenter.chatSearchResultsAvailable, guid, searchResultMessages.get(lastReturnedNum).getId(), getMask()); if (lastReturnedNum >= searchResultMessages.size()) {
lastReturnedNum = searchResultMessages.size() - 1;
}
MessageObject messageObject = searchResultMessages.get(lastReturnedNum);
NotificationCenter.getInstance().postNotificationName(NotificationCenter.chatSearchResultsAvailable, guid, messageObject.getId(), getMask(), messageObject.getDialogId());
} }
} }
if (queryWithDialogFinal == dialog_id && messagesSearchEndReached[0] && mergeDialogId != 0) {
messagesSearchEndReached[1] = false;
searchMessagesInChat(lastSearchQuery, dialog_id, mergeDialogId, guid, 0);
}
} }
} }
reqId = 0;
} }
}); });
} }

View File

@ -82,39 +82,7 @@ public class ReplyMessageQuery {
message.id = cursor.intValue(1); message.id = cursor.intValue(1);
message.date = cursor.intValue(2); message.date = cursor.intValue(2);
message.dialog_id = dialog_id; message.dialog_id = dialog_id;
if (message.from_id > 0) { MessagesStorage.addUsersAndChatsFromMessage(message, usersToLoad, chatsToLoad);
if (!usersToLoad.contains(message.from_id)) {
usersToLoad.add(message.from_id);
}
} else {
if (!chatsToLoad.contains(-message.from_id)) {
chatsToLoad.add(-message.from_id);
}
}
if (message.action != null && message.action.user_id != 0) {
if (!usersToLoad.contains(message.action.user_id)) {
usersToLoad.add(message.action.user_id);
}
}
if (message.media != null && message.media.user_id != 0) {
if (!usersToLoad.contains(message.media.user_id)) {
usersToLoad.add(message.media.user_id);
}
}
if (message.media != null && message.media.audio != null && message.media.audio.user_id != 0) {
if (!usersToLoad.contains(message.media.audio.user_id)) {
usersToLoad.add(message.media.audio.user_id);
}
}
if (message.fwd_from_id instanceof TLRPC.TL_peerUser) {
if (!usersToLoad.contains(message.fwd_from_id.user_id)) {
usersToLoad.add(message.fwd_from_id.user_id);
}
} else if (message.fwd_from_id instanceof TLRPC.TL_peerChannel) {
if (!chatsToLoad.contains(message.fwd_from_id.channel_id)) {
chatsToLoad.add(message.fwd_from_id.channel_id);
}
}
result.add(message); result.add(message);
replyMessages.remove((Integer) message.id); replyMessages.remove((Integer) message.id);
} }
@ -206,9 +174,15 @@ public class ReplyMessageQuery {
} }
private static void broadcastReplyMessages(final ArrayList<TLRPC.Message> result, final HashMap<Integer, ArrayList<MessageObject>> replyMessageOwners, final ArrayList<TLRPC.User> users, final ArrayList<TLRPC.Chat> chats, final long dialog_id, final boolean isCache) { private static void broadcastReplyMessages(final ArrayList<TLRPC.Message> result, final HashMap<Integer, ArrayList<MessageObject>> replyMessageOwners, final ArrayList<TLRPC.User> users, final ArrayList<TLRPC.Chat> chats, final long dialog_id, final boolean isCache) {
final HashMap<Integer, TLRPC.User> usersHashMap = new HashMap<>(); final HashMap<Integer, TLRPC.User> usersDict = new HashMap<>();
for (TLRPC.User user : users) { for (int a = 0; a < users.size(); a++) {
usersHashMap.put(user.id, user); 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);
} }
AndroidUtilities.runOnUIThread(new Runnable() { AndroidUtilities.runOnUIThread(new Runnable() {
@Override @Override
@ -216,11 +190,13 @@ public class ReplyMessageQuery {
MessagesController.getInstance().putUsers(users, isCache); MessagesController.getInstance().putUsers(users, isCache);
MessagesController.getInstance().putChats(chats, isCache); MessagesController.getInstance().putChats(chats, isCache);
boolean changed = false; boolean changed = false;
for (TLRPC.Message message : result) { for (int a = 0; a < result.size(); a++) {
TLRPC.Message message = result.get(a);
ArrayList<MessageObject> arrayList = replyMessageOwners.get(message.id); ArrayList<MessageObject> arrayList = replyMessageOwners.get(message.id);
if (arrayList != null) { if (arrayList != null) {
MessageObject messageObject = new MessageObject(message, usersHashMap, false); MessageObject messageObject = new MessageObject(message, usersDict, chatsDict, false);
for (MessageObject m : arrayList) { for (int b = 0; b < arrayList.size(); b++) {
MessageObject m = arrayList.get(b);
m.replyMessageObject = messageObject; m.replyMessageObject = messageObject;
} }
changed = true; changed = true;

View File

@ -197,13 +197,15 @@ public class SharedMediaQuery {
putMediaDatabase(uid, type, res.messages, max_id, topReached); putMediaDatabase(uid, type, res.messages, max_id, topReached);
} }
final HashMap<Integer, TLRPC.User> usersLocal = new HashMap<>(); final HashMap<Integer, TLRPC.User> usersDict = new HashMap<>();
for (TLRPC.User u : res.users) { for (int a = 0; a < res.users.size(); a++) {
usersLocal.put(u.id, u); TLRPC.User u = res.users.get(a);
usersDict.put(u.id, u);
} }
final ArrayList<MessageObject> objects = new ArrayList<>(); final ArrayList<MessageObject> objects = new ArrayList<>();
for (TLRPC.Message message : res.messages) { for (int a = 0; a < res.messages.size(); a++) {
objects.add(new MessageObject(message, usersLocal, true)); TLRPC.Message message = res.messages.get(a);
objects.add(new MessageObject(message, usersDict, true));
} }
AndroidUtilities.runOnUIThread(new Runnable() { AndroidUtilities.runOnUIThread(new Runnable() {
@ -273,37 +275,6 @@ public class SharedMediaQuery {
} }
cursor.dispose(); cursor.dispose();
/*cursor = MessagesStorage.getInstance().getDatabase().queryFinalized(String.format(Locale.US, "SELECT data, send_state, date FROM messages WHERE uid = %d ORDER BY mid ASC LIMIT %d", uid, 1000));
ArrayList<TLRPC.Message> photos = new ArrayList<>();
ArrayList<TLRPC.Message> docs = new ArrayList<>();
while (cursor.next()) {
NativeByteBuffer data = new NativeByteBuffer(cursor.byteArrayLength(1));
if (data != null && cursor.byteBufferValue(1, data) != 0) {
TLRPC.Message message = (TLRPC.Message) TLClassStore.Instance().TLdeserialize(data, data.readInt32());
MessageObject.setIsUnread(message, cursor.intValue(0) != 1);
message.date = cursor.intValue(2);
message.send_state = cursor.intValue(1);
message.dialog_id = uid;
if (message.ttl > 60 && message.media instanceof TLRPC.TL_messageMediaPhoto || message.media instanceof TLRPC.TL_messageMediaVideo) {
photos.add(message);
} else if (message.media instanceof TLRPC.TL_messageMediaDocument) {
docs.add(message);
}
}
data.reuse();
}
cursor.dispose();
if (!photos.isEmpty() || !docs.isEmpty()) {
MessagesStorage.getInstance().getDatabase().beginTransaction();
if (!photos.isEmpty()) {
putMediaDatabaseInternal(uid, MEDIA_PHOTOVIDEO, photos);
}
if (docs.isEmpty()) {
putMediaDatabaseInternal(uid, MEDIA_FILE, docs);
}
MessagesStorage.getInstance().getDatabase().commitTransaction();
}*/
if (count != -1) { if (count != -1) {
putMediaCountDatabase(uid, type, count); putMediaCountDatabase(uid, type, count);
} }

View File

@ -74,7 +74,7 @@ public class StickersQuery {
if (document != null) { if (document != null) {
long setId = getStickerSetId(document); long setId = getStickerSetId(document);
TLRPC.TL_messages_stickerSet stickerSet = stickerSetsById.get(setId); TLRPC.TL_messages_stickerSet stickerSet = stickerSetsById.get(setId);
if (stickerSet != null && (stickerSet.set.flags & 2) != 0) { if (stickerSet != null && stickerSet.set.disabled) {
return null; return null;
} }
} }
@ -156,7 +156,9 @@ public class StickersQuery {
TLRPC.TL_messages_stickerSet oldSet = stickerSetsById.get(stickerSet.id); TLRPC.TL_messages_stickerSet oldSet = stickerSetsById.get(stickerSet.id);
if (oldSet != null && oldSet.set.hash == stickerSet.hash) { if (oldSet != null && oldSet.set.hash == stickerSet.hash) {
oldSet.set.flags = stickerSet.flags; oldSet.set.disabled = stickerSet.disabled;
oldSet.set.installed = stickerSet.installed;
oldSet.set.official = stickerSet.official;
newStickerSets.put(oldSet.set.id, oldSet); newStickerSets.put(oldSet.set.id, oldSet);
newStickerArray.add(oldSet); newStickerArray.add(oldSet);
@ -206,24 +208,32 @@ public class StickersQuery {
@Override @Override
public void run() { public void run() {
try { try {
SQLitePreparedStatement state = MessagesStorage.getInstance().getDatabase().executeFast("REPLACE INTO stickers_v2 VALUES(?, ?, ?, ?)"); if (stickers != null) {
state.requery(); SQLitePreparedStatement state = MessagesStorage.getInstance().getDatabase().executeFast("REPLACE INTO stickers_v2 VALUES(?, ?, ?, ?)");
int size = 4; state.requery();
for (int a = 0; a < stickers.size(); a++) { int size = 4;
size += stickers.get(a).getObjectSize(); for (int a = 0; a < stickers.size(); a++) {
size += stickers.get(a).getObjectSize();
}
NativeByteBuffer data = new NativeByteBuffer(size);
data.writeInt32(stickers.size());
for (int a = 0; a < stickers.size(); a++) {
stickers.get(a).serializeToStream(data);
}
state.bindInteger(1, 1);
state.bindByteBuffer(2, data);
state.bindInteger(3, date);
state.bindString(4, hash);
state.step();
data.reuse();
state.dispose();
} else {
SQLitePreparedStatement state = MessagesStorage.getInstance().getDatabase().executeFast("UPDATE stickers_v2 SET date = ?");
state.requery();
state.bindInteger(1, date);
state.step();
state.dispose();
} }
NativeByteBuffer data = new NativeByteBuffer(size);
data.writeInt32(stickers.size());
for (int a = 0; a < stickers.size(); a++) {
stickers.get(a).serializeToStream(data);
}
state.bindInteger(1, 1);
state.bindByteBuffer(2, data);
state.bindInteger(3, date);
state.bindString(4, hash);
state.step();
data.reuse();
state.dispose();
} catch (Exception e) { } catch (Exception e) {
FileLog.e("tmessages", e); FileLog.e("tmessages", e);
} }
@ -291,7 +301,7 @@ public class StickersQuery {
} }
stickersByIdNew.put(document.id, document); stickersByIdNew.put(document.id, document);
} }
if ((stickerSet.set.flags & 2) == 0) { if (!stickerSet.set.disabled) {
for (int b = 0; b < stickerSet.packs.size(); b++) { for (int b = 0; b < stickerSet.packs.size(); b++) {
TLRPC.TL_stickerPack stickerPack = stickerSet.packs.get(b); TLRPC.TL_stickerPack stickerPack = stickerSet.packs.get(b);
if (stickerPack == null || stickerPack.emoticon == null) { if (stickerPack == null || stickerPack.emoticon == null) {
@ -333,6 +343,14 @@ public class StickersQuery {
} catch (Throwable e) { } catch (Throwable e) {
FileLog.e("tmessages", e); FileLog.e("tmessages", e);
} }
} else if (!cache) {
AndroidUtilities.runOnUIThread(new Runnable() {
@Override
public void run() {
loadDate = date;
}
});
putStickersToCache(null, date, null);
} }
} }
}); });
@ -433,11 +451,7 @@ public class StickersQuery {
stickerSetID.access_hash = stickerSet.access_hash; stickerSetID.access_hash = stickerSet.access_hash;
stickerSetID.id = stickerSet.id; stickerSetID.id = stickerSet.id;
if (hide != 0) { if (hide != 0) {
if (hide == 1) { stickerSet.disabled = hide == 1;
stickerSet.flags |= 2;
} else {
stickerSet.flags &= ~2;
}
NotificationCenter.getInstance().postNotificationName(NotificationCenter.stickersDidLoaded); NotificationCenter.getInstance().postNotificationName(NotificationCenter.stickersDidLoaded);
TLRPC.TL_messages_installStickerSet req = new TLRPC.TL_messages_installStickerSet(); TLRPC.TL_messages_installStickerSet req = new TLRPC.TL_messages_installStickerSet();
req.stickerset = stickerSetID; req.stickerset = stickerSetID;

View File

@ -27,6 +27,7 @@ import java.net.InterfaceAddress;
import java.net.NetworkInterface; import java.net.NetworkInterface;
import java.util.Enumeration; import java.util.Enumeration;
import java.util.List; import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
public class ConnectionsManager { public class ConnectionsManager {
@ -57,7 +58,7 @@ public class ConnectionsManager {
private int lastClassGuid = 1; private int lastClassGuid = 1;
private boolean isUpdating = false; private boolean isUpdating = false;
private int connectionState = native_getConnectionState(); private int connectionState = native_getConnectionState();
private volatile int lastRequestToken = 1; private AtomicInteger lastRequestToken = new AtomicInteger(1);
private PowerManager.WakeLock wakeLock = null; private PowerManager.WakeLock wakeLock = null;
private static volatile ConnectionsManager Instance = null; private static volatile ConnectionsManager Instance = null;
@ -114,11 +115,11 @@ public class ConnectionsManager {
} }
public int sendRequest(final TLObject object, final RequestDelegate onComplete, final QuickAckDelegate onQuickAck, final int flags, final int datacenterId, final int connetionType, final boolean immediate) { public int sendRequest(final TLObject object, final RequestDelegate onComplete, final QuickAckDelegate onQuickAck, final int flags, final int datacenterId, final int connetionType, final boolean immediate) {
final int requestToken = lastRequestToken++; final int requestToken = lastRequestToken.getAndIncrement();
Utilities.stageQueue.postRunnable(new Runnable() { Utilities.stageQueue.postRunnable(new Runnable() {
@Override @Override
public void run() { public void run() {
FileLog.d("tmessages", "send request " + object); FileLog.d("tmessages", "send request " + object + " with token = " + requestToken);
NativeByteBuffer buffer = new NativeByteBuffer(object.getObjectSize()); NativeByteBuffer buffer = new NativeByteBuffer(object.getObjectSize());
object.serializeToStream(buffer); object.serializeToStream(buffer);
object.freeResources(); object.freeResources();

File diff suppressed because it is too large Load Diff

View File

@ -896,7 +896,7 @@ public class ActionBarLayout extends FrameLayout {
onCloseAnimationEndRunnable = new Runnable() { onCloseAnimationEndRunnable = new Runnable() {
@Override @Override
public void run() { public void run() {
removeFragmentFromStack(currentFragment); removeFragmentFromStackInternal(currentFragment);
setVisibility(GONE); setVisibility(GONE);
if (backgroundView != null) { if (backgroundView != null) {
backgroundView.setVisibility(GONE); backgroundView.setVisibility(GONE);
@ -935,7 +935,7 @@ public class ActionBarLayout extends FrameLayout {
}); });
currentAnimation.start(); currentAnimation.start();
} else { } else {
removeFragmentFromStack(currentFragment); removeFragmentFromStackInternal(currentFragment);
setVisibility(GONE); setVisibility(GONE);
if (backgroundView != null) { if (backgroundView != null) {
backgroundView.setVisibility(GONE); backgroundView.setVisibility(GONE);
@ -998,16 +998,24 @@ public class ActionBarLayout extends FrameLayout {
} }
} }
public void removeFragmentFromStack(BaseFragment fragment) { private void removeFragmentFromStackInternal(BaseFragment fragment) {
fragment.onPause(); fragment.onPause();
fragment.onFragmentDestroy(); fragment.onFragmentDestroy();
fragment.setParentLayout(null); fragment.setParentLayout(null);
fragmentsStack.remove(fragment); fragmentsStack.remove(fragment);
} }
public void removeFragmentFromStack(BaseFragment fragment) {
if (useAlphaAnimations && fragmentsStack.size() == 1 && AndroidUtilities.isTablet()) {
closeLastFragment(true);
} else {
removeFragmentFromStackInternal(fragment);
}
}
public void removeAllFragments() { public void removeAllFragments() {
for (int a = 0; a < fragmentsStack.size(); a++) { for (int a = 0; a < fragmentsStack.size(); a++) {
removeFragmentFromStack(fragmentsStack.get(a)); removeFragmentFromStackInternal(fragmentsStack.get(a));
a--; a--;
} }
} }

View File

@ -288,7 +288,6 @@ public class ActionBarMenuItem extends FrameLayoutFixed {
} }
if (popupWindow == null) { if (popupWindow == null) {
popupWindow = new ActionBarPopupWindow(popupLayout, LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT); popupWindow = new ActionBarPopupWindow(popupLayout, LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT);
//popupWindow.setBackgroundDrawable(new BitmapDrawable());
if (Build.VERSION.SDK_INT >= 19) { if (Build.VERSION.SDK_INT >= 19) {
popupWindow.setAnimationStyle(0); popupWindow.setAnimationStyle(0);
} else { } else {

View File

@ -90,13 +90,22 @@ public class ActionBarPopupWindow extends PopupWindow {
setPadding(AndroidUtilities.dp(8), AndroidUtilities.dp(8), AndroidUtilities.dp(8), AndroidUtilities.dp(8)); setPadding(AndroidUtilities.dp(8), AndroidUtilities.dp(8), AndroidUtilities.dp(8), AndroidUtilities.dp(8));
setWillNotDraw(false); setWillNotDraw(false);
scrollView = new ScrollView(context); try {
scrollView.setVerticalScrollBarEnabled(false); scrollView = new ScrollView(context);
addView(scrollView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT)); scrollView.setVerticalScrollBarEnabled(false);
addView(scrollView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT));
} catch (Throwable e) {
FileLog.e("tmessages", e);
}
linearLayout = new LinearLayout(context); linearLayout = new LinearLayout(context);
linearLayout.setOrientation(LinearLayout.VERTICAL); linearLayout.setOrientation(LinearLayout.VERTICAL);
scrollView.addView(linearLayout, new ScrollView.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT)); if (scrollView != null) {
scrollView.addView(linearLayout, new ScrollView.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT));
} else {
addView(linearLayout, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT));
}
} }
public void setShowedFromBotton(boolean value) { public void setShowedFromBotton(boolean value) {
@ -215,7 +224,9 @@ public class ActionBarPopupWindow extends PopupWindow {
} }
public void scrollToTop() { public void scrollToTop() {
scrollView.scrollTo(0, 0); if (scrollView != null) {
scrollView.scrollTo(0, 0);
}
} }
} }
@ -374,6 +385,7 @@ public class ActionBarPopupWindow extends PopupWindow {
} }
public void dismiss(boolean animated) { public void dismiss(boolean animated) {
setFocusable(false);
if (animationEnabled && animated) { if (animationEnabled && animated) {
if (windowAnimatorSet != null) { if (windowAnimatorSet != null) {
windowAnimatorSet.cancel(); windowAnimatorSet.cancel();
@ -414,7 +426,6 @@ public class ActionBarPopupWindow extends PopupWindow {
}); });
windowAnimatorSet.start(); windowAnimatorSet.start();
} else { } else {
setFocusable(false);
try { try {
super.dismiss(); super.dismiss();
} catch (Exception e) { } catch (Exception e) {

View File

@ -31,6 +31,7 @@ import android.view.View;
import android.view.ViewAnimationUtils; import android.view.ViewAnimationUtils;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.view.Window; import android.view.Window;
import android.view.WindowInsets;
import android.view.WindowManager; import android.view.WindowManager;
import android.view.animation.AccelerateInterpolator; import android.view.animation.AccelerateInterpolator;
import android.view.animation.DecelerateInterpolator; import android.view.animation.DecelerateInterpolator;
@ -55,6 +56,7 @@ public class BottomSheet extends Dialog {
private LinearLayout containerView; private LinearLayout containerView;
private FrameLayout container; private FrameLayout container;
private Object lastInsets;
private boolean dismissed; private boolean dismissed;
private int tag; private int tag;
@ -70,6 +72,8 @@ public class BottomSheet extends Dialog {
private ColorDrawable backgroundDrawable = new ColorDrawable(0xff000000); private ColorDrawable backgroundDrawable = new ColorDrawable(0xff000000);
private static Drawable shadowDrawable; private static Drawable shadowDrawable;
private boolean focusable;
private Paint ciclePaint = new Paint(Paint.ANTI_ALIAS_FLAG); private Paint ciclePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
private static int backgroundPaddingTop; private static int backgroundPaddingTop;
@ -193,10 +197,11 @@ public class BottomSheet extends Dialog {
} }
} }
public BottomSheet(Context context) { public BottomSheet(Context context, boolean needFocus) {
super(context); super(context);
container = new FrameLayout(getContext()) { container = new FrameLayout(getContext()) {
@Override @Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int width = MeasureSpec.getSize(widthMeasureSpec); int width = MeasureSpec.getSize(widthMeasureSpec);
@ -225,7 +230,12 @@ public class BottomSheet extends Dialog {
if (child.getVisibility() == GONE || child == containerView) { if (child.getVisibility() == GONE || child == containerView) {
continue; continue;
} }
measureChildWithMargins(child, widthMeasureSpec, 0, heightMeasureSpec, 0); if (lastInsets != null && Build.VERSION.SDK_INT >= 21) {
WindowInsets wi = (WindowInsets) lastInsets;
wi = wi.replaceSystemWindowInsets(wi.getSystemWindowInsetLeft(), wi.getSystemWindowInsetTop(), 0, wi.getSystemWindowInsetBottom());
child.dispatchApplyWindowInsets(wi);
}
measureChildWithMargins(child, MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY), 0, MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY), 0);
} }
} }
@ -296,8 +306,18 @@ public class BottomSheet extends Dialog {
} }
}); });
container.setBackgroundDrawable(backgroundDrawable); container.setBackgroundDrawable(backgroundDrawable);
if (Build.VERSION.SDK_INT >= 21) { focusable = needFocus;
if (Build.VERSION.SDK_INT >= 21 && !focusable) {
container.setFitsSystemWindows(true); container.setFitsSystemWindows(true);
container.setOnApplyWindowInsetsListener(new View.OnApplyWindowInsetsListener() {
@SuppressLint("NewApi")
@Override
public WindowInsets onApplyWindowInsets(View v, WindowInsets insets) {
lastInsets = insets;
container.requestLayout();
return insets.consumeSystemWindowInsets();
}
});
container.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN); container.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
} }
} }
@ -424,9 +444,13 @@ public class BottomSheet extends Dialog {
WindowManager.LayoutParams params = getWindow().getAttributes(); WindowManager.LayoutParams params = getWindow().getAttributes();
params.width = ViewGroup.LayoutParams.MATCH_PARENT; params.width = ViewGroup.LayoutParams.MATCH_PARENT;
params.gravity = Gravity.TOP | Gravity.LEFT; params.gravity = Gravity.TOP | Gravity.LEFT;
params.flags |= WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM; if (!focusable) {
params.dimAmount = 0; params.flags |= WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
params.flags &= ~WindowManager.LayoutParams.FLAG_DIM_BEHIND; params.dimAmount = 0;
params.flags &= ~WindowManager.LayoutParams.FLAG_DIM_BEHIND;
} else {
params.dimAmount = 0.2f;
}
if (Build.VERSION.SDK_INT < 21) { if (Build.VERSION.SDK_INT < 21) {
params.height = ViewGroup.LayoutParams.MATCH_PARENT; params.height = ViewGroup.LayoutParams.MATCH_PARENT;
} }
@ -436,6 +460,9 @@ public class BottomSheet extends Dialog {
@Override @Override
public void show() { public void show() {
super.show(); super.show();
if (focusable) {
getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);
}
dismissed = false; dismissed = false;
if (Build.VERSION.SDK_INT >= 21 || !useRevealAnimation) { if (Build.VERSION.SDK_INT >= 21 || !useRevealAnimation) {
containerView.setBackgroundDrawable(shadowDrawable); containerView.setBackgroundDrawable(shadowDrawable);
@ -592,7 +619,7 @@ public class BottomSheet extends Dialog {
AnimatorSetProxy animatorSetProxy = new AnimatorSetProxy(); AnimatorSetProxy animatorSetProxy = new AnimatorSetProxy();
animatorSetProxy.playTogether( animatorSetProxy.playTogether(
ObjectAnimatorProxy.ofFloat(containerView, "translationY", 0), ObjectAnimatorProxy.ofFloat(containerView, "translationY", 0),
ObjectAnimatorProxy.ofInt(backgroundDrawable, "alpha", 51)); ObjectAnimatorProxy.ofInt(backgroundDrawable, "alpha", focusable ? 0 : 51));
animatorSetProxy.setDuration(200); animatorSetProxy.setDuration(200);
animatorSetProxy.setStartDelay(20); animatorSetProxy.setStartDelay(20);
animatorSetProxy.setInterpolator(new DecelerateInterpolator()); animatorSetProxy.setInterpolator(new DecelerateInterpolator());
@ -718,7 +745,11 @@ public class BottomSheet extends Dialog {
private BottomSheet bottomSheet; private BottomSheet bottomSheet;
public Builder(Context context) { public Builder(Context context) {
bottomSheet = new BottomSheet(context); bottomSheet = new BottomSheet(context, false);
}
public Builder(Context context, boolean needFocus) {
bottomSheet = new BottomSheet(context, needFocus);
} }
public Builder setItems(CharSequence[] items, final OnClickListener onClickListener) { public Builder setItems(CharSequence[] items, final OnClickListener onClickListener) {

View File

@ -41,7 +41,7 @@ public class BaseSearchAdapter extends BaseFragmentAdapter {
protected HashMap<String, HashtagObject> hashtagsByText; protected HashMap<String, HashtagObject> hashtagsByText;
protected boolean hashtagsLoadedFromDb = false; protected boolean hashtagsLoadedFromDb = false;
public void queryServerSearch(final String query, final boolean allowChats) { public void queryServerSearch(final String query, final boolean allowChats, final boolean allowBots) {
if (reqId != 0) { if (reqId != 0) {
ConnectionsManager.getInstance().cancelRequest(reqId, true); ConnectionsManager.getInstance().cancelRequest(reqId, true);
reqId = 0; reqId = 0;
@ -72,6 +72,9 @@ public class BaseSearchAdapter extends BaseFragmentAdapter {
} }
} }
for (int a = 0; a < res.users.size(); a++) { for (int a = 0; a < res.users.size(); a++) {
if (!allowBots && res.users.get(a).bot) {
continue;
}
globalSearch.add(res.users.get(a)); globalSearch.add(res.users.get(a));
} }
lastFoundUsername = query; lastFoundUsername = query;

View File

@ -238,7 +238,7 @@ public class ContactsAdapter extends BaseSectionsAdapter {
} }
} else if (type == 0) { } else if (type == 0) {
if (convertView == null) { if (convertView == null) {
convertView = new UserCell(mContext, 58); convertView = new UserCell(mContext, 58, 1);
((UserCell) convertView).setStatusColors(0xffa8a8a8, 0xff3b84c0); ((UserCell) convertView).setStatusColors(0xffa8a8a8, 0xff3b84c0);
} }

View File

@ -46,7 +46,7 @@ public class DialogsAdapter extends RecyclerView.Adapter {
public boolean isDataSetChanged() { public boolean isDataSetChanged() {
int current = currentCount; int current = currentCount;
return current != getItemCount(); return current != getItemCount() || current == 1;
} }
private ArrayList<TLRPC.Dialog> getDialogsArray() { private ArrayList<TLRPC.Dialog> getDialogsArray() {

View File

@ -16,6 +16,7 @@ import android.view.ViewGroup;
import org.telegram.SQLite.SQLiteCursor; import org.telegram.SQLite.SQLiteCursor;
import org.telegram.SQLite.SQLitePreparedStatement; import org.telegram.SQLite.SQLitePreparedStatement;
import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.AndroidUtilities;
import org.telegram.messenger.ChatObject;
import org.telegram.messenger.ContactsController; import org.telegram.messenger.ContactsController;
import org.telegram.messenger.LocaleController; import org.telegram.messenger.LocaleController;
import org.telegram.messenger.MessageObject; import org.telegram.messenger.MessageObject;
@ -128,15 +129,29 @@ public class DialogsSearchAdapter extends BaseSearchAdapterRecycler {
} }
return; return;
} }
final TLRPC.TL_messages_search req = new TLRPC.TL_messages_search();
final TLRPC.TL_messages_searchGlobal req = new TLRPC.TL_messages_searchGlobal();
req.limit = 20; req.limit = 20;
req.peer = new TLRPC.TL_inputPeerEmpty();
req.q = query; req.q = query;
if (lastMessagesSearchString != null && query.equals(lastMessagesSearchString) && !searchResultMessages.isEmpty()) { if (lastMessagesSearchString != null && query.equals(lastMessagesSearchString) && !searchResultMessages.isEmpty()) {
req.max_id = searchResultMessages.get(searchResultMessages.size() - 1).getId(); MessageObject lastMessage = searchResultMessages.get(searchResultMessages.size() - 1);
req.offset_id = lastMessage.getId();
req.offset_date = lastMessage.messageOwner.date;
int id;
if (lastMessage.messageOwner.to_id.channel_id != 0) {
id = -lastMessage.messageOwner.to_id.channel_id;
} else if (lastMessage.messageOwner.to_id.chat_id != 0) {
id = -lastMessage.messageOwner.to_id.chat_id;
} else {
id = lastMessage.messageOwner.to_id.user_id;
}
req.offset_peer = MessagesController.getInputPeer(id);
} else {
req.offset_date = 0;
req.offset_id = 0;
req.offset_peer = new TLRPC.TL_inputPeerEmpty();
} }
lastMessagesSearchString = query; lastMessagesSearchString = query;
req.filter = new TLRPC.TL_inputMessagesFilterEmpty();
final int currentReqId = ++lastReqId; final int currentReqId = ++lastReqId;
if (delegate != null) { if (delegate != null) {
delegate.searchStateChanged(true); delegate.searchStateChanged(true);
@ -153,7 +168,7 @@ public class DialogsSearchAdapter extends BaseSearchAdapterRecycler {
MessagesStorage.getInstance().putUsersAndChats(res.users, res.chats, true, true); MessagesStorage.getInstance().putUsersAndChats(res.users, res.chats, true, true);
MessagesController.getInstance().putUsers(res.users, false); MessagesController.getInstance().putUsers(res.users, false);
MessagesController.getInstance().putChats(res.chats, false); MessagesController.getInstance().putChats(res.chats, false);
if (req.max_id == 0) { if (req.offset_id == 0) {
searchResultMessages.clear(); searchResultMessages.clear();
} }
for (TLRPC.Message message : res.messages) { for (TLRPC.Message message : res.messages) {
@ -258,7 +273,14 @@ public class DialogsSearchAdapter extends BaseSearchAdapterRecycler {
} else { } else {
did = AndroidUtilities.makeBroadcastId(chat.id); did = AndroidUtilities.makeBroadcastId(chat.id);
} }
hashMap.get(did).object = chat; if (chat.migrated_to != null) {
RecentSearchObject recentSearchObject = hashMap.remove(did);
if (recentSearchObject != null) {
arrayList.remove(recentSearchObject);
}
} else {
hashMap.get(did).object = chat;
}
} }
} }
@ -391,7 +413,7 @@ public class DialogsSearchAdapter extends BaseSearchAdapterRecycler {
int resultCount = 0; int resultCount = 0;
HashMap<Long, DialogSearchResult> dialogsResult = new HashMap<>(); HashMap<Long, DialogSearchResult> dialogsResult = new HashMap<>();
SQLiteCursor cursor = MessagesStorage.getInstance().getDatabase().queryFinalized("SELECT did, date FROM dialogs ORDER BY date DESC LIMIT 200"); SQLiteCursor cursor = MessagesStorage.getInstance().getDatabase().queryFinalized("SELECT did, date FROM dialogs ORDER BY date DESC LIMIT 400");
while (cursor.next()) { while (cursor.next()) {
long id = cursor.longValue(0); long id = cursor.longValue(0);
DialogSearchResult dialogSearchResult = new DialogSearchResult(); DialogSearchResult dialogSearchResult = new DialogSearchResult();
@ -481,16 +503,18 @@ public class DialogsSearchAdapter extends BaseSearchAdapterRecycler {
NativeByteBuffer data = new NativeByteBuffer(cursor.byteArrayLength(0)); NativeByteBuffer data = new NativeByteBuffer(cursor.byteArrayLength(0));
if (data != null && cursor.byteBufferValue(0, data) != 0) { if (data != null && cursor.byteBufferValue(0, data) != 0) {
TLRPC.Chat chat = TLRPC.Chat.TLdeserialize(data, data.readInt32(false), false); TLRPC.Chat chat = TLRPC.Chat.TLdeserialize(data, data.readInt32(false), false);
long dialog_id; if (!(chat == null || chat.deactivated || ChatObject.isChannel(chat) && ChatObject.isNotInChat(chat))) {
if (chat.id > 0) { long dialog_id;
dialog_id = -chat.id; if (chat.id > 0) {
} else { dialog_id = -chat.id;
dialog_id = AndroidUtilities.makeBroadcastId(chat.id); } else {
dialog_id = AndroidUtilities.makeBroadcastId(chat.id);
}
DialogSearchResult dialogSearchResult = dialogsResult.get(dialog_id);
dialogSearchResult.name = AndroidUtilities.generateSearchName(chat.title, null, q);
dialogSearchResult.object = chat;
resultCount++;
} }
DialogSearchResult dialogSearchResult = dialogsResult.get(dialog_id);
dialogSearchResult.name = AndroidUtilities.generateSearchName(chat.title, null, q);
dialogSearchResult.object = chat;
resultCount++;
} }
data.reuse(); data.reuse();
break; break;
@ -589,7 +613,8 @@ public class DialogsSearchAdapter extends BaseSearchAdapterRecycler {
ArrayList<TLObject> resultArray = new ArrayList<>(); ArrayList<TLObject> resultArray = new ArrayList<>();
ArrayList<CharSequence> resultArrayNames = new ArrayList<>(); ArrayList<CharSequence> resultArrayNames = new ArrayList<>();
for (DialogSearchResult dialogSearchResult : searchResults) { for (int a = 0; a < searchResults.size(); a++) {
DialogSearchResult dialogSearchResult = searchResults.get(a);
resultArray.add(dialogSearchResult.object); resultArray.add(dialogSearchResult.object);
resultArrayNames.add(dialogSearchResult.name); resultArrayNames.add(dialogSearchResult.name);
} }
@ -797,7 +822,19 @@ public class DialogsSearchAdapter extends BaseSearchAdapterRecycler {
public Object getItem(int i) { public Object getItem(int i) {
if (needMessagesSearch != 2 && (lastSearchText == null || lastSearchText.length() == 0) && !recentSearchObjects.isEmpty()) { if (needMessagesSearch != 2 && (lastSearchText == null || lastSearchText.length() == 0) && !recentSearchObjects.isEmpty()) {
if (i > 0 && i - 1 < recentSearchObjects.size()) { if (i > 0 && i - 1 < recentSearchObjects.size()) {
return recentSearchObjects.get(i - 1).object; TLObject object = recentSearchObjects.get(i - 1).object;
if (object instanceof TLRPC.User) {
TLRPC.User user = MessagesController.getInstance().getUser(((TLRPC.User) object).id);
if (user != null) {
object = user;
}
} else if (object instanceof TLRPC.Chat) {
TLRPC.Chat chat = MessagesController.getInstance().getChat(((TLRPC.Chat) object).id);
if (chat != null) {
object = chat;
}
}
return object;
} else { } else {
return null; return null;
} }

View File

@ -166,8 +166,9 @@ public class MentionsAdapter extends BaseSearchAdapter {
} }
String usernameString = result.toString().toLowerCase(); String usernameString = result.toString().toLowerCase();
ArrayList<TLRPC.User> newResult = new ArrayList<>(); ArrayList<TLRPC.User> newResult = new ArrayList<>();
if (info instanceof TLRPC.TL_chatFull) { if (info.participants != null) {
for (TLRPC.TL_chatParticipant chatParticipant : info.participants.participants) { for (int a = 0; a < info.participants.participants.size(); a++) {
TLRPC.ChatParticipant chatParticipant = info.participants.participants.get(a);
TLRPC.User user = MessagesController.getInstance().getUser(chatParticipant.user_id); TLRPC.User user = MessagesController.getInstance().getUser(chatParticipant.user_id);
if (user == null || UserObject.isUserSelf(user)) { if (user == null || UserObject.isUserSelf(user)) {
continue; continue;
@ -220,11 +221,13 @@ public class MentionsAdapter extends BaseSearchAdapter {
ArrayList<TLRPC.User> newResultUsers = new ArrayList<>(); ArrayList<TLRPC.User> newResultUsers = new ArrayList<>();
String command = result.toString().toLowerCase(); String command = result.toString().toLowerCase();
for (HashMap.Entry<Integer, TLRPC.BotInfo> entry : botInfo.entrySet()) { for (HashMap.Entry<Integer, TLRPC.BotInfo> entry : botInfo.entrySet()) {
for (TLRPC.TL_botCommand botCommand : entry.getValue().commands) { TLRPC.BotInfo botInfo = entry.getValue();
for (int a = 0; a < botInfo.commands.size(); a++) {
TLRPC.TL_botCommand botCommand = botInfo.commands.get(a);
if (botCommand != null && botCommand.command != null && botCommand.command.startsWith(command)) { if (botCommand != null && botCommand.command != null && botCommand.command.startsWith(command)) {
newResult.add("/" + botCommand.command); newResult.add("/" + botCommand.command);
newResultHelp.add(botCommand.description); newResultHelp.add(botCommand.description);
newResultUsers.add(MessagesController.getInstance().getUser(entry.getValue().user_id)); newResultUsers.add(MessagesController.getInstance().getUser(botInfo.user_id));
} }
} }
} }
@ -311,8 +314,12 @@ public class MentionsAdapter extends BaseSearchAdapter {
if (i < 0 || i >= searchResultCommands.size()) { if (i < 0 || i >= searchResultCommands.size()) {
return null; return null;
} }
if (searchResultCommandsUsers != null && botsCount != 1) { if (searchResultCommandsUsers != null && (botsCount != 1 || info instanceof TLRPC.TL_channelFull)) {
return String.format("%s@%s", searchResultCommands.get(i), searchResultCommandsUsers.get(i).username); if (searchResultCommandsUsers.get(i) != null) {
return String.format("%s@%s", searchResultCommands.get(i), searchResultCommandsUsers.get(i) != null ? searchResultCommandsUsers.get(i).username : "");
} else {
return String.format("%s", searchResultCommands.get(i));
}
} }
return searchResultCommands.get(i); return searchResultCommands.get(i);
} }
@ -338,7 +345,7 @@ public class MentionsAdapter extends BaseSearchAdapter {
} else if (searchResultHashtags != null) { } else if (searchResultHashtags != null) {
((MentionCell) view).setText(searchResultHashtags.get(i)); ((MentionCell) view).setText(searchResultHashtags.get(i));
} else if (searchResultCommands != null) { } else if (searchResultCommands != null) {
((MentionCell) view).setBotCommand(searchResultCommands.get(i), searchResultCommandsHelp.get(i), searchResultCommandsUsers.get(i)); ((MentionCell) view).setBotCommand(searchResultCommands.get(i), searchResultCommandsHelp.get(i), searchResultCommandsUsers != null ? searchResultCommandsUsers.get(i) : null);
} }
return view; return view;
} }

View File

@ -74,20 +74,19 @@ public class PhotoAttachAdapter extends RecyclerView.Adapter {
@Override @Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
PhotoAttachPhotoCell cell = new PhotoAttachPhotoCell(mContext); PhotoAttachPhotoCell cell = new PhotoAttachPhotoCell(mContext);
cell.setOnCheckClickLisnener(new View.OnClickListener() { cell.setDelegate(new PhotoAttachPhotoCell.PhotoAttachPhotoCellDelegate() {
@Override @Override
public void onClick(View v) { public void onCheckClick(PhotoAttachPhotoCell v) {
PhotoAttachPhotoCell cell = (PhotoAttachPhotoCell) v.getParent(); MediaController.PhotoEntry photoEntry = v.getPhotoEntry();
MediaController.PhotoEntry photoEntry = cell.getPhotoEntry();
if (selectedPhotos.containsKey(photoEntry.imageId)) { if (selectedPhotos.containsKey(photoEntry.imageId)) {
selectedPhotos.remove(photoEntry.imageId); selectedPhotos.remove(photoEntry.imageId);
cell.setChecked(false, true); v.setChecked(false, true);
photoEntry.imagePath = null; photoEntry.imagePath = null;
photoEntry.thumbPath = null; photoEntry.thumbPath = null;
cell.setPhotoEntry(photoEntry, cell.getTag() == MediaController.allPhotosAlbumEntry.photos.size() - 1); v.setPhotoEntry(photoEntry, v.getTag() == MediaController.allPhotosAlbumEntry.photos.size() - 1);
} else { } else {
selectedPhotos.put(photoEntry.imageId, photoEntry); selectedPhotos.put(photoEntry.imageId, photoEntry);
cell.setChecked(true, true); v.setChecked(true, true);
} }
delegate.selectedPhotosChanged(); delegate.selectedPhotosChanged();
} }

View File

@ -43,13 +43,15 @@ public class SearchAdapter extends BaseSearchAdapter {
private boolean useUserCell; private boolean useUserCell;
private boolean onlyMutual; private boolean onlyMutual;
private boolean allowChats; private boolean allowChats;
private boolean allowBots;
public SearchAdapter(Context context, HashMap<Integer, TLRPC.User> arg1, boolean usernameSearch, boolean mutual, boolean chats) { public SearchAdapter(Context context, HashMap<Integer, TLRPC.User> arg1, boolean usernameSearch, boolean mutual, boolean chats, boolean bots) {
mContext = context; mContext = context;
ignoreUsers = arg1; ignoreUsers = arg1;
onlyMutual = mutual; onlyMutual = mutual;
allowUsernameSearch = usernameSearch; allowUsernameSearch = usernameSearch;
allowChats = chats; allowChats = chats;
allowBots = bots;
} }
public void setCheckedMap(HashMap<Integer, ?> map) { public void setCheckedMap(HashMap<Integer, ?> map) {
@ -72,7 +74,7 @@ public class SearchAdapter extends BaseSearchAdapter {
searchResult.clear(); searchResult.clear();
searchResultNames.clear(); searchResultNames.clear();
if (allowUsernameSearch) { if (allowUsernameSearch) {
queryServerSearch(null, allowChats); queryServerSearch(null, allowChats, allowBots);
} }
notifyDataSetChanged(); notifyDataSetChanged();
} else { } else {
@ -97,7 +99,7 @@ public class SearchAdapter extends BaseSearchAdapter {
@Override @Override
public void run() { public void run() {
if (allowUsernameSearch) { if (allowUsernameSearch) {
queryServerSearch(query, allowChats); queryServerSearch(query, allowChats, allowBots);
} }
final ArrayList<TLRPC.TL_contact> contactsCopy = new ArrayList<>(); final ArrayList<TLRPC.TL_contact> contactsCopy = new ArrayList<>();
contactsCopy.addAll(ContactsController.getInstance().contacts); contactsCopy.addAll(ContactsController.getInstance().contacts);
@ -122,9 +124,10 @@ public class SearchAdapter extends BaseSearchAdapter {
ArrayList<TLRPC.User> resultArray = new ArrayList<>(); ArrayList<TLRPC.User> resultArray = new ArrayList<>();
ArrayList<CharSequence> resultArrayNames = new ArrayList<>(); ArrayList<CharSequence> resultArrayNames = new ArrayList<>();
for (TLRPC.TL_contact contact : contactsCopy) { for (int a = 0; a < contactsCopy.size(); a++) {
TLRPC.TL_contact contact = contactsCopy.get(a);
TLRPC.User user = MessagesController.getInstance().getUser(contact.user_id); TLRPC.User user = MessagesController.getInstance().getUser(contact.user_id);
if (user.id == UserConfig.getClientUserId() || onlyMutual && (user.flags & TLRPC.USER_FLAG_MUTUAL_CONTACT) == 0) { if (user.id == UserConfig.getClientUserId() || onlyMutual && !user.mutual_contact) {
continue; continue;
} }
@ -235,7 +238,7 @@ public class SearchAdapter extends BaseSearchAdapter {
} else { } else {
if (view == null) { if (view == null) {
if (useUserCell) { if (useUserCell) {
view = new UserCell(mContext, 1); view = new UserCell(mContext, 1, 1);
if (checkedMap != null) { if (checkedMap != null) {
((UserCell) view).setChecked(false, false); ((UserCell) view).setChecked(false, false);
} }

View File

@ -217,7 +217,7 @@ public class AudioSelectActivity extends BaseFragment implements NotificationCen
File file = new File(audioEntry.path); File file = new File(audioEntry.path);
TLRPC.TL_message message = new TLRPC.TL_message(); TLRPC.TL_message message = new TLRPC.TL_message();
message.flags = TLRPC.MESSAGE_FLAG_OUT; message.out = true;
message.id = id; message.id = id;
message.to_id = new TLRPC.TL_peerUser(); message.to_id = new TLRPC.TL_peerUser();
message.to_id.user_id = message.from_id = UserConfig.getClientUserId(); message.to_id.user_id = message.from_id = UserConfig.getClientUserId();

View File

@ -263,7 +263,7 @@ public class BlockedUsersActivity extends BaseFragment implements NotificationCe
int type = getItemViewType(i); int type = getItemViewType(i);
if (type == 0) { if (type == 0) {
if (view == null) { if (view == null) {
view = new UserCell(mContext, 1); view = new UserCell(mContext, 1, 0);
} }
TLRPC.User user = MessagesController.getInstance().getUser(MessagesController.getInstance().blockedUsers.get(i)); TLRPC.User user = MessagesController.getInstance().getUser(MessagesController.getInstance().blockedUsers.get(i));
if (user != null) { if (user != null) {

View File

@ -0,0 +1,187 @@
/*
* 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-2015.
*/
package org.telegram.ui.Cells;
import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.text.Layout;
import android.text.Spannable;
import android.text.SpannableStringBuilder;
import android.text.StaticLayout;
import android.text.TextPaint;
import android.text.style.ClickableSpan;
import android.view.Gravity;
import android.view.MotionEvent;
import android.widget.FrameLayout;
import android.widget.ImageView;
import org.telegram.messenger.AndroidUtilities;
import org.telegram.messenger.Emoji;
import org.telegram.messenger.FileLog;
import org.telegram.messenger.LocaleController;
import org.telegram.messenger.MessageObject;
import org.telegram.ui.Components.LayoutHelper;
import org.telegram.ui.Components.LinkPath;
import org.telegram.ui.Components.URLSpanNoUnderline;
public class AboutLinkCell extends FrameLayout {
private StaticLayout textLayout;
private TextPaint textPaint;
private Paint urlPaint;
private String oldText;
private int textX;
private int textY;
private SpannableStringBuilder stringBuilder;
private ImageView imageView;
private ClickableSpan pressedLink;
private LinkPath urlPath = new LinkPath();
private AboutLinkCellDelegate delegate;
public interface AboutLinkCellDelegate {
void didPressUrl(String url);
}
public AboutLinkCell(Context context) {
super(context);
textPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG);
textPaint.setTextSize(AndroidUtilities.dp(16));
textPaint.setColor(0xff000000);
textPaint.linkColor = 0xff316f9f;
urlPaint = new Paint();
urlPaint.setColor(0x33316f9f);
imageView = new ImageView(context);
imageView.setScaleType(ImageView.ScaleType.CENTER);
addView(imageView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.TOP, LocaleController.isRTL ? 0 : 16, 5, LocaleController.isRTL ? 16 : 0, 0));
setWillNotDraw(false);
}
public void setDelegate(AboutLinkCellDelegate botHelpCellDelegate) {
delegate = botHelpCellDelegate;
}
private void resetPressedLink() {
if (pressedLink != null) {
pressedLink = null;
}
invalidate();
}
public void setTextAndIcon(String text, int resId) {
if (text == null || text.length() == 0) {
setVisibility(GONE);
return;
}
if (text != null && oldText != null && text.equals(oldText)) {
return;
}
oldText = text;
stringBuilder = new SpannableStringBuilder(oldText);
MessageObject.addLinks(stringBuilder, false);
Emoji.replaceEmoji(stringBuilder, textPaint.getFontMetricsInt(), AndroidUtilities.dp(20), false);
requestLayout();
if (resId == 0) {
imageView.setImageDrawable(null);
} else {
imageView.setImageResource(resId);
}
}
@Override
public boolean onTouchEvent(MotionEvent event) {
float x = event.getX();
float y = event.getY();
boolean result = false;
if (textLayout != null) {
if (event.getAction() == MotionEvent.ACTION_DOWN || pressedLink != null && event.getAction() == MotionEvent.ACTION_UP) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
resetPressedLink();
try {
int x2 = (int) (x - textX);
int y2 = (int) (y - textY);
final int line = textLayout.getLineForVertical(y2);
final int off = textLayout.getOffsetForHorizontal(line, x2);
final float left = textLayout.getLineLeft(line);
if (left <= x2 && left + textLayout.getLineWidth(line) >= x2) {
Spannable buffer = (Spannable) textLayout.getText();
ClickableSpan[] link = buffer.getSpans(off, off, ClickableSpan.class);
if (link.length != 0) {
resetPressedLink();
pressedLink = link[0];
result = true;
try {
int start = buffer.getSpanStart(pressedLink);
urlPath.setCurrentLayout(textLayout, start);
textLayout.getSelectionPath(start, buffer.getSpanEnd(pressedLink), urlPath);
} catch (Exception e) {
FileLog.e("tmessages", e);
}
} else {
resetPressedLink();
}
} else {
resetPressedLink();
}
} catch (Exception e) {
resetPressedLink();
FileLog.e("tmessages", e);
}
} else if (pressedLink != null) {
try {
if (pressedLink instanceof URLSpanNoUnderline) {
String url = ((URLSpanNoUnderline) pressedLink).getURL();
if (url.startsWith("@") || url.startsWith("#") || url.startsWith("/")) {
if (delegate != null) {
delegate.didPressUrl(url);
}
}
} else {
pressedLink.onClick(this);
}
} catch (Exception e) {
FileLog.e("tmessages", e);
}
resetPressedLink();
result = true;
}
} else if (event.getAction() == MotionEvent.ACTION_CANCEL) {
resetPressedLink();
}
}
return result || super.onTouchEvent(event);
}
@SuppressLint("DrawAllocation")
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
textLayout = new StaticLayout(stringBuilder, textPaint, MeasureSpec.getSize(widthMeasureSpec) - AndroidUtilities.dp(71 + 16), Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false);
super.onMeasure(MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(textLayout.getHeight() + AndroidUtilities.dp(16), MeasureSpec.EXACTLY));
}
@Override
protected void onDraw(Canvas canvas) {
canvas.save();
canvas.translate(textX = AndroidUtilities.dp(LocaleController.isRTL ? 16 : 71), textY = AndroidUtilities.dp(8));
if (pressedLink != null) {
canvas.drawPath(urlPath, urlPaint);
}
textLayout.draw(canvas);
canvas.restore();
}
}

View File

@ -1,61 +0,0 @@
/*
* 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-2015.
*/
package org.telegram.ui.Cells;
import android.content.Context;
import android.os.Build;
import android.view.Gravity;
import android.view.MotionEvent;
import android.widget.FrameLayout;
import android.widget.ImageView;
import org.telegram.messenger.AndroidUtilities;
import org.telegram.messenger.LocaleController;
import org.telegram.messenger.R;
import org.telegram.ui.Components.LayoutHelper;
import org.telegram.ui.Components.SimpleTextView;
public class AddMemberCell extends FrameLayout {
private SimpleTextView textView;
public AddMemberCell(Context context) {
super(context);
ImageView imageView = new ImageView(context);
imageView.setImageResource(R.drawable.addmember);
imageView.setScaleType(ImageView.ScaleType.CENTER);
addView(imageView, LayoutHelper.createFrame(48, 48, (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.TOP, LocaleController.isRTL ? 0 : 68, 8, LocaleController.isRTL ? 68 : 0, 0));
textView = new SimpleTextView(context);
textView.setTextColor(0xff212121);
textView.setTextSize(17);
textView.setGravity((LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.TOP);
addView(textView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 20, (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.TOP, LocaleController.isRTL ? 28 : 129, 22.5f, LocaleController.isRTL ? 129 : 28, 0));
}
@Override
public boolean onTouchEvent(MotionEvent event) {
if (Build.VERSION.SDK_INT >= 21 && getBackground() != null) {
if (event.getAction() == MotionEvent.ACTION_DOWN || event.getAction() == MotionEvent.ACTION_MOVE) {
getBackground().setHotspot(event.getX(), event.getY());
}
}
return super.onTouchEvent(event);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(64), MeasureSpec.EXACTLY));
}
public void setText(String text) {
textView.setText(text);
}
}

View File

@ -22,6 +22,7 @@ import android.view.MotionEvent;
import android.view.View; import android.view.View;
import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.AndroidUtilities;
import org.telegram.messenger.Emoji;
import org.telegram.messenger.LocaleController; import org.telegram.messenger.LocaleController;
import org.telegram.messenger.MessageObject; import org.telegram.messenger.MessageObject;
import org.telegram.messenger.FileLog; import org.telegram.messenger.FileLog;
@ -97,6 +98,7 @@ public class BotHelpCell extends View {
stringBuilder.append(text); stringBuilder.append(text);
MessageObject.addLinks(stringBuilder); MessageObject.addLinks(stringBuilder);
stringBuilder.setSpan(new TypefaceSpan(AndroidUtilities.getTypeface("fonts/rmedium.ttf")), 0, help.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); stringBuilder.setSpan(new TypefaceSpan(AndroidUtilities.getTypeface("fonts/rmedium.ttf")), 0, help.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
Emoji.replaceEmoji(stringBuilder, textPaint.getFontMetricsInt(), AndroidUtilities.dp(20), false);
textLayout = new StaticLayout(stringBuilder, textPaint, width, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); textLayout = new StaticLayout(stringBuilder, textPaint, width, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false);
width = 0; width = 0;
height = textLayout.getHeight() + AndroidUtilities.dp(4 + 18); height = textLayout.getHeight() + AndroidUtilities.dp(4 + 18);

View File

@ -51,6 +51,7 @@ public class ChatBaseCell extends BaseCell implements MediaController.FileDownlo
void didPressUrl(MessageObject messageObject, ClickableSpan url, boolean longPress); void didPressUrl(MessageObject messageObject, ClickableSpan url, boolean longPress);
void needOpenWebView(String url, String title, String originalUrl, int w, int h); void needOpenWebView(String url, String title, String originalUrl, int w, int h);
void didClickedImage(ChatBaseCell cell); void didClickedImage(ChatBaseCell cell);
void didPressShare(ChatBaseCell cell);
boolean canPerformActions(); boolean canPerformActions();
} }
@ -104,6 +105,11 @@ public class ChatBaseCell extends BaseCell implements MediaController.FileDownlo
private boolean replyPressed = false; private boolean replyPressed = false;
private TLRPC.FileLocation currentReplyPhoto; private TLRPC.FileLocation currentReplyPhoto;
private boolean drawShareButton;
private boolean sharePressed;
private int shareStartX;
private int shareStartY;
private StaticLayout nameLayout; private StaticLayout nameLayout;
protected int nameWidth; protected int nameWidth;
private float nameOffsetX = 0; private float nameOffsetX = 0;
@ -306,7 +312,7 @@ public class ChatBaseCell extends BaseCell implements MediaController.FileDownlo
} }
protected void measureTime(MessageObject messageObject) { protected void measureTime(MessageObject messageObject) {
currentTimeString = LocaleController.formatterDay.format((long) (messageObject.messageOwner.date) * 1000); currentTimeString = LocaleController.getInstance().formatterDay.format((long) (messageObject.messageOwner.date) * 1000);
timeTextWidth = timeWidth = (int) Math.ceil(timeMediaPaint.measureText(currentTimeString)); timeTextWidth = timeWidth = (int) Math.ceil(timeMediaPaint.measureText(currentTimeString));
if ((messageObject.messageOwner.flags & TLRPC.MESSAGE_FLAG_HAS_VIEWS) != 0) { if ((messageObject.messageOwner.flags & TLRPC.MESSAGE_FLAG_HAS_VIEWS) != 0) {
currentViewsString = String.format("%s", LocaleController.formatShortNumber(Math.max(1, messageObject.messageOwner.views), null)); currentViewsString = String.format("%s", LocaleController.formatShortNumber(Math.max(1, messageObject.messageOwner.views), null));
@ -323,6 +329,7 @@ public class ChatBaseCell extends BaseCell implements MediaController.FileDownlo
isCheckPressed = true; isCheckPressed = true;
isAvatarVisible = false; isAvatarVisible = false;
wasLayout = false; wasLayout = false;
drawShareButton = false;
replyNameLayout = null; replyNameLayout = null;
replyTextLayout = null; replyTextLayout = null;
replyNameWidth = 0; replyNameWidth = 0;
@ -345,6 +352,9 @@ public class ChatBaseCell extends BaseCell implements MediaController.FileDownlo
currentUser = MessagesController.getInstance().getUser(messageObject.messageOwner.from_id); currentUser = MessagesController.getInstance().getUser(messageObject.messageOwner.from_id);
} else if (messageObject.messageOwner.from_id < 0) { } else if (messageObject.messageOwner.from_id < 0) {
currentChat = MessagesController.getInstance().getChat(-messageObject.messageOwner.from_id); currentChat = MessagesController.getInstance().getChat(-messageObject.messageOwner.from_id);
if (messageObject.messageOwner.to_id.channel_id != 0 && (messageObject.messageOwner.reply_to_msg_id == 0 || messageObject.type != 13)) {
drawShareButton = true;
}
} }
if (isChat && !messageObject.isOutOwner() && messageObject.messageOwner.from_id > 0) { if (isChat && !messageObject.isOutOwner() && messageObject.messageOwner.from_id > 0) {
isAvatarVisible = true; isAvatarVisible = true;
@ -379,7 +389,7 @@ public class ChatBaseCell extends BaseCell implements MediaController.FileDownlo
currentTimePaint = timeMediaPaint; currentTimePaint = timeMediaPaint;
} }
currentTimeString = LocaleController.formatterDay.format((long) (messageObject.messageOwner.date) * 1000); currentTimeString = LocaleController.getInstance().formatterDay.format((long) (messageObject.messageOwner.date) * 1000);
timeTextWidth = timeWidth = (int)Math.ceil(currentTimePaint.measureText(currentTimeString)); timeTextWidth = timeWidth = (int)Math.ceil(currentTimePaint.measureText(currentTimeString));
if ((messageObject.messageOwner.flags & TLRPC.MESSAGE_FLAG_HAS_VIEWS) != 0) { if ((messageObject.messageOwner.flags & TLRPC.MESSAGE_FLAG_HAS_VIEWS) != 0) {
currentViewsString = String.format("%s", LocaleController.formatShortNumber(Math.max(1, messageObject.messageOwner.views), null)); currentViewsString = String.format("%s", LocaleController.formatShortNumber(Math.max(1, messageObject.messageOwner.views), null));
@ -398,15 +408,22 @@ public class ChatBaseCell extends BaseCell implements MediaController.FileDownlo
currentNameString = "DELETED"; currentNameString = "DELETED";
} }
nameWidth = getMaxNameWidth(); nameWidth = getMaxNameWidth();
if (nameWidth < 0) {
nameWidth = AndroidUtilities.dp(100);
}
CharSequence nameStringFinal = TextUtils.ellipsize(currentNameString.replace("\n", " "), namePaint, nameWidth - AndroidUtilities.dp(12), TextUtils.TruncateAt.END); CharSequence nameStringFinal = TextUtils.ellipsize(currentNameString.replace("\n", " "), namePaint, nameWidth - AndroidUtilities.dp(12), TextUtils.TruncateAt.END);
nameLayout = new StaticLayout(nameStringFinal, namePaint, nameWidth, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); try {
if (nameLayout.getLineCount() > 0) { nameLayout = new StaticLayout(nameStringFinal, namePaint, nameWidth, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false);
nameWidth = (int)Math.ceil(nameLayout.getLineWidth(0)); if (nameLayout != null && nameLayout.getLineCount() > 0) {
namesOffset += AndroidUtilities.dp(19); nameWidth = (int)Math.ceil(nameLayout.getLineWidth(0));
nameOffsetX = nameLayout.getLineLeft(0); namesOffset += AndroidUtilities.dp(19);
} else { nameOffsetX = nameLayout.getLineLeft(0);
nameWidth = 0; } else {
nameWidth = 0;
}
} catch (Exception e) {
FileLog.e("tmessages", e);
} }
} else { } else {
currentNameString = null; currentNameString = null;
@ -580,16 +597,16 @@ public class ChatBaseCell extends BaseCell implements MediaController.FileDownlo
if (isAvatarVisible && avatarImage.isInsideImage(x, y)) { if (isAvatarVisible && avatarImage.isInsideImage(x, y)) {
avatarPressed = true; avatarPressed = true;
result = true; result = true;
} else if (drawForwardedName && forwardedNameLayout != null) { } else if (drawForwardedName && forwardedNameLayout != null && x >= forwardNameX && x <= forwardNameX + forwardedNameWidth && y >= forwardNameY && y <= forwardNameY + AndroidUtilities.dp(32)) {
if (x >= forwardNameX && x <= forwardNameX + forwardedNameWidth && y >= forwardNameY && y <= forwardNameY + AndroidUtilities.dp(32)) { forwardNamePressed = true;
forwardNamePressed = true; result = true;
result = true; } else if (currentMessageObject.isReply() && x >= replyStartX && x <= replyStartX + Math.max(replyNameWidth, replyTextWidth) && y >= replyStartY && y <= replyStartY + AndroidUtilities.dp(35)) {
} replyPressed = true;
} else if (currentMessageObject.isReply()) { result = true;
if (x >= replyStartX && x <= replyStartX + Math.max(replyNameWidth, replyTextWidth) && y >= replyStartY && y <= replyStartY + AndroidUtilities.dp(35)) { } else if (drawShareButton && x >= shareStartX && x <= shareStartX + AndroidUtilities.dp(40) && y >= shareStartY && y <= shareStartY + AndroidUtilities.dp(32)) {
replyPressed = true; sharePressed = true;
result = true; result = true;
} invalidate();
} }
if (result) { if (result) {
startCheckLongPress(); startCheckLongPress();
@ -649,6 +666,21 @@ public class ChatBaseCell extends BaseCell implements MediaController.FileDownlo
replyPressed = false; replyPressed = false;
} }
} }
} else if (sharePressed) {
if (event.getAction() == MotionEvent.ACTION_UP) {
sharePressed = false;
playSoundEffect(SoundEffectConstants.CLICK);
if (delegate != null) {
delegate.didPressShare(this);
}
} else if (event.getAction() == MotionEvent.ACTION_CANCEL) {
sharePressed = false;
} else if (event.getAction() == MotionEvent.ACTION_MOVE) {
if (!(x >= shareStartX && x <= shareStartX + AndroidUtilities.dp(40) && y >= shareStartY && y <= shareStartY + AndroidUtilities.dp(32))) {
sharePressed = false;
}
}
invalidate();
} }
} }
return result; return result;
@ -767,6 +799,11 @@ public class ChatBaseCell extends BaseCell implements MediaController.FileDownlo
onAfterBackgroundDraw(canvas); onAfterBackgroundDraw(canvas);
if (drawShareButton) {
ResourceLoader.shareDrawable[ApplicationLoader.isCustomTheme() ? 1 : 0][sharePressed ? 1 : 0].setBounds(shareStartX = currentBackgroundDrawable.getBounds().right + AndroidUtilities.dp(8), shareStartY = layoutHeight - AndroidUtilities.dp(41), currentBackgroundDrawable.getBounds().right + AndroidUtilities.dp(40), layoutHeight - AndroidUtilities.dp(9));
ResourceLoader.shareDrawable[ApplicationLoader.isCustomTheme() ? 1 : 0][sharePressed ? 1 : 0].draw(canvas);
}
if (drawName && nameLayout != null) { if (drawName && nameLayout != null) {
canvas.save(); canvas.save();
if (media) { if (media) {

View File

@ -198,6 +198,9 @@ public class ChatContactCell extends ChatBaseCell {
String currentNameString = ContactsController.formatName(messageObject.messageOwner.media.first_name, messageObject.messageOwner.media.last_name); String currentNameString = ContactsController.formatName(messageObject.messageOwner.media.first_name, messageObject.messageOwner.media.last_name);
int nameWidth = Math.min((int) Math.ceil(namePaint.measureText(currentNameString)), maxWidth); int nameWidth = Math.min((int) Math.ceil(namePaint.measureText(currentNameString)), maxWidth);
if (maxWidth < 0) {
maxWidth = AndroidUtilities.dp(100);
}
CharSequence stringFinal = TextUtils.ellipsize(currentNameString.replace("\n", " "), namePaint, nameWidth, TextUtils.TruncateAt.END); CharSequence stringFinal = TextUtils.ellipsize(currentNameString.replace("\n", " "), namePaint, nameWidth, TextUtils.TruncateAt.END);
nameLayout = new StaticLayout(stringFinal, namePaint, nameWidth, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); nameLayout = new StaticLayout(stringFinal, namePaint, nameWidth, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false);

View File

@ -498,7 +498,7 @@ public class ChatMediaCell extends ChatBaseCell {
if (currentNameString == null || !currentNameString.equals(name)) { if (currentNameString == null || !currentNameString.equals(name)) {
currentNameString = name; currentNameString = name;
nameLayout = StaticLayoutEx.createStaticLayout(currentNameString, namePaint, maxWidth, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false, TextUtils.TruncateAt.END, maxWidth, 1); nameLayout = StaticLayoutEx.createStaticLayout(currentNameString, namePaint, maxWidth, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false, TextUtils.TruncateAt.END, maxWidth, 1);
if (nameLayout.getLineCount() > 0) { if (nameLayout != null && nameLayout.getLineCount() > 0) {
nameWidth = Math.min(maxWidth, (int) Math.ceil(nameLayout.getLineWidth(0))); nameWidth = Math.min(maxWidth, (int) Math.ceil(nameLayout.getLineWidth(0)));
nameOffsetX = (int) Math.ceil(-nameLayout.getLineLeft(0)); nameOffsetX = (int) Math.ceil(-nameLayout.getLineLeft(0));
} else { } else {
@ -746,14 +746,18 @@ public class ChatMediaCell extends ChatBaseCell {
backgroundWidth += AndroidUtilities.dp(9); backgroundWidth += AndroidUtilities.dp(9);
} }
if (messageObject.caption != null) { if (messageObject.caption != null) {
nameLayout = new StaticLayout(messageObject.caption, MessageObject.textPaint, photoWidth - AndroidUtilities.dp(10), Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); try {
if (nameLayout.getLineCount() > 0) { nameLayout = new StaticLayout(messageObject.caption, MessageObject.textPaint, photoWidth - AndroidUtilities.dp(10), Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false);
captionHeight = nameLayout.getHeight(); if (nameLayout != null && nameLayout.getLineCount() > 0) {
additionHeight += captionHeight + AndroidUtilities.dp(9); captionHeight = nameLayout.getHeight();
float lastLineWidth = nameLayout.getLineWidth(nameLayout.getLineCount() - 1) + nameLayout.getLineLeft(nameLayout.getLineCount() - 1); additionHeight += captionHeight + AndroidUtilities.dp(9);
if (photoWidth - AndroidUtilities.dp(8) - lastLineWidth < timeWidthTotal) { float lastLineWidth = nameLayout.getLineWidth(nameLayout.getLineCount() - 1) + nameLayout.getLineLeft(nameLayout.getLineCount() - 1);
additionHeight += AndroidUtilities.dp(14); if (photoWidth - AndroidUtilities.dp(8) - lastLineWidth < timeWidthTotal) {
additionHeight += AndroidUtilities.dp(14);
}
} }
} catch (Exception e) {
FileLog.e("tmessages", e);
} }
} }

View File

@ -532,17 +532,18 @@ public class ChatMessageCell extends ChatBaseCell {
} }
} }
boolean authorIsRTL = false;
if (webPage.author != null) { if (webPage.author != null) {
try { try {
if (linkPreviewHeight != 0) { if (linkPreviewHeight != 0) {
linkPreviewHeight += AndroidUtilities.dp(2); linkPreviewHeight += AndroidUtilities.dp(2);
totalHeight += AndroidUtilities.dp(2); totalHeight += AndroidUtilities.dp(2);
} }
int width = Math.min((int) Math.ceil(replyNamePaint.measureText(webPage.author)), linkPreviewMaxWidth); //int width = Math.min((int) Math.ceil(replyNamePaint.measureText(webPage.author)), linkPreviewMaxWidth);
if (restLinesCount == 3 && (!isSmallImage || webPage.description == null)) { if (restLinesCount == 3 && (!isSmallImage || webPage.description == null)) {
authorLayout = new StaticLayout(webPage.author, replyNamePaint, width, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); authorLayout = new StaticLayout(webPage.author, replyNamePaint, linkPreviewMaxWidth, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false);
} else { } else {
authorLayout = generateStaticLayout(webPage.author, replyNamePaint, width, linkPreviewMaxWidth - AndroidUtilities.dp(48 + 2), restLinesCount, 1); authorLayout = generateStaticLayout(webPage.author, replyNamePaint, linkPreviewMaxWidth, linkPreviewMaxWidth - AndroidUtilities.dp(48 + 2), restLinesCount, 1);
restLinesCount -= authorLayout.getLineCount(); restLinesCount -= authorLayout.getLineCount();
} }
int height = authorLayout.getLineBottom(authorLayout.getLineCount() - 1); int height = authorLayout.getLineBottom(authorLayout.getLineCount() - 1);
@ -550,6 +551,13 @@ public class ChatMessageCell extends ChatBaseCell {
totalHeight += height; totalHeight += height;
int lineLeft = (int) authorLayout.getLineLeft(0); int lineLeft = (int) authorLayout.getLineLeft(0);
authorX = -lineLeft; authorX = -lineLeft;
int width;
if (lineLeft != 0) {
width = authorLayout.getWidth() - lineLeft;
authorIsRTL = true;
} else {
width = (int) Math.ceil(authorLayout.getLineWidth(0));
}
maxChildWidth = Math.max(maxChildWidth, width + additinalWidth); maxChildWidth = Math.max(maxChildWidth, width + additinalWidth);
maxWebWidth = Math.max(maxWebWidth, width + additinalWidth); maxWebWidth = Math.max(maxWebWidth, width + additinalWidth);
} catch (Exception e) { } catch (Exception e) {
@ -575,19 +583,31 @@ public class ChatMessageCell extends ChatBaseCell {
int height = descriptionLayout.getLineBottom(descriptionLayout.getLineCount() - 1); int height = descriptionLayout.getLineBottom(descriptionLayout.getLineCount() - 1);
linkPreviewHeight += height; linkPreviewHeight += height;
totalHeight += height; totalHeight += height;
boolean hasRTL = false;
for (int a = 0; a < descriptionLayout.getLineCount(); a++) { for (int a = 0; a < descriptionLayout.getLineCount(); a++) {
int lineLeft = (int) Math.ceil(descriptionLayout.getLineLeft(a)); int lineLeft = (int) Math.ceil(descriptionLayout.getLineLeft(a));
if (a == 0 && descriptionX == 0) { if (lineLeft != 0) {
descriptionX = -lineLeft; hasRTL = true;
} else { if (descriptionX == 0) {
descriptionX = Math.max(descriptionX, -lineLeft); descriptionX = -lineLeft;
} else {
descriptionX = Math.max(descriptionX, -lineLeft);
}
}
}
for (int a = 0; a < descriptionLayout.getLineCount(); a++) {
int lineLeft = (int) Math.ceil(descriptionLayout.getLineLeft(a));
if (lineLeft == 0 && descriptionX != 0) {
descriptionX = 0;
} }
int width; int width;
if (lineLeft != 0) { if (lineLeft != 0) {
width = descriptionLayout.getWidth() - lineLeft; width = descriptionLayout.getWidth() - lineLeft;
} else { } else {
width = (int) Math.ceil(descriptionLayout.getLineWidth(a)); width = hasRTL ? descriptionLayout.getWidth() : (int) Math.ceil(descriptionLayout.getLineWidth(a));
} }
if (a < restLines || lineLeft != 0 && isSmallImage) { if (a < restLines || lineLeft != 0 && isSmallImage) {
width += AndroidUtilities.dp(48 + 2); width += AndroidUtilities.dp(48 + 2);
@ -596,6 +616,9 @@ public class ChatMessageCell extends ChatBaseCell {
if (titleIsRTL) { if (titleIsRTL) {
titleX += (width + additinalWidth - maxWebWidth); titleX += (width + additinalWidth - maxWebWidth);
} }
if (authorIsRTL) {
authorX += (width + additinalWidth - maxWebWidth);
}
maxWebWidth = width + additinalWidth; maxWebWidth = width + additinalWidth;
} }
maxChildWidth = Math.max(maxChildWidth, width + additinalWidth); maxChildWidth = Math.max(maxChildWidth, width + additinalWidth);

View File

@ -21,6 +21,7 @@ import android.view.MotionEvent;
import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.AndroidUtilities;
import org.telegram.PhoneFormat.PhoneFormat; import org.telegram.PhoneFormat.PhoneFormat;
import org.telegram.messenger.ChatObject;
import org.telegram.messenger.LocaleController; import org.telegram.messenger.LocaleController;
import org.telegram.messenger.MessageObject; import org.telegram.messenger.MessageObject;
import org.telegram.messenger.UserObject; import org.telegram.messenger.UserObject;
@ -40,7 +41,6 @@ public class DialogCell extends BaseCell {
private static TextPaint namePaint; private static TextPaint namePaint;
private static TextPaint nameEncryptedPaint; private static TextPaint nameEncryptedPaint;
private static TextPaint nameUnknownPaint;
private static TextPaint messagePaint; private static TextPaint messagePaint;
private static TextPaint messagePrintingPaint; private static TextPaint messagePrintingPaint;
private static TextPaint timePaint; private static TextPaint timePaint;
@ -55,6 +55,7 @@ public class DialogCell extends BaseCell {
private static Drawable countDrawableGrey; private static Drawable countDrawableGrey;
private static Drawable groupDrawable; private static Drawable groupDrawable;
private static Drawable broadcastDrawable; private static Drawable broadcastDrawable;
private static Drawable botDrawable;
private static Drawable muteDrawable; private static Drawable muteDrawable;
private static Drawable verifiedDrawable; private static Drawable verifiedDrawable;
@ -87,6 +88,7 @@ public class DialogCell extends BaseCell {
private boolean drawNameLock; private boolean drawNameLock;
private boolean drawNameGroup; private boolean drawNameGroup;
private boolean drawNameBroadcast; private boolean drawNameBroadcast;
private boolean drawNameBot;
private int nameMuteLeft; private int nameMuteLeft;
private int nameLockLeft; private int nameLockLeft;
private int nameLockTop; private int nameLockTop;
@ -136,11 +138,6 @@ public class DialogCell extends BaseCell {
nameEncryptedPaint.setColor(0xff00a60e); nameEncryptedPaint.setColor(0xff00a60e);
nameEncryptedPaint.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); nameEncryptedPaint.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf"));
nameUnknownPaint = new TextPaint(TextPaint.ANTI_ALIAS_FLAG);
nameUnknownPaint.setTextSize(AndroidUtilities.dp(17));
nameUnknownPaint.setColor(0xff4d83b3);
nameUnknownPaint.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf"));
messagePaint = new TextPaint(TextPaint.ANTI_ALIAS_FLAG); messagePaint = new TextPaint(TextPaint.ANTI_ALIAS_FLAG);
messagePaint.setTextSize(AndroidUtilities.dp(16)); messagePaint.setTextSize(AndroidUtilities.dp(16));
messagePaint.setColor(0xff8f8f8f); messagePaint.setColor(0xff8f8f8f);
@ -176,6 +173,7 @@ public class DialogCell extends BaseCell {
broadcastDrawable = getResources().getDrawable(R.drawable.list_broadcast); broadcastDrawable = getResources().getDrawable(R.drawable.list_broadcast);
muteDrawable = getResources().getDrawable(R.drawable.mute_grey); muteDrawable = getResources().getDrawable(R.drawable.mute_grey);
verifiedDrawable = getResources().getDrawable(R.drawable.check_list); verifiedDrawable = getResources().getDrawable(R.drawable.check_list);
botDrawable = getResources().getDrawable(R.drawable.bot_list);
} }
setBackgroundResource(R.drawable.list_selector); setBackgroundResource(R.drawable.list_selector);
@ -264,6 +262,7 @@ public class DialogCell extends BaseCell {
drawNameGroup = false; drawNameGroup = false;
drawNameBroadcast = false; drawNameBroadcast = false;
drawNameLock = false; drawNameLock = false;
drawNameBot = false;
drawVerified = false; drawVerified = false;
if (encryptedChat != null) { if (encryptedChat != null) {
@ -278,14 +277,14 @@ public class DialogCell extends BaseCell {
} }
} else { } else {
if (chat != null) { if (chat != null) {
if (chat.id < 0 || chat instanceof TLRPC.TL_channel || chat instanceof TLRPC.TL_channelForbidden) { if (chat.id < 0 || ChatObject.isChannel(chat) && !chat.megagroup) {
drawNameBroadcast = true; drawNameBroadcast = true;
nameLockTop = AndroidUtilities.dp(16.5f); nameLockTop = AndroidUtilities.dp(16.5f);
} else { } else {
drawNameGroup = true; drawNameGroup = true;
nameLockTop = AndroidUtilities.dp(17.5f); nameLockTop = AndroidUtilities.dp(17.5f);
} }
drawVerified = (chat.flags & TLRPC.CHAT_FLAG_IS_VERIFIED) != 0; drawVerified = chat.verified;
if (!LocaleController.isRTL) { if (!LocaleController.isRTL) {
nameLockLeft = AndroidUtilities.dp(AndroidUtilities.leftBaseline); nameLockLeft = AndroidUtilities.dp(AndroidUtilities.leftBaseline);
@ -300,6 +299,20 @@ public class DialogCell extends BaseCell {
} else { } else {
nameLeft = AndroidUtilities.dp(14); nameLeft = AndroidUtilities.dp(14);
} }
if (user != null) {
if (user.bot) {
drawNameBot = true;
nameLockTop = AndroidUtilities.dp(16.5f);
if (!LocaleController.isRTL) {
nameLockLeft = AndroidUtilities.dp(AndroidUtilities.leftBaseline);
nameLeft = AndroidUtilities.dp(AndroidUtilities.leftBaseline + 4) + botDrawable.getIntrinsicWidth();
} else {
nameLockLeft = getMeasuredWidth() - AndroidUtilities.dp(AndroidUtilities.leftBaseline) - botDrawable.getIntrinsicWidth();
nameLeft = AndroidUtilities.dp(14);
}
}
drawVerified = user.verified;
}
} }
} }
@ -383,11 +396,11 @@ public class DialogCell extends BaseCell {
mess = mess.substring(0, 150); mess = mess.substring(0, 150);
} }
mess = mess.replace("\n", " "); mess = mess.replace("\n", " ");
messageString = Emoji.replaceEmoji(AndroidUtilities.replaceTags(String.format("<c#ff4d83b3>%s:</c> <c#ff808080>%s</c>", name, mess), AndroidUtilities.FLAG_TAG_COLOR), messagePaint.getFontMetricsInt(), AndroidUtilities.dp(20), false); messageString = Emoji.replaceEmoji(AndroidUtilities.replaceTags(String.format("<c#ff4d83b3>%s:</c> <c#ff808080>%s</c>", name.replace("\n", ""), mess), AndroidUtilities.FLAG_TAG_COLOR), messagePaint.getFontMetricsInt(), AndroidUtilities.dp(20), false);
} else { } else {
if (message.messageOwner.media != null && !message.isMediaEmpty()) { if (message.messageOwner.media != null && !message.isMediaEmpty()) {
currentMessagePaint = messagePrintingPaint; currentMessagePaint = messagePrintingPaint;
messageString = Emoji.replaceEmoji(AndroidUtilities.replaceTags(String.format("<c#ff4d83b3>%s:</c> <c#ff4d83b3>%s</c>", name, message.messageText), AndroidUtilities.FLAG_TAG_COLOR), messagePaint.getFontMetricsInt(), AndroidUtilities.dp(20), false); messageString = Emoji.replaceEmoji(AndroidUtilities.replaceTags(String.format("<c#ff4d83b3>%s:</c> <c#ff4d83b3>%s</c>", name.replace("\n", ""), message.messageText), AndroidUtilities.FLAG_TAG_COLOR), messagePaint.getFontMetricsInt(), AndroidUtilities.dp(20), false);
} else { } else {
if (message.messageOwner.message != null) { if (message.messageOwner.message != null) {
String mess = message.messageOwner.message; String mess = message.messageOwner.message;
@ -395,7 +408,7 @@ public class DialogCell extends BaseCell {
mess = mess.substring(0, 150); mess = mess.substring(0, 150);
} }
mess = mess.replace("\n", " "); mess = mess.replace("\n", " ");
messageString = Emoji.replaceEmoji(AndroidUtilities.replaceTags(String.format("<c#ff4d83b3>%s:</c> <c#ff808080>%s</c>", name, mess), AndroidUtilities.FLAG_TAG_COLOR), messagePaint.getFontMetricsInt(), AndroidUtilities.dp(20), false); messageString = Emoji.replaceEmoji(AndroidUtilities.replaceTags(String.format("<c#ff4d83b3>%s:</c> <c#ff808080>%s</c>", name.replace("\n", ""), mess), AndroidUtilities.FLAG_TAG_COLOR), messagePaint.getFontMetricsInt(), AndroidUtilities.dp(20), false);
} }
} }
} }
@ -468,7 +481,6 @@ public class DialogCell extends BaseCell {
if (user.phone != null && user.phone.length() != 0) { if (user.phone != null && user.phone.length() != 0) {
nameString = PhoneFormat.getInstance().format("+" + user.phone); nameString = PhoneFormat.getInstance().format("+" + user.phone);
} else { } else {
currentNamePaint = nameUnknownPaint;
nameString = UserObject.getUserName(user); nameString = UserObject.getUserName(user);
} }
} }
@ -497,6 +509,8 @@ public class DialogCell extends BaseCell {
nameWidth -= AndroidUtilities.dp(4) + groupDrawable.getIntrinsicWidth(); nameWidth -= AndroidUtilities.dp(4) + groupDrawable.getIntrinsicWidth();
} else if (drawNameBroadcast) { } else if (drawNameBroadcast) {
nameWidth -= AndroidUtilities.dp(4) + broadcastDrawable.getIntrinsicWidth(); nameWidth -= AndroidUtilities.dp(4) + broadcastDrawable.getIntrinsicWidth();
} else if (drawNameBot) {
nameWidth -= AndroidUtilities.dp(4) + botDrawable.getIntrinsicWidth();
} }
if (drawClock) { if (drawClock) {
int w = clockDrawable.getIntrinsicWidth() + AndroidUtilities.dp(5); int w = clockDrawable.getIntrinsicWidth() + AndroidUtilities.dp(5);
@ -678,7 +692,7 @@ public class DialogCell extends BaseCell {
public void checkCurrentDialogIndex() { public void checkCurrentDialogIndex() {
if (index < getDialogsArray().size()) { if (index < getDialogsArray().size()) {
TLRPC.Dialog dialog = getDialogsArray().get(index); TLRPC.Dialog dialog = getDialogsArray().get(index);
if (currentDialogId != dialog.id || message != null && message.getId() != dialog.top_message || unreadCount != dialog.unread_count) { if (currentDialogId != dialog.id || message != null && message.getId() != dialog.top_message || unreadCount != dialog.unread_count || message == null && MessagesController.getInstance().dialogMessage.get(dialog.id) != null) {
currentDialogId = dialog.id; currentDialogId = dialog.id;
update(0); update(0);
} }
@ -766,6 +780,12 @@ public class DialogCell extends BaseCell {
} else { } else {
if (lower_id < 0) { if (lower_id < 0) {
chat = MessagesController.getInstance().getChat(-lower_id); chat = MessagesController.getInstance().getChat(-lower_id);
if (!isDialogCell && chat != null && chat.migrated_to != null) {
TLRPC.Chat chat2 = MessagesController.getInstance().getChat(chat.migrated_to.channel_id);
if (chat2 != null) {
chat = chat2;
}
}
} else { } else {
user = MessagesController.getInstance().getUser(lower_id); user = MessagesController.getInstance().getUser(lower_id);
} }
@ -819,6 +839,9 @@ public class DialogCell extends BaseCell {
} else if (drawNameBroadcast) { } else if (drawNameBroadcast) {
setDrawableBounds(broadcastDrawable, nameLockLeft, nameLockTop); setDrawableBounds(broadcastDrawable, nameLockLeft, nameLockTop);
broadcastDrawable.draw(canvas); broadcastDrawable.draw(canvas);
} else if (drawNameBot) {
setDrawableBounds(botDrawable, nameLockLeft, nameLockTop);
botDrawable.draw(canvas);
} }
if (nameLayout != null) { if (nameLayout != null) {

View File

@ -15,6 +15,7 @@ import android.widget.FrameLayout;
import android.widget.TextView; import android.widget.TextView;
import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.AndroidUtilities;
import org.telegram.messenger.FileLog;
import org.telegram.ui.Components.LayoutHelper; import org.telegram.ui.Components.LayoutHelper;
public class DrawerActionCell extends FrameLayout { public class DrawerActionCell extends FrameLayout {
@ -42,7 +43,11 @@ public class DrawerActionCell extends FrameLayout {
} }
public void setTextAndIcon(String text, int resId) { public void setTextAndIcon(String text, int resId) {
textView.setText(text); try {
textView.setCompoundDrawablesWithIntrinsicBounds(resId, 0, 0, 0); textView.setText(text);
textView.setCompoundDrawablesWithIntrinsicBounds(resId, 0, 0, 0);
} catch (Throwable e) {
FileLog.e("tmessages", e);
}
} }
} }

View File

@ -9,8 +9,10 @@
package org.telegram.ui.Cells; package org.telegram.ui.Cells;
import android.content.Context; import android.content.Context;
import android.graphics.Rect;
import android.view.Gravity; import android.view.Gravity;
import android.view.MotionEvent; import android.view.MotionEvent;
import android.view.SoundEffectConstants;
import android.view.View; import android.view.View;
import android.widget.FrameLayout; import android.widget.FrameLayout;
@ -28,6 +30,13 @@ public class PhotoAttachPhotoCell extends FrameLayout {
private FrameLayout checkFrame; private FrameLayout checkFrame;
private CheckBox checkBox; private CheckBox checkBox;
private boolean isLast; private boolean isLast;
private boolean pressed;
private static Rect rect = new Rect();
private PhotoAttachPhotoCellDelegate delegate;
public interface PhotoAttachPhotoCellDelegate {
void onCheckClick(PhotoAttachPhotoCell v);
}
private MediaController.PhotoEntry photoEntry; private MediaController.PhotoEntry photoEntry;
@ -36,13 +45,7 @@ public class PhotoAttachPhotoCell extends FrameLayout {
imageView = new BackupImageView(context); imageView = new BackupImageView(context);
addView(imageView, LayoutHelper.createFrame(80, 80)); addView(imageView, LayoutHelper.createFrame(80, 80));
checkFrame = new FrameLayout(context) { checkFrame = new FrameLayout(context);
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
getParent().requestDisallowInterceptTouchEvent(true);
return super.onInterceptTouchEvent(ev);
}
};
addView(checkFrame, LayoutHelper.createFrame(42, 42, Gravity.LEFT | Gravity.TOP, 38, 0, 0, 0)); addView(checkFrame, LayoutHelper.createFrame(42, 42, Gravity.LEFT | Gravity.TOP, 38, 0, 0, 0));
checkBox = new CheckBox(context, R.drawable.checkbig); checkBox = new CheckBox(context, R.drawable.checkbig);
@ -72,6 +75,7 @@ public class PhotoAttachPhotoCell extends FrameLayout {
} }
public void setPhotoEntry(MediaController.PhotoEntry entry, boolean last) { public void setPhotoEntry(MediaController.PhotoEntry entry, boolean last) {
pressed = false;
photoEntry = entry; photoEntry = entry;
isLast = last; isLast = last;
if (photoEntry.thumbPath != null) { if (photoEntry.thumbPath != null) {
@ -95,4 +99,43 @@ public class PhotoAttachPhotoCell extends FrameLayout {
public void setOnCheckClickLisnener(OnClickListener onCheckClickLisnener) { public void setOnCheckClickLisnener(OnClickListener onCheckClickLisnener) {
checkFrame.setOnClickListener(onCheckClickLisnener); checkFrame.setOnClickListener(onCheckClickLisnener);
} }
public void setDelegate(PhotoAttachPhotoCellDelegate delegate) {
this.delegate = delegate;
}
@Override
public boolean onTouchEvent(MotionEvent event) {
boolean result = false;
checkFrame.getHitRect(rect);
if (event.getAction() == MotionEvent.ACTION_DOWN) {
if (rect.contains((int) event.getX(), (int) event.getY())) {
pressed = true;
invalidate();
result = true;
}
} else if (pressed) {
if (event.getAction() == MotionEvent.ACTION_UP) {
getParent().requestDisallowInterceptTouchEvent(true);
pressed = false;
playSoundEffect(SoundEffectConstants.CLICK);
delegate.onCheckClick(this);
invalidate();
} else if (event.getAction() == MotionEvent.ACTION_CANCEL) {
pressed = false;
invalidate();
} else if (event.getAction() == MotionEvent.ACTION_MOVE) {
if (!(rect.contains((int) event.getX(), (int) event.getY()))) {
pressed = false;
invalidate();
}
}
}
if (!result) {
result = super.onTouchEvent(event);
}
return result;
}
} }

View File

@ -41,9 +41,11 @@ public class ProfileSearchCell extends BaseCell {
private static TextPaint offlinePaint; private static TextPaint offlinePaint;
private static TextPaint countPaint; private static TextPaint countPaint;
private static Drawable lockDrawable; private static Drawable lockDrawable;
private static Drawable botDrawable;
private static Drawable broadcastDrawable; private static Drawable broadcastDrawable;
private static Drawable groupDrawable; private static Drawable groupDrawable;
private static Drawable countDrawable; private static Drawable countDrawable;
private static Drawable countDrawableGrey;
private static Drawable checkDrawable; private static Drawable checkDrawable;
private static Paint linePaint; private static Paint linePaint;
@ -55,7 +57,7 @@ public class ProfileSearchCell extends BaseCell {
private TLRPC.User user = null; private TLRPC.User user = null;
private TLRPC.Chat chat = null; private TLRPC.Chat chat = null;
private TLRPC.EncryptedChat encryptedChat = null; private TLRPC.EncryptedChat encryptedChat = null;
long dialog_id; private long dialog_id;
private String lastName = null; private String lastName = null;
private int lastStatus = 0; private int lastStatus = 0;
@ -70,6 +72,7 @@ public class ProfileSearchCell extends BaseCell {
private boolean drawNameLock; private boolean drawNameLock;
private boolean drawNameBroadcast; private boolean drawNameBroadcast;
private boolean drawNameGroup; private boolean drawNameGroup;
private boolean drawNameBot;
private int nameLockLeft; private int nameLockLeft;
private int nameLockTop; private int nameLockTop;
@ -119,7 +122,9 @@ public class ProfileSearchCell extends BaseCell {
lockDrawable = getResources().getDrawable(R.drawable.list_secret); lockDrawable = getResources().getDrawable(R.drawable.list_secret);
groupDrawable = getResources().getDrawable(R.drawable.list_group); groupDrawable = getResources().getDrawable(R.drawable.list_group);
countDrawable = getResources().getDrawable(R.drawable.dialogs_badge); countDrawable = getResources().getDrawable(R.drawable.dialogs_badge);
countDrawableGrey = getResources().getDrawable(R.drawable.dialogs_badge2);
checkDrawable = getResources().getDrawable(R.drawable.check_list); checkDrawable = getResources().getDrawable(R.drawable.check_list);
botDrawable = getResources().getDrawable(R.drawable.bot_list);
} }
avatarImage = new ImageReceiver(this); avatarImage = new ImageReceiver(this);
@ -188,6 +193,7 @@ public class ProfileSearchCell extends BaseCell {
drawNameLock = false; drawNameLock = false;
drawNameGroup = false; drawNameGroup = false;
drawCheck = false; drawCheck = false;
drawNameBot = false;
if (encryptedChat != null) { if (encryptedChat != null) {
drawNameLock = true; drawNameLock = true;
@ -208,7 +214,7 @@ public class ProfileSearchCell extends BaseCell {
nameLockTop = AndroidUtilities.dp(28.5f); nameLockTop = AndroidUtilities.dp(28.5f);
} else { } else {
dialog_id = -chat.id; dialog_id = -chat.id;
if (ChatObject.isChannel(chat)) { if (ChatObject.isChannel(chat) && !chat.megagroup) {
drawNameBroadcast = true; drawNameBroadcast = true;
nameLockTop = AndroidUtilities.dp(28.5f); nameLockTop = AndroidUtilities.dp(28.5f);
} else { } else {
@ -216,7 +222,7 @@ public class ProfileSearchCell extends BaseCell {
nameLockTop = AndroidUtilities.dp(30); nameLockTop = AndroidUtilities.dp(30);
} }
} }
drawCheck = (chat.flags & TLRPC.CHAT_FLAG_IS_VERIFIED) != 0; drawCheck = chat.verified;
if (!LocaleController.isRTL) { if (!LocaleController.isRTL) {
nameLockLeft = AndroidUtilities.dp(AndroidUtilities.leftBaseline); nameLockLeft = AndroidUtilities.dp(AndroidUtilities.leftBaseline);
nameLeft = AndroidUtilities.dp(AndroidUtilities.leftBaseline + 4) + (drawNameGroup ? groupDrawable.getIntrinsicWidth() : broadcastDrawable.getIntrinsicWidth()); nameLeft = AndroidUtilities.dp(AndroidUtilities.leftBaseline + 4) + (drawNameGroup ? groupDrawable.getIntrinsicWidth() : broadcastDrawable.getIntrinsicWidth());
@ -231,6 +237,20 @@ public class ProfileSearchCell extends BaseCell {
} else { } else {
nameLeft = AndroidUtilities.dp(11); nameLeft = AndroidUtilities.dp(11);
} }
if (user.bot) {
drawNameBot = true;
if (!LocaleController.isRTL) {
nameLockLeft = AndroidUtilities.dp(AndroidUtilities.leftBaseline);
nameLeft = AndroidUtilities.dp(AndroidUtilities.leftBaseline + 4) + botDrawable.getIntrinsicWidth();
} else {
nameLockLeft = getMeasuredWidth() - AndroidUtilities.dp(AndroidUtilities.leftBaseline + 2) - botDrawable.getIntrinsicWidth();
nameLeft = AndroidUtilities.dp(11);
}
nameLockTop = AndroidUtilities.dp(16.5f);
} else {
nameLockTop = AndroidUtilities.dp(17);
}
drawCheck = user.verified;
} }
} }
@ -271,6 +291,8 @@ public class ProfileSearchCell extends BaseCell {
nameWidth -= AndroidUtilities.dp(6) + broadcastDrawable.getIntrinsicWidth(); nameWidth -= AndroidUtilities.dp(6) + broadcastDrawable.getIntrinsicWidth();
} else if (drawNameGroup) { } else if (drawNameGroup) {
nameWidth -= AndroidUtilities.dp(6) + groupDrawable.getIntrinsicWidth(); nameWidth -= AndroidUtilities.dp(6) + groupDrawable.getIntrinsicWidth();
} else if (drawNameBot) {
nameWidth -= AndroidUtilities.dp(6) + botDrawable.getIntrinsicWidth();
} }
if (drawCount) { if (drawCount) {
@ -313,7 +335,7 @@ public class ProfileSearchCell extends BaseCell {
if (subLabel != null) { if (subLabel != null) {
onlineString = subLabel; onlineString = subLabel;
} else if (user != null) { } else if (user != null) {
if ((user.flags & TLRPC.USER_FLAG_BOT) != 0) { if (user.bot) {
onlineString = LocaleController.getString("Bot", R.string.Bot); onlineString = LocaleController.getString("Bot", R.string.Bot);
} else { } else {
onlineString = LocaleController.formatUserStatus(user); onlineString = LocaleController.formatUserStatus(user);
@ -327,7 +349,7 @@ public class ProfileSearchCell extends BaseCell {
CharSequence onlineStringFinal = TextUtils.ellipsize(onlineString, currentOnlinePaint, onlineWidth - AndroidUtilities.dp(12), TextUtils.TruncateAt.END); CharSequence onlineStringFinal = TextUtils.ellipsize(onlineString, currentOnlinePaint, onlineWidth - AndroidUtilities.dp(12), TextUtils.TruncateAt.END);
onlineLayout = new StaticLayout(onlineStringFinal, currentOnlinePaint, onlineWidth, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); onlineLayout = new StaticLayout(onlineStringFinal, currentOnlinePaint, onlineWidth, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false);
nameTop = AndroidUtilities.dp(13); nameTop = AndroidUtilities.dp(13);
if (subLabel != null) { if (subLabel != null && !drawNameBot) {
nameLockTop -= AndroidUtilities.dp(12); nameLockTop -= AndroidUtilities.dp(12);
} }
} else { } else {
@ -492,6 +514,9 @@ public class ProfileSearchCell extends BaseCell {
} else if (drawNameBroadcast) { } else if (drawNameBroadcast) {
setDrawableBounds(broadcastDrawable, nameLockLeft, nameLockTop); setDrawableBounds(broadcastDrawable, nameLockLeft, nameLockTop);
broadcastDrawable.draw(canvas); broadcastDrawable.draw(canvas);
} else if (drawNameBot) {
setDrawableBounds(botDrawable, nameLockLeft, nameLockTop);
botDrawable.draw(canvas);
} }
if (nameLayout != null) { if (nameLayout != null) {
@ -517,8 +542,13 @@ public class ProfileSearchCell extends BaseCell {
} }
if (countLayout != null) { if (countLayout != null) {
setDrawableBounds(countDrawable, countLeft - AndroidUtilities.dp(5.5f), countTop, countWidth + AndroidUtilities.dp(11), countDrawable.getIntrinsicHeight()); if (MessagesController.getInstance().isDialogMuted(dialog_id)) {
countDrawable.draw(canvas); setDrawableBounds(countDrawableGrey, countLeft - AndroidUtilities.dp(5.5f), countTop, countWidth + AndroidUtilities.dp(11), countDrawableGrey.getIntrinsicHeight());
countDrawableGrey.draw(canvas);
} else {
setDrawableBounds(countDrawable, countLeft - AndroidUtilities.dp(5.5f), countTop, countWidth + AndroidUtilities.dp(11), countDrawable.getIntrinsicHeight());
countDrawable.draw(canvas);
}
canvas.save(); canvas.save();
canvas.translate(countLeft, countTop + AndroidUtilities.dp(4)); canvas.translate(countLeft, countTop + AndroidUtilities.dp(4));
countLayout.draw(canvas); countLayout.draw(canvas);

View File

@ -0,0 +1,101 @@
/*
* 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-2015.
*/
package org.telegram.ui.Cells;
import android.content.Context;
import android.text.TextUtils;
import android.util.TypedValue;
import android.view.Gravity;
import android.widget.FrameLayout;
import android.widget.TextView;
import org.telegram.messenger.AndroidUtilities;
import org.telegram.messenger.ContactsController;
import org.telegram.messenger.MessagesController;
import org.telegram.messenger.R;
import org.telegram.tgnet.TLRPC;
import org.telegram.ui.Components.AvatarDrawable;
import org.telegram.ui.Components.BackupImageView;
import org.telegram.ui.Components.CheckBox;
import org.telegram.ui.Components.LayoutHelper;
public class ShareDialogCell extends FrameLayout {
private BackupImageView imageView;
private TextView nameTextView;
private CheckBox checkBox;
private AvatarDrawable avatarDrawable = new AvatarDrawable();
public ShareDialogCell(Context context) {
super(context);
imageView = new BackupImageView(context);
imageView.setRoundRadius(AndroidUtilities.dp(27));
addView(imageView, LayoutHelper.createFrame(54, 54, Gravity.TOP | Gravity.CENTER_HORIZONTAL, 0, 7, 0, 0));
nameTextView = new TextView(context);
nameTextView.setTextColor(0xff212121);
nameTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 12);
nameTextView.setMaxLines(2);
nameTextView.setGravity(Gravity.TOP | Gravity.CENTER_HORIZONTAL);
nameTextView.setLines(2);
nameTextView.setEllipsize(TextUtils.TruncateAt.END);
addView(nameTextView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.LEFT | Gravity.TOP, 6, 64, 6, 0));
checkBox = new CheckBox(context, R.drawable.round_check2);
checkBox.setSize(24);
checkBox.setCheckOffset(AndroidUtilities.dp(1));
checkBox.setVisibility(VISIBLE);
checkBox.setColor(0xff3ec1f9);
addView(checkBox, LayoutHelper.createFrame(24, 24, Gravity.CENTER_HORIZONTAL | Gravity.TOP, 17, 39, 0, 0));
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(100), MeasureSpec.EXACTLY));
}
public void setDialog(TLRPC.Dialog dialog, boolean checked, CharSequence name) {
int lower_id = (int) dialog.id;
TLRPC.FileLocation photo = null;
if (lower_id > 0) {
TLRPC.User user = MessagesController.getInstance().getUser(lower_id);
if (name != null) {
nameTextView.setText(name);
} else if (user != null) {
nameTextView.setText(ContactsController.formatName(user.first_name, user.last_name));
} else {
nameTextView.setText("");
}
avatarDrawable.setInfo(user);
if (user != null && user.photo != null) {
photo = user.photo.photo_small;
}
} else {
TLRPC.Chat chat = MessagesController.getInstance().getChat(-lower_id);
if (name != null) {
nameTextView.setText(name);
} else if (chat != null) {
nameTextView.setText(chat.title);
} else {
nameTextView.setText("");
}
avatarDrawable.setInfo(chat);
if (chat != null && chat.photo != null) {
photo = chat.photo.photo_small;
}
}
imageView.setImage(photo, "50_50", avatarDrawable);
checkBox.setChecked(checked, false);
}
public void setChecked(boolean checked, boolean animated) {
checkBox.setChecked(checked, animated);
}
}

View File

@ -220,7 +220,7 @@ public class SharedDocumentCell extends FrameLayout implements MediaController.F
thumbImageView.setImage(document.messageOwner.media.document.thumb.location, "40_40", (Drawable) null); thumbImageView.setImage(document.messageOwner.media.document.thumb.location, "40_40", (Drawable) null);
} }
long date = (long) document.messageOwner.date * 1000; long date = (long) document.messageOwner.date * 1000;
dateTextView.setText(String.format("%s, %s", AndroidUtilities.formatFileSize(document.messageOwner.media.document.size), LocaleController.formatString("formatDateAtTime", R.string.formatDateAtTime, LocaleController.formatterYear.format(new Date(date)), LocaleController.formatterDay.format(new Date(date))))); dateTextView.setText(String.format("%s, %s", AndroidUtilities.formatFileSize(document.messageOwner.media.document.size), LocaleController.formatString("formatDateAtTime", R.string.formatDateAtTime, LocaleController.getInstance().formatterYear.format(new Date(date)), LocaleController.getInstance().formatterDay.format(new Date(date)))));
} else { } else {
nameTextView.setText(""); nameTextView.setText("");
extTextView.setText(""); extTextView.setText("");

View File

@ -98,7 +98,7 @@ public class StickerSetCell extends FrameLayout {
stickersSet = set; stickersSet = set;
textView.setText(stickersSet.set.title); textView.setText(stickersSet.set.title);
if ((stickersSet.set.flags & 2) != 0) { if (stickersSet.set.disabled) {
ViewProxy.setAlpha(textView, 0.5f); ViewProxy.setAlpha(textView, 0.5f);
ViewProxy.setAlpha(valueTextView, 0.5f); ViewProxy.setAlpha(valueTextView, 0.5f);
ViewProxy.setAlpha(imageView, 0.5f); ViewProxy.setAlpha(imageView, 0.5f);

View File

@ -28,8 +28,6 @@ public class TextCell extends FrameLayout {
private ImageView imageView; private ImageView imageView;
private ImageView valueImageView; private ImageView valueImageView;
private boolean multiline;
public TextCell(Context context) { public TextCell(Context context) {
super(context); super(context);
@ -63,7 +61,7 @@ public class TextCell extends FrameLayout {
@Override @Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.EXACTLY), multiline ? MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED) : MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(48), MeasureSpec.EXACTLY)); super.onMeasure(MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(48), MeasureSpec.EXACTLY));
} }
public void setTextColor(int color) { public void setTextColor(int color) {
@ -83,27 +81,7 @@ public class TextCell extends FrameLayout {
imageView.setVisibility(VISIBLE); imageView.setVisibility(VISIBLE);
valueTextView.setVisibility(INVISIBLE); valueTextView.setVisibility(INVISIBLE);
valueImageView.setVisibility(INVISIBLE); valueImageView.setVisibility(INVISIBLE);
if (multiline) { imageView.setPadding(0, AndroidUtilities.dp(7), 0, 0);
imageView.setPadding(0, 0, 0, 0);
} else {
imageView.setPadding(0, AndroidUtilities.dp(7), 0, 0);
}
}
public void setMultiline(boolean value) {
if (multiline == value) {
return;
}
multiline = value;
if (value) {
textView.setSingleLine(false);
textView.setPadding(0, AndroidUtilities.dp(6), 0, AndroidUtilities.dp(6));
} else {
textView.setLines(1);
textView.setMaxLines(1);
textView.setSingleLine(true);
}
requestLayout();
} }
public void setTextAndValue(String text, String value) { public void setTextAndValue(String text, String value) {
@ -120,10 +98,6 @@ public class TextCell extends FrameLayout {
valueImageView.setImageDrawable(drawable); valueImageView.setImageDrawable(drawable);
valueTextView.setVisibility(INVISIBLE); valueTextView.setVisibility(INVISIBLE);
imageView.setVisibility(INVISIBLE); imageView.setVisibility(INVISIBLE);
if (multiline) { imageView.setPadding(0, AndroidUtilities.dp(7), 0, 0);
imageView.setPadding(0, 0, 0, 0);
} else {
imageView.setPadding(0, AndroidUtilities.dp(7), 0, 0);
}
} }
} }

View File

@ -25,6 +25,7 @@ import org.telegram.messenger.UserConfig;
import org.telegram.ui.Components.AvatarDrawable; import org.telegram.ui.Components.AvatarDrawable;
import org.telegram.ui.Components.BackupImageView; import org.telegram.ui.Components.BackupImageView;
import org.telegram.ui.Components.CheckBox; import org.telegram.ui.Components.CheckBox;
import org.telegram.ui.Components.CheckBoxSquare;
import org.telegram.ui.Components.LayoutHelper; import org.telegram.ui.Components.LayoutHelper;
import org.telegram.ui.Components.SimpleTextView; import org.telegram.ui.Components.SimpleTextView;
@ -35,6 +36,7 @@ public class UserCell extends FrameLayout {
private SimpleTextView statusTextView; private SimpleTextView statusTextView;
private ImageView imageView; private ImageView imageView;
private CheckBox checkBox; private CheckBox checkBox;
private CheckBoxSquare checkBoxBig;
private AvatarDrawable avatarDrawable; private AvatarDrawable avatarDrawable;
private TLObject currentObject = null; private TLObject currentObject = null;
@ -50,7 +52,7 @@ public class UserCell extends FrameLayout {
private int statusColor = 0xffa8a8a8; private int statusColor = 0xffa8a8a8;
private int statusOnlineColor = 0xff3b84c0; private int statusOnlineColor = 0xff3b84c0;
public UserCell(Context context, int padding) { public UserCell(Context context, int padding, int checkbox) {
super(context); super(context);
avatarDrawable = new AvatarDrawable(); avatarDrawable = new AvatarDrawable();
@ -75,9 +77,14 @@ public class UserCell extends FrameLayout {
imageView.setVisibility(GONE); imageView.setVisibility(GONE);
addView(imageView, LayoutHelper.createFrame(LayoutParams.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.CENTER_VERTICAL, LocaleController.isRTL ? 0 : 16, 0, LocaleController.isRTL ? 16 : 0, 0)); addView(imageView, LayoutHelper.createFrame(LayoutParams.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.CENTER_VERTICAL, LocaleController.isRTL ? 0 : 16, 0, LocaleController.isRTL ? 16 : 0, 0));
checkBox = new CheckBox(context, R.drawable.round_check2); if (checkbox == 2) {
checkBox.setVisibility(INVISIBLE); checkBoxBig = new CheckBoxSquare(context);
addView(checkBox, LayoutHelper.createFrame(22, 22, (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.TOP, LocaleController.isRTL ? 0 : 37 + padding, 38, LocaleController.isRTL ? 37 + padding : 0, 0)); addView(checkBoxBig, LayoutHelper.createFrame(18, 18, (LocaleController.isRTL ? Gravity.LEFT : Gravity.RIGHT) | Gravity.CENTER_VERTICAL, LocaleController.isRTL ? 19 : 0, 0, LocaleController.isRTL ? 0 : 19, 0));
} else if (checkbox == 1) {
checkBox = new CheckBox(context, R.drawable.round_check2);
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));
}
} }
public void setData(TLObject user, CharSequence name, CharSequence status, int resId) { public void setData(TLObject user, CharSequence name, CharSequence status, int resId) {
@ -98,10 +105,23 @@ public class UserCell extends FrameLayout {
} }
public void setChecked(boolean checked, boolean animated) { public void setChecked(boolean checked, boolean animated) {
if (checkBox.getVisibility() != VISIBLE) { if (checkBox != null) {
checkBox.setVisibility(VISIBLE); if (checkBox.getVisibility() != VISIBLE) {
checkBox.setVisibility(VISIBLE);
}
checkBox.setChecked(checked, animated);
} else if (checkBoxBig != null) {
if (checkBoxBig.getVisibility() != VISIBLE) {
checkBoxBig.setVisibility(VISIBLE);
}
checkBoxBig.setChecked(checked, animated);
}
}
public void setCheckDisabled(boolean disabled) {
if (checkBoxBig != null) {
checkBoxBig.setDisabled(disabled);
} }
checkBox.setChecked(checked, animated);
} }
@Override @Override
@ -191,9 +211,9 @@ public class UserCell extends FrameLayout {
statusTextView.setTextColor(statusColor); statusTextView.setTextColor(statusColor);
statusTextView.setText(currrntStatus); statusTextView.setText(currrntStatus);
} else if (currentUser != null) { } else if (currentUser != null) {
if ((currentUser.flags & TLRPC.USER_FLAG_BOT) != 0) { if (currentUser.bot) {
statusTextView.setTextColor(statusColor); statusTextView.setTextColor(statusColor);
if ((currentUser.flags & TLRPC.USER_FLAG_BOT_READING_HISTORY) != 0) { if (currentUser.bot_chat_history) {
statusTextView.setText(LocaleController.getString("BotStatusRead", R.string.BotStatusRead)); statusTextView.setText(LocaleController.getString("BotStatusRead", R.string.BotStatusRead));
} else { } else {
statusTextView.setText(LocaleController.getString("BotStatusCantRead", R.string.BotStatusCantRead)); statusTextView.setText(LocaleController.getString("BotStatusCantRead", R.string.BotStatusCantRead));

View File

@ -139,8 +139,15 @@ public class ChangeChatNameActivity extends BaseFragment {
@Override @Override
public void onTransitionAnimationEnd(boolean isOpen, boolean backward) { public void onTransitionAnimationEnd(boolean isOpen, boolean backward) {
if (isOpen) { if (isOpen) {
firstNameField.requestFocus(); AndroidUtilities.runOnUIThread(new Runnable() {
AndroidUtilities.showKeyboard(firstNameField); @Override
public void run() {
if (firstNameField != null) {
firstNameField.requestFocus();
AndroidUtilities.showKeyboard(firstNameField);
}
}
}, 100);
} }
} }

View File

@ -187,8 +187,15 @@ public class ChangeNameActivity extends BaseFragment {
@Override @Override
public void onTransitionAnimationEnd(boolean isOpen, boolean backward) { public void onTransitionAnimationEnd(boolean isOpen, boolean backward) {
if (isOpen) { if (isOpen) {
firstNameField.requestFocus(); AndroidUtilities.runOnUIThread(new Runnable() {
AndroidUtilities.showKeyboard(firstNameField); @Override
public void run() {
if (firstNameField != null) {
firstNameField.requestFocus();
AndroidUtilities.showKeyboard(firstNameField);
}
}
}, 100);
} }
} }
} }

View File

@ -56,6 +56,7 @@ import org.telegram.messenger.AnimationCompat.AnimatorListenerAdapterProxy;
import org.telegram.messenger.AnimationCompat.AnimatorSetProxy; import org.telegram.messenger.AnimationCompat.AnimatorSetProxy;
import org.telegram.messenger.AnimationCompat.ObjectAnimatorProxy; import org.telegram.messenger.AnimationCompat.ObjectAnimatorProxy;
import org.telegram.messenger.AnimationCompat.ViewProxy; import org.telegram.messenger.AnimationCompat.ViewProxy;
import org.telegram.ui.Components.HintEditText;
import org.telegram.ui.Components.LayoutHelper; import org.telegram.ui.Components.LayoutHelper;
import org.telegram.ui.Components.SlideView; import org.telegram.ui.Components.SlideView;
import org.telegram.ui.Components.TypefaceSpan; import org.telegram.ui.Components.TypefaceSpan;
@ -259,7 +260,7 @@ public class ChangePhoneActivity extends BaseFragment {
public class PhoneView extends SlideView implements AdapterView.OnItemSelectedListener { public class PhoneView extends SlideView implements AdapterView.OnItemSelectedListener {
private EditText codeField; private EditText codeField;
private EditText phoneField; private HintEditText phoneField;
private TextView countryButton; private TextView countryButton;
private int countryState = 0; private int countryState = 0;
@ -267,6 +268,7 @@ public class ChangePhoneActivity extends BaseFragment {
private ArrayList<String> countriesArray = new ArrayList<>(); private ArrayList<String> countriesArray = new ArrayList<>();
private HashMap<String, String> countriesMap = new HashMap<>(); private HashMap<String, String> countriesMap = new HashMap<>();
private HashMap<String, String> codesMap = new HashMap<>(); private HashMap<String, String> codesMap = new HashMap<>();
private HashMap<String, String> phoneFormatMap = new HashMap<>();
private boolean ignoreSelection = false; private boolean ignoreSelection = false;
private boolean ignoreOnTextChange = false; private boolean ignoreOnTextChange = false;
@ -287,14 +289,7 @@ public class ChangePhoneActivity extends BaseFragment {
countryButton.setEllipsize(TextUtils.TruncateAt.END); countryButton.setEllipsize(TextUtils.TruncateAt.END);
countryButton.setGravity(Gravity.LEFT | Gravity.CENTER_HORIZONTAL); countryButton.setGravity(Gravity.LEFT | Gravity.CENTER_HORIZONTAL);
countryButton.setBackgroundResource(R.drawable.spinner_states); countryButton.setBackgroundResource(R.drawable.spinner_states);
addView(countryButton); addView(countryButton, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 36, 20, 0, 20, 14));
LayoutParams layoutParams = (LayoutParams) countryButton.getLayoutParams();
layoutParams.width = LayoutHelper.MATCH_PARENT;
layoutParams.height = AndroidUtilities.dp(36);
layoutParams.leftMargin = AndroidUtilities.dp(20);
layoutParams.rightMargin = AndroidUtilities.dp(20);
layoutParams.bottomMargin = AndroidUtilities.dp(14);
countryButton.setLayoutParams(layoutParams);
countryButton.setOnClickListener(new OnClickListener() { countryButton.setOnClickListener(new OnClickListener() {
@Override @Override
public void onClick(View view) { public void onClick(View view) {
@ -303,7 +298,14 @@ public class ChangePhoneActivity extends BaseFragment {
@Override @Override
public void didSelectCountry(String name) { public void didSelectCountry(String name) {
selectCountry(name); selectCountry(name);
AndroidUtilities.runOnUIThread(new Runnable() {
@Override
public void run() {
AndroidUtilities.showKeyboard(phoneField);
}
}, 300);
phoneField.requestFocus(); phoneField.requestFocus();
phoneField.setSelection(phoneField.length());
} }
}); });
presentFragment(fragment); presentFragment(fragment);
@ -313,34 +315,17 @@ public class ChangePhoneActivity extends BaseFragment {
View view = new View(context); View view = new View(context);
view.setPadding(AndroidUtilities.dp(12), 0, AndroidUtilities.dp(12), 0); view.setPadding(AndroidUtilities.dp(12), 0, AndroidUtilities.dp(12), 0);
view.setBackgroundColor(0xffdbdbdb); view.setBackgroundColor(0xffdbdbdb);
addView(view); addView(view, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 1, 24, -17.5f, 24, 0));
layoutParams = (LayoutParams) view.getLayoutParams();
layoutParams.width = LayoutHelper.MATCH_PARENT;
layoutParams.height = 1;
layoutParams.leftMargin = AndroidUtilities.dp(24);
layoutParams.rightMargin = AndroidUtilities.dp(24);
layoutParams.topMargin = AndroidUtilities.dp(-17.5f);
view.setLayoutParams(layoutParams);
LinearLayout linearLayout = new LinearLayout(context); LinearLayout linearLayout = new LinearLayout(context);
linearLayout.setOrientation(HORIZONTAL); linearLayout.setOrientation(HORIZONTAL);
addView(linearLayout); addView(linearLayout, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, 0, 20, 0, 0));
layoutParams = (LayoutParams) linearLayout.getLayoutParams();
layoutParams.width = LayoutHelper.MATCH_PARENT;
layoutParams.height = LayoutHelper.WRAP_CONTENT;
layoutParams.topMargin = AndroidUtilities.dp(20);
linearLayout.setLayoutParams(layoutParams);
TextView textView = new TextView(context); TextView textView = new TextView(context);
textView.setText("+"); textView.setText("+");
textView.setTextColor(0xff212121); textView.setTextColor(0xff212121);
textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 18); textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 18);
linearLayout.addView(textView); linearLayout.addView(textView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, 24, 0, 0, 0));
layoutParams = (LayoutParams) textView.getLayoutParams();
layoutParams.width = LayoutHelper.WRAP_CONTENT;
layoutParams.height = LayoutHelper.WRAP_CONTENT;
layoutParams.leftMargin = AndroidUtilities.dp(24);
textView.setLayoutParams(layoutParams);
codeField = new EditText(context); codeField = new EditText(context);
codeField.setInputType(InputType.TYPE_CLASS_PHONE); codeField.setInputType(InputType.TYPE_CLASS_PHONE);
@ -352,15 +337,9 @@ public class ChangePhoneActivity extends BaseFragment {
codeField.setGravity(Gravity.LEFT | Gravity.CENTER_VERTICAL); codeField.setGravity(Gravity.LEFT | Gravity.CENTER_VERTICAL);
codeField.setImeOptions(EditorInfo.IME_ACTION_NEXT | EditorInfo.IME_FLAG_NO_EXTRACT_UI); codeField.setImeOptions(EditorInfo.IME_ACTION_NEXT | EditorInfo.IME_FLAG_NO_EXTRACT_UI);
InputFilter[] inputFilters = new InputFilter[1]; InputFilter[] inputFilters = new InputFilter[1];
inputFilters[0] = new InputFilter.LengthFilter(4); inputFilters[0] = new InputFilter.LengthFilter(5);
codeField.setFilters(inputFilters); codeField.setFilters(inputFilters);
linearLayout.addView(codeField); linearLayout.addView(codeField, LayoutHelper.createLinear(55, 36, -9, 0, 16, 0));
layoutParams = (LayoutParams) codeField.getLayoutParams();
layoutParams.width = AndroidUtilities.dp(55);
layoutParams.height = AndroidUtilities.dp(36);
layoutParams.rightMargin = AndroidUtilities.dp(16);
layoutParams.leftMargin = AndroidUtilities.dp(-9);
codeField.setLayoutParams(layoutParams);
codeField.addTextChangedListener(new TextWatcher() { codeField.addTextChangedListener(new TextWatcher() {
@Override @Override
public void beforeTextChanged(CharSequence charSequence, int i, int i2, int i3) { public void beforeTextChanged(CharSequence charSequence, int i, int i2, int i3) {
@ -383,26 +362,57 @@ public class ChangePhoneActivity extends BaseFragment {
codeField.setText(text); codeField.setText(text);
if (text.length() == 0) { if (text.length() == 0) {
countryButton.setText(LocaleController.getString("ChooseCountry", R.string.ChooseCountry)); countryButton.setText(LocaleController.getString("ChooseCountry", R.string.ChooseCountry));
phoneField.setHintText(null);
countryState = 1; countryState = 1;
} else { } else {
String country = codesMap.get(text); String country;
boolean ok = false;
String textToSet = null;
if (text.length() > 4) {
ignoreOnTextChange = true;
for (int a = 4; a >= 1; a--) {
String sub = text.substring(0, a);
country = codesMap.get(sub);
if (country != null) {
ok = true;
textToSet = text.substring(a, text.length()) + phoneField.getText().toString();
codeField.setText(text = sub);
break;
}
}
if (!ok) {
ignoreOnTextChange = true;
textToSet = text.substring(1, text.length()) + phoneField.getText().toString();
codeField.setText(text = text.substring(0, 1));
}
}
country = codesMap.get(text);
if (country != null) { if (country != null) {
int index = countriesArray.indexOf(country); int index = countriesArray.indexOf(country);
if (index != -1) { if (index != -1) {
ignoreSelection = true; ignoreSelection = true;
countryButton.setText(countriesArray.get(index)); countryButton.setText(countriesArray.get(index));
String hint = phoneFormatMap.get(text);
updatePhoneField(); phoneField.setHintText(hint != null ? hint.replace('X', '') : null);
countryState = 0; countryState = 0;
} else { } else {
countryButton.setText(LocaleController.getString("WrongCountry", R.string.WrongCountry)); countryButton.setText(LocaleController.getString("WrongCountry", R.string.WrongCountry));
phoneField.setHintText(null);
countryState = 2; countryState = 2;
} }
} else { } else {
countryButton.setText(LocaleController.getString("WrongCountry", R.string.WrongCountry)); countryButton.setText(LocaleController.getString("WrongCountry", R.string.WrongCountry));
phoneField.setHintText(null);
countryState = 2; countryState = 2;
} }
codeField.setSelection(codeField.getText().length()); if (!ok) {
codeField.setSelection(codeField.getText().length());
}
if (textToSet != null) {
phoneField.requestFocus();
phoneField.setText(textToSet);
phoneField.setSelection(phoneField.length());
}
} }
} }
}); });
@ -411,13 +421,14 @@ public class ChangePhoneActivity extends BaseFragment {
public boolean onEditorAction(TextView textView, int i, KeyEvent keyEvent) { public boolean onEditorAction(TextView textView, int i, KeyEvent keyEvent) {
if (i == EditorInfo.IME_ACTION_NEXT) { if (i == EditorInfo.IME_ACTION_NEXT) {
phoneField.requestFocus(); phoneField.requestFocus();
phoneField.setSelection(phoneField.length());
return true; return true;
} }
return false; return false;
} }
}); });
phoneField = new EditText(context); phoneField = new HintEditText(context);
phoneField.setInputType(InputType.TYPE_CLASS_PHONE); phoneField.setInputType(InputType.TYPE_CLASS_PHONE);
phoneField.setTextColor(0xff212121); phoneField.setTextColor(0xff212121);
phoneField.setHintTextColor(0xff979797); phoneField.setHintTextColor(0xff979797);
@ -427,43 +438,25 @@ public class ChangePhoneActivity extends BaseFragment {
phoneField.setMaxLines(1); phoneField.setMaxLines(1);
phoneField.setGravity(Gravity.LEFT | Gravity.CENTER_VERTICAL); phoneField.setGravity(Gravity.LEFT | Gravity.CENTER_VERTICAL);
phoneField.setImeOptions(EditorInfo.IME_ACTION_NEXT | EditorInfo.IME_FLAG_NO_EXTRACT_UI); phoneField.setImeOptions(EditorInfo.IME_ACTION_NEXT | EditorInfo.IME_FLAG_NO_EXTRACT_UI);
linearLayout.addView(phoneField); linearLayout.addView(phoneField, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 36, 0, 0, 24, 0));
layoutParams = (LayoutParams) phoneField.getLayoutParams();
layoutParams.width = LayoutHelper.MATCH_PARENT;
layoutParams.height = AndroidUtilities.dp(36);
layoutParams.rightMargin = AndroidUtilities.dp(24);
phoneField.setLayoutParams(layoutParams);
phoneField.addTextChangedListener(new TextWatcher() { phoneField.addTextChangedListener(new TextWatcher() {
private int characterAction = -1;
private int actionPosition;
@Override @Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) { public void beforeTextChanged(CharSequence s, int start, int count, int after) {
if (ignoreOnPhoneChange) { if (count == 0 && after == 1) {
return; characterAction = 1;
} } else if (count == 1 && after == 0) {
if (count == 1 && after == 0 && s.length() > 1) { if (s.charAt(start) == ' ' && start > 0) {
String phoneChars = "0123456789"; characterAction = 3;
String str = s.toString(); actionPosition = start - 1;
String substr = str.substring(start, start + 1); } else {
if (!phoneChars.contains(substr)) { characterAction = 2;
ignoreOnPhoneChange = true;
StringBuilder builder = new StringBuilder(str);
int toDelete = 0;
for (int a = start; a >= 0; a--) {
substr = str.substring(a, a + 1);
if(phoneChars.contains(substr)) {
break;
}
toDelete++;
}
builder.delete(Math.max(0, start - toDelete), start + 1);
str = builder.toString();
if (PhoneFormat.strip(str).length() == 0) {
phoneField.setText("");
} else {
phoneField.setText(str);
updatePhoneField();
}
ignoreOnPhoneChange = false;
} }
} else {
characterAction = -1;
} }
} }
@ -477,7 +470,47 @@ public class ChangePhoneActivity extends BaseFragment {
if (ignoreOnPhoneChange) { if (ignoreOnPhoneChange) {
return; return;
} }
updatePhoneField(); int start = phoneField.getSelectionStart();
String phoneChars = "0123456789";
String str = phoneField.getText().toString();
if (characterAction == 3) {
str = str.substring(0, actionPosition) + str.substring(actionPosition + 1, str.length());
start--;
}
StringBuilder builder = new StringBuilder(str.length());
for (int a = 0; a < str.length(); a++) {
String ch = str.substring(a, a + 1);
if (phoneChars.contains(ch)) {
builder.append(ch);
}
}
ignoreOnPhoneChange = true;
String hint = phoneField.getHintText();
if (hint != null) {
for (int a = 0; a < builder.length(); a++) {
if (a < hint.length()) {
if (hint.charAt(a) == ' ') {
builder.insert(a, ' ');
a++;
if (start == a && characterAction != 2 && characterAction != 3) {
start++;
}
}
} else {
builder.insert(a, ' ');
if (start == a + 1 && characterAction != 2 && characterAction != 3) {
start++;
}
break;
}
}
}
phoneField.setText(builder);
if (start >= 0) {
phoneField.setSelection(start <= phoneField.length() ? start : phoneField.length());
}
phoneField.onTextChange();
ignoreOnPhoneChange = false;
} }
}); });
phoneField.setOnEditorActionListener(new TextView.OnEditorActionListener() { phoneField.setOnEditorActionListener(new TextView.OnEditorActionListener() {
@ -497,16 +530,7 @@ public class ChangePhoneActivity extends BaseFragment {
textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14);
textView.setGravity(Gravity.LEFT); textView.setGravity(Gravity.LEFT);
textView.setLineSpacing(AndroidUtilities.dp(2), 1.0f); textView.setLineSpacing(AndroidUtilities.dp(2), 1.0f);
addView(textView); addView(textView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.LEFT, 24, 28, 24, 10));
layoutParams = (LayoutParams) textView.getLayoutParams();
layoutParams.width = LayoutHelper.WRAP_CONTENT;
layoutParams.height = LayoutHelper.WRAP_CONTENT;
layoutParams.leftMargin = AndroidUtilities.dp(24);
layoutParams.rightMargin = AndroidUtilities.dp(24);
layoutParams.topMargin = AndroidUtilities.dp(28);
layoutParams.bottomMargin = AndroidUtilities.dp(10);
layoutParams.gravity = Gravity.LEFT;
textView.setLayoutParams(layoutParams);
HashMap<String, String> languageMap = new HashMap<>(); HashMap<String, String> languageMap = new HashMap<>();
try { try {
@ -517,6 +541,9 @@ public class ChangePhoneActivity extends BaseFragment {
countriesArray.add(0, args[2]); countriesArray.add(0, args[2]);
countriesMap.put(args[2], args[0]); countriesMap.put(args[2], args[0]);
codesMap.put(args[0], args[2]); codesMap.put(args[0], args[2]);
if (args.length > 3) {
phoneFormatMap.put(args[0], args[3]);
}
languageMap.put(args[1], args[2]); languageMap.put(args[1], args[2]);
} }
reader.close(); reader.close();
@ -554,12 +581,14 @@ public class ChangePhoneActivity extends BaseFragment {
} }
if (codeField.length() == 0) { if (codeField.length() == 0) {
countryButton.setText(LocaleController.getString("ChooseCountry", R.string.ChooseCountry)); countryButton.setText(LocaleController.getString("ChooseCountry", R.string.ChooseCountry));
phoneField.setHintText(null);
countryState = 1; countryState = 1;
} }
if (codeField.length() != 0) { if (codeField.length() != 0) {
AndroidUtilities.showKeyboard(phoneField); AndroidUtilities.showKeyboard(phoneField);
phoneField.requestFocus(); phoneField.requestFocus();
phoneField.setSelection(phoneField.length());
} else { } else {
AndroidUtilities.showKeyboard(codeField); AndroidUtilities.showKeyboard(codeField);
codeField.requestFocus(); codeField.requestFocus();
@ -570,39 +599,15 @@ public class ChangePhoneActivity extends BaseFragment {
int index = countriesArray.indexOf(name); int index = countriesArray.indexOf(name);
if (index != -1) { if (index != -1) {
ignoreOnTextChange = true; ignoreOnTextChange = true;
codeField.setText(countriesMap.get(name)); String code = countriesMap.get(name);
codeField.setText(code);
countryButton.setText(name); countryButton.setText(name);
String hint = phoneFormatMap.get(code);
phoneField.setHintText(hint != null ? hint.replace('X', '') : null);
countryState = 0; countryState = 0;
} }
} }
private void updatePhoneField() {
ignoreOnPhoneChange = true;
try {
String codeText = codeField.getText().toString();
String phone = PhoneFormat.getInstance().format("+" + codeText + phoneField.getText().toString());
int idx = phone.indexOf(" ");
if (idx != -1) {
String resultCode = PhoneFormat.stripExceptNumbers(phone.substring(0, idx));
if (!codeText.equals(resultCode)) {
phone = PhoneFormat.getInstance().format(phoneField.getText().toString()).trim();
phoneField.setText(phone);
int len = phoneField.length();
phoneField.setSelection(phoneField.length());
} else {
phoneField.setText(phone.substring(idx).trim());
int len = phoneField.length();
phoneField.setSelection(phoneField.length());
}
} else {
phoneField.setSelection(phoneField.length());
}
} catch (Exception e) {
FileLog.e("tmessages", e);
}
ignoreOnPhoneChange = false;
}
@Override @Override
public void onItemSelected(AdapterView<?> adapterView, View view, int i, long l) { public void onItemSelected(AdapterView<?> adapterView, View view, int i, long l) {
if (ignoreSelection) { if (ignoreSelection) {
@ -612,7 +617,6 @@ public class ChangePhoneActivity extends BaseFragment {
ignoreOnTextChange = true; ignoreOnTextChange = true;
String str = countriesArray.get(i); String str = countriesArray.get(i);
codeField.setText(countriesMap.get(str)); codeField.setText(countriesMap.get(str));
updatePhoneField();
} }
@Override @Override
@ -686,8 +690,14 @@ public class ChangePhoneActivity extends BaseFragment {
public void onShow() { public void onShow() {
super.onShow(); super.onShow();
if (phoneField != null) { if (phoneField != null) {
AndroidUtilities.showKeyboard(phoneField); if (codeField.length() != 0) {
phoneField.setSelection(phoneField.length()); AndroidUtilities.showKeyboard(phoneField);
phoneField.requestFocus();
phoneField.setSelection(phoneField.length());
} else {
AndroidUtilities.showKeyboard(codeField);
codeField.requestFocus();
}
} }
} }
@ -713,6 +723,7 @@ public class ChangePhoneActivity extends BaseFragment {
private volatile int codeTime = 15000; private volatile int codeTime = 15000;
private double lastCurrentTime; private double lastCurrentTime;
private double lastCodeTime; private double lastCodeTime;
private boolean ignoreOnTextChange;
private boolean waitingForSms = false; private boolean waitingForSms = false;
private boolean nextPressed = false; private boolean nextPressed = false;
private String lastError = ""; private String lastError = "";
@ -755,6 +766,27 @@ public class ChangePhoneActivity extends BaseFragment {
layoutParams.leftMargin = AndroidUtilities.dp(24); layoutParams.leftMargin = AndroidUtilities.dp(24);
layoutParams.rightMargin = AndroidUtilities.dp(24); layoutParams.rightMargin = AndroidUtilities.dp(24);
codeField.setLayoutParams(layoutParams); codeField.setLayoutParams(layoutParams);
codeField.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
@Override
public void afterTextChanged(Editable s) {
if (ignoreOnTextChange) {
return;
}
if (codeField.length() == 5) {
onNextPressed();
}
}
});
codeField.setOnEditorActionListener(new TextView.OnEditorActionListener() { codeField.setOnEditorActionListener(new TextView.OnEditorActionListener() {
@Override @Override
public boolean onEditorAction(TextView textView, int i, KeyEvent keyEvent) { public boolean onEditorAction(TextView textView, int i, KeyEvent keyEvent) {
@ -1051,6 +1083,7 @@ public class ChangePhoneActivity extends BaseFragment {
return; return;
} }
if (codeField != null) { if (codeField != null) {
ignoreOnTextChange = true;
codeField.setText("" + args[0]); codeField.setText("" + args[0]);
onNextPressed(); onNextPressed();
} }

View File

@ -307,7 +307,7 @@ public class ChannelCreateActivity extends BaseFragment implements NotificationC
result.add(user); result.add(user);
} }
} }
MessagesController.getInstance().addUsersToChannel(chatId, result); MessagesController.getInstance().addUsersToChannel(chatId, result, null);
NotificationCenter.getInstance().postNotificationName(NotificationCenter.closeChats); NotificationCenter.getInstance().postNotificationName(NotificationCenter.closeChats);
Bundle args2 = new Bundle(); Bundle args2 = new Bundle();
args2.putInt("chat_id", chatId); args2.putInt("chat_id", chatId);
@ -655,7 +655,7 @@ public class ChannelCreateActivity extends BaseFragment implements NotificationC
actionBar.setTitle(LocaleController.getString("ChannelAddMembers", R.string.ChannelAddMembers)); actionBar.setTitle(LocaleController.getString("ChannelAddMembers", R.string.ChannelAddMembers));
actionBar.setSubtitle(LocaleController.formatPluralString("Members", selectedContacts.size())); actionBar.setSubtitle(LocaleController.formatPluralString("Members", selectedContacts.size()));
searchListViewAdapter = new SearchAdapter(context, null, false, false, false); searchListViewAdapter = new SearchAdapter(context, null, false, false, false, false);
searchListViewAdapter.setCheckedMap(selectedContacts); searchListViewAdapter.setCheckedMap(selectedContacts);
searchListViewAdapter.setUseUserCell(true); searchListViewAdapter.setUseUserCell(true);
listViewAdapter = new ContactsAdapter(context, 1, false, null, false); listViewAdapter = new ContactsAdapter(context, 1, false, null, false);

View File

@ -118,7 +118,7 @@ public class ChannelEditActivity extends BaseFragment implements AvatarUpdater.A
return false; return false;
} }
if (info == null) { if (info == null) {
MessagesStorage.getInstance().loadChatInfo(chatId, semaphore, false); MessagesStorage.getInstance().loadChatInfo(chatId, semaphore, false, false);
try { try {
semaphore.acquire(); semaphore.acquire();
} catch (Exception e) { } catch (Exception e) {
@ -132,7 +132,7 @@ public class ChannelEditActivity extends BaseFragment implements AvatarUpdater.A
wasPrivate = currentChat.username == null || currentChat.username.length() == 0; wasPrivate = currentChat.username == null || currentChat.username.length() == 0;
avatarUpdater.parentFragment = this; avatarUpdater.parentFragment = this;
avatarUpdater.delegate = this; avatarUpdater.delegate = this;
allowComments = (currentChat.flags & TLRPC.CHAT_FLAG_IS_BROADCAST) == 0; allowComments = !currentChat.broadcast;
return super.onFragmentCreate(); return super.onFragmentCreate();
} }
@ -178,14 +178,16 @@ public class ChannelEditActivity extends BaseFragment implements AvatarUpdater.A
AndroidUtilities.shakeView(nameTextView, 2, 0); AndroidUtilities.shakeView(nameTextView, 2, 0);
return; return;
} }
if ((currentChat.username == null && userNameTextView.length() != 0) || (currentChat.username != null && !currentChat.username.equalsIgnoreCase(userNameTextView.getText().toString()))) { if (userNameTextView != null) {
if (userNameTextView.length() != 0 && !lastNameAvailable) { if ((currentChat.username == null && userNameTextView.length() != 0) || (currentChat.username != null && !currentChat.username.equalsIgnoreCase(userNameTextView.getText().toString()))) {
Vibrator v = (Vibrator) getParentActivity().getSystemService(Context.VIBRATOR_SERVICE); if (userNameTextView.length() != 0 && !lastNameAvailable) {
if (v != null) { Vibrator v = (Vibrator) getParentActivity().getSystemService(Context.VIBRATOR_SERVICE);
v.vibrate(200); if (v != null) {
v.vibrate(200);
}
AndroidUtilities.shakeView(checkTextView, 2, 0);
return;
} }
AndroidUtilities.shakeView(checkTextView, 2, 0);
return;
} }
} }
@ -211,7 +213,7 @@ public class ChannelEditActivity extends BaseFragment implements AvatarUpdater.A
progressDialog.show(); progressDialog.show();
return; return;
} }
boolean currentAllowComments = (currentChat.flags & TLRPC.CHAT_FLAG_IS_BROADCAST) == 0; boolean currentAllowComments = !currentChat.broadcast;
if (allowComments != currentAllowComments) { if (allowComments != currentAllowComments) {
MessagesController.getInstance().toogleChannelComments(chatId, allowComments); MessagesController.getInstance().toogleChannelComments(chatId, allowComments);
} }
@ -221,9 +223,11 @@ public class ChannelEditActivity extends BaseFragment implements AvatarUpdater.A
if (info != null && !info.about.equals(descriptionTextView.getText().toString())) { if (info != null && !info.about.equals(descriptionTextView.getText().toString())) {
MessagesController.getInstance().updateChannelAbout(chatId, descriptionTextView.getText().toString(), info); MessagesController.getInstance().updateChannelAbout(chatId, descriptionTextView.getText().toString(), info);
} }
String oldUserName = currentChat.username != null ? currentChat.username : ""; if (userNameTextView != null) {
if (!oldUserName.equals(userNameTextView.getText().toString())) { String oldUserName = currentChat.username != null ? currentChat.username : "";
MessagesController.getInstance().updateChannelUserName(chatId, userNameTextView.getText().toString()); if (!oldUserName.equals(userNameTextView.getText().toString())) {
MessagesController.getInstance().updateChannelUserName(chatId, userNameTextView.getText().toString());
}
} }
if (uploadedAvatar != null) { if (uploadedAvatar != null) {
MessagesController.getInstance().changeChatAvatar(chatId, uploadedAvatar); MessagesController.getInstance().changeChatAvatar(chatId, uploadedAvatar);
@ -299,7 +303,11 @@ public class ChannelEditActivity extends BaseFragment implements AvatarUpdater.A
}); });
nameTextView = new EditText(context); nameTextView = new EditText(context);
nameTextView.setHint(LocaleController.getString("EnterChannelName", R.string.EnterChannelName)); if (currentChat.megagroup) {
nameTextView.setHint(LocaleController.getString("GroupName", R.string.GroupName));
} else {
nameTextView.setHint(LocaleController.getString("EnterChannelName", R.string.EnterChannelName));
}
nameTextView.setMaxLines(4); nameTextView.setMaxLines(4);
nameTextView.setGravity(Gravity.CENTER_VERTICAL | (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT)); nameTextView.setGravity(Gravity.CENTER_VERTICAL | (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT));
nameTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16); nameTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16);
@ -382,90 +390,95 @@ public class ChannelEditActivity extends BaseFragment implements AvatarUpdater.A
}); });
TextInfoPrivacyCell infoCell = new TextInfoPrivacyCell(context); TextInfoPrivacyCell infoCell = new TextInfoPrivacyCell(context);
infoCell.setText(LocaleController.getString("DescriptionInfo", R.string.DescriptionInfo)); if (currentChat.megagroup) {
infoCell.setText(LocaleController.getString("DescriptionInfoMega", R.string.DescriptionInfoMega));
} else {
infoCell.setText(LocaleController.getString("DescriptionInfo", R.string.DescriptionInfo));
}
infoCell.setBackgroundResource(R.drawable.greydivider); infoCell.setBackgroundResource(R.drawable.greydivider);
linearLayout.addView(infoCell, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); linearLayout.addView(infoCell, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT));
if (!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));
linearLayout2 = new LinearLayout(context); LinearLayout publicContainer = new LinearLayout(context);
linearLayout2.setOrientation(LinearLayout.VERTICAL); publicContainer.setOrientation(LinearLayout.HORIZONTAL);
linearLayout2.setBackgroundColor(0xffffffff); linearLayout2.addView(publicContainer, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 36, 17, 7, 17, 0));
linearLayout2.setPadding(0, 0, 0, AndroidUtilities.dp(7));
linearLayout.addView(linearLayout2, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT));
LinearLayout publicContainer = new LinearLayout(context); EditText editText = new EditText(context);
publicContainer.setOrientation(LinearLayout.HORIZONTAL); editText.setText("telegram.me/");
linearLayout2.addView(publicContainer, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 36, 17, 7, 17, 0)); 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));
EditText editText = new EditText(context); userNameTextView = new EditText(context);
editText.setText("telegram.me/"); userNameTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 18);
editText.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 18); userNameTextView.setHintTextColor(0xff979797);
editText.setHintTextColor(0xff979797); userNameTextView.setTextColor(0xff212121);
editText.setTextColor(0xff212121); userNameTextView.setMaxLines(1);
editText.setMaxLines(1); userNameTextView.setLines(1);
editText.setLines(1); userNameTextView.setBackgroundDrawable(null);
editText.setEnabled(false); userNameTextView.setPadding(0, 0, 0, 0);
editText.setBackgroundDrawable(null); userNameTextView.setSingleLine(true);
editText.setPadding(0, 0, 0, 0); userNameTextView.setText(currentChat.username);
editText.setSingleLine(true); userNameTextView.setInputType(InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS | InputType.TYPE_TEXT_FLAG_MULTI_LINE | InputType.TYPE_TEXT_FLAG_AUTO_CORRECT);
editText.setInputType(InputType.TYPE_TEXT_FLAG_MULTI_LINE | InputType.TYPE_TEXT_FLAG_AUTO_CORRECT); userNameTextView.setImeOptions(EditorInfo.IME_ACTION_DONE);
editText.setImeOptions(EditorInfo.IME_ACTION_DONE); userNameTextView.setHint(LocaleController.getString("ChannelUsernamePlaceholder", R.string.ChannelUsernamePlaceholder));
publicContainer.addView(editText, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, 36)); userNameTextView.setOnFocusChangeListener(new View.OnFocusChangeListener() {
@Override
userNameTextView = new EditText(context); public void onFocusChange(View v, boolean hasFocus) {
userNameTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 18); if (wasPrivate && hasFocus && !privateAlertShown) {
userNameTextView.setHintTextColor(0xff979797); AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity());
userNameTextView.setTextColor(0xff212121); builder.setTitle(LocaleController.getString("AppName", R.string.AppName));
userNameTextView.setMaxLines(1); builder.setMessage(LocaleController.getString("ChannelWasPrivateAlert", R.string.ChannelWasPrivateAlert));
userNameTextView.setLines(1); builder.setPositiveButton(LocaleController.getString("Close", R.string.Close), null);
userNameTextView.setBackgroundDrawable(null); showDialog(builder.create());
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));
builder.setMessage(LocaleController.getString("ChannelWasPrivateAlert", R.string.ChannelWasPrivateAlert));
builder.setPositiveButton(LocaleController.getString("Close", R.string.Close), null);
showDialog(builder.create());
} }
} });
}); AndroidUtilities.clearCursorDrawable(userNameTextView);
AndroidUtilities.clearCursorDrawable(userNameTextView); publicContainer.addView(userNameTextView, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 36));
publicContainer.addView(userNameTextView, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 36)); userNameTextView.addTextChangedListener(new TextWatcher() {
userNameTextView.addTextChangedListener(new TextWatcher() { @Override
@Override public void beforeTextChanged(CharSequence charSequence, int i, int i2, int i3) {
public void beforeTextChanged(CharSequence charSequence, int i, int i2, int i3) {
} }
@Override @Override
public void onTextChanged(CharSequence charSequence, int i, int i2, int i3) { public void onTextChanged(CharSequence charSequence, int i, int i2, int i3) {
checkUserName(userNameTextView.getText().toString(), false); checkUserName(userNameTextView.getText().toString(), false);
} }
@Override @Override
public void afterTextChanged(Editable editable) { public void afterTextChanged(Editable editable) {
} }
}); });
checkTextView = new TextView(context); checkTextView = new TextView(context);
checkTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 15); checkTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 15);
checkTextView.setGravity(LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT); checkTextView.setGravity(LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT);
checkTextView.setVisibility(View.GONE); 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)); 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 = new TextInfoPrivacyCell(context);
infoCell.setBackgroundResource(R.drawable.greydivider); infoCell.setBackgroundResource(R.drawable.greydivider);
infoCell.setText(LocaleController.getString("ChannelUsernameHelp", R.string.ChannelUsernameHelp)); infoCell.setText(LocaleController.getString("ChannelUsernameHelp", R.string.ChannelUsernameHelp));
linearLayout.addView(infoCell, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); linearLayout.addView(infoCell, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT));
}
/*frameLayout = new FrameLayoutFixed(context); /*frameLayout = new FrameLayoutFixed(context);
@ -496,13 +509,21 @@ public class ChannelEditActivity extends BaseFragment implements AvatarUpdater.A
TextSettingsCell textCell = new TextSettingsCell(context); TextSettingsCell textCell = new TextSettingsCell(context);
textCell.setTextColor(0xffed3d39); textCell.setTextColor(0xffed3d39);
textCell.setBackgroundResource(R.drawable.list_selector); textCell.setBackgroundResource(R.drawable.list_selector);
textCell.setText(LocaleController.getString("ChannelDelete", R.string.ChannelDelete), false); if (currentChat.megagroup) {
textCell.setText(LocaleController.getString("DeleteMega", R.string.DeleteMega), false);
} else {
textCell.setText(LocaleController.getString("ChannelDelete", R.string.ChannelDelete), false);
}
frameLayout.addView(textCell, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); frameLayout.addView(textCell, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT));
textCell.setOnClickListener(new View.OnClickListener() { textCell.setOnClickListener(new View.OnClickListener() {
@Override @Override
public void onClick(View v) { public void onClick(View v) {
AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity());
builder.setMessage(LocaleController.getString("ChannelDeleteAlert", R.string.ChannelDeleteAlert)); if (currentChat.megagroup) {
builder.setMessage(LocaleController.getString("MegaDeleteAlert", R.string.MegaDeleteAlert));
} else {
builder.setMessage(LocaleController.getString("ChannelDeleteAlert", R.string.ChannelDeleteAlert));
}
builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); builder.setTitle(LocaleController.getString("AppName", R.string.AppName));
builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), new DialogInterface.OnClickListener() { builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), new DialogInterface.OnClickListener() {
@Override @Override
@ -524,7 +545,11 @@ public class ChannelEditActivity extends BaseFragment implements AvatarUpdater.A
infoCell = new TextInfoPrivacyCell(context); infoCell = new TextInfoPrivacyCell(context);
infoCell.setBackgroundResource(R.drawable.greydivider_bottom); infoCell.setBackgroundResource(R.drawable.greydivider_bottom);
infoCell.setText(LocaleController.getString("ChannelDeleteInfo", R.string.ChannelDeleteInfo)); if (currentChat.megagroup) {
infoCell.setText(LocaleController.getString("MegaDeleteInfo", R.string.MegaDeleteInfo));
} else {
infoCell.setText(LocaleController.getString("ChannelDeleteInfo", R.string.ChannelDeleteInfo));
}
linearLayout.addView(infoCell, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); linearLayout.addView(infoCell, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT));
nameTextView.setText(currentChat.title); nameTextView.setText(currentChat.title);

View File

@ -57,8 +57,10 @@ public class ChannelUsersActivity extends BaseFragment implements NotificationCe
private int chatId; private int chatId;
private int type; private int type;
private boolean loadingUsers; private boolean loadingUsers;
private boolean firstLoaded;
private boolean isAdmin; private boolean isAdmin;
private boolean isPublic; private boolean isPublic;
private boolean isMegagroup;
private int participantsStartRow; private int participantsStartRow;
public ChannelUsersActivity(Bundle args) { public ChannelUsersActivity(Bundle args) {
@ -66,9 +68,12 @@ public class ChannelUsersActivity extends BaseFragment implements NotificationCe
chatId = arguments.getInt("chat_id"); chatId = arguments.getInt("chat_id");
type = arguments.getInt("type"); type = arguments.getInt("type");
TLRPC.Chat chat = MessagesController.getInstance().getChat(chatId); TLRPC.Chat chat = MessagesController.getInstance().getChat(chatId);
if (chat != null && (chat.flags & TLRPC.CHAT_FLAG_ADMIN) != 0) { if (chat != null) {
isAdmin = true; if (chat.creator) {
isPublic = (chat.flags & TLRPC.CHAT_FLAG_IS_PUBLIC) != 0; isAdmin = true;
isPublic = (chat.flags & TLRPC.CHAT_FLAG_IS_PUBLIC) != 0;
}
isMegagroup = chat.megagroup;
} }
if (type == 0) { if (type == 0) {
participantsStartRow = 0; participantsStartRow = 0;
@ -121,7 +126,11 @@ public class ChannelUsersActivity extends BaseFragment implements NotificationCe
emptyView = new EmptyTextProgressView(context); emptyView = new EmptyTextProgressView(context);
if (type == 0) { if (type == 0) {
emptyView.setText(LocaleController.getString("NoBlocked", R.string.NoBlocked)); if (isMegagroup) {
emptyView.setText(LocaleController.getString("NoBlockedGroup", R.string.NoBlockedGroup));
} else {
emptyView.setText(LocaleController.getString("NoBlocked", R.string.NoBlocked));
}
} }
frameLayout.addView(emptyView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); frameLayout.addView(emptyView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT));
@ -171,6 +180,9 @@ public class ChannelUsersActivity extends BaseFragment implements NotificationCe
args.putBoolean("returnAsResult", true); args.putBoolean("returnAsResult", true);
args.putBoolean("needForwardCount", false); args.putBoolean("needForwardCount", false);
args.putBoolean("allowUsernameSearch", true); args.putBoolean("allowUsernameSearch", true);
if (isMegagroup) {
args.putBoolean("allowBots", false);
}
args.putString("selectAlertString", LocaleController.getString("ChannelAddUserAdminAlert", R.string.ChannelAddUserAdminAlert)); args.putString("selectAlertString", LocaleController.getString("ChannelAddUserAdminAlert", R.string.ChannelAddUserAdminAlert));
ContactsActivity fragment = new ContactsActivity(args); ContactsActivity fragment = new ContactsActivity(args);
fragment.setDelegate(new ContactsActivity.ContactsActivityDelegate() { fragment.setDelegate(new ContactsActivity.ContactsActivityDelegate() {
@ -195,7 +207,7 @@ public class ChannelUsersActivity extends BaseFragment implements NotificationCe
} }
}); });
if (isAdmin) { if (isAdmin || isMegagroup && type == 0) {
listView.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() { listView.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
@Override @Override
public boolean onItemLongClick(AdapterView<?> adapterView, View view, int i, long l) { public boolean onItemLongClick(AdapterView<?> adapterView, View view, int i, long l) {
@ -280,18 +292,19 @@ public class ChannelUsersActivity extends BaseFragment implements NotificationCe
ConnectionsManager.getInstance().sendRequest(req, new RequestDelegate() { ConnectionsManager.getInstance().sendRequest(req, new RequestDelegate() {
@Override @Override
public void run(TLObject response, final TLRPC.TL_error error) { public void run(TLObject response, final TLRPC.TL_error error) {
if (response instanceof TLRPC.TL_boolTrue) { if (error == null) {
MessagesController.getInstance().processUpdates((TLRPC.Updates) response, false);
AndroidUtilities.runOnUIThread(new Runnable() { AndroidUtilities.runOnUIThread(new Runnable() {
@Override @Override
public void run() { public void run() {
MessagesController.getInstance().loadFullChat(chatId, 0, true); MessagesController.getInstance().loadFullChat(chatId, 0, true);
} }
}, 1000); }, 1000);
} else if (error != null) { } else {
AndroidUtilities.runOnUIThread(new Runnable() { AndroidUtilities.runOnUIThread(new Runnable() {
@Override @Override
public void run() { public void run() {
AlertsCreator.showAddUserAlert(error.text, ChannelUsersActivity.this); AlertsCreator.showAddUserAlert(error.text, ChannelUsersActivity.this, !isMegagroup);
} }
}); });
} }
@ -329,7 +342,7 @@ public class ChannelUsersActivity extends BaseFragment implements NotificationCe
return; return;
} }
loadingUsers = true; loadingUsers = true;
if (emptyView != null) { if (emptyView != null && !firstLoaded) {
emptyView.showProgress(); emptyView.showProgress();
} }
if (listViewAdapter != null) { if (listViewAdapter != null) {
@ -421,6 +434,7 @@ public class ChannelUsersActivity extends BaseFragment implements NotificationCe
} }
} }
loadingUsers = false; loadingUsers = false;
firstLoaded = true;
if (emptyView != null) { if (emptyView != null) {
emptyView.showTextView(); emptyView.showTextView();
} }
@ -486,7 +500,7 @@ public class ChannelUsersActivity extends BaseFragment implements NotificationCe
@Override @Override
public int getCount() { public int getCount() {
if (participants.isEmpty() && type == 0 || loadingUsers) { if (participants.isEmpty() && type == 0 || loadingUsers && !firstLoaded) {
return 0; return 0;
} }
return participants.size() + participantsStartRow + 1; return participants.size() + participantsStartRow + 1;
@ -512,7 +526,7 @@ public class ChannelUsersActivity extends BaseFragment implements NotificationCe
int viewType = getItemViewType(i); int viewType = getItemViewType(i);
if (viewType == 0) { if (viewType == 0) {
if (view == null) { if (view == null) {
view = new UserCell(mContext, 1); view = new UserCell(mContext, 1, 0);
view.setBackgroundColor(0xffffffff); view.setBackgroundColor(0xffffffff);
} }
UserCell userCell = (UserCell) view; UserCell userCell = (UserCell) view;
@ -540,19 +554,27 @@ public class ChannelUsersActivity extends BaseFragment implements NotificationCe
view = new TextInfoPrivacyCell(mContext); view = new TextInfoPrivacyCell(mContext);
} }
if (type == 0) { if (type == 0) {
((TextInfoPrivacyCell) view).setText(LocaleController.getString("UnblockText", R.string.UnblockText)); ((TextInfoPrivacyCell) view).setText(String.format("%1$s\n\n%2$s", LocaleController.getString("NoBlockedGroup", R.string.NoBlockedGroup), LocaleController.getString("UnblockText", R.string.UnblockText)));
view.setBackgroundResource(R.drawable.greydivider_bottom); view.setBackgroundResource(R.drawable.greydivider_bottom);
} else if (type == 1) { } else if (type == 1) {
if (i == 1 && isAdmin) { if (i == 1 && isAdmin) {
((TextInfoPrivacyCell) view).setText(LocaleController.getString("ChannelAdminsInfo", R.string.ChannelAdminsInfo)); if (isMegagroup) {
((TextInfoPrivacyCell) view).setText(LocaleController.getString("MegaAdminsInfo", R.string.MegaAdminsInfo));
} else {
((TextInfoPrivacyCell) view).setText(LocaleController.getString("ChannelAdminsInfo", R.string.ChannelAdminsInfo));
}
view.setBackgroundResource(R.drawable.greydivider); view.setBackgroundResource(R.drawable.greydivider);
} else { } else {
((TextInfoPrivacyCell) view).setText(""); ((TextInfoPrivacyCell) view).setText("");
view.setBackgroundResource(R.drawable.greydivider_bottom); view.setBackgroundResource(R.drawable.greydivider_bottom);
} }
} else if (type == 2) { } else if (type == 2) {
if ((!isPublic && i == 2 || i == 1) &&isAdmin) { if ((!isPublic && i == 2 || i == 1) && isAdmin) {
((TextInfoPrivacyCell) view).setText(LocaleController.getString("ChannelMembersInfo", R.string.ChannelMembersInfo)); if (isMegagroup) {
((TextInfoPrivacyCell) view).setText("");
} else {
((TextInfoPrivacyCell) view).setText(LocaleController.getString("ChannelMembersInfo", R.string.ChannelMembersInfo));
}
view.setBackgroundResource(R.drawable.greydivider); view.setBackgroundResource(R.drawable.greydivider);
} else { } else {
((TextInfoPrivacyCell) view).setText(""); ((TextInfoPrivacyCell) view).setText("");

File diff suppressed because it is too large Load Diff

View File

@ -70,6 +70,7 @@ public class AlertsCreator {
editor.putInt("notifyuntil_" + dialog_id, untilTime); editor.putInt("notifyuntil_" + dialog_id, untilTime);
flags = ((long) untilTime << 32) | 1; flags = ((long) untilTime << 32) | 1;
} }
NotificationsController.getInstance().removeNotificationsForDialog(dialog_id);
MessagesStorage.getInstance().setDialogFlags(dialog_id, flags); MessagesStorage.getInstance().setDialogFlags(dialog_id, flags);
editor.commit(); editor.commit();
TLRPC.Dialog dialog = MessagesController.getInstance().dialogs_dict.get(dialog_id); TLRPC.Dialog dialog = MessagesController.getInstance().dialogs_dict.get(dialog_id);
@ -84,7 +85,7 @@ public class AlertsCreator {
return builder.create(); return builder.create();
} }
public static void showAddUserAlert(String error, final BaseFragment fragment) { public static void showAddUserAlert(String error, final BaseFragment fragment, boolean isChannel) {
if (error == null || fragment == null || fragment.getParentActivity() == null) { if (error == null || fragment == null || fragment.getParentActivity() == null) {
return; return;
} }
@ -109,16 +110,39 @@ public class AlertsCreator {
case "USER_BLOCKED": case "USER_BLOCKED":
case "USER_BOT": case "USER_BOT":
case "USER_ID_INVALID": case "USER_ID_INVALID":
builder.setMessage(LocaleController.getString("ChannelUserCantAdd", R.string.ChannelUserCantAdd)); if (isChannel) {
builder.setMessage(LocaleController.getString("ChannelUserCantAdd", R.string.ChannelUserCantAdd));
} else {
builder.setMessage(LocaleController.getString("GroupUserCantAdd", R.string.GroupUserCantAdd));
}
break; break;
case "USERS_TOO_MUCH": case "USERS_TOO_MUCH":
builder.setMessage(LocaleController.getString("ChannelUserAddLimit", R.string.ChannelUserAddLimit)); if (isChannel) {
builder.setMessage(LocaleController.getString("ChannelUserAddLimit", R.string.ChannelUserAddLimit));
} else {
builder.setMessage(LocaleController.getString("GroupUserAddLimit", R.string.GroupUserAddLimit));
}
break; break;
case "USER_NOT_MUTUAL_CONTACT": case "USER_NOT_MUTUAL_CONTACT":
builder.setMessage(LocaleController.getString("ChannelUserLeftError", R.string.ChannelUserLeftError)); if (isChannel) {
builder.setMessage(LocaleController.getString("ChannelUserLeftError", R.string.ChannelUserLeftError));
} else {
builder.setMessage(LocaleController.getString("GroupUserLeftError", R.string.GroupUserLeftError));
}
break; break;
case "ADMINS_TOO_MUCH": case "ADMINS_TOO_MUCH":
builder.setMessage(LocaleController.getString("ChannelUserCantAdmin", R.string.ChannelUserCantAdmin)); if (isChannel) {
builder.setMessage(LocaleController.getString("ChannelUserCantAdmin", R.string.ChannelUserCantAdmin));
} else {
builder.setMessage(LocaleController.getString("GroupUserCantAdmin", R.string.GroupUserCantAdmin));
}
break;
case "BOTS_TOO_MUCH":
if (isChannel) {
builder.setMessage(LocaleController.getString("ChannelUserCantBot", R.string.ChannelUserCantBot));
} else {
builder.setMessage(LocaleController.getString("GroupUserCantBot", R.string.GroupUserCantBot));
}
break; break;
} }
builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), null); builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), null);

View File

@ -30,7 +30,7 @@ public class AvatarDrawable extends Drawable {
private static Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG); private static Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
private static TextPaint namePaint; private static TextPaint namePaint;
private static TextPaint namePaintSmall; private static TextPaint namePaintSmall;
private static int[] arrColors = {0xffe56555, 0xfff28c48, 0xff549cdd, 0xff76c84d, 0xff5fbed5, 0xff549cdd, 0xff8e85ee, 0xfff2749a}; private static int[] arrColors = {0xffe56555, 0xfff28c48, 0xff8e85ee, 0xff76c84d, 0xff5fbed5, 0xff549cdd, 0xff8e85ee, 0xfff2749a};
private static int[] arrColorsProfiles = {0xffd86f65, 0xfff69d61, 0xff8c79d2, 0xff67b35d, 0xff56a2bb, 0xff5c98cd, 0xff8c79d2, 0xfff37fa6}; private static int[] arrColorsProfiles = {0xffd86f65, 0xfff69d61, 0xff8c79d2, 0xff67b35d, 0xff56a2bb, 0xff5c98cd, 0xff8c79d2, 0xfff37fa6};
private static int[] arrColorsProfilesBack = {0xffca6056, 0xfff18944, 0xff7d6ac4, 0xff56a14c, 0xff4492ac, 0xff4c84b6, 0xff7d6ac4, 0xff4c84b6}; private static int[] arrColorsProfilesBack = {0xffca6056, 0xfff18944, 0xff7d6ac4, 0xff56a14c, 0xff4492ac, 0xff4c84b6, 0xff7d6ac4, 0xff4c84b6};
private static int[] arrColorsProfilesText = {0xfff9cbc5, 0xfffdddc8, 0xffcdc4ed, 0xffc0edba, 0xffb8e2f0, 0xffb3d7f7, 0xffcdc4ed, 0xffb3d7f7}; private static int[] arrColorsProfilesText = {0xfff9cbc5, 0xfffdddc8, 0xffcdc4ed, 0xffc0edba, 0xffb8e2f0, 0xffb3d7f7, 0xffcdc4ed, 0xffb3d7f7};
@ -92,6 +92,10 @@ public class AvatarDrawable extends Drawable {
} }
} }
public void setProfile(boolean value) {
isProfile = value;
}
public void setSmallStyle(boolean value) { public void setSmallStyle(boolean value) {
smallStyle = value; smallStyle = value;
} }

View File

@ -88,7 +88,7 @@ public class BotKeyboardView extends LinearLayout {
buttonViews.clear(); buttonViews.clear();
if (buttons != null && botButtons.rows.size() != 0) { if (buttons != null && botButtons.rows.size() != 0) {
isFullSize = (buttons.flags & 1) == 0; isFullSize = !buttons.resize;
buttonHeight = !isFullSize ? 42 : (int) Math.max(42, (panelHeight - AndroidUtilities.dp(30) - (botButtons.rows.size() - 1) * AndroidUtilities.dp(10)) / botButtons.rows.size() / AndroidUtilities.density); buttonHeight = !isFullSize ? 42 : (int) Math.max(42, (panelHeight - AndroidUtilities.dp(30) - (botButtons.rows.size() - 1) * AndroidUtilities.dp(10)) / botButtons.rows.size() / AndroidUtilities.density);
for (int a = 0; a < buttons.rows.size(); a++) { for (int a = 0; a < buttons.rows.size(); a++) {
TLRPC.TL_keyboardButtonRow row = buttons.rows.get(a); TLRPC.TL_keyboardButtonRow row = buttons.rows.get(a);

View File

@ -690,7 +690,7 @@ public class ChatActivityEnterView extends FrameLayoutFixed implements Notificat
return isAsAdmin; return isAsAdmin;
} }
public void showTopView(boolean animated) { public void showTopView(boolean animated, final boolean openKeyboard) {
if (topView == null || topViewShowed || getVisibility() != VISIBLE) { if (topView == null || topViewShowed || getVisibility() != VISIBLE) {
return; return;
} }
@ -713,7 +713,7 @@ public class ChatActivityEnterView extends FrameLayoutFixed implements Notificat
public void onAnimationEnd(Object animation) { public void onAnimationEnd(Object animation) {
if (currentTopViewAnimation != null && currentTopViewAnimation.equals(animation)) { if (currentTopViewAnimation != null && currentTopViewAnimation.equals(animation)) {
setTopViewAnimation(1.0f); setTopViewAnimation(1.0f);
if (!forceShowSendButton) { if (!forceShowSendButton || openKeyboard) {
openKeyboard(); openKeyboard();
} }
currentTopViewAnimation = null; currentTopViewAnimation = null;
@ -724,7 +724,7 @@ public class ChatActivityEnterView extends FrameLayoutFixed implements Notificat
currentTopViewAnimation.start(); currentTopViewAnimation.start();
} else { } else {
setTopViewAnimation(1.0f); setTopViewAnimation(1.0f);
if (!forceShowSendButton) { if (!forceShowSendButton || openKeyboard) {
openKeyboard(); openKeyboard();
} }
} }
@ -829,6 +829,7 @@ public class ChatActivityEnterView extends FrameLayoutFixed implements Notificat
public void onPause() { public void onPause() {
isPaused = true; isPaused = true;
closeKeyboard();
} }
public void onResume() { public void onResume() {
@ -849,8 +850,8 @@ public class ChatActivityEnterView extends FrameLayoutFixed implements Notificat
dialog_id = id; dialog_id = id;
if ((int) dialog_id < 0) { if ((int) dialog_id < 0) {
TLRPC.Chat currentChat = MessagesController.getInstance().getChat(-(int) dialog_id); TLRPC.Chat currentChat = MessagesController.getInstance().getChat(-(int) dialog_id);
isAsAdmin = ChatObject.isChannel(currentChat) && ((currentChat.flags & TLRPC.CHAT_FLAG_ADMIN) != 0 || (currentChat.flags & TLRPC.CHAT_FLAG_USER_IS_EDITOR) != 0); isAsAdmin = ChatObject.isChannel(currentChat) && (currentChat.creator || currentChat.editor) && !currentChat.megagroup;
adminModeAvailable = isAsAdmin && (currentChat.flags & TLRPC.CHAT_FLAG_IS_BROADCAST) == 0; adminModeAvailable = isAsAdmin && !currentChat.broadcast;
if (adminModeAvailable) { if (adminModeAvailable) {
SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("mainconfig", Activity.MODE_PRIVATE); SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("mainconfig", Activity.MODE_PRIVATE);
isAsAdmin = preferences.getBoolean("asadmin_" + dialog_id, true); isAsAdmin = preferences.getBoolean("asadmin_" + dialog_id, true);
@ -865,8 +866,9 @@ public class ChatActivityEnterView extends FrameLayoutFixed implements Notificat
private void updateFieldHint() { private void updateFieldHint() {
boolean isChannel = false; boolean isChannel = false;
if ((int) dialog_id < 0 && ChatObject.isChannel(MessagesController.getInstance().getChat(-(int) dialog_id))) { if ((int) dialog_id < 0) {
isChannel = true; TLRPC.Chat chat = MessagesController.getInstance().getChat(-(int) dialog_id);
isChannel = ChatObject.isChannel(chat) && !chat.megagroup;
} }
if (isChannel) { if (isChannel) {
messageEditText.setHint(isAsAdmin ? LocaleController.getString("ChannelBroadcast", R.string.ChannelBroadcast) : LocaleController.getString("ChannelComment", R.string.ChannelComment)); messageEditText.setHint(isAsAdmin ? LocaleController.getString("ChannelBroadcast", R.string.ChannelBroadcast) : LocaleController.getString("ChannelComment", R.string.ChannelComment));
@ -946,9 +948,9 @@ public class ChatActivityEnterView extends FrameLayoutFixed implements Notificat
} }
private String getTrimmedString(String src) { private String getTrimmedString(String src) {
String result = src.trim(); src = src.trim();
if (result.length() == 0) { if (src.length() == 0) {
return result; return src;
} }
while (src.startsWith("\n")) { while (src.startsWith("\n")) {
src = src.substring(1); src = src.substring(1);
@ -1240,13 +1242,18 @@ public class ChatActivityEnterView extends FrameLayoutFixed implements Notificat
this.delegate = delegate; this.delegate = delegate;
} }
public void setCommand(MessageObject messageObject, String command, boolean longPress) { public void setCommand(MessageObject messageObject, String command, boolean longPress, boolean username) {
if (command == null || getVisibility() != VISIBLE) { if (command == null || getVisibility() != VISIBLE) {
return; return;
} }
if (longPress) { if (longPress) {
String text = messageEditText.getText().toString(); String text = messageEditText.getText().toString();
text = command + " " + text.replaceFirst("^/[a-zA-Z@\\d_]{1,255}(\\s|$)", ""); TLRPC.User user = messageObject != null && (int) dialog_id < 0 ? MessagesController.getInstance().getUser(messageObject.messageOwner.from_id) : null;
if ((botCount != 1 || username) && user != null && user.bot && !command.contains("@")) {
text = String.format(Locale.US, "%s@%s", command, user.username) + " " + text.replaceFirst("^/[a-zA-Z@\\d_]{1,255}(\\s|$)", "");
} else {
text = command + " " + text.replaceFirst("^/[a-zA-Z@\\d_]{1,255}(\\s|$)", "");
}
ignoreTextChange = true; ignoreTextChange = true;
messageEditText.setText(text); messageEditText.setText(text);
messageEditText.setSelection(messageEditText.getText().length()); messageEditText.setSelection(messageEditText.getText().length());
@ -1256,7 +1263,7 @@ public class ChatActivityEnterView extends FrameLayoutFixed implements Notificat
} }
} else { } else {
TLRPC.User user = messageObject != null && (int) dialog_id < 0 ? MessagesController.getInstance().getUser(messageObject.messageOwner.from_id) : null; TLRPC.User user = messageObject != null && (int) dialog_id < 0 ? MessagesController.getInstance().getUser(messageObject.messageOwner.from_id) : null;
if (botCount != 1 && user != null && (user.flags & TLRPC.USER_FLAG_BOT) != 0 && !command.contains("@")) { if ((botCount != 1 || username) && user != null && user.bot && !command.contains("@")) {
SendMessagesHelper.getInstance().sendMessage(String.format(Locale.US, "%s@%s", command, user.username), dialog_id, null, null, false, asAdmin()); SendMessagesHelper.getInstance().sendMessage(String.format(Locale.US, "%s@%s", command, user.username), dialog_id, null, null, false, asAdmin());
} else { } else {
SendMessagesHelper.getInstance().sendMessage(command, dialog_id, null, null, false, asAdmin()); SendMessagesHelper.getInstance().sendMessage(command, dialog_id, null, null, false, asAdmin());
@ -1406,7 +1413,7 @@ public class ChatActivityEnterView extends FrameLayoutFixed implements Notificat
if (replyingMessageObject != null) { if (replyingMessageObject != null) {
openKeyboardInternal(); openKeyboardInternal();
setButtons(botMessageObject, false); setButtons(botMessageObject, false);
} else if ((botButtonsMessageObject.messageOwner.reply_markup.flags & 2) != 0) { } else if (botButtonsMessageObject.messageOwner.reply_markup.single_use) {
openKeyboardInternal(); openKeyboardInternal();
SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("mainconfig", Activity.MODE_PRIVATE); SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("mainconfig", Activity.MODE_PRIVATE);
preferences.edit().putInt("answered_" + dialog_id, botButtonsMessageObject.getId()).commit(); preferences.edit().putInt("answered_" + dialog_id, botButtonsMessageObject.getId()).commit();
@ -1426,7 +1433,7 @@ public class ChatActivityEnterView extends FrameLayoutFixed implements Notificat
if (botReplyMarkup != null) { if (botReplyMarkup != null) {
SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("mainconfig", Activity.MODE_PRIVATE); SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("mainconfig", Activity.MODE_PRIVATE);
boolean keyboardHidden = preferences.getInt("hidekeyboard_" + dialog_id, 0) == messageObject.getId(); boolean keyboardHidden = preferences.getInt("hidekeyboard_" + dialog_id, 0) == messageObject.getId();
if (botButtonsMessageObject != replyingMessageObject && (botReplyMarkup.flags & 2) != 0) { if (botButtonsMessageObject != replyingMessageObject && botReplyMarkup.single_use) {
if (preferences.getInt("answered_" + dialog_id, 0) == messageObject.getId()) { if (preferences.getInt("answered_" + dialog_id, 0) == messageObject.getId()) {
return; return;
} }
@ -1594,6 +1601,10 @@ public class ChatActivityEnterView extends FrameLayoutFixed implements Notificat
AndroidUtilities.showKeyboard(messageEditText); AndroidUtilities.showKeyboard(messageEditText);
} }
public void closeKeyboard() {
AndroidUtilities.hideKeyboard(messageEditText);
}
public boolean isPopupShowing() { public boolean isPopupShowing() {
return emojiView != null && emojiView.getVisibility() == VISIBLE || botKeyboardView != null && botKeyboardView.getVisibility() == VISIBLE; return emojiView != null && emojiView.getVisibility() == VISIBLE || botKeyboardView != null && botKeyboardView.getVisibility() == VISIBLE;
} }

View File

@ -0,0 +1,222 @@
/*
* 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-2015.
*/
package org.telegram.ui.Components;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.RectF;
import android.view.View;
import org.telegram.messenger.AndroidUtilities;
import org.telegram.messenger.AnimationCompat.ObjectAnimatorProxy;
public class CheckBoxSquare extends View {
private static Paint eraser;
private static Paint checkPaint;
private static Paint backgroundPaint;
private static RectF rectF;
private Bitmap drawBitmap;
private Canvas drawCanvas;
private float progress;
private ObjectAnimatorProxy checkAnimator;
private boolean isCheckAnimation = true;
private boolean attachedToWindow;
private boolean isChecked;
private boolean isDisabled;
private int color = 0xff43a0df;
private final static float progressBounceDiff = 0.2f;
public CheckBoxSquare(Context context) {
super(context);
if (checkPaint == null) {
checkPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
checkPaint.setColor(0xffffffff);
checkPaint.setStyle(Paint.Style.STROKE);
checkPaint.setStrokeWidth(AndroidUtilities.dp(2));
eraser = new Paint(Paint.ANTI_ALIAS_FLAG);
eraser.setColor(0);
eraser.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
backgroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
rectF = new RectF();
}
drawBitmap = Bitmap.createBitmap(AndroidUtilities.dp(18), AndroidUtilities.dp(18), Bitmap.Config.ARGB_4444);
drawCanvas = new Canvas(drawBitmap);
}
@Override
public void setVisibility(int visibility) {
super.setVisibility(visibility);
if (visibility == VISIBLE && drawBitmap == null) {
}
}
public void setProgress(float value) {
if (progress == value) {
return;
}
progress = value;
invalidate();
}
public float getProgress() {
return progress;
}
public void setColor(int value) {
color = value;
}
private void cancelCheckAnimator() {
if (checkAnimator != null) {
checkAnimator.cancel();
}
}
private void animateToCheckedState(boolean newCheckedState) {
isCheckAnimation = newCheckedState;
checkAnimator = ObjectAnimatorProxy.ofFloatProxy(this, "progress", newCheckedState ? 1 : 0);
checkAnimator.setDuration(300);
checkAnimator.start();
}
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
attachedToWindow = true;
}
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
attachedToWindow = false;
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
}
public void setChecked(boolean checked, boolean animated) {
if (checked == isChecked) {
return;
}
isChecked = checked;
if (attachedToWindow && animated) {
animateToCheckedState(checked);
} else {
cancelCheckAnimator();
setProgress(checked ? 1.0f : 0.0f);
}
}
public void setDisabled(boolean disabled) {
isDisabled = disabled;
invalidate();
}
public boolean isChecked() {
return isChecked;
}
@Override
protected void onDraw(Canvas canvas) {
if (getVisibility() != VISIBLE) {
return;
}
float checkProgress;
float bounceProgress;
if (progress <= 0.5f) {
bounceProgress = checkProgress = progress / 0.5f;
int rD = (int) ((Color.red(color) - 0x73) * checkProgress);
int gD = (int) ((Color.green(color) - 0x73) * checkProgress);
int bD = (int) ((Color.blue(color) - 0x73) * checkProgress);
int c = Color.rgb(0x73 + rD, 0x73 + gD, 0x73 + bD);
backgroundPaint.setColor(c);
} else {
bounceProgress = 2.0f - progress / 0.5f;
checkProgress = 1.0f;
backgroundPaint.setColor(color);
}
if (isDisabled) {
backgroundPaint.setColor(0xffb0b0b0);
}
float bounce = AndroidUtilities.dp(1) * bounceProgress;
rectF.set(bounce, bounce, AndroidUtilities.dp(18) - bounce, AndroidUtilities.dp(18) - bounce);
drawBitmap.eraseColor(0);
drawCanvas.drawRoundRect(rectF, AndroidUtilities.dp(2), AndroidUtilities.dp(2), backgroundPaint);
if (checkProgress != 1) {
float rad = Math.min(AndroidUtilities.dp(7), AndroidUtilities.dp(7) * checkProgress + bounce);
rectF.set(AndroidUtilities.dp(2) + rad, AndroidUtilities.dp(2) + rad, AndroidUtilities.dp(16) - rad, AndroidUtilities.dp(16) - rad);
drawCanvas.drawRect(rectF, eraser);
}
if (progress > 0.5f) {
int endX = (int) (AndroidUtilities.dp(7.5f) - AndroidUtilities.dp(5) * (1.0f - bounceProgress)); //dp 2.5f
int endY = (int) (AndroidUtilities.dpf2(13.5f) - AndroidUtilities.dp(5) * (1.0f - bounceProgress)); //dpf2 8.5f
drawCanvas.drawLine(AndroidUtilities.dp(7.5f), (int) AndroidUtilities.dpf2(13.5f), endX, endY, checkPaint);
endX = (int) (AndroidUtilities.dpf2(6.5f) + AndroidUtilities.dp(9) * (1.0f - bounceProgress)); //dpf2 15.5f
endY = (int) (AndroidUtilities.dpf2(13.5f) - AndroidUtilities.dp(9) * (1.0f - bounceProgress)); //dpf2 4.5f
drawCanvas.drawLine((int) AndroidUtilities.dpf2(6.5f), (int) AndroidUtilities.dpf2(13.5f), endX, endY, checkPaint);
}
canvas.drawBitmap(drawBitmap, 0, 0, null);
/*eraser2.setStrokeWidth(AndroidUtilities.dp(size + 6));
drawBitmap.eraseColor(0);
float rad = getMeasuredWidth() / 2;
float roundProgress = progress >= 0.5f ? 1.0f : progress / 0.5f;
float checkProgress = progress < 0.5f ? 0.0f : (progress - 0.5f) / 0.5f;
float roundProgressCheckState = isCheckAnimation ? progress : (1.0f - progress);
if (roundProgressCheckState < progressBounceDiff) {
rad -= AndroidUtilities.dp(2) * roundProgressCheckState / progressBounceDiff;
} else if (roundProgressCheckState < progressBounceDiff * 2) {
rad -= AndroidUtilities.dp(2) - AndroidUtilities.dp(2) * (roundProgressCheckState - progressBounceDiff) / progressBounceDiff;
}
if (drawBackground) {
paint.setColor(0x44000000);
canvas.drawCircle(getMeasuredWidth() / 2, getMeasuredHeight() / 2, rad - AndroidUtilities.dp(1), paint);
canvas.drawCircle(getMeasuredWidth() / 2, getMeasuredHeight() / 2, rad - AndroidUtilities.dp(1), backgroundPaint);
}
paint.setColor(color);
bitmapCanvas.drawCircle(getMeasuredWidth() / 2, getMeasuredHeight() / 2, rad, paint);
bitmapCanvas.drawCircle(getMeasuredWidth() / 2, getMeasuredHeight() / 2, rad * (1 - roundProgress), eraser);
canvas.drawBitmap(drawBitmap, 0, 0, null);
checkBitmap.eraseColor(0);
int w = checkDrawable.getIntrinsicWidth();
int h = checkDrawable.getIntrinsicHeight();
int x = (getMeasuredWidth() - w) / 2;
int y = (getMeasuredHeight() - h) / 2;
checkDrawable.setBounds(x, y + checkOffset, x + w, y + h + checkOffset);
checkDrawable.draw(checkCanvas);
checkCanvas.drawCircle(getMeasuredWidth() / 2 - AndroidUtilities.dp(2.5f), getMeasuredHeight() / 2 + AndroidUtilities.dp(4), ((getMeasuredWidth() + AndroidUtilities.dp(6)) / 2) * (1 - checkProgress), eraser2);
canvas.drawBitmap(checkBitmap, 0, 0, null);*/
}
}

View File

@ -1166,7 +1166,7 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific
ArrayList<TLRPC.TL_messages_stickerSet> packs = StickersQuery.getStickerSets(); ArrayList<TLRPC.TL_messages_stickerSet> packs = StickersQuery.getStickerSets();
for (int a = 0; a < packs.size(); a++) { for (int a = 0; a < packs.size(); a++) {
TLRPC.TL_messages_stickerSet pack = packs.get(a); TLRPC.TL_messages_stickerSet pack = packs.get(a);
if ((pack.set.flags & 2) != 0 || pack.documents == null || pack.documents.isEmpty()) { if (pack.set.disabled || pack.documents == null || pack.documents.isEmpty()) {
continue; continue;
} }
stickerSets.add(pack); stickerSets.add(pack);

View File

@ -151,7 +151,11 @@ public class FrameLayoutFixed extends FrameLayout {
} }
} catch (Exception e) { } catch (Exception e) {
FileLog.e("tmessages", e); FileLog.e("tmessages", e);
super.onMeasure(widthMeasureSpec, heightMeasureSpec); try {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
} catch (Exception e2) {
FileLog.e("tmessages", e2);
}
} }
} }
} }

View File

@ -0,0 +1,73 @@
/*
* 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-2015.
*/
package org.telegram.ui.Components;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import android.widget.EditText;
import org.telegram.messenger.AndroidUtilities;
public class HintEditText extends EditText {
private String hintText;
private float textOffset;
private float spaceSize;
private float numberSize;
private Paint paint = new Paint();
private Rect rect = new Rect();
public HintEditText(Context context) {
super(context);
paint.setColor(0xff979797);
}
public String getHintText() {
return hintText;
}
public void setHintText(String value) {
hintText = value;
onTextChange();
setText(getText());
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
onTextChange();
}
public void onTextChange() {
textOffset = (length() > 0 ? getPaint().measureText(getText(), 0, length()) : 0);
spaceSize = getPaint().measureText(" ");
numberSize = getPaint().measureText("1");
invalidate();
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (hintText != null && length() < hintText.length()) {
int top = getMeasuredHeight() / 2;
float offsetX = textOffset;
for (int a = length(); a < hintText.length(); a++) {
if (hintText.charAt(a) == ' ') {
offsetX += spaceSize;
} else {
rect.set((int) offsetX + AndroidUtilities.dp(1), top, (int) (offsetX + numberSize) - AndroidUtilities.dp(1), top + AndroidUtilities.dp(2));
canvas.drawRect(rect, paint);
offsetX += numberSize;
}
}
}
}
}

View File

@ -11,6 +11,7 @@ package org.telegram.ui.Components;
import android.widget.FrameLayout; import android.widget.FrameLayout;
import android.widget.LinearLayout; import android.widget.LinearLayout;
import android.widget.RelativeLayout; import android.widget.RelativeLayout;
import android.widget.ScrollView;
import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.AndroidUtilities;
@ -23,6 +24,10 @@ public class LayoutHelper {
return (int) (size < 0 ? size : AndroidUtilities.dp(size)); return (int) (size < 0 ? size : AndroidUtilities.dp(size));
} }
public static FrameLayout.LayoutParams createScroll(int width, int height, int gravity) {
return new ScrollView.LayoutParams(getSize(width), getSize(height), gravity);
}
public static FrameLayout.LayoutParams createFrame(int width, float height, int gravity, float leftMargin, float topMargin, float rightMargin, float bottomMargin) { public static FrameLayout.LayoutParams createFrame(int width, float height, int gravity, float leftMargin, float topMargin, float rightMargin, float bottomMargin) {
FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams(getSize(width), getSize(height), gravity); FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams(getSize(width), getSize(height), gravity);
layoutParams.setMargins(AndroidUtilities.dp(leftMargin), AndroidUtilities.dp(topMargin), AndroidUtilities.dp(rightMargin), AndroidUtilities.dp(bottomMargin)); layoutParams.setMargins(AndroidUtilities.dp(leftMargin), AndroidUtilities.dp(topMargin), AndroidUtilities.dp(rightMargin), AndroidUtilities.dp(bottomMargin));
@ -100,7 +105,7 @@ public class LayoutHelper {
return layoutParams; return layoutParams;
} }
public static LinearLayout.LayoutParams createLinear(int width, int height, int leftMargin, int topMargin, int rightMargin, int bottomMargin) { public static LinearLayout.LayoutParams createLinear(int width, int height, float leftMargin, float topMargin, float rightMargin, float bottomMargin) {
LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(getSize(width), getSize(height)); LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(getSize(width), getSize(height));
layoutParams.setMargins(AndroidUtilities.dp(leftMargin), AndroidUtilities.dp(topMargin), AndroidUtilities.dp(rightMargin), AndroidUtilities.dp(bottomMargin)); layoutParams.setMargins(AndroidUtilities.dp(leftMargin), AndroidUtilities.dp(topMargin), AndroidUtilities.dp(rightMargin), AndroidUtilities.dp(bottomMargin));
return layoutParams; return layoutParams;

View File

@ -47,23 +47,13 @@ public class PickerBottomLayout extends FrameLayout {
cancelButton.setPadding(AndroidUtilities.dp(29), 0, AndroidUtilities.dp(29), 0); cancelButton.setPadding(AndroidUtilities.dp(29), 0, AndroidUtilities.dp(29), 0);
cancelButton.setText(LocaleController.getString("Cancel", R.string.Cancel).toUpperCase()); cancelButton.setText(LocaleController.getString("Cancel", R.string.Cancel).toUpperCase());
cancelButton.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); cancelButton.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf"));
addView(cancelButton); addView(cancelButton, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.MATCH_PARENT, Gravity.TOP | Gravity.LEFT));
LayoutParams layoutParams = (LayoutParams) cancelButton.getLayoutParams();
layoutParams.width = LayoutHelper.WRAP_CONTENT;
layoutParams.height = LayoutHelper.MATCH_PARENT;
layoutParams.gravity = Gravity.TOP | Gravity.LEFT;
cancelButton.setLayoutParams(layoutParams);
doneButton = new LinearLayout(context); doneButton = new LinearLayout(context);
doneButton.setOrientation(LinearLayout.HORIZONTAL); doneButton.setOrientation(LinearLayout.HORIZONTAL);
doneButton.setBackgroundResource(isDarkTheme ? R.drawable.bar_selector_picker : R.drawable.bar_selector_audio); doneButton.setBackgroundResource(isDarkTheme ? R.drawable.bar_selector_picker : R.drawable.bar_selector_audio);
doneButton.setPadding(AndroidUtilities.dp(29), 0, AndroidUtilities.dp(29), 0); doneButton.setPadding(AndroidUtilities.dp(29), 0, AndroidUtilities.dp(29), 0);
addView(doneButton); addView(doneButton, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.MATCH_PARENT, Gravity.TOP | Gravity.RIGHT));
layoutParams = (LayoutParams) doneButton.getLayoutParams();
layoutParams.width = LayoutHelper.WRAP_CONTENT;
layoutParams.height = LayoutHelper.MATCH_PARENT;
layoutParams.gravity = Gravity.TOP | Gravity.RIGHT;
doneButton.setLayoutParams(layoutParams);
doneButtonBadgeTextView = new TextView(context); doneButtonBadgeTextView = new TextView(context);
doneButtonBadgeTextView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); doneButtonBadgeTextView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf"));
@ -73,13 +63,7 @@ public class PickerBottomLayout extends FrameLayout {
doneButtonBadgeTextView.setBackgroundResource(isDarkTheme ? R.drawable.photobadge : R.drawable.bluecounter); doneButtonBadgeTextView.setBackgroundResource(isDarkTheme ? R.drawable.photobadge : R.drawable.bluecounter);
doneButtonBadgeTextView.setMinWidth(AndroidUtilities.dp(23)); doneButtonBadgeTextView.setMinWidth(AndroidUtilities.dp(23));
doneButtonBadgeTextView.setPadding(AndroidUtilities.dp(8), 0, AndroidUtilities.dp(8), AndroidUtilities.dp(1)); doneButtonBadgeTextView.setPadding(AndroidUtilities.dp(8), 0, AndroidUtilities.dp(8), AndroidUtilities.dp(1));
doneButton.addView(doneButtonBadgeTextView); doneButton.addView(doneButtonBadgeTextView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, 23, Gravity.CENTER_VERTICAL, 0, 0, 10, 0));
LinearLayout.LayoutParams layoutParams1 = (LinearLayout.LayoutParams) doneButtonBadgeTextView.getLayoutParams();
layoutParams1.width = LayoutHelper.WRAP_CONTENT;
layoutParams1.height = AndroidUtilities.dp(23);
layoutParams1.rightMargin = AndroidUtilities.dp(10);
layoutParams1.gravity = Gravity.CENTER_VERTICAL;
doneButtonBadgeTextView.setLayoutParams(layoutParams1);
doneButtonTextView = new TextView(context); doneButtonTextView = new TextView(context);
doneButtonTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); doneButtonTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14);
@ -88,12 +72,7 @@ public class PickerBottomLayout extends FrameLayout {
doneButtonTextView.setCompoundDrawablePadding(AndroidUtilities.dp(8)); doneButtonTextView.setCompoundDrawablePadding(AndroidUtilities.dp(8));
doneButtonTextView.setText(LocaleController.getString("Send", R.string.Send).toUpperCase()); doneButtonTextView.setText(LocaleController.getString("Send", R.string.Send).toUpperCase());
doneButtonTextView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); doneButtonTextView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf"));
doneButton.addView(doneButtonTextView); doneButton.addView(doneButtonTextView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_VERTICAL));
layoutParams1 = (LinearLayout.LayoutParams) doneButtonTextView.getLayoutParams();
layoutParams1.width = LayoutHelper.WRAP_CONTENT;
layoutParams1.gravity = Gravity.CENTER_VERTICAL;
layoutParams1.height = LayoutHelper.WRAP_CONTENT;
doneButtonTextView.setLayoutParams(layoutParams1);
} }
public void updateSelectedCount(int count, boolean disable) { public void updateSelectedCount(int count, boolean disable) {

View File

@ -19,6 +19,8 @@ import android.view.View;
import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.AndroidUtilities;
import org.telegram.messenger.AnimationCompat.ObjectAnimatorProxy; import org.telegram.messenger.AnimationCompat.ObjectAnimatorProxy;
import org.telegram.messenger.FileLog;
import org.telegram.messenger.ImageLoader;
public class RadioButton extends View { public class RadioButton extends View {
@ -50,8 +52,15 @@ public class RadioButton extends View {
eraser.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR)); eraser.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
} }
bitmap = Bitmap.createBitmap(AndroidUtilities.dp(size), AndroidUtilities.dp(size), Bitmap.Config.ARGB_4444); try {
bitmapCanvas = new Canvas(bitmap); bitmap = Bitmap.createBitmap(AndroidUtilities.dp(size), AndroidUtilities.dp(size), Bitmap.Config.ARGB_4444);
if (ImageLoader.getInstance().runtimeHack != null) {
ImageLoader.getInstance().runtimeHack.trackFree(bitmap.getRowBytes() * bitmap.getHeight());
}
bitmapCanvas = new Canvas(bitmap);
} catch (Throwable e) {
FileLog.e("tmessages", e);
}
} }
public void setProgress(float value) { public void setProgress(float value) {
@ -86,7 +95,7 @@ public class RadioButton extends View {
private void animateToCheckedState(boolean newCheckedState) { private void animateToCheckedState(boolean newCheckedState) {
checkAnimator = ObjectAnimatorProxy.ofFloatProxy(this, "progress", newCheckedState ? 1 : 0); checkAnimator = ObjectAnimatorProxy.ofFloatProxy(this, "progress", newCheckedState ? 1 : 0);
checkAnimator.setDuration(300); checkAnimator.setDuration(200);
checkAnimator.start(); checkAnimator.start();
} }
@ -100,6 +109,11 @@ public class RadioButton extends View {
protected void onDetachedFromWindow() { protected void onDetachedFromWindow() {
super.onDetachedFromWindow(); super.onDetachedFromWindow();
attachedToWindow = false; attachedToWindow = false;
if (bitmap != null && ImageLoader.getInstance().runtimeHack != null) {
ImageLoader.getInstance().runtimeHack.trackAlloc(bitmap.getRowBytes() * bitmap.getHeight());
bitmap.recycle();
bitmap = null;
}
} }
public void setChecked(boolean checked, boolean animated) { public void setChecked(boolean checked, boolean animated) {
@ -124,10 +138,20 @@ public class RadioButton extends View {
protected void onDraw(Canvas canvas) { protected void onDraw(Canvas canvas) {
if (bitmap == null || bitmap.getWidth() != getMeasuredWidth()) { if (bitmap == null || bitmap.getWidth() != getMeasuredWidth()) {
if (bitmap != null) { if (bitmap != null) {
if (ImageLoader.getInstance().runtimeHack != null) {
ImageLoader.getInstance().runtimeHack.trackAlloc(bitmap.getRowBytes() * bitmap.getHeight());
}
bitmap.recycle(); bitmap.recycle();
} }
bitmap = Bitmap.createBitmap(getMeasuredWidth(), getMeasuredHeight(), Bitmap.Config.ARGB_8888); try {
bitmapCanvas = new Canvas(bitmap); bitmap = Bitmap.createBitmap(getMeasuredWidth(), getMeasuredHeight(), Bitmap.Config.ARGB_8888);
if (ImageLoader.getInstance().runtimeHack != null) {
ImageLoader.getInstance().runtimeHack.trackFree(bitmap.getRowBytes() * bitmap.getHeight());
}
bitmapCanvas = new Canvas(bitmap);
} catch (Throwable e) {
FileLog.e("tmessages", e);
}
} }
float circleProgress; float circleProgress;
float innerRad; float innerRad;
@ -147,16 +171,18 @@ public class RadioButton extends View {
paint.setColor(c); paint.setColor(c);
checkedPaint.setColor(c); checkedPaint.setColor(c);
} }
bitmap.eraseColor(0); if (bitmap != null) {
float rad = size / 2 - (1 + circleProgress) * AndroidUtilities.density; bitmap.eraseColor(0);
bitmapCanvas.drawCircle(getMeasuredWidth() / 2, getMeasuredHeight() / 2, rad, paint); float rad = size / 2 - (1 + circleProgress) * AndroidUtilities.density;
if (progress <= 0.5f) { bitmapCanvas.drawCircle(getMeasuredWidth() / 2, getMeasuredHeight() / 2, rad, paint);
bitmapCanvas.drawCircle(getMeasuredWidth() / 2, getMeasuredHeight() / 2, (rad - AndroidUtilities.dp(1)), checkedPaint); if (progress <= 0.5f) {
bitmapCanvas.drawCircle(getMeasuredWidth() / 2, getMeasuredHeight() / 2, (rad - AndroidUtilities.dp(1)) * (1.0f - circleProgress), eraser); bitmapCanvas.drawCircle(getMeasuredWidth() / 2, getMeasuredHeight() / 2, (rad - AndroidUtilities.dp(1)), checkedPaint);
} else { bitmapCanvas.drawCircle(getMeasuredWidth() / 2, getMeasuredHeight() / 2, (rad - AndroidUtilities.dp(1)) * (1.0f - circleProgress), eraser);
bitmapCanvas.drawCircle(getMeasuredWidth() / 2, getMeasuredHeight() / 2, size / 4 + (rad - AndroidUtilities.dp(1) - size / 4) * circleProgress, checkedPaint); } else {
} bitmapCanvas.drawCircle(getMeasuredWidth() / 2, getMeasuredHeight() / 2, size / 4 + (rad - AndroidUtilities.dp(1) - size / 4) * circleProgress, checkedPaint);
}
canvas.drawBitmap(bitmap, 0, 0, null); canvas.drawBitmap(bitmap, 0, 0, null);
}
} }
} }

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