- Base updated: v3.1.2
* Recent search results * Tap and hold sticker to preview before sending - Bug fixes
This commit is contained in:
parent
3bc33bf670
commit
2b3d852636
@ -82,8 +82,8 @@ android {
|
||||
applicationId "org.telegram.plus"
|
||||
minSdkVersion 8
|
||||
targetSdkVersion 22
|
||||
versionCode 590
|
||||
versionName "3.1.1.9"
|
||||
versionCode 592
|
||||
versionName "3.1.2.0"
|
||||
multiDexEnabled true
|
||||
}
|
||||
}
|
||||
|
@ -940,10 +940,14 @@ public class ContactsController {
|
||||
@Override
|
||||
public void run() {
|
||||
FileLog.e("tmessages", "done loading contacts");
|
||||
if (from == 1 && contactsArr.isEmpty()) {
|
||||
if (from == 1 && (contactsArr.isEmpty() || UserConfig.lastContactsSyncTime < (int) (System.currentTimeMillis() / 1000) - 24 * 60 * 60)) {
|
||||
loadContacts(false, true);
|
||||
return;
|
||||
}
|
||||
if (from == 0) {
|
||||
UserConfig.lastContactsSyncTime = (int) (System.currentTimeMillis() / 1000);
|
||||
UserConfig.saveConfig(false);
|
||||
}
|
||||
|
||||
for (TLRPC.TL_contact contact : contactsArr) {
|
||||
if (usersDict.get(contact.user_id) == null && contact.user_id != UserConfig.getClientUserId()) {
|
||||
@ -1809,18 +1813,14 @@ public class ContactsController {
|
||||
}
|
||||
|
||||
public static String formatName(String firstName, String lastName) {
|
||||
if ((firstName == null || firstName.length() == 0) && (lastName == null || lastName.length() == 0)) {
|
||||
/*if ((firstName == null || firstName.length() == 0) && (lastName == null || lastName.length() == 0)) {
|
||||
return LocaleController.getString("HiddenName", R.string.HiddenName);
|
||||
}
|
||||
}*/
|
||||
if (firstName != null) {
|
||||
firstName = firstName.trim();
|
||||
//firstName = firstName.replaceAll("[^\\x00-\\x7F]", "");
|
||||
//firstName = firstName.trim().replaceAll(" +", " ");
|
||||
}
|
||||
if (lastName != null) {
|
||||
lastName = lastName.trim();
|
||||
//lastName = lastName.replaceAll("[^\\x00-\\x7F]", "");
|
||||
//lastName = lastName.trim().replaceAll(" +", " ");
|
||||
}
|
||||
StringBuilder result = new StringBuilder((firstName != null ? firstName.length() : 0) + (lastName != null ? lastName.length() : 0) + 1);
|
||||
if (LocaleController.nameDisplayOrder == 1) {
|
||||
|
@ -61,8 +61,6 @@ public class Emoji {
|
||||
};
|
||||
|
||||
public static long[][] data = {
|
||||
new long[]
|
||||
{},
|
||||
new long[]//189
|
||||
{
|
||||
0x00000000D83DDE04L, 0x00000000D83DDE03L, 0x00000000D83DDE00L, 0x00000000D83DDE0AL, 0x000000000000263AL, 0x00000000D83DDE09L, 0x00000000D83DDE0DL,
|
||||
@ -215,10 +213,10 @@ public class Emoji {
|
||||
bigImgSize = AndroidUtilities.dp(32);
|
||||
}
|
||||
|
||||
for (int j = 1; j < data.length; j++) {
|
||||
for (int j = 0; j < data.length; j++) {
|
||||
for (int i = 0; i < data[j].length; i++) {
|
||||
Rect rect = new Rect((i % cols[j - 1]) * emojiFullSize, (i / cols[j - 1]) * emojiFullSize, (i % cols[j - 1] + 1) * emojiFullSize, (i / cols[j - 1] + 1) * emojiFullSize);
|
||||
rects.put(data[j][i], new DrawableInfo(rect, (byte) (j - 1)));
|
||||
Rect rect = new Rect((i % cols[j]) * emojiFullSize, (i / cols[j]) * emojiFullSize, (i % cols[j] + 1) * emojiFullSize, (i / cols[j] + 1) * emojiFullSize);
|
||||
rects.put(data[j][i], new DrawableInfo(rect, (byte) j));
|
||||
}
|
||||
}
|
||||
placeholderPaint = new Paint();
|
||||
|
@ -1206,30 +1206,11 @@ public class ImageLoader {
|
||||
telegramPath = new File(Environment.getExternalStorageDirectory(), "Telegram");
|
||||
telegramPath.mkdirs();
|
||||
|
||||
boolean canRename = false;
|
||||
|
||||
try {
|
||||
for (int a = 0; a < 5; a++) {
|
||||
File srcFile = new File(cachePath, "temp.file");
|
||||
srcFile.createNewFile();
|
||||
File dstFile = new File(telegramPath, "temp.file");
|
||||
canRename = srcFile.renameTo(dstFile);
|
||||
srcFile.delete();
|
||||
dstFile.delete();
|
||||
if (canRename) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
FileLog.e("tmessages", e);
|
||||
}
|
||||
|
||||
if (canRename) {
|
||||
if (telegramPath.isDirectory()) {
|
||||
try {
|
||||
File imagePath = new File(telegramPath, "Telegram Images");
|
||||
imagePath.mkdir();
|
||||
if (imagePath.isDirectory()) {
|
||||
if (imagePath.isDirectory() && canMoveFiles(cachePath, imagePath)) {
|
||||
mediaDirs.put(FileLoader.MEDIA_DIR_IMAGE, imagePath);
|
||||
FileLog.e("tmessages", "image path = " + imagePath);
|
||||
}
|
||||
@ -1240,7 +1221,7 @@ public class ImageLoader {
|
||||
try {
|
||||
File videoPath = new File(telegramPath, "Telegram Video");
|
||||
videoPath.mkdir();
|
||||
if (videoPath.isDirectory()) {
|
||||
if (videoPath.isDirectory() && canMoveFiles(cachePath, videoPath)) {
|
||||
mediaDirs.put(FileLoader.MEDIA_DIR_VIDEO, videoPath);
|
||||
FileLog.e("tmessages", "video path = " + videoPath);
|
||||
}
|
||||
@ -1251,7 +1232,7 @@ public class ImageLoader {
|
||||
try {
|
||||
File audioPath = new File(telegramPath, "Telegram Audio");
|
||||
audioPath.mkdir();
|
||||
if (audioPath.isDirectory()) {
|
||||
if (audioPath.isDirectory() && canMoveFiles(cachePath, audioPath)) {
|
||||
new File(audioPath, ".nomedia").createNewFile();
|
||||
mediaDirs.put(FileLoader.MEDIA_DIR_AUDIO, audioPath);
|
||||
FileLog.e("tmessages", "audio path = " + audioPath);
|
||||
@ -1263,7 +1244,7 @@ public class ImageLoader {
|
||||
try {
|
||||
File documentPath = new File(telegramPath, "Telegram Documents");
|
||||
documentPath.mkdir();
|
||||
if (documentPath.isDirectory()) {
|
||||
if (documentPath.isDirectory() && canMoveFiles(cachePath, documentPath)) {
|
||||
new File(documentPath, ".nomedia").createNewFile();
|
||||
mediaDirs.put(FileLoader.MEDIA_DIR_DOCUMENT, documentPath);
|
||||
FileLog.e("tmessages", "documents path = " + documentPath);
|
||||
@ -1275,7 +1256,7 @@ public class ImageLoader {
|
||||
try {
|
||||
File themesPath = new File(telegramPath, "Themes");
|
||||
themesPath.mkdir();
|
||||
if (themesPath.isDirectory()) {
|
||||
if (themesPath.isDirectory() && canMoveFiles(cachePath, themesPath)) {
|
||||
new File(themesPath, ".nomedia").createNewFile();
|
||||
mediaDirs.put(FileLoader.MEDIA_DIR_THEME, themesPath);
|
||||
FileLog.e("tmessages", "themes path = " + themesPath);
|
||||
@ -1288,7 +1269,6 @@ public class ImageLoader {
|
||||
} else {
|
||||
FileLog.e("tmessages", "this Android can't rename files");
|
||||
}
|
||||
}
|
||||
MediaController.getInstance().checkSaveToGalleryFiles();
|
||||
} catch (Exception e) {
|
||||
FileLog.e("tmessages", e);
|
||||
@ -1297,6 +1277,38 @@ public class ImageLoader {
|
||||
return mediaDirs;
|
||||
}
|
||||
|
||||
private boolean canMoveFiles(File from, File to) {
|
||||
RandomAccessFile file = null;
|
||||
try {
|
||||
for (int a = 0; a < 5; a++) {
|
||||
File srcFile = new File(from, "temp.file");
|
||||
srcFile.createNewFile();
|
||||
file = new RandomAccessFile(srcFile, "rws");
|
||||
file.write(1);
|
||||
file.close();
|
||||
file = null;
|
||||
File dstFile = new File(to, "temp.file");
|
||||
boolean canRename = srcFile.renameTo(dstFile);
|
||||
srcFile.delete();
|
||||
dstFile.delete();
|
||||
if (canRename) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
FileLog.e("tmessages", e);
|
||||
} finally {
|
||||
try {
|
||||
if (file != null) {
|
||||
file.close();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
FileLog.e("tmessages", e);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public Float getFileProgress(String location) {
|
||||
if (location == null) {
|
||||
return null;
|
||||
|
@ -1449,6 +1449,9 @@ public class MediaController implements NotificationCenter.NotificationCenterDel
|
||||
}
|
||||
|
||||
private void buildShuffledPlayList() {
|
||||
if (playlist.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
ArrayList<MessageObject> all = new ArrayList<>(playlist);
|
||||
shuffledPlaylist.clear();
|
||||
|
||||
@ -2496,7 +2499,7 @@ public class MediaController implements NotificationCenter.NotificationCenterDel
|
||||
albumEntry.addPhoto(photoEntry);
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
} catch (Throwable e) {
|
||||
FileLog.e("tmessages", e);
|
||||
} finally {
|
||||
if (cursor != null) {
|
||||
@ -2555,7 +2558,7 @@ public class MediaController implements NotificationCenter.NotificationCenterDel
|
||||
albumEntry.addPhoto(photoEntry);
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
} catch (Throwable e) {
|
||||
FileLog.e("tmessages", e);
|
||||
} finally {
|
||||
if (cursor != null) {
|
||||
|
@ -131,6 +131,8 @@ public class MessagesStorage {
|
||||
|
||||
database.executeFast("CREATE TABLE sent_files_v2(uid TEXT, type INTEGER, data BLOB, PRIMARY KEY (uid, type))").stepThis().dispose();
|
||||
|
||||
database.executeFast("CREATE TABLE search_recent(did INTEGER PRIMARY KEY, date INTEGER);").stepThis().dispose();
|
||||
|
||||
//database.executeFast("CREATE TABLE messages_holes(uid INTEGER, start INTEGER, end INTEGER, PRIMARY KEY(uid, start));").stepThis().dispose();
|
||||
//database.executeFast("CREATE INDEX IF NOT EXISTS type_uid_end_messages_holes ON messages_holes(uid, end);").stepThis().dispose();
|
||||
//database.executeFast("CREATE TABLE secret_holes(uid INTEGER, seq_in INTEGER, seq_out INTEGER, data BLOB, PRIMARY KEY (uid, seq_in, seq_out));").stepThis().dispose();
|
||||
@ -170,7 +172,7 @@ public class MessagesStorage {
|
||||
database.executeFast("CREATE INDEX IF NOT EXISTS bot_keyboard_idx_mid ON bot_keyboard(mid);").stepThis().dispose();
|
||||
|
||||
//version
|
||||
database.executeFast("PRAGMA user_version = 20").stepThis().dispose();
|
||||
database.executeFast("PRAGMA user_version = 21").stepThis().dispose();
|
||||
} else {
|
||||
try {
|
||||
SQLiteCursor cursor = database.queryFinalized("SELECT seq, pts, date, qts, lsv, sg, pbytes FROM params WHERE id = 1");
|
||||
@ -201,7 +203,7 @@ public class MessagesStorage {
|
||||
}
|
||||
}
|
||||
int version = database.executeInt("PRAGMA user_version");
|
||||
if (version < 20) {
|
||||
if (version < 21) {
|
||||
updateDbToLastVersion(version);
|
||||
}
|
||||
}
|
||||
@ -410,7 +412,12 @@ public class MessagesStorage {
|
||||
database.executeFast("CREATE TABLE IF NOT EXISTS bot_keyboard(uid INTEGER PRIMARY KEY, mid INTEGER, info BLOB)").stepThis().dispose();
|
||||
database.executeFast("CREATE INDEX IF NOT EXISTS bot_keyboard_idx_mid ON bot_keyboard(mid);").stepThis().dispose();
|
||||
database.executeFast("PRAGMA user_version = 20").stepThis().dispose();
|
||||
//version = 20;
|
||||
version = 20;
|
||||
}
|
||||
if (version == 20) {
|
||||
database.executeFast("CREATE TABLE search_recent(did INTEGER PRIMARY KEY, date INTEGER);").stepThis().dispose();
|
||||
database.executeFast("PRAGMA user_version = 21").stepThis().dispose();
|
||||
//version = 21;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
FileLog.e("tmessages", e);
|
||||
@ -887,6 +894,7 @@ public class MessagesStorage {
|
||||
if (!messagesOnly) {
|
||||
database.executeFast("DELETE FROM dialogs WHERE did = " + did).stepThis().dispose();
|
||||
database.executeFast("DELETE FROM chat_settings WHERE uid = " + did).stepThis().dispose();
|
||||
database.executeFast("DELETE FROM search_recent WHERE did = " + did).stepThis().dispose();
|
||||
int lower_id = (int)did;
|
||||
int high_id = (int)(did >> 32);
|
||||
if (lower_id != 0) {
|
||||
@ -2100,11 +2108,19 @@ public class MessagesStorage {
|
||||
storageQueue.postRunnable(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
database.commitTransaction();
|
||||
} catch (Exception e) {
|
||||
FileLog.e("tmessages", e);
|
||||
}
|
||||
}
|
||||
});
|
||||
} else {
|
||||
try {
|
||||
database.commitTransaction();
|
||||
} catch (Exception e) {
|
||||
FileLog.e("tmessages", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -2745,6 +2761,7 @@ public class MessagesStorage {
|
||||
database.beginTransaction();
|
||||
|
||||
SQLitePreparedStatement state = database.executeFast("UPDATE messages SET data = ? WHERE mid = ?");
|
||||
SQLitePreparedStatement state2 = database.executeFast("UPDATE media_v2 SET data = ? WHERE mid = ?");
|
||||
for (TLRPC.Message message : messages) {
|
||||
ByteBufferDesc data = buffersStorage.getFreeBuffer(message.getObjectSize());
|
||||
message.serializeToStream(data);
|
||||
@ -2754,9 +2771,15 @@ public class MessagesStorage {
|
||||
state.bindInteger(2, message.id);
|
||||
state.step();
|
||||
|
||||
state2.requery();
|
||||
state2.bindByteBuffer(1, data.buffer);
|
||||
state2.bindInteger(2, message.id);
|
||||
state2.step();
|
||||
|
||||
buffersStorage.reuseFreeBuffer(data);
|
||||
}
|
||||
state.dispose();
|
||||
state2.dispose();
|
||||
|
||||
database.commitTransaction();
|
||||
|
||||
|
@ -32,6 +32,7 @@ public class SharedMediaQuery {
|
||||
public final static int MEDIA_PHOTOVIDEO = 0;
|
||||
public final static int MEDIA_FILE = 1;
|
||||
public final static int MEDIA_AUDIO = 2;
|
||||
public final static int MEDIA_URL = 3;
|
||||
|
||||
public static void loadMedia(final long uid, final int offset, final int count, final int max_id, final int type, final boolean fromCache, final int classGuid) {
|
||||
int lower_part = (int)uid;
|
||||
@ -48,6 +49,8 @@ public class SharedMediaQuery {
|
||||
req.filter = new TLRPC.TL_inputMessagesFilterDocument();
|
||||
} else if (type == MEDIA_AUDIO) {
|
||||
req.filter = new TLRPC.TL_inputMessagesFilterAudio();
|
||||
} else if (type == MEDIA_URL) {
|
||||
req.filter = new TLRPC.TL_inputMessagesFilterUrl();
|
||||
}
|
||||
req.q = "";
|
||||
if (uid < 0) {
|
||||
@ -94,6 +97,8 @@ public class SharedMediaQuery {
|
||||
req.filter = new TLRPC.TL_inputMessagesFilterDocument();
|
||||
} else if (type == MEDIA_AUDIO) {
|
||||
req.filter = new TLRPC.TL_inputMessagesFilterAudio();
|
||||
} else if (type == MEDIA_URL) {
|
||||
req.filter = new TLRPC.TL_inputMessagesFilterUrl();
|
||||
}
|
||||
req.q = "";
|
||||
if (uid < 0) {
|
||||
@ -144,15 +149,17 @@ public class SharedMediaQuery {
|
||||
return -1;
|
||||
}
|
||||
if (message.media instanceof TLRPC.TL_messageMediaPhoto || message.media instanceof TLRPC.TL_messageMediaVideo) {
|
||||
return SharedMediaQuery.MEDIA_PHOTOVIDEO;
|
||||
return MEDIA_PHOTOVIDEO;
|
||||
} else if (message.media instanceof TLRPC.TL_messageMediaDocument) {
|
||||
if (MessageObject.isStickerMessage(message)) {
|
||||
return -1;
|
||||
} else {
|
||||
return SharedMediaQuery.MEDIA_FILE;
|
||||
return MEDIA_FILE;
|
||||
}
|
||||
} else if (message.media instanceof TLRPC.TL_messageMediaAudio) {
|
||||
return SharedMediaQuery.MEDIA_AUDIO;
|
||||
return MEDIA_AUDIO;
|
||||
} else if (message.media instanceof TLRPC.TL_messageMediaWebPage) {
|
||||
return MEDIA_URL;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
@ -160,7 +167,11 @@ public class SharedMediaQuery {
|
||||
public static boolean canAddMessageToMedia(TLRPC.Message message) {
|
||||
if (message instanceof TLRPC.TL_message_secret && message.media instanceof TLRPC.TL_messageMediaPhoto && message.ttl != 0 && message.ttl <= 60) {
|
||||
return false;
|
||||
} else if (message.media instanceof TLRPC.TL_messageMediaPhoto || message.media instanceof TLRPC.TL_messageMediaVideo || message.media instanceof TLRPC.TL_messageMediaDocument || message.media instanceof TLRPC.TL_messageMediaAudio) {
|
||||
} else if (message.media instanceof TLRPC.TL_messageMediaPhoto ||
|
||||
message.media instanceof TLRPC.TL_messageMediaVideo ||
|
||||
message.media instanceof TLRPC.TL_messageMediaDocument ||
|
||||
message.media instanceof TLRPC.TL_messageMediaAudio/* ||
|
||||
message.media instanceof TLRPC.TL_messageMediaWebPage && !(message.media.webpage instanceof TLRPC.TL_webPageEmpty)*/) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
@ -110,8 +110,9 @@ public class StickersQuery {
|
||||
ArrayList<TLRPC.TL_messages_stickerSet> newStickerArray = null;
|
||||
int date = 0;
|
||||
String hash = null;
|
||||
SQLiteCursor cursor = null;
|
||||
try {
|
||||
SQLiteCursor cursor = MessagesStorage.getInstance().getDatabase().queryFinalized("SELECT data, date, hash FROM stickers_v2 WHERE 1");
|
||||
cursor = MessagesStorage.getInstance().getDatabase().queryFinalized("SELECT data, date, hash FROM stickers_v2 WHERE 1");
|
||||
if (cursor.next()) {
|
||||
ByteBufferDesc data = MessagesStorage.getInstance().getBuffersStorage().getFreeBuffer(cursor.byteArrayLength(0));
|
||||
if (data != null && cursor.byteBufferValue(0, data.buffer) != 0) {
|
||||
@ -128,9 +129,12 @@ public class StickersQuery {
|
||||
hash = cursor.stringValue(2);
|
||||
MessagesStorage.getInstance().getBuffersStorage().reuseFreeBuffer(data);
|
||||
}
|
||||
cursor.dispose();
|
||||
} catch (Exception e) {
|
||||
} catch (Throwable e) {
|
||||
FileLog.e("tmessages", e);
|
||||
} finally {
|
||||
if (cursor != null) {
|
||||
cursor.dispose();
|
||||
}
|
||||
}
|
||||
processLoadedStickers(newStickerArray, true, date, hash);
|
||||
}
|
||||
@ -229,7 +233,7 @@ public class StickersQuery {
|
||||
});
|
||||
}
|
||||
|
||||
private static long getStickerSetId(TLRPC.Document document) {
|
||||
public static long getStickerSetId(TLRPC.Document document) {
|
||||
for (TLRPC.DocumentAttribute attribute : document.attributes) {
|
||||
if (attribute instanceof TLRPC.TL_documentAttributeSticker) {
|
||||
if (attribute.stickerset instanceof TLRPC.TL_inputStickerSetID) {
|
||||
|
@ -28,43 +28,43 @@ public interface Cache {
|
||||
* @param key Cache key
|
||||
* @return An {@link Entry} or null in the event of a cache miss
|
||||
*/
|
||||
Entry get(String key);
|
||||
public Entry get(String key);
|
||||
|
||||
/**
|
||||
* Adds or replaces an entry to the cache.
|
||||
* @param key Cache key
|
||||
* @param entry Data to store and metadata for cache coherency, TTL, etc.
|
||||
*/
|
||||
void put(String key, Entry entry);
|
||||
public void put(String key, Entry entry);
|
||||
|
||||
/**
|
||||
* Performs any potentially long-running actions needed to initialize the cache;
|
||||
* will be called from a worker thread.
|
||||
*/
|
||||
void initialize();
|
||||
public void initialize();
|
||||
|
||||
/**
|
||||
* Invalidates an entry in the cache.
|
||||
* @param key Cache key
|
||||
* @param fullExpire True to fully expire the entry, false to soft expire
|
||||
*/
|
||||
void invalidate(String key, boolean fullExpire);
|
||||
public void invalidate(String key, boolean fullExpire);
|
||||
|
||||
/**
|
||||
* Removes an entry from the cache.
|
||||
* @param key Cache key
|
||||
*/
|
||||
void remove(String key);
|
||||
public void remove(String key);
|
||||
|
||||
/**
|
||||
* Empties the cache.
|
||||
*/
|
||||
void clear();
|
||||
public void clear();
|
||||
|
||||
/**
|
||||
* Data and metadata for an entry returned by the cache.
|
||||
*/
|
||||
class Entry {
|
||||
public static class Entry {
|
||||
/** The data returned from cache. */
|
||||
public byte[] data;
|
||||
|
||||
@ -74,6 +74,9 @@ public interface Cache {
|
||||
/** Date of this response as reported by the server. */
|
||||
public long serverDate;
|
||||
|
||||
/** The last modified date for the requested object. */
|
||||
public long lastModified;
|
||||
|
||||
/** TTL for this record. */
|
||||
public long ttl;
|
||||
|
||||
|
@ -151,6 +151,7 @@ public class CacheDispatcher extends Thread {
|
||||
if (mQuit) {
|
||||
return;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -26,5 +26,5 @@ public interface Network {
|
||||
* @return A {@link NetworkResponse} with data and caching metadata; will never be null
|
||||
* @throws VolleyError on errors
|
||||
*/
|
||||
NetworkResponse performRequest(Request<?> request) throws VolleyError;
|
||||
public NetworkResponse performRequest(Request<?> request) throws VolleyError;
|
||||
}
|
||||
|
@ -28,9 +28,9 @@ import java.util.concurrent.BlockingQueue;
|
||||
* Provides a thread for performing network dispatch from a queue of requests.
|
||||
*
|
||||
* Requests added to the specified queue are processed from the network via a
|
||||
* specified {@link org.telegram.android.volley.Network} interface. Responses are committed to cache, if
|
||||
* eligible, using a specified {@link org.telegram.android.volley.Cache} interface. Valid responses and
|
||||
* errors are posted back to the caller via a {@link org.telegram.android.volley.ResponseDelivery}.
|
||||
* specified {@link Network} interface. Responses are committed to cache, if
|
||||
* eligible, using a specified {@link Cache} interface. Valid responses and
|
||||
* errors are posted back to the caller via a {@link ResponseDelivery}.
|
||||
*/
|
||||
public class NetworkDispatcher extends Thread {
|
||||
/** The queue of requests to service. */
|
||||
|
@ -22,7 +22,7 @@ import java.util.Collections;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Data and headers returned from {@link org.telegram.android.volley.Network#performRequest(org.telegram.android.volley.Request)}.
|
||||
* Data and headers returned from {@link Network#performRequest(Request)}.
|
||||
*/
|
||||
public class NetworkResponse {
|
||||
/**
|
||||
|
@ -18,9 +18,13 @@ package org.telegram.android.volley;
|
||||
|
||||
import android.net.TrafficStats;
|
||||
import android.net.Uri;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.os.SystemClock;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import org.telegram.android.volley.VolleyLog.MarkerLog;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URLEncoder;
|
||||
import java.util.Collections;
|
||||
@ -53,6 +57,9 @@ public abstract class Request<T> implements Comparable<Request<T>> {
|
||||
int PATCH = 7;
|
||||
}
|
||||
|
||||
/** An event log tracing the lifetime of this request; for debugging. */
|
||||
private final MarkerLog mEventLog = MarkerLog.ENABLED ? new MarkerLog() : null;
|
||||
|
||||
/**
|
||||
* Request method of this request. Currently supports GET, POST, PUT, DELETE, HEAD, OPTIONS,
|
||||
* TRACE, and PATCH.
|
||||
@ -83,12 +90,6 @@ public abstract class Request<T> implements Comparable<Request<T>> {
|
||||
/** Whether or not a response has been delivered for this request yet. */
|
||||
private boolean mResponseDelivered = false;
|
||||
|
||||
// A cheap variant of request tracing used to dump slow requests.
|
||||
private long mRequestBirthTime = 0;
|
||||
|
||||
/** Threshold at which we should log the request (even when debug logging is not enabled). */
|
||||
private static final long SLOW_REQUEST_THRESHOLD_MS = 3000;
|
||||
|
||||
/** The retry policy for this request. */
|
||||
private RetryPolicy mRetryPolicy;
|
||||
|
||||
@ -108,6 +109,7 @@ public abstract class Request<T> implements Comparable<Request<T>> {
|
||||
* is provided by subclasses, who have a better idea of how to deliver an
|
||||
* already-parsed response.
|
||||
*
|
||||
* @deprecated Use {@link #Request(int, String, com.android.volley.Response.ErrorListener)}.
|
||||
*/
|
||||
@Deprecated
|
||||
public Request(String url, Response.ErrorListener listener) {
|
||||
@ -155,6 +157,9 @@ public abstract class Request<T> implements Comparable<Request<T>> {
|
||||
return mTag;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return this request's {@link com.android.volley.Response.ErrorListener}.
|
||||
*/
|
||||
public Response.ErrorListener getErrorListener() {
|
||||
return mErrorListener;
|
||||
}
|
||||
@ -196,8 +201,8 @@ public abstract class Request<T> implements Comparable<Request<T>> {
|
||||
* Adds an event to this request's event log; for debugging.
|
||||
*/
|
||||
public void addMarker(String tag) {
|
||||
if (mRequestBirthTime == 0) {
|
||||
mRequestBirthTime = SystemClock.elapsedRealtime();
|
||||
if (MarkerLog.ENABLED) {
|
||||
mEventLog.add(tag, Thread.currentThread().getId());
|
||||
}
|
||||
}
|
||||
|
||||
@ -210,9 +215,24 @@ public abstract class Request<T> implements Comparable<Request<T>> {
|
||||
if (mRequestQueue != null) {
|
||||
mRequestQueue.finish(this);
|
||||
}
|
||||
long requestTime = SystemClock.elapsedRealtime() - mRequestBirthTime;
|
||||
if (requestTime >= SLOW_REQUEST_THRESHOLD_MS) {
|
||||
VolleyLog.d("%d ms: %s", requestTime, this.toString());
|
||||
if (MarkerLog.ENABLED) {
|
||||
final long threadId = Thread.currentThread().getId();
|
||||
if (Looper.myLooper() != Looper.getMainLooper()) {
|
||||
// If we finish marking off of the main thread, we need to
|
||||
// actually do it on the main thread to ensure correct ordering.
|
||||
Handler mainThread = new Handler(Looper.getMainLooper());
|
||||
mainThread.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
mEventLog.add(tag, threadId);
|
||||
mEventLog.finish(this.toString());
|
||||
}
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
mEventLog.add(tag, threadId);
|
||||
mEventLog.finish(this.toString());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -19,9 +19,11 @@ package org.telegram.android.volley;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Queue;
|
||||
import java.util.Set;
|
||||
@ -31,12 +33,18 @@ import java.util.concurrent.atomic.AtomicInteger;
|
||||
/**
|
||||
* A request dispatch queue with a thread pool of dispatchers.
|
||||
*
|
||||
* Calling {@link #add(org.telegram.android.volley.Request)} will enqueue the given Request for dispatch,
|
||||
* Calling {@link #add(Request)} will enqueue the given Request for dispatch,
|
||||
* resolving from either cache or network on a worker thread, and then delivering
|
||||
* a parsed response on the main thread.
|
||||
*/
|
||||
public class RequestQueue {
|
||||
|
||||
/** Callback interface for completed requests. */
|
||||
public static interface RequestFinishedListener<T> {
|
||||
/** Called when a request has finished processing. */
|
||||
public void onRequestFinished(Request<T> request);
|
||||
}
|
||||
|
||||
/** Used for generating monotonically-increasing sequence numbers for requests. */
|
||||
private AtomicInteger mSequenceGenerator = new AtomicInteger();
|
||||
|
||||
@ -86,6 +94,9 @@ public class RequestQueue {
|
||||
/** The cache dispatcher. */
|
||||
private CacheDispatcher mCacheDispatcher;
|
||||
|
||||
private List<RequestFinishedListener> mFinishedListeners =
|
||||
new ArrayList<RequestFinishedListener>();
|
||||
|
||||
/**
|
||||
* Creates the worker pool. Processing will not begin until {@link #start()} is called.
|
||||
*
|
||||
@ -149,9 +160,9 @@ public class RequestQueue {
|
||||
if (mCacheDispatcher != null) {
|
||||
mCacheDispatcher.quit();
|
||||
}
|
||||
for (NetworkDispatcher mDispatcher : mDispatchers) {
|
||||
if (mDispatcher != null) {
|
||||
mDispatcher.quit();
|
||||
for (int i = 0; i < mDispatchers.length; i++) {
|
||||
if (mDispatchers[i] != null) {
|
||||
mDispatchers[i].quit();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -175,7 +186,7 @@ public class RequestQueue {
|
||||
* {@link RequestQueue#cancelAll(RequestFilter)}.
|
||||
*/
|
||||
public interface RequestFilter {
|
||||
boolean apply(Request<?> request);
|
||||
public boolean apply(Request<?> request);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -261,11 +272,16 @@ public class RequestQueue {
|
||||
* <p>Releases waiting requests for <code>request.getCacheKey()</code> if
|
||||
* <code>request.shouldCache()</code>.</p>
|
||||
*/
|
||||
void finish(Request<?> request) {
|
||||
<T> void finish(Request<T> request) {
|
||||
// Remove from the set of requests currently being processed.
|
||||
synchronized (mCurrentRequests) {
|
||||
mCurrentRequests.remove(request);
|
||||
}
|
||||
synchronized (mFinishedListeners) {
|
||||
for (RequestFinishedListener<T> listener : mFinishedListeners) {
|
||||
listener.onRequestFinished(request);
|
||||
}
|
||||
}
|
||||
|
||||
if (request.shouldCache()) {
|
||||
synchronized (mWaitingRequests) {
|
||||
@ -283,4 +299,19 @@ public class RequestQueue {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public <T> void addRequestFinishedListener(RequestFinishedListener<T> listener) {
|
||||
synchronized (mFinishedListeners) {
|
||||
mFinishedListeners.add(listener);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a RequestFinishedListener. Has no effect if listener was not previously added.
|
||||
*/
|
||||
public <T> void removeRequestFinishedListener(RequestFinishedListener<T> listener) {
|
||||
synchronized (mFinishedListeners) {
|
||||
mFinishedListeners.remove(listener);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -26,7 +26,7 @@ public class Response<T> {
|
||||
/** Callback interface for delivering parsed responses. */
|
||||
public interface Listener<T> {
|
||||
/** Called when a response is received. */
|
||||
void onResponse(T response);
|
||||
public void onResponse(T response);
|
||||
}
|
||||
|
||||
/** Callback interface for delivering error responses. */
|
||||
@ -35,7 +35,7 @@ public class Response<T> {
|
||||
* Callback method that an error has been occurred with the
|
||||
* provided error code and optional user-readable message.
|
||||
*/
|
||||
void onErrorResponse(VolleyError error);
|
||||
public void onErrorResponse(VolleyError error);
|
||||
}
|
||||
|
||||
/** Returns a successful response containing the parsed result. */
|
||||
|
@ -20,16 +20,16 @@ public interface ResponseDelivery {
|
||||
/**
|
||||
* Parses a response from the network or cache and delivers it.
|
||||
*/
|
||||
void postResponse(Request<?> request, Response<?> response);
|
||||
public void postResponse(Request<?> request, Response<?> response);
|
||||
|
||||
/**
|
||||
* Parses a response from the network or cache and delivers it. The provided
|
||||
* Runnable will be executed after delivery.
|
||||
*/
|
||||
void postResponse(Request<?> request, Response<?> response, Runnable runnable);
|
||||
public void postResponse(Request<?> request, Response<?> response, Runnable runnable);
|
||||
|
||||
/**
|
||||
* Posts an error for the given request.
|
||||
*/
|
||||
void postError(Request<?> request, VolleyError error);
|
||||
public void postError(Request<?> request, VolleyError error);
|
||||
}
|
||||
|
@ -24,12 +24,12 @@ public interface RetryPolicy {
|
||||
/**
|
||||
* Returns the current timeout (used for logging).
|
||||
*/
|
||||
int getCurrentTimeout();
|
||||
public int getCurrentTimeout();
|
||||
|
||||
/**
|
||||
* Returns the current retry count (used for logging).
|
||||
*/
|
||||
int getCurrentRetryCount();
|
||||
public int getCurrentRetryCount();
|
||||
|
||||
/**
|
||||
* Prepares for the next retry by applying a backoff to the timeout.
|
||||
@ -37,5 +37,5 @@ public interface RetryPolicy {
|
||||
* @throws VolleyError In the event that the retry could not be performed (for example if we
|
||||
* ran out of attempts), the passed in error is thrown.
|
||||
*/
|
||||
void retry(VolleyError error) throws VolleyError;
|
||||
public void retry(VolleyError error) throws VolleyError;
|
||||
}
|
||||
|
@ -29,3 +29,4 @@ public class ServerError extends VolleyError {
|
||||
super();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -23,7 +23,12 @@ import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
/** Logging helper class. */
|
||||
/**
|
||||
* Logging helper class.
|
||||
* <p/>
|
||||
* to see Volley logs call:<br/>
|
||||
* {@code <android-sdk>/platform-tools/adb shell setprop log.tag.Volley VERBOSE}
|
||||
*/
|
||||
public class VolleyLog {
|
||||
public static String TAG = "Volley";
|
||||
|
||||
@ -89,7 +94,7 @@ public class VolleyLog {
|
||||
callingClass = callingClass.substring(callingClass.lastIndexOf('.') + 1);
|
||||
callingClass = callingClass.substring(callingClass.lastIndexOf('$') + 1);
|
||||
|
||||
caller = callingClass + "" + trace[i].getMethodName();
|
||||
caller = callingClass + "." + trace[i].getMethodName();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -16,6 +16,8 @@
|
||||
|
||||
package org.telegram.android.volley.toolbox;
|
||||
|
||||
import org.telegram.android.volley.AuthFailureError;
|
||||
|
||||
import android.accounts.Account;
|
||||
import android.accounts.AccountManager;
|
||||
import android.accounts.AccountManagerFuture;
|
||||
@ -23,14 +25,12 @@ import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
|
||||
import org.telegram.android.volley.AuthFailureError;
|
||||
|
||||
/**
|
||||
* An Authenticator that uses {@link AccountManager} to get auth
|
||||
* tokens of a specified type for a specified account.
|
||||
*/
|
||||
public class AndroidAuthenticator implements Authenticator {
|
||||
private final Context mContext;
|
||||
private final AccountManager mAccountManager;
|
||||
private final Account mAccount;
|
||||
private final String mAuthTokenType;
|
||||
private final boolean mNotifyAuthFailure;
|
||||
@ -54,7 +54,13 @@ public class AndroidAuthenticator implements Authenticator {
|
||||
*/
|
||||
public AndroidAuthenticator(Context context, Account account, String authTokenType,
|
||||
boolean notifyAuthFailure) {
|
||||
mContext = context;
|
||||
this(AccountManager.get(context), account, authTokenType, notifyAuthFailure);
|
||||
}
|
||||
|
||||
// Visible for testing. Allows injection of a mock AccountManager.
|
||||
AndroidAuthenticator(AccountManager accountManager, Account account,
|
||||
String authTokenType, boolean notifyAuthFailure) {
|
||||
mAccountManager = accountManager;
|
||||
mAccount = account;
|
||||
mAuthTokenType = authTokenType;
|
||||
mNotifyAuthFailure = notifyAuthFailure;
|
||||
@ -71,8 +77,7 @@ public class AndroidAuthenticator implements Authenticator {
|
||||
@SuppressWarnings("deprecation")
|
||||
@Override
|
||||
public String getAuthToken() throws AuthFailureError {
|
||||
final AccountManager accountManager = AccountManager.get(mContext);
|
||||
AccountManagerFuture<Bundle> future = accountManager.getAuthToken(mAccount,
|
||||
AccountManagerFuture<Bundle> future = mAccountManager.getAuthToken(mAccount,
|
||||
mAuthTokenType, mNotifyAuthFailure, null, null);
|
||||
Bundle result;
|
||||
try {
|
||||
@ -97,6 +102,6 @@ public class AndroidAuthenticator implements Authenticator {
|
||||
|
||||
@Override
|
||||
public void invalidateAuthToken(String authToken) {
|
||||
AccountManager.get(mContext).invalidateAuthToken(mAccount.type, authToken);
|
||||
mAccountManager.invalidateAuthToken(mAccount.type, authToken);
|
||||
}
|
||||
}
|
||||
|
@ -27,10 +27,10 @@ public interface Authenticator {
|
||||
*
|
||||
* @throws AuthFailureError If authentication did not succeed
|
||||
*/
|
||||
String getAuthToken() throws AuthFailureError;
|
||||
public String getAuthToken() throws AuthFailureError;
|
||||
|
||||
/**
|
||||
* Invalidates the provided auth token.
|
||||
*/
|
||||
void invalidateAuthToken(String authToken);
|
||||
public void invalidateAuthToken(String authToken);
|
||||
}
|
||||
|
@ -18,15 +18,9 @@ package org.telegram.android.volley.toolbox;
|
||||
|
||||
import android.os.SystemClock;
|
||||
|
||||
import org.apache.http.Header;
|
||||
import org.apache.http.HttpEntity;
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.apache.http.HttpStatus;
|
||||
import org.apache.http.StatusLine;
|
||||
import org.apache.http.conn.ConnectTimeoutException;
|
||||
import org.apache.http.impl.cookie.DateUtils;
|
||||
import org.telegram.android.volley.AuthFailureError;
|
||||
import org.telegram.android.volley.Cache;
|
||||
import org.telegram.android.volley.Cache.Entry;
|
||||
import org.telegram.android.volley.Network;
|
||||
import org.telegram.android.volley.NetworkError;
|
||||
import org.telegram.android.volley.NetworkResponse;
|
||||
@ -38,6 +32,14 @@ import org.telegram.android.volley.TimeoutError;
|
||||
import org.telegram.android.volley.VolleyError;
|
||||
import org.telegram.android.volley.VolleyLog;
|
||||
|
||||
import org.apache.http.Header;
|
||||
import org.apache.http.HttpEntity;
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.apache.http.HttpStatus;
|
||||
import org.apache.http.StatusLine;
|
||||
import org.apache.http.conn.ConnectTimeoutException;
|
||||
import org.apache.http.impl.cookie.DateUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.MalformedURLException;
|
||||
@ -49,14 +51,14 @@ import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
|
||||
/**
|
||||
* A network performing Volley requests over an {@link org.telegram.android.volley.toolbox.HttpStack}.
|
||||
* A network performing Volley requests over an {@link HttpStack}.
|
||||
*/
|
||||
public class BasicNetwork implements Network {
|
||||
protected static final boolean DEBUG = VolleyLog.DEBUG;
|
||||
|
||||
private static final int SLOW_REQUEST_THRESHOLD_MS = 3000;
|
||||
private static int SLOW_REQUEST_THRESHOLD_MS = 3000;
|
||||
|
||||
private static final int DEFAULT_POOL_SIZE = 4096;
|
||||
private static int DEFAULT_POOL_SIZE = 4096;
|
||||
|
||||
protected final HttpStack mHttpStack;
|
||||
|
||||
@ -99,7 +101,7 @@ public class BasicNetwork implements Network {
|
||||
// Handle cache validation.
|
||||
if (statusCode == HttpStatus.SC_NOT_MODIFIED) {
|
||||
|
||||
Cache.Entry entry = request.getCacheEntry();
|
||||
Entry entry = request.getCacheEntry();
|
||||
if (entry == null) {
|
||||
return new NetworkResponse(HttpStatus.SC_NOT_MODIFIED, null,
|
||||
responseHeaders, true,
|
||||
@ -210,8 +212,8 @@ public class BasicNetwork implements Network {
|
||||
headers.put("If-None-Match", entry.etag);
|
||||
}
|
||||
|
||||
if (entry.serverDate > 0) {
|
||||
Date refTime = new Date(entry.serverDate);
|
||||
if (entry.lastModified > 0) {
|
||||
Date refTime = new Date(entry.lastModified);
|
||||
headers.put("If-Modified-Since", DateUtils.formatDate(refTime));
|
||||
}
|
||||
}
|
||||
@ -256,8 +258,8 @@ public class BasicNetwork implements Network {
|
||||
*/
|
||||
protected static Map<String, String> convertHeaders(Header[] headers) {
|
||||
Map<String, String> result = new TreeMap<String, String>(String.CASE_INSENSITIVE_ORDER);
|
||||
for (Header header : headers) {
|
||||
result.put(header.getName(), header.getValue());
|
||||
for (int i = 0; i < headers.length; i++) {
|
||||
result.put(headers[i].getName(), headers[i].getValue());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
@ -16,14 +16,14 @@
|
||||
|
||||
package org.telegram.android.volley.toolbox;
|
||||
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
|
||||
import org.telegram.android.volley.Cache;
|
||||
import org.telegram.android.volley.NetworkResponse;
|
||||
import org.telegram.android.volley.Request;
|
||||
import org.telegram.android.volley.Response;
|
||||
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
|
||||
/**
|
||||
* A synthetic request used for clearing the cache.
|
||||
*/
|
||||
|
@ -22,6 +22,7 @@ import org.telegram.android.volley.Cache;
|
||||
import org.telegram.android.volley.VolleyLog;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.EOFException;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
@ -42,45 +43,30 @@ import java.util.Map;
|
||||
*/
|
||||
public class DiskBasedCache implements Cache {
|
||||
|
||||
/**
|
||||
* Map of the Key, CacheHeader pairs
|
||||
*/
|
||||
/** Map of the Key, CacheHeader pairs */
|
||||
private final Map<String, CacheHeader> mEntries =
|
||||
new LinkedHashMap<String, CacheHeader>(16, .75f, true);
|
||||
|
||||
/**
|
||||
* Total amount of space currently used by the cache in bytes.
|
||||
*/
|
||||
/** Total amount of space currently used by the cache in bytes. */
|
||||
private long mTotalSize = 0;
|
||||
|
||||
/**
|
||||
* The root directory to use for the cache.
|
||||
*/
|
||||
/** The root directory to use for the cache. */
|
||||
private final File mRootDirectory;
|
||||
|
||||
/**
|
||||
* The maximum size of the cache in bytes.
|
||||
*/
|
||||
/** The maximum size of the cache in bytes. */
|
||||
private final int mMaxCacheSizeInBytes;
|
||||
|
||||
/**
|
||||
* Default maximum disk usage in bytes.
|
||||
*/
|
||||
/** Default maximum disk usage in bytes. */
|
||||
private static final int DEFAULT_DISK_USAGE_BYTES = 5 * 1024 * 1024;
|
||||
|
||||
/**
|
||||
* High water mark percentage for the cache
|
||||
*/
|
||||
/** High water mark percentage for the cache */
|
||||
private static final float HYSTERESIS_FACTOR = 0.9f;
|
||||
|
||||
/**
|
||||
* Magic number for current version of cache file format.
|
||||
*/
|
||||
private static final int CACHE_MAGIC = 0x20140623;
|
||||
/** Magic number for current version of cache file format. */
|
||||
private static final int CACHE_MAGIC = 0x20150306;
|
||||
|
||||
/**
|
||||
* Constructs an instance of the DiskBasedCache at the specified directory.
|
||||
*
|
||||
* @param rootDirectory The root directory of the cache.
|
||||
* @param maxCacheSizeInBytes The maximum size of the cache in bytes.
|
||||
*/
|
||||
@ -92,7 +78,6 @@ public class DiskBasedCache implements Cache {
|
||||
/**
|
||||
* Constructs an instance of the DiskBasedCache at the specified directory using
|
||||
* the default maximum cache size of 5MB.
|
||||
*
|
||||
* @param rootDirectory The root directory of the cache.
|
||||
*/
|
||||
public DiskBasedCache(File rootDirectory) {
|
||||
@ -129,7 +114,7 @@ public class DiskBasedCache implements Cache {
|
||||
File file = getFileForKey(key);
|
||||
CountingInputStream cis = null;
|
||||
try {
|
||||
cis = new CountingInputStream(new FileInputStream(file));
|
||||
cis = new CountingInputStream(new BufferedInputStream(new FileInputStream(file)));
|
||||
CacheHeader.readHeader(cis); // eat header
|
||||
byte[] data = streamToBytes(cis, (int) (file.length() - cis.bytesRead));
|
||||
return entry.toCacheEntry(data);
|
||||
@ -181,15 +166,13 @@ public class DiskBasedCache implements Cache {
|
||||
if (fis != null) {
|
||||
fis.close();
|
||||
}
|
||||
} catch (IOException ignored) {
|
||||
}
|
||||
} catch (IOException ignored) { }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Invalidates an entry in the cache.
|
||||
*
|
||||
* @param key Cache key
|
||||
* @param fullExpire True to fully expire the entry, false to soft expire
|
||||
*/
|
||||
@ -214,7 +197,7 @@ public class DiskBasedCache implements Cache {
|
||||
pruneIfNeeded(entry.data.length);
|
||||
File file = getFileForKey(key);
|
||||
try {
|
||||
FileOutputStream fos = new FileOutputStream(file);
|
||||
BufferedOutputStream fos = new BufferedOutputStream(new FileOutputStream(file));
|
||||
CacheHeader e = new CacheHeader(key, entry);
|
||||
boolean success = e.writeHeader(fos);
|
||||
if (!success) {
|
||||
@ -227,7 +210,6 @@ public class DiskBasedCache implements Cache {
|
||||
putEntry(key, e);
|
||||
return;
|
||||
} catch (IOException e) {
|
||||
/**/
|
||||
}
|
||||
boolean deleted = file.delete();
|
||||
if (!deleted) {
|
||||
@ -250,7 +232,6 @@ public class DiskBasedCache implements Cache {
|
||||
|
||||
/**
|
||||
* Creates a pseudo-unique filename for the specified cache key.
|
||||
*
|
||||
* @param key The key to generate a file name for.
|
||||
* @return A pseudo-unique filename.
|
||||
*/
|
||||
@ -270,7 +251,6 @@ public class DiskBasedCache implements Cache {
|
||||
|
||||
/**
|
||||
* Prunes the cache to fit the amount of bytes specified.
|
||||
*
|
||||
* @param neededSpace The amount of bytes we are trying to fit into the cache.
|
||||
*/
|
||||
private void pruneIfNeeded(int neededSpace) {
|
||||
@ -312,7 +292,6 @@ public class DiskBasedCache implements Cache {
|
||||
|
||||
/**
|
||||
* Puts the entry with the specified key into the cache.
|
||||
*
|
||||
* @param key The key to identify the entry by.
|
||||
* @param entry The entry to cache.
|
||||
*/
|
||||
@ -339,7 +318,7 @@ public class DiskBasedCache implements Cache {
|
||||
|
||||
/**
|
||||
* Reads the contents of an InputStream into a byte[].
|
||||
*/
|
||||
* */
|
||||
private static byte[] streamToBytes(InputStream in, int length) throws IOException {
|
||||
byte[] bytes = new byte[length];
|
||||
int count;
|
||||
@ -358,48 +337,35 @@ public class DiskBasedCache implements Cache {
|
||||
*/
|
||||
// Visible for testing.
|
||||
static class CacheHeader {
|
||||
/**
|
||||
* The size of the data identified by this CacheHeader. (This is not
|
||||
* serialized to disk.
|
||||
*/
|
||||
/** The size of the data identified by this CacheHeader. (This is not
|
||||
* serialized to disk. */
|
||||
public long size;
|
||||
|
||||
/**
|
||||
* The key that identifies the cache entry.
|
||||
*/
|
||||
/** The key that identifies the cache entry. */
|
||||
public String key;
|
||||
|
||||
/**
|
||||
* ETag for cache coherence.
|
||||
*/
|
||||
/** ETag for cache coherence. */
|
||||
public String etag;
|
||||
|
||||
/**
|
||||
* Date of this response as reported by the server.
|
||||
*/
|
||||
/** Date of this response as reported by the server. */
|
||||
public long serverDate;
|
||||
|
||||
/**
|
||||
* TTL for this record.
|
||||
*/
|
||||
/** The last modified date for the requested object. */
|
||||
public long lastModified;
|
||||
|
||||
/** TTL for this record. */
|
||||
public long ttl;
|
||||
|
||||
/**
|
||||
* Soft TTL for this record.
|
||||
*/
|
||||
/** Soft TTL for this record. */
|
||||
public long softTtl;
|
||||
|
||||
/**
|
||||
* Headers from the response resulting in this cache entry.
|
||||
*/
|
||||
/** Headers from the response resulting in this cache entry. */
|
||||
public Map<String, String> responseHeaders;
|
||||
|
||||
private CacheHeader() {
|
||||
}
|
||||
private CacheHeader() { }
|
||||
|
||||
/**
|
||||
* Instantiates a new CacheHeader object
|
||||
*
|
||||
* @param key The key that identifies the cache entry
|
||||
* @param entry The cache entry.
|
||||
*/
|
||||
@ -408,6 +374,7 @@ public class DiskBasedCache implements Cache {
|
||||
this.size = entry.data.length;
|
||||
this.etag = entry.etag;
|
||||
this.serverDate = entry.serverDate;
|
||||
this.lastModified = entry.lastModified;
|
||||
this.ttl = entry.ttl;
|
||||
this.softTtl = entry.softTtl;
|
||||
this.responseHeaders = entry.responseHeaders;
|
||||
@ -415,7 +382,6 @@ public class DiskBasedCache implements Cache {
|
||||
|
||||
/**
|
||||
* Reads the header off of an InputStream and returns a CacheHeader object.
|
||||
*
|
||||
* @param is The InputStream to read from.
|
||||
* @throws IOException
|
||||
*/
|
||||
@ -432,9 +398,11 @@ public class DiskBasedCache implements Cache {
|
||||
entry.etag = null;
|
||||
}
|
||||
entry.serverDate = readLong(is);
|
||||
entry.lastModified = readLong(is);
|
||||
entry.ttl = readLong(is);
|
||||
entry.softTtl = readLong(is);
|
||||
entry.responseHeaders = readStringStringMap(is);
|
||||
|
||||
return entry;
|
||||
}
|
||||
|
||||
@ -446,6 +414,7 @@ public class DiskBasedCache implements Cache {
|
||||
e.data = data;
|
||||
e.etag = etag;
|
||||
e.serverDate = serverDate;
|
||||
e.lastModified = lastModified;
|
||||
e.ttl = ttl;
|
||||
e.softTtl = softTtl;
|
||||
e.responseHeaders = responseHeaders;
|
||||
@ -462,6 +431,7 @@ public class DiskBasedCache implements Cache {
|
||||
writeString(os, key);
|
||||
writeString(os, etag == null ? "" : etag);
|
||||
writeLong(os, serverDate);
|
||||
writeLong(os, lastModified);
|
||||
writeLong(os, ttl);
|
||||
writeLong(os, softTtl);
|
||||
writeStringStringMap(responseHeaders, os);
|
||||
@ -537,14 +507,14 @@ public class DiskBasedCache implements Cache {
|
||||
}
|
||||
|
||||
static void writeLong(OutputStream os, long n) throws IOException {
|
||||
os.write((byte) (n >>> 0));
|
||||
os.write((byte) (n >>> 8));
|
||||
os.write((byte) (n >>> 16));
|
||||
os.write((byte) (n >>> 24));
|
||||
os.write((byte) (n >>> 32));
|
||||
os.write((byte) (n >>> 40));
|
||||
os.write((byte) (n >>> 48));
|
||||
os.write((byte) (n >>> 56));
|
||||
os.write((byte)(n >>> 0));
|
||||
os.write((byte)(n >>> 8));
|
||||
os.write((byte)(n >>> 16));
|
||||
os.write((byte)(n >>> 24));
|
||||
os.write((byte)(n >>> 32));
|
||||
os.write((byte)(n >>> 40));
|
||||
os.write((byte)(n >>> 48));
|
||||
os.write((byte)(n >>> 56));
|
||||
}
|
||||
|
||||
static long readLong(InputStream is) throws IOException {
|
||||
@ -596,4 +566,6 @@ public class DiskBasedCache implements Cache {
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -16,6 +16,10 @@
|
||||
|
||||
package org.telegram.android.volley.toolbox;
|
||||
|
||||
import org.telegram.android.volley.AuthFailureError;
|
||||
import org.telegram.android.volley.Request;
|
||||
import org.telegram.android.volley.Request.Method;
|
||||
|
||||
import org.apache.http.HttpEntity;
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.apache.http.NameValuePair;
|
||||
@ -33,8 +37,6 @@ import org.apache.http.entity.ByteArrayEntity;
|
||||
import org.apache.http.message.BasicNameValuePair;
|
||||
import org.apache.http.params.HttpConnectionParams;
|
||||
import org.apache.http.params.HttpParams;
|
||||
import org.telegram.android.volley.AuthFailureError;
|
||||
import org.telegram.android.volley.Request;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
@ -92,7 +94,7 @@ public class HttpClientStack implements HttpStack {
|
||||
/* protected */ static HttpUriRequest createHttpRequest(Request<?> request,
|
||||
Map<String, String> additionalHeaders) throws AuthFailureError {
|
||||
switch (request.getMethod()) {
|
||||
case Request.Method.DEPRECATED_GET_OR_POST: {
|
||||
case Method.DEPRECATED_GET_OR_POST: {
|
||||
// This is the deprecated way that needs to be handled for backwards compatibility.
|
||||
// If the request's post body is null, then the assumption is that the request is
|
||||
// GET. Otherwise, it is assumed that the request is a POST.
|
||||
@ -108,29 +110,29 @@ public class HttpClientStack implements HttpStack {
|
||||
return new HttpGet(request.getUrl());
|
||||
}
|
||||
}
|
||||
case Request.Method.GET:
|
||||
case Method.GET:
|
||||
return new HttpGet(request.getUrl());
|
||||
case Request.Method.DELETE:
|
||||
case Method.DELETE:
|
||||
return new HttpDelete(request.getUrl());
|
||||
case Request.Method.POST: {
|
||||
case Method.POST: {
|
||||
HttpPost postRequest = new HttpPost(request.getUrl());
|
||||
postRequest.addHeader(HEADER_CONTENT_TYPE, request.getBodyContentType());
|
||||
setEntityIfNonEmptyBody(postRequest, request);
|
||||
return postRequest;
|
||||
}
|
||||
case Request.Method.PUT: {
|
||||
case Method.PUT: {
|
||||
HttpPut putRequest = new HttpPut(request.getUrl());
|
||||
putRequest.addHeader(HEADER_CONTENT_TYPE, request.getBodyContentType());
|
||||
setEntityIfNonEmptyBody(putRequest, request);
|
||||
return putRequest;
|
||||
}
|
||||
case Request.Method.HEAD:
|
||||
case Method.HEAD:
|
||||
return new HttpHead(request.getUrl());
|
||||
case Request.Method.OPTIONS:
|
||||
case Method.OPTIONS:
|
||||
return new HttpOptions(request.getUrl());
|
||||
case Request.Method.TRACE:
|
||||
case Method.TRACE:
|
||||
return new HttpTrace(request.getUrl());
|
||||
case Request.Method.PATCH: {
|
||||
case Method.PATCH: {
|
||||
HttpPatch patchRequest = new HttpPatch(request.getUrl());
|
||||
patchRequest.addHeader(HEADER_CONTENT_TYPE, request.getBodyContentType());
|
||||
setEntityIfNonEmptyBody(patchRequest, request);
|
||||
|
@ -16,11 +16,12 @@
|
||||
|
||||
package org.telegram.android.volley.toolbox;
|
||||
|
||||
import org.telegram.android.volley.Cache;
|
||||
import org.telegram.android.volley.NetworkResponse;
|
||||
|
||||
import org.apache.http.impl.cookie.DateParseException;
|
||||
import org.apache.http.impl.cookie.DateUtils;
|
||||
import org.apache.http.protocol.HTTP;
|
||||
import org.telegram.android.volley.Cache;
|
||||
import org.telegram.android.volley.NetworkResponse;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
@ -41,10 +42,14 @@ public class HttpHeaderParser {
|
||||
Map<String, String> headers = response.headers;
|
||||
|
||||
long serverDate = 0;
|
||||
long lastModified = 0;
|
||||
long serverExpires = 0;
|
||||
long softExpire = 0;
|
||||
long finalExpire = 0;
|
||||
long maxAge = 0;
|
||||
long staleWhileRevalidate = 0;
|
||||
boolean hasCacheControl = false;
|
||||
boolean mustRevalidate = false;
|
||||
|
||||
String serverEtag = null;
|
||||
String headerValue;
|
||||
@ -58,18 +63,22 @@ public class HttpHeaderParser {
|
||||
if (headerValue != null) {
|
||||
hasCacheControl = true;
|
||||
String[] tokens = headerValue.split(",");
|
||||
for (String token1 : tokens) {
|
||||
String token = token1.trim();
|
||||
for (int i = 0; i < tokens.length; i++) {
|
||||
String token = tokens[i].trim();
|
||||
if (token.equals("no-cache") || token.equals("no-store")) {
|
||||
return null;
|
||||
} else if (token.startsWith("max-age=")) {
|
||||
try {
|
||||
maxAge = Long.parseLong(token.substring(8));
|
||||
} catch (Exception e) {
|
||||
/**/
|
||||
}
|
||||
} else if (token.startsWith("stale-while-revalidate=")) {
|
||||
try {
|
||||
staleWhileRevalidate = Long.parseLong(token.substring(23));
|
||||
} catch (Exception e) {
|
||||
}
|
||||
} else if (token.equals("must-revalidate") || token.equals("proxy-revalidate")) {
|
||||
maxAge = 0;
|
||||
mustRevalidate = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -79,23 +88,33 @@ public class HttpHeaderParser {
|
||||
serverExpires = parseDateAsEpoch(headerValue);
|
||||
}
|
||||
|
||||
headerValue = headers.get("Last-Modified");
|
||||
if (headerValue != null) {
|
||||
lastModified = parseDateAsEpoch(headerValue);
|
||||
}
|
||||
|
||||
serverEtag = headers.get("ETag");
|
||||
|
||||
// Cache-Control takes precedence over an Expires header, even if both exist and Expires
|
||||
// is more restrictive.
|
||||
if (hasCacheControl) {
|
||||
softExpire = now + maxAge * 1000;
|
||||
finalExpire = mustRevalidate
|
||||
? softExpire
|
||||
: softExpire + staleWhileRevalidate * 1000;
|
||||
} else if (serverDate > 0 && serverExpires >= serverDate) {
|
||||
// Default semantic for Expire header in HTTP specification is softExpire.
|
||||
softExpire = now + (serverExpires - serverDate);
|
||||
finalExpire = softExpire;
|
||||
}
|
||||
|
||||
Cache.Entry entry = new Cache.Entry();
|
||||
entry.data = response.data;
|
||||
entry.etag = serverEtag;
|
||||
entry.softTtl = softExpire;
|
||||
entry.ttl = entry.softTtl;
|
||||
entry.ttl = finalExpire;
|
||||
entry.serverDate = serverDate;
|
||||
entry.lastModified = lastModified;
|
||||
entry.responseHeaders = headers;
|
||||
|
||||
return entry;
|
||||
@ -115,10 +134,14 @@ public class HttpHeaderParser {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the charset specified in the Content-Type of this header,
|
||||
* or the HTTP default (ISO-8859-1) if none can be found.
|
||||
* Retrieve a charset from headers
|
||||
*
|
||||
* @param headers An {@link java.util.Map} of headers
|
||||
* @param defaultCharset Charset to return if none can be found
|
||||
* @return Returns the charset specified in the Content-Type of this header,
|
||||
* or the defaultCharset if none can be found.
|
||||
*/
|
||||
public static String parseCharset(Map<String, String> headers) {
|
||||
public static String parseCharset(Map<String, String> headers, String defaultCharset) {
|
||||
String contentType = headers.get(HTTP.CONTENT_TYPE);
|
||||
if (contentType != null) {
|
||||
String[] params = contentType.split(";");
|
||||
@ -132,6 +155,14 @@ public class HttpHeaderParser {
|
||||
}
|
||||
}
|
||||
|
||||
return HTTP.DEFAULT_CONTENT_CHARSET;
|
||||
return defaultCharset;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the charset specified in the Content-Type of this header,
|
||||
* or the HTTP default (ISO-8859-1) if none can be found.
|
||||
*/
|
||||
public static String parseCharset(Map<String, String> headers) {
|
||||
return parseCharset(headers, HTTP.DEFAULT_CONTENT_CHARSET);
|
||||
}
|
||||
}
|
||||
|
@ -16,10 +16,11 @@
|
||||
|
||||
package org.telegram.android.volley.toolbox;
|
||||
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.telegram.android.volley.AuthFailureError;
|
||||
import org.telegram.android.volley.Request;
|
||||
|
||||
import org.apache.http.HttpResponse;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Map;
|
||||
|
||||
@ -38,7 +39,7 @@ public interface HttpStack {
|
||||
* {@link Request#getHeaders()}
|
||||
* @return the HTTP response
|
||||
*/
|
||||
HttpResponse performRequest(Request<?> request, Map<String, String> additionalHeaders)
|
||||
public HttpResponse performRequest(Request<?> request, Map<String, String> additionalHeaders)
|
||||
throws IOException, AuthFailureError;
|
||||
|
||||
}
|
||||
|
@ -16,17 +16,20 @@
|
||||
|
||||
package org.telegram.android.volley.toolbox;
|
||||
|
||||
import org.telegram.android.volley.AuthFailureError;
|
||||
import org.telegram.android.volley.Request;
|
||||
import org.telegram.android.volley.Request.Method;
|
||||
|
||||
import org.apache.http.Header;
|
||||
import org.apache.http.HttpEntity;
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.apache.http.HttpStatus;
|
||||
import org.apache.http.ProtocolVersion;
|
||||
import org.apache.http.StatusLine;
|
||||
import org.apache.http.entity.BasicHttpEntity;
|
||||
import org.apache.http.message.BasicHeader;
|
||||
import org.apache.http.message.BasicHttpResponse;
|
||||
import org.apache.http.message.BasicStatusLine;
|
||||
import org.telegram.android.volley.AuthFailureError;
|
||||
import org.telegram.android.volley.Request;
|
||||
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
@ -42,7 +45,7 @@ import javax.net.ssl.HttpsURLConnection;
|
||||
import javax.net.ssl.SSLSocketFactory;
|
||||
|
||||
/**
|
||||
* An {@link org.telegram.android.volley.toolbox.HttpStack} based on {@link HttpURLConnection}.
|
||||
* An {@link HttpStack} based on {@link HttpURLConnection}.
|
||||
*/
|
||||
public class HurlStack implements HttpStack {
|
||||
|
||||
@ -56,7 +59,7 @@ public class HurlStack implements HttpStack {
|
||||
* Returns a URL to use instead of the provided one, or null to indicate
|
||||
* this URL should not be used at all.
|
||||
*/
|
||||
String rewriteUrl(String originalUrl);
|
||||
public String rewriteUrl(String originalUrl);
|
||||
}
|
||||
|
||||
private final UrlRewriter mUrlRewriter;
|
||||
@ -113,7 +116,9 @@ public class HurlStack implements HttpStack {
|
||||
StatusLine responseStatus = new BasicStatusLine(protocolVersion,
|
||||
connection.getResponseCode(), connection.getResponseMessage());
|
||||
BasicHttpResponse response = new BasicHttpResponse(responseStatus);
|
||||
if (hasResponseBody(request.getMethod(), responseStatus.getStatusCode())) {
|
||||
response.setEntity(entityFromConnection(connection));
|
||||
}
|
||||
for (Entry<String, List<String>> header : connection.getHeaderFields().entrySet()) {
|
||||
if (header.getKey() != null) {
|
||||
Header h = new BasicHeader(header.getKey(), header.getValue().get(0));
|
||||
@ -123,6 +128,20 @@ public class HurlStack implements HttpStack {
|
||||
return response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a response message contains a body.
|
||||
* @see <a href="https://tools.ietf.org/html/rfc7230#section-3.3">RFC 7230 section 3.3</a>
|
||||
* @param requestMethod request method
|
||||
* @param responseCode response status code
|
||||
* @return whether the response has a body
|
||||
*/
|
||||
private static boolean hasResponseBody(int requestMethod, int responseCode) {
|
||||
return requestMethod != Request.Method.HEAD
|
||||
&& !(HttpStatus.SC_CONTINUE <= responseCode && responseCode < HttpStatus.SC_OK)
|
||||
&& responseCode != HttpStatus.SC_NO_CONTENT
|
||||
&& responseCode != HttpStatus.SC_NOT_MODIFIED;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes an {@link HttpEntity} from the given {@link HttpURLConnection}.
|
||||
* @param connection
|
||||
@ -177,7 +196,7 @@ public class HurlStack implements HttpStack {
|
||||
/* package */ static void setConnectionParametersForRequest(HttpURLConnection connection,
|
||||
Request<?> request) throws IOException, AuthFailureError {
|
||||
switch (request.getMethod()) {
|
||||
case Request.Method.DEPRECATED_GET_OR_POST:
|
||||
case Method.DEPRECATED_GET_OR_POST:
|
||||
// This is the deprecated way that needs to be handled for backwards compatibility.
|
||||
// If the request's post body is null, then the assumption is that the request is
|
||||
// GET. Otherwise, it is assumed that the request is a POST.
|
||||
@ -195,32 +214,32 @@ public class HurlStack implements HttpStack {
|
||||
out.close();
|
||||
}
|
||||
break;
|
||||
case Request.Method.GET:
|
||||
case Method.GET:
|
||||
// Not necessary to set the request method because connection defaults to GET but
|
||||
// being explicit here.
|
||||
connection.setRequestMethod("GET");
|
||||
break;
|
||||
case Request.Method.DELETE:
|
||||
case Method.DELETE:
|
||||
connection.setRequestMethod("DELETE");
|
||||
break;
|
||||
case Request.Method.POST:
|
||||
case Method.POST:
|
||||
connection.setRequestMethod("POST");
|
||||
addBodyIfExists(connection, request);
|
||||
break;
|
||||
case Request.Method.PUT:
|
||||
case Method.PUT:
|
||||
connection.setRequestMethod("PUT");
|
||||
addBodyIfExists(connection, request);
|
||||
break;
|
||||
case Request.Method.HEAD:
|
||||
case Method.HEAD:
|
||||
connection.setRequestMethod("HEAD");
|
||||
break;
|
||||
case Request.Method.OPTIONS:
|
||||
case Method.OPTIONS:
|
||||
connection.setRequestMethod("OPTIONS");
|
||||
break;
|
||||
case Request.Method.TRACE:
|
||||
case Method.TRACE:
|
||||
connection.setRequestMethod("TRACE");
|
||||
break;
|
||||
case Request.Method.PATCH:
|
||||
case Method.PATCH:
|
||||
connection.setRequestMethod("PATCH");
|
||||
addBodyIfExists(connection, request);
|
||||
break;
|
||||
|
@ -20,10 +20,11 @@ import android.graphics.Bitmap.Config;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.widget.ImageView;
|
||||
|
||||
import android.widget.ImageView.ScaleType;
|
||||
import org.telegram.android.volley.Request;
|
||||
import org.telegram.android.volley.RequestQueue;
|
||||
import org.telegram.android.volley.Response;
|
||||
import org.telegram.android.volley.Response.ErrorListener;
|
||||
import org.telegram.android.volley.Response.Listener;
|
||||
import org.telegram.android.volley.VolleyError;
|
||||
|
||||
import java.util.HashMap;
|
||||
@ -71,8 +72,8 @@ public class ImageLoader {
|
||||
* must not block. Implementation with an LruCache is recommended.
|
||||
*/
|
||||
public interface ImageCache {
|
||||
Bitmap getBitmap(String url);
|
||||
void putBitmap(String url, Bitmap bitmap);
|
||||
public Bitmap getBitmap(String url);
|
||||
public void putBitmap(String url, Bitmap bitmap);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -127,7 +128,7 @@ public class ImageLoader {
|
||||
* or
|
||||
* - onErrorResponse will be called if there was an error loading the image.
|
||||
*/
|
||||
public interface ImageListener extends Response.ErrorListener {
|
||||
public interface ImageListener extends ErrorListener {
|
||||
/**
|
||||
* Listens for non-error changes to the loading of the image request.
|
||||
*
|
||||
@ -138,7 +139,7 @@ public class ImageLoader {
|
||||
* image loading in order to, for example, run an animation to fade in network loaded
|
||||
* images.
|
||||
*/
|
||||
void onResponse(ImageContainer response, boolean isImmediate);
|
||||
public void onResponse(ImageContainer response, boolean isImmediate);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -149,9 +150,22 @@ public class ImageLoader {
|
||||
* @return True if the item exists in cache, false otherwise.
|
||||
*/
|
||||
public boolean isCached(String requestUrl, int maxWidth, int maxHeight) {
|
||||
return isCached(requestUrl, maxWidth, maxHeight, ScaleType.CENTER_INSIDE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the item is available in the cache.
|
||||
*
|
||||
* @param requestUrl The url of the remote image
|
||||
* @param maxWidth The maximum width of the returned image.
|
||||
* @param maxHeight The maximum height of the returned image.
|
||||
* @param scaleType The scaleType of the imageView.
|
||||
* @return True if the item exists in cache, false otherwise.
|
||||
*/
|
||||
public boolean isCached(String requestUrl, int maxWidth, int maxHeight, ScaleType scaleType) {
|
||||
throwIfNotOnMainThread();
|
||||
|
||||
String cacheKey = getCacheKey(requestUrl, maxWidth, maxHeight);
|
||||
String cacheKey = getCacheKey(requestUrl, maxWidth, maxHeight, scaleType);
|
||||
return mCache.getBitmap(cacheKey) != null;
|
||||
}
|
||||
|
||||
@ -168,6 +182,15 @@ public class ImageLoader {
|
||||
return get(requestUrl, listener, 0, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Equivalent to calling {@link #get(String, ImageListener, int, int, ScaleType)} with
|
||||
* {@code Scaletype == ScaleType.CENTER_INSIDE}.
|
||||
*/
|
||||
public ImageContainer get(String requestUrl, ImageListener imageListener,
|
||||
int maxWidth, int maxHeight) {
|
||||
return get(requestUrl, imageListener, maxWidth, maxHeight, ScaleType.CENTER_INSIDE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Issues a bitmap request with the given URL if that image is not available
|
||||
* in the cache, and returns a bitmap container that contains all of the data
|
||||
@ -177,15 +200,17 @@ public class ImageLoader {
|
||||
* @param imageListener The listener to call when the remote image is loaded
|
||||
* @param maxWidth The maximum width of the returned image.
|
||||
* @param maxHeight The maximum height of the returned image.
|
||||
* @param scaleType The ImageViews ScaleType used to calculate the needed image size.
|
||||
* @return A container object that contains all of the properties of the request, as well as
|
||||
* the currently available image (default if remote is not loaded).
|
||||
*/
|
||||
public ImageContainer get(String requestUrl, ImageListener imageListener,
|
||||
int maxWidth, int maxHeight) {
|
||||
int maxWidth, int maxHeight, ScaleType scaleType) {
|
||||
|
||||
// only fulfill requests that were initiated from the main thread.
|
||||
throwIfNotOnMainThread();
|
||||
|
||||
final String cacheKey = getCacheKey(requestUrl, maxWidth, maxHeight);
|
||||
final String cacheKey = getCacheKey(requestUrl, maxWidth, maxHeight, scaleType);
|
||||
|
||||
// Try to look up the request in the cache of remote images.
|
||||
Bitmap cachedBitmap = mCache.getBitmap(cacheKey);
|
||||
@ -213,7 +238,8 @@ public class ImageLoader {
|
||||
|
||||
// The request is not already in flight. Send the new request to the network and
|
||||
// track it.
|
||||
Request<Bitmap> newRequest = makeImageRequest(requestUrl, maxWidth, maxHeight, cacheKey);
|
||||
Request<Bitmap> newRequest = makeImageRequest(requestUrl, maxWidth, maxHeight, scaleType,
|
||||
cacheKey);
|
||||
|
||||
mRequestQueue.add(newRequest);
|
||||
mInFlightRequests.put(cacheKey,
|
||||
@ -221,14 +247,14 @@ public class ImageLoader {
|
||||
return imageContainer;
|
||||
}
|
||||
|
||||
protected Request<Bitmap> makeImageRequest(String requestUrl, int maxWidth, int maxHeight, final String cacheKey) {
|
||||
return new ImageRequest(requestUrl, new Response.Listener<Bitmap>() {
|
||||
protected Request<Bitmap> makeImageRequest(String requestUrl, int maxWidth, int maxHeight,
|
||||
ScaleType scaleType, final String cacheKey) {
|
||||
return new ImageRequest(requestUrl, new Listener<Bitmap>() {
|
||||
@Override
|
||||
public void onResponse(Bitmap response) {
|
||||
onGetImageSuccess(cacheKey, response);
|
||||
}
|
||||
}, maxWidth, maxHeight,
|
||||
Config.RGB_565, new Response.ErrorListener() {
|
||||
}, maxWidth, maxHeight, scaleType, Config.RGB_565, new ErrorListener() {
|
||||
@Override
|
||||
public void onErrorResponse(VolleyError error) {
|
||||
onGetImageError(cacheKey, error);
|
||||
@ -471,8 +497,11 @@ public class ImageLoader {
|
||||
* @param url The URL of the request.
|
||||
* @param maxWidth The max-width of the output.
|
||||
* @param maxHeight The max-height of the output.
|
||||
* @param scaleType The scaleType of the imageView.
|
||||
*/
|
||||
private static String getCacheKey(String url, int maxWidth, int maxHeight) {
|
||||
return "#W" + maxWidth + "#H" + maxHeight + url;
|
||||
private static String getCacheKey(String url, int maxWidth, int maxHeight, ScaleType scaleType) {
|
||||
return new StringBuilder(url.length() + 12).append("#W").append(maxWidth)
|
||||
.append("#H").append(maxHeight).append("#S").append(scaleType.ordinal()).append(url)
|
||||
.toString();
|
||||
}
|
||||
}
|
||||
|
@ -16,10 +16,6 @@
|
||||
|
||||
package org.telegram.android.volley.toolbox;
|
||||
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Bitmap.Config;
|
||||
import android.graphics.BitmapFactory;
|
||||
|
||||
import org.telegram.android.volley.DefaultRetryPolicy;
|
||||
import org.telegram.android.volley.NetworkResponse;
|
||||
import org.telegram.android.volley.ParseError;
|
||||
@ -27,6 +23,11 @@ import org.telegram.android.volley.Request;
|
||||
import org.telegram.android.volley.Response;
|
||||
import org.telegram.android.volley.VolleyLog;
|
||||
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Bitmap.Config;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.widget.ImageView.ScaleType;
|
||||
|
||||
/**
|
||||
* A canned request for getting an image at a given URL and calling
|
||||
* back with a decoded Bitmap.
|
||||
@ -45,6 +46,7 @@ public class ImageRequest extends Request<Bitmap> {
|
||||
private final Config mDecodeConfig;
|
||||
private final int mMaxWidth;
|
||||
private final int mMaxHeight;
|
||||
private ScaleType mScaleType;
|
||||
|
||||
/** Decoding lock so that we don't decode more than one image at a time (to avoid OOM's) */
|
||||
private static final Object sDecodeLock = new Object();
|
||||
@ -63,11 +65,12 @@ public class ImageRequest extends Request<Bitmap> {
|
||||
* @param maxWidth Maximum width to decode this bitmap to, or zero for none
|
||||
* @param maxHeight Maximum height to decode this bitmap to, or zero for
|
||||
* none
|
||||
* @param scaleType The ImageViews ScaleType used to calculate the needed image size.
|
||||
* @param decodeConfig Format to decode the bitmap to
|
||||
* @param errorListener Error listener, or null to ignore errors
|
||||
*/
|
||||
public ImageRequest(String url, Response.Listener<Bitmap> listener, int maxWidth, int maxHeight,
|
||||
Config decodeConfig, Response.ErrorListener errorListener) {
|
||||
ScaleType scaleType, Config decodeConfig, Response.ErrorListener errorListener) {
|
||||
super(Method.GET, url, errorListener);
|
||||
setRetryPolicy(
|
||||
new DefaultRetryPolicy(IMAGE_TIMEOUT_MS, IMAGE_MAX_RETRIES, IMAGE_BACKOFF_MULT));
|
||||
@ -75,8 +78,19 @@ public class ImageRequest extends Request<Bitmap> {
|
||||
mDecodeConfig = decodeConfig;
|
||||
mMaxWidth = maxWidth;
|
||||
mMaxHeight = maxHeight;
|
||||
mScaleType = scaleType;
|
||||
}
|
||||
|
||||
/**
|
||||
* For API compatibility with the pre-ScaleType variant of the constructor. Equivalent to
|
||||
* the normal constructor with {@code ScaleType.CENTER_INSIDE}.
|
||||
*/
|
||||
@Deprecated
|
||||
public ImageRequest(String url, Response.Listener<Bitmap> listener, int maxWidth, int maxHeight,
|
||||
Config decodeConfig, Response.ErrorListener errorListener) {
|
||||
this(url, listener, maxWidth, maxHeight,
|
||||
ScaleType.CENTER_INSIDE, decodeConfig, errorListener);
|
||||
}
|
||||
@Override
|
||||
public Priority getPriority() {
|
||||
return Priority.LOW;
|
||||
@ -92,14 +106,24 @@ public class ImageRequest extends Request<Bitmap> {
|
||||
* maintain aspect ratio with primary dimension
|
||||
* @param actualPrimary Actual size of the primary dimension
|
||||
* @param actualSecondary Actual size of the secondary dimension
|
||||
* @param scaleType The ScaleType used to calculate the needed image size.
|
||||
*/
|
||||
private static int getResizedDimension(int maxPrimary, int maxSecondary, int actualPrimary,
|
||||
int actualSecondary) {
|
||||
int actualSecondary, ScaleType scaleType) {
|
||||
|
||||
// If no dominant value at all, just return the actual.
|
||||
if (maxPrimary == 0 && maxSecondary == 0) {
|
||||
if ((maxPrimary == 0) && (maxSecondary == 0)) {
|
||||
return actualPrimary;
|
||||
}
|
||||
|
||||
// If ScaleType.FIT_XY fill the whole rectangle, ignore ratio.
|
||||
if (scaleType == ScaleType.FIT_XY) {
|
||||
if (maxPrimary == 0) {
|
||||
return actualPrimary;
|
||||
}
|
||||
return maxPrimary;
|
||||
}
|
||||
|
||||
// If primary is unspecified, scale primary to match secondary's scaling ratio.
|
||||
if (maxPrimary == 0) {
|
||||
double ratio = (double) maxSecondary / (double) actualSecondary;
|
||||
@ -112,7 +136,16 @@ public class ImageRequest extends Request<Bitmap> {
|
||||
|
||||
double ratio = (double) actualSecondary / (double) actualPrimary;
|
||||
int resized = maxPrimary;
|
||||
if (resized * ratio > maxSecondary) {
|
||||
|
||||
// If ScaleType.CENTER_CROP fill the whole rectangle, preserve aspect ratio.
|
||||
if (scaleType == ScaleType.CENTER_CROP) {
|
||||
if ((resized * ratio) < maxSecondary) {
|
||||
resized = (int) (maxSecondary / ratio);
|
||||
}
|
||||
return resized;
|
||||
}
|
||||
|
||||
if ((resized * ratio) > maxSecondary) {
|
||||
resized = (int) (maxSecondary / ratio);
|
||||
}
|
||||
return resized;
|
||||
@ -150,9 +183,9 @@ public class ImageRequest extends Request<Bitmap> {
|
||||
|
||||
// Then compute the dimensions we would ideally like to decode to.
|
||||
int desiredWidth = getResizedDimension(mMaxWidth, mMaxHeight,
|
||||
actualWidth, actualHeight);
|
||||
actualWidth, actualHeight, mScaleType);
|
||||
int desiredHeight = getResizedDimension(mMaxHeight, mMaxWidth,
|
||||
actualHeight, actualWidth);
|
||||
actualHeight, actualWidth, mScaleType);
|
||||
|
||||
// Decode to the nearest power of two scaling factor.
|
||||
decodeOptions.inJustDecodeBounds = false;
|
||||
|
@ -16,11 +16,14 @@
|
||||
|
||||
package org.telegram.android.volley.toolbox;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.telegram.android.volley.NetworkResponse;
|
||||
import org.telegram.android.volley.ParseError;
|
||||
import org.telegram.android.volley.Response;
|
||||
import org.telegram.android.volley.Response.ErrorListener;
|
||||
import org.telegram.android.volley.Response.Listener;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
|
||||
@ -35,15 +38,30 @@ public class JsonArrayRequest extends JsonRequest<JSONArray> {
|
||||
* @param listener Listener to receive the JSON response
|
||||
* @param errorListener Error listener, or null to ignore errors.
|
||||
*/
|
||||
public JsonArrayRequest(String url, Response.Listener<JSONArray> listener, Response.ErrorListener errorListener) {
|
||||
public JsonArrayRequest(String url, Listener<JSONArray> listener, ErrorListener errorListener) {
|
||||
super(Method.GET, url, null, listener, errorListener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new request.
|
||||
* @param method the HTTP method to use
|
||||
* @param url URL to fetch the JSON from
|
||||
* @param jsonRequest A {@link JSONArray} to post with the request. Null is allowed and
|
||||
* indicates no parameters will be posted along with request.
|
||||
* @param listener Listener to receive the JSON response
|
||||
* @param errorListener Error listener, or null to ignore errors.
|
||||
*/
|
||||
public JsonArrayRequest(int method, String url, JSONArray jsonRequest,
|
||||
Listener<JSONArray> listener, ErrorListener errorListener) {
|
||||
super(method, url, (jsonRequest == null) ? null : jsonRequest.toString(), listener,
|
||||
errorListener);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Response<JSONArray> parseNetworkResponse(NetworkResponse response) {
|
||||
try {
|
||||
String jsonString =
|
||||
new String(response.data, HttpHeaderParser.parseCharset(response.headers));
|
||||
String jsonString = new String(response.data,
|
||||
HttpHeaderParser.parseCharset(response.headers, PROTOCOL_CHARSET));
|
||||
return Response.success(new JSONArray(jsonString),
|
||||
HttpHeaderParser.parseCacheHeaders(response));
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
|
@ -16,11 +16,14 @@
|
||||
|
||||
package org.telegram.android.volley.toolbox;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
import org.telegram.android.volley.NetworkResponse;
|
||||
import org.telegram.android.volley.ParseError;
|
||||
import org.telegram.android.volley.Response;
|
||||
import org.telegram.android.volley.Response.ErrorListener;
|
||||
import org.telegram.android.volley.Response.Listener;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
|
||||
@ -40,7 +43,7 @@ public class JsonObjectRequest extends JsonRequest<JSONObject> {
|
||||
* @param errorListener Error listener, or null to ignore errors.
|
||||
*/
|
||||
public JsonObjectRequest(int method, String url, JSONObject jsonRequest,
|
||||
Response.Listener<JSONObject> listener, Response.ErrorListener errorListener) {
|
||||
Listener<JSONObject> listener, ErrorListener errorListener) {
|
||||
super(method, url, (jsonRequest == null) ? null : jsonRequest.toString(), listener,
|
||||
errorListener);
|
||||
}
|
||||
@ -49,9 +52,10 @@ public class JsonObjectRequest extends JsonRequest<JSONObject> {
|
||||
* Constructor which defaults to <code>GET</code> if <code>jsonRequest</code> is
|
||||
* <code>null</code>, <code>POST</code> otherwise.
|
||||
*
|
||||
* @see #JsonObjectRequest(int, String, JSONObject, Listener, ErrorListener)
|
||||
*/
|
||||
public JsonObjectRequest(String url, JSONObject jsonRequest, Response.Listener<JSONObject> listener,
|
||||
Response.ErrorListener errorListener) {
|
||||
public JsonObjectRequest(String url, JSONObject jsonRequest, Listener<JSONObject> listener,
|
||||
ErrorListener errorListener) {
|
||||
this(jsonRequest == null ? Method.GET : Method.POST, url, jsonRequest,
|
||||
listener, errorListener);
|
||||
}
|
||||
@ -59,8 +63,8 @@ public class JsonObjectRequest extends JsonRequest<JSONObject> {
|
||||
@Override
|
||||
protected Response<JSONObject> parseNetworkResponse(NetworkResponse response) {
|
||||
try {
|
||||
String jsonString =
|
||||
new String(response.data, HttpHeaderParser.parseCharset(response.headers));
|
||||
String jsonString = new String(response.data,
|
||||
HttpHeaderParser.parseCharset(response.headers, PROTOCOL_CHARSET));
|
||||
return Response.success(new JSONObject(jsonString),
|
||||
HttpHeaderParser.parseCacheHeaders(response));
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
|
@ -19,6 +19,8 @@ package org.telegram.android.volley.toolbox;
|
||||
import org.telegram.android.volley.NetworkResponse;
|
||||
import org.telegram.android.volley.Request;
|
||||
import org.telegram.android.volley.Response;
|
||||
import org.telegram.android.volley.Response.ErrorListener;
|
||||
import org.telegram.android.volley.Response.Listener;
|
||||
import org.telegram.android.volley.VolleyLog;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
@ -30,28 +32,29 @@ import java.io.UnsupportedEncodingException;
|
||||
* @param <T> JSON type of response expected
|
||||
*/
|
||||
public abstract class JsonRequest<T> extends Request<T> {
|
||||
/** Charset for request. */
|
||||
private static final String PROTOCOL_CHARSET = "utf-8";
|
||||
/** Default charset for JSON request. */
|
||||
protected static final String PROTOCOL_CHARSET = "utf-8";
|
||||
|
||||
/** Content type for request. */
|
||||
private static final String PROTOCOL_CONTENT_TYPE =
|
||||
String.format("application/json; charset=%s", PROTOCOL_CHARSET);
|
||||
|
||||
private final Response.Listener<T> mListener;
|
||||
private final Listener<T> mListener;
|
||||
private final String mRequestBody;
|
||||
|
||||
/**
|
||||
* Deprecated constructor for a JsonRequest which defaults to GET unless {@link #getPostBody()}
|
||||
* or {@link #getPostParams()} is overridden (which defaults to POST).
|
||||
*
|
||||
* @deprecated Use {@link #JsonRequest(int, String, String, Listener, ErrorListener)}.
|
||||
*/
|
||||
public JsonRequest(String url, String requestBody, Response.Listener<T> listener,
|
||||
Response.ErrorListener errorListener) {
|
||||
public JsonRequest(String url, String requestBody, Listener<T> listener,
|
||||
ErrorListener errorListener) {
|
||||
this(Method.DEPRECATED_GET_OR_POST, url, requestBody, listener, errorListener);
|
||||
}
|
||||
|
||||
public JsonRequest(int method, String url, String requestBody, Response.Listener<T> listener,
|
||||
Response.ErrorListener errorListener) {
|
||||
public JsonRequest(int method, String url, String requestBody, Listener<T> listener,
|
||||
ErrorListener errorListener) {
|
||||
super(method, url, errorListener);
|
||||
mListener = listener;
|
||||
mRequestBody = requestBody;
|
||||
|
@ -103,6 +103,7 @@ public class NetworkImageView extends ImageView {
|
||||
void loadImageIfNecessary(final boolean isInLayoutPass) {
|
||||
int width = getWidth();
|
||||
int height = getHeight();
|
||||
ScaleType scaleType = getScaleType();
|
||||
|
||||
boolean wrapWidth = false, wrapHeight = false;
|
||||
if (getLayoutParams() != null) {
|
||||
@ -177,7 +178,7 @@ public class NetworkImageView extends ImageView {
|
||||
setImageResource(mDefaultImageId);
|
||||
}
|
||||
}
|
||||
}, maxWidth, maxHeight);
|
||||
}, maxWidth, maxHeight, scaleType);
|
||||
|
||||
// update the ImageContainer to be the new bitmap container.
|
||||
mImageContainer = newContainer;
|
||||
|
@ -25,7 +25,7 @@ import java.io.IOException;
|
||||
*/
|
||||
public class PoolingByteArrayOutputStream extends ByteArrayOutputStream {
|
||||
/**
|
||||
* If the {@link #PoolingByteArrayOutputStream(org.telegram.android.volley.toolbox.ByteArrayPool)} constructor is called, this is
|
||||
* If the {@link #PoolingByteArrayOutputStream(ByteArrayPool)} constructor is called, this is
|
||||
* the default size to which the underlying byte array is initialized.
|
||||
*/
|
||||
private static final int DEFAULT_SIZE = 256;
|
||||
|
@ -126,7 +126,10 @@ public class RequestFuture<T> implements Future<T>, Response.Listener<T>,
|
||||
|
||||
@Override
|
||||
public boolean isCancelled() {
|
||||
return mRequest != null && mRequest.isCanceled();
|
||||
if (mRequest == null) {
|
||||
return false;
|
||||
}
|
||||
return mRequest.isCanceled();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -19,6 +19,8 @@ package org.telegram.android.volley.toolbox;
|
||||
import org.telegram.android.volley.NetworkResponse;
|
||||
import org.telegram.android.volley.Request;
|
||||
import org.telegram.android.volley.Response;
|
||||
import org.telegram.android.volley.Response.ErrorListener;
|
||||
import org.telegram.android.volley.Response.Listener;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
|
||||
@ -26,7 +28,7 @@ import java.io.UnsupportedEncodingException;
|
||||
* A canned request for retrieving the response body at a given URL as a String.
|
||||
*/
|
||||
public class StringRequest extends Request<String> {
|
||||
private final Response.Listener<String> mListener;
|
||||
private final Listener<String> mListener;
|
||||
|
||||
/**
|
||||
* Creates a new request with the given method.
|
||||
@ -36,8 +38,8 @@ public class StringRequest extends Request<String> {
|
||||
* @param listener Listener to receive the String response
|
||||
* @param errorListener Error listener, or null to ignore errors
|
||||
*/
|
||||
public StringRequest(int method, String url, Response.Listener<String> listener,
|
||||
Response.ErrorListener errorListener) {
|
||||
public StringRequest(int method, String url, Listener<String> listener,
|
||||
ErrorListener errorListener) {
|
||||
super(method, url, errorListener);
|
||||
mListener = listener;
|
||||
}
|
||||
@ -49,7 +51,7 @@ public class StringRequest extends Request<String> {
|
||||
* @param listener Listener to receive the String response
|
||||
* @param errorListener Error listener, or null to ignore errors
|
||||
*/
|
||||
public StringRequest(String url, Response.Listener<String> listener, Response.ErrorListener errorListener) {
|
||||
public StringRequest(String url, Listener<String> listener, ErrorListener errorListener) {
|
||||
this(Method.GET, url, listener, errorListener);
|
||||
}
|
||||
|
||||
|
@ -48,7 +48,6 @@ public class Volley {
|
||||
PackageInfo info = context.getPackageManager().getPackageInfo(packageName, 0);
|
||||
userAgent = packageName + "/" + info.versionCode;
|
||||
} catch (NameNotFoundException e) {
|
||||
/**/
|
||||
}
|
||||
|
||||
if (stack == null) {
|
||||
|
@ -10,7 +10,6 @@ package org.telegram.messenger;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.AlarmManager;
|
||||
import android.app.Application;
|
||||
import android.app.PendingIntent;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
@ -25,6 +24,7 @@ import android.os.Build;
|
||||
import android.os.Handler;
|
||||
import android.os.PowerManager;
|
||||
import android.support.multidex.MultiDex;
|
||||
import android.support.multidex.MultiDexApplication;
|
||||
|
||||
import com.google.android.gms.common.ConnectionResult;
|
||||
import com.google.android.gms.common.GooglePlayServicesUtil;
|
||||
@ -44,7 +44,8 @@ import org.telegram.ui.Components.ForegroundDetector;
|
||||
import java.io.File;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
public class ApplicationLoader extends Application {
|
||||
//public class ApplicationLoader extends Application {
|
||||
public class ApplicationLoader extends MultiDexApplication {
|
||||
|
||||
private GoogleCloudMessaging gcm;
|
||||
private AtomicInteger msgId = new AtomicInteger();
|
||||
@ -360,8 +361,15 @@ public class ApplicationLoader extends Application {
|
||||
|
||||
@Override
|
||||
protected void attachBaseContext(Context base) {
|
||||
try{
|
||||
super.attachBaseContext(base);
|
||||
MultiDex.install(this);
|
||||
} catch (Exception e) {
|
||||
String vmName = System.getProperty("java.vm.name");
|
||||
if (!vmName.startsWith("Java")) {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void storeRegistrationId(Context context, String regId) {
|
||||
|
@ -113,7 +113,7 @@ public class BuffersStorage {
|
||||
arrayToReuse = freeBuffers128;
|
||||
} else if (buffer.buffer.capacity() == 1024 + 200) {
|
||||
arrayToReuse = freeBuffers1024;
|
||||
} if (buffer.buffer.capacity() == 4096 + 200) {
|
||||
} else if (buffer.buffer.capacity() == 4096 + 200) {
|
||||
arrayToReuse = freeBuffers4096;
|
||||
} else if (buffer.buffer.capacity() == 16384 + 200) {
|
||||
arrayToReuse = freeBuffers16384;
|
||||
|
@ -243,6 +243,11 @@ public class FileLoadOperation {
|
||||
downloadedBytes = (int)cacheFileTemp.length();
|
||||
nextDownloadOffset = downloadedBytes = downloadedBytes / currentDownloadChunkSize * currentDownloadChunkSize;
|
||||
}
|
||||
|
||||
if (BuildVars.DEBUG_VERSION) {
|
||||
FileLog.d("tmessages", "start loading file to temp = " + cacheFileTemp + " final = " + cacheFileFinal);
|
||||
}
|
||||
|
||||
if (fileNameIv != null) {
|
||||
cacheIvTemp = new File(tempPath, fileNameIv);
|
||||
try {
|
||||
@ -307,6 +312,9 @@ public class FileLoadOperation {
|
||||
return;
|
||||
}
|
||||
state = stateFailed;
|
||||
if (BuildVars.DEBUG_VERSION) {
|
||||
FileLog.e("tmessages", "cancel downloading file to " + cacheFileFinal);
|
||||
}
|
||||
cleanup();
|
||||
for (RequestInfo requestInfo : requestInfos) {
|
||||
if (requestInfo.requestToken != 0) {
|
||||
@ -356,9 +364,15 @@ public class FileLoadOperation {
|
||||
}
|
||||
if (cacheFileTemp != null) {
|
||||
if (!cacheFileTemp.renameTo(cacheFileFinal)) {
|
||||
if (BuildVars.DEBUG_VERSION) {
|
||||
FileLog.e("tmessages", "unable to rename temp = " + cacheFileTemp + " to final = " + cacheFileFinal);
|
||||
}
|
||||
cacheFileFinal = cacheFileTemp;
|
||||
}
|
||||
}
|
||||
if (BuildVars.DEBUG_VERSION) {
|
||||
FileLog.e("tmessages", "finished downloading file to " + cacheFileFinal);
|
||||
}
|
||||
delegate.didFinishLoadingFile(FileLoadOperation.this, cacheFileFinal);
|
||||
}
|
||||
|
||||
|
@ -577,6 +577,14 @@ public class FileLoader {
|
||||
return getPathToAttach(sizeFull);
|
||||
}
|
||||
}
|
||||
} else if (message.media instanceof TLRPC.TL_messageMediaWebPage && message.media.webpage.photo != null) {
|
||||
ArrayList<TLRPC.PhotoSize> sizes = message.media.webpage.photo.sizes;
|
||||
if (sizes.size() > 0) {
|
||||
TLRPC.PhotoSize sizeFull = getClosestPhotoSizeWithSize(sizes, AndroidUtilities.getPhotoSize());
|
||||
if (sizeFull != null) {
|
||||
return getPathToAttach(sizeFull);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return new File("");
|
||||
@ -621,7 +629,7 @@ public class FileLoader {
|
||||
}
|
||||
} else if (attach instanceof TLRPC.PhotoSize) {
|
||||
TLRPC.PhotoSize photoSize = (TLRPC.PhotoSize) attach;
|
||||
if (photoSize.location == null || photoSize.location.key != null || photoSize.location.volume_id == Integer.MIN_VALUE && photoSize.location.local_id < 0) {
|
||||
if (photoSize.location == null || photoSize.location.key != null || photoSize.location.volume_id == Integer.MIN_VALUE && photoSize.location.local_id < 0 || photoSize.size < 0) {
|
||||
dir = getInstance().getDirectory(MEDIA_DIR_CACHE);
|
||||
} else {
|
||||
dir = getInstance().getDirectory(MEDIA_DIR_IMAGE);
|
||||
|
@ -89,6 +89,7 @@ public class HandshakeAction extends Action implements TcpConnection.TcpConnecti
|
||||
|
||||
final Object lock = new Object();
|
||||
static ArrayList<HashMap<String, Object>> serverPublicKeys = null;
|
||||
|
||||
HashMap<String, Object> selectPublicKey(ArrayList<Long> fingerprints) {
|
||||
synchronized (lock) {
|
||||
if (serverPublicKeys == null) {
|
||||
@ -150,7 +151,7 @@ public class HandshakeAction extends Action implements TcpConnection.TcpConnecti
|
||||
}
|
||||
|
||||
for (HashMap<String, Object> keyDesc : serverPublicKeys) {
|
||||
long keyFingerprint = (Long)keyDesc.get("fingerprint");
|
||||
long keyFingerprint = (Long) keyDesc.get("fingerprint");
|
||||
for (long nFingerprint : fingerprints) {
|
||||
if (nFingerprint == keyFingerprint) {
|
||||
return keyDesc;
|
||||
@ -161,7 +162,7 @@ public class HandshakeAction extends Action implements TcpConnection.TcpConnecti
|
||||
}
|
||||
|
||||
long generateMessageId() {
|
||||
long messageId = (long)((((double)System.currentTimeMillis()) * 4294967296.0) / 1000.0);
|
||||
long messageId = (long) ((((double) System.currentTimeMillis()) * 4294967296.0) / 1000.0);
|
||||
if (messageId <= lastOutgoingMessageId) {
|
||||
messageId = lastOutgoingMessageId + 1;
|
||||
}
|
||||
@ -197,7 +198,7 @@ public class HandshakeAction extends Action implements TcpConnection.TcpConnecti
|
||||
}
|
||||
|
||||
processedPQRes = true;
|
||||
final TLRPC.TL_resPQ resPq = (TLRPC.TL_resPQ)message;
|
||||
final TLRPC.TL_resPQ resPq = (TLRPC.TL_resPQ) message;
|
||||
if (Utilities.arraysEquals(authNonce, 0, resPq.nonce, 0)) {
|
||||
final HashMap<String, Object> publicKey = selectPublicKey(resPq.server_public_key_fingerprints);
|
||||
if (publicKey == null) {
|
||||
@ -221,11 +222,11 @@ public class HandshakeAction extends Action implements TcpConnection.TcpConnecti
|
||||
@Override
|
||||
public void run() {
|
||||
ByteBuffer pBytes = ByteBuffer.allocate(4);
|
||||
pBytes.putInt((int)factorizedPq.p);
|
||||
pBytes.putInt((int) factorizedPq.p);
|
||||
byte[] pData = pBytes.array();
|
||||
|
||||
ByteBuffer qBytes = ByteBuffer.allocate(4);
|
||||
qBytes.putInt((int)factorizedPq.q);
|
||||
qBytes.putInt((int) factorizedPq.q);
|
||||
byte[] qData = qBytes.array();
|
||||
|
||||
TLRPC.TL_req_DH_params reqDH = new TLRPC.TL_req_DH_params();
|
||||
@ -233,7 +234,7 @@ public class HandshakeAction extends Action implements TcpConnection.TcpConnecti
|
||||
reqDH.server_nonce = authServerNonce;
|
||||
reqDH.p = pData;
|
||||
reqDH.q = qData;
|
||||
reqDH.public_key_fingerprint = (Long)publicKey.get("fingerprint");
|
||||
reqDH.public_key_fingerprint = (Long) publicKey.get("fingerprint");
|
||||
|
||||
SerializedData os = new SerializedData();
|
||||
|
||||
@ -261,7 +262,7 @@ public class HandshakeAction extends Action implements TcpConnection.TcpConnecti
|
||||
dataWithHash.writeByte(b[0]);
|
||||
}
|
||||
|
||||
byte[] encryptedBytes = Utilities.encryptWithRSA((BigInteger[])publicKey.get("key"), dataWithHash.toByteArray());
|
||||
byte[] encryptedBytes = Utilities.encryptWithRSA((BigInteger[]) publicKey.get("key"), dataWithHash.toByteArray());
|
||||
dataWithHash.cleanup();
|
||||
SerializedData encryptedData = new SerializedData();
|
||||
encryptedData.writeRaw(encryptedBytes);
|
||||
@ -300,7 +301,7 @@ public class HandshakeAction extends Action implements TcpConnection.TcpConnecti
|
||||
if (authNewNonce == null) {
|
||||
return;
|
||||
}
|
||||
TLRPC.TL_server_DH_params_ok serverDhParams = (TLRPC.TL_server_DH_params_ok)message;
|
||||
TLRPC.TL_server_DH_params_ok serverDhParams = (TLRPC.TL_server_DH_params_ok) message;
|
||||
|
||||
SerializedData tmpAesKey = new SerializedData();
|
||||
|
||||
@ -423,17 +424,17 @@ public class HandshakeAction extends Action implements TcpConnection.TcpConnecti
|
||||
for (int i = 7; i >= 0; i--) {
|
||||
byte a_ = authNewNonce[i];
|
||||
byte b_ = authServerNonce[i];
|
||||
byte x = (byte)(a_ ^ b_);
|
||||
byte x = (byte) (a_ ^ b_);
|
||||
serverSaltData.writeByte(x);
|
||||
}
|
||||
ByteBuffer saltBuffer = ByteBuffer.wrap(serverSaltData.toByteArray());
|
||||
serverSaltData.cleanup();
|
||||
|
||||
timeDifference = dhInnerData.server_time - (int)(System.currentTimeMillis() / 1000);
|
||||
timeDifference = dhInnerData.server_time - (int) (System.currentTimeMillis() / 1000);
|
||||
|
||||
serverSalt = new ServerSalt();
|
||||
serverSalt.validSince = (int)(System.currentTimeMillis() / 1000) + timeDifference;
|
||||
serverSalt.validUntil = (int)(System.currentTimeMillis() / 1000) + timeDifference + 30 * 60;
|
||||
serverSalt.validSince = (int) (System.currentTimeMillis() / 1000) + timeDifference;
|
||||
serverSalt.validUntil = (int) (System.currentTimeMillis() / 1000) + timeDifference + 30 * 60;
|
||||
serverSalt.value = saltBuffer.getLong();
|
||||
|
||||
FileLog.d("tmessages", String.format(Locale.US, "===== Time difference: %d", timeDifference));
|
||||
@ -489,7 +490,7 @@ public class HandshakeAction extends Action implements TcpConnection.TcpConnecti
|
||||
setClientDHParamsMsgData = null;
|
||||
}
|
||||
|
||||
TLRPC.Set_client_DH_params_answer dhAnswer = (TLRPC.Set_client_DH_params_answer)message;
|
||||
TLRPC.Set_client_DH_params_answer dhAnswer = (TLRPC.Set_client_DH_params_answer) message;
|
||||
|
||||
if (!Utilities.arraysEquals(authNonce, 0, dhAnswer.nonce, 0)) {
|
||||
FileLog.e("tmessages", "***** Invalid DH answer nonce");
|
||||
@ -544,7 +545,7 @@ public class HandshakeAction extends Action implements TcpConnection.TcpConnecti
|
||||
System.arraycopy(newNonceHash3Full, newNonceHash3Full.length - 16, newNonceHash3, 0, 16);
|
||||
|
||||
if (message instanceof TLRPC.TL_dh_gen_ok) {
|
||||
TLRPC.TL_dh_gen_ok dhGenOk = (TLRPC.TL_dh_gen_ok)message;
|
||||
TLRPC.TL_dh_gen_ok dhGenOk = (TLRPC.TL_dh_gen_ok) message;
|
||||
if (!Utilities.arraysEquals(newNonceHash1, 0, dhGenOk.new_nonce_hash1, 0)) {
|
||||
FileLog.e("tmessages", "***** Invalid DH answer nonce hash 1");
|
||||
beginHandshake(false);
|
||||
@ -569,7 +570,7 @@ public class HandshakeAction extends Action implements TcpConnection.TcpConnecti
|
||||
}
|
||||
});
|
||||
} else if (message instanceof TLRPC.TL_dh_gen_retry) {
|
||||
TLRPC.TL_dh_gen_retry dhRetry = (TLRPC.TL_dh_gen_retry)message;
|
||||
TLRPC.TL_dh_gen_retry dhRetry = (TLRPC.TL_dh_gen_retry) message;
|
||||
if (!Utilities.arraysEquals(newNonceHash2, 0, dhRetry.new_nonce_hash2, 0)) {
|
||||
FileLog.e("tmessages", "***** Invalid DH answer nonce hash 2");
|
||||
beginHandshake(false);
|
||||
@ -578,7 +579,7 @@ public class HandshakeAction extends Action implements TcpConnection.TcpConnecti
|
||||
FileLog.d("tmessages", "***** Retry DH");
|
||||
beginHandshake(false);
|
||||
} else if (message instanceof TLRPC.TL_dh_gen_fail) {
|
||||
TLRPC.TL_dh_gen_fail dhFail = (TLRPC.TL_dh_gen_fail)message;
|
||||
TLRPC.TL_dh_gen_fail dhFail = (TLRPC.TL_dh_gen_fail) message;
|
||||
if (!Utilities.arraysEquals(newNonceHash3, 0, dhFail.new_nonce_hash3, 0)) {
|
||||
FileLog.e("tmessages", "***** Invalid DH answer nonce hash 3");
|
||||
beginHandshake(false);
|
||||
|
@ -11729,6 +11729,15 @@ public class TLRPC {
|
||||
}
|
||||
}
|
||||
|
||||
public static class TL_inputMessagesFilterUrl extends MessagesFilter {
|
||||
public static int constructor = 0x7ef0dd87;
|
||||
|
||||
|
||||
public void serializeToStream(AbsSerializedData stream) {
|
||||
stream.writeInt32(constructor);
|
||||
}
|
||||
}
|
||||
|
||||
public static class TL_inputMessagesFilterPhotoVideo extends MessagesFilter {
|
||||
public static int constructor = 0x56e9f0e4;
|
||||
|
||||
|
@ -300,10 +300,6 @@ public class TcpConnection extends ConnectionContext {
|
||||
}
|
||||
}
|
||||
|
||||
public void resumeConnection() {
|
||||
|
||||
}
|
||||
|
||||
private void reconnect() {
|
||||
suspendConnection(false);
|
||||
connectionState = TcpConnectionState.TcpConnectionStageReconnecting;
|
||||
|
@ -39,6 +39,7 @@ public class UserConfig {
|
||||
public static int lastPauseTime = 0;
|
||||
public static boolean isWaitingForPasscodeEnter = false;
|
||||
public static int lastUpdateVersion;
|
||||
public static int lastContactsSyncTime;
|
||||
|
||||
public static int getNewMessageId() {
|
||||
int id;
|
||||
@ -76,6 +77,7 @@ public class UserConfig {
|
||||
editor.putInt("autoLockIn", autoLockIn);
|
||||
editor.putInt("lastPauseTime", lastPauseTime);
|
||||
editor.putInt("lastUpdateVersion", lastUpdateVersion);
|
||||
editor.putInt("lastContactsSyncTime", lastContactsSyncTime);
|
||||
|
||||
if (currentUser != null) {
|
||||
if (withFile) {
|
||||
@ -206,6 +208,7 @@ public class UserConfig {
|
||||
autoLockIn = preferences.getInt("autoLockIn", 60 * 60);
|
||||
lastPauseTime = preferences.getInt("lastPauseTime", 0);
|
||||
lastUpdateVersion = preferences.getInt("lastUpdateVersion", 511);
|
||||
lastContactsSyncTime = preferences.getInt("lastContactsSyncTime", (int) (System.currentTimeMillis() / 1000) - 23 * 60 * 60);
|
||||
String user = preferences.getString("user", null);
|
||||
if (user != null) {
|
||||
byte[] userBytes = Base64.decode(user, Base64.DEFAULT);
|
||||
@ -279,6 +282,7 @@ public class UserConfig {
|
||||
lastPauseTime = 0;
|
||||
isWaitingForPasscodeEnter = false;
|
||||
lastUpdateVersion = BuildVars.BUILD_VERSION;
|
||||
lastContactsSyncTime = (int) (System.currentTimeMillis() / 1000) - 23 * 60 * 60;
|
||||
saveConfig(true);
|
||||
}
|
||||
}
|
||||
|
@ -629,7 +629,7 @@ public class Utilities {
|
||||
editor.commit();
|
||||
//}
|
||||
}
|
||||
Utilities.loadWallpaperFromSDPath(ApplicationLoader.applicationContext, wName);
|
||||
loadWallpaperFromSDPath(ApplicationLoader.applicationContext, wName);
|
||||
}
|
||||
return themeName;
|
||||
}
|
||||
|
@ -135,8 +135,8 @@ public class ActionBarPopupWindow extends PopupWindow {
|
||||
if (child.getVisibility() != VISIBLE) {
|
||||
continue;
|
||||
}
|
||||
int position = positions.get(child);
|
||||
if (height - (position * AndroidUtilities.dp(48) + AndroidUtilities.dp(32)) > value * height) {
|
||||
Integer position = positions.get(child);
|
||||
if (position != null && height - (position * AndroidUtilities.dp(48) + AndroidUtilities.dp(32)) > value * height) {
|
||||
break;
|
||||
}
|
||||
lastStartedChild = a - 1;
|
||||
@ -148,8 +148,8 @@ public class ActionBarPopupWindow extends PopupWindow {
|
||||
if (child.getVisibility() != VISIBLE) {
|
||||
continue;
|
||||
}
|
||||
int position = positions.get(child);
|
||||
if ((position + 1) * AndroidUtilities.dp(48) - AndroidUtilities.dp(24) > value * height) {
|
||||
Integer position = positions.get(child);
|
||||
if (position != null && (position + 1) * AndroidUtilities.dp(48) - AndroidUtilities.dp(24) > value * height) {
|
||||
break;
|
||||
}
|
||||
lastStartedChild = a + 1;
|
||||
|
@ -29,7 +29,8 @@ public class MenuDrawable extends Drawable {
|
||||
|
||||
public MenuDrawable() {
|
||||
super();
|
||||
paint.setColor(0xffffffff);
|
||||
//paint.setColor(0xffffffff);
|
||||
paint.setColor(AndroidUtilities.getIntDef("chatsHeaderIconsColor", 0xffffffff)); //Plus
|
||||
paint.setStrokeWidth(AndroidUtilities.dp(2));
|
||||
}
|
||||
|
||||
|
@ -15,6 +15,7 @@ import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import org.telegram.SQLite.SQLiteCursor;
|
||||
import org.telegram.SQLite.SQLitePreparedStatement;
|
||||
import org.telegram.android.AndroidUtilities;
|
||||
import org.telegram.android.ContactsController;
|
||||
import org.telegram.android.LocaleController;
|
||||
@ -60,6 +61,10 @@ public class DialogsSearchAdapter extends BaseSearchAdapterRecycler {
|
||||
private boolean messagesSearchEndReached;
|
||||
private String lastMessagesSearchString;
|
||||
private int lastSearchId = 0;
|
||||
private int dialogsType;
|
||||
|
||||
private ArrayList<RecentSearchObject> recentSearchObjects = new ArrayList<>();
|
||||
private HashMap<Long, RecentSearchObject> recentSearchObjectsById = new HashMap<>();
|
||||
|
||||
private class Holder extends RecyclerView.ViewHolder {
|
||||
|
||||
@ -74,13 +79,21 @@ public class DialogsSearchAdapter extends BaseSearchAdapterRecycler {
|
||||
public CharSequence name;
|
||||
}
|
||||
|
||||
protected static class RecentSearchObject {
|
||||
TLObject object;
|
||||
int date;
|
||||
long did;
|
||||
}
|
||||
|
||||
public interface MessagesActivitySearchAdapterDelegate {
|
||||
void searchStateChanged(boolean searching);
|
||||
}
|
||||
|
||||
public DialogsSearchAdapter(Context context, int messagesSearch) {
|
||||
public DialogsSearchAdapter(Context context, int messagesSearch, int type) {
|
||||
mContext = context;
|
||||
needMessagesSearch = messagesSearch;
|
||||
dialogsType = type;
|
||||
loadRecentSearch();
|
||||
}
|
||||
|
||||
public void setDelegate(MessagesActivitySearchAdapterDelegate delegate) {
|
||||
@ -162,7 +175,194 @@ public class DialogsSearchAdapter extends BaseSearchAdapterRecycler {
|
||||
}, true, RPCRequest.RPCRequestClassGeneric | RPCRequest.RPCRequestClassFailOnServerErrors);
|
||||
}
|
||||
|
||||
private void searchDialogsInternal(final String query, final int dialogsType, final int searchId) {
|
||||
public boolean hasRecentRearch() {
|
||||
return !recentSearchObjects.isEmpty();
|
||||
}
|
||||
|
||||
public boolean isRecentSearchDisplayed() {
|
||||
return (lastSearchText == null || lastSearchText.length() == 0) && !recentSearchObjects.isEmpty();
|
||||
}
|
||||
|
||||
private void loadRecentSearch() {
|
||||
MessagesStorage.getInstance().getStorageQueue().postRunnable(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
SQLiteCursor cursor = MessagesStorage.getInstance().getDatabase().queryFinalized("SELECT did, date FROM search_recent WHERE 1");
|
||||
|
||||
ArrayList<Integer> usersToLoad = new ArrayList<>();
|
||||
ArrayList<Integer> chatsToLoad = new ArrayList<>();
|
||||
ArrayList<Integer> encryptedToLoad = new ArrayList<>();
|
||||
ArrayList<TLRPC.User> encUsers = new ArrayList<>();
|
||||
|
||||
final ArrayList<RecentSearchObject> arrayList = new ArrayList<>();
|
||||
final HashMap<Long, RecentSearchObject> hashMap = new HashMap<>();
|
||||
while (cursor.next()) {
|
||||
long did = cursor.longValue(0);
|
||||
|
||||
boolean add = false;
|
||||
int lower_id = (int) did;
|
||||
int high_id = (int) (did >> 32);
|
||||
if (lower_id != 0) {
|
||||
if (high_id == 1) {
|
||||
if (dialogsType == 0 && !chatsToLoad.contains(lower_id)) {
|
||||
chatsToLoad.add(lower_id);
|
||||
add = true;
|
||||
}
|
||||
} else {
|
||||
if (lower_id > 0) {
|
||||
if (dialogsType != 2 && !usersToLoad.contains(lower_id)) {
|
||||
usersToLoad.add(lower_id);
|
||||
add = true;
|
||||
}
|
||||
} else {
|
||||
if (!chatsToLoad.contains(-lower_id)) {
|
||||
chatsToLoad.add(-lower_id);
|
||||
add = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (dialogsType == 0) {
|
||||
if (!encryptedToLoad.contains(high_id)) {
|
||||
encryptedToLoad.add(high_id);
|
||||
add = true;
|
||||
}
|
||||
}
|
||||
if (add) {
|
||||
RecentSearchObject recentSearchObject = new RecentSearchObject();
|
||||
recentSearchObject.did = did;
|
||||
recentSearchObject.date = cursor.intValue(1);
|
||||
arrayList.add(recentSearchObject);
|
||||
hashMap.put(recentSearchObject.did, recentSearchObject);
|
||||
}
|
||||
}
|
||||
cursor.dispose();
|
||||
|
||||
|
||||
ArrayList<TLRPC.User> users = new ArrayList<>();
|
||||
|
||||
if (!encryptedToLoad.isEmpty()) {
|
||||
ArrayList<TLRPC.EncryptedChat> encryptedChats = new ArrayList<>();
|
||||
MessagesStorage.getInstance().getEncryptedChatsInternal(TextUtils.join(",", encryptedToLoad), encryptedChats, usersToLoad);
|
||||
for (int a = 0; a < encryptedChats.size(); a++) {
|
||||
hashMap.get((long) encryptedChats.get(a).id << 32).object = encryptedChats.get(a);
|
||||
}
|
||||
}
|
||||
|
||||
if (!chatsToLoad.isEmpty()) {
|
||||
ArrayList<TLRPC.Chat> chats = new ArrayList<>();
|
||||
MessagesStorage.getInstance().getChatsInternal(TextUtils.join(",", chatsToLoad), chats);
|
||||
for (int a = 0; a < chats.size(); a++) {
|
||||
TLRPC.Chat chat = chats.get(a);
|
||||
long did;
|
||||
if (chat.id > 0) {
|
||||
did = -chat.id;
|
||||
} else {
|
||||
did = AndroidUtilities.makeBroadcastId(chat.id);
|
||||
}
|
||||
hashMap.get(did).object = chat;
|
||||
}
|
||||
}
|
||||
|
||||
if (!usersToLoad.isEmpty()) {
|
||||
MessagesStorage.getInstance().getUsersInternal(TextUtils.join(",", usersToLoad), users);
|
||||
for (int a = 0; a < users.size(); a++) {
|
||||
TLRPC.User user = users.get(a);
|
||||
RecentSearchObject recentSearchObject = hashMap.get((long) user.id);
|
||||
if (recentSearchObject != null) {
|
||||
recentSearchObject.object = user;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Collections.sort(arrayList, new Comparator<RecentSearchObject>() {
|
||||
@Override
|
||||
public int compare(RecentSearchObject lhs, RecentSearchObject rhs) {
|
||||
if (lhs.date < rhs.date) {
|
||||
return 1;
|
||||
} else if (lhs.date > rhs.date) {
|
||||
return -1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
});
|
||||
AndroidUtilities.runOnUIThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
setRecentSearch(arrayList, hashMap);
|
||||
}
|
||||
});
|
||||
} catch (Exception e) {
|
||||
FileLog.e("tmessages", e);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void putRecentSearch(final long did, TLObject object) {
|
||||
RecentSearchObject recentSearchObject = recentSearchObjectsById.get(did);
|
||||
if (recentSearchObject == null) {
|
||||
recentSearchObject = new RecentSearchObject();
|
||||
recentSearchObjectsById.put(did, recentSearchObject);
|
||||
} else {
|
||||
recentSearchObjects.remove(recentSearchObject);
|
||||
}
|
||||
recentSearchObjects.add(0, recentSearchObject);
|
||||
recentSearchObject.did = did;
|
||||
recentSearchObject.object = object;
|
||||
recentSearchObject.date = (int) System.currentTimeMillis() / 1000;
|
||||
notifyDataSetChanged();
|
||||
MessagesStorage.getInstance().getStorageQueue().postRunnable(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
SQLitePreparedStatement state = MessagesStorage.getInstance().getDatabase().executeFast("REPLACE INTO search_recent VALUES(?, ?)");
|
||||
state.requery();
|
||||
state.bindLong(1, did);
|
||||
state.bindInteger(2, (int) System.currentTimeMillis() / 1000);
|
||||
state.step();
|
||||
state.dispose();
|
||||
} catch (Exception e) {
|
||||
FileLog.e("tmessages", e);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void clearRecentSearch() {
|
||||
recentSearchObjectsById = new HashMap<>();
|
||||
recentSearchObjects = new ArrayList<>();
|
||||
notifyDataSetChanged();
|
||||
MessagesStorage.getInstance().getStorageQueue().postRunnable(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
MessagesStorage.getInstance().getDatabase().executeFast("DELETE FROM search_recent WHERE 1").stepThis().dispose();
|
||||
} catch (Exception e) {
|
||||
FileLog.e("tmessages", e);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void setRecentSearch(ArrayList<RecentSearchObject> arrayList, HashMap<Long, RecentSearchObject> hashMap) {
|
||||
recentSearchObjects = arrayList;
|
||||
recentSearchObjectsById = hashMap;
|
||||
for (int a = 0; a < recentSearchObjects.size(); a++) {
|
||||
RecentSearchObject recentSearchObject = recentSearchObjects.get(a);
|
||||
if (recentSearchObject.object instanceof TLRPC.User) {
|
||||
MessagesController.getInstance().putUser((TLRPC.User) recentSearchObject.object, true);
|
||||
} else if (recentSearchObject.object instanceof TLRPC.Chat) {
|
||||
MessagesController.getInstance().putChat((TLRPC.Chat) recentSearchObject.object, true);
|
||||
} else if (recentSearchObject.object instanceof TLRPC.EncryptedChat) {
|
||||
MessagesController.getInstance().putEncryptedChat((TLRPC.EncryptedChat) recentSearchObject.object, true);
|
||||
}
|
||||
}
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
private void searchDialogsInternal(final String query, final int searchId) {
|
||||
if (needMessagesSearch == 2) {
|
||||
return;
|
||||
}
|
||||
@ -479,10 +679,6 @@ public class DialogsSearchAdapter extends BaseSearchAdapterRecycler {
|
||||
});
|
||||
}
|
||||
|
||||
public String getLastSearchText() {
|
||||
return lastSearchText;
|
||||
}
|
||||
|
||||
public boolean isGlobalSearch(int i) {
|
||||
return i > searchResult.size() && i <= globalSearch.size() + searchResult.size();
|
||||
}
|
||||
@ -506,10 +702,11 @@ public class DialogsSearchAdapter extends BaseSearchAdapterRecycler {
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
public void searchDialogs(final String query, final int dialogsType) {
|
||||
public void searchDialogs(final String query) {
|
||||
if (query != null && lastSearchText != null && query.equals(lastSearchText)) {
|
||||
return;
|
||||
}
|
||||
lastSearchText = query;
|
||||
try {
|
||||
if (searchTimer != null) {
|
||||
searchTimer.cancel();
|
||||
@ -564,7 +761,7 @@ public class DialogsSearchAdapter extends BaseSearchAdapterRecycler {
|
||||
} catch (Exception e) {
|
||||
FileLog.e("tmessages", e);
|
||||
}
|
||||
searchDialogsInternal(query, dialogsType, searchId);
|
||||
searchDialogsInternal(query, searchId);
|
||||
AndroidUtilities.runOnUIThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
@ -581,6 +778,9 @@ public class DialogsSearchAdapter extends BaseSearchAdapterRecycler {
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
if ((lastSearchText == null || lastSearchText.length() == 0) && !recentSearchObjects.isEmpty()) {
|
||||
return recentSearchObjects.size() + 1;
|
||||
}
|
||||
if (!searchResultHashtags.isEmpty()) {
|
||||
return searchResultHashtags.size() + 1;
|
||||
}
|
||||
@ -597,8 +797,19 @@ public class DialogsSearchAdapter extends BaseSearchAdapterRecycler {
|
||||
}
|
||||
|
||||
public Object getItem(int i) {
|
||||
if ((lastSearchText == null || lastSearchText.length() == 0) && !recentSearchObjects.isEmpty()) {
|
||||
if (i > 0 && i - 1 < recentSearchObjects.size()) {
|
||||
return recentSearchObjects.get(i - 1).object;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
if (!searchResultHashtags.isEmpty()) {
|
||||
if (i > 0) {
|
||||
return searchResultHashtags.get(i - 1);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
int localCount = searchResult.size();
|
||||
int globalCount = globalSearch.isEmpty() ? 0 : globalSearch.size() + 1;
|
||||
@ -652,11 +863,14 @@ public class DialogsSearchAdapter extends BaseSearchAdapterRecycler {
|
||||
TLRPC.User user = null;
|
||||
TLRPC.Chat chat = null;
|
||||
TLRPC.EncryptedChat encryptedChat = null;
|
||||
CharSequence username = null;
|
||||
CharSequence name = null;
|
||||
boolean isRecent = false;
|
||||
|
||||
|
||||
|
||||
int localCount = searchResult.size();
|
||||
int globalCount = globalSearch.isEmpty() ? 0 : globalSearch.size() + 1;
|
||||
String hexDarkColor = String.format("#%08X", (0xFFFFFFFF & AndroidUtilities.getIntDarkerColor("themeColor", 0x15)));
|
||||
cell.useSeparator = (position != getItemCount() - 1 && position != localCount - 1 && position != localCount + globalCount - 1);
|
||||
|
||||
Object obj = getItem(position);
|
||||
if (obj instanceof TLRPC.User) {
|
||||
user = (TLRPC.User) obj;
|
||||
@ -667,8 +881,14 @@ public class DialogsSearchAdapter extends BaseSearchAdapterRecycler {
|
||||
user = MessagesController.getInstance().getUser(encryptedChat.user_id);
|
||||
}
|
||||
|
||||
CharSequence username = null;
|
||||
CharSequence name = null;
|
||||
if ((lastSearchText == null || lastSearchText.length() == 0) && !recentSearchObjects.isEmpty()) {
|
||||
isRecent = true;
|
||||
cell.useSeparator = position != getItemCount() - 1;
|
||||
} else {
|
||||
int localCount = searchResult.size();
|
||||
int globalCount = globalSearch.isEmpty() ? 0 : globalSearch.size() + 1;
|
||||
cell.useSeparator = (position != getItemCount() - 1 && position != localCount - 1 && position != localCount + globalCount - 1);
|
||||
|
||||
if (position < searchResult.size()) {
|
||||
name = searchResultNames.get(position);
|
||||
if (name != null && user != null && user.username != null && user.username.length() > 0) {
|
||||
@ -690,15 +910,17 @@ public class DialogsSearchAdapter extends BaseSearchAdapterRecycler {
|
||||
FileLog.e("tmessages", e);
|
||||
}
|
||||
}
|
||||
|
||||
cell.setData(user, chat, encryptedChat, name, username);
|
||||
}
|
||||
cell.setData(user, chat, encryptedChat, name, username, isRecent);
|
||||
break;
|
||||
}
|
||||
case 1: {
|
||||
GreySectionCell cell = (GreySectionCell) holder.itemView;
|
||||
cell.setBackgroundColor(themePrefs.getInt("chatsRowColor", 0xfff2f2f2));
|
||||
cell.setTextColor(themePrefs.getInt("chatsNameColor", 0xff8a8a8a));
|
||||
if (!searchResultHashtags.isEmpty()) {
|
||||
if ((lastSearchText == null || lastSearchText.length() == 0) && !recentSearchObjects.isEmpty()) {
|
||||
cell.setText(LocaleController.getString("Recent", R.string.Recent).toUpperCase());
|
||||
} else if (!searchResultHashtags.isEmpty()) {
|
||||
cell.setText(LocaleController.getString("Hashtags", R.string.Hashtags).toUpperCase());
|
||||
} else if (!globalSearch.isEmpty() && position == searchResult.size()) {
|
||||
cell.setText(LocaleController.getString("GlobalSearch", R.string.GlobalSearch));
|
||||
@ -729,6 +951,9 @@ public class DialogsSearchAdapter extends BaseSearchAdapterRecycler {
|
||||
|
||||
@Override
|
||||
public int getItemViewType(int i) {
|
||||
if ((lastSearchText == null || lastSearchText.length() == 0) && !recentSearchObjects.isEmpty()) {
|
||||
return i == 0 ? 1 : 0;
|
||||
}
|
||||
if (!searchResultHashtags.isEmpty()) {
|
||||
return i == 0 ? 1 : 4;
|
||||
}
|
||||
|
@ -269,7 +269,7 @@ public class SearchAdapter extends BaseSearchAdapter {
|
||||
((UserCell) view).setChecked(checkedMap.containsKey(user.id), false);
|
||||
}
|
||||
} else {
|
||||
((ProfileSearchCell) view).setData(user, null, null, name, username);
|
||||
((ProfileSearchCell) view).setData(user, null, null, name, username, false);
|
||||
((ProfileSearchCell) view).useSeparator = (i != getCount() - 1 && i != searchResult.size() - 1);
|
||||
if (ignoreUsers != null) {
|
||||
if (ignoreUsers.containsKey(user.id)) {
|
||||
|
@ -288,6 +288,7 @@ public class BlockedUsersActivity extends BaseFragment implements NotificationCe
|
||||
if (type == 0) {
|
||||
if (view == null) {
|
||||
view = new UserCell(mContext, 1);
|
||||
view.setTag("Pref");
|
||||
}
|
||||
((UserCell) view).setNameColor(preferences.getInt("prefTitleColor", 0xff212121));
|
||||
((UserCell) view).setStatusColor(preferences.getInt("prefSummaryColor", 0xff8a8a8a));
|
||||
|
@ -56,8 +56,10 @@ public class BaseCell extends View {
|
||||
}
|
||||
|
||||
protected void setDrawableBounds(Drawable drawable, int x, int y, int w, int h) {
|
||||
if (drawable != null) {
|
||||
drawable.setBounds(x, y, x + w, y + h);
|
||||
}
|
||||
}
|
||||
|
||||
protected void startCheckLongPress() {
|
||||
if (checkingForLongPress) {
|
||||
|
@ -22,16 +22,18 @@ import org.telegram.android.AndroidUtilities;
|
||||
import org.telegram.android.ImageLoader;
|
||||
import org.telegram.android.MessagesController;
|
||||
import org.telegram.android.SendMessagesHelper;
|
||||
import org.telegram.messenger.BuildVars;
|
||||
import org.telegram.messenger.FileLoader;
|
||||
import org.telegram.android.MediaController;
|
||||
import org.telegram.android.MessageObject;
|
||||
import org.telegram.messenger.FileLog;
|
||||
import org.telegram.ui.Components.RadialProgress;
|
||||
import org.telegram.ui.Components.ResourceLoader;
|
||||
import org.telegram.ui.Components.SeekBar;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
public class ChatAudioCell extends ChatBaseCell implements SeekBar.SeekBarDelegate, MediaController.FileDownloadProgressListener {
|
||||
public class ChatAudioCell extends ChatBaseCell implements SeekBar.SeekBarDelegate {
|
||||
|
||||
private static TextPaint timePaint;
|
||||
private static Paint circlePaint;
|
||||
@ -51,11 +53,8 @@ public class ChatAudioCell extends ChatBaseCell implements SeekBar.SeekBarDelega
|
||||
private int timeWidth;
|
||||
private String lastTimeString = null;
|
||||
|
||||
private int TAG;
|
||||
|
||||
public ChatAudioCell(Context context) {
|
||||
super(context);
|
||||
TAG = MediaController.getInstance().generateObserverTag();
|
||||
|
||||
seekBar = new SeekBar(context);
|
||||
seekBar.delegate = this;
|
||||
@ -222,6 +221,9 @@ public class ChatAudioCell extends ChatBaseCell implements SeekBar.SeekBarDelega
|
||||
if (cacheFile == null) {
|
||||
cacheFile = FileLoader.getPathToMessage(currentMessageObject.messageOwner);
|
||||
}
|
||||
if (BuildVars.DEBUG_VERSION) {
|
||||
FileLog.d("tmessages", "looking for audio in " + cacheFile);
|
||||
}
|
||||
if (cacheFile.exists()) {
|
||||
MediaController.getInstance().removeLoadingFileObserver(this);
|
||||
boolean playing = MediaController.getInstance().isPlayingAudio(currentMessageObject);
|
||||
@ -277,11 +279,6 @@ public class ChatAudioCell extends ChatBaseCell implements SeekBar.SeekBarDelega
|
||||
radialProgress.setProgress(progress, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getObserverTag() {
|
||||
return TAG;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSeekBarDrag(float progress) {
|
||||
if (currentMessageObject == null) {
|
||||
@ -382,7 +379,7 @@ public class ChatAudioCell extends ChatBaseCell implements SeekBar.SeekBarDelega
|
||||
timePaint.setColor(0xffa1aab3);
|
||||
circlePaint.setColor(0xff4195e5);
|
||||
}
|
||||
radialProgress.onDraw(canvas);
|
||||
radialProgress.draw(canvas);
|
||||
|
||||
canvas.save();
|
||||
canvas.translate(timeX, AndroidUtilities.dp(42) + namesOffset);
|
||||
|
@ -28,6 +28,7 @@ import org.telegram.android.AndroidUtilities;
|
||||
import org.telegram.android.Emoji;
|
||||
import org.telegram.android.ImageReceiver;
|
||||
import org.telegram.android.LocaleController;
|
||||
import org.telegram.android.MediaController;
|
||||
import org.telegram.android.MessageObject;
|
||||
import org.telegram.android.MessagesController;
|
||||
import org.telegram.android.UserObject;
|
||||
@ -41,7 +42,7 @@ import org.telegram.ui.Components.LinkPath;
|
||||
import org.telegram.ui.Components.ResourceLoader;
|
||||
import org.telegram.ui.Components.StaticLayoutEx;
|
||||
|
||||
public class ChatBaseCell extends BaseCell {
|
||||
public class ChatBaseCell extends BaseCell implements MediaController.FileDownloadProgressListener {
|
||||
|
||||
public interface ChatBaseCellDelegate {
|
||||
void didPressedUserAvatar(ChatBaseCell cell, TLRPC.User user);
|
||||
@ -50,6 +51,7 @@ public class ChatBaseCell extends BaseCell {
|
||||
void didPressReplyMessage(ChatBaseCell cell, int id);
|
||||
void didPressUrl(MessageObject messageObject, String url);
|
||||
void needOpenWebView(String url, String title, String originalUrl, int w, int h);
|
||||
void didClickedImage(ChatBaseCell cell);
|
||||
boolean canPerformActions();
|
||||
}
|
||||
|
||||
@ -57,6 +59,7 @@ public class ChatBaseCell extends BaseCell {
|
||||
protected boolean linkPreviewPressed;
|
||||
protected LinkPath urlPath = new LinkPath();
|
||||
protected static Paint urlPaint;
|
||||
private int TAG;
|
||||
|
||||
public boolean isChat = false;
|
||||
protected boolean isPressed = false;
|
||||
@ -185,6 +188,7 @@ public class ChatBaseCell extends BaseCell {
|
||||
avatarImage.setRoundRadius(AndroidUtilities.dp(21));
|
||||
avatarDrawable = new AvatarDrawable();
|
||||
replyImageReceiver = new ImageReceiver(this);
|
||||
TAG = MediaController.getInstance().generateObserverTag();
|
||||
//Chat Photo
|
||||
SharedPreferences themePrefs = ApplicationLoader.applicationContext.getSharedPreferences(AndroidUtilities.THEME_PREFS, AndroidUtilities.THEME_PREFS_MODE);
|
||||
int radius = AndroidUtilities.dp(themePrefs.getInt("chatAvatarRadius", 32));
|
||||
@ -719,6 +723,10 @@ public class ChatBaseCell extends BaseCell {
|
||||
|
||||
}
|
||||
|
||||
public ImageReceiver getPhotoImage() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onLongPress() {
|
||||
if (delegate != null) {
|
||||
@ -783,7 +791,7 @@ public class ChatBaseCell extends BaseCell {
|
||||
setDrawableBounds(currentBackgroundDrawable, (!media ? 0 : AndroidUtilities.dp(9)), AndroidUtilities.dp(1), backgroundWidth, layoutHeight - AndroidUtilities.dp(2));
|
||||
}
|
||||
}
|
||||
if (drawBackground) {
|
||||
if (drawBackground && currentBackgroundDrawable != null) {
|
||||
currentBackgroundDrawable.draw(canvas);
|
||||
}
|
||||
|
||||
@ -1061,4 +1069,29 @@ public class ChatBaseCell extends BaseCell {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailedDownload(String fileName) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSuccessDownload(String fileName) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onProgressDownload(String fileName, float progress) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onProgressUpload(String fileName, float progress, boolean isEncrypted) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getObserverTag() {
|
||||
return TAG;
|
||||
}
|
||||
}
|
||||
|
@ -52,11 +52,9 @@ import org.telegram.ui.PhotoViewer;
|
||||
import java.io.File;
|
||||
import java.util.Locale;
|
||||
|
||||
public class ChatMediaCell extends ChatBaseCell implements MediaController.FileDownloadProgressListener {
|
||||
public class ChatMediaCell extends ChatBaseCell {
|
||||
|
||||
public interface ChatMediaCellDelegate {
|
||||
void didClickedImage(ChatMediaCell cell);
|
||||
|
||||
void didPressedOther(ChatMediaCell cell);
|
||||
}
|
||||
|
||||
@ -84,8 +82,6 @@ public class ChatMediaCell extends ChatBaseCell implements MediaController.FileD
|
||||
|
||||
private boolean allowedToSetPhoto = true;
|
||||
|
||||
private int TAG;
|
||||
|
||||
private int buttonState = 0;
|
||||
private int buttonPressed = 0;
|
||||
private boolean imagePressed = false;
|
||||
@ -143,8 +139,6 @@ public class ChatMediaCell extends ChatBaseCell implements MediaController.FileD
|
||||
locationAddressPaint.setTextSize(AndroidUtilities.dp(14));
|
||||
}
|
||||
|
||||
TAG = MediaController.getInstance().generateObserverTag();
|
||||
|
||||
photoImage = new ImageReceiver(this);
|
||||
radialProgress = new RadialProgress(this);
|
||||
}
|
||||
@ -359,8 +353,8 @@ public class ChatMediaCell extends ChatBaseCell implements MediaController.FileD
|
||||
private void didClickedImage() {
|
||||
if (currentMessageObject.type == 1) {
|
||||
if (buttonState == -1) {
|
||||
if (mediaDelegate != null) {
|
||||
mediaDelegate.didClickedImage(this);
|
||||
if (delegate != null) {
|
||||
delegate.didClickedImage(this);
|
||||
}
|
||||
} else if (buttonState == 0) {
|
||||
didPressedButton(false);
|
||||
@ -381,13 +375,13 @@ public class ChatMediaCell extends ChatBaseCell implements MediaController.FileD
|
||||
didPressedButton(false);
|
||||
}
|
||||
} else if (currentMessageObject.type == 4) {
|
||||
if (mediaDelegate != null) {
|
||||
mediaDelegate.didClickedImage(this);
|
||||
if (delegate != null) {
|
||||
delegate.didClickedImage(this);
|
||||
}
|
||||
} else if (currentMessageObject.type == 9) {
|
||||
if (buttonState == -1) {
|
||||
if (mediaDelegate != null) {
|
||||
mediaDelegate.didClickedImage(this);
|
||||
if (delegate != null) {
|
||||
delegate.didClickedImage(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -463,8 +457,8 @@ public class ChatMediaCell extends ChatBaseCell implements MediaController.FileD
|
||||
radialProgress.setBackground(getDrawableForCurrentState(), false, animated);
|
||||
}
|
||||
} else if (buttonState == 3) {
|
||||
if (mediaDelegate != null) {
|
||||
mediaDelegate.didClickedImage(this);
|
||||
if (delegate != null) {
|
||||
delegate.didClickedImage(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -931,6 +925,7 @@ public class ChatMediaCell extends ChatBaseCell implements MediaController.FileD
|
||||
updateButtonState(dataChanged);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ImageReceiver getPhotoImage() {
|
||||
return photoImage;
|
||||
}
|
||||
@ -981,10 +976,11 @@ public class ChatMediaCell extends ChatBaseCell implements MediaController.FileD
|
||||
if (cacheFile.exists() && cacheFile.length() == 0) {
|
||||
cacheFile.delete();
|
||||
}
|
||||
//
|
||||
if (!currentMessageObject.isOut() && cacheFile.exists() && cacheFile.length() != 0 && currentMessageObject.messageOwner.media.document != null) {
|
||||
if(cacheFile.lastModified()/1000 < currentMessageObject.messageOwner.media.document.date)cacheFile.delete();
|
||||
}
|
||||
//Plus
|
||||
//if (!currentMessageObject.isOut() && cacheFile.exists() && cacheFile.length() != 0 && currentMessageObject.messageOwner.media.document != null) {
|
||||
// Log.e("ChatMediaCell", cacheFile.getAbsolutePath().toString());
|
||||
// if(cacheFile.lastModified()/1000 < currentMessageObject.messageOwner.media.document.date)cacheFile.delete();
|
||||
//}
|
||||
//
|
||||
if (!cacheFile.exists()) {
|
||||
MediaController.getInstance().addLoadingFileObserver(fileName, this);
|
||||
@ -1187,7 +1183,7 @@ public class ChatMediaCell extends ChatBaseCell implements MediaController.FileD
|
||||
}
|
||||
}
|
||||
|
||||
radialProgress.onDraw(canvas);
|
||||
radialProgress.draw(canvas);
|
||||
try{
|
||||
if(themePrefs.getBoolean("chatMemberColorCheck", false)){
|
||||
senderPaint.setColor(themePrefs.getInt("chatMemberColor", AndroidUtilities.getIntDarkerColor("themeColor", 0x15)));
|
||||
@ -1321,9 +1317,4 @@ public class ChatMediaCell extends ChatBaseCell implements MediaController.FileD
|
||||
public void onProgressUpload(String fileName, float progress, boolean isEncrypted) {
|
||||
radialProgress.setProgress(progress, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getObserverTag() {
|
||||
return TAG;
|
||||
}
|
||||
}
|
||||
|
@ -25,8 +25,10 @@ import android.text.TextPaint;
|
||||
import android.text.TextUtils;
|
||||
import android.text.style.ClickableSpan;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.SoundEffectConstants;
|
||||
|
||||
import org.telegram.android.AndroidUtilities;
|
||||
import org.telegram.android.ImageLoader;
|
||||
import org.telegram.android.ImageReceiver;
|
||||
import org.telegram.android.MediaController;
|
||||
import org.telegram.android.MessageObject;
|
||||
@ -35,6 +37,7 @@ import org.telegram.messenger.FileLoader;
|
||||
import org.telegram.messenger.FileLog;
|
||||
import org.telegram.messenger.R;
|
||||
import org.telegram.messenger.TLRPC;
|
||||
import org.telegram.ui.Components.RadialProgress;
|
||||
import org.telegram.ui.Components.ResourceLoader;
|
||||
import org.telegram.ui.Components.StaticLayoutEx;
|
||||
import org.telegram.ui.Components.URLSpanNoUnderline;
|
||||
@ -52,8 +55,10 @@ public class ChatMessageCell extends ChatBaseCell {
|
||||
private int firstVisibleBlockNum = 0;
|
||||
private int totalVisibleBlocksCount = 0;
|
||||
|
||||
private RadialProgress radialProgress;
|
||||
private ImageReceiver linkImageView;
|
||||
private boolean isSmallImage;
|
||||
private boolean drawImageButton;
|
||||
private boolean drawLinkImageView;
|
||||
private boolean hasLinkPreview;
|
||||
private int linkPreviewHeight;
|
||||
@ -70,19 +75,31 @@ public class ChatMessageCell extends ChatBaseCell {
|
||||
private StaticLayout authorLayout;
|
||||
private static TextPaint durationPaint;
|
||||
|
||||
private int buttonX;
|
||||
private int buttonY;
|
||||
private int buttonState;
|
||||
private boolean buttonPressed;
|
||||
private boolean photoNotSet;
|
||||
private TLRPC.PhotoSize currentPhotoObject;
|
||||
private TLRPC.PhotoSize currentPhotoObjectThumb;
|
||||
private String currentPhotoFilter;
|
||||
private String currentPhotoFilterThumb;
|
||||
private boolean cancelLoading;
|
||||
|
||||
private static Drawable igvideoDrawable;
|
||||
|
||||
public ChatMessageCell(Context context) {
|
||||
super(context);
|
||||
drawForwardedName = true;
|
||||
linkImageView = new ImageReceiver(this);
|
||||
radialProgress = new RadialProgress(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onTouchEvent(MotionEvent event) {
|
||||
boolean result = false;
|
||||
if (currentMessageObject != null && currentMessageObject.textLayoutBlocks != null && !currentMessageObject.textLayoutBlocks.isEmpty() && currentMessageObject.messageText instanceof Spannable && delegate.canPerformActions()) {
|
||||
if (event.getAction() == MotionEvent.ACTION_DOWN || (linkPreviewPressed || pressedLink != null) && event.getAction() == MotionEvent.ACTION_UP) {
|
||||
if (event.getAction() == MotionEvent.ACTION_DOWN || (linkPreviewPressed || pressedLink != null || buttonPressed) && event.getAction() == MotionEvent.ACTION_UP) {
|
||||
int x = (int) event.getX();
|
||||
int y = (int) event.getY();
|
||||
if (x >= textX && y >= textY && x <= textX + currentMessageObject.textWidth && y <= textY + currentMessageObject.textHeight) {
|
||||
@ -150,8 +167,13 @@ public class ChatMessageCell extends ChatBaseCell {
|
||||
if (event.getAction() == MotionEvent.ACTION_DOWN) {
|
||||
resetPressedLink();
|
||||
if (drawLinkImageView && linkImageView.isInsideImage(x, y)) {
|
||||
if (drawImageButton && buttonState != -1 && x >= buttonX && x <= buttonX + AndroidUtilities.dp(48) && y >= buttonY && y <= buttonY + AndroidUtilities.dp(48)) {
|
||||
buttonPressed = true;
|
||||
result = true;
|
||||
} else {
|
||||
linkPreviewPressed = true;
|
||||
result = true;
|
||||
}
|
||||
} else {
|
||||
if (descriptionLayout != null && y >= descriptionY) {
|
||||
try {
|
||||
@ -193,9 +215,12 @@ public class ChatMessageCell extends ChatBaseCell {
|
||||
try {
|
||||
if (pressedLink != null) {
|
||||
pressedLink.onClick(this);
|
||||
} else {
|
||||
if (drawImageButton && delegate != null) {
|
||||
delegate.didClickedImage(this);
|
||||
} else {
|
||||
TLRPC.WebPage webPage = currentMessageObject.messageOwner.media.webpage;
|
||||
if (Build.VERSION.SDK_INT >= 19 && webPage.embed_url != null && webPage.embed_url.length() != 0) {
|
||||
if (Build.VERSION.SDK_INT >= 16 && webPage.embed_url != null && webPage.embed_url.length() != 0) {
|
||||
delegate.needOpenWebView(webPage.embed_url, webPage.site_name, webPage.url, webPage.embed_width, webPage.embed_height);
|
||||
} else {
|
||||
Uri uri = Uri.parse(webPage.url);
|
||||
@ -204,11 +229,27 @@ public class ChatMessageCell extends ChatBaseCell {
|
||||
getContext().startActivity(intent);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
FileLog.e("tmessages", e);
|
||||
}
|
||||
resetPressedLink();
|
||||
result = true;
|
||||
} else if (buttonPressed) {
|
||||
if (event.getAction() == MotionEvent.ACTION_UP) {
|
||||
buttonPressed = false;
|
||||
playSoundEffect(SoundEffectConstants.CLICK);
|
||||
didPressedButton(false);
|
||||
invalidate();
|
||||
} else if (event.getAction() == MotionEvent.ACTION_CANCEL) {
|
||||
buttonPressed = false;
|
||||
invalidate();
|
||||
} else if (event.getAction() == MotionEvent.ACTION_MOVE) {
|
||||
if (!(x >= buttonX && x <= buttonX + AndroidUtilities.dp(48) && y >= buttonY && y <= buttonY + AndroidUtilities.dp(48))) {
|
||||
buttonPressed = false;
|
||||
invalidate();
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
resetPressedLink();
|
||||
@ -263,7 +304,7 @@ public class ChatMessageCell extends ChatBaseCell {
|
||||
return left1 <= right2;
|
||||
}
|
||||
|
||||
private StaticLayout generateStaticLayout(CharSequence text, TextPaint paint, int maxWidth, int smallWidth, int linesCount, int maxLines) {
|
||||
public static StaticLayout generateStaticLayout(CharSequence text, TextPaint paint, int maxWidth, int smallWidth, int linesCount, int maxLines) {
|
||||
SpannableStringBuilder stringBuilder = new SpannableStringBuilder(text);
|
||||
int addedChars = 0;
|
||||
StaticLayout layout = new StaticLayout(text, paint, smallWidth, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false);
|
||||
@ -298,21 +339,30 @@ public class ChatMessageCell extends ChatBaseCell {
|
||||
return super.isUserDataChanged();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ImageReceiver getPhotoImage() {
|
||||
return linkImageView;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDetachedFromWindow() {
|
||||
super.onDetachedFromWindow();
|
||||
linkImageView.onDetachedFromWindow();
|
||||
MediaController.getInstance().removeLoadingFileObserver(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onAttachedToWindow() {
|
||||
super.onAttachedToWindow();
|
||||
linkImageView.onAttachedToWindow();
|
||||
if (linkImageView.onAttachedToWindow()) {
|
||||
updateButtonState(false);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMessageObject(MessageObject messageObject) {
|
||||
if (currentMessageObject != messageObject || isUserDataChanged()) {
|
||||
boolean dataChanged = currentMessageObject == messageObject && (isUserDataChanged() || photoNotSet);
|
||||
if (currentMessageObject != messageObject || dataChanged) {
|
||||
if (currentMessageObject != messageObject) {
|
||||
firstVisibleBlockNum = 0;
|
||||
lastVisibleBlockNum = 0;
|
||||
@ -321,6 +371,7 @@ public class ChatMessageCell extends ChatBaseCell {
|
||||
hasLinkPreview = false;
|
||||
resetPressedLink();
|
||||
linkPreviewPressed = false;
|
||||
buttonPressed = false;
|
||||
linkPreviewHeight = 0;
|
||||
isInstagram = false;
|
||||
durationLayout = null;
|
||||
@ -328,6 +379,10 @@ public class ChatMessageCell extends ChatBaseCell {
|
||||
titleLayout = null;
|
||||
siteNameLayout = null;
|
||||
authorLayout = null;
|
||||
drawImageButton = false;
|
||||
currentPhotoObject = null;
|
||||
currentPhotoObjectThumb = null;
|
||||
currentPhotoFilter = null;
|
||||
int maxWidth;
|
||||
|
||||
if (AndroidUtilities.isTablet()) {
|
||||
@ -352,13 +407,10 @@ public class ChatMessageCell extends ChatBaseCell {
|
||||
|
||||
backgroundWidth = maxWidth;
|
||||
|
||||
//Log.e("setMessageObject 1", "backgroundWidth " + backgroundWidth+" layoutWidth " + layoutWidth);
|
||||
|
||||
super.setMessageObject(messageObject);
|
||||
|
||||
backgroundWidth = messageObject.textWidth;
|
||||
totalHeight = messageObject.textHeight + AndroidUtilities.dp(19.5f) + namesOffset;
|
||||
//Log.e("setMessageObject 2", "backgroundWidth " + backgroundWidth+" namesOffset " + namesOffset);
|
||||
|
||||
int maxChildWidth = Math.max(backgroundWidth, nameWidth);
|
||||
maxChildWidth = Math.max(maxChildWidth, forwardedNameWidth);
|
||||
@ -551,9 +603,10 @@ public class ChatMessageCell extends ChatBaseCell {
|
||||
smallImage = false;
|
||||
isSmallImage = false;
|
||||
}
|
||||
drawImageButton = webPage.type != null && webPage.type.equals("photo");
|
||||
int maxPhotoWidth = smallImage ? AndroidUtilities.dp(48) : linkPreviewMaxWidth;
|
||||
TLRPC.PhotoSize currentPhotoObject = FileLoader.getClosestPhotoSizeWithSize(messageObject.photoThumbs, maxPhotoWidth, true);
|
||||
TLRPC.PhotoSize currentPhotoObjectThumb = FileLoader.getClosestPhotoSizeWithSize(messageObject.photoThumbs, 80);
|
||||
currentPhotoObject = FileLoader.getClosestPhotoSizeWithSize(messageObject.photoThumbs, drawImageButton ? AndroidUtilities.getPhotoSize() : maxPhotoWidth, !drawImageButton);
|
||||
currentPhotoObjectThumb = FileLoader.getClosestPhotoSizeWithSize(messageObject.photoThumbs, 80);
|
||||
if (currentPhotoObjectThumb == currentPhotoObject) {
|
||||
currentPhotoObjectThumb = null;
|
||||
}
|
||||
@ -606,11 +659,14 @@ public class ChatMessageCell extends ChatBaseCell {
|
||||
photoExist = false;
|
||||
}
|
||||
|
||||
String filter = String.format(Locale.US, "%d_%d", width, height);
|
||||
currentPhotoFilter = String.format(Locale.US, "%d_%d", width, height);
|
||||
currentPhotoFilterThumb = String.format(Locale.US, "%d_%d_b", width, height);
|
||||
|
||||
if (photoExist || MediaController.getInstance().canDownloadMedia(MediaController.AUTODOWNLOAD_MASK_PHOTO) || FileLoader.getInstance().isLoadingFile(fileName)) {
|
||||
linkImageView.setImage(currentPhotoObject.location, filter, currentPhotoObjectThumb != null ? currentPhotoObjectThumb.location : null, String.format(Locale.US, "%d_%d_b", width, height), 0, null, false);
|
||||
photoNotSet = false;
|
||||
linkImageView.setImage(currentPhotoObject.location, currentPhotoFilter, currentPhotoObjectThumb != null ? currentPhotoObjectThumb.location : null, currentPhotoFilterThumb, 0, null, false);
|
||||
} else {
|
||||
photoNotSet = true;
|
||||
if (currentPhotoObjectThumb != null) {
|
||||
linkImageView.setImage(null, null, currentPhotoObjectThumb.location, String.format(Locale.US, "%d_%d_b", width, height), 0, null, false);
|
||||
} else {
|
||||
@ -671,6 +727,7 @@ public class ChatMessageCell extends ChatBaseCell {
|
||||
|
||||
//Log.e("setMessageObject 3", "backgroundWidth " + backgroundWidth+" maxChildWidth " + maxChildWidth);
|
||||
}
|
||||
updateButtonState(dataChanged);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -813,8 +870,17 @@ public class ChatMessageCell extends ChatBaseCell {
|
||||
linkImageView.setImageCoords(textX + backgroundWidth - AndroidUtilities.dp(77), smallImageStartY, linkImageView.getImageWidth(), linkImageView.getImageHeight());
|
||||
} else {
|
||||
linkImageView.setImageCoords(textX + AndroidUtilities.dp(10), linkPreviewY, linkImageView.getImageWidth(), linkImageView.getImageHeight());
|
||||
if (drawImageButton) {
|
||||
int size = AndroidUtilities.dp(48);
|
||||
buttonX = (int) (linkImageView.getImageX() + (linkImageView.getImageWidth() - size) / 2.0f);
|
||||
buttonY = (int) (linkImageView.getImageY() + (linkImageView.getImageHeight() - size) / 2.0f) + namesOffset;
|
||||
radialProgress.setProgressRect(buttonX, buttonY, buttonX + AndroidUtilities.dp(48), buttonY + AndroidUtilities.dp(48));
|
||||
}
|
||||
}
|
||||
linkImageView.draw(canvas);
|
||||
if (drawImageButton) {
|
||||
radialProgress.draw(canvas);
|
||||
}
|
||||
|
||||
if (isInstagram && igvideoDrawable != null) {
|
||||
int x = linkImageView.getImageX() + linkImageView.getImageWidth() - igvideoDrawable.getIntrinsicWidth() - AndroidUtilities.dp(4);
|
||||
@ -837,4 +903,99 @@ public class ChatMessageCell extends ChatBaseCell {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Drawable getDrawableForCurrentState() {
|
||||
if (buttonState >= 0 && buttonState < 4) {
|
||||
if (buttonState == 1) {
|
||||
return ResourceLoader.buttonStatesDrawables[4];
|
||||
} else {
|
||||
return ResourceLoader.buttonStatesDrawables[buttonState];
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void updateButtonState(boolean animated) {
|
||||
if (currentPhotoObject == null || !drawImageButton) {
|
||||
return;
|
||||
}
|
||||
String fileName = FileLoader.getAttachFileName(currentPhotoObject);
|
||||
File cacheFile = FileLoader.getPathToAttach(currentPhotoObject, true);
|
||||
if (fileName == null) {
|
||||
radialProgress.setBackground(null, false, false);
|
||||
return;
|
||||
}
|
||||
if (!cacheFile.exists()) {
|
||||
MediaController.getInstance().addLoadingFileObserver(fileName, this);
|
||||
float setProgress = 0;
|
||||
boolean progressVisible = false;
|
||||
if (!FileLoader.getInstance().isLoadingFile(fileName)) {
|
||||
if (cancelLoading || !MediaController.getInstance().canDownloadMedia(MediaController.AUTODOWNLOAD_MASK_PHOTO)) {
|
||||
buttonState = 0;
|
||||
} else {
|
||||
progressVisible = true;
|
||||
buttonState = 1;
|
||||
}
|
||||
} else {
|
||||
progressVisible = true;
|
||||
buttonState = 1;
|
||||
Float progress = ImageLoader.getInstance().getFileProgress(fileName);
|
||||
setProgress = progress != null ? progress : 0;
|
||||
}
|
||||
radialProgress.setProgress(setProgress, false);
|
||||
radialProgress.setBackground(getDrawableForCurrentState(), progressVisible, animated);
|
||||
invalidate();
|
||||
} else {
|
||||
MediaController.getInstance().removeLoadingFileObserver(this);
|
||||
buttonState = -1;
|
||||
radialProgress.setBackground(getDrawableForCurrentState(), false, animated);
|
||||
invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
private void didPressedButton(boolean animated) {
|
||||
if (buttonState == 0) {
|
||||
cancelLoading = false;
|
||||
radialProgress.setProgress(0, false);
|
||||
linkImageView.setImage(currentPhotoObject.location, currentPhotoFilter, currentPhotoObjectThumb != null ? currentPhotoObjectThumb.location : null, currentPhotoFilterThumb, 0, null, false);
|
||||
buttonState = 1;
|
||||
radialProgress.setBackground(getDrawableForCurrentState(), true, animated);
|
||||
invalidate();
|
||||
} else if (buttonState == 1) {
|
||||
if (currentMessageObject.isOut() && currentMessageObject.isSending()) {
|
||||
if (delegate != null) {
|
||||
delegate.didPressedCancelSendButton(this);
|
||||
}
|
||||
} else {
|
||||
cancelLoading = true;
|
||||
linkImageView.cancelLoadImage();
|
||||
buttonState = 0;
|
||||
radialProgress.setBackground(getDrawableForCurrentState(), false, animated);
|
||||
invalidate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailedDownload(String fileName) {
|
||||
updateButtonState(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSuccessDownload(String fileName) {
|
||||
radialProgress.setProgress(1, true);
|
||||
if (!photoNotSet) {
|
||||
updateButtonState(true);
|
||||
} else {
|
||||
setMessageObject(currentMessageObject);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onProgressDownload(String fileName, float progress) {
|
||||
radialProgress.setProgress(progress, true);
|
||||
if (buttonState != 1) {
|
||||
updateButtonState(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -49,8 +49,9 @@ public class DrawerActionCell extends FrameLayout {
|
||||
textView.setText(text);
|
||||
//textView.setCompoundDrawablesWithIntrinsicBounds(resId, 0, 0, 0);
|
||||
int color = AndroidUtilities.getIntDef("drawerIconColor", 0xff737373);
|
||||
getResources().getDrawable(resId).setColorFilter(color, PorterDuff.Mode.SRC_IN);
|
||||
textView.setCompoundDrawablesWithIntrinsicBounds(getResources().getDrawable(resId), null, null, null);
|
||||
Drawable d = getResources().getDrawable(resId);
|
||||
d.setColorFilter(color, PorterDuff.Mode.SRC_IN);
|
||||
textView.setCompoundDrawablesWithIntrinsicBounds(d, null, null, null);
|
||||
}
|
||||
|
||||
public void setTextAndIcon(String text, Drawable drawable) {
|
||||
|
@ -40,9 +40,11 @@ public class ProfileSearchCell extends BaseCell {
|
||||
private static TextPaint nameEncryptedPaint;
|
||||
private static TextPaint onlinePaint;
|
||||
private static TextPaint offlinePaint;
|
||||
private static TextPaint countPaint;
|
||||
private static Drawable lockDrawable;
|
||||
private static Drawable broadcastDrawable;
|
||||
private static Drawable groupDrawable;
|
||||
private static Drawable countDrawable;
|
||||
private static Paint linePaint;
|
||||
|
||||
private CharSequence currentName;
|
||||
@ -53,6 +55,7 @@ public class ProfileSearchCell extends BaseCell {
|
||||
private TLRPC.User user = null;
|
||||
private TLRPC.Chat chat = null;
|
||||
private TLRPC.EncryptedChat encryptedChat = null;
|
||||
long dialog_id;
|
||||
|
||||
private String lastName = null;
|
||||
private int lastStatus = 0;
|
||||
@ -70,6 +73,13 @@ public class ProfileSearchCell extends BaseCell {
|
||||
private int nameLockLeft;
|
||||
private int nameLockTop;
|
||||
|
||||
private boolean drawCount;
|
||||
private int lastUnreadCount;
|
||||
private int countTop = AndroidUtilities.dp(25);
|
||||
private int countLeft;
|
||||
private int countWidth;
|
||||
private StaticLayout countLayout;
|
||||
|
||||
private int onlineLeft;
|
||||
private StaticLayout onlineLayout;
|
||||
|
||||
@ -100,9 +110,15 @@ public class ProfileSearchCell extends BaseCell {
|
||||
linePaint = new Paint();
|
||||
linePaint.setColor(0xffdcdcdc);
|
||||
|
||||
countPaint = new TextPaint(TextPaint.ANTI_ALIAS_FLAG);
|
||||
countPaint.setTextSize(AndroidUtilities.dp(13));
|
||||
countPaint.setColor(0xffffffff);
|
||||
countPaint.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf"));
|
||||
|
||||
broadcastDrawable = getResources().getDrawable(R.drawable.list_broadcast);
|
||||
lockDrawable = getResources().getDrawable(R.drawable.list_secret);
|
||||
groupDrawable = getResources().getDrawable(R.drawable.list_group);
|
||||
countDrawable = getResources().getDrawable(R.drawable.dialogs_badge);
|
||||
}
|
||||
|
||||
avatarImage = new ImageReceiver(this);
|
||||
@ -120,12 +136,13 @@ public class ProfileSearchCell extends BaseCell {
|
||||
return super.onTouchEvent(event);
|
||||
}
|
||||
|
||||
public void setData(TLRPC.User u, TLRPC.Chat c, TLRPC.EncryptedChat ec, CharSequence n, CharSequence s) {
|
||||
public void setData(TLRPC.User u, TLRPC.Chat c, TLRPC.EncryptedChat ec, CharSequence n, CharSequence s, boolean needCount) {
|
||||
currentName = n;
|
||||
user = u;
|
||||
chat = c;
|
||||
encryptedChat = ec;
|
||||
subLabel = s;
|
||||
drawCount = needCount;
|
||||
update(0);
|
||||
}
|
||||
|
||||
@ -167,6 +184,7 @@ public class ProfileSearchCell extends BaseCell {
|
||||
|
||||
if (encryptedChat != null) {
|
||||
drawNameLock = true;
|
||||
dialog_id = ((long) encryptedChat.id) << 32;
|
||||
if (!LocaleController.isRTL) {
|
||||
nameLockLeft = AndroidUtilities.dp(AndroidUtilities.leftBaseline);
|
||||
nameLeft = AndroidUtilities.dp(AndroidUtilities.leftBaseline + 4) + lockDrawable.getIntrinsicWidth();
|
||||
@ -177,11 +195,12 @@ public class ProfileSearchCell extends BaseCell {
|
||||
nameLockTop = AndroidUtilities.dp(16.5f);
|
||||
} else {
|
||||
if (chat != null) {
|
||||
|
||||
if (chat.id < 0) {
|
||||
dialog_id = AndroidUtilities.makeBroadcastId(chat.id);
|
||||
drawNameBroadcast = true;
|
||||
nameLockTop = AndroidUtilities.dp(28.5f);
|
||||
} else {
|
||||
dialog_id = -chat.id;
|
||||
drawNameGroup = true;
|
||||
nameLockTop = AndroidUtilities.dp(30);
|
||||
}
|
||||
@ -193,6 +212,7 @@ public class ProfileSearchCell extends BaseCell {
|
||||
nameLeft = AndroidUtilities.dp(11);
|
||||
}
|
||||
} else {
|
||||
dialog_id = user.id;
|
||||
if (!LocaleController.isRTL) {
|
||||
nameLeft = AndroidUtilities.dp(AndroidUtilities.leftBaseline);
|
||||
} else {
|
||||
@ -240,6 +260,30 @@ public class ProfileSearchCell extends BaseCell {
|
||||
nameWidth -= AndroidUtilities.dp(6) + groupDrawable.getIntrinsicWidth();
|
||||
}
|
||||
|
||||
if (drawCount) {
|
||||
TLRPC.TL_dialog dialog = MessagesController.getInstance().dialogs_dict.get(dialog_id);
|
||||
if (dialog != null && dialog.unread_count != 0) {
|
||||
lastUnreadCount = dialog.unread_count;
|
||||
String countString = String.format("%d", dialog.unread_count);
|
||||
countWidth = Math.max(AndroidUtilities.dp(12), (int) Math.ceil(countPaint.measureText(countString)));
|
||||
countLayout = new StaticLayout(countString, countPaint, countWidth, Layout.Alignment.ALIGN_CENTER, 1.0f, 0.0f, false);
|
||||
int w = countWidth + AndroidUtilities.dp(18);
|
||||
nameWidth -= w;
|
||||
if (!LocaleController.isRTL) {
|
||||
countLeft = getMeasuredWidth() - countWidth - AndroidUtilities.dp(19);
|
||||
} else {
|
||||
countLeft = AndroidUtilities.dp(19);
|
||||
nameLeft += w;
|
||||
}
|
||||
} else {
|
||||
lastUnreadCount = 0;
|
||||
countLayout = null;
|
||||
}
|
||||
} else {
|
||||
lastUnreadCount = 0;
|
||||
countLayout = null;
|
||||
}
|
||||
|
||||
CharSequence nameStringFinal = TextUtils.ellipsize(nameString, currentNamePaint, nameWidth - AndroidUtilities.dp(12), TextUtils.TruncateAt.END);
|
||||
nameLayout = new StaticLayout(nameStringFinal, currentNamePaint, nameWidth, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false);
|
||||
|
||||
@ -250,12 +294,12 @@ public class ProfileSearchCell extends BaseCell {
|
||||
onlineLeft = AndroidUtilities.dp(11);
|
||||
}
|
||||
|
||||
CharSequence onlineString;
|
||||
CharSequence onlineString = "";
|
||||
TextPaint currentOnlinePaint = offlinePaint;
|
||||
|
||||
if (subLabel != null) {
|
||||
onlineString = subLabel;
|
||||
} else {
|
||||
} else if (user != null) {
|
||||
if ((user.flags & TLRPC.USER_FLAG_BOT) != 0) {
|
||||
onlineString = LocaleController.getString("Bot", R.string.Bot);
|
||||
} else {
|
||||
@ -370,6 +414,12 @@ public class ProfileSearchCell extends BaseCell {
|
||||
continueUpdate = true;
|
||||
}
|
||||
}
|
||||
if (!continueUpdate && drawCount && (mask & MessagesController.UPDATE_MASK_READ_DIALOG_MESSAGE) != 0) {
|
||||
TLRPC.TL_dialog dialog = MessagesController.getInstance().dialogs_dict.get(dialog_id);
|
||||
if (dialog != null && dialog.unread_count != lastUnreadCount) {
|
||||
continueUpdate = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!continueUpdate) {
|
||||
return;
|
||||
@ -428,10 +478,12 @@ public class ProfileSearchCell extends BaseCell {
|
||||
broadcastDrawable.draw(canvas);
|
||||
}
|
||||
|
||||
if (nameLayout != null) {
|
||||
canvas.save();
|
||||
canvas.translate(nameLeft, nameTop);
|
||||
nameLayout.draw(canvas);
|
||||
canvas.restore();
|
||||
}
|
||||
|
||||
if (onlineLayout != null) {
|
||||
canvas.save();
|
||||
@ -440,6 +492,15 @@ public class ProfileSearchCell extends BaseCell {
|
||||
canvas.restore();
|
||||
}
|
||||
|
||||
if (countLayout != null) {
|
||||
setDrawableBounds(countDrawable, countLeft - AndroidUtilities.dp(5.5f), countTop, countWidth + AndroidUtilities.dp(11), countDrawable.getIntrinsicHeight());
|
||||
countDrawable.draw(canvas);
|
||||
canvas.save();
|
||||
canvas.translate(countLeft, countTop + AndroidUtilities.dp(4));
|
||||
countLayout.draw(canvas);
|
||||
canvas.restore();
|
||||
}
|
||||
|
||||
avatarImage.draw(canvas);
|
||||
}
|
||||
}
|
||||
|
@ -9,8 +9,12 @@
|
||||
package org.telegram.ui.Cells;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Canvas;
|
||||
import android.os.Build;
|
||||
import android.util.TypedValue;
|
||||
import android.view.Gravity;
|
||||
import android.view.View;
|
||||
import android.view.animation.AccelerateInterpolator;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
@ -26,6 +30,13 @@ public class StickerEmojiCell extends FrameLayout {
|
||||
private BackupImageView imageView;
|
||||
private TLRPC.Document sticker;
|
||||
private TextView emojiTextView;
|
||||
private float alpha = 1;
|
||||
private boolean changingAlpha;
|
||||
private long lastUpdateTime;
|
||||
private boolean scaled;
|
||||
private float scale;
|
||||
private long time = 0;
|
||||
private AccelerateInterpolator interpolator = new AccelerateInterpolator(0.5f);
|
||||
|
||||
public StickerEmojiCell(Context context) {
|
||||
super(context);
|
||||
@ -39,15 +50,6 @@ public class StickerEmojiCell extends FrameLayout {
|
||||
addView(emojiTextView, LayoutHelper.createFrame(28, 28, Gravity.BOTTOM | Gravity.RIGHT));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPressed(boolean pressed) {
|
||||
if (imageView.getImageReceiver().getPressed() != pressed) {
|
||||
imageView.getImageReceiver().setPressed(pressed);
|
||||
imageView.invalidate();
|
||||
}
|
||||
super.setPressed(pressed);
|
||||
}
|
||||
|
||||
public TLRPC.Document getSticker() {
|
||||
return sticker;
|
||||
}
|
||||
@ -78,4 +80,67 @@ public class StickerEmojiCell extends FrameLayout {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void disable() {
|
||||
changingAlpha = true;
|
||||
alpha = 0.5f;
|
||||
time = 0;
|
||||
imageView.getImageReceiver().setAlpha(alpha);
|
||||
imageView.invalidate();
|
||||
lastUpdateTime = System.currentTimeMillis();
|
||||
invalidate();
|
||||
}
|
||||
|
||||
public void setScaled(boolean value) {
|
||||
scaled = value;
|
||||
lastUpdateTime = System.currentTimeMillis();
|
||||
invalidate();
|
||||
}
|
||||
|
||||
public boolean isDisabled() {
|
||||
return changingAlpha;
|
||||
}
|
||||
|
||||
public boolean showingBitmap() {
|
||||
return imageView.getImageReceiver().getBitmap() != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
|
||||
boolean result = super.drawChild(canvas, child, drawingTime);
|
||||
if (child == imageView && (changingAlpha || scaled && scale != 0.8f || !scaled && scale != 1.0f)) {
|
||||
long newTime = System.currentTimeMillis();
|
||||
long dt = (newTime - lastUpdateTime);
|
||||
lastUpdateTime = newTime;
|
||||
if (changingAlpha) {
|
||||
time += dt;
|
||||
if (time > 1050) {
|
||||
time = 1050;
|
||||
}
|
||||
alpha = 0.5f + interpolator.getInterpolation(time / 1050.0f) * 0.5f;
|
||||
if (alpha >= 1.0f) {
|
||||
changingAlpha = false;
|
||||
alpha = 1.0f;
|
||||
}
|
||||
imageView.getImageReceiver().setAlpha(alpha);
|
||||
} else if (scaled && scale != 0.8f) {
|
||||
scale -= dt / 400.0f;
|
||||
if (scale < 0.8f) {
|
||||
scale = 0.8f;
|
||||
}
|
||||
} else {
|
||||
scale += dt / 400.0f;
|
||||
if (scale > 1.0f) {
|
||||
scale = 1.0f;
|
||||
}
|
||||
}
|
||||
if (Build.VERSION.SDK_INT >= 11) {
|
||||
imageView.setScaleX(scale);
|
||||
imageView.setScaleY(scale);
|
||||
}
|
||||
imageView.invalidate();
|
||||
invalidate();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
@ -128,6 +128,10 @@ public class UserCell extends FrameLayout {
|
||||
Drawable d = getResources().getDrawable(currentDrawable);
|
||||
d.setColorFilter(dColor, PorterDuff.Mode.SRC_IN);
|
||||
}
|
||||
}else if(tag.contains("Pref")){
|
||||
setStatusColors(themePrefs.getInt("prefSummaryColor", 0xff8a8a8a), AndroidUtilities.getIntDarkerColor("themeColor", -0x40));
|
||||
nameColor = themePrefs.getInt("prefTitleColor", 0xff212121);
|
||||
nameTextView.setTextColor(nameColor);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -287,10 +287,10 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not
|
||||
private final static int bot_help = 30;
|
||||
private final static int bot_settings = 31;
|
||||
|
||||
|
||||
private final static int attach_photo = 0;//6;
|
||||
private final static int attach_gallery = 1;//7;
|
||||
private final static int attach_video = 2;//8;
|
||||
|
||||
private final static int attach_audio = 3;
|
||||
private final static int attach_document = 4;//9;
|
||||
private final static int attach_contact = 5;
|
||||
@ -841,22 +841,30 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not
|
||||
|
||||
@Override
|
||||
public void onRevealAnimationStart(boolean open) {
|
||||
if (chatAttachView != null) {
|
||||
chatAttachView.onRevealAnimationStart(open);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRevealAnimationProgress(boolean open, float radius, int x, int y) {
|
||||
if (chatAttachView != null) {
|
||||
chatAttachView.onRevealAnimationProgress(open, radius, x, y);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRevealAnimationEnd(boolean open) {
|
||||
if (chatAttachView != null) {
|
||||
chatAttachView.onRevealAnimationEnd(open);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onOpenAnimationEnd() {
|
||||
if (chatAttachView != null) {
|
||||
chatAttachView.onRevealAnimationEnd(true);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -1134,8 +1142,6 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not
|
||||
|
||||
@Override
|
||||
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
||||
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
|
||||
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
|
||||
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
|
||||
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
|
||||
|
||||
@ -1436,8 +1442,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not
|
||||
} catch (Exception e) {
|
||||
FileLog.e("tmessages", e);
|
||||
}
|
||||
} else {
|
||||
if (SecretPhotoViewer.getInstance().isVisible()) {
|
||||
} else if (SecretPhotoViewer.getInstance().isVisible()) {
|
||||
AndroidUtilities.runOnUIThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
@ -1447,7 +1452,6 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not
|
||||
});
|
||||
SecretPhotoViewer.getInstance().closePhoto();
|
||||
}
|
||||
}
|
||||
} else if (event.getAction() != MotionEvent.ACTION_DOWN) {
|
||||
if (SecretPhotoViewer.getInstance().isVisible()) {
|
||||
return true;
|
||||
@ -1477,12 +1481,10 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not
|
||||
int x = (int) event.getX();
|
||||
int y = (int) event.getY();
|
||||
int count = chatListView.getChildCount();
|
||||
Rect rect = new Rect();
|
||||
for (int a = 0; a < count; a++) {
|
||||
View view = chatListView.getChildAt(a);
|
||||
int top = view.getTop();
|
||||
int bottom = view.getBottom();
|
||||
view.getLocalVisibleRect(rect);
|
||||
if (top > y || bottom < y) {
|
||||
continue;
|
||||
}
|
||||
@ -3372,8 +3374,9 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not
|
||||
if (extractUriFrom.contains("com.google.android.apps.photos.contentprovider")) {
|
||||
try {
|
||||
String firstExtraction = extractUriFrom.split("/1/")[1];
|
||||
if (firstExtraction.contains("/ACTUAL")) {
|
||||
firstExtraction = firstExtraction.replace("/ACTUAL", "");
|
||||
int index = firstExtraction.indexOf("/ACTUAL");
|
||||
if (index != -1) {
|
||||
firstExtraction = firstExtraction.substring(0, index);
|
||||
String secondExtraction = URLDecoder.decode(firstExtraction, "UTF-8");
|
||||
uri = Uri.parse(secondExtraction);
|
||||
}
|
||||
@ -4267,9 +4270,11 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not
|
||||
if (cell.getMessageObject() != null && cell.getMessageObject().getId() == mid) {
|
||||
MessageObject playing = cell.getMessageObject();
|
||||
MessageObject player = MediaController.getInstance().getPlayingMessageObject();
|
||||
if (player != null) {
|
||||
playing.audioProgress = player.audioProgress;
|
||||
playing.audioProgressSec = player.audioProgressSec;
|
||||
cell.updateProgress();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -5061,6 +5066,9 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not
|
||||
moveScrollToLastMessage();
|
||||
}
|
||||
} else if (option == 1) {
|
||||
if (getParentActivity() == null) {
|
||||
return;
|
||||
}
|
||||
final MessageObject finalSelectedObject = selectedObject;
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity());
|
||||
builder.setMessage(LocaleController.formatString("AreYouSureDeleteMessages", R.string.AreYouSureDeleteMessages, LocaleController.formatPluralString("messages", 1)));
|
||||
@ -5108,7 +5116,6 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not
|
||||
FileLog.e("tmessages", e);
|
||||
}
|
||||
} else if (option == 4) {
|
||||
String fileName = selectedObject.getFileName();
|
||||
String path = selectedObject.messageOwner.attachPath;
|
||||
if (path != null && path.length() > 0) {
|
||||
File temp = new File(path);
|
||||
@ -5446,8 +5453,8 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not
|
||||
MessageObject messageToOpen = null;
|
||||
ImageReceiver imageReceiver = null;
|
||||
View view = chatListView.getChildAt(a);
|
||||
if (view instanceof ChatMediaCell) {
|
||||
ChatMediaCell cell = (ChatMediaCell) view;
|
||||
if (view instanceof ChatBaseCell) {
|
||||
ChatBaseCell cell = (ChatBaseCell) view;
|
||||
MessageObject message = cell.getMessageObject();
|
||||
if (message != null && message.getId() == messageObject.getId()) {
|
||||
messageToOpen = message;
|
||||
@ -5671,7 +5678,6 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not
|
||||
@Override
|
||||
public void needOpenWebView(String url, String title, String originalUrl, int w, int h) {
|
||||
BottomSheet.Builder builder = new BottomSheet.Builder(mContext);
|
||||
|
||||
builder.setCustomView(new WebFrameLayout(mContext, builder.create(), title, originalUrl, url, w, h));
|
||||
builder.setUseFullWidth(true);
|
||||
showDialog(builder.create());
|
||||
@ -5681,12 +5687,9 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not
|
||||
public void didPressReplyMessage(ChatBaseCell cell, int id) {
|
||||
scrollToMessageId(id, cell.getMessageObject().getId(), true);
|
||||
}
|
||||
});
|
||||
if (view instanceof ChatMediaCell) {
|
||||
((ChatMediaCell) view).setAllowedToSetPhoto(openAnimationEnded);
|
||||
((ChatMediaCell) view).setMediaDelegate(new ChatMediaCell.ChatMediaCellDelegate() {
|
||||
|
||||
@Override
|
||||
public void didClickedImage(ChatMediaCell cell) {
|
||||
public void didClickedImage(ChatBaseCell cell) {
|
||||
MessageObject message = cell.getMessageObject();
|
||||
if (message.isSendError()) {
|
||||
createMenu(cell, false);
|
||||
@ -5694,7 +5697,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not
|
||||
} else if (message.isSending()) {
|
||||
return;
|
||||
}
|
||||
if (message.type == 1) {
|
||||
if (message.type == 1 || message.type == 0) {
|
||||
PhotoViewer.getInstance().setParentActivity(getParentActivity());
|
||||
PhotoViewer.getInstance().openPhoto(message, ChatActivity.this);
|
||||
} else if (message.type == 3) {
|
||||
@ -5770,7 +5773,10 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
if (view instanceof ChatMediaCell) {
|
||||
((ChatMediaCell) view).setAllowedToSetPhoto(openAnimationEnded);
|
||||
((ChatMediaCell) view).setMediaDelegate(new ChatMediaCell.ChatMediaCellDelegate() {
|
||||
@Override
|
||||
public void didPressedOther(ChatMediaCell cell) {
|
||||
createMenu(cell, true);
|
||||
|
@ -177,7 +177,7 @@ public class ChatActivityEnterView extends FrameLayoutFixed implements Notificat
|
||||
|
||||
emojiButton = new ImageView(context);
|
||||
//emojiButton.setImageResource(R.drawable.ic_msg_panel_smiles);
|
||||
Drawable emoji = parentActivity.getResources().getDrawable(R.drawable.ic_msg_panel_smiles);
|
||||
Drawable emoji = getResources().getDrawable(R.drawable.ic_msg_panel_smiles);
|
||||
SharedPreferences themePrefs = ApplicationLoader.applicationContext.getSharedPreferences(AndroidUtilities.THEME_PREFS, AndroidUtilities.THEME_PREFS_MODE);
|
||||
final int color = themePrefs.getInt("chatEditTextIconsColor", 0xffadadad);
|
||||
emoji.setColorFilter(color, PorterDuff.Mode.SRC_IN);
|
||||
@ -380,7 +380,7 @@ public class ChatActivityEnterView extends FrameLayoutFixed implements Notificat
|
||||
//audioSendButton.setImageResource(R.drawable.mic_button_states);
|
||||
//audioSendButton.setBackgroundColor(0xffffffff);
|
||||
audioSendButton.setSoundEffectsEnabled(false);
|
||||
Drawable mic = parentActivity.getResources().getDrawable(R.drawable.mic);
|
||||
Drawable mic = getResources().getDrawable(R.drawable.mic);
|
||||
mic.setColorFilter(color, PorterDuff.Mode.SRC_IN);
|
||||
audioSendButton.setImageDrawable(mic);
|
||||
audioSendButton.setBackgroundColor(0x00000000);
|
||||
@ -389,7 +389,7 @@ public class ChatActivityEnterView extends FrameLayoutFixed implements Notificat
|
||||
audioSendButton.setOnTouchListener(new View.OnTouchListener() {
|
||||
@Override
|
||||
public boolean onTouch(View view, MotionEvent motionEvent) {
|
||||
Drawable mic = parentActivity.getResources().getDrawable(R.drawable.mic);
|
||||
Drawable mic = getResources().getDrawable(R.drawable.mic);
|
||||
if (motionEvent.getAction() == MotionEvent.ACTION_DOWN) {
|
||||
mic.setColorFilter(0xffda564d, PorterDuff.Mode.SRC_IN);
|
||||
audioSendButton.setImageDrawable(mic);
|
||||
@ -495,7 +495,7 @@ public class ChatActivityEnterView extends FrameLayoutFixed implements Notificat
|
||||
private void updateTheme() {
|
||||
SharedPreferences themePrefs = ApplicationLoader.applicationContext.getSharedPreferences(AndroidUtilities.THEME_PREFS, AndroidUtilities.THEME_PREFS_MODE);
|
||||
int def = themePrefs.getInt("themeColor", AndroidUtilities.defColor);
|
||||
Drawable send = parentActivity.getResources().getDrawable(R.drawable.ic_send);
|
||||
Drawable send = getResources().getDrawable(R.drawable.ic_send);
|
||||
send.setColorFilter(themePrefs.getInt("chatSendIconColor", themePrefs.getInt("chatEditTextIconsColor", def)), PorterDuff.Mode.SRC_IN);
|
||||
sendButton.setImageDrawable(send);
|
||||
messageEditText.setTextColor(themePrefs.getInt("chatEditTextColor", 0xff000000));
|
||||
@ -1257,7 +1257,6 @@ public class ChatActivityEnterView extends FrameLayoutFixed implements Notificat
|
||||
private void showPopup(int show, int contentType) {
|
||||
SharedPreferences themePrefs = ApplicationLoader.applicationContext.getSharedPreferences(AndroidUtilities.THEME_PREFS, AndroidUtilities.THEME_PREFS_MODE);
|
||||
int color = themePrefs.getInt("chatEditTextIconsColor", 0xffadadad);
|
||||
Drawable d;
|
||||
if (show == 1) {
|
||||
if (contentType == 0 && emojiView == null) {
|
||||
if (parentActivity == null) {
|
||||
@ -1340,23 +1339,27 @@ public class ChatActivityEnterView extends FrameLayoutFixed implements Notificat
|
||||
if (sizeNotifierLayout != null) {
|
||||
emojiPadding = currentHeight;
|
||||
sizeNotifierLayout.requestLayout();
|
||||
try{
|
||||
if (contentType == 0) {
|
||||
d = getResources().getDrawable(R.drawable.ic_msg_panel_kb);
|
||||
Drawable d = getResources().getDrawable(R.drawable.ic_msg_panel_kb);
|
||||
d.setColorFilter(color, PorterDuff.Mode.SRC_IN);
|
||||
emojiButton.setImageDrawable(d);
|
||||
//emojiButton.setImageResource(R.drawable.ic_msg_panel_kb);
|
||||
} else if (contentType == 1) {
|
||||
d = getResources().getDrawable(R.drawable.ic_msg_panel_smiles);
|
||||
Drawable d = getResources().getDrawable(R.drawable.ic_msg_panel_smiles);
|
||||
d.setColorFilter(color, PorterDuff.Mode.SRC_IN);
|
||||
emojiButton.setImageDrawable(d);
|
||||
//emojiButton.setImageResource(R.drawable.ic_msg_panel_smiles);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
FileLog.e("tmessages", e);
|
||||
}
|
||||
updateBotButton();
|
||||
onWindowSizeChanged();
|
||||
}
|
||||
} else {
|
||||
if (emojiButton != null) {
|
||||
d = getResources().getDrawable(R.drawable.ic_msg_panel_smiles);
|
||||
Drawable d = getResources().getDrawable(R.drawable.ic_msg_panel_smiles);
|
||||
d.setColorFilter(color, PorterDuff.Mode.SRC_IN);
|
||||
emojiButton.setImageDrawable(d);
|
||||
//emojiButton.setImageResource(R.drawable.ic_msg_panel_smiles);
|
||||
|
@ -23,6 +23,7 @@ import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.AbsListView;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.BaseAdapter;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.GridView;
|
||||
@ -42,6 +43,7 @@ import org.telegram.messenger.R;
|
||||
import org.telegram.messenger.TLRPC;
|
||||
import org.telegram.ui.Cells.EmptyCell;
|
||||
import org.telegram.ui.Cells.StickerEmojiCell;
|
||||
import org.telegram.ui.StickerPreviewViewer;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
@ -57,8 +59,11 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific
|
||||
}
|
||||
|
||||
private ArrayList<EmojiGridAdapter> adapters = new ArrayList<>();
|
||||
private HashMap<Long, Integer> emojiUseHistory = new HashMap<>();
|
||||
private ArrayList<Long> recentEmoji = new ArrayList<>();
|
||||
private HashMap<Long, Integer> stickersUseHistory = new HashMap<>();
|
||||
private ArrayList<TLRPC.Document> recentStickers = new ArrayList<>();
|
||||
private HashMap<Long, Integer> stickerSetsUseCount = new HashMap<>();
|
||||
private ArrayList<TLRPC.TL_messages_stickerSet> stickerSets = new ArrayList<>();
|
||||
|
||||
private int[] icons = {
|
||||
@ -79,6 +84,13 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific
|
||||
private StickersGridAdapter stickersGridAdapter;
|
||||
private LinearLayout pagerSlidingTabStripContainer;
|
||||
private ScrollSlidingTabStrip scrollSlidingTabStrip;
|
||||
private GridView stickersGridView;
|
||||
private AdapterView.OnItemClickListener stickersOnItemClickListener;
|
||||
private Runnable openStickerPreviewRunnable;
|
||||
private StickerEmojiCell currentStickerPreviewCell;
|
||||
|
||||
private int startX;
|
||||
private int startY;
|
||||
|
||||
private int oldWidth;
|
||||
private int lastNotifyWidth;
|
||||
@ -96,7 +108,7 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific
|
||||
int tabColor = themePrefs.getInt("chatEmojiViewTabColor", AndroidUtilities.getIntDarkerColor("themeColor", -0x15));
|
||||
int lineColor = bgColor == 0xfff5f6f7 ? 0xffe2e5e7 : AndroidUtilities.setDarkColor(bgColor, 0x10);
|
||||
//setOrientation(LinearLayout.VERTICAL);
|
||||
for (int i = 0; i < Emoji.data.length; i++) {
|
||||
for (int i = 0; i < Emoji.data.length + 1; i++) {
|
||||
GridView gridView = new GridView(context);
|
||||
if (AndroidUtilities.isTablet()) {
|
||||
gridView.setColumnWidth(AndroidUtilities.dp(60));
|
||||
@ -106,7 +118,7 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific
|
||||
gridView.setNumColumns(-1);
|
||||
views.add(gridView);
|
||||
|
||||
EmojiGridAdapter emojiGridAdapter = new EmojiGridAdapter(Emoji.data[i]);
|
||||
EmojiGridAdapter emojiGridAdapter = new EmojiGridAdapter(i - 1);
|
||||
gridView.setAdapter(emojiGridAdapter);
|
||||
//AndroidUtilities.setListViewEdgeEffectColor(gridView, 0xfff5f6f7);
|
||||
AndroidUtilities.setListViewEdgeEffectColor(gridView, bgColor);
|
||||
@ -115,25 +127,187 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific
|
||||
|
||||
if (showStickers) {
|
||||
StickersQuery.checkStickers();
|
||||
GridView gridView = new GridView(context);
|
||||
gridView.setColumnWidth(AndroidUtilities.dp(72));
|
||||
gridView.setNumColumns(-1);
|
||||
gridView.setPadding(0, AndroidUtilities.dp(4), 0, 0);
|
||||
gridView.setClipToPadding(false);
|
||||
views.add(gridView);
|
||||
stickersGridView = new GridView(context) {
|
||||
@Override
|
||||
public boolean onInterceptTouchEvent(MotionEvent event) {
|
||||
if (event.getAction() == MotionEvent.ACTION_DOWN) {
|
||||
int x = (int) event.getX();
|
||||
int y = (int) event.getY();
|
||||
int count = stickersGridView.getChildCount();
|
||||
for (int a = 0; a < count; a++) {
|
||||
View view = stickersGridView.getChildAt(a);
|
||||
int top = view.getTop();
|
||||
int bottom = view.getBottom();
|
||||
int left = view.getLeft();
|
||||
int right = view.getRight();
|
||||
if (top > y || bottom < y || left > x || right < x) {
|
||||
continue;
|
||||
}
|
||||
if (!(view instanceof StickerEmojiCell) || !((StickerEmojiCell) view).showingBitmap()) {
|
||||
return super.onInterceptTouchEvent(event);
|
||||
}
|
||||
startX = x;
|
||||
startY = y;
|
||||
currentStickerPreviewCell = (StickerEmojiCell) view;
|
||||
openStickerPreviewRunnable = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (openStickerPreviewRunnable == null) {
|
||||
return;
|
||||
}
|
||||
stickersGridView.setOnItemClickListener(null);
|
||||
stickersGridView.requestDisallowInterceptTouchEvent(true);
|
||||
openStickerPreviewRunnable = null;
|
||||
StickerPreviewViewer.getInstance().setParentActivity((Activity) getContext());
|
||||
StickerPreviewViewer.getInstance().setKeyboardHeight(EmojiView.this.getMeasuredHeight());
|
||||
StickerPreviewViewer.getInstance().open(currentStickerPreviewCell.getSticker());
|
||||
currentStickerPreviewCell.setScaled(true);
|
||||
}
|
||||
};
|
||||
AndroidUtilities.runOnUIThread(openStickerPreviewRunnable, 200);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
stickersGridView.setSelector(R.drawable.transparent);
|
||||
stickersGridView.setColumnWidth(AndroidUtilities.dp(72));
|
||||
stickersGridView.setNumColumns(-1);
|
||||
stickersGridView.setPadding(0, AndroidUtilities.dp(4), 0, 0);
|
||||
stickersGridView.setClipToPadding(false);
|
||||
views.add(stickersGridView);
|
||||
stickersGridAdapter = new StickersGridAdapter(context);
|
||||
gridView.setAdapter(stickersGridAdapter);
|
||||
//AndroidUtilities.setListViewEdgeEffectColor(gridView, 0xfff5f6f7);
|
||||
AndroidUtilities.setListViewEdgeEffectColor(gridView, bgColor);
|
||||
stickersGridView.setAdapter(stickersGridAdapter);
|
||||
stickersGridView.setOnTouchListener(new OnTouchListener() {
|
||||
@Override
|
||||
public boolean onTouch(View v, MotionEvent event) {
|
||||
if (openStickerPreviewRunnable != null || StickerPreviewViewer.getInstance().isVisible()) {
|
||||
if (event.getAction() == MotionEvent.ACTION_UP || event.getAction() == MotionEvent.ACTION_CANCEL || event.getAction() == MotionEvent.ACTION_POINTER_UP) {
|
||||
AndroidUtilities.runOnUIThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
stickersGridView.setOnItemClickListener(stickersOnItemClickListener);
|
||||
}
|
||||
}, 150);
|
||||
if (openStickerPreviewRunnable != null) {
|
||||
AndroidUtilities.cancelRunOnUIThread(openStickerPreviewRunnable);
|
||||
openStickerPreviewRunnable = null;
|
||||
} else if (StickerPreviewViewer.getInstance().isVisible()) {
|
||||
StickerPreviewViewer.getInstance().close();
|
||||
if (currentStickerPreviewCell != null) {
|
||||
currentStickerPreviewCell.setScaled(false);
|
||||
currentStickerPreviewCell = null;
|
||||
}
|
||||
}
|
||||
} else if (event.getAction() != MotionEvent.ACTION_DOWN) {
|
||||
if (StickerPreviewViewer.getInstance().isVisible()) {
|
||||
if (event.getAction() == MotionEvent.ACTION_MOVE) {
|
||||
int x = (int) event.getX();
|
||||
int y = (int) event.getY();
|
||||
int count = stickersGridView.getChildCount();
|
||||
for (int a = 0; a < count; a++) {
|
||||
View view = stickersGridView.getChildAt(a);
|
||||
int top = view.getTop();
|
||||
int bottom = view.getBottom();
|
||||
int left = view.getLeft();
|
||||
int right = view.getRight();
|
||||
if (top > y || bottom < y || left > x || right < x) {
|
||||
continue;
|
||||
}
|
||||
if (!(view instanceof StickerEmojiCell) || view == currentStickerPreviewCell) {
|
||||
break;
|
||||
}
|
||||
if (currentStickerPreviewCell != null) {
|
||||
currentStickerPreviewCell.setScaled(false);
|
||||
}
|
||||
currentStickerPreviewCell = (StickerEmojiCell) view;
|
||||
StickerPreviewViewer.getInstance().setKeyboardHeight(EmojiView.this.getMeasuredHeight());
|
||||
StickerPreviewViewer.getInstance().open(currentStickerPreviewCell.getSticker());
|
||||
currentStickerPreviewCell.setScaled(true);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
} else if (openStickerPreviewRunnable != null) {
|
||||
if (event.getAction() == MotionEvent.ACTION_MOVE) {
|
||||
if (Math.hypot(startX - event.getX(), startY - event.getY()) > AndroidUtilities.dp(10)) {
|
||||
AndroidUtilities.cancelRunOnUIThread(openStickerPreviewRunnable);
|
||||
openStickerPreviewRunnable = null;
|
||||
}
|
||||
} else {
|
||||
AndroidUtilities.cancelRunOnUIThread(openStickerPreviewRunnable);
|
||||
openStickerPreviewRunnable = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
});
|
||||
stickersOnItemClickListener = new AdapterView.OnItemClickListener() {
|
||||
@Override
|
||||
public void onItemClick(AdapterView<?> parent, View view, int position, long i) {
|
||||
if (!(view instanceof StickerEmojiCell)) {
|
||||
return;
|
||||
}
|
||||
if (openStickerPreviewRunnable != null) {
|
||||
AndroidUtilities.cancelRunOnUIThread(openStickerPreviewRunnable);
|
||||
openStickerPreviewRunnable = null;
|
||||
}
|
||||
if (currentStickerPreviewCell != null) {
|
||||
currentStickerPreviewCell.setScaled(false);
|
||||
currentStickerPreviewCell = null;
|
||||
}
|
||||
StickerEmojiCell cell = (StickerEmojiCell) view;
|
||||
if (cell.isDisabled()) {
|
||||
return;
|
||||
}
|
||||
cell.disable();
|
||||
TLRPC.Document document = cell.getSticker();
|
||||
Integer count = stickersUseHistory.get(document.id);
|
||||
if (count == null) {
|
||||
count = 0;
|
||||
}
|
||||
if (count == 0 && stickersUseHistory.size() > 19) {
|
||||
for (int a = recentStickers.size() - 1; a >= 0; a--) {
|
||||
TLRPC.Document sticker = recentStickers.get(a);
|
||||
stickersUseHistory.remove(sticker.id);
|
||||
recentStickers.remove(a);
|
||||
if (stickersUseHistory.size() <= 19) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
stickersUseHistory.put(document.id, ++count);
|
||||
|
||||
long id = StickersQuery.getStickerSetId(document);
|
||||
if (id != -1) {
|
||||
count = stickerSetsUseCount.get(id);
|
||||
if (count == null) {
|
||||
count = 0;
|
||||
}
|
||||
stickerSetsUseCount.put(id, ++count);
|
||||
}
|
||||
|
||||
saveRecentStickers();
|
||||
if (listener != null) {
|
||||
listener.onStickerSelected(document);
|
||||
}
|
||||
}
|
||||
};
|
||||
stickersGridView.setOnItemClickListener(stickersOnItemClickListener);
|
||||
AndroidUtilities.setListViewEdgeEffectColor(stickersGridView, 0xfff5f6f7);
|
||||
|
||||
stickersWrap = new FrameLayout(context);
|
||||
stickersWrap.addView(gridView);
|
||||
stickersWrap.addView(stickersGridView);
|
||||
|
||||
TextView textView = new TextView(context);
|
||||
textView.setText(LocaleController.getString("NoStickers", R.string.NoStickers));
|
||||
textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 18);
|
||||
textView.setTextColor(0xff888888);
|
||||
stickersWrap.addView(textView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER));
|
||||
gridView.setEmptyView(textView);
|
||||
stickersGridView.setEmptyView(textView);
|
||||
|
||||
scrollSlidingTabStrip = new ScrollSlidingTabStrip(context) {
|
||||
|
||||
@ -226,7 +400,7 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific
|
||||
}
|
||||
});
|
||||
|
||||
gridView.setOnScrollListener(new AbsListView.OnScrollListener() {
|
||||
stickersGridView.setOnScrollListener(new AbsListView.OnScrollListener() {
|
||||
@Override
|
||||
public void onScrollStateChanged(AbsListView view, int scrollState) {
|
||||
|
||||
@ -246,7 +420,6 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific
|
||||
scrollSlidingTabStrip.onPageScrolled(stickersGridAdapter.getTabForPosition(firstVisibleItem) + 1, 0);
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
//setBackgroundColor(0xfff5f6f7);
|
||||
@ -317,7 +490,7 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific
|
||||
} else if (event.getAction() == MotionEvent.ACTION_CANCEL || event.getAction() == MotionEvent.ACTION_UP) {
|
||||
backspacePressed = false;
|
||||
if (!backspaceOnce) {
|
||||
if (EmojiView.this.listener != null && EmojiView.this.listener.onBackspace()) {
|
||||
if (listener != null && listener.onBackspace()) {
|
||||
backspaceButton.performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP);
|
||||
}
|
||||
}
|
||||
@ -397,7 +570,7 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific
|
||||
if (!backspacePressed) {
|
||||
return;
|
||||
}
|
||||
if (EmojiView.this.listener != null && EmojiView.this.listener.onBackspace()) {
|
||||
if (listener != null && listener.onBackspace()) {
|
||||
backspaceButton.performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP);
|
||||
}
|
||||
backspaceOnce = true;
|
||||
@ -406,33 +579,6 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific
|
||||
}, time);
|
||||
}
|
||||
|
||||
private void addToRecent(long code) {
|
||||
if (pager.getCurrentItem() == 0) {
|
||||
return;
|
||||
}
|
||||
ArrayList<Long> recent = new ArrayList<>();
|
||||
long[] currentRecent = Emoji.data[0];
|
||||
boolean was = false;
|
||||
for (long aCurrentRecent : currentRecent) {
|
||||
if (code == aCurrentRecent) {
|
||||
recent.add(0, code);
|
||||
was = true;
|
||||
} else {
|
||||
recent.add(aCurrentRecent);
|
||||
}
|
||||
}
|
||||
if (!was) {
|
||||
recent.add(0, code);
|
||||
}
|
||||
Emoji.data[0] = new long[Math.min(recent.size(), 50)];
|
||||
for (int q = 0; q < Emoji.data[0].length; q++) {
|
||||
Emoji.data[0][q] = recent.get(q);
|
||||
}
|
||||
adapters.get(0).data = Emoji.data[0];
|
||||
adapters.get(0).notifyDataSetChanged();
|
||||
saveRecents();
|
||||
}
|
||||
|
||||
private String convert(long paramLong) {
|
||||
String str = "";
|
||||
for (int i = 0; ; i++) {
|
||||
@ -446,16 +592,22 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific
|
||||
}
|
||||
}
|
||||
|
||||
private void saveRecents() {
|
||||
ArrayList<Long> arrayList = new ArrayList<>(Emoji.data[0].length);
|
||||
for (int j = 0; j < Emoji.data[0].length; j++) {
|
||||
arrayList.add(Emoji.data[0][j]);
|
||||
private void saveRecentEmoji() {
|
||||
SharedPreferences preferences = getContext().getSharedPreferences("emoji", Activity.MODE_PRIVATE);
|
||||
StringBuilder stringBuilder = new StringBuilder();
|
||||
for (HashMap.Entry<Long, Integer> entry : emojiUseHistory.entrySet()) {
|
||||
if (stringBuilder.length() != 0) {
|
||||
stringBuilder.append(",");
|
||||
}
|
||||
getContext().getSharedPreferences("emoji", 0).edit().putString("recents", TextUtils.join(",", arrayList)).commit();
|
||||
stringBuilder.append(entry.getKey());
|
||||
stringBuilder.append("=");
|
||||
stringBuilder.append(entry.getValue());
|
||||
}
|
||||
preferences.edit().putString("emojis", stringBuilder.toString()).commit();
|
||||
}
|
||||
|
||||
private void saveRecentStickers() {
|
||||
SharedPreferences preferences = getContext().getSharedPreferences("emoji", Activity.MODE_PRIVATE);
|
||||
SharedPreferences.Editor editor = getContext().getSharedPreferences("emoji", Activity.MODE_PRIVATE).edit();
|
||||
StringBuilder stringBuilder = new StringBuilder();
|
||||
for (HashMap.Entry<Long, Integer> entry : stickersUseHistory.entrySet()) {
|
||||
if (stringBuilder.length() != 0) {
|
||||
@ -465,7 +617,64 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific
|
||||
stringBuilder.append("=");
|
||||
stringBuilder.append(entry.getValue());
|
||||
}
|
||||
preferences.edit().putString("stickers", stringBuilder.toString()).commit();
|
||||
editor.putString("stickers", stringBuilder.toString());
|
||||
|
||||
ArrayList<Long> toRemove = null;
|
||||
for (HashMap.Entry<Long, Integer> entry : stickerSetsUseCount.entrySet()) {
|
||||
if (!StickersQuery.isStickerPackInstalled(entry.getKey())) {
|
||||
if (toRemove == null) {
|
||||
toRemove = new ArrayList<>();
|
||||
}
|
||||
toRemove.add(entry.getKey());
|
||||
}
|
||||
}
|
||||
if (toRemove != null) {
|
||||
for (int a = 0; a < toRemove.size(); a++) {
|
||||
stickerSetsUseCount.remove(toRemove.get(a));
|
||||
}
|
||||
}
|
||||
|
||||
stringBuilder.setLength(0);
|
||||
for (HashMap.Entry<Long, Integer> entry : stickerSetsUseCount.entrySet()) {
|
||||
if (stringBuilder.length() != 0) {
|
||||
stringBuilder.append(",");
|
||||
}
|
||||
stringBuilder.append(entry.getKey());
|
||||
stringBuilder.append("=");
|
||||
stringBuilder.append(entry.getValue());
|
||||
}
|
||||
editor.putString("sets", stringBuilder.toString());
|
||||
|
||||
editor.commit();
|
||||
}
|
||||
|
||||
private void sortEmoji() {
|
||||
recentEmoji.clear();
|
||||
for (HashMap.Entry<Long, Integer> entry : emojiUseHistory.entrySet()) {
|
||||
recentEmoji.add(entry.getKey());
|
||||
}
|
||||
Collections.sort(recentEmoji, new Comparator<Long>() {
|
||||
@Override
|
||||
public int compare(Long lhs, Long rhs) {
|
||||
Integer count1 = emojiUseHistory.get(lhs);
|
||||
Integer count2 = emojiUseHistory.get(rhs);
|
||||
if (count1 == null) {
|
||||
count1 = 0;
|
||||
}
|
||||
if (count2 == null) {
|
||||
count2 = 0;
|
||||
}
|
||||
if (count1 > count2) {
|
||||
return -1;
|
||||
} else if (count1 < count2) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
});
|
||||
while (recentEmoji.size() > 50) {
|
||||
recentEmoji.remove(recentEmoji.size() - 1);
|
||||
}
|
||||
}
|
||||
|
||||
private void sortStickers() {
|
||||
@ -482,11 +691,9 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific
|
||||
hashMap.put(sticker.id, entry.getValue());
|
||||
}
|
||||
}
|
||||
if (!stickersUseHistory.isEmpty()) {
|
||||
stickersUseHistory = hashMap;
|
||||
saveRecents();
|
||||
} else {
|
||||
if (stickersUseHistory.size() != hashMap.size()) {
|
||||
stickersUseHistory = hashMap;
|
||||
saveRecentStickers();
|
||||
}
|
||||
Collections.sort(recentStickers, new Comparator<TLRPC.Document>() {
|
||||
@Override
|
||||
@ -526,34 +733,81 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific
|
||||
continue;
|
||||
}
|
||||
stickerSets.add(pack);
|
||||
scrollSlidingTabStrip.addStickerTab(pack.documents.get(0));
|
||||
}
|
||||
Collections.sort(stickerSets, new Comparator<TLRPC.TL_messages_stickerSet>() {
|
||||
@Override
|
||||
public int compare(TLRPC.TL_messages_stickerSet lhs, TLRPC.TL_messages_stickerSet rhs) {
|
||||
Integer count1 = stickerSetsUseCount.get(lhs.set.id);
|
||||
Integer count2 = stickerSetsUseCount.get(rhs.set.id);
|
||||
if (count1 == null) {
|
||||
count1 = 0;
|
||||
}
|
||||
if (count2 == null) {
|
||||
count2 = 0;
|
||||
}
|
||||
if (count1 > count2) {
|
||||
return -1;
|
||||
} else if (count1 < count2) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
});
|
||||
for (int a = 0; a < stickerSets.size(); a++) {
|
||||
scrollSlidingTabStrip.addStickerTab(stickerSets.get(a).documents.get(0));
|
||||
}
|
||||
scrollSlidingTabStrip.updateTabStyles();
|
||||
}
|
||||
|
||||
public void loadRecents() {
|
||||
String str;
|
||||
SharedPreferences preferences = getContext().getSharedPreferences("emoji", Activity.MODE_PRIVATE);
|
||||
String str = preferences.getString("recents", "");
|
||||
|
||||
if (preferences.contains("recents")) {
|
||||
try {
|
||||
str = preferences.getString("recents", "");
|
||||
if (str != null && str.length() > 0) {
|
||||
String[] args = str.split(",");
|
||||
Emoji.data[0] = new long[args.length];
|
||||
for (int i = 0; i < args.length; i++) {
|
||||
Emoji.data[0][i] = Long.parseLong(args[i]);
|
||||
emojiUseHistory.put(Long.parseLong(args[i]), args.length - i);
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
FileLog.e("tmessages", e);
|
||||
}
|
||||
sortEmoji();
|
||||
preferences.edit().remove("recents").commit();
|
||||
saveRecentEmoji();
|
||||
adapters.get(0).notifyDataSetChanged();
|
||||
} else {
|
||||
Emoji.data[0] = new long[]{0x00000000D83DDE02L, 0x00000000D83DDE18L, 0x0000000000002764L, 0x00000000D83DDE0DL, 0x00000000D83DDE0AL, 0x00000000D83DDE01L,
|
||||
try {
|
||||
emojiUseHistory.clear();
|
||||
str = preferences.getString("emojis", "");
|
||||
if (str != null && str.length() > 0) {
|
||||
String[] args = str.split(",");
|
||||
for (String arg : args) {
|
||||
String[] args2 = arg.split("=");
|
||||
emojiUseHistory.put(Long.parseLong(args2[0]), Integer.parseInt(args2[1]));
|
||||
}
|
||||
}
|
||||
if (emojiUseHistory.isEmpty()) {
|
||||
long[] newRecent = new long[]{0x00000000D83DDE02L, 0x00000000D83DDE18L, 0x0000000000002764L, 0x00000000D83DDE0DL, 0x00000000D83DDE0AL, 0x00000000D83DDE01L,
|
||||
0x00000000D83DDC4DL, 0x000000000000263AL, 0x00000000D83DDE14L, 0x00000000D83DDE04L, 0x00000000D83DDE2DL, 0x00000000D83DDC8BL,
|
||||
0x00000000D83DDE12L, 0x00000000D83DDE33L, 0x00000000D83DDE1CL, 0x00000000D83DDE48L, 0x00000000D83DDE09L, 0x00000000D83DDE03L,
|
||||
0x00000000D83DDE22L, 0x00000000D83DDE1DL, 0x00000000D83DDE31L, 0x00000000D83DDE21L, 0x00000000D83DDE0FL, 0x00000000D83DDE1EL,
|
||||
0x00000000D83DDE05L, 0x00000000D83DDE1AL, 0x00000000D83DDE4AL, 0x00000000D83DDE0CL, 0x00000000D83DDE00L, 0x00000000D83DDE0BL,
|
||||
0x00000000D83DDE06L, 0x00000000D83DDC4CL, 0x00000000D83DDE10L, 0x00000000D83DDE15L};
|
||||
for (int i = 0; i < newRecent.length; i++) {
|
||||
emojiUseHistory.put(newRecent[i], newRecent.length - i);
|
||||
}
|
||||
adapters.get(0).data = Emoji.data[0];
|
||||
saveRecentEmoji();
|
||||
}
|
||||
sortEmoji();
|
||||
adapters.get(0).notifyDataSetChanged();
|
||||
} catch (Exception e) {
|
||||
FileLog.e("tmessages", e);
|
||||
}
|
||||
}
|
||||
|
||||
if (showStickers) {
|
||||
try {
|
||||
@ -566,6 +820,16 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific
|
||||
stickersUseHistory.put(Long.parseLong(args2[0]), Integer.parseInt(args2[1]));
|
||||
}
|
||||
}
|
||||
|
||||
stickerSetsUseCount.clear();
|
||||
str = preferences.getString("sets", "");
|
||||
if (str != null && str.length() > 0) {
|
||||
String[] args = str.split(",");
|
||||
for (String arg : args) {
|
||||
String[] args2 = arg.split("=");
|
||||
stickerSetsUseCount.put(Long.parseLong(args2[0]), Integer.parseInt(args2[1]));
|
||||
}
|
||||
}
|
||||
sortStickers();
|
||||
updateStickerTabs();
|
||||
} catch (Exception e) {
|
||||
@ -600,11 +864,26 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific
|
||||
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
|
||||
if (lastNotifyWidth != right - left) {
|
||||
lastNotifyWidth = right - left;
|
||||
reloadStickersAdapter();
|
||||
}
|
||||
super.onLayout(changed, left, top, right, bottom);
|
||||
}
|
||||
|
||||
private void reloadStickersAdapter() {
|
||||
if (stickersGridAdapter != null) {
|
||||
stickersGridAdapter.notifyDataSetChanged();
|
||||
}
|
||||
if (StickerPreviewViewer.getInstance().isVisible()) {
|
||||
StickerPreviewViewer.getInstance().close();
|
||||
}
|
||||
if (openStickerPreviewRunnable != null) {
|
||||
AndroidUtilities.cancelRunOnUIThread(openStickerPreviewRunnable);
|
||||
openStickerPreviewRunnable = null;
|
||||
}
|
||||
if (currentStickerPreviewCell != null) {
|
||||
currentStickerPreviewCell.setScaled(false);
|
||||
currentStickerPreviewCell = null;
|
||||
}
|
||||
super.onLayout(changed, left, top, right, bottom);
|
||||
}
|
||||
|
||||
public void setListener(Listener value) {
|
||||
@ -630,11 +909,15 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific
|
||||
@Override
|
||||
public void setVisibility(int visibility) {
|
||||
super.setVisibility(visibility);
|
||||
if (visibility != GONE && stickersGridAdapter != null) {
|
||||
if (visibility != GONE) {
|
||||
sortEmoji();
|
||||
adapters.get(0).notifyDataSetChanged();
|
||||
if (stickersGridAdapter != null) {
|
||||
NotificationCenter.getInstance().addObserver(this, NotificationCenter.stickersDidLoaded);
|
||||
sortStickers();
|
||||
updateStickerTabs();
|
||||
stickersGridAdapter.notifyDataSetChanged();
|
||||
reloadStickersAdapter();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -650,7 +933,7 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific
|
||||
public void didReceivedNotification(int id, Object... args) {
|
||||
if (id == NotificationCenter.stickersDidLoaded) {
|
||||
updateStickerTabs();
|
||||
stickersGridAdapter.notifyDataSetChanged();
|
||||
reloadStickersAdapter();
|
||||
}
|
||||
}
|
||||
|
||||
@ -731,31 +1014,6 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific
|
||||
super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(82), MeasureSpec.EXACTLY));
|
||||
}
|
||||
};
|
||||
view.setOnClickListener(new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
if (listener != null) {
|
||||
TLRPC.Document document = ((StickerEmojiCell) v).getSticker();
|
||||
Integer count = stickersUseHistory.get(document.id);
|
||||
if (count == null) {
|
||||
count = 0;
|
||||
}
|
||||
if (count == 0 && stickersUseHistory.size() > 19) {
|
||||
for (int a = recentStickers.size() - 1; a >= 0; a--) {
|
||||
TLRPC.Document sticker = recentStickers.get(a);
|
||||
stickersUseHistory.remove(sticker.id);
|
||||
recentStickers.remove(a);
|
||||
if (stickersUseHistory.size() <= 19) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
stickersUseHistory.put(document.id, ++count);
|
||||
saveRecentStickers();
|
||||
listener.onStickerSelected(document);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
((StickerEmojiCell) view).setSticker(sticker, false);
|
||||
} else {
|
||||
@ -825,45 +1083,76 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific
|
||||
}
|
||||
|
||||
private class EmojiGridAdapter extends BaseAdapter {
|
||||
long[] data;
|
||||
|
||||
public EmojiGridAdapter(long[] arg2) {
|
||||
this.data = arg2;
|
||||
private int emojiPage;
|
||||
|
||||
public EmojiGridAdapter(int page) {
|
||||
emojiPage = page;
|
||||
}
|
||||
|
||||
public int getCount() {
|
||||
return data.length;
|
||||
if (emojiPage == -1) {
|
||||
return recentEmoji.size();
|
||||
}
|
||||
return Emoji.data[emojiPage].length;
|
||||
}
|
||||
|
||||
public Object getItem(int i) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public long getItemId(int i) {
|
||||
return data[i];
|
||||
@Override
|
||||
public long getItemId(int position) {
|
||||
return position;
|
||||
}
|
||||
|
||||
public View getView(int i, View view, ViewGroup paramViewGroup) {
|
||||
ImageView imageView = (ImageView)view;
|
||||
if (imageView == null) {
|
||||
imageView = new ImageView(EmojiView.this.getContext()) {
|
||||
public void onMeasure(int paramAnonymousInt1, int paramAnonymousInt2) {
|
||||
setMeasuredDimension(View.MeasureSpec.getSize(paramAnonymousInt1), View.MeasureSpec.getSize(paramAnonymousInt1));
|
||||
imageView = new ImageView(getContext()) {
|
||||
public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
||||
setMeasuredDimension(View.MeasureSpec.getSize(widthMeasureSpec), View.MeasureSpec.getSize(widthMeasureSpec));
|
||||
}
|
||||
};
|
||||
imageView.setOnClickListener(new View.OnClickListener() {
|
||||
public void onClick(View view) {
|
||||
if (EmojiView.this.listener != null) {
|
||||
EmojiView.this.listener.onEmojiSelected(EmojiView.this.convert((Long)view.getTag()));
|
||||
Long code = (Long) view.getTag();
|
||||
Integer count = emojiUseHistory.get(code);
|
||||
if (count == null) {
|
||||
count = 0;
|
||||
}
|
||||
if (count == 0 && emojiUseHistory.size() > 50) {
|
||||
for (int a = recentEmoji.size() - 1; a >= 0; a--) {
|
||||
Long emoji = recentEmoji.get(a);
|
||||
emojiUseHistory.remove(emoji);
|
||||
recentEmoji.remove(a);
|
||||
if (emojiUseHistory.size() <= 50) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
emojiUseHistory.put(code, ++count);
|
||||
if (pager.getCurrentItem() != 0) {
|
||||
sortEmoji();
|
||||
}
|
||||
saveRecentEmoji();
|
||||
adapters.get(0).notifyDataSetChanged();
|
||||
if (listener != null) {
|
||||
listener.onEmojiSelected(convert((Long)view.getTag()));
|
||||
}
|
||||
EmojiView.this.addToRecent((Long)view.getTag());
|
||||
}
|
||||
});
|
||||
imageView.setBackgroundResource(R.drawable.list_selector);
|
||||
imageView.setScaleType(ImageView.ScaleType.CENTER);
|
||||
}
|
||||
imageView.setImageDrawable(Emoji.getEmojiBigDrawable(data[i]));
|
||||
imageView.setTag(data[i]);
|
||||
long code;
|
||||
if (emojiPage == -1) {
|
||||
code = recentEmoji.get(i);
|
||||
} else {
|
||||
code = Emoji.data[emojiPage][i];
|
||||
}
|
||||
imageView.setImageDrawable(Emoji.getEmojiBigDrawable(code));
|
||||
imageView.setTag(code);
|
||||
return imageView;
|
||||
}
|
||||
|
||||
|
@ -135,7 +135,7 @@ public class RadialProgress {
|
||||
return previousDrawable != null || currentDrawable != null ? animatedAlphaValue : 0.0f;
|
||||
}
|
||||
|
||||
public void onDraw(Canvas canvas) {
|
||||
public void draw(Canvas canvas) {
|
||||
if (previousDrawable != null) {
|
||||
previousDrawable.setAlpha((int)(255 * animatedAlphaValue));
|
||||
previousDrawable.setBounds((int)progressRect.left, (int)progressRect.top, (int)progressRect.right, (int)progressRect.bottom);
|
||||
|
@ -8,6 +8,7 @@
|
||||
|
||||
package org.telegram.ui.Components;
|
||||
|
||||
import android.content.SharedPreferences;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.ColorFilter;
|
||||
import android.graphics.Paint;
|
||||
@ -15,6 +16,7 @@ import android.graphics.RectF;
|
||||
import android.graphics.drawable.Drawable;
|
||||
|
||||
import org.telegram.android.AndroidUtilities;
|
||||
import org.telegram.messenger.ApplicationLoader;
|
||||
|
||||
public class RecordStatusDrawable extends Drawable {
|
||||
|
||||
@ -27,7 +29,9 @@ public class RecordStatusDrawable extends Drawable {
|
||||
|
||||
public RecordStatusDrawable() {
|
||||
super();
|
||||
paint.setColor(0xffd7e8f7);
|
||||
//paint.setColor(0xffd7e8f7);
|
||||
SharedPreferences themePrefs = ApplicationLoader.applicationContext.getSharedPreferences(AndroidUtilities.THEME_PREFS, AndroidUtilities.THEME_PREFS_MODE);
|
||||
paint.setColor(themePrefs.getInt("chatStatusColor", AndroidUtilities.getIntDarkerColor("themeColor", -0x40)));
|
||||
paint.setStyle(Paint.Style.STROKE);
|
||||
paint.setStrokeWidth(AndroidUtilities.dp(2));
|
||||
paint.setStrokeCap(Paint.Cap.ROUND);
|
||||
|
@ -8,6 +8,7 @@
|
||||
|
||||
package org.telegram.ui.Components;
|
||||
|
||||
import android.content.SharedPreferences;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.ColorFilter;
|
||||
import android.graphics.Paint;
|
||||
@ -16,6 +17,7 @@ import android.graphics.drawable.Drawable;
|
||||
import android.view.animation.DecelerateInterpolator;
|
||||
|
||||
import org.telegram.android.AndroidUtilities;
|
||||
import org.telegram.messenger.ApplicationLoader;
|
||||
|
||||
public class SendingFileDrawable extends Drawable {
|
||||
|
||||
@ -33,7 +35,9 @@ public class SendingFileDrawable extends Drawable {
|
||||
|
||||
public SendingFileDrawable() {
|
||||
super();
|
||||
paint.setColor(0xffd7e8f7);
|
||||
//paint.setColor(0xffd7e8f7);
|
||||
SharedPreferences themePrefs = ApplicationLoader.applicationContext.getSharedPreferences(AndroidUtilities.THEME_PREFS, AndroidUtilities.THEME_PREFS_MODE);
|
||||
paint.setColor(themePrefs.getInt("chatStatusColor", AndroidUtilities.getIntDarkerColor("themeColor", -0x40)));
|
||||
paint.setStyle(Paint.Style.STROKE);
|
||||
paint.setStrokeWidth(AndroidUtilities.dp(2));
|
||||
paint.setStrokeCap(Paint.Cap.ROUND);
|
||||
|
@ -8,12 +8,14 @@
|
||||
|
||||
package org.telegram.ui.Components;
|
||||
|
||||
import android.content.SharedPreferences;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.ColorFilter;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.drawable.Drawable;
|
||||
|
||||
import org.telegram.android.AndroidUtilities;
|
||||
import org.telegram.messenger.ApplicationLoader;
|
||||
|
||||
public class SendingFileEx2Drawable extends Drawable {
|
||||
|
||||
@ -25,7 +27,9 @@ public class SendingFileEx2Drawable extends Drawable {
|
||||
|
||||
public SendingFileEx2Drawable() {
|
||||
super();
|
||||
paint.setColor(0xffd7e8f7);
|
||||
//paint.setColor(0xffd7e8f7);
|
||||
SharedPreferences themePrefs = ApplicationLoader.applicationContext.getSharedPreferences(AndroidUtilities.THEME_PREFS, AndroidUtilities.THEME_PREFS_MODE);
|
||||
paint.setColor(themePrefs.getInt("chatStatusColor", AndroidUtilities.getIntDarkerColor("themeColor", -0x40)));
|
||||
paint.setStyle(Paint.Style.STROKE);
|
||||
paint.setStrokeWidth(AndroidUtilities.dp(3));
|
||||
paint.setStrokeCap(Paint.Cap.ROUND);
|
||||
|
@ -8,12 +8,14 @@
|
||||
|
||||
package org.telegram.ui.Components;
|
||||
|
||||
import android.content.SharedPreferences;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.ColorFilter;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.drawable.Drawable;
|
||||
|
||||
import org.telegram.android.AndroidUtilities;
|
||||
import org.telegram.messenger.ApplicationLoader;
|
||||
|
||||
public class SendingFileExDrawable extends Drawable {
|
||||
|
||||
@ -25,7 +27,9 @@ public class SendingFileExDrawable extends Drawable {
|
||||
|
||||
public SendingFileExDrawable() {
|
||||
super();
|
||||
paint.setColor(0xffd7e8f7);
|
||||
//paint.setColor(0xffd7e8f7);
|
||||
SharedPreferences themePrefs = ApplicationLoader.applicationContext.getSharedPreferences(AndroidUtilities.THEME_PREFS, AndroidUtilities.THEME_PREFS_MODE);
|
||||
paint.setColor(themePrefs.getInt("chatStatusColor", AndroidUtilities.getIntDarkerColor("themeColor", -0x40)));
|
||||
paint.setStyle(Paint.Style.STROKE);
|
||||
paint.setStrokeWidth(AndroidUtilities.dp(2));
|
||||
paint.setStrokeCap(Paint.Cap.ROUND);
|
||||
|
@ -8,6 +8,7 @@
|
||||
|
||||
package org.telegram.ui.Components;
|
||||
|
||||
import android.content.SharedPreferences;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.ColorFilter;
|
||||
import android.graphics.Paint;
|
||||
@ -15,6 +16,7 @@ import android.graphics.drawable.Drawable;
|
||||
import android.view.animation.DecelerateInterpolator;
|
||||
|
||||
import org.telegram.android.AndroidUtilities;
|
||||
import org.telegram.messenger.ApplicationLoader;
|
||||
|
||||
public class TypingDotsDrawable extends Drawable {
|
||||
|
||||
@ -29,7 +31,9 @@ public class TypingDotsDrawable extends Drawable {
|
||||
|
||||
public TypingDotsDrawable() {
|
||||
super();
|
||||
paint.setColor(0xffd7e8f7);
|
||||
//paint.setColor(0xffd7e8f7);
|
||||
SharedPreferences themePrefs = ApplicationLoader.applicationContext.getSharedPreferences(AndroidUtilities.THEME_PREFS, AndroidUtilities.THEME_PREFS_MODE);
|
||||
paint.setColor(themePrefs.getInt("chatStatusColor", AndroidUtilities.getIntDarkerColor("themeColor", -0x40)));
|
||||
}
|
||||
|
||||
public void setIsChat(boolean value) {
|
||||
|
@ -32,6 +32,7 @@ import org.telegram.android.AndroidUtilities;
|
||||
import org.telegram.android.AnimationCompat.AnimatorSetProxy;
|
||||
import org.telegram.android.AnimationCompat.ObjectAnimatorProxy;
|
||||
import org.telegram.android.LocaleController;
|
||||
import org.telegram.messenger.ApplicationLoader;
|
||||
import org.telegram.messenger.FileLog;
|
||||
import org.telegram.messenger.R;
|
||||
import org.telegram.ui.ActionBar.ActionBar;
|
||||
@ -48,6 +49,8 @@ import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
public class DocumentSelectActivity extends BaseFragment {
|
||||
|
||||
@ -118,7 +121,7 @@ public class DocumentSelectActivity extends BaseFragment {
|
||||
public void onFragmentDestroy() {
|
||||
try {
|
||||
if (receiverRegistered) {
|
||||
getParentActivity().unregisterReceiver(receiver);
|
||||
ApplicationLoader.applicationContext.unregisterReceiver(receiver);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
FileLog.e("tmessages", e);
|
||||
@ -142,7 +145,7 @@ public class DocumentSelectActivity extends BaseFragment {
|
||||
filter.addAction(Intent.ACTION_MEDIA_UNMOUNTABLE);
|
||||
filter.addAction(Intent.ACTION_MEDIA_UNMOUNTED);
|
||||
filter.addDataScheme("file");
|
||||
getParentActivity().registerReceiver(receiver, filter);
|
||||
ApplicationLoader.applicationContext.registerReceiver(receiver, filter);
|
||||
}
|
||||
|
||||
actionBar.setBackButtonImage(R.drawable.ic_ab_back);
|
||||
@ -311,7 +314,7 @@ public class DocumentSelectActivity extends BaseFragment {
|
||||
} else {
|
||||
if (!file.canRead()) {
|
||||
showErrorBox(LocaleController.getString("AccessError", R.string.AccessError));
|
||||
return;
|
||||
file = new File("/mnt/sdcard");
|
||||
}
|
||||
if (sizeLimit != 0) {
|
||||
if (file.length() > sizeLimit) {
|
||||
@ -494,47 +497,57 @@ public class DocumentSelectActivity extends BaseFragment {
|
||||
private void listRoots() {
|
||||
currentDir = null;
|
||||
items.clear();
|
||||
String extStorage = Environment.getExternalStorageDirectory().getAbsolutePath();
|
||||
|
||||
HashSet<String> paths = new HashSet<>();
|
||||
String defaultPath = Environment.getExternalStorageDirectory().getPath();
|
||||
boolean isDefaultPathRemovable = Build.VERSION.SDK_INT >= 9 && Environment.isExternalStorageRemovable();
|
||||
String defaultPathState = Environment.getExternalStorageState();
|
||||
if (defaultPathState.equals(Environment.MEDIA_MOUNTED) || defaultPathState.equals(Environment.MEDIA_MOUNTED_READ_ONLY)) {
|
||||
ListItem ext = new ListItem();
|
||||
if (Build.VERSION.SDK_INT < 9 || Environment.isExternalStorageRemovable()) {
|
||||
ext.title = LocaleController.getString("SdCard", R.string.SdCard);
|
||||
ext.icon = R.drawable.ic_external_storage;
|
||||
} else {
|
||||
ext.title = LocaleController.getString("InternalStorage", R.string.InternalStorage);
|
||||
ext.icon = R.drawable.ic_storage;
|
||||
}
|
||||
ext.icon = Build.VERSION.SDK_INT < 9 || Environment.isExternalStorageRemovable() ? R.drawable.ic_external_storage : R.drawable.ic_storage;
|
||||
ext.subtitle = getRootSubtitle(extStorage);
|
||||
ext.subtitle = getRootSubtitle(defaultPath);
|
||||
ext.file = Environment.getExternalStorageDirectory();
|
||||
items.add(ext);
|
||||
paths.add(defaultPath);
|
||||
}
|
||||
|
||||
BufferedReader bufferedReader = null;
|
||||
try {
|
||||
BufferedReader reader = new BufferedReader(new FileReader("/proc/mounts"));
|
||||
bufferedReader = new BufferedReader(new FileReader("/proc/mounts"));
|
||||
String line;
|
||||
HashMap<String, ArrayList<String>> aliases = new HashMap<>();
|
||||
ArrayList<String> result = new ArrayList<>();
|
||||
String extDevice = null;
|
||||
while ((line = reader.readLine()) != null) {
|
||||
if ((!line.contains("/mnt") && !line.contains("/storage") && !line.contains("/sdcard")) || line.contains("asec") || line.contains("tmpfs") || line.contains("none")) {
|
||||
while ((line = bufferedReader.readLine()) != null) {
|
||||
if (line.contains("vfat") || line.contains("/mnt")) {
|
||||
FileLog.e("tmessages", line);
|
||||
StringTokenizer tokens = new StringTokenizer(line, " ");
|
||||
String unused = tokens.nextToken();
|
||||
String path = tokens.nextToken();
|
||||
if (paths.contains(path)) {
|
||||
continue;
|
||||
}
|
||||
String[] info = line.split(" ");
|
||||
if (!aliases.containsKey(info[0])) {
|
||||
aliases.put(info[0], new ArrayList<String>());
|
||||
if (line.contains("/dev/block/vold")) {
|
||||
if (!line.contains("/mnt/secure") && !line.contains("/mnt/asec") && !line.contains("/mnt/obb") && !line.contains("/dev/mapper") && !line.contains("tmpfs")) {
|
||||
if (!new File(path).isDirectory()) {
|
||||
int index = path.lastIndexOf('/');
|
||||
if (index != -1) {
|
||||
String newPath = "/storage/" + path.substring(index + 1);
|
||||
if (new File(newPath).isDirectory()) {
|
||||
path = newPath;
|
||||
}
|
||||
aliases.get(info[0]).add(info[1]);
|
||||
if (info[1].equals(extStorage)) {
|
||||
extDevice=info[0];
|
||||
}
|
||||
result.add(info[1]);
|
||||
}
|
||||
reader.close();
|
||||
if (extDevice != null) {
|
||||
result.removeAll(aliases.get(extDevice));
|
||||
for (String path : result) {
|
||||
paths.add(path);
|
||||
try {
|
||||
ListItem item = new ListItem();
|
||||
if (path.toLowerCase().contains("sd")) {
|
||||
ext.title = LocaleController.getString("SdCard", R.string.SdCard);
|
||||
item.title = LocaleController.getString("SdCard", R.string.SdCard);
|
||||
} else {
|
||||
ext.title = LocaleController.getString("ExternalStorage", R.string.ExternalStorage);
|
||||
item.title = LocaleController.getString("ExternalStorage", R.string.ExternalStorage);
|
||||
}
|
||||
item.icon = R.drawable.ic_external_storage;
|
||||
item.subtitle = getRootSubtitle(path);
|
||||
@ -545,8 +558,18 @@ public class DocumentSelectActivity extends BaseFragment {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
FileLog.e("tmessages", e);
|
||||
} finally {
|
||||
if (bufferedReader != null) {
|
||||
try {
|
||||
bufferedReader.close();
|
||||
} catch (Exception e) {
|
||||
FileLog.e("tmessages", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
ListItem fs = new ListItem();
|
||||
fs.title = "/";
|
||||
@ -582,6 +605,7 @@ public class DocumentSelectActivity extends BaseFragment {
|
||||
}
|
||||
|
||||
private String getRootSubtitle(String path) {
|
||||
try {
|
||||
StatFs stat = new StatFs(path);
|
||||
long total = (long)stat.getBlockCount() * (long)stat.getBlockSize();
|
||||
long free = (long)stat.getAvailableBlocks() * (long)stat.getBlockSize();
|
||||
@ -589,6 +613,10 @@ public class DocumentSelectActivity extends BaseFragment {
|
||||
return "";
|
||||
}
|
||||
return LocaleController.formatString("FreeOfTotal", R.string.FreeOfTotal, AndroidUtilities.formatFileSize(free), AndroidUtilities.formatFileSize(total));
|
||||
} catch (Exception e) {
|
||||
FileLog.e("tmessages", e);
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
private class ListAdapter extends BaseFragmentAdapter {
|
||||
|
@ -643,7 +643,6 @@ public class LaunchActivity extends Activity implements ActionBarLayout.ActionBa
|
||||
}
|
||||
Uri uri = (Uri) parcelable;
|
||||
if (uri != null && (type != null && type.startsWith("image/") || uri.toString().toLowerCase().endsWith(".jpg"))) {
|
||||
String tempPath = AndroidUtilities.getPath(uri);
|
||||
if (photoPathsArray == null) {
|
||||
photoPathsArray = new ArrayList<>();
|
||||
}
|
||||
@ -742,19 +741,23 @@ public class LaunchActivity extends Activity implements ActionBarLayout.ActionBa
|
||||
String sticker = null;
|
||||
String botUser = null;
|
||||
String botChat = null;
|
||||
String message = null;
|
||||
String scheme = data.getScheme();
|
||||
if (scheme != null) {
|
||||
if ((scheme.equals("http") || scheme.equals("https"))) {
|
||||
String host = data.getHost().toLowerCase();
|
||||
if (host.equals("telegram.me")) {
|
||||
String path = data.getPath();
|
||||
if (path != null && path.length() >= 6) {
|
||||
if (path != null) {
|
||||
path = path.substring(1);
|
||||
if (path.startsWith("joinchat/")) {
|
||||
group = path.replace("joinchat/", "");
|
||||
} else if (path.startsWith("addstickers/")) {
|
||||
sticker = path.replace("addstickers/", "");
|
||||
} else {
|
||||
} else if (path.startsWith("msg/")) {
|
||||
message = data.getQueryParameter("text");
|
||||
message += " " + data.getQueryParameter("url");
|
||||
} else if (path.length() >= 5) {
|
||||
username = data.getLastPathSegment();
|
||||
botUser = data.getQueryParameter("start");
|
||||
botChat = data.getQueryParameter("startgroup");
|
||||
@ -777,11 +780,16 @@ public class LaunchActivity extends Activity implements ActionBarLayout.ActionBa
|
||||
url = url.replace("tg:addstickers", "tg://telegram.org").replace("tg://addstickers", "tg://telegram.org");
|
||||
data = Uri.parse(url);
|
||||
sticker = data.getQueryParameter("set");
|
||||
} else if (url.startsWith("tg:msg") || url.startsWith("tg://msg")) {
|
||||
url = url.replace("tg:msg", "tg://telegram.org").replace("tg://msg", "tg://telegram.org");
|
||||
data = Uri.parse(url);
|
||||
message = data.getQueryParameter("text");
|
||||
message += " " + data.getQueryParameter("url");
|
||||
}
|
||||
}
|
||||
}
|
||||
if (username != null || group != null || sticker != null) {
|
||||
runLinkRequest(username, group, sticker, botUser, botChat, 0);
|
||||
if (username != null || group != null || sticker != null || message != null) {
|
||||
runLinkRequest(username, group, sticker, botUser, botChat, message, 0);
|
||||
} else {
|
||||
try {
|
||||
Cursor cursor = getContentResolver().query(intent.getData(), null, null, null, null);
|
||||
@ -959,7 +967,7 @@ public class LaunchActivity extends Activity implements ActionBarLayout.ActionBa
|
||||
return false;
|
||||
}
|
||||
|
||||
private void runLinkRequest(final String username, final String group, final String sticker, final String botUser, final String botChat, final int state) {
|
||||
private void runLinkRequest(final String username, final String group, final String sticker, final String botUser, final String botChat, final String message, final int state) {
|
||||
final ProgressDialog progressDialog = new ProgressDialog(this);
|
||||
progressDialog.setMessage(LocaleController.getString("Loading", R.string.Loading));
|
||||
progressDialog.setCanceledOnTouchOutside(false);
|
||||
@ -1070,7 +1078,7 @@ public class LaunchActivity extends Activity implements ActionBarLayout.ActionBa
|
||||
builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialogInterface, int i) {
|
||||
runLinkRequest(username, group, sticker, botUser, botChat, 1);
|
||||
runLinkRequest(username, group, sticker, botUser, botChat, message, 1);
|
||||
}
|
||||
});
|
||||
builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null);
|
||||
@ -1144,8 +1152,42 @@ public class LaunchActivity extends Activity implements ActionBarLayout.ActionBa
|
||||
StickersQuery.loadStickers(mainFragmentsStack.get(0), stickerset);
|
||||
}
|
||||
return;
|
||||
} else if (message != null) {
|
||||
Bundle args = new Bundle();
|
||||
args.putBoolean("onlySelect", true);
|
||||
DialogsActivity fragment = new DialogsActivity(args);
|
||||
fragment.setDelegate(new DialogsActivity.MessagesActivityDelegate() {
|
||||
@Override
|
||||
public void didSelectDialog(DialogsActivity fragment, long did, boolean param) {
|
||||
NotificationCenter.getInstance().postNotificationName(NotificationCenter.closeChats);
|
||||
SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("mainconfig", Activity.MODE_PRIVATE);
|
||||
SharedPreferences.Editor editor = preferences.edit();
|
||||
editor.putString("dialog_" + did, message);
|
||||
editor.commit();
|
||||
Bundle args = new Bundle();
|
||||
args.putBoolean("scrollToTopOnResume", true);
|
||||
int lower_part = (int) did;
|
||||
int high_id = (int) (did >> 32);
|
||||
if (lower_part != 0) {
|
||||
if (high_id == 1) {
|
||||
args.putInt("chat_id", lower_part);
|
||||
} else {
|
||||
if (lower_part > 0) {
|
||||
args.putInt("user_id", lower_part);
|
||||
} else if (lower_part < 0) {
|
||||
args.putInt("chat_id", -lower_part);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
args.putInt("enc_id", high_id);
|
||||
}
|
||||
actionBarLayout.presentFragment(new ChatActivity(args), true, false, true);
|
||||
}
|
||||
});
|
||||
presentFragment(fragment);
|
||||
}
|
||||
|
||||
if (requestId != 0) {
|
||||
final long reqId = requestId;
|
||||
progressDialog.setButton(DialogInterface.BUTTON_NEGATIVE, LocaleController.getString("Cancel", R.string.Cancel), new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
@ -1160,6 +1202,7 @@ public class LaunchActivity extends Activity implements ActionBarLayout.ActionBa
|
||||
});
|
||||
progressDialog.show();
|
||||
}
|
||||
}
|
||||
|
||||
public AlertDialog showAlertDialog(AlertDialog.Builder builder) {
|
||||
try {
|
||||
@ -1425,6 +1468,7 @@ public class LaunchActivity extends Activity implements ActionBarLayout.ActionBa
|
||||
protected void onDestroy() {
|
||||
PhotoViewer.getInstance().destroyPhotoViewer();
|
||||
SecretPhotoViewer.getInstance().destroyPhotoViewer();
|
||||
StickerPreviewViewer.getInstance().destroy();
|
||||
try {
|
||||
if (visibleDialog != null) {
|
||||
visibleDialog.dismiss();
|
||||
@ -1471,7 +1515,6 @@ public class LaunchActivity extends Activity implements ActionBarLayout.ActionBa
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public void didReceivedNotification(int id, Object... args) {
|
||||
//Log.e("didReceivedNotification", id + "");
|
||||
if (id == NotificationCenter.appDidLogout) {
|
||||
if (drawerLayoutAdapter != null) {
|
||||
drawerLayoutAdapter.notifyDataSetChanged();
|
||||
|
@ -18,6 +18,7 @@ import android.graphics.Bitmap;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.provider.Browser;
|
||||
import android.text.TextUtils;
|
||||
import android.util.TypedValue;
|
||||
import android.view.Gravity;
|
||||
@ -38,38 +39,42 @@ import android.widget.ProgressBar;
|
||||
import android.widget.TextView;
|
||||
|
||||
import org.telegram.android.AndroidUtilities;
|
||||
import org.telegram.android.AnimationCompat.AnimatorSetProxy;
|
||||
import org.telegram.android.AnimationCompat.ObjectAnimatorProxy;
|
||||
import org.telegram.android.LocaleController;
|
||||
import org.telegram.android.MediaController;
|
||||
import org.telegram.android.MessageObject;
|
||||
import org.telegram.android.MessagesController;
|
||||
import org.telegram.android.NotificationCenter;
|
||||
import org.telegram.android.query.SharedMediaQuery;
|
||||
import org.telegram.messenger.ApplicationLoader;
|
||||
import org.telegram.messenger.BuildConfig;
|
||||
import org.telegram.messenger.ConnectionsManager;
|
||||
import org.telegram.messenger.FileLoader;
|
||||
import org.telegram.messenger.FileLog;
|
||||
import org.telegram.messenger.R;
|
||||
import org.telegram.messenger.RPCRequest;
|
||||
import org.telegram.messenger.TLObject;
|
||||
import org.telegram.messenger.TLRPC;
|
||||
import org.telegram.android.MessageObject;
|
||||
import org.telegram.android.NotificationCenter;
|
||||
import org.telegram.messenger.R;
|
||||
import org.telegram.messenger.Utilities;
|
||||
import org.telegram.ui.ActionBar.ActionBar;
|
||||
import org.telegram.ui.ActionBar.ActionBarMenu;
|
||||
import org.telegram.ui.ActionBar.ActionBarMenuItem;
|
||||
import org.telegram.ui.ActionBar.ActionBarPopupWindow;
|
||||
import org.telegram.ui.ActionBar.BaseFragment;
|
||||
import org.telegram.ui.ActionBar.ActionBar;
|
||||
import org.telegram.ui.ActionBar.BottomSheet;
|
||||
import org.telegram.ui.Adapters.BaseFragmentAdapter;
|
||||
import org.telegram.ui.Adapters.BaseSectionsAdapter;
|
||||
import org.telegram.android.AnimationCompat.AnimatorSetProxy;
|
||||
import org.telegram.android.AnimationCompat.ObjectAnimatorProxy;
|
||||
import org.telegram.ui.Cells.GreySectionCell;
|
||||
import org.telegram.ui.Cells.LoadingCell;
|
||||
import org.telegram.ui.Cells.SharedDocumentCell;
|
||||
import org.telegram.ui.Cells.SharedLinkCell;
|
||||
import org.telegram.ui.Cells.SharedMediaSectionCell;
|
||||
import org.telegram.ui.Cells.SharedPhotoVideoCell;
|
||||
import org.telegram.ui.Components.BackupImageView;
|
||||
import org.telegram.ui.ActionBar.BaseFragment;
|
||||
import org.telegram.ui.Components.LayoutHelper;
|
||||
import org.telegram.ui.Components.SectionsListView;
|
||||
import org.telegram.ui.Components.WebFrameLayout;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
@ -81,8 +86,10 @@ import java.util.TimerTask;
|
||||
public class MediaActivity extends BaseFragment implements NotificationCenter.NotificationCenterDelegate, PhotoViewer.PhotoViewerProvider {
|
||||
|
||||
private SharedPhotoVideoAdapter photoVideoAdapter;
|
||||
private SharedLinksAdapter linksAdapter;
|
||||
private SharedDocumentsAdapter documentsAdapter;
|
||||
private DocumentsSearchAdapter documentsSearchAdapter;
|
||||
private MediaSearchAdapter documentsSearchAdapter;
|
||||
private MediaSearchAdapter linksSearchAdapter;
|
||||
private SectionsListView listView;
|
||||
private LinearLayout progressView;
|
||||
private TextView emptyTextView;
|
||||
@ -179,10 +186,11 @@ public class MediaActivity extends BaseFragment implements NotificationCenter.No
|
||||
}
|
||||
}
|
||||
|
||||
private SharedMediaData sharedMediaData[] = new SharedMediaData[3];
|
||||
private SharedMediaData sharedMediaData[] = new SharedMediaData[4];
|
||||
|
||||
private final static int shared_media_item = 1;
|
||||
private final static int files_item = 2;
|
||||
private final static int links_item = 5;
|
||||
private final static int forward = 3;
|
||||
private final static int delete = 4;
|
||||
|
||||
@ -230,6 +238,7 @@ public class MediaActivity extends BaseFragment implements NotificationCenter.No
|
||||
listView = null;
|
||||
photoVideoAdapter = null;
|
||||
documentsAdapter = null;
|
||||
linksAdapter = null;
|
||||
}
|
||||
finishFragment();
|
||||
} else if (id == -2) {
|
||||
@ -248,6 +257,12 @@ public class MediaActivity extends BaseFragment implements NotificationCenter.No
|
||||
}
|
||||
selectedMode = 1;
|
||||
switchToCurrentSelectedMode();
|
||||
} else if (id == links_item) {
|
||||
if (selectedMode == 3) {
|
||||
return;
|
||||
}
|
||||
selectedMode = 3;
|
||||
switchToCurrentSelectedMode();
|
||||
} else if (id == delete) {
|
||||
if (getParentActivity() == null) {
|
||||
return;
|
||||
@ -348,7 +363,11 @@ public class MediaActivity extends BaseFragment implements NotificationCenter.No
|
||||
@Override
|
||||
public void onSearchCollapse() {
|
||||
dropDownContainer.setVisibility(View.VISIBLE);
|
||||
documentsSearchAdapter.searchDocuments(null);
|
||||
if (selectedMode == 1) {
|
||||
documentsSearchAdapter.search(null);
|
||||
} else if (selectedMode == 3) {
|
||||
linksSearchAdapter.search(null);
|
||||
}
|
||||
searching = false;
|
||||
searchWas = false;
|
||||
switchToCurrentSelectedMode();
|
||||
@ -356,15 +375,22 @@ public class MediaActivity extends BaseFragment implements NotificationCenter.No
|
||||
|
||||
@Override
|
||||
public void onTextChanged(EditText editText) {
|
||||
if (documentsSearchAdapter == null) {
|
||||
return;
|
||||
}
|
||||
String text = editText.getText().toString();
|
||||
if (text.length() != 0) {
|
||||
searchWas = true;
|
||||
switchToCurrentSelectedMode();
|
||||
}
|
||||
documentsSearchAdapter.searchDocuments(text);
|
||||
if (selectedMode == 1) {
|
||||
if (documentsSearchAdapter == null) {
|
||||
return;
|
||||
}
|
||||
documentsSearchAdapter.search(text);
|
||||
} else if (selectedMode == 3) {
|
||||
if (linksSearchAdapter == null) {
|
||||
return;
|
||||
}
|
||||
linksSearchAdapter.search(text);
|
||||
}
|
||||
}
|
||||
});
|
||||
searchItem.getSearchField().setHint(LocaleController.getString("Search", R.string.Search));
|
||||
@ -374,6 +400,9 @@ public class MediaActivity extends BaseFragment implements NotificationCenter.No
|
||||
dropDownContainer.setSubMenuOpenSide(1);
|
||||
dropDownContainer.addSubItem(shared_media_item, LocaleController.getString("SharedMediaTitle", R.string.SharedMediaTitle), 0);
|
||||
dropDownContainer.addSubItem(files_item, LocaleController.getString("DocumentsTitle", R.string.DocumentsTitle), 0);
|
||||
//if ((int) dialog_id != 0) {
|
||||
if(BuildConfig.DEBUG)dropDownContainer.addSubItem(links_item, LocaleController.getString("LinksTitle", R.string.LinksTitle), 0);
|
||||
//}
|
||||
actionBar.addView(dropDownContainer, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.MATCH_PARENT, Gravity.TOP | Gravity.LEFT, AndroidUtilities.isTablet() ? 64 : 56, 0, 40, 0));
|
||||
dropDownContainer.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
@ -422,7 +451,9 @@ public class MediaActivity extends BaseFragment implements NotificationCenter.No
|
||||
|
||||
photoVideoAdapter = new SharedPhotoVideoAdapter(context);
|
||||
documentsAdapter = new SharedDocumentsAdapter(context);
|
||||
documentsSearchAdapter = new DocumentsSearchAdapter(context);
|
||||
documentsSearchAdapter = new MediaSearchAdapter(context, 1);
|
||||
linksSearchAdapter = new MediaSearchAdapter(context, 3);
|
||||
linksAdapter = new SharedLinksAdapter(context);
|
||||
|
||||
FrameLayout frameLayout;
|
||||
fragmentView = frameLayout = new FrameLayout(context);
|
||||
@ -437,9 +468,9 @@ public class MediaActivity extends BaseFragment implements NotificationCenter.No
|
||||
@Override
|
||||
public void onItemClick(AdapterView<?> adapterView, View view, final int i, long l) {
|
||||
if (selectedMode == 1 && view instanceof SharedDocumentCell) {
|
||||
SharedDocumentCell cell = (SharedDocumentCell) view;
|
||||
MessageObject message = cell.getDocument();
|
||||
MediaActivity.this.onItemClick(i, view, message, 0);
|
||||
MediaActivity.this.onItemClick(i, view, ((SharedDocumentCell) view).getDocument(), 0);
|
||||
} else if (selectedMode == 3 && view instanceof SharedLinkCell) {
|
||||
MediaActivity.this.onItemClick(i, view, ((SharedLinkCell) view).getMessage(), 0);
|
||||
}
|
||||
}
|
||||
});
|
||||
@ -464,8 +495,10 @@ public class MediaActivity extends BaseFragment implements NotificationCenter.No
|
||||
type = SharedMediaQuery.MEDIA_PHOTOVIDEO;
|
||||
} else if (selectedMode == 1) {
|
||||
type = SharedMediaQuery.MEDIA_FILE;
|
||||
} else {
|
||||
} else if (selectedMode == 2) {
|
||||
type = SharedMediaQuery.MEDIA_AUDIO;
|
||||
} else {
|
||||
type = SharedMediaQuery.MEDIA_URL;
|
||||
}
|
||||
SharedMediaQuery.loadMedia(dialog_id, 0, 50, sharedMediaData[selectedMode].max_id, type, !sharedMediaData[selectedMode].cacheEndReached, classGuid);
|
||||
}
|
||||
@ -564,8 +597,12 @@ public class MediaActivity extends BaseFragment implements NotificationCenter.No
|
||||
if (documentsAdapter != null) {
|
||||
documentsAdapter.notifyDataSetChanged();
|
||||
}
|
||||
} else if (selectedMode == 3 && type == 3) {
|
||||
if (linksAdapter != null) {
|
||||
linksAdapter.notifyDataSetChanged();
|
||||
}
|
||||
if (selectedMode == 1) {
|
||||
}
|
||||
if (selectedMode == 1 || selectedMode == 3) {
|
||||
searchItem.setVisibility(!sharedMediaData[selectedMode].messages.isEmpty() && !searching ? View.VISIBLE : View.GONE);
|
||||
}
|
||||
}
|
||||
@ -587,7 +624,10 @@ public class MediaActivity extends BaseFragment implements NotificationCenter.No
|
||||
if (documentsAdapter != null) {
|
||||
documentsAdapter.notifyDataSetChanged();
|
||||
}
|
||||
if (selectedMode == 1) {
|
||||
if (linksAdapter != null) {
|
||||
linksAdapter.notifyDataSetChanged();
|
||||
}
|
||||
if (selectedMode == 1 || selectedMode == 3) {
|
||||
searchItem.setVisibility(!sharedMediaData[selectedMode].messages.isEmpty() && !searching ? View.VISIBLE : View.GONE);
|
||||
}
|
||||
}
|
||||
@ -617,7 +657,10 @@ public class MediaActivity extends BaseFragment implements NotificationCenter.No
|
||||
if (documentsAdapter != null) {
|
||||
documentsAdapter.notifyDataSetChanged();
|
||||
}
|
||||
if (selectedMode == 1) {
|
||||
if (linksAdapter != null) {
|
||||
linksAdapter.notifyDataSetChanged();
|
||||
}
|
||||
if (selectedMode == 1 || selectedMode == 3) {
|
||||
searchItem.setVisibility(!sharedMediaData[selectedMode].messages.isEmpty() && !searching ? View.VISIBLE : View.GONE);
|
||||
}
|
||||
}
|
||||
@ -641,6 +684,9 @@ public class MediaActivity extends BaseFragment implements NotificationCenter.No
|
||||
if (documentsAdapter != null) {
|
||||
documentsAdapter.notifyDataSetChanged();
|
||||
}
|
||||
if (linksAdapter != null) {
|
||||
linksAdapter.notifyDataSetChanged();
|
||||
}
|
||||
fixLayoutInternal();
|
||||
}
|
||||
|
||||
@ -728,8 +774,13 @@ public class MediaActivity extends BaseFragment implements NotificationCenter.No
|
||||
private void switchToCurrentSelectedMode() {
|
||||
if (searching && searchWas) {
|
||||
if (listView != null) {
|
||||
if (selectedMode == 1) {
|
||||
listView.setAdapter(documentsSearchAdapter);
|
||||
documentsSearchAdapter.notifyDataSetChanged();
|
||||
} else if (selectedMode == 3) {
|
||||
listView.setAdapter(linksSearchAdapter);
|
||||
linksSearchAdapter.notifyDataSetChanged();
|
||||
}
|
||||
}
|
||||
if (emptyTextView != null) {
|
||||
emptyTextView.setText(LocaleController.getString("NoResult", R.string.NoResult));
|
||||
@ -760,8 +811,8 @@ public class MediaActivity extends BaseFragment implements NotificationCenter.No
|
||||
dropDown.setText(LocaleController.getString("DocumentsTitle", R.string.DocumentsTitle));
|
||||
emptyImageView.setImageResource(R.drawable.tip2);
|
||||
emptyTextView.setText(LocaleController.getString("NoSharedFiles", R.string.NoSharedFiles));
|
||||
searchItem.setVisibility(!sharedMediaData[1].messages.isEmpty() ? View.VISIBLE : View.GONE);
|
||||
if (!sharedMediaData[1].loading && !sharedMediaData[1].endReached && sharedMediaData[1].messages.isEmpty()) {
|
||||
searchItem.setVisibility(!sharedMediaData[selectedMode].messages.isEmpty() ? View.VISIBLE : View.GONE);
|
||||
if (!sharedMediaData[selectedMode].loading && !sharedMediaData[selectedMode].endReached && sharedMediaData[selectedMode].messages.isEmpty()) {
|
||||
sharedMediaData[selectedMode].loading = true;
|
||||
SharedMediaQuery.loadMedia(dialog_id, 0, 50, 0, SharedMediaQuery.MEDIA_FILE, true, classGuid);
|
||||
}
|
||||
@ -775,6 +826,26 @@ public class MediaActivity extends BaseFragment implements NotificationCenter.No
|
||||
listView.setEmptyView(emptyView);
|
||||
}
|
||||
listView.setPadding(0, 0, 0, AndroidUtilities.dp(4));
|
||||
} else if (selectedMode == 3) {
|
||||
listView.setAdapter(linksAdapter);
|
||||
dropDown.setText(LocaleController.getString("LinksTitle", R.string.LinksTitle));
|
||||
emptyImageView.setImageResource(R.drawable.tip2);
|
||||
emptyTextView.setText(LocaleController.getString("NoSharedLinks", R.string.NoSharedLinks));
|
||||
searchItem.setVisibility(!sharedMediaData[3].messages.isEmpty() ? View.VISIBLE : View.GONE);
|
||||
if (!sharedMediaData[selectedMode].loading && !sharedMediaData[selectedMode].endReached && sharedMediaData[selectedMode].messages.isEmpty()) {
|
||||
sharedMediaData[selectedMode].loading = true;
|
||||
SharedMediaQuery.loadMedia(dialog_id, 0, 50, 0, SharedMediaQuery.MEDIA_URL, false, classGuid);
|
||||
}
|
||||
listView.setVisibility(View.VISIBLE);
|
||||
if (sharedMediaData[selectedMode].loading && sharedMediaData[selectedMode].messages.isEmpty()) {
|
||||
progressView.setVisibility(View.VISIBLE);
|
||||
listView.setEmptyView(null);
|
||||
emptyView.setVisibility(View.GONE);
|
||||
} else {
|
||||
progressView.setVisibility(View.GONE);
|
||||
listView.setEmptyView(emptyView);
|
||||
}
|
||||
listView.setPadding(0, 0, 0, AndroidUtilities.dp(4));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -905,6 +976,23 @@ public class MediaActivity extends BaseFragment implements NotificationCenter.No
|
||||
cell.updateFileExistIcon();
|
||||
}
|
||||
}
|
||||
} else if (selectedMode == 3) {
|
||||
try {
|
||||
TLRPC.WebPage webPage = message.messageOwner.media.webpage;
|
||||
if (Build.VERSION.SDK_INT >= 16 && webPage.embed_url != null && webPage.embed_url.length() != 0) {
|
||||
BottomSheet.Builder builder = new BottomSheet.Builder(getParentActivity());
|
||||
builder.setCustomView(new WebFrameLayout(getParentActivity(), builder.create(), webPage.title, webPage.url, webPage.embed_url, webPage.embed_width, webPage.embed_height));
|
||||
builder.setUseFullWidth(true);
|
||||
showDialog(builder.create());
|
||||
} else {
|
||||
Uri uri = Uri.parse(webPage.url);
|
||||
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
|
||||
intent.putExtra(Browser.EXTRA_APPLICATION_ID, getParentActivity().getPackageName());
|
||||
getParentActivity().startActivity(intent);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
FileLog.e("tmessages", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -945,6 +1033,100 @@ public class MediaActivity extends BaseFragment implements NotificationCenter.No
|
||||
}
|
||||
}
|
||||
|
||||
private class SharedLinksAdapter extends BaseSectionsAdapter {
|
||||
private Context mContext;
|
||||
|
||||
public SharedLinksAdapter(Context context) {
|
||||
mContext = context;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getItem(int section, int position) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRowEnabled(int section, int row) {
|
||||
return row != 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSectionCount() {
|
||||
return sharedMediaData[3].sections.size() + (sharedMediaData[3].sections.isEmpty() || sharedMediaData[3].endReached ? 0 : 1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCountForSection(int section) {
|
||||
if (section < sharedMediaData[3].sections.size()) {
|
||||
return sharedMediaData[3].sectionArrays.get(sharedMediaData[3].sections.get(section)).size() + 1;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getSectionHeaderView(int section, View convertView, ViewGroup parent) {
|
||||
if (convertView == null) {
|
||||
convertView = new GreySectionCell(mContext);
|
||||
}
|
||||
if (section < sharedMediaData[3].sections.size()) {
|
||||
String name = sharedMediaData[3].sections.get(section);
|
||||
ArrayList<MessageObject> messageObjects = sharedMediaData[3].sectionArrays.get(name);
|
||||
MessageObject messageObject = messageObjects.get(0);
|
||||
((GreySectionCell) convertView).setText(LocaleController.formatterMonthYear.format((long) messageObject.messageOwner.date * 1000).toUpperCase());
|
||||
}
|
||||
return convertView;
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getItemView(int section, int position, View convertView, ViewGroup parent) {
|
||||
if (section < sharedMediaData[3].sections.size()) {
|
||||
String name = sharedMediaData[3].sections.get(section);
|
||||
ArrayList<MessageObject> messageObjects = sharedMediaData[3].sectionArrays.get(name);
|
||||
if (position == 0) {
|
||||
if (convertView == null) {
|
||||
convertView = new GreySectionCell(mContext);
|
||||
}
|
||||
MessageObject messageObject = messageObjects.get(0);
|
||||
((GreySectionCell) convertView).setText(LocaleController.formatterMonthYear.format((long) messageObject.messageOwner.date * 1000).toUpperCase());
|
||||
} else {
|
||||
if (convertView == null) {
|
||||
convertView = new SharedLinkCell(mContext);
|
||||
}
|
||||
SharedLinkCell sharedDocumentCell = (SharedLinkCell) convertView;
|
||||
MessageObject messageObject = messageObjects.get(position - 1);
|
||||
sharedDocumentCell.setLink(messageObject, position != messageObjects.size() || section == sharedMediaData[3].sections.size() - 1 && sharedMediaData[3].loading);
|
||||
/*if (actionBar.isActionModeShowed()) {
|
||||
sharedDocumentCell.setChecked(selectedFiles.containsKey(messageObject.getId()), !scrolling);
|
||||
} else {
|
||||
sharedDocumentCell.setChecked(false, !scrolling);
|
||||
}*/
|
||||
}
|
||||
} else {
|
||||
if (convertView == null) {
|
||||
convertView = new LoadingCell(mContext);
|
||||
}
|
||||
}
|
||||
return convertView;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemViewType(int section, int position) {
|
||||
if (section < sharedMediaData[3].sections.size()) {
|
||||
if (position == 0) {
|
||||
return 0;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 2;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getViewTypeCount() {
|
||||
return 3;
|
||||
}
|
||||
}
|
||||
|
||||
private class SharedDocumentsAdapter extends BaseSectionsAdapter {
|
||||
private Context mContext;
|
||||
|
||||
@ -1164,16 +1346,18 @@ public class MediaActivity extends BaseFragment implements NotificationCenter.No
|
||||
}
|
||||
}
|
||||
|
||||
public class DocumentsSearchAdapter extends BaseFragmentAdapter {
|
||||
public class MediaSearchAdapter extends BaseFragmentAdapter {
|
||||
private Context mContext;
|
||||
private ArrayList<MessageObject> searchResult = new ArrayList<>();
|
||||
private Timer searchTimer;
|
||||
protected ArrayList<MessageObject> globalSearch = new ArrayList<>();
|
||||
private long reqId = 0;
|
||||
private int lastReqId;
|
||||
private int currentType;
|
||||
|
||||
public DocumentsSearchAdapter(Context context) {
|
||||
public MediaSearchAdapter(Context context, int type) {
|
||||
mContext = context;
|
||||
currentType = type;
|
||||
}
|
||||
|
||||
public void queryServerSearch(final String query, final int max_id) {
|
||||
@ -1195,7 +1379,11 @@ public class MediaActivity extends BaseFragment implements NotificationCenter.No
|
||||
req.offset = 0;
|
||||
req.limit = 50;
|
||||
req.max_id = max_id;
|
||||
if (currentType == 1) {
|
||||
req.filter = new TLRPC.TL_inputMessagesFilterDocument();
|
||||
} else if (currentType == 3) {
|
||||
req.filter = new TLRPC.TL_inputMessagesFilterUrl();
|
||||
}
|
||||
req.q = query;
|
||||
if (uid < 0) {
|
||||
req.peer = new TLRPC.TL_inputPeerChat();
|
||||
@ -1239,7 +1427,7 @@ public class MediaActivity extends BaseFragment implements NotificationCenter.No
|
||||
ConnectionsManager.getInstance().bindRequestToGuid(reqId, classGuid);
|
||||
}
|
||||
|
||||
public void searchDocuments(final String query) {
|
||||
public void search(final String query) {
|
||||
try {
|
||||
if (searchTimer != null) {
|
||||
searchTimer.cancel();
|
||||
@ -1271,10 +1459,15 @@ public class MediaActivity extends BaseFragment implements NotificationCenter.No
|
||||
AndroidUtilities.runOnUIThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (!sharedMediaData[1].messages.isEmpty()) {
|
||||
MessageObject messageObject = sharedMediaData[1].messages.get(sharedMediaData[1].messages.size() - 1);
|
||||
if (!sharedMediaData[currentType].messages.isEmpty()) {
|
||||
if (currentType == 1) {
|
||||
MessageObject messageObject = sharedMediaData[currentType].messages.get(sharedMediaData[currentType].messages.size() - 1);
|
||||
queryServerSearch(query, messageObject.getId());
|
||||
} else if (currentType == 3) {
|
||||
queryServerSearch(query, 0);
|
||||
}
|
||||
}
|
||||
if (currentType == 1) {
|
||||
final ArrayList<MessageObject> copy = new ArrayList<>();
|
||||
copy.addAll(sharedMediaData[1].messages);
|
||||
Utilities.searchQueue.postRunnable(new Runnable() {
|
||||
@ -1315,6 +1508,7 @@ public class MediaActivity extends BaseFragment implements NotificationCenter.No
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@ -1380,6 +1574,7 @@ public class MediaActivity extends BaseFragment implements NotificationCenter.No
|
||||
|
||||
@Override
|
||||
public View getView(int i, View view, ViewGroup viewGroup) {
|
||||
if (currentType == 1) {
|
||||
if (view == null) {
|
||||
view = new SharedDocumentCell(mContext);
|
||||
}
|
||||
@ -1391,6 +1586,19 @@ public class MediaActivity extends BaseFragment implements NotificationCenter.No
|
||||
} else {
|
||||
sharedDocumentCell.setChecked(false, !scrolling);
|
||||
}
|
||||
} else if (currentType == 3) {
|
||||
if (view == null) {
|
||||
view = new SharedLinkCell(mContext);
|
||||
}
|
||||
SharedLinkCell sharedLinkCell = (SharedLinkCell) view;
|
||||
MessageObject messageObject = getItem(i);
|
||||
sharedLinkCell.setLink(messageObject, i != getCount() - 1);
|
||||
/*if (actionBar.isActionModeShowed()) {
|
||||
sharedDocumentCell.setChecked(selectedFiles.containsKey(messageObject.getId()), !scrolling);
|
||||
} else {
|
||||
sharedDocumentCell.setChecked(false, !scrolling);
|
||||
}*/
|
||||
}
|
||||
return view;
|
||||
}
|
||||
|
||||
|
@ -780,6 +780,7 @@ public class PhotoPickerActivity extends BaseFragment implements NotificationCen
|
||||
updateSearchInterface();
|
||||
}
|
||||
});
|
||||
jsonObjReq.setShouldCache(false);
|
||||
jsonObjReq.setTag("search");
|
||||
requestQueue.add(jsonObjReq);
|
||||
} catch (Exception e) {
|
||||
@ -866,6 +867,7 @@ public class PhotoPickerActivity extends BaseFragment implements NotificationCen
|
||||
return headers;
|
||||
}
|
||||
};
|
||||
jsonObjReq.setShouldCache(false);
|
||||
jsonObjReq.setTag("search");
|
||||
requestQueue.add(jsonObjReq);
|
||||
} catch (Exception e) {
|
||||
|
@ -14,10 +14,12 @@ import android.app.AlertDialog;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.PixelFormat;
|
||||
import android.graphics.PorterDuff;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.RectF;
|
||||
import android.graphics.drawable.BitmapDrawable;
|
||||
@ -26,6 +28,7 @@ import android.graphics.drawable.Drawable;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.provider.Browser;
|
||||
import android.text.TextUtils;
|
||||
import android.util.TypedValue;
|
||||
import android.view.GestureDetector;
|
||||
@ -893,9 +896,17 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat
|
||||
|
||||
actionBar = new ActionBar(activity);
|
||||
actionBar.setBackgroundColor(0x7F000000);
|
||||
SharedPreferences themePrefs = ApplicationLoader.applicationContext.getSharedPreferences(AndroidUtilities.THEME_PREFS, AndroidUtilities.THEME_PREFS_MODE);
|
||||
int def = themePrefs.getInt("themeColor", AndroidUtilities.defColor);
|
||||
actionBar.setBackgroundColor(themePrefs.getInt("chatHeaderColor", def));
|
||||
actionBar.setOccupyStatusBar(false);
|
||||
actionBar.setItemsBackground(R.drawable.bar_selector_white);
|
||||
actionBar.setBackButtonImage(R.drawable.ic_ab_back);
|
||||
//actionBar.setBackButtonImage(R.drawable.ic_ab_back);
|
||||
Drawable back = parentActivity.getResources().getDrawable(R.drawable.ic_ab_back);
|
||||
int iconsColor = themePrefs.getInt("chatHeaderIconsColor", 0xffffffff);
|
||||
back.setColorFilter(iconsColor, PorterDuff.Mode.MULTIPLY);
|
||||
actionBar.setBackButtonDrawable(back);
|
||||
actionBar.setTitleColor(iconsColor);
|
||||
actionBar.setTitle(LocaleController.formatString("Of", R.string.Of, 1, 1));
|
||||
containerView.addView(actionBar, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT));
|
||||
|
||||
@ -1101,7 +1112,10 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat
|
||||
|
||||
ActionBarMenu menu = actionBar.createMenu();
|
||||
|
||||
menuItem = menu.addItem(0, R.drawable.ic_ab_other);
|
||||
//menuItem = menu.addItem(0, R.drawable.ic_ab_other);
|
||||
Drawable dots = parentActivity.getResources().getDrawable(R.drawable.ic_ab_other);
|
||||
dots.setColorFilter(AndroidUtilities.getIntDef("chatHeaderIconsColor", 0xffffffff), PorterDuff.Mode.MULTIPLY);
|
||||
menuItem = menu.addItem(0, dots);
|
||||
menuItem.addSubItem(gallery_menu_showall, LocaleController.getString("ShowAllMedia", R.string.ShowAllMedia), 0);
|
||||
menuItem.addSubItem(gallery_menu_save, LocaleController.getString("SaveToGallery", R.string.SaveToGallery), 0);
|
||||
menuItem.addSubItem(gallery_menu_delete, LocaleController.getString("Delete", R.string.Delete), 0);
|
||||
@ -1159,6 +1173,13 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat
|
||||
File f = null;
|
||||
|
||||
if (currentMessageObject != null) {
|
||||
if (currentMessageObject.messageOwner.media instanceof TLRPC.TL_messageMediaWebPage) {
|
||||
Uri uri = Uri.parse(currentMessageObject.messageOwner.media.webpage.url);
|
||||
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
|
||||
intent.putExtra(Browser.EXTRA_APPLICATION_ID, parentActivity.getPackageName());
|
||||
parentActivity.startActivity(intent);
|
||||
return;
|
||||
}
|
||||
f = FileLoader.getPathToMessage(currentMessageObject.messageOwner);
|
||||
} else if (currentFileLocation != null) {
|
||||
f = FileLoader.getPathToAttach(currentFileLocation, avatarsUserId != 0);
|
||||
@ -2020,7 +2041,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat
|
||||
} else if (message.messageOwner.media != null) {
|
||||
if (message.messageOwner.media instanceof TLRPC.TL_messageMediaVideo) {
|
||||
return file.volume_id + "_" + file.id + ".mp4";
|
||||
} else if (message.messageOwner.media instanceof TLRPC.TL_messageMediaPhoto) {
|
||||
} else if (message.messageOwner.media instanceof TLRPC.TL_messageMediaPhoto || message.messageOwner.media instanceof TLRPC.TL_messageMediaWebPage) {
|
||||
return file.volume_id + "_" + file.local_id + ".jpg";
|
||||
}
|
||||
}
|
||||
@ -2076,7 +2097,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat
|
||||
size[0] = -1;
|
||||
}
|
||||
}
|
||||
} else if (message.messageOwner.media instanceof TLRPC.TL_messageMediaPhoto && message.messageOwner.media.photo != null) {
|
||||
} else if (message.messageOwner.media instanceof TLRPC.TL_messageMediaPhoto && message.messageOwner.media.photo != null || message.messageOwner.media instanceof TLRPC.TL_messageMediaWebPage && message.messageOwner.media.webpage != null) {
|
||||
TLRPC.PhotoSize sizeFull = FileLoader.getClosestPhotoSizeWithSize(message.photoThumbs, AndroidUtilities.getPhotoSize());
|
||||
if (sizeFull != null) {
|
||||
size[0] = sizeFull.size;
|
||||
@ -2138,7 +2159,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat
|
||||
return location;
|
||||
}
|
||||
}
|
||||
} else if (message.messageOwner.media instanceof TLRPC.TL_messageMediaPhoto) {
|
||||
} else if (message.messageOwner.media instanceof TLRPC.TL_messageMediaPhoto || message.messageOwner.media instanceof TLRPC.TL_messageMediaWebPage) {
|
||||
TLRPC.PhotoSize sizeFull = FileLoader.getClosestPhotoSizeWithSize(message.photoThumbs, AndroidUtilities.getPhotoSize());
|
||||
if (sizeFull != null) {
|
||||
TLRPC.TL_inputFileLocation location = new TLRPC.TL_inputFileLocation();
|
||||
@ -2237,7 +2258,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat
|
||||
|
||||
if (messageObject != null && messages == null) {
|
||||
imagesArr.add(messageObject);
|
||||
if (messageObject.messageOwner.action == null || messageObject.messageOwner.action instanceof TLRPC.TL_messageActionEmpty) {
|
||||
if (!(messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaWebPage) && (messageObject.messageOwner.action == null || messageObject.messageOwner.action instanceof TLRPC.TL_messageActionEmpty)) {
|
||||
needSearchImageInArr = true;
|
||||
imagesByIds.put(messageObject.getId(), messageObject);
|
||||
if (messageObject.messageOwner.dialog_id != 0) {
|
||||
@ -2397,6 +2418,8 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat
|
||||
}
|
||||
actionBar.setTitle(LocaleController.formatString("Of", R.string.Of, (totalImagesCount - imagesArr.size()) + currentIndex + 1, totalImagesCount));
|
||||
}
|
||||
} else if (currentMessageObject.messageOwner.media instanceof TLRPC.TL_messageMediaWebPage) {
|
||||
actionBar.setTitle(LocaleController.getString("AttachPhoto", R.string.AttachPhoto));
|
||||
}
|
||||
if (currentMessageObject.messageOwner.ttl != 0) {
|
||||
menuItem.hideSubItem(gallery_menu_save);
|
||||
|
@ -58,18 +58,6 @@ public class SecretPhotoViewer implements NotificationCenter.NotificationCenterD
|
||||
}
|
||||
}
|
||||
|
||||
private class FrameLayoutTouchListener extends FrameLayout {
|
||||
public FrameLayoutTouchListener(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onTouchEvent(MotionEvent event) {
|
||||
FileLog.e("tmessages", event.toString());
|
||||
return super.onTouchEvent(event);
|
||||
}
|
||||
}
|
||||
|
||||
private class SecretDeleteTimer extends FrameLayout {
|
||||
private String currentInfoString;
|
||||
private int infoWidth;
|
||||
@ -147,7 +135,7 @@ public class SecretPhotoViewer implements NotificationCenter.NotificationCenterD
|
||||
|
||||
private Activity parentActivity;
|
||||
private WindowManager.LayoutParams windowLayoutParams;
|
||||
private FrameLayoutTouchListener windowView;
|
||||
private FrameLayout windowView;
|
||||
private FrameLayoutDrawer containerView;
|
||||
private ImageReceiver centerImage = new ImageReceiver();
|
||||
private SecretDeleteTimer secretDeleteTimer;
|
||||
@ -205,7 +193,7 @@ public class SecretPhotoViewer implements NotificationCenter.NotificationCenterD
|
||||
}
|
||||
parentActivity = activity;
|
||||
|
||||
windowView = new FrameLayoutTouchListener(activity);
|
||||
windowView = new FrameLayout(activity);
|
||||
windowView.setBackgroundColor(0xff000000);
|
||||
windowView.setFocusable(true);
|
||||
windowView.setFocusableInTouchMode(true);
|
||||
|
@ -316,7 +316,7 @@ public class ThemingDrawerActivity extends BaseFragment {
|
||||
commitInt("drawerNameColor", color);
|
||||
}
|
||||
|
||||
},themePrefs.getInt("drawerNameColor", 0xffffffff), CENTER, 0, false);
|
||||
},themePrefs.getInt("drawerNameColor", 0xffffffff), CENTER, 0, true);
|
||||
colorDialog.show();
|
||||
} else if (i == phoneColorRow) {
|
||||
if (getParentActivity() == null) {
|
||||
@ -330,7 +330,7 @@ public class ThemingDrawerActivity extends BaseFragment {
|
||||
commitInt("drawerPhoneColor", color);
|
||||
}
|
||||
|
||||
},themePrefs.getInt("drawerPhoneColor", AndroidUtilities.getIntDarkerColor("themeColor",-0x40)), CENTER, 0, false);
|
||||
},themePrefs.getInt("drawerPhoneColor", AndroidUtilities.getIntDarkerColor("themeColor",-0x40)), CENTER, 0, true);
|
||||
|
||||
colorDialog.show();
|
||||
} else if (i == avatarRadiusRow) {
|
||||
|
@ -274,7 +274,7 @@ public class VideoEditorActivity extends BaseFragment implements TextureView.Sur
|
||||
compressVideo = (CheckBox) fragmentView.findViewById(R.id.compress_video);
|
||||
compressVideo.setText(LocaleController.getString("CompressVideo", R.string.CompressVideo));
|
||||
SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("mainconfig", Activity.MODE_PRIVATE);
|
||||
//compressVideo.setVisibility(originalHeight != resultHeight || originalWidth != resultWidth ? View.VISIBLE : View.GONE);
|
||||
compressVideo.setVisibility(originalHeight != resultHeight || originalWidth != resultWidth ? View.VISIBLE : View.GONE);
|
||||
compressVideo.setChecked(preferences.getBoolean("compress_video", true));
|
||||
compressVideo.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
|
||||
@Override
|
||||
|
@ -59,6 +59,7 @@
|
||||
<string name="WillUnmuteIn">خلال %1$s</string>
|
||||
<string name="MuteDisable">تعطيل</string>
|
||||
<string name="Hashtags">الأوسمة</string>
|
||||
<string name="Recent">حديث</string>
|
||||
<!--broadcasts-->
|
||||
<string name="NewBroadcastList">رسالة جماعية جديدة</string>
|
||||
<string name="EnterListName">أدخل اسم القائمة</string>
|
||||
@ -391,9 +392,11 @@
|
||||
<string name="AutoLockDisabled">معطّل</string>
|
||||
<!--media view-->
|
||||
<string name="NoMedia">شارك المقاطع المرئية والصور في هذه المحادثة لتستطيع الوصول إليها من أية جهاز من أجهزتك</string>
|
||||
<string name="DocumentsTitle">ملفات</string>
|
||||
<string name="DocumentsTitle">الملفات المشاركة</string>
|
||||
<string name="SharedMediaTitle">الوسائط المشتركة</string>
|
||||
<string name="LinksTitle">الروابط المشاركة</string>
|
||||
<string name="NoSharedFiles">شارك الملفات والمستندات في هذه المحادثة لتستطيع الوصول إليها من أية جهاز من أجهزتك</string>
|
||||
<string name="NoSharedLinks">شارك الروابط في هذه المحادثة لتستطيع الوصول إليها من أية جهاز من أجهزتك</string>
|
||||
<!--map view-->
|
||||
<string name="Map">الخريطة</string>
|
||||
<string name="Satellite">قمر صناعي</string>
|
||||
@ -834,10 +837,10 @@
|
||||
<string name="formatterDay12H">h:mm a</string>
|
||||
<string name="formatDateAtTime">%1$s الساعة %2$s</string>
|
||||
<!--update text-->
|
||||
<string name="updateText">تم تحديث تيليجرام نسخة الأندرويد. الجديد في النسخة رقم 3.1:\n\n- بحث عن الرسائل داخل محادثات محددة. \n- إعادة تصميم كاملة لشاشة ارفاق الملفات. إرسال جهات اتصال وملفات صوتية مباشرة من خيار المرفقات. \n- تطوير لتشغيل الوسائط داخل التطبيق (يوتيوب, ڤيميو, ساوندكلاود وغيرها.),.\n\nللاستزادة، اطلع هنا:\nhttps://telegram.org/blog/search-and-media</string>
|
||||
<string name="updateBuild">590</string>
|
||||
<!--Telegram+-->
|
||||
<string name="updatePlusText"></string>
|
||||
<string name="updateText">تم تحديث تيليجرام نسخة الاندرويد. الجديد في نسخة ٣.١.٢: \n\n- كلمات البحث الحديثة. \n- اضغط باستمرار لاستعراض الملصق قبل إرساله.</string>
|
||||
<string name="updateBuild">591</string>
|
||||
<!--Telegram+--><!--
|
||||
<string name="updatePlusText"></string>-->
|
||||
<string name="TelegramForAndroid">بلاس مسنجر للأندرويد</string>
|
||||
<string name="Theming">الثيمات</string>
|
||||
<string name="colorHexInvalid">شفرة تعريف اللون غير صحيحه!</string>
|
||||
|
@ -59,6 +59,7 @@
|
||||
<string name="WillUnmuteIn">In %1$s</string>
|
||||
<string name="MuteDisable">Dauerhaft Stumm</string>
|
||||
<string name="Hashtags">HASHTAGS</string>
|
||||
<string name="Recent">LETZTE</string>
|
||||
<!--broadcasts-->
|
||||
<string name="NewBroadcastList">Neue Broadcast Liste</string>
|
||||
<string name="EnterListName">Listenname</string>
|
||||
@ -234,7 +235,7 @@
|
||||
<string name="EncryptionKey">Geheimer Schlüssel</string>
|
||||
<string name="MessageLifetime">Selbstzerstörungs-Timer</string>
|
||||
<string name="ShortMessageLifetimeForever">Aus</string>
|
||||
<string name="EncryptionKeyDescription">Das ist eine Darstellung des Schlüssels für den Geheimen Chat mit <![CDATA[<b>]]>%1$s<![CDATA[</b>]]>.<![CDATA[<br><br>]]>Wenn dieses Bild auf <![CDATA[<b>]]>%2$s\s<![CDATA[</b>]]>s Telefon genau so aussieht, ist euer Chat zu 200%% sicher.<![CDATA[<br><br>]]>Erfahre mehr auf telegram.org</string>
|
||||
<string name="EncryptionKeyDescription">Die Abbildung zeigt den aktuellen Schlüssel dieses geheimen Chats mit <![CDATA[<b>]]>%1$s<![CDATA[</b>]]>.<![CDATA[<br><br>]]>Wenn dieses Bild auf dem Gerät von <![CDATA[<b>]]>%2$s<![CDATA[</b>]]> genau so aussieht, ist euer Chat zu 200%% sicher.<![CDATA[<br><br>]]>Erfahre mehr auf telegram.org</string>
|
||||
<string name="NumberUnknown">Unbekannt</string>
|
||||
<string name="Info">Info</string>
|
||||
<string name="Phone">Telefon</string>
|
||||
@ -391,9 +392,11 @@
|
||||
<string name="AutoLockDisabled">Deaktiviert</string>
|
||||
<!--media view-->
|
||||
<string name="NoMedia">Die hier geteilten Bilder und Videos kannst du von jedem deiner Geräte aufrufen.</string>
|
||||
<string name="DocumentsTitle">Dateien</string>
|
||||
<string name="DocumentsTitle">Geteilte Dateien</string>
|
||||
<string name="SharedMediaTitle">Geteilte Medien</string>
|
||||
<string name="LinksTitle">Geteilte Links</string>
|
||||
<string name="NoSharedFiles">Die hier geteilten Dateien kannst du von jedem deiner Geräte aufrufen.</string>
|
||||
<string name="NoSharedLinks">Die hier geteilten Links kannst du von jedem deiner Geräte aufrufen.</string>
|
||||
<!--map view-->
|
||||
<string name="Map">Karte</string>
|
||||
<string name="Satellite">Satellit</string>
|
||||
@ -834,11 +837,11 @@
|
||||
<string name="formatterDay12H">h:mm a</string>
|
||||
<string name="formatDateAtTime">%1$s um %2$s</string>
|
||||
<!--update text-->
|
||||
<string name="updateText">Plus Messenger für Android wurde aktualisiert. Neu in Version 3.1:\n\n- Direkte Suche in Chats.\n- In Chats versteckt sich ein komplett neues Menü hinter der Büroklammer. Nun kann man dort auch Musik und Kontakte versenden.\n- In-App Medienwiedergabe für YouTube, Vimeo, SoundCloud, etc. optimiert und neuer Player für Audiodateien.\n\nMehr dazu unter:\nhttps://telegram.org/blog/search-and-media</string>
|
||||
<string name="updateBuild">590</string>
|
||||
<!--Telegram+-->
|
||||
<string name="updateText">Plus Messenger für Android wurde aktualisiert. Neu in Version 3.1.2:\n\n- Die letzte Suche wird gespeichert\n- Stickervorschau: Sticker vor dem Senden antippen und halten</string>
|
||||
<string name="updateBuild">591</string>
|
||||
<!--Telegram+--><!--
|
||||
<string name="updatePlusText">
|
||||
\n\nNeu in 3.1.1.9:\n\n- Neue Sprechblase iOS hinzugefügt (Dank an Edwin Macalopu)\n- Neuer MOD Benutzernamen zusammen mit Mitgliedsnamen in Gruppen anzeigen\n- Zeigt Gruppe Admin im Gruppenprofil. Der Admin Benutzer hat ein eigenes Symbol\n- Neuer MOD Profilbild, Name und Telefonnummer im Hauptmenü zentrieren\n- Neuer MOD um Wiedergabe von Audio im Chat zu halten wird der Näherungssensor deaktiviert\n- Neuer MOD ändert Profilbild Farbe in Profilübersicht \n- Fehlerbeseitigung\n\n Prüfen und Anwenden von Themen für den Plus Messenger: https://play.google.com/store/apps/details?id=es.rafalense.themes</string>
|
||||
\n\nNeu in 3.1.1.9:\n\n- Neue Sprechblase iOS hinzugefügt (Dank an Edwin Macalopu)\n- Neuer MOD Benutzernamen zusammen mit Mitgliedsnamen in Gruppen anzeigen\n- Zeigt Gruppe Admin im Gruppenprofil. Der Admin Benutzer hat ein eigenes Symbol\n- Neuer MOD Profilbild, Name und Telefonnummer im Hauptmenü zentrieren\n- Neuer MOD um Wiedergabe von Audio im Chat zu halten wird der Näherungssensor deaktiviert\n- Neuer MOD ändert Profilbild Farbe in Profilübersicht \n- Fehlerbeseitigung\n\n Prüfen und Anwenden von Themen für den Plus Messenger: https://play.google.com/store/apps/details?id=es.rafalense.themes</string>-->
|
||||
<string name="TelegramForAndroid">Plus Messenger für Android</string>
|
||||
<string name="Theming">Themen bearbeiten</string>
|
||||
<string name="colorHexInvalid">Ungültiger Hex-Code!</string>
|
||||
|
@ -59,6 +59,7 @@
|
||||
<string name="WillUnmuteIn">En %1$s</string>
|
||||
<string name="MuteDisable">Desactivar</string>
|
||||
<string name="Hashtags">HASHTAGS</string>
|
||||
<string name="Recent">RECIENTES</string>
|
||||
<!--broadcasts-->
|
||||
<string name="NewBroadcastList">Nueva difusión</string>
|
||||
<string name="EnterListName">Nombre de la lista</string>
|
||||
@ -393,7 +394,9 @@
|
||||
<string name="NoMedia">Comparte fotos y vídeos en este chat y accede a ellos desde cualquier dispositivo.</string>
|
||||
<string name="DocumentsTitle">Archivos</string>
|
||||
<string name="SharedMediaTitle">Multimedia</string>
|
||||
<string name="LinksTitle">Enlaces</string>
|
||||
<string name="NoSharedFiles">Comparte archivos en este chat y accede a ellos desde cualquier dispositivo.</string>
|
||||
<string name="NoSharedLinks">Comparte enlaces en este chat y accede a ellos desde cualquiera de tus dispositivos.</string>
|
||||
<!--map view-->
|
||||
<string name="Map">Mapa</string>
|
||||
<string name="Satellite">Satélite</string>
|
||||
@ -834,10 +837,10 @@
|
||||
<string name="formatterDay12H">h:mm a</string>
|
||||
<string name="formatDateAtTime">%1$s a las %2$s</string>
|
||||
<!--update text-->
|
||||
<string name="updateText">Plus Messenger para Android fue actualizada. Novedades en la versión 3.1:\n\n- Busca mensajes dentro de un chat en específico.\n- Menú para adjuntar completamente rediseñado. Envía contactos y archivos de audio directamente desde el menú para adjuntar.\n- Reproducción de multimedia dentro de la aplicación mejorada (YouTube, Vimeo, SoundCloud etc.), nuevo reproductor para archivos de audio largos.\n\nMás sobre esta actualización:\nhttps://telegram.org/blog/search-and-media</string>
|
||||
<string name="updateBuild">590</string>
|
||||
<string name="updateText">Plus Messenger para Android fue actualizada. Novedades en la versión 3.1.2:\n\n- Búsquedas recientes\n- Mantén pulsado sobre un sticker para obtener una vista previa antes de enviarlo</string>
|
||||
<string name="updateBuild">591</string>
|
||||
<!--Telegram+-->
|
||||
<string name="updatePlusText">\n\nNovedades en 3.1.1.9:\n\n- Añadidos nuevos bocadillos iOs (gracias a Edwin Macalopu)\n- Nuevo MOD para mostrar nombre de usuario junto con nombre de miembro en grupos\n- Se muestra admin en perfil de grupo\n- Nuevo MOD para centrar foto, nombre y número en menú de navegación\n- Nuevo MOD para no parar audio en chat desactivando actuación de sensor de proximidad\n- Nuevo MOD para cambiar color de iconos en pantalla perfil\n- Solución de errores\n\n- Revisa, descarga y aplica temas para Plus Messenger: https://play.google.com/store/apps/details?id=es.rafalense.themes</string>
|
||||
<string name="updatePlusText">Novedades en 3.1.2.0:\n\n- Solución de errores</string>
|
||||
<string name="TelegramForAndroid">Plus Messenger para Android</string>
|
||||
<string name="Theming">Tematización</string>
|
||||
<string name="colorHexInvalid">¡Color hexadecimal inválido!</string>
|
||||
|
@ -832,7 +832,7 @@
|
||||
<string name="formatDateAtTime">%1$s à %2$s</string>
|
||||
<!--update text--><!--
|
||||
<string name="updateText">Plus Messenger pour Android vient d\'être mis à jour. Nouveautés de la version 2.9: \n\n- Installez et partagez des paquets de stickers personnalisés comme celui-ci: this one: https://play.google.com/store/apps/details?id=es.rafalense.themes\n- Si vous êtes un artiste, créez vos paquets de stickers, en utilisant notre robot @stickers. \n\n- Utilisez Telegram avec Android Auto.</string>-->
|
||||
<string name="updateBuild">590</string>
|
||||
<string name="updateBuild">591</string>
|
||||
<!--Telegram+-->
|
||||
<string name="TelegramForAndroid">Plus Messenger pour Android</string>
|
||||
<string name="Theming">Thème</string>
|
||||
|
@ -515,9 +515,9 @@
|
||||
<string name="formatDateAtTime">%1$s पर %2$s</string>
|
||||
<!--update text-->
|
||||
<string name="updateText">Plus Messenger for Android has been updated. New in Version 3.0:\n\n\n\n- Dedicated tabs for each one of your custom sticker sets in the sticker panel. Add custom stickers like https://telegram.me/addstickers/Animals\n- New bot API, free for everyone. If you\'re an engineer, create your own bots for games, services or integrations. Learn more at https://telegram.org/blog/bot-revolution\n https://play.google.com/store/apps/details?id=es.rafalense.themes</string>
|
||||
<string name="updateBuild">590</string>
|
||||
<!--Telegram+-->
|
||||
<string name="updatePlusText"></string>
|
||||
<string name="updateBuild">591</string>
|
||||
<!--Telegram+--><!--
|
||||
<string name="updatePlusText"></string>-->
|
||||
<string name="TelegramForAndroid">Android के लिए प्लस मैसेंजर</string>
|
||||
<string name="Theming">थीमिंग</string>
|
||||
<string name="colorHexInvalid">रंग का हेक्स कोड गलत है!</string>
|
||||
|
@ -59,6 +59,7 @@
|
||||
<string name="WillUnmuteIn">Tra %1$s</string>
|
||||
<string name="MuteDisable">Disabilita</string>
|
||||
<string name="Hashtags">HASHTAG</string>
|
||||
<string name="Recent">RECENTI</string>
|
||||
<!--broadcasts-->
|
||||
<string name="NewBroadcastList">Nuova lista broadcast</string>
|
||||
<string name="EnterListName">Immetti il nome della lista</string>
|
||||
@ -301,7 +302,7 @@
|
||||
<string name="ContactJoined">Un contatto si è unito a Telegram</string>
|
||||
<string name="Pebble">PEBBLE</string>
|
||||
<string name="Language">Lingua</string>
|
||||
<string name="AskAQuestionInfo">Nota che il supporto di Telegram è fornito da volontari. Proviamo a rispondere non appena possibile, ma potrebbe volerci un pò.<![CDATA[<br><br>]]>Dai un\'occhiata alle <![CDATA[<a href=\"https://telegram.org/faq/it#domande-generali\">FAQdi Telegram</a>]]>: troverai risposte alla maggior parte delle domande e suggerimenti importanti per <![CDATA[<a href=\"https://telegram.org/faq/it#risoluzione-dei-problemi\">l\'individuazione del problema</a>]]></string>
|
||||
<string name="AskAQuestionInfo">Nota che il supporto di Telegram è fornito da volontari. Proviamo a rispondere non appena possibile, ma potrebbe volerci un pò.<![CDATA[<br><br>]]>Dai un\'occhiata alle <![CDATA[<a href=\"https://telegram.org/faq/it#domande-generali\">FAQ di Telegram</a>]]>: troverai risposte alla maggior parte delle domande e suggerimenti importanti per <![CDATA[<a href=\"https://telegram.org/faq/it#risoluzione-dei-problemi\">l\'individuazione del problema</a>]]></string>
|
||||
<string name="AskButton">Chiedi a un volontario</string>
|
||||
<string name="TelegramFaq">FAQ di Telegram</string>
|
||||
<string name="TelegramFaqUrl">https://telegram.org/faq/it</string>
|
||||
@ -391,9 +392,11 @@
|
||||
<string name="AutoLockDisabled">Disabilitato</string>
|
||||
<!--media view-->
|
||||
<string name="NoMedia">Condividi foto e video in questa chat e accedi ad essi da ogni tuo dispositivo.</string>
|
||||
<string name="DocumentsTitle">File</string>
|
||||
<string name="DocumentsTitle">File condivisi</string>
|
||||
<string name="SharedMediaTitle">Media condivisi</string>
|
||||
<string name="LinksTitle">Link condivisi</string>
|
||||
<string name="NoSharedFiles">Condividi file e documenti in questa chat e accedi ad essi da ogni tuo dispositivo.</string>
|
||||
<string name="NoSharedLinks">Condividi link in questa chat ed accedi ad essi da ogni tuo dispositivo.</string>
|
||||
<!--map view-->
|
||||
<string name="Map">Mappa</string>
|
||||
<string name="Satellite">Satellite</string>
|
||||
@ -834,11 +837,11 @@
|
||||
<string name="formatterDay12H">h:mm a</string>
|
||||
<string name="formatDateAtTime">%1$s alle %2$s</string>
|
||||
<!--update text-->
|
||||
<string name="updateText">Plus Messenger per Android si è aggiornato. Nuovo nella versione 3.1:\n\n- Cerca messaggi all\'interno di una specifica chat.\n- Menu degli allegati completamente ridisegnato. Invia contatti e audio direttamente dal menu degli allegati.\n- Riproduzione in-app migliorata (YouTube, Vimeo, SoundCloud etc.), nuovo player per i file audio.\n\nMaggiori informazioni su questo aggiornamento:\nhttps://telegram.org/blog/search-and-media</string>
|
||||
<string name="updateBuild">590</string>
|
||||
<!--Telegram+-->
|
||||
<string name="updateText">Plus Messenger per Android si è aggiornato. Nuovo nella versione 3.1.2:\n\n- Risultati recenti nella ricerca\n- Tieni premuto su uno sticker per visualizzare l\'anteprima prima di inviarlo</string>
|
||||
<string name="updateBuild">591</string>
|
||||
<!--Telegram+--><!--
|
||||
<string name="updatePlusText">
|
||||
\n\nNew in 3.1.1.9:\n\n- Nuove bolle in stile iOS aggiunte (tgrazie a Edwin Macalopu)\n- Nuova MOD per mostrare l\'username assieme al nome del partecipante del gruppo\n- Mostra l\'amministratore del gruppo nella schermata del profilo del gruppo. L\'amministratore ha un\'icona particolare\n- Nuova MOD per centrare l\'avatar, il nome ed il telefono nel menu di navigazione\n- Nuova MOD per continuare a riprodurre gli audio nelle chat disabilitndo l\'azione del sensore di prossimità\n- Nuova MOD per cambiare il colore delle icone nella schermata profilo\n- Bug fixes\n\nEsplora e scarica temi per Plus Messenger: https://play.google.com/store/apps/details?id=es.rafalense.themes</string>
|
||||
\n\nNew in 3.1.1.9:\n\n- Nuove bolle in stile iOS aggiunte (tgrazie a Edwin Macalopu)\n- Nuova MOD per mostrare l\'username assieme al nome del partecipante del gruppo\n- Mostra l\'amministratore del gruppo nella schermata del profilo del gruppo. L\'amministratore ha un\'icona particolare\n- Nuova MOD per centrare l\'avatar, il nome ed il telefono nel menu di navigazione\n- Nuova MOD per continuare a riprodurre gli audio nelle chat disabilitndo l\'azione del sensore di prossimità\n- Nuova MOD per cambiare il colore delle icone nella schermata profilo\n- Bug fixes\n\nEsplora e scarica temi per Plus Messenger: https://play.google.com/store/apps/details?id=es.rafalense.themes</string>-->
|
||||
<string name="TelegramForAndroid">Plus Messenger per Android</string>
|
||||
<string name="Theming">Personalizzazione</string>
|
||||
<string name="colorHexInvalid">Codice del colore esadecimale non valido!</string>
|
||||
|
@ -59,6 +59,7 @@
|
||||
<string name="WillUnmuteIn">%1$s 후</string>
|
||||
<string name="MuteDisable">비활성화</string>
|
||||
<string name="Hashtags">해시태그</string>
|
||||
<string name="Recent">최신</string>
|
||||
<!--broadcasts-->
|
||||
<string name="NewBroadcastList">새 단체 메시지 리스트</string>
|
||||
<string name="EnterListName">리스트 이름을 입력하세요</string>
|
||||
@ -391,9 +392,11 @@
|
||||
<string name="AutoLockDisabled">비활성화됨</string>
|
||||
<!--media view-->
|
||||
<string name="NoMedia">이 채팅방에서 사진이나 동영상을 공유하면 다른 기기에서도 보실 수 있습니다.</string>
|
||||
<string name="DocumentsTitle">파일</string>
|
||||
<string name="DocumentsTitle">공유한 파일</string>
|
||||
<string name="SharedMediaTitle">공유된 미디어</string>
|
||||
<string name="LinksTitle">공유한 링크</string>
|
||||
<string name="NoSharedFiles">이 채팅방에서 파일이나 문서를 공유하면 다른 기기에서도 보실 수 있습니다.</string>
|
||||
<string name="NoSharedLinks">이 채팅방에서 파일이나 문서를 공유하면 다른 기기에서도 보실 수 있습니다.</string>
|
||||
<!--map view-->
|
||||
<string name="Map">지도</string>
|
||||
<string name="Satellite">위성</string>
|
||||
@ -834,6 +837,6 @@
|
||||
<string name="formatterDay12H">a h:mm</string>
|
||||
<string name="formatDateAtTime">%1$s %2$s</string>
|
||||
<!--update text-->
|
||||
<string name="updateText">텔레그램 안드로이드 버전이 업데이트 되었습니다. 새로운 버전은 3.1 입니다:\n\n- 특정 대화창에서 검색. \n- 첨부 메뉴 개선. 해당 메뉴에서 바로 연락처, 오디오를 전송 가능. \n- 인앱 미디어 재생 기능 향상 (YouTube, Vimeo, SoundCloud etc). 대용량 오디오 파일 별도 플레이어 기능. \n\nhttps://telegram.org/blog/search-and-media에서 자세한 사항을 알아보세요.</string>
|
||||
<string name="updateBuild">590</string>
|
||||
<string name="updateText">텔레그램 안드로이드 버전이 업데이트 되었습니다. 새로운 버전은 3.1.2 입니다:\n\n- 최신 검색 결과\n- 스티커를 꾹 누를 경우 미리보기 기능</string>
|
||||
<string name="updateBuild">591</string>
|
||||
</resources>
|
@ -59,6 +59,7 @@
|
||||
<string name="WillUnmuteIn">Over %1$s</string>
|
||||
<string name="MuteDisable">Uitschakelen</string>
|
||||
<string name="Hashtags">HASHTAGS</string>
|
||||
<string name="Recent">RECENT</string>
|
||||
<!--broadcasts-->
|
||||
<string name="NewBroadcastList">Nieuwe verzendlijst</string>
|
||||
<string name="EnterListName">Naam van lijst</string>
|
||||
@ -391,9 +392,11 @@
|
||||
<string name="AutoLockDisabled">Uitgeschakeld</string>
|
||||
<!--media view-->
|
||||
<string name="NoMedia">Deel foto\'s en video\'s in deze chat om ze op al je apparaten te kunnen benaderen.</string>
|
||||
<string name="DocumentsTitle">Bestanden</string>
|
||||
<string name="DocumentsTitle">Gedeelde bestanden</string>
|
||||
<string name="SharedMediaTitle">Gedeelde media</string>
|
||||
<string name="LinksTitle">Gedeelde links</string>
|
||||
<string name="NoSharedFiles">Deel bestanden en documenten in deze chat om ze op al je apparaten te kunnen benaderen.</string>
|
||||
<string name="NoSharedLinks">Deel links in deze chat om ze op al je apparaten te kunnen benaderen.</string>
|
||||
<!--map view-->
|
||||
<string name="Map">Kaart</string>
|
||||
<string name="Satellite">Satelliet</string>
|
||||
@ -834,10 +837,10 @@
|
||||
<string name="formatterDay12H">h:mm a</string>
|
||||
<string name="formatDateAtTime">%1$s om %2$s</string>
|
||||
<!--update text-->
|
||||
<string name="updateText">Plus Messenger voor Android is bijgewerkt. Nieuw in versie 3.1:\n\n- Zoek naar berichten in een specifieke chat.\n- Volledig opnieuw ontworpen bijlagemenu. Verstuur contacten en audiobestanden rechtstreeks vanuit het bijlagemenu.\n- Afspelen van media in de app verbeterd (YouTube, Vimeo, SoundCloud, etc.), nieuwe speler voor grote audiobestanden.\n\nMeer weten? Kijk op:\nhttps://telegram.org/blog/search-and-media</string>
|
||||
<string name="updateBuild">590</string>
|
||||
<!--Telegram+-->
|
||||
<string name="updatePlusText"></string>
|
||||
<string name="updateText">Plus Messenger voor Android is bijgewerkt. Nieuw in versie 3.1.2:\n\n- Recente zoekresultaten\n- Stickers aantikken en vasthouden om een voorbeeld weer te geven voor het versturen.</string>
|
||||
<string name="updateBuild">591</string>
|
||||
<!--Telegram+--><!--
|
||||
<string name="updatePlusText"></string>-->
|
||||
<string name="TelegramForAndroid">Plus Messenger voor Android</string>
|
||||
<string name="Theming">Uiterlijk Aanpassen</string>
|
||||
<string name="colorHexInvalid">Ongeldige hexadecimale kleurcode!</string>
|
||||
|
@ -59,6 +59,7 @@
|
||||
<string name="WillUnmuteIn">Em %1$s</string>
|
||||
<string name="MuteDisable">Desativar</string>
|
||||
<string name="Hashtags">HASHTAGS</string>
|
||||
<string name="Recent">RECENTE</string>
|
||||
<!--broadcasts-->
|
||||
<string name="NewBroadcastList">Nova Lista de Transmissão</string>
|
||||
<string name="EnterListName">Digite o nome da lista</string>
|
||||
@ -391,9 +392,11 @@
|
||||
<string name="AutoLockDisabled">Desativado</string>
|
||||
<!--media view-->
|
||||
<string name="NoMedia">Compartilhar fotos e vídeos no chat e acessá-los em qualquer um de seus dispositivos.</string>
|
||||
<string name="DocumentsTitle">Arquivos</string>
|
||||
<string name="DocumentsTitle">Arquivos Compartilhados</string>
|
||||
<string name="SharedMediaTitle">Mídia Compartilhada</string>
|
||||
<string name="LinksTitle">Links Compartilhados</string>
|
||||
<string name="NoSharedFiles">Compartilhar arquivos e documentos no chat e acessá-los de qualquer um de seus dispositivos.</string>
|
||||
<string name="NoSharedLinks">Compartilhe links nesse chat e os acesse de qualquer um de seus dispositivos</string>
|
||||
<!--map view-->
|
||||
<string name="Map">Mapa</string>
|
||||
<string name="Satellite">Satélite</string>
|
||||
@ -834,11 +837,11 @@
|
||||
<string name="formatterDay12H">h:mm a</string>
|
||||
<string name="formatDateAtTime">%1$s às %2$s</string>
|
||||
<!--update text-->
|
||||
<string name="updateText">Plus Messenger para Android foi atualizado. Novo na versão 3.1:\n\n- Busca por mensagens dentro de um chat específico.\n-Menu de anexo totalmente redesenhado. Envie contatos e arquivos de áudio diretamente do menu de anexo.\n- Reprodução melhorada de mídia dentro do aplicativo (YouTube, Vimeo, SoundCloud, etc.), novo player para grandes arquivos de áudio.\n\nMais sobre a atualização:\nhttps://telegram.org/blog/search-and-media</string>
|
||||
<string name="updateBuild">590</string>
|
||||
<!--Telegram+-->
|
||||
<string name="updateText">Plus Messenger para Android acaba de ser atualizado. Novo na versão 3.1.2\n\n- Resultados das buscas recentes\n- Pressione e mantenha em um sticker para pré-visualizar antes do envio</string>
|
||||
<string name="updateBuild">591</string>
|
||||
<!--Telegram+--><!--
|
||||
<string name="updatePlusText">
|
||||
\n\nNew in 3.1.1.9:\n\n- New MOD to center avatar, name and phone in navigation menu\n- New MOD to don\'t stop audio in chat (disables proximity sensor action)\n-New MOD to change icons color in profile screen\n- Bug fixes</string>
|
||||
\n\nNew in 3.1.1.9:\n\n- New MOD to center avatar, name and phone in navigation menu\n- New MOD to don\'t stop audio in chat (disables proximity sensor action)\n-New MOD to change icons color in profile screen\n- Bug fixes</string>-->
|
||||
<string name="TelegramForAndroid">Plus Messenger para Android</string>
|
||||
<string name="Theming">Personalização</string>
|
||||
<string name="colorHexInvalid">Código de cor hexadecimal inválido!</string>
|
||||
|
@ -59,6 +59,7 @@
|
||||
<string name="WillUnmuteIn">Em %1$s</string>
|
||||
<string name="MuteDisable">Desativar</string>
|
||||
<string name="Hashtags">HASHTAGS</string>
|
||||
<string name="Recent">RECENTE</string>
|
||||
<!--broadcasts-->
|
||||
<string name="NewBroadcastList">Nova Lista de Transmissão</string>
|
||||
<string name="EnterListName">Digite o nome da lista</string>
|
||||
@ -391,9 +392,11 @@
|
||||
<string name="AutoLockDisabled">Desativado</string>
|
||||
<!--media view-->
|
||||
<string name="NoMedia">Compartilhar fotos e vídeos no chat e acessá-los em qualquer um de seus dispositivos.</string>
|
||||
<string name="DocumentsTitle">Arquivos</string>
|
||||
<string name="DocumentsTitle">Arquivos Compartilhados</string>
|
||||
<string name="SharedMediaTitle">Mídia Compartilhada</string>
|
||||
<string name="LinksTitle">Links Compartilhados</string>
|
||||
<string name="NoSharedFiles">Compartilhar arquivos e documentos no chat e acessá-los de qualquer um de seus dispositivos.</string>
|
||||
<string name="NoSharedLinks">Compartilhe links nesse chat e os acesse de qualquer um de seus dispositivos</string>
|
||||
<!--map view-->
|
||||
<string name="Map">Mapa</string>
|
||||
<string name="Satellite">Satélite</string>
|
||||
@ -834,8 +837,8 @@
|
||||
<string name="formatterDay12H">h:mm a</string>
|
||||
<string name="formatDateAtTime">%1$s às %2$s</string>
|
||||
<!--update text-->
|
||||
<string name="updateText">Plus Messenger para Android foi atualizado. Novo na versão 3.1:\n\n- Busca por mensagens dentro de um chat específico.\n-Menu de anexo totalmente redesenhado. Envie contatos e arquivos de áudio diretamente do menu de anexo.\n- Reprodução melhorada de mídia dentro do aplicativo (YouTube, Vimeo, SoundCloud, etc.), novo player para grandes arquivos de áudio.\n\nMais sobre a atualização:\nhttps://telegram.org/blog/search-and-media</string>
|
||||
<string name="updateBuild">590</string>
|
||||
<string name="updateText">Plus Messenger para Android acaba de ser atualizado. Novo na versão 3.1.2\n\n- Resultados das buscas recentes\n- Pressione e mantenha em um sticker para pré-visualizar antes do envio</string>
|
||||
<string name="updateBuild">591</string>
|
||||
<!--Telegram+-->
|
||||
<string name="TelegramForAndroid">Plus Messenger para Android</string>
|
||||
<string name="Theming">Temas</string>
|
||||
|
@ -832,7 +832,7 @@
|
||||
<string name="formatDateAtTime">%1$s в %2$s</string>
|
||||
<!--update text-->
|
||||
<string name="updateText">Plus Messenger для Android обновлён. Новое в версии 3.1:\n\n- Поиск сообщений внутри конкретного чата.\n- Полностью переработано меню вложений. Отправка контактов и аудиофайлов прямо из меню вложений.\n- Улучшено воспроизведение медиа в приложении (YouTube, Vimeo, SoundCloud и др.), новый плеер для больших аудиофайлов.\n\nБольше об этом обновлении:\nhttps://telegram.org/blog/search-and-media</string>
|
||||
<string name="updateBuild">590</string>
|
||||
<string name="updateBuild">591</string>
|
||||
<!--Telegram+-->
|
||||
<string name="TelegramForAndroid">Plus Messenger для Android</string>
|
||||
<string name="Theming">Кастомизация</string>
|
||||
|
@ -461,10 +461,10 @@
|
||||
<string name="formatterDay24H">HH:mm</string>
|
||||
<!--update text-->
|
||||
<string name="updateText">Plus Messenger için temalar indirin ve uygulayın. Hergün yeni temalar ekleniyor:\n https://play.google.com/store/apps/details?id=es.rafalense.themes</string>
|
||||
<string name="updateBuild">590</string>
|
||||
<!--Telegram+-->
|
||||
<string name="updateBuild">591</string>
|
||||
<!--Telegram+--><!--
|
||||
<string name="updatePlusText">
|
||||
\n\n3.1.1.9\'daki Yenilikler\n\n- Yeni iOS baloncuğu eklendi (Edwin Macalopu\'ya teşekkürler)\n- Gruplarda kullanıcı adı iler beraber üye ismini birlikte gösteren yeni MOD eklendi\n- Grup profilinde admin gösterilir. Admin kendi ikonuna sahiptir\n- Sol menüde avatar,isim ve telefonu ortalamayı sağlayan yeni MOD eklendi\n- Sohbete yakınlık sensörü eylemlerini kapatmayı ve çalan sesleri devam ettirmeyi sağlayan yeni MOD eklendi \n- Profil ekranına ikon renklerini değiştirmeyi sağlayan yeni MOD eklendi\n- Hata düzeltmeleri \n\n Plus Messenger için temalar: https://play.google.com/store/apps/details?id=es.rafalense.themes</string>
|
||||
\n\n3.1.1.9\'daki Yenilikler\n\n- Yeni iOS baloncuğu eklendi (Edwin Macalopu\'ya teşekkürler)\n- Gruplarda kullanıcı adı iler beraber üye ismini birlikte gösteren yeni MOD eklendi\n- Grup profilinde admin gösterilir. Admin kendi ikonuna sahiptir\n- Sol menüde avatar,isim ve telefonu ortalamayı sağlayan yeni MOD eklendi\n- Sohbete yakınlık sensörü eylemlerini kapatmayı ve çalan sesleri devam ettirmeyi sağlayan yeni MOD eklendi \n- Profil ekranına ikon renklerini değiştirmeyi sağlayan yeni MOD eklendi\n- Hata düzeltmeleri \n\n Plus Messenger için temalar: https://play.google.com/store/apps/details?id=es.rafalense.themes</string>-->
|
||||
<string name="TelegramForAndroid">Android için Plus Messenger</string>
|
||||
<string name="Theming">Tema</string>
|
||||
<string name="colorHexInvalid">Geçersiz renk hex kodu!</string>
|
||||
|
@ -804,7 +804,7 @@
|
||||
<string name="formatDateAtTime">%1$s 的 %2$s</string>
|
||||
<!--update text-->
|
||||
<string name="updateText">Android 版的 Plus Messenger 已更新。最新版本 3.1 的新增功能有:\n\n- 在特定聊天中搜索消息内容。\n- 全新设计的附件选择菜单。从附件选择菜单中直接发送联系人资料或语音文件。\n- 改进的程序内媒体播放功能 (YouTube, Vimoe, Soundcloud 等), 新播放器适用于大型语音文件。\n\n更多更新请查看:\nhttps://telegram.org/blog/search-and-media</string>
|
||||
<string name="updateBuild">590</string>
|
||||
<string name="updateBuild">591</string>
|
||||
<!--Telegram+--><!--
|
||||
<string name="updatePlusText">\n\n在 3.0.1.3 版的新功能:\n\n- 添加设置使用手机字体选项\n- 添加聊天/群组聊天内搜索聊天记录选项\n- 在设置/主题调整界面里添加标头颜色、标题颜色和标头图标颜色的设置\n- 添加主界面群组图标颜色的设置\n- 添加导航栏中头像大小的设置\n- 错误修复</string>-->
|
||||
<string name="TelegramForAndroid">Plus Messenger for Android</string>
|
||||
|
@ -808,10 +808,10 @@
|
||||
<string name="formatDateAtTime">%1$s 於時間 %2$s</string>
|
||||
<!--update text-->
|
||||
<string name="updateText">Android 版的 Plus Messenger 已經更新。在版本 3.1 的新功能:\n\n- 在特定的聊天室裡搜尋訊息。\n- 完全重新設計的附件選單。從附件選單直接傳送「聯絡人」資訊和「音訊檔」。\n- 改進的程式內媒體播放( YouTube、Vimoe、SoundCloud 等 ),新的播放器適用於大型音訊檔。\n\n更多關於這次的更新:\nhttps://telegram.org/blog/search-and-media</string>
|
||||
<string name="updateBuild">590</string>
|
||||
<!--Telegram+-->
|
||||
<string name="updateBuild">591</string>
|
||||
<!--Telegram+--><!--
|
||||
<string name="updatePlusText">
|
||||
\n\n在 3.1.1.9 版的新功能:\n\n- 新的模組在聊天畫面顯示擁有的大頭照\n- 加入新的泡泡邊緣 (感謝 Edwin Macalopu)\n- 錯誤修復</string>
|
||||
\n\n在 3.1.1.9 版的新功能:\n\n- 新的模組在聊天畫面顯示擁有的大頭照\n- 加入新的泡泡邊緣 (感謝 Edwin Macalopu)\n- 錯誤修復</string>-->
|
||||
<string name="TelegramForAndroid">適用於 Android 的 Plus Messenger</string>
|
||||
<string name="Theming">自製佈景主題</string>
|
||||
<string name="colorHexInvalid">無效的十六進位顏色代碼!</string>
|
||||
|
@ -58,6 +58,7 @@
|
||||
<string name="WillUnmuteIn">In %1$s</string>
|
||||
<string name="MuteDisable">Disable</string>
|
||||
<string name="Hashtags">HASHTAGS</string>
|
||||
<string name="Recent">RECENT</string>
|
||||
<!--broadcasts-->
|
||||
<string name="NewBroadcastList">New Broadcast List</string>
|
||||
<string name="EnterListName">Enter list name</string>
|
||||
@ -390,9 +391,11 @@
|
||||
<string name="AutoLockDisabled">Disabled</string>
|
||||
<!--media view-->
|
||||
<string name="NoMedia">Share photos and videos in this chat and access them on any of your devices.</string>
|
||||
<string name="DocumentsTitle">Files</string>
|
||||
<string name="DocumentsTitle">Shared Files</string>
|
||||
<string name="SharedMediaTitle">Shared Media</string>
|
||||
<string name="LinksTitle">Shared Links</string>
|
||||
<string name="NoSharedFiles">Share files and documents in this chat and access them on any of your devices.</string>
|
||||
<string name="NoSharedLinks">Share links in this chat and access them on any of your devices.</string>
|
||||
<!--map view-->
|
||||
<string name="Map">Map</string>
|
||||
<string name="Satellite">Satellite</string>
|
||||
@ -833,10 +836,10 @@
|
||||
<string name="formatterDay12H">h:mm a</string>
|
||||
<string name="formatDateAtTime">%1$s at %2$s</string>
|
||||
<!--update text-->
|
||||
<string name="updateText">Plus Messenger for Android has been updated. New in version 3.1:\n\n- Search for messages inside a specific chat.\n- Fully redesigned attachment menu. Send contacts and audio files straight from the attachment menu.\n- Improved in-app media playback (YouTube, Vimeo, SoundCloud etc.), new player for large audio files.\n\nMore about this update:\nhttps://telegram.org/blog/search-and-media</string>
|
||||
<string name="updateBuild">590</string>
|
||||
<string name="updateText">Plus Messenger for Android has been updated. New in version 3.1.2:\n\n- Recent search results\n- Tap and hold sticker to preview before sending</string>
|
||||
<string name="updateBuild">591</string>
|
||||
<!--Telegram+-->
|
||||
<string name="updatePlusText">\n\nNew in 3.1.1.9:\n\n- New bubble iOS added (thanks to Edwin Macalopu)\n- New MOD to show username together with member name in groups\n- Shows group admin in group profile. Admin user has its own icon\n- New MOD to center avatar, name and phone in navigation menu\n- New MOD to keep playing audio in chat disabling proximity sensor action\n- New MOD to change icons color in profile screen\n- Bug fixes\n\nCheck and apply themes for Plus Messenger: https://play.google.com/store/apps/details?id=es.rafalense.themes</string>
|
||||
<string name="updatePlusText">\n\nNew in 3.1.2.0:\n\n- Bug fixes</string>
|
||||
<string name="TelegramForAndroid">Plus Messenger for Android</string>
|
||||
<string name="Theming">Theming</string>
|
||||
<string name="colorHexInvalid">Invalid color hex code!</string>
|
||||
|
Loading…
Reference in New Issue
Block a user